From d1a8ccc12767d31b4353311f71edb14b8a4240d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 6 Nov 2005 12:35:49 +0400 Subject: [PATCH 001/101] Fix for bug #13044: BIT_COUNT with NULL values. sql/item_func.cc: Fix for bug #13044: BIT_COUNT with NULL values. Always set null_value. --- mysql-test/r/func_op.result | 11 +++++++++++ mysql-test/t/func_op.test | 12 ++++++++++++ sql/item_func.cc | 5 +---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index d009a66353e..486c55870c2 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -25,3 +25,14 @@ select -1 >> 0, -1 << 0; select -1 >> 1, -1 << 1; -1 >> 1 -1 << 1 9223372036854775807 18446744073709551614 +drop table if exists t1,t2; +create table t1(a int); +create table t2(a int, b int); +insert into t1 values (1), (2), (3); +insert into t2 values (1, 7), (3, 7); +select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +a a b bit_count(t2.b) +1 1 7 3 +2 NULL NULL NULL +3 3 7 3 +drop table t1, t2; diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index a312d6ac8c0..ab96caaff82 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -14,3 +14,15 @@ select 1 | -1, 1 ^ -1, 1 & -1; select 0 | -1, 0 ^ -1, 0 & -1; select -1 >> 0, -1 << 0; select -1 >> 1, -1 << 1; + +# +# Bug 13044: wrong bit_count() results +# + +drop table if exists t1,t2; +create table t1(a int); +create table t2(a int, b int); +insert into t1 values (1), (2), (3); +insert into t2 values (1, 7), (3, 7); +select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +drop table t1, t2; diff --git a/sql/item_func.cc b/sql/item_func.cc index 855e86b2382..e83d1f35db8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1138,11 +1138,8 @@ longlong Item_func_find_in_set::val_int() longlong Item_func_bit_count::val_int() { ulonglong value= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) - { - null_value=1; /* purecov: inspected */ + if ((null_value= args[0]->null_value)) return 0; /* purecov: inspected */ - } return (longlong) my_count_bits(value); } From 520dffb5204a471030c3e43494cd3419136bce05 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 10:06:07 +0100 Subject: [PATCH 002/101] WL 2826: First step in error handling of ALTER TABLE for partitioning BUILD/SETUP.sh: Add possibility for BUILD scripts to add error inject flag BUILD/compile-pentium-debug-max: Add error inject flag to this script configure.in: Add handling of --with-error-inject in configure script sql/ha_ndbcluster.cc: Add possibility to rename handler file sql/ha_ndbcluster.h: Add possibility to rename handler file sql/ha_partition.cc: Add possibility to rename handler file sql/ha_partition.h: Add possibility to rename handler file sql/handler.h: Add possibility to rename handler file sql/mysql_priv.h: Add error inject macros sql/mysqld.cc: Add error inject system variables sql/set_var.cc: Add error inject system variables sql/sql_class.h: Add error inject system variables sql/sql_table.cc: Start modifying code for introducing table log, Step 1 sql/unireg.cc: Add rename flag to handler file call sql/sql_partition.cc: Changes to ADD/DROP/CHANGE partitions --- BUILD/SETUP.sh | 1 + BUILD/compile-pentium-debug-max | 2 +- configure.in | 13 +++ sql/ha_ndbcluster.cc | 8 +- sql/ha_ndbcluster.h | 3 +- sql/ha_partition.cc | 27 +++++- sql/ha_partition.h | 3 +- sql/handler.h | 6 +- sql/mysql_priv.h | 30 +++++- sql/mysqld.cc | 6 ++ sql/set_var.cc | 10 ++ sql/sql_class.h | 4 + sql/sql_partition.cc | 163 ++++++++++++++++++++----------- sql/sql_table.cc | 167 ++++++++++++++++++-------------- sql/unireg.cc | 2 +- 15 files changed, 307 insertions(+), 138 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index eece41d72e6..e76507b1a77 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -71,6 +71,7 @@ pentium_cflags="$check_cpu_cflags" pentium64_cflags="$check_cpu_cflags -m64" ppc_cflags="$check_cpu_cflags" sparc_cflags="" +error_inject_flag="--with-error-inject " # be as fast as we can be without losing our ability to backtrace fast_cflags="-O3 -fno-omit-frame-pointer" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index 7a11ad24c44..d065ed2bf71 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -3,7 +3,7 @@ path=`dirname $0` . "$path/SETUP.sh" $@ --with-debug=full -extra_flags="$pentium_cflags $debug_cflags $max_cflags" +extra_flags="$pentium_cflags $debug_cflags $max_cflags $error_inject_flag" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs $max_configs" diff --git a/configure.in b/configure.in index ffc311a7857..ad69365a1b9 100644 --- a/configure.in +++ b/configure.in @@ -654,6 +654,7 @@ else AC_MSG_RESULT([no]) fi + MYSQL_SYS_LARGEFILE # Types that must be checked AFTER large file support is checked @@ -1554,6 +1555,18 @@ then DEBUG_OPTIMIZE_CXX="" fi +# If we should allow error injection tests +AC_ARG_WITH(error-inject, + [ --with-error-inject Enable error injection in MySQL Server], + [ with_error_inject=$withval ], + [ with_error_inject=no ]) + +if test "$with_error_inject" = "yes" +then + CFLAGS="-DERROR_INJECT_SUPPORT $CFLAGS" + CXXFLAGS="-DERROR_INJECT_SUPPORT $CXXFLAGS" +fi + AC_ARG_WITH(debug, [ --without-debug Build a production version without debugging code], [with_debug=$withval], diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 85f43ba2757..deea59b8074 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4399,7 +4399,9 @@ int ha_ndbcluster::create(const char *name, DBUG_RETURN(my_errno); } -int ha_ndbcluster::create_handler_files(const char *file) +int ha_ndbcluster::create_handler_files(const char *file, + const char *old_name, + bool rename_flag) { const char *name; Ndb* ndb; @@ -4410,6 +4412,10 @@ int ha_ndbcluster::create_handler_files(const char *file) DBUG_ENTER("create_handler_files"); + if (rename_flag) + { + DBUG_RETURN(FALSE); + } if (!(ndb= get_ndb())) DBUG_RETURN(HA_ERR_NO_CONNECTION); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index a62356d41ab..3ec6ada9a98 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -588,7 +588,8 @@ class ha_ndbcluster: public handler int rename_table(const char *from, const char *to); int delete_table(const char *name); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); - int create_handler_files(const char *file); + int create_handler_files(const char *file, const char *old_name, + bool rename_flag); int get_default_no_partitions(ulonglong max_rows); bool get_no_parts(const char *name, uint *no_parts); void set_auto_partitions(partition_info *part_info); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 50299dffd85..d318c4ab348 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -563,7 +563,9 @@ int ha_partition::rename_table(const char *from, const char *to) and types of engines in the partitions. */ -int ha_partition::create_handler_files(const char *name) +int ha_partition::create_handler_files(const char *path, + const char *old_path, + bool rename_flag) { DBUG_ENTER("ha_partition::create_handler_files()"); @@ -571,10 +573,27 @@ int ha_partition::create_handler_files(const char *name) We need to update total number of parts since we might write the handler file as part of a partition management command */ - if (create_handler_file(name)) + if (rename_flag) { - my_error(ER_CANT_CREATE_HANDLER_FILE, MYF(0)); - DBUG_RETURN(1); + char name[FN_REFLEN]; + char old_name[FN_REFLEN]; + char *par_str= ".par"; + + strxmov(name, path, par_str, NullS); + strxmov(old_name, old_path, par_str, NullS); + if (my_delete(name, MYF(MY_WME)) || + my_rename(old_name, name, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + } + else + { + if (create_handler_file(path)) + { + my_error(ER_CANT_CREATE_HANDLER_FILE, MYF(0)); + DBUG_RETURN(1); + } } DBUG_RETURN(0); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 35435844064..f62231bb11e 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -179,7 +179,8 @@ public: virtual int rename_table(const char *from, const char *to); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); - virtual int create_handler_files(const char *name); + virtual int create_handler_files(const char *name, + const char *old_name, bool rename_flag); virtual void update_create_info(HA_CREATE_INFO *create_info); virtual char *update_table_comment(const char *comment); virtual int change_partitions(HA_CREATE_INFO *create_info, diff --git a/sql/handler.h b/sql/handler.h index d29c499f954..b6a925695b8 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1779,7 +1779,11 @@ public: virtual void drop_table(const char *name); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; - virtual int create_handler_files(const char *name) { return FALSE;} + virtual int create_handler_files(const char *name, const char *old_name, + bool rename_flag) + { + return FALSE; + } virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 589ca1349c1..b501e4c7663 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -603,6 +603,29 @@ struct Query_cache_query_flags #define query_cache_invalidate_by_MyISAM_filename_ref NULL #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_INJECTOR(x) +#define ERROR_INJECTOR_ACTION(x) +#define ERROR_INJECTOR_CRASH(x) +#else + +inline bool +my_error_inject(int error) +{ + return (current_thd->variables.error_inject_code == error) ? 1 : 0; +} + +#define ERROR_INJECTOR_CRASH(code) \ + (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0 +#define ERROR_INJECTOR_ACTION(code, action) \ + (my_error_inject((code)) ? ((action), 0) : 0 +#define ERROR_INJECT(code) \ + (my_error_inject((code)) ? 1 : 0) +#endif uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); void write_bin_log(THD *thd, bool clear_error, @@ -1099,9 +1122,10 @@ typedef struct st_lock_param_type } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); -#define WFRM_INITIAL_WRITE 1 -#define WFRM_CREATE_HANDLER_FILES 2 -#define WFRM_PACK_FRM 4 +bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt); +#define WFRM_WRITE_SHADOW 1 +#define WFRM_INSTALL_SHADOW 2 +#define WFRM_PACK_FRM bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f5b93e6a5e5..07e2abc1de5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7055,6 +7055,12 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; global_system_variables.old_alter_table= 0; +#ifdef ERROR_INJECT_SUPPORT + global_system_variables.error_inject_code= 0; + global_system_variables.error_inject_value= 0; + max_system_variables.error_inject_code= ~0; + max_system_variables.error_inject_value= ~0; +#endif /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal diff --git a/sql/set_var.cc b/sql/set_var.cc index b85b2576b83..bc6c68e87f6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -215,6 +215,12 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout", &delayed_insert_timeout); sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); +#ifdef ERROR_INJECT_SUPPORT +sys_var_long_ptr sys_error_inject_code("error_inject_code", + &error_inject_code); +sys_var_long_ptr sys_error_inject_value("error_inject_value", + &error_inject_value); +#endif sys_var_event_executor sys_event_executor("event_scheduler", &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", @@ -729,6 +735,10 @@ SHOW_VAR init_vars[]= { {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, {sys_engine_condition_pushdown.name, (char*) &sys_engine_condition_pushdown, SHOW_SYS}, +#ifdef ERROR_INJECT_SUPPORT + {sys_error_inject_code.name,(char*) &sys_error_inject_code, SHOW_SYS}, + {sys_error_inject_value.name,(char*)&sys_error_inject_value, SHOW_SYS}, +#endif {sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index 00440449be8..bf6633f98ed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -186,6 +186,10 @@ struct system_variables ha_rows max_join_size; ulong auto_increment_increment, auto_increment_offset; ulong bulk_insert_buff_size; +#ifdef ERROR_INJECT_SUPPORT + ulong error_inject_code; + ulong error_inject_value; +#endif ulong join_buff_size; ulong long_query_time; ulong max_allowed_packet; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c29f5ef5650..114ac273d52 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5244,7 +5244,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 1) Write the new frm, pack it and then delete it 2) Perform the change within the handler */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE | WFRM_PACK_FRM)) || + if ((mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM)) || (mysql_change_partitions(lpt))) { fast_alter_partition_error_handler(lpt); @@ -5275,29 +5275,56 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, after a DROP PARTITION) if one ensured that failed accesses to the dropped partitions was aborted for sure (thus only possible for transactional engines). - - 1) Lock the table in TL_WRITE_ONLY to ensure all other accesses to + + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the new frm file as a shadow frm + 2) Write the table log to ensure that the operation is completed + even in the presence of a MySQL Server crash + 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to the table have completed - 2) Write the new frm file where the partitions have changed but are - still remaining with the state PART_TO_BE_DROPPED - 3) Write the bin log - 4) Prepare MyISAM handlers for drop of partitions - 5) Ensure that any users that has opened the table but not yet + 4) Write the bin log + Unfortunately the writing of the binlog is not synchronised with + other logging activities. So no matter in which order the binlog + is written compared to other activities there will always be cases + where crashes make strange things occur. In this placement it can + happen that the ALTER TABLE DROP PARTITION gets performed in the + master but not in the slaves if we have a crash, after writing the + table log but before writing the binlog. A solution to this would + require writing the statement first in the table log and then + when recovering from the crash read the binlog and insert it into + the binlog if not written already. + 5) Install the previously written shadow frm file + 6) Ensure that any users that has opened the table but not yet reached the abort lock do that before downgrading the lock. - 6) Drop the partitions - 7) Write the frm file that the partition has been dropped - 8) Wait until all accesses using the old frm file has completed - 9) Complete query + 7) Prepare MyISAM handlers for drop of partitions + 8) Drop the partitions + 9) Remove entries from table log + 10) Wait until all accesses using the old frm file has completed + 11) Complete query + + We insert Error injections at all places where it could be interesting + to test if recovery is properly done. */ - if ((abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || + if (write_log_shadow_frm(lpt) || + ERROR_INJECTOR_CRASH(1000) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECTOR_CRASH(1001) || + write_log_drop_partition(lpt) || + ERROR_INJECTOR_CRASH(1002) || + abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && - (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || + write_bin_log(thd, FALSE, + thd->query, thd->query_length), FALSE) || + ERROR_INJECTOR_CRASH(1003) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || - (mysql_drop_partitions(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || + ERROR_INJECTOR_CRASH(1004) || + table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || + ERROR_INJECTOR_CRASH(1005) || + mysql_drop_partitions(lpt) || + ERROR_INJECTOR_CRASH(1006) || + write_log_completed(lpt) || + ERROR_INJECTOR_CRASH(1007) || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); @@ -5317,26 +5344,38 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, miss updates made by a transaction serialised before it that are inserted into the new partition. - 1) Write the new frm file where state of added partitions is - changed to PART_TO_BE_ADDED + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the new frm file as a shadow frm file + 2) Log the changes to happen in table log 2) Add the new partitions 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Write a new frm file of the table where the partitions are added - to the table. - 5) Write binlog + 4) Write binlog + 5) Install the new frm file of the table where the partitions are + added to the table. 6) Wait until all accesses using the old frm file has completed - 7) Complete query + 7) Remove entries from table log + 8) Complete query */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || - (mysql_change_partitions(lpt)) || - (abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || + if (write_log_shadow_frm(lpt) || + ERROR_INJECTED_CRASH(1010) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECTED_CRASH(1011) || + write_log_add_partition(lpt) || + ERROR_INJECTED_CRASH(1012) || + mysql_change_partitions(lpt) || + ERROR_INJECTED_CRASH(1013) || + abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - (close_open_tables_and_downgrade(lpt), FALSE)) + ERROR_INJECTED_CRASH(1014) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECTED_CRASH(1015) || + (close_open_tables_and_downgrade(lpt), FALSE) || + write_log_completed(lpt) || + ERROR_INJECTED_CRASH(1016)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5375,40 +5414,56 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, use a lower lock level. This can be handled inside store_lock in the respective handler. - 1) Write the new frm file where state of added partitions is - changed to PART_TO_BE_ADDED and the reorganised partitions - are set in state PART_TO_BE_REORGED. - 2) Add the new partitions + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the shadow frm file of new partitioning + 2) Log such that temporary partitions added in change phase are + removed in a crash situation + 3) Add the new partitions Copy from the reorganised partitions to the new partitions - 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users + 4) Log that operation is completed and log all complete actions + needed to complete operation from here + 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Prepare MyISAM handlers for rename and delete of partitions - 5) Write a new frm file of the table where the partitions are - reorganised. - 6) Rename the reorged partitions such that they are no longer + 6) Prepare MyISAM handlers for rename and delete of partitions + 7) Rename the reorged partitions such that they are no longer used and rename those added to their real new names. - 7) Write bin log - 8) Wait until all accesses using the old frm file has completed - 9) Drop the reorganised partitions - 10)Write a new frm file of the table where the partitions are - reorganised. - 11)Wait until all accesses using the old frm file has completed - 12)Complete query + 8) Write bin log + 9) Install the shadow frm file + 10) Wait until all accesses using the old frm file has completed + 11) Drop the reorganised partitions + 12) Remove log entry + 13)Wait until all accesses using the old frm file has completed + 14)Complete query */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || - (mysql_change_partitions(lpt)) || - (abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || - (mysql_rename_partitions(lpt)) || + if (write_log_shadow_frm(lpt) || + ERROR_INJECT_CRASH(1020) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECT_CRASH(1021) || + write_log_ph1_change_partition(lpt) || + ERROR_INJECT_CRASH(1022) || + mysql_change_partitions(lpt) || + ERROR_INJECT_CRASH(1023) || + write_log_ph2_change_partition(lpt) || + ERROR_INJECT_CRASH(1024) || + abort_and_upgrade_lock(lpt) || + table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || + ERROR_INJECT_CRASH(1025) || + mysql_rename_partitions(lpt) || + ERROR_INJECT_CRASH(1026) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH(1027) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECT_CRASH(1028) || (close_open_tables_and_downgrade(lpt), FALSE) || - (mysql_drop_partitions(lpt)) || - (mysql_write_frm(lpt, 0UL)) || + ERROR_INJECT_CRASH(1029) || + mysql_drop_partitions(lpt) || + ERROR_INJECT_CRASH(1030) || + write_log_completed(lpt) || + ERROR_INJECT_CRASH(1031) || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2938f27c58d..809a70a0d45 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -245,6 +245,28 @@ static int mysql_copy_key_list(List *orig_key, } +/* + SYNOPSIS + write_table_log() + lpt Struct carrying parameters to the function + + RETURN VALUES + TRUE Failure in writing the log + FALSE Success + + DESCRIPTION + A careful write of the table log is performed to ensure that we can + handle crashes occurring during CREATE and ALTER TABLE processing. +*/ + +bool +write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_table_log"); + DBUG_RETURN(FALSE); +} + + /* SYNOPSIS mysql_write_frm() @@ -277,83 +299,66 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ int error= 0; char path[FN_REFLEN+1]; + char shadow_path[FN_REFLEN+1]; + char shadow_frm_name[FN_REFLEN+1]; char frm_name[FN_REFLEN+1]; DBUG_ENTER("mysql_write_frm"); - if (flags & WFRM_INITIAL_WRITE) + /* + Build shadow frm file name + */ + build_table_filename(shadow_path, sizeof(path), lpt->db, + lpt->table_name, "#"); + strxmov(shadow_frm_name, path, reg_ext, NullS); + if (flags & WFRM_WRITE_SHADOW) { - error= mysql_copy_create_list(lpt->create_list, - &lpt->new_create_list); - error+= mysql_copy_key_list(lpt->key_list, - &lpt->new_key_list); - if (error) + if (mysql_copy_create_list(lpt->create_list, + &lpt->new_create_list) || + mysql_copy_key_list(lpt->key_list, + &lpt->new_key_list) || + mysql_prepare_table(lpt->thd, lpt->create_info, + &lpt->new_create_list, + &lpt->new_key_list, + /*tmp_table*/ 1, + &lpt->db_options, + lpt->table->file, + &lpt->key_info_buffer, + &lpt->key_count, + /*select_field_count*/ 0))) { DBUG_RETURN(TRUE); } - } - build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - strxmov(frm_name, path, reg_ext, NullS); - if ((flags & WFRM_INITIAL_WRITE) && - (mysql_prepare_table(lpt->thd, lpt->create_info, &lpt->new_create_list, - &lpt->new_key_list,/*tmp_table*/ 1, &lpt->db_options, - lpt->table->file, &lpt->key_info_buffer, - &lpt->key_count, /*select_field_count*/ 0))) - { - DBUG_RETURN(TRUE); - } #ifdef WITH_PARTITION_STORAGE_ENGINE - { - partition_info *part_info= lpt->table->part_info; - char *part_syntax_buf; - uint syntax_len, i; - bool any_unnormal_state= FALSE; - - if (part_info) { - uint max_part_state_len= part_info->partitions.elements + - part_info->temp_partitions.elements; - if (!(part_info->part_state= (uchar*)sql_alloc(max_part_state_len))) + partition_info *part_info= lpt->table->part_info; + char *part_syntax_buf; + uint syntax_len; + + if (part_info) { - DBUG_RETURN(TRUE); + if (!(part_syntax_buf= generate_partition_syntax(part_info, + &syntax_len, + TRUE, FALSE))) + { + DBUG_RETURN(TRUE); + } + part_info->part_info_string= part_syntax_buf; + part_info->part_info_len= syntax_len; } - part_info->part_state_len= 0; - if (!(part_syntax_buf= generate_partition_syntax(part_info, - &syntax_len, - TRUE, FALSE))) - { - DBUG_RETURN(TRUE); - } - for (i= 0; i < part_info->part_state_len; i++) - { - enum partition_state part_state= - (enum partition_state)part_info->part_state[i]; - if (part_state != PART_NORMAL && part_state != PART_IS_ADDED) - any_unnormal_state= TRUE; - } - if (!any_unnormal_state) - { - part_info->part_state= NULL; - part_info->part_state_len= 0; - } - part_info->part_info_string= part_syntax_buf; - part_info->part_info_len= syntax_len; } - } #endif - /* - We write the frm file with the LOCK_open mutex since otherwise we could - overwrite the frm file as another is reading it in open_table. - */ - lpt->create_info->table_options= lpt->db_options; - VOID(pthread_mutex_lock(&LOCK_open)); - if ((mysql_create_frm(lpt->thd, frm_name, lpt->db, lpt->table_name, - lpt->create_info, lpt->new_create_list, lpt->key_count, - lpt->key_info_buffer, lpt->table->file)) || - ((flags & WFRM_CREATE_HANDLER_FILES) && - lpt->table->file->create_handler_files(path))) - { - error= 1; - goto end; + /* Write shadow frm file */ + lpt->create_info->table_options= lpt->db_options; + if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db, + lpt->table_name, lpt->create_info, + lpt->new_create_list, lpt->key_count, + lpt->key_info_buffer, lpt->table->file)) || + lpt->table->file->create_handler_files(shadow_path, NULL, FALSE)) + { + my_delete(shadow_frm_name, MYF(0)); + error= 1; + goto end; + } } if (flags & WFRM_PACK_FRM) { @@ -365,7 +370,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ const void *data= 0; uint length= 0; - if (readfrm(path, &data, &length) || + if (readfrm(shadow_path, &data, &length) || packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len)) { my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); @@ -374,11 +379,31 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) error= 1; goto end; } - error= my_delete(frm_name, MYF(MY_WME)); + error= my_delete(shadow_frm_name, MYF(MY_WME)); } - /* Frm file have been updated to reflect the change about to happen. */ + if (flags & WFRM_INSTALL_SHADOW) + { + /* + Build frm file name + */ + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + strxmov(frm_name, path, reg_ext, NullS); + /* + When we are changing to use new frm file we need to ensure that we + don't collide with another thread in process to open the frm file. + */ + VOID(pthread_mutex_lock(&LOCK_open)); + if (my_delete(frm_name, MYF(MY_WME)) || + my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || + lpt->table->file->create_handler_files(path, shadow_path, TRUE)) + { + error= 1; + } + VOID(pthread_mutex_unlock(&LOCK_open)); + } + end: - VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(error); } @@ -4631,7 +4656,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(reg_path)); + table->file->create_handler_files(reg_path, NULL, FALSE)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) goto err; @@ -4677,7 +4702,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(reg_path)); + table->file->create_handler_files(reg_path, NULL, FALSE)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) goto err; @@ -4900,7 +4925,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); } /* Tell the handler that a new frm file is in place. */ - if (table->file->create_handler_files(reg_path)) + if (table->file->create_handler_files(reg_path, NULL, FALSE)) { VOID(pthread_mutex_unlock(&LOCK_open)); goto err; diff --git a/sql/unireg.cc b/sql/unireg.cc index 2c5f4b34091..ab362b130b0 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -330,7 +330,7 @@ int rea_create_table(THD *thd, const char *path, // Make sure mysql_create_frm din't remove extension DBUG_ASSERT(*fn_rext(frm_name)); - if (file->create_handler_files(path)) + if (file->create_handler_files(path, NULL, FALSE)) goto err_handler; if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, create_info,0)) From 9b6c2bc2bf0747b9d3d0546d07fa43e75589bed2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 14:00:00 +0100 Subject: [PATCH 003/101] WL 2826: Another step sql/mysql_priv.h: Set error_inject_code to zero after firing error injection sql/sql_partition.cc: New entries for new functions --- sql/mysql_priv.h | 8 ++- sql/sql_partition.cc | 163 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 161 insertions(+), 10 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b501e4c7663..fd5c2c019de 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -616,7 +616,13 @@ struct Query_cache_query_flags inline bool my_error_inject(int error) { - return (current_thd->variables.error_inject_code == error) ? 1 : 0; + THD *thd= current_thd; + if (thd->variables.error_inject_code == error) + { + thd->variables.error_inject_code= 0; + return 1; + } + return 0; } #define ERROR_INJECTOR_CRASH(code) \ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 114ac273d52..e9e5fa3fb73 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5114,6 +5114,146 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Write the log entry to ensure that the shadow frm file is removed at + crash. + SYNOPSIS + write_log_shadow_frm() + lpt Struct containing parameters + install_frm Should we log action to install shadow frm or should + the action be to remove the shadow frm file. + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to the table log indicating a drop/install of the shadow frm + file and its corresponding handler file. +*/ + +bool +write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) +{ + DBUG_ENTER("write_log_shadow_frm"); + DBUG_RETURN(FALSE); +} + + +/* + Write the log entries to ensure that the drop partition command is completed + even in the presence of a crash. + + SYNOPSIS + write_log_drop_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the table log indicating all partitions to drop and to + install the shadow frm file and remove the old frm file. +*/ + +bool +write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_drop_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write the log entries to ensure that the drop partition command is completed + even in the presence of a crash. + + SYNOPSIS + write_log_drop_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the table log indicating all partitions to drop and to + install the shadow frm file and remove the old frm file. +*/ + +bool +write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_drop_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write the log entries to ensure that the add partition command is not + executed at all if a crash before it has completed + + SYNOPSIS + write_log_add_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the table log indicating all partitions to drop and to + remove the shadow frm file. +*/ + +bool +write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_add_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write indicator of how to abort in first phase of change partitions + SYNOPSIS + write_log_ph1_change_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the log entries to remove partitions in creation when changing + partitions in an ADD/REORGANIZE/COALESCE command. These commands will + abort the entire operation if the system crashes before the next phase + is done. +*/ + +bool +write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_ph1_change_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write description of how to complete the operation after first phase of + change partitions. + + SYNOPSIS + write_log_ph2_change_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + We will write log entries that specify to remove all partitions reorganised, + to rename others to reflect the new naming scheme and to install the shadow + frm file. +*/ + +bool +write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_ph2_change_partition"); + DBUG_RETURN(FALSE); +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -5305,7 +5445,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ - if (write_log_shadow_frm(lpt) || + if (write_log_shadow_frm(lpt, FALSE) || ERROR_INJECTOR_CRASH(1000) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECTOR_CRASH(1001) || @@ -5352,13 +5492,16 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. 4) Write binlog - 5) Install the new frm file of the table where the partitions are + 5) Now the change is completed except for the installation of the + new frm file. We thus write an action in the log to change to + the shadow frm file + 6) Install the new frm file of the table where the partitions are added to the table. - 6) Wait until all accesses using the old frm file has completed - 7) Remove entries from table log - 8) Complete query + 7) Wait until all accesses using the old frm file has completed + 8) Remove entries from table log + 9) Complete query */ - if (write_log_shadow_frm(lpt) || + if (write_log_shadow_frm(lpt, FALSE) || ERROR_INJECTED_CRASH(1010) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECTED_CRASH(1011) || @@ -5371,11 +5514,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || ERROR_INJECTED_CRASH(1014) || - mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + write_log_shadow_frm(lpt, TRUE) || ERROR_INJECTED_CRASH(1015) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECTED_CRASH(1016) || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECTED_CRASH(1016)) + ERROR_INJECTED_CRASH(1017)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5437,7 +5582,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 14)Complete query */ - if (write_log_shadow_frm(lpt) || + if (write_log_shadow_frm(lpt, FALSE) || ERROR_INJECT_CRASH(1020) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH(1021) || From 83d418a25f21931e1f1ac79c8c27b5e893a87d4e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 16:38:08 +0100 Subject: [PATCH 004/101] WL 2826: A third step, fixing generate_partition_syntax sql/mysql_priv.h: Make it possible to set injector code and value Declare header part of a set of new functions sql/sql_partition.cc: Fix generate_partition_syntax to handle shadow variant of frm file --- sql/mysql_priv.h | 15 ++++++++ sql/sql_partition.cc | 86 +++----------------------------------------- 2 files changed, 20 insertions(+), 81 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fd5c2c019de..22fb67ff3fb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -611,8 +611,15 @@ struct Query_cache_query_flags #define ERROR_INJECTOR(x) #define ERROR_INJECTOR_ACTION(x) #define ERROR_INJECTOR_CRASH(x) +#define SET_ERROR_INJECT_CODE(x) +#define SET_ERROR_INJECT_VALUE(x) #else +#define SET_ERROR_INJECT_CODE(x) \ + current_thd->variables.error_inject_code= (x) +#define SET_ERROR_INJECT_VALUE(x) \ + current_thd->variables.error_inject_value= (x) + inline bool my_error_inject(int error) { @@ -632,6 +639,7 @@ my_error_inject(int error) #define ERROR_INJECT(code) \ (my_error_inject((code)) ? 1 : 0) #endif + uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); void write_bin_log(THD *thd, bool clear_error, @@ -1128,7 +1136,14 @@ typedef struct st_lock_param_type } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); + bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); +bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); + #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index e9e5fa3fb73..d2a4579f53b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2388,15 +2388,10 @@ char *generate_partition_syntax(partition_info *part_info, char path[FN_REFLEN]; int err= 0; List_iterator part_it(part_info->partitions); - List_iterator temp_it(part_info->temp_partitions); File fptr; char *buf= NULL; //Return buffer - uint use_temp= 0; - uint no_temp_parts= part_info->temp_partitions.elements; - bool write_part_state; DBUG_ENTER("generate_partition_syntax"); - write_part_state= (part_info->part_state && !part_info->part_state_len); if (unlikely(((fptr= create_temp_file(path,mysql_tmpdir,"psy", 0,0))) < 0)) DBUG_RETURN(NULL); #ifndef __WIN__ @@ -2459,8 +2454,7 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_space(fptr); } } - no_parts= part_info->no_parts; - tot_no_parts= no_parts + no_temp_parts; + tot_no_parts= part_info->partitions.elements; no_subparts= part_info->no_subparts; if (write_all || (!part_info->use_default_partitions)) @@ -2469,57 +2463,10 @@ char *generate_partition_syntax(partition_info *part_info, i= 0; do { - /* - We need to do some clever list manipulation here since we have two - different needs for our list processing and here we take some of the - cost of using a simpler list processing for the other parts of the - code. - - ALTER TABLE REORGANIZE PARTITIONS has the list of partitions to be - the final list as the main list and the reorganised partitions is in - the temporary partition list. Thus when finding the first part added - we insert the temporary list if there is such a list. If there is no - temporary list we are performing an ADD PARTITION. - */ - if (use_temp && use_temp <= no_temp_parts) + part_elem= part_it++; + if (part_elem->part_state != PART_TO_BE_DROPPED && + part_elem->part_state != PART_REORGED_DROPPED) { - part_elem= temp_it++; - DBUG_ASSERT(no_temp_parts); - no_temp_parts--; - } - else if (use_temp) - { - DBUG_ASSERT(no_parts); - part_elem= save_part_elem; - use_temp= 0; - no_parts--; - } - else - { - part_elem= part_it++; - if ((part_elem->part_state == PART_TO_BE_ADDED || - part_elem->part_state == PART_IS_ADDED) && no_temp_parts) - { - save_part_elem= part_elem; - part_elem= temp_it++; - no_temp_parts--; - use_temp= 1; - } - else - { - DBUG_ASSERT(no_parts); - no_parts--; - } - } - - if (part_elem->part_state != PART_IS_DROPPED) - { - if (write_part_state) - { - uint32 part_state_id= part_info->part_state_len; - part_info->part_state[part_state_id]= (uchar)part_elem->part_state; - part_info->part_state_len= part_state_id+1; - } err+= add_partition(fptr); err+= add_string(fptr, part_elem->partition_name); err+= add_space(fptr); @@ -2558,7 +2505,6 @@ char *generate_partition_syntax(partition_info *part_info, if (i == (tot_no_parts-1)) err+= add_end_parenthesis(fptr); } while (++i < tot_no_parts); - DBUG_ASSERT(!no_parts && !no_temp_parts); } if (err) goto close_file; @@ -4576,6 +4522,7 @@ that are reorganised. my_error(ER_ROW_IS_REFERENCED, MYF(0)); DBUG_RETURN(TRUE); } + tab_part_info->no_parts-= no_parts_dropped; } else if ((alter_info->flags & ALTER_OPTIMIZE_PARTITION) || (alter_info->flags & ALTER_ANALYZE_PARTITION) || @@ -5138,29 +5085,6 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) } -/* - Write the log entries to ensure that the drop partition command is completed - even in the presence of a crash. - - SYNOPSIS - write_log_drop_partition() - lpt Struct containing parameters - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Prepare entries to the table log indicating all partitions to drop and to - install the shadow frm file and remove the old frm file. -*/ - -bool -write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("write_log_drop_partition"); - DBUG_RETURN(FALSE); -} - - /* Write the log entries to ensure that the drop partition command is completed even in the presence of a crash. From c31c4eec46819d67fa9f1f78d9091c9e616ec5fb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 17:05:22 +0100 Subject: [PATCH 005/101] WL 2826: Fourth step Remove partition state from frm file Ensure we can still load tables created in 5.1.6 for the time being sql/table.cc: Remove partition state from frm file Ensure we can still load tables created in 5.1.6 for the time being sql/unireg.cc: Remove partition state from frm file Ensure we can still load tables created in 5.1.6 for the time being --- sql/table.cc | 35 ++++++----------------------------- sql/unireg.cc | 7 ------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index b912683d371..046ed6d1add 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -638,38 +638,15 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } - if (share->mysql_version > 50105 && next_chunk + 5 < buff_end) + if (share->mysql_version == 50106) { /* - Partition state was introduced to support partition management in version 5.1.5 - */ - uint32 part_state_len= uint4korr(next_chunk); -#ifdef WITH_PARTITION_STORAGE_ENGINE - if ((share->part_state_len= part_state_len)) - if (!(share->part_state= - (uchar*) memdup_root(&share->mem_root, next_chunk + 4, - part_state_len))) - { - my_free(buff, MYF(0)); - goto err; - } -#else - if (part_state_len) - { - DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined")); - my_free(buff, MYF(0)); - goto err; - } -#endif - next_chunk+= 4 + part_state_len; + Partition state array was here in version 5.1.6, this code makes + it possible to load a 5.1.6 table in later versions. Can most + likely be removed at some point in time. + */ + next_chunk+= 4; } -#ifdef WITH_PARTITION_STORAGE_ENGINE - else - { - share->part_state_len= 0; - share->part_state= NULL; - } -#endif keyinfo= share->key_info; for (i= 0; i < keys; i++, keyinfo++) { diff --git a/sql/unireg.cc b/sql/unireg.cc index ab362b130b0..ce886253554 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -136,7 +136,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, if (part_info) { create_info->extra_size+= part_info->part_info_len; - create_info->extra_size+= part_info->part_state_len; } #endif @@ -209,12 +208,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, my_write(file, (const byte*)part_info->part_info_string, part_info->part_info_len + 1, MYF_RW)) goto err; - DBUG_PRINT("info", ("Part state len = %d", part_info->part_state_len)); - int4store(buff, part_info->part_state_len); - if (my_write(file, (const byte*)buff, 4, MYF_RW) || - my_write(file, (const byte*)part_info->part_state, - part_info->part_state_len, MYF_RW)) - goto err; } else #endif From 04c95dc23a659e0abbd4aa1e8159ae350754dfbf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 21:38:35 +0100 Subject: [PATCH 006/101] WL 2826: Fifth step Removed partition state from parser sql/sql_yacc.yy: Removed partition state from parser --- sql/sql_yacc.yy | 71 ++++--------------------------------------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a86eccb493f..03a6ba4baca 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3582,75 +3582,14 @@ part_definition: LEX *lex= Lex; partition_info *part_info= lex->part_info; partition_element *p_elem= new partition_element(); - uint part_id= part_info->partitions.elements + - part_info->temp_partitions.elements; - enum partition_state part_state; + uint part_id= part_info->partitions.elements; - if (part_info->part_state) - part_state= (enum partition_state)part_info->part_state[part_id]; - else - part_state= PART_NORMAL; - switch (part_state) + if (!p_elem || part_info->partitions.push_back(p_elem)) { - case PART_TO_BE_DROPPED: - /* - This part is currently removed so we keep it in a - temporary list for REPAIR TABLE to be able to handle - failures during drop partition process. - */ - case PART_TO_BE_ADDED: - /* - This part is currently being added so we keep it in a - temporary list for REPAIR TABLE to be able to handle - failures during add partition process. - */ - if (!p_elem || part_info->temp_partitions.push_back(p_elem)) - { - mem_alloc_error(sizeof(partition_element)); - YYABORT; - } - break; - case PART_IS_ADDED: - /* - Part has been added and is now a normal partition - */ - case PART_TO_BE_REORGED: - /* - This part is currently reorganised, it is still however - used so we keep it in the list of partitions. We do - however need the state to be able to handle REPAIR TABLE - after failures in the reorganisation process. - */ - case PART_REORGED_DROPPED: - /* - This part is currently reorganised as part of a - COALESCE PARTITION and it will be dropped without a new - replacement partition after completing the reorganisation. - */ - case PART_CHANGED: - /* - This part is currently split or merged as part of ADD - PARTITION for a hash partition or as part of COALESCE - PARTITION for a hash partitioned table. - */ - case PART_IS_CHANGED: - /* - This part has been split or merged as part of ADD - PARTITION for a hash partition or as part of COALESCE - PARTITION for a hash partitioned table. - */ - case PART_NORMAL: - if (!p_elem || part_info->partitions.push_back(p_elem)) - { - mem_alloc_error(sizeof(partition_element)); - YYABORT; - } - break; - default: - mem_alloc_error((part_id * 1000) + part_state); - YYABORT; + mem_alloc_error(sizeof(partition_element)); + YYABORT; } - p_elem->part_state= part_state; + p_elem->part_state= PART_NORMAL; part_info->curr_part_elem= p_elem; part_info->current_partition= p_elem; part_info->use_default_partitions= FALSE; From e254606f0bbf993a21b6f1f0ad5fe12be8739cbe Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2006 12:05:29 -0500 Subject: [PATCH 007/101] WL #2826: Sixth step, made it work with test cases BUILD/SETUP.sh: Fixed BUILD scripts BUILD/compile-pentium-debug-max: Fixed BUILD scripts sql/ha_partition.cc: Need to handle states differently when creating handler files sql/mysql_priv.h: Some error inject fixes sql/mysqld.cc: Some error inject fixes sql/set_var.cc: Some error inject fixes sql/sql_partition.cc: Fixing a bug with generate partition syntax A number of fixes sql/sql_table.cc: Fix a few bugs sql/table.cc: fix --- BUILD/SETUP.sh | 2 +- BUILD/compile-pentium-debug-max | 4 +- sql/ha_partition.cc | 8 ++-- sql/mysql_priv.h | 21 +++++----- sql/mysqld.cc | 4 ++ sql/set_var.cc | 3 +- sql/sql_partition.cc | 71 +++++++++++++++++++++------------ sql/sql_table.cc | 6 +-- sql/table.cc | 2 + 9 files changed, 76 insertions(+), 45 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index e76507b1a77..00e78d0719d 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -71,7 +71,7 @@ pentium_cflags="$check_cpu_cflags" pentium64_cflags="$check_cpu_cflags -m64" ppc_cflags="$check_cpu_cflags" sparc_cflags="" -error_inject_flag="--with-error-inject " +error_inject="--with-error-inject " # be as fast as we can be without losing our ability to backtrace fast_cflags="-O3 -fno-omit-frame-pointer" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index d065ed2bf71..9aa71239bd8 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -3,9 +3,9 @@ path=`dirname $0` . "$path/SETUP.sh" $@ --with-debug=full -extra_flags="$pentium_cflags $debug_cflags $max_cflags $error_inject_flag" +extra_flags="$pentium_cflags $debug_cflags $max_cflags" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" -extra_configs="$pentium_configs $debug_configs $max_configs" +extra_configs="$pentium_configs $debug_configs $max_configs $error_inject" . "$path/FINISH.sh" diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d318c4ab348..193fe863f8c 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1879,8 +1879,8 @@ bool ha_partition::create_handler_file(const char *name) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && - part_elem->part_state != PART_IS_ADDED && - part_elem->part_state != PART_IS_CHANGED) + part_elem->part_state != PART_TO_BE_ADDED && + part_elem->part_state != PART_CHANGED) continue; tablename_to_filename(part_elem->partition_name, part_name, FN_REFLEN); @@ -1931,8 +1931,8 @@ bool ha_partition::create_handler_file(const char *name) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && - part_elem->part_state != PART_IS_ADDED && - part_elem->part_state != PART_IS_CHANGED) + part_elem->part_state != PART_TO_BE_ADDED && + part_elem->part_state != PART_CHANGED) continue; if (!m_is_sub_partitioned) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 22fb67ff3fb..8c207992d5e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -608,9 +608,9 @@ struct Query_cache_query_flags in various error cases. */ #ifndef ERROR_INJECT_SUPPORT -#define ERROR_INJECTOR(x) -#define ERROR_INJECTOR_ACTION(x) -#define ERROR_INJECTOR_CRASH(x) +#define ERROR_INJECT(x) 0 +#define ERROR_INJECT_ACTION(x) 0 +#define ERROR_INJECT_CRASH(x) 0 #define SET_ERROR_INJECT_CODE(x) #define SET_ERROR_INJECT_VALUE(x) #else @@ -624,7 +624,7 @@ inline bool my_error_inject(int error) { THD *thd= current_thd; - if (thd->variables.error_inject_code == error) + if (thd->variables.error_inject_code == (uint)error) { thd->variables.error_inject_code= 0; return 1; @@ -632,10 +632,10 @@ my_error_inject(int error) return 0; } -#define ERROR_INJECTOR_CRASH(code) \ - (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0 -#define ERROR_INJECTOR_ACTION(code, action) \ - (my_error_inject((code)) ? ((action), 0) : 0 +#define ERROR_INJECT_CRASH(code) \ + (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0) +#define ERROR_INJECT_ACTION(code, action) \ + (my_error_inject((code)) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ (my_error_inject((code)) ? 1 : 0) #endif @@ -1146,7 +1146,7 @@ bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 -#define WFRM_PACK_FRM +#define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); @@ -1317,6 +1317,9 @@ extern ulong delayed_insert_timeout; extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; +#ifdef ERROR_INJECT_SUPPORT +extern ulong error_inject_code, error_inject_value; +#endif extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; extern ulong slow_launch_threads, slow_launch_time; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 07e2abc1de5..d9853e26197 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -503,6 +503,10 @@ ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; ulong delayed_insert_errors,flush_time; +#ifdef ERROR_INJECT_SUPPORT +ulong error_inject_code= 0; +ulong error_inject_value= 0; +#endif ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong max_connections, max_connect_errors; diff --git a/sql/set_var.cc b/sql/set_var.cc index bc6c68e87f6..4c156c134cf 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -217,10 +217,11 @@ sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); #ifdef ERROR_INJECT_SUPPORT sys_var_long_ptr sys_error_inject_code("error_inject_code", - &error_inject_code); + &error_inject_code); sys_var_long_ptr sys_error_inject_value("error_inject_value", &error_inject_value); #endif + sys_var_event_executor sys_event_executor("event_scheduler", &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d2a4579f53b..ed8b62cc300 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2459,6 +2459,7 @@ char *generate_partition_syntax(partition_info *part_info, if (write_all || (!part_info->use_default_partitions)) { + bool first= TRUE; err+= add_begin_parenthesis(fptr); i= 0; do @@ -2467,6 +2468,12 @@ char *generate_partition_syntax(partition_info *part_info, if (part_elem->part_state != PART_TO_BE_DROPPED && part_elem->part_state != PART_REORGED_DROPPED) { + if (!first) + { + err+= add_comma(fptr); + err+= add_space(fptr); + } + first= FALSE; err+= add_partition(fptr); err+= add_string(fptr, part_elem->partition_name); err+= add_space(fptr); @@ -2496,11 +2503,6 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_end_parenthesis(fptr); } while (++j < no_subparts); } - if (i != (tot_no_parts-1)) - { - err+= add_comma(fptr); - err+= add_space(fptr); - } } if (i == (tot_no_parts-1)) err+= add_end_parenthesis(fptr); @@ -5178,6 +5180,25 @@ write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Remove entry from table log and release resources for others to use + + SYNOPSIS + write_log_completed() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ +static +bool +write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_ph2_change_partition"); + DBUG_RETURN(FALSE); +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -5308,8 +5329,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 1) Write the new frm, pack it and then delete it 2) Perform the change within the handler */ - if ((mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM)) || - (mysql_change_partitions(lpt))) + if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM) || + mysql_change_partitions(lpt)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5370,25 +5391,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, to test if recovery is properly done. */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECTOR_CRASH(1000) || + ERROR_INJECT_CRASH(1000) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECTOR_CRASH(1001) || + ERROR_INJECT_CRASH(1001) || write_log_drop_partition(lpt) || - ERROR_INJECTOR_CRASH(1002) || + ERROR_INJECT_CRASH(1002) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && - write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE) || - ERROR_INJECTOR_CRASH(1003) || + (write_bin_log(thd, FALSE, + thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH(1003) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECTOR_CRASH(1004) || + ERROR_INJECT_CRASH(1004) || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECTOR_CRASH(1005) || + ERROR_INJECT_CRASH(1005) || mysql_drop_partitions(lpt) || - ERROR_INJECTOR_CRASH(1006) || + ERROR_INJECT_CRASH(1006) || write_log_completed(lpt) || - ERROR_INJECTOR_CRASH(1007) || + ERROR_INJECT_CRASH(1007) || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); @@ -5426,25 +5447,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 9) Complete query */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECTED_CRASH(1010) || + ERROR_INJECT_CRASH(1010) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECTED_CRASH(1011) || + ERROR_INJECT_CRASH(1011) || write_log_add_partition(lpt) || - ERROR_INJECTED_CRASH(1012) || + ERROR_INJECT_CRASH(1012) || mysql_change_partitions(lpt) || - ERROR_INJECTED_CRASH(1013) || + ERROR_INJECT_CRASH(1013) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECTED_CRASH(1014) || + ERROR_INJECT_CRASH(1014) || write_log_shadow_frm(lpt, TRUE) || - ERROR_INJECTED_CRASH(1015) || + ERROR_INJECT_CRASH(1015) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECTED_CRASH(1016) || + ERROR_INJECT_CRASH(1016) || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECTED_CRASH(1017)) + ERROR_INJECT_CRASH(1017)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 809a70a0d45..fe37b70c3b3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -307,9 +307,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) /* Build shadow frm file name */ - build_table_filename(shadow_path, sizeof(path), lpt->db, + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - strxmov(shadow_frm_name, path, reg_ext, NullS); + strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); if (flags & WFRM_WRITE_SHADOW) { if (mysql_copy_create_list(lpt->create_list, @@ -324,7 +324,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) lpt->table->file, &lpt->key_info_buffer, &lpt->key_count, - /*select_field_count*/ 0))) + /*select_field_count*/ 0)) { DBUG_RETURN(TRUE); } diff --git a/sql/table.cc b/sql/table.cc index 046ed6d1add..ed34273334d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -638,6 +638,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } +#if 0 if (share->mysql_version == 50106) { /* @@ -647,6 +648,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, */ next_chunk+= 4; } +#endif keyinfo= share->key_info; for (i= 0; i < keys; i++, keyinfo++) { From 7ea92dcc3cd1bde451ebd63a9ea0b85aa89cbe53 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2006 18:05:30 +0100 Subject: [PATCH 008/101] WL 2826: Seventh step, more fixes for error injects Removed session variables for error injects started using DBUG macros for error injects include/my_dbug.h: Added new DBUG macros sql/sql_class.cc: Removed session variables for error injects sql/sql_class.h: Removed session variables for error injects sql/mysql_priv.h: Changed ERROR INJECT macros to use DBUG macros sql/mysqld.cc: Removed session variables for error injects sql/set_var.cc: Removed session variables for error injects --- include/my_dbug.h | 6 ++++++ sql/mysql_priv.h | 31 ++++++++++++++++++++----------- sql/mysqld.cc | 10 ---------- sql/set_var.cc | 11 ----------- sql/sql_class.cc | 3 +++ sql/sql_class.h | 7 +++---- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/include/my_dbug.h b/include/my_dbug.h index b76a3fcc8c9..f20ba696a95 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -72,6 +72,10 @@ extern void _db_unlock_file(void); #define DBUG_ASSERT(A) assert(A) #define DBUG_EXECUTE_IF(keyword,a1) \ {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} +#define DBUG_EXECUTE_COND(keyword, a1) \ + (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) +#define DBUG_COND(keyword) \ + ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) #else /* No debugger */ #define DBUG_ENTER(a1) @@ -79,6 +83,8 @@ extern void _db_unlock_file(void); #define DBUG_VOID_RETURN return #define DBUG_EXECUTE(keyword,a1) {} #define DBUG_EXECUTE_IF(keyword,a1) {} +#define DBUG_EXECUTE_COND(keyword, a1) 0 +#define DBUG_COND(keyword) 0 #define DBUG_PRINT(keyword,arglist) {} #define DBUG_PUSH(a1) {} #define DBUG_POP() {} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8c207992d5e..2324af23442 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -608,36 +608,45 @@ struct Query_cache_query_flags in various error cases. */ #ifndef ERROR_INJECT_SUPPORT + #define ERROR_INJECT(x) 0 -#define ERROR_INJECT_ACTION(x) 0 +#define ERROR_INJECT_ACTION(x,action) 0 #define ERROR_INJECT_CRASH(x) 0 -#define SET_ERROR_INJECT_CODE(x) +#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 -#define SET_ERROR_INJECT_CODE(x) \ - current_thd->variables.error_inject_code= (x) #define SET_ERROR_INJECT_VALUE(x) \ - current_thd->variables.error_inject_value= (x) + current_thd->error_inject_value= (x) inline bool -my_error_inject(int error) +my_error_inject(int value) { THD *thd= current_thd; - if (thd->variables.error_inject_code == (uint)error) + if (thd->error_inject_value == (uint)value) { - thd->variables.error_inject_code= 0; + thd->error_inject_value= 0; return 1; } return 0; } #define ERROR_INJECT_CRASH(code) \ - (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0) + DBUG_EXECUTE_COND(code, abort();) #define ERROR_INJECT_ACTION(code, action) \ - (my_error_inject((code)) ? ((action), 0) : 0) + DBUG_EXECUTE_COND(code, action) #define ERROR_INJECT(code) \ - (my_error_inject((code)) ? 1 : 0) + DBUG_COND(code) +#define ERROR_INJECT_VALUE(value) \ + my_error_inject(value) +#define ERROR_INJECT_VALUE_ACTION(value,action) \ + (my_error_inject(value) ? (action) : 0) +#define ERROR_INJECT_VALUE_CRASH(value) \ + (my_error_inject(value) ? abort() : 0) + #endif uint build_table_path(char *buff, size_t bufflen, const char *db, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d9853e26197..f5b93e6a5e5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -503,10 +503,6 @@ ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; ulong delayed_insert_errors,flush_time; -#ifdef ERROR_INJECT_SUPPORT -ulong error_inject_code= 0; -ulong error_inject_value= 0; -#endif ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong max_connections, max_connect_errors; @@ -7059,12 +7055,6 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; global_system_variables.old_alter_table= 0; -#ifdef ERROR_INJECT_SUPPORT - global_system_variables.error_inject_code= 0; - global_system_variables.error_inject_value= 0; - max_system_variables.error_inject_code= ~0; - max_system_variables.error_inject_value= ~0; -#endif /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal diff --git a/sql/set_var.cc b/sql/set_var.cc index 4c156c134cf..b85b2576b83 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -215,13 +215,6 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout", &delayed_insert_timeout); sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); -#ifdef ERROR_INJECT_SUPPORT -sys_var_long_ptr sys_error_inject_code("error_inject_code", - &error_inject_code); -sys_var_long_ptr sys_error_inject_value("error_inject_value", - &error_inject_value); -#endif - sys_var_event_executor sys_event_executor("event_scheduler", &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", @@ -736,10 +729,6 @@ SHOW_VAR init_vars[]= { {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, {sys_engine_condition_pushdown.name, (char*) &sys_engine_condition_pushdown, SHOW_SYS}, -#ifdef ERROR_INJECT_SUPPORT - {sys_error_inject_code.name,(char*) &sys_error_inject_code, SHOW_SYS}, - {sys_error_inject_value.name,(char*)&sys_error_inject_value, SHOW_SYS}, -#endif {sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 959e4912c1c..bb110bef31f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -222,6 +222,9 @@ THD::THD() cuted_fields= sent_row_count= 0L; limit_found_rows= 0; 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 bf6633f98ed..e78dfed30ab 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -186,10 +186,6 @@ struct system_variables ha_rows max_join_size; ulong auto_increment_increment, auto_increment_offset; ulong bulk_insert_buff_size; -#ifdef ERROR_INJECT_SUPPORT - ulong error_inject_code; - ulong error_inject_value; -#endif ulong join_buff_size; ulong long_query_time; ulong max_allowed_packet; @@ -1103,6 +1099,9 @@ public: query_id_t query_id, warn_id; ulong thread_id, 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; From 846adac5e932d0f12e149a813cea8816064cf635 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2006 18:05:31 +0100 Subject: [PATCH 009/101] WL 2826: Eigth step Inserted monty patch to allow for adding and dropping DBUG keywords per thread dbug/dbug.c: Inserted monty patch to allow for adding and dropping DBUG keywords per thread include/my_dbug.h: Inserted monty patch to allow for adding and dropping DBUG keywords per thread --- dbug/dbug.c | 87 ++++++++++++++++++++++++++++++++++++++++++++--- include/my_dbug.h | 8 ++++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/dbug/dbug.c b/dbug/dbug.c index 91b7e7b6c4c..6604b8bdb98 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -249,6 +249,7 @@ typedef struct st_code_state { uint u_line; /* User source code line number */ int locked; /* If locked with _db_lock_file */ const char *u_keyword; /* Keyword for current macro */ + struct link *keywords; /* Thread specific, active keywords */ } CODE_STATE; /* Parse a debug command string */ @@ -1252,7 +1253,9 @@ static BOOLEAN DoProfile () BOOLEAN _db_strict_keyword_ ( const char *keyword) { - if (stack -> keywords == NULL) + CODE_STATE *state; + if (stack->keywords == NULL && + (!(state= code_state()) || state->keywords == NULL)) return FALSE; return _db_keyword_ (keyword); } @@ -1288,16 +1291,15 @@ const char *keyword) REGISTER BOOLEAN result; CODE_STATE *state; - if (!init_done) - _db_push_ (""); - /* Sasha: pre-my_thread_init() safety */ if (!(state=code_state())) return FALSE; result = FALSE; if (DEBUGGING && !state->disable_output && state->level <= stack -> maxdepth && InList (stack -> functions, state->func) && - InList (stack -> keywords, keyword) && + (InList (stack -> keywords, keyword) || + (state -> keywords && + InList (state -> keywords, keyword))) && InList (stack -> processes, _db_process_)) result = TRUE; return (result); @@ -1373,6 +1375,81 @@ struct link *linkp) } +/* + * FUNCTION + * + * Add key word to _db_strict_keyword_ list + * + * SYNOPSIS + * + * VOID _db_add_strict_keyword(keyword) + * const char *keyword; + * + * DESCRIPTION + * + * Add key word to _db_strict_keyword_ to active DEBUG_EXECUTE_IF + * statements for this thread only + * + * Returns TRUE if keyword accepted, FALSE otherwise. + * + */ + +BOOLEAN _db_add_strict_keyword_(const char *keyword) +{ + CODE_STATE *state; + struct link *tmp; + uint length; + + if (!(state=code_state()) || + !(tmp= (struct link *) DbugMalloc(sizeof(struct link) + + (length= strlen(keyword)+1)))) + return FALSE; + tmp->str= (char*) (tmp+1); + memcpy(tmp->str, keyword, length); + tmp->next_link= state->keywords; + state->keywords= tmp; + return TRUE; +} + +/* + * FUNCTION + * + * Remove key word from thread specific _db_strict_keyword_ list + * + * SYNOPSIS + * + * VOID _db_del_strict_keyword_(keyword) + * const char *keyword; + * + * DESCRIPTION + * + * Delete key word from _db_strict_keyword_ to decative DEBUG_EXECUTE_IF + * statements for this thread only + * + * Returns TRUE if keyword deleted, FALSE otherwise. + * + */ + +BOOLEAN _db_del_strict_keyword_(const char *keyword) +{ + CODE_STATE *state; + struct link *link, **linkp; + + if (!(state=code_state())) + return FALSE; + + for (linkp= &state->keywords; (link= *linkp); linkp= &link->next_link) + { + if (STREQ(link->str, keyword)) + { + *linkp= link->next_link; + free(link); + return TRUE; + } + } + return (FALSE); +} + /* * FUNCTION * diff --git a/include/my_dbug.h b/include/my_dbug.h index f20ba696a95..ac6eec46716 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -24,8 +24,10 @@ extern "C" { extern int _db_on_,_no_db_; extern FILE *_db_fp_; extern char *_db_process_; -extern int _db_keyword_(const char *keyword); +extern int _db_keyword_(const char *keyword); extern int _db_strict_keyword_(const char *keyword); +extern int _db_add_strict_keyword_(const char *keyword); +extern int _db_del_strict_keyword_(const char *keyword); extern void _db_setjmp_(void); extern void _db_longjmp_(void); extern void _db_push_(const char *control); @@ -76,6 +78,8 @@ extern void _db_unlock_file(void); (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) #define DBUG_COND(keyword) \ ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) +#define DBUG_ADD_KEYWORD(key) _db_add_strict_keyword_(key) +#define DBUG_DEL_KEYWORD(key) _db_del_strict_keyword_(key) #else /* No debugger */ #define DBUG_ENTER(a1) @@ -85,6 +89,8 @@ extern void _db_unlock_file(void); #define DBUG_EXECUTE_IF(keyword,a1) {} #define DBUG_EXECUTE_COND(keyword, a1) 0 #define DBUG_COND(keyword) 0 +#define DBUG_ADD_KEYWORD(key) +#define DBUG_DEL_KEYWORD(key) #define DBUG_PRINT(keyword,arglist) {} #define DBUG_PUSH(a1) {} #define DBUG_POP() {} From dde234ae1d7b4762149cc6e2a931e7d035899061 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 4 Feb 2006 13:03:35 +0100 Subject: [PATCH 010/101] WL 2826: Nineth step Updated error inject scripts dbug/dbug_long.h: Updated scripts in dub_long.h as well sql/mysql_priv.h: Updated error inject scripts --- dbug/dbug_long.h | 13 +++++++++++++ sql/mysql_priv.h | 16 ++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h index 829df181ef1..4035ca56b66 100644 --- a/dbug/dbug_long.h +++ b/dbug/dbug_long.h @@ -127,6 +127,11 @@ # define DBUG_SETJMP setjmp # define DBUG_LONGJMP longjmp # define DBUG_DUMP(keyword,a1) +# define DBUG_EXECUTE_IF(keyword, a1) +# define DBUG_EXECUTE_COND(keyword, a1) 0 +# define DBUG_COND(keyword) 0 +# define DBUG_ADD_KEYWORD(key) +# define DBUG_DEL_KEYWORD(key) # else # define DBUG_ENTER(a) \ auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \ @@ -157,4 +162,12 @@ # define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) # define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) # define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) +# define DBUG_EXECUTE_IF(keyword,a1) \ + {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} +# define DBUG_EXECUTE_COND(keyword, a1) \ + (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) +# define DBUG_COND(keyword) \ + ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) +# define DBUG_ADD_KEYWORD(key) _db_add_strict_keyword_(key) +# define DBUG_DEL_KEYWORD(key) _db_del_strict_keyword_(key) # endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2324af23442..2718f5d855d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -622,6 +622,18 @@ struct Query_cache_query_flags #define SET_ERROR_INJECT_VALUE(x) \ current_thd->error_inject_value= (x) +inline bool +my_error_inject_name(const char *dbug_str) +{ + if (_db_on_ && _db_strict_keyword_ (dbug_str)) + { + DBUG_DEL_KEYWORD(dbug_str); + return 1; + } + return 0; +} + + inline bool my_error_inject(int value) { @@ -637,9 +649,9 @@ my_error_inject(int value) #define ERROR_INJECT_CRASH(code) \ DBUG_EXECUTE_COND(code, abort();) #define ERROR_INJECT_ACTION(code, action) \ - DBUG_EXECUTE_COND(code, action) + (my_error_inject_name(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ - DBUG_COND(code) + my_error_inject_name(code) #define ERROR_INJECT_VALUE(value) \ my_error_inject(value) #define ERROR_INJECT_VALUE_ACTION(value,action) \ From 84627f5bc7756860d4d6641df15f8d966dca9738 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 6 Feb 2006 21:47:03 +0100 Subject: [PATCH 011/101] WL 2826: Step 10 New methods to read/write/initialise table log sql/mysql_priv.h: New methods to read/write/initialise table log sql/sql_table.cc: New methods to read/write/initialise table log --- sql/mysql_priv.h | 19 +++++++- sql/sql_table.cc | 120 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2718f5d855d..e48fb7c7536 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1158,7 +1158,24 @@ typedef struct st_lock_param_type void mem_alloc_error(size_t size); -bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt); +typedef struct st_table_log_entry +{ + const char *name; + const char *from_name; + const char *handler_type; + char action_type; +} TABLE_LOG_ENTRY; + + +bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, + uint next_entry, + uint *entry_written); +bool write_execute_table_log_entry(uint first_entry, uint *exec_entry); +uint read_table_log_header(); +bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry); +bool init_table_log(); +void release_table_log(); + bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index fe37b70c3b3..9fece576f63 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -247,11 +247,12 @@ static int mysql_copy_key_list(List *orig_key, /* SYNOPSIS - write_table_log() - lpt Struct carrying parameters to the function + write_table_log_entry() + table_log_entry Information about log entry + out:entry_written Entry information written into RETURN VALUES - TRUE Failure in writing the log + TRUE Error FALSE Success DESCRIPTION @@ -260,13 +261,122 @@ static int mysql_copy_key_list(List *orig_key, */ bool -write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt) +write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, + uint next_entry, + uint *entry_written) { - DBUG_ENTER("write_table_log"); + DBUG_ENTER("write_table_log_entry"); DBUG_RETURN(FALSE); } +/* + Write final entry in the table log + SYNOPSIS + write_execute_table_log_entry() + first_entry First entry in linked list of entries + to execute, if 0 = NULL it means that + the entry is removed and the entries + are put into the free list. + in:out:exec_entry Entry to execute, 0 = NULL if the entry + is written first time and needs to be + returned. In this case the entry written + is returned in this parameter + RETURN VALUES + TRUE Error + FALSE Success + + DESCRIPTION + This is the last write in the table log. The previous log entries have + already been written but not yet synched to disk. +*/ + +bool +write_execute_table_log_entry(uint first_entry, uint *exec_entry) +{ + DBUG_ENTER("write_execute_table_log_entry"); + DBUG_RETURN(FALSE); +} + + +/* + Read header of table log file + SYNOPSIS + read_table_log_header() + RETURN VALUES + > 0 Last entry in table log + 0 No entries in table log + DESCRIPTION + When we read the table log header we get information about maximum sizes + of names in the table log and we also get information about the number + of entries in the table log. +*/ + +uint +read_table_log_header() +{ + DBUG_ENTER("read_table_log_header"); + DBUG_RETURN(0); +} + + +/* + Read a table log entry + SYNOPSIS + read_table_log_entry() + read_entry Number of entry to read + out:entry_info Information from entry + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Read a specified entry in the table log +*/ + +bool +read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) +{ + DBUG_ENTER("read_table_log_entry"); + DBUG_RETURN(FALSE); +} + + +/* + Initialise table log + SYNOPSIS + init_table_log() + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the header of the table log file and length of names. Also set + number of entries to zero. +*/ + +bool +init_table_log() +{ + DBUG_ENTER("init_table_log"); + DBUG_RETURN(FALSE); +} + + +/* + Release all memory allocated to the table log + SYNOPSIS + release_table_log() + RETURN VALUES + NONE +*/ + +void +release_table_log() +{ + DBUG_ENTER("release_table_log"); + DBUG_RETURN_VOID; +} + + /* SYNOPSIS mysql_write_frm() From e4a92796f2d892d606f37abc468cadda5ef7c0d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Feb 2006 10:45:07 +0100 Subject: [PATCH 012/101] WL 2826: Step 11 Lots of new code for table log include/my_sys.h: Spell error sql/mysql_priv.h: More structs and methods for table log sql/sql_partition.cc: lock/unlock global table log mutex sql/sql_table.cc: Lots of new code for table log --- include/my_sys.h | 2 +- sql/mysql_priv.h | 7 ++ sql/sql_partition.cc | 18 ++++ sql/sql_table.cc | 227 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 252 insertions(+), 2 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 00c42fc5935..c2cdea2c54f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -559,7 +559,7 @@ extern File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, uint error_message_number, myf MyFlags); extern File my_create(const char *FileName,int CreateFlags, - int AccsesFlags, myf MyFlags); + int AccessFlags, myf MyFlags); extern int my_close(File Filedes,myf MyFlags); extern File my_dup(File file, myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e48fb7c7536..7c7cc0b42d7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1163,7 +1163,9 @@ typedef struct st_table_log_entry const char *name; const char *from_name; const char *handler_type; + uint next_entry; char action_type; + char entry_type; } TABLE_LOG_ENTRY; @@ -1175,6 +1177,11 @@ uint read_table_log_header(); bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry); bool init_table_log(); void release_table_log(); +void execute_table_log_recovery(); +bool execute_table_log_entry(uint first_entry); +bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry); +void lock_global_table_log(); +void unlock_global_table_log(); bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ed8b62cc300..816f2cda157 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5083,6 +5083,9 @@ bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) { DBUG_ENTER("write_log_shadow_frm"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5106,6 +5109,9 @@ bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_drop_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5129,6 +5135,9 @@ bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_add_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5152,6 +5161,9 @@ bool write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_ph1_change_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5176,6 +5188,9 @@ bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_ph2_change_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5195,6 +5210,9 @@ bool write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_ph2_change_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9fece576f63..7fe130c5ec3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -244,6 +244,52 @@ static int mysql_copy_key_list(List *orig_key, DBUG_RETURN(FALSE); } +/* +-------------------------------------------------------------------------- + + MODULE: Table log + ----------------- + + This module is used to ensure that we can recover from crashes that occur + in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2; + We need to ensure that both t1 and t2 are dropped and not only t1 and + also that each table drop is entirely done and not "half-baked". + + To support this we create log entries for each meta-data statement in the + table log while we are executing. These entries are dropped when the + operation is completed. + + At recovery those entries that were not completed will be executed. + + There is only one table log in the system and it is protected by a mutex + and there is a global struct that contains information about its current + state. + +-------------------------------------------------------------------------- +*/ + + +typedef struct st_table_log_memory_entry +{ + uint entry_pos; +} TABLE_LOG_MEMORY_ENTRY; + +typedef struct st_global_table_log +{ + char file_entry[IO_SIZE]; + char file_name_str[FN_REFLEN]; + char *file_name; + List free_entries; + List log_entries; + File file_id; + uint name_len; + uint handler_type_len; +} GLOBAL_TABLE_LOG; + +GLOBAL_TABLE_LOG global_table_log; + +pthread_mutex_t LOCK_gtl; + /* SYNOPSIS @@ -299,6 +345,31 @@ write_execute_table_log_entry(uint first_entry, uint *exec_entry) } +/* + Read one entry from table log file + SYNOPSIS + read_table_log_file_entry() + file_id File identifier + file_entry Memory area to read entry into + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +read_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +{ + bool error= FALSE; + DBUG_ENTER("read_table_log_file_entry"); + + if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + /* Read header of table log file SYNOPSIS @@ -315,8 +386,20 @@ write_execute_table_log_entry(uint first_entry, uint *exec_entry) uint read_table_log_header() { + char *file_entry= (char*)&global_table_log.file_entry; DBUG_ENTER("read_table_log_header"); - DBUG_RETURN(0); + + if (read_table_log_file_entry(global_table_log.file_id, + (char*)&file_entry, 0UL)) + { + DBUG_RETURN(0); + } + entry_no= uint4korr(&file_entry[0]); + global_table_log.name_len= uint2korr(&file_entry[4]); + global_table_log.handler_type_len= uint2korr(&file_entry[6]); + global_table_log.free_entries.clear(); + VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); + DBUG_RETURN(entry_no); } @@ -356,7 +439,17 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) bool init_table_log() { + uint no_entries= 0; + uint16 const_var; DBUG_ENTER("init_table_log"); + VOID(my_delete(global_table_log.file_name)); + global_table_log.file_id= my_open(global_table_log.file_name, + 0, 0, MYF(0)); + int4store(&global_table_log.file_entry[0], &no_entries); + const_var= NAMELEN; + int2store(&global_table_log.file_entry[4], &const_var); + const_var= 32; + int2store(&global_table_log.file_entry[6], &const_var); DBUG_RETURN(FALSE); } @@ -373,10 +466,142 @@ void release_table_log() { DBUG_ENTER("release_table_log"); + + VOID(pthread_mutex_destroy(&LOCK_gtl)); DBUG_RETURN_VOID; } +/* + Lock mutex for global table log + SYNOPSIS + lock_global_table_log() + RETURN VALUES + NONE +*/ + +void +lock_global_table_log() +{ + DBUG_ENTER("lock_global_table_log"); + + VOID(pthread_mutex_lock(&LOCK_gtl)); + DBUG_RETURN_VOID; +} + + +/* + Unlock mutex for global table log + SYNOPSIS + unlock_global_table_log() + RETURN VALUES + NONE +*/ + +void +unlock_global_table_log() +{ + DBUG_ENTER("unlock_global_table_log"); + + VOID(pthread_mutex_unlock(&LOCK_gtl)); + DBUG_RETURN_VOID; +} + + +/* + Execute one action in a table log entry + SYNOPSIS + execute_table_log_action() + table_log_entry Information in action entry to execute + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) +{ + DBUG_ENTER("execute_table_log_action"); + DBUG_RETURN(FALSE); +} + + +/* + Execute one entry in the table log. Executing an entry means executing + a linked list of actions. + SYNOPSIS + execute_table_log_entry() + first_entry Reference to first action in entry + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +execute_table_log_entry(uint first_entry) +{ + TABLE_LOG_ENTRY table_log_entry; + uint read_entry= first_entry; + DBUG_ENTER("execute_table_log_entry"); + + do + { + read_table_log_entry(read_entry, &table_log_entry); + DBUG_ASSERT(table_log_entry.entry_type == 'i'); + if (execute_table_log_action(&table_log_entry)) + { + /* error handling */ + DBUG_RETURN(TRUE); + } + read_entry= table_log_entry.next_entry; + } while (read_entry); + DBUG_RETURN(FALSE); +} + + +/* + Execute the table log at recovery of MySQL Server + SYNOPSIS + execute_table_log_recovery() + RETURN VALUES + NONE +*/ + +void +execute_table_log_recovery() +{ + uint no_entries, i; + TABLE_LOG_ENTRY table_log_entry; + DBUG_ENTER("execute_table_log_recovery"); + + no_entries= read_log_header(); + for (i= 0; i < no_entries; i++) + { + read_table_log_entry(i, &table_log_entry); + if (table_log_entry.entry_type == 'e') + { + if (execute_table_log_entry(table_log_entry.next_entry)) + { + /* error handling */ + DBUG_RETURN_VOID; + } + } + } + init_table_log(); + DBUG_RETURN_VOID; +} + + +/* +--------------------------------------------------------------------------- + + END MODULE Table log + -------------------- + +--------------------------------------------------------------------------- +*/ + + /* SYNOPSIS mysql_write_frm() From e09fb5ceaa6761563675bc72d053a03e48ebf3c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Feb 2006 16:26:34 +0100 Subject: [PATCH 013/101] WL 2826: Step 12 More table log code sql/mysql_priv.h: Added new call sql/sql_table.cc: New table log code --- sql/mysql_priv.h | 1 + sql/sql_table.cc | 121 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 113 insertions(+), 9 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7c7cc0b42d7..a8f73ac1915 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1182,6 +1182,7 @@ bool execute_table_log_entry(uint first_entry); bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry); void lock_global_table_log(); void unlock_global_table_log(); +bool sync_table_log(); bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7fe130c5ec3..7a6b24c0b66 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -281,6 +281,7 @@ typedef struct st_global_table_log char *file_name; List free_entries; List log_entries; + uint no_entries; File file_id; uint name_len; uint handler_type_len; @@ -291,6 +292,52 @@ GLOBAL_TABLE_LOG global_table_log; pthread_mutex_t LOCK_gtl; +/* + Sync table log file + SYNOPSIS + sync_table_log() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +sync_table_log() +{ + bool error= FALSE; + DBUG_ENTER("sync_table_log"); + + if (my_sync(global_table_log.file_id, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Write one entry from table log file + SYNOPSIS + write_table_log_file_entry() + file_id File identifier + file_entry Memory area to read entry into + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +{ + bool error= FALSE; + DBUG_ENTER("read_table_log_file_entry"); + + if (my_pwrite(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + /* SYNOPSIS write_table_log_entry() @@ -308,10 +355,67 @@ pthread_mutex_t LOCK_gtl; bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - uint next_entry, uint *entry_written) { + bool write_header, error; DBUG_ENTER("write_table_log_entry"); + + global_table_log.file_entry[0]= 'i'; + global_table_log.file_entry[1]= table_log_entry->action_type; + int4store(&global_table_log.file_entry[2], + table_log_entry->next_entry); + strcpy(&global_table_log.file_entry[6], table_log_entry->name); + if (table_log_entry.action_type == 'r') + global_table_log.file_entry[6 + NAMELEN]= 0; + else + strcpy(&global_table_log.file_entry[6 + NAMELEN], + table_log_entry->from_name); + strcpy(&global_table_log.file_entry[6 + (2*NAMELEN)], + table_log_entry->handler_type); + if (global_table_log.free_entries.is_empty()) + { + global_table_log.no_entries++; + entry_no= global_table_log.no_entries; + write_header= TRUE; + } + else + { + TABLE_LOG_MEMORY *tmp= global_table_log.free_entries.pop(); + global_table_log.log_entries.push_back(tmp); + entry_no= tmp->entry_pos; + write_header= FALSE; + } + error= FALSE; + if (write_table_log_entry(global_table_log.file_id, + global_table_log.file_entry, + entry_no)) + error= TRUE; + else if (write_header || !(write_table_log_header())) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Write table log header + SYNOPSIS + write_table_log_header() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +write_table_log_header() +{ + uint16 const_var; + DBUG_ENTER("write_table_log_header"); + + int4store(&global_table_log.file_entry[0], global_table_log.no_entries); + const_var= NAMELEN; + int2store(&global_table_log.file_entry[4], const_var); + const_var= 32; + int2store(&global_table_log.file_entry[6], const_var); DBUG_RETURN(FALSE); } @@ -398,6 +502,8 @@ read_table_log_header() global_table_log.name_len= uint2korr(&file_entry[4]); global_table_log.handler_type_len= uint2korr(&file_entry[6]); global_table_log.free_entries.clear(); + global_table_log.log_entries.clear(); + global_table_log.no_entries= 0; VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); DBUG_RETURN(entry_no); } @@ -439,18 +545,15 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) bool init_table_log() { - uint no_entries= 0; - uint16 const_var; + bool error= FALSE; DBUG_ENTER("init_table_log"); + VOID(my_delete(global_table_log.file_name)); global_table_log.file_id= my_open(global_table_log.file_name, 0, 0, MYF(0)); - int4store(&global_table_log.file_entry[0], &no_entries); - const_var= NAMELEN; - int2store(&global_table_log.file_entry[4], &const_var); - const_var= 32; - int2store(&global_table_log.file_entry[6], &const_var); - DBUG_RETURN(FALSE); + if (write_table_log_header()) + error= TRUE; + DBUG_RETURN(error); } From 910bf3808a63693b6671db948a790297817968c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 15:14:15 +0100 Subject: [PATCH 014/101] WL 2826: Error handling for ALTER TABLE for partitioning Most of the code for handling the table log is in place now, except the action part at recovery and proper error handling in some places. sql/mysql_priv.h: Removed internal methods from external table log interface Added and changed interface sql/mysqld.cc: Added call to execute table log recovery sql/sql_table.cc: Most of the code for handling the table log is in place now, except the action part at recovery and proper error handling in some places. --- sql/mysql_priv.h | 19 +- sql/mysqld.cc | 2 +- sql/sql_table.cc | 623 ++++++++++++++++++++++++++++++----------------- 3 files changed, 414 insertions(+), 230 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a8f73ac1915..3be2b4508f1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1168,21 +1168,24 @@ typedef struct st_table_log_entry char entry_type; } TABLE_LOG_ENTRY; +typedef struct st_table_log_memory_entry +{ + uint entry_pos; + TABLE_LOG_MEMORY *next_log_entry; + TABLE_LOG_MEMORY *prev_log_entry; + TABLE_LOG_MEMORY *next_active_log_entry; +} TABLE_LOG_MEMORY_ENTRY; bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - uint next_entry, - uint *entry_written); -bool write_execute_table_log_entry(uint first_entry, uint *exec_entry); -uint read_table_log_header(); -bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry); -bool init_table_log(); + TABLE_LOG_MEMORY_ENTRY **active_entry); +bool write_execute_table_log_entry(uint first_entry, + TABLE_LOG_MEMORY_ENTRY **active_entry); +void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); void release_table_log(); void execute_table_log_recovery(); bool execute_table_log_entry(uint first_entry); -bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry); void lock_global_table_log(); void unlock_global_table_log(); -bool sync_table_log(); bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f5b93e6a5e5..7f7cf957477 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3676,7 +3676,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); unireg_abort(1); } } - + execute_table_log_recovery(); init_events(); create_shutdown_thread(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7a6b24c0b66..8934f4be90f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -265,22 +265,19 @@ static int mysql_copy_key_list(List *orig_key, and there is a global struct that contains information about its current state. + History: + First version written in 2006 by Mikael Ronstrom -------------------------------------------------------------------------- */ -typedef struct st_table_log_memory_entry -{ - uint entry_pos; -} TABLE_LOG_MEMORY_ENTRY; - typedef struct st_global_table_log { char file_entry[IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; - List free_entries; - List log_entries; + TABLE_LOG_MEMORY_ENTRY *first_free; + TABLE_LOG_MEMORY_ENTRY *first_used; uint no_entries; File file_id; uint name_len; @@ -301,6 +298,7 @@ pthread_mutex_t LOCK_gtl; FALSE Success */ +static bool sync_table_log() { @@ -308,7 +306,10 @@ sync_table_log() DBUG_ENTER("sync_table_log"); if (my_sync(global_table_log.file_id, MYF(0))) + { + /* Write to error log */ error= TRUE; + } DBUG_RETURN(error); } @@ -317,8 +318,6 @@ sync_table_log() Write one entry from table log file SYNOPSIS write_table_log_file_entry() - file_id File identifier - file_entry Memory area to read entry into entry_no Entry number to read RETURN VALUES TRUE Error @@ -327,10 +326,12 @@ sync_table_log() static bool -write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +write_table_log_file_entry(uint entry_no) { bool error= FALSE; - DBUG_ENTER("read_table_log_file_entry"); + File file_id= global_table_log.file_id; + char *file_entry= (char*)global_table_log.file_entry; + DBUG_ENTER("write_table_log_file_entry"); if (my_pwrite(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) error= TRUE; @@ -338,6 +339,264 @@ write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) } +/* + Write table log header + SYNOPSIS + write_table_log_header() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_table_log_header() +{ + uint16 const_var; + bool error= FALSE; + DBUG_ENTER("write_table_log_header"); + + int4store(&global_table_log.file_entry[0], global_table_log.no_entries); + const_var= NAMELEN; + int2store(&global_table_log.file_entry[4], const_var); + const_var= 32; + int2store(&global_table_log.file_entry[6], const_var); + if (write_table_log_file_entry(0UL)) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Read one entry from table log file + SYNOPSIS + read_table_log_file_entry() + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +read_table_log_file_entry(uint entry_no) +{ + bool error= FALSE; + File file_id= global_table_log.file_id; + char *file_entry= (char*)global_table_log.file_entry; + DBUG_ENTER("read_table_log_file_entry"); + + if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Create table log file name + SYNOPSIS + create_table_log_file_name() + file_name Filename setup + RETURN VALUES + NONE +*/ + +static +void +create_table_log_file_name(char *file_name) +{ + strxmov(file_name, mysql_data_home, "/", "table_log.log", NullS); +} + + +/* + Read header of table log file + SYNOPSIS + read_table_log_header() + RETURN VALUES + > 0 Last entry in table log + 0 No entries in table log + DESCRIPTION + When we read the table log header we get information about maximum sizes + of names in the table log and we also get information about the number + of entries in the table log. +*/ + +static +uint +read_table_log_header() +{ + char *file_entry= (char*)global_table_log.file_entry; + char file_name[FN_REFLEN]; + DBUG_ENTER("read_table_log_header"); + + bzero(file_entry, sizeof(global_table_log.file_entry)); + create_table_log_file_name(file_name); + if (!(my_open(file_name, O_RDWR | O_TRUNC, MYF(0)))) + { + if (read_table_log_file_entry(0UL)) + { + /* Write message into error log */ + } + } + entry_no= uint4korr(&file_entry[0]); + global_table_log.name_len= uint2korr(&file_entry[4]); + global_table_log.handler_type_len= uint2korr(&file_entry[6]); + global_table_log.first_free= NULL; + global_table_log.first_used= NULL; + global_table_log.no_entries= 0; + VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); + DBUG_RETURN(entry_no); +} + + +/* + Read a table log entry + SYNOPSIS + read_table_log_entry() + read_entry Number of entry to read + out:entry_info Information from entry + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Read a specified entry in the table log +*/ + +bool +read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) +{ + char *file_entry= (char*)&global_table_log.file_entry; + DBUG_ENTER("read_table_log_entry"); + + if (read_table_log_file_entry(global_table_log.file_id, + (char*)&file_entry, read_entry)) + { + /* Error handling */ + DBUG_RETURN(TRUE); + } + table_log_entry->entry_type= file_entry[0]; + table_log_entry->action_type= file_entry[1]; + table_log_entry->next_entry= uint4korr(&file_entry[2]); + table_log_entry->name= &file_entry[6]; + index= 6 + global_table_log->name_len; + table_log_entry->from_name= &file_entry[index]; + index+= global_table_log->name_len; + table_log_entry->handler_type= &file_entry[index]; + DBUG_RETURN(FALSE); +} + + +/* + Initialise table log + SYNOPSIS + init_table_log() + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the header of the table log file and length of names. Also set + number of entries to zero. +*/ + +static +bool +init_table_log() +{ + bool error= FALSE; + char file_name[FN_REFLEN]; + DBUG_ENTER("init_table_log"); + + create_table_log_file_name(file_name); + VOID(my_delete(file_name)); + if ((global_table_log.file_id= my_create(file_name, + CREATE_MODE, + create_flags, MYF(0))) < 0) + { + /* Couldn't create table log file, this is serious error */ + abort(); + } + if (write_table_log_header()) + { + /* Write to error log */ + error= TRUE; + } + DBUG_RETURN(error); +} + + +/* + Execute one action in a table log entry + SYNOPSIS + execute_table_log_action() + table_log_entry Information in action entry to execute + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) +{ + DBUG_ENTER("execute_table_log_action"); + DBUG_RETURN(FALSE); +} + + +/* + Get a free entry in the table log + SYNOPSIS + get_free_table_log_entry() + out:active_entry A table log memory entry returned + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry) +{ + bool write_header; + TABLE_LOG_MEMORY_ENTRY *used_entry; + TABLE_LOG_MEMORY_ENTRY *first_used= global_table_log.first_used; + if (global_table_log.first_free == NULL) + { + if (!(used_entry= my_malloc(sizeof(TABLE_LOG_MEMORY_ENTRY)))) + { + DBUG_RETURN(TRUE); + } + global_table_log.no_entries++; + used_entry->entry_no= entry_no= global_table_log.no_entries; + write_header= TRUE; + } + else + { + used_entry= global_table_log.first_free; + global_table_log.first_free= used_entry->next_log_entry; + entry_no= first_free->entry_pos; + used_entry= first_free; + write_header= FALSE; + } + /* + Move from free list to used list + */ + used_entry->next_log_entry= first_used; + used_entry->prev_log_entry= NULL; + global_table_log.first_used= used_entry; + if (first_used) + first_used->prev_log_entry= used_entry; + + *active_entry= used_entry; +} + + +/* + External interface methods for the Table log Module + --------------------------------------------------- +*/ + /* SYNOPSIS write_table_log_entry() @@ -355,9 +614,9 @@ write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - uint *entry_written) + TABLE_LOG_MEMORY_ENTRY **active_entry) { - bool write_header, error; + bool error; DBUG_ENTER("write_table_log_entry"); global_table_log.file_entry[0]= 'i'; @@ -372,54 +631,23 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, table_log_entry->from_name); strcpy(&global_table_log.file_entry[6 + (2*NAMELEN)], table_log_entry->handler_type); - if (global_table_log.free_entries.is_empty()) + if (get_free_table_log_entry(active_entry)) { - global_table_log.no_entries++; - entry_no= global_table_log.no_entries; - write_header= TRUE; - } - else - { - TABLE_LOG_MEMORY *tmp= global_table_log.free_entries.pop(); - global_table_log.log_entries.push_back(tmp); - entry_no= tmp->entry_pos; - write_header= FALSE; + DBUG_RETURN(TRUE); } error= FALSE; - if (write_table_log_entry(global_table_log.file_id, - global_table_log.file_entry, - entry_no)) + if (write_table_log_file_entry(global_table_log.file_id, + global_table_log.file_entry, + (*active_entry)->entry_pos)) error= TRUE; else if (write_header || !(write_table_log_header())) error= TRUE; + if (error) + release_table_log_memory_entry(*active_entry); DBUG_RETURN(error); } -/* - Write table log header - SYNOPSIS - write_table_log_header() - RETURN VALUES - TRUE Error - FALSE Success -*/ - -bool -write_table_log_header() -{ - uint16 const_var; - DBUG_ENTER("write_table_log_header"); - - int4store(&global_table_log.file_entry[0], global_table_log.no_entries); - const_var= NAMELEN; - int2store(&global_table_log.file_entry[4], const_var); - const_var= 32; - int2store(&global_table_log.file_entry[6], const_var); - DBUG_RETURN(FALSE); -} - - /* Write final entry in the table log SYNOPSIS @@ -442,118 +670,141 @@ write_table_log_header() */ bool -write_execute_table_log_entry(uint first_entry, uint *exec_entry) +write_execute_table_log_entry(uint first_entry, + TABLE_LOG_MEMORY_ENTRY **active_entry) { + char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); + + VOID(sync_table_log()); + file_entry[0]= 'e'; + file_entry[1]= 0; /* Ignored for execute entries */ + int4store(&file_entry[2], first_entry); + file_entry[6]= 0; + file_entry[6 + NAMELEN]= 0; + file_entry[6 + 2*NAMELEN]= 0; + if (get_free_table_log_entry(active_entry)) + { + DBUG_RETURN(TRUE); + } + if (write_table_log_file_entry((*active_entry)->entry_pos)) + { + release_table_log_memory_entry(*active_entry); + DBUG_RETURN(TRUE); + } + VOID(sync_table_log()); DBUG_RETURN(FALSE); } /* - Read one entry from table log file + Release a log memory entry SYNOPSIS - read_table_log_file_entry() - file_id File identifier - file_entry Memory area to read entry into - entry_no Entry number to read + release_table_log_memory_entry() + log_memory_entry Log memory entry to release RETURN VALUES - TRUE Error - FALSE Success + NONE +*/ + +void +release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) +{ + TABLE_LOG_MEMORY_ENTRY *first_free= global_table_log.first_free; + TABLE_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; + TABLE_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; + DBUG_ENTER("release_table_log_memory_entry"); + + global_table_log.first_free= log_entry; + log_entry->next_log_entry= first_free; + + if (prev_log_entry) + prev_log_entry->next_log_entry= next_log_entry; + else + global_table_log.first_used= next_log_entry; + if (next_log_entry) + next_log_entry->prev_log_entry= prev_log_entry; + DBUG_RETURN_VOID; +} + + +/* + Execute one entry in the table log. Executing an entry means executing + a linked list of actions. + SYNOPSIS + execute_table_log_entry() + first_entry Reference to first action in entry + RETURN VALUES + TRUE Error + FALSE Success */ static bool -read_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +execute_table_log_entry(uint first_entry) { - bool error= FALSE; - DBUG_ENTER("read_table_log_file_entry"); + TABLE_LOG_ENTRY table_log_entry; + uint read_entry= first_entry; + DBUG_ENTER("execute_table_log_entry"); - if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) - error= TRUE; - DBUG_RETURN(error); -} - - -/* - Read header of table log file - SYNOPSIS - read_table_log_header() - RETURN VALUES - > 0 Last entry in table log - 0 No entries in table log - DESCRIPTION - When we read the table log header we get information about maximum sizes - of names in the table log and we also get information about the number - of entries in the table log. -*/ - -uint -read_table_log_header() -{ - char *file_entry= (char*)&global_table_log.file_entry; - DBUG_ENTER("read_table_log_header"); - - if (read_table_log_file_entry(global_table_log.file_id, - (char*)&file_entry, 0UL)) + do { - DBUG_RETURN(0); - } - entry_no= uint4korr(&file_entry[0]); - global_table_log.name_len= uint2korr(&file_entry[4]); - global_table_log.handler_type_len= uint2korr(&file_entry[6]); - global_table_log.free_entries.clear(); - global_table_log.log_entries.clear(); - global_table_log.no_entries= 0; - VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); - DBUG_RETURN(entry_no); -} - - -/* - Read a table log entry - SYNOPSIS - read_table_log_entry() - read_entry Number of entry to read - out:entry_info Information from entry - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Read a specified entry in the table log -*/ - -bool -read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) -{ - DBUG_ENTER("read_table_log_entry"); + if (read_table_log_entry(read_entry, &table_log_entry)) + { + DBUG_ASSERT(0); + /* Write to error log and continue with next log entry */ + break; + } + DBUG_ASSERT(table_log_entry.entry_type == 'i'); + if (execute_table_log_action(&table_log_entry)) + { + DBUG_ASSERT(0); + /* Write to error log and continue with next log entry */ + break; + } + read_entry= table_log_entry.next_entry; + } while (read_entry); DBUG_RETURN(FALSE); } - /* - Initialise table log + Execute the table log at recovery of MySQL Server SYNOPSIS - init_table_log() + execute_table_log_recovery() RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Write the header of the table log file and length of names. Also set - number of entries to zero. + NONE */ -bool -init_table_log() +void +execute_table_log_recovery() { - bool error= FALSE; - DBUG_ENTER("init_table_log"); + uint no_entries, i; + TABLE_LOG_ENTRY table_log_entry; + DBUG_ENTER("execute_table_log_recovery"); - VOID(my_delete(global_table_log.file_name)); - global_table_log.file_id= my_open(global_table_log.file_name, - 0, 0, MYF(0)); - if (write_table_log_header()) - error= TRUE; - DBUG_RETURN(error); + no_entries= read_log_header(); + for (i= 0; i < no_entries; i++) + { + if (read_table_log_entry(i, &table_log_entry)) + { + DBUG_ASSERT(0); + /* Write to error log */ + break; + } + if (table_log_entry.entry_type == 'e') + { + if (execute_table_log_entry(table_log_entry.next_entry)) + { + /* + Currently errors are either crashing or ignored so we should + never end up here + */ + abort(); + DBUG_RETURN_VOID; + } + } + } + VOID(init_table_log()); + DBUG_RETURN_VOID; } @@ -568,9 +819,23 @@ init_table_log() void release_table_log() { + TABLE_LOG_MEMORY_ENTRY *free_list= global_table_log.first_free; + TABLE_LOG_MEMORY_ENTRY *used_list= global_table_log.first_used; DBUG_ENTER("release_table_log"); VOID(pthread_mutex_destroy(&LOCK_gtl)); + while (used_list) + { + TABLE_LOG_MEMORY_ENTRY tmp= used_list; + my_free(used_list, MYF(0)); + used_list= tmp->next_log_entry; + } + while (free_list) + { + TABLE_LOG_MEMORY_ENTRY tmp= free_list; + my_free(free_list, MYF(0)); + free_list= tmp->next_log_entry; + } DBUG_RETURN_VOID; } @@ -611,90 +876,6 @@ unlock_global_table_log() } -/* - Execute one action in a table log entry - SYNOPSIS - execute_table_log_action() - table_log_entry Information in action entry to execute - RETURN VALUES - TRUE Error - FALSE Success -*/ - -bool -execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) -{ - DBUG_ENTER("execute_table_log_action"); - DBUG_RETURN(FALSE); -} - - -/* - Execute one entry in the table log. Executing an entry means executing - a linked list of actions. - SYNOPSIS - execute_table_log_entry() - first_entry Reference to first action in entry - RETURN VALUES - TRUE Error - FALSE Success -*/ - -bool -execute_table_log_entry(uint first_entry) -{ - TABLE_LOG_ENTRY table_log_entry; - uint read_entry= first_entry; - DBUG_ENTER("execute_table_log_entry"); - - do - { - read_table_log_entry(read_entry, &table_log_entry); - DBUG_ASSERT(table_log_entry.entry_type == 'i'); - if (execute_table_log_action(&table_log_entry)) - { - /* error handling */ - DBUG_RETURN(TRUE); - } - read_entry= table_log_entry.next_entry; - } while (read_entry); - DBUG_RETURN(FALSE); -} - - -/* - Execute the table log at recovery of MySQL Server - SYNOPSIS - execute_table_log_recovery() - RETURN VALUES - NONE -*/ - -void -execute_table_log_recovery() -{ - uint no_entries, i; - TABLE_LOG_ENTRY table_log_entry; - DBUG_ENTER("execute_table_log_recovery"); - - no_entries= read_log_header(); - for (i= 0; i < no_entries; i++) - { - read_table_log_entry(i, &table_log_entry); - if (table_log_entry.entry_type == 'e') - { - if (execute_table_log_entry(table_log_entry.next_entry)) - { - /* error handling */ - DBUG_RETURN_VOID; - } - } - } - init_table_log(); - DBUG_RETURN_VOID; -} - - /* --------------------------------------------------------------------------- From e5200bc17d910718a5161ac590ccd49e80424ac5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 18:04:58 -0500 Subject: [PATCH 015/101] WL 2826: Error handling for ALTER TABLE for partitioning Step 13 Lots of compilation fixes sql/mysql_priv.h: Lots of compilation fixes sql/sql_partition.cc: Lots of compilation fixes sql/sql_table.cc: Lots of compilation fixes --- sql/mysql_priv.h | 8 ++-- sql/sql_partition.cc | 56 +++++++++++------------ sql/sql_table.cc | 103 +++++++++++++++++++++++++------------------ 3 files changed, 91 insertions(+), 76 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3be2b4508f1..9c52a4c8028 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -647,7 +647,7 @@ my_error_inject(int value) } #define ERROR_INJECT_CRASH(code) \ - DBUG_EXECUTE_COND(code, abort();) + DBUG_EXECUTE_COND(code, abort()) #define ERROR_INJECT_ACTION(code, action) \ (my_error_inject_name(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ @@ -1171,9 +1171,9 @@ typedef struct st_table_log_entry typedef struct st_table_log_memory_entry { uint entry_pos; - TABLE_LOG_MEMORY *next_log_entry; - TABLE_LOG_MEMORY *prev_log_entry; - TABLE_LOG_MEMORY *next_active_log_entry; + struct st_table_log_memory_entry *next_log_entry; + struct st_table_log_memory_entry *prev_log_entry; + struct st_table_log_memory_entry *next_active_log_entry; } TABLE_LOG_MEMORY_ENTRY; bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 816f2cda157..deb47e76771 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5409,25 +5409,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, to test if recovery is properly done. */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECT_CRASH(1000) || + ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECT_CRASH(1001) || + ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || - ERROR_INJECT_CRASH(1002) || + ERROR_INJECT_CRASH("crash_drop_partition_3") || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH(1003) || + ERROR_INJECT_CRASH("crash_drop_partition_4") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH(1004) || + ERROR_INJECT_CRASH("crash_drop_partition_5") || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH(1005) || + ERROR_INJECT_CRASH("crash_drop_partition_6") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH(1006) || + ERROR_INJECT_CRASH("crash_drop_partition_7") || write_log_completed(lpt) || - ERROR_INJECT_CRASH(1007) || + ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); @@ -5465,25 +5465,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 9) Complete query */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECT_CRASH(1010) || + ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECT_CRASH(1011) || + ERROR_INJECT_CRASH("crash_add_partition_2") || write_log_add_partition(lpt) || - ERROR_INJECT_CRASH(1012) || + ERROR_INJECT_CRASH("crash_add_partition_3") || mysql_change_partitions(lpt) || - ERROR_INJECT_CRASH(1013) || + ERROR_INJECT_CRASH("crash_add_partition_4") || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH(1014) || + ERROR_INJECT_CRASH("crash_add_partition_5") || write_log_shadow_frm(lpt, TRUE) || - ERROR_INJECT_CRASH(1015) || + ERROR_INJECT_CRASH("crash_add_partition_6") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH(1016) || + ERROR_INJECT_CRASH("crash_add_partition_7") || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECT_CRASH(1017)) + ERROR_INJECT_CRASH("crash_add_partition_8")) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5546,32 +5546,32 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECT_CRASH(1020) || + ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECT_CRASH(1021) || + ERROR_INJECT_CRASH("crash_change_partition_2") || write_log_ph1_change_partition(lpt) || - ERROR_INJECT_CRASH(1022) || + ERROR_INJECT_CRASH("crash_change_partition_3") || mysql_change_partitions(lpt) || - ERROR_INJECT_CRASH(1023) || + ERROR_INJECT_CRASH("crash_change_partition_4") || write_log_ph2_change_partition(lpt) || - ERROR_INJECT_CRASH(1024) || + ERROR_INJECT_CRASH("crash_change_partition_5") || abort_and_upgrade_lock(lpt) || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH(1025) || + ERROR_INJECT_CRASH("crash_change_partition_6") || mysql_rename_partitions(lpt) || - ERROR_INJECT_CRASH(1026) || + ERROR_INJECT_CRASH("crash_change_partition_7") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH(1027) || + ERROR_INJECT_CRASH("crash_change_partition_8") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH(1028) || + ERROR_INJECT_CRASH("crash_change_partition_9") || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH(1029) || + ERROR_INJECT_CRASH("crash_change_partition_10") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH(1030) || + ERROR_INJECT_CRASH("crash_change_partition_11") || write_log_completed(lpt) || - ERROR_INJECT_CRASH(1031) || + ERROR_INJECT_CRASH("crash_change_partition_12") || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8934f4be90f..f45ce41741a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -357,7 +357,7 @@ write_table_log_header() DBUG_ENTER("write_table_log_header"); int4store(&global_table_log.file_entry[0], global_table_log.no_entries); - const_var= NAMELEN; + const_var= FN_LEN; int2store(&global_table_log.file_entry[4], const_var); const_var= 32; int2store(&global_table_log.file_entry[6], const_var); @@ -428,11 +428,12 @@ read_table_log_header() { char *file_entry= (char*)global_table_log.file_entry; char file_name[FN_REFLEN]; + uint entry_no; DBUG_ENTER("read_table_log_header"); bzero(file_entry, sizeof(global_table_log.file_entry)); create_table_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_TRUNC, MYF(0)))) + if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(0)))) { if (read_table_log_file_entry(0UL)) { @@ -467,10 +468,10 @@ bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) { char *file_entry= (char*)&global_table_log.file_entry; + uint inx; DBUG_ENTER("read_table_log_entry"); - if (read_table_log_file_entry(global_table_log.file_id, - (char*)&file_entry, read_entry)) + if (read_table_log_file_entry(read_entry)) { /* Error handling */ DBUG_RETURN(TRUE); @@ -479,10 +480,10 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) table_log_entry->action_type= file_entry[1]; table_log_entry->next_entry= uint4korr(&file_entry[2]); table_log_entry->name= &file_entry[6]; - index= 6 + global_table_log->name_len; - table_log_entry->from_name= &file_entry[index]; - index+= global_table_log->name_len; - table_log_entry->handler_type= &file_entry[index]; + inx= 6 + global_table_log.name_len; + table_log_entry->from_name= &file_entry[inx]; + inx+= global_table_log.name_len; + table_log_entry->handler_type= &file_entry[inx]; DBUG_RETURN(FALSE); } @@ -508,10 +509,11 @@ init_table_log() DBUG_ENTER("init_table_log"); create_table_log_file_name(file_name); - VOID(my_delete(file_name)); + VOID(my_delete(file_name, MYF(0))); if ((global_table_log.file_id= my_create(file_name, CREATE_MODE, - create_flags, MYF(0))) < 0) + O_RDWR | O_TRUNC | O_BINARY, + MYF(0))) < 0) { /* Couldn't create table log file, this is serious error */ abort(); @@ -556,28 +558,31 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) static bool -get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry) +get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, + bool *write_header) { - bool write_header; + uint entry_no; TABLE_LOG_MEMORY_ENTRY *used_entry; TABLE_LOG_MEMORY_ENTRY *first_used= global_table_log.first_used; + DBUG_ENTER("get_free_table_log_entry"); + if (global_table_log.first_free == NULL) { - if (!(used_entry= my_malloc(sizeof(TABLE_LOG_MEMORY_ENTRY)))) + if (!(used_entry= (TABLE_LOG_MEMORY_ENTRY*)my_malloc( + sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(0)))) { DBUG_RETURN(TRUE); } global_table_log.no_entries++; - used_entry->entry_no= entry_no= global_table_log.no_entries; - write_header= TRUE; + used_entry->entry_pos= entry_no= global_table_log.no_entries; + *write_header= TRUE; } else { used_entry= global_table_log.first_free; global_table_log.first_free= used_entry->next_log_entry; - entry_no= first_free->entry_pos; - used_entry= first_free; - write_header= FALSE; + entry_no= used_entry->entry_pos; + *write_header= FALSE; } /* Move from free list to used list @@ -589,6 +594,7 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry) first_used->prev_log_entry= used_entry; *active_entry= used_entry; + DBUG_RETURN(FALSE); } @@ -616,7 +622,7 @@ bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, TABLE_LOG_MEMORY_ENTRY **active_entry) { - bool error; + bool error, write_header; DBUG_ENTER("write_table_log_entry"); global_table_log.file_entry[0]= 'i'; @@ -624,24 +630,25 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, int4store(&global_table_log.file_entry[2], table_log_entry->next_entry); strcpy(&global_table_log.file_entry[6], table_log_entry->name); - if (table_log_entry.action_type == 'r') - global_table_log.file_entry[6 + NAMELEN]= 0; + if (table_log_entry->action_type == 'r') + global_table_log.file_entry[6 + FN_LEN]= 0; else - strcpy(&global_table_log.file_entry[6 + NAMELEN], + strcpy(&global_table_log.file_entry[6 + FN_LEN], table_log_entry->from_name); - strcpy(&global_table_log.file_entry[6 + (2*NAMELEN)], + strcpy(&global_table_log.file_entry[6 + (2*FN_LEN)], table_log_entry->handler_type); - if (get_free_table_log_entry(active_entry)) + if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } error= FALSE; - if (write_table_log_file_entry(global_table_log.file_id, - global_table_log.file_entry, - (*active_entry)->entry_pos)) - error= TRUE; - else if (write_header || !(write_table_log_header())) + if (write_table_log_file_entry((*active_entry)->entry_pos)) error= TRUE; + if (write_header && !error) + { + if (sync_table_log() || write_table_log_header()) + error= TRUE; + } if (error) release_table_log_memory_entry(*active_entry); DBUG_RETURN(error); @@ -673,6 +680,7 @@ bool write_execute_table_log_entry(uint first_entry, TABLE_LOG_MEMORY_ENTRY **active_entry) { + bool write_header; char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); @@ -681,9 +689,9 @@ write_execute_table_log_entry(uint first_entry, file_entry[1]= 0; /* Ignored for execute entries */ int4store(&file_entry[2], first_entry); file_entry[6]= 0; - file_entry[6 + NAMELEN]= 0; - file_entry[6 + 2*NAMELEN]= 0; - if (get_free_table_log_entry(active_entry)) + file_entry[6 + FN_LEN]= 0; + file_entry[6 + 2*FN_LEN]= 0; + if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } @@ -693,6 +701,14 @@ write_execute_table_log_entry(uint first_entry, DBUG_RETURN(TRUE); } VOID(sync_table_log()); + if (write_header) + { + if (write_table_log_header()) + { + release_table_log_memory_entry(*active_entry); + DBUG_RETURN(TRUE); + } + } DBUG_RETURN(FALSE); } @@ -723,7 +739,7 @@ release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) global_table_log.first_used= next_log_entry; if (next_log_entry) next_log_entry->prev_log_entry= prev_log_entry; - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -738,7 +754,6 @@ release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) FALSE Success */ -static bool execute_table_log_entry(uint first_entry) { @@ -781,7 +796,7 @@ execute_table_log_recovery() TABLE_LOG_ENTRY table_log_entry; DBUG_ENTER("execute_table_log_recovery"); - no_entries= read_log_header(); + no_entries= read_table_log_header(); for (i= 0; i < no_entries; i++) { if (read_table_log_entry(i, &table_log_entry)) @@ -799,12 +814,12 @@ execute_table_log_recovery() never end up here */ abort(); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } } } VOID(init_table_log()); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -826,17 +841,17 @@ release_table_log() VOID(pthread_mutex_destroy(&LOCK_gtl)); while (used_list) { - TABLE_LOG_MEMORY_ENTRY tmp= used_list; - my_free(used_list, MYF(0)); + TABLE_LOG_MEMORY_ENTRY *tmp= used_list; + my_free((char*)used_list, MYF(0)); used_list= tmp->next_log_entry; } while (free_list) { - TABLE_LOG_MEMORY_ENTRY tmp= free_list; - my_free(free_list, MYF(0)); + TABLE_LOG_MEMORY_ENTRY *tmp= free_list; + my_free((char*)free_list, MYF(0)); free_list= tmp->next_log_entry; } - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -854,7 +869,7 @@ lock_global_table_log() DBUG_ENTER("lock_global_table_log"); VOID(pthread_mutex_lock(&LOCK_gtl)); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -872,7 +887,7 @@ unlock_global_table_log() DBUG_ENTER("unlock_global_table_log"); VOID(pthread_mutex_unlock(&LOCK_gtl)); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } From 256d85273205f1387e9b9faa4ded94080609ce64 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 20:26:56 -0500 Subject: [PATCH 016/101] WL 2826: Error handling of ALTER TABLE for partitioning Close down table log also at exit of main thread sql/mysqld.cc: Close down table log also at exit of main thread sql/sql_table.cc: Close down table log also at exit of main thread --- sql/mysqld.cc | 1 + sql/sql_table.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7f7cf957477..80cb4333725 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3708,6 +3708,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); + release_table_log(); #ifndef __WIN__ #ifdef EXTRA_DEBUG2 diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f45ce41741a..5477a8a33fa 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -851,6 +851,7 @@ release_table_log() my_free((char*)free_list, MYF(0)); free_list= tmp->next_log_entry; } + VOID(my_close(global_table_log.file_id, MYF(0))); DBUG_VOID_RETURN; } From 836912d1c7a8c1118786e791ebe8e514461dfa8b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 11:05:05 +0100 Subject: [PATCH 017/101] WL 2826: Error handling for ALTER TABLE for partitioning Step 14: First version of table log for add/Drop partition sql/ha_partition.cc: Moved create partition name code to sql_partition.cc sql/handler.h: Added entries in partition_info to keep track of table log entries sql/mysql_priv.h: Moved create partition name code to sql_partition.cc sql/sql_partition.cc: Moved create partition name code to sql_partition.cc First version of table log for add/drop partition sql/sql_table.cc: Add IO_SIZE to table log header --- sql/ha_partition.cc | 82 ------------ sql/handler.h | 6 +- sql/mysql_priv.h | 10 ++ sql/sql_partition.cc | 298 ++++++++++++++++++++++++++++++++++++++++++- sql/sql_table.cc | 11 +- 5 files changed, 321 insertions(+), 86 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 193fe863f8c..80047d438e1 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -391,88 +391,6 @@ int ha_partition::ha_initialise() /**************************************************************************** MODULE meta data changes ****************************************************************************/ -/* - Create partition names - - SYNOPSIS - create_partition_name() - out:out Created partition name string - in1 First part - in2 Second part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the partition name, service routine to - the del_ren_cre_table method. -*/ - -#define NORMAL_PART_NAME 0 -#define TEMP_PART_NAME 1 -#define RENAMED_PART_NAME 2 -static void create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate) -{ - char transl_part_name[FN_REFLEN]; - const char *transl_part; - - if (translate) - { - tablename_to_filename(in2, transl_part_name, FN_REFLEN); - transl_part= transl_part_name; - } - else - transl_part= in2; - if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part, NullS); - else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); -} - -/* - Create subpartition name - - SYNOPSIS - create_subpartition_name() - out:out Created partition name string - in1 First part - in2 Second part - in3 Third part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the subpartition name, service routine to - the del_ren_cre_table method. -*/ - -static void create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant) -{ - char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; - - tablename_to_filename(in2, transl_part_name, FN_REFLEN); - tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); - if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, NullS); - else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#REN#", NullS); -} - - /* Delete a table diff --git a/sql/handler.h b/sql/handler.h index b6a925695b8..205f137e28a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -799,6 +799,8 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, PARTITION_ITERATOR *part_iter); +struct TABLE_LOG_MEMORY_ENTRY; + class partition_info : public Sql_alloc { public: @@ -845,7 +847,9 @@ public: Item *subpart_expr; Item *item_free_list; - + + TABLE_LOG_MEMORY_ENTRY *first_log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry; /* A bitmap of partitions used by the current query. Usage pattern: diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9c52a4c8028..fe6babaea66 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1135,6 +1135,16 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, bool remove_table_from_cache(THD *thd, const char *db, const char *table, uint flags); +#define NORMAL_PART_NAME 0 +#define TEMP_PART_NAME 1 +#define RENAMED_PART_NAME 2 +void create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate); +void create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant); + typedef struct st_lock_param_type { ulonglong copied; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index deb47e76771..8c5c1016097 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5063,6 +5063,50 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Insert log entry into list + SYNOPSIS + insert_part_info_log_entry_list() + log_entry + RETURN VALUES + NONE +*/ + +static +void +insert_part_info_log_entry_list(partition_info *part_info, + TABLE_LOG_MEMORY_ENTRY *log_entry) +{ + log_entry->next_active_log_entry= part_info->first_log_entry; + part_info->first_log_entry= log_entry; +} + + +/* + Release all log entries for this partition info struct + SYNOPSIS + release_part_info_log_entries() + first_log_entry First log entry in list to release + RETURN VALUES + NONE +*/ + +static +void +release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) +{ + DBUG_ENTER("release_part_info_log_entries"); + + while (log_entry) + { + release_table_log_memory_entry(log_entry); + log_entry= log_entry->next_log_entry; + } + part_info->first_log_entry= NULL; + DBUG_VOID_RETURN; +} + + /* Write the log entry to ensure that the shadow frm file is removed at crash. @@ -5082,11 +5126,111 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) { + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char shadow_path[FN_LEN]; DBUG_ENTER("write_log_shadow_frm"); lock_global_table_log(); + do + { + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + table_log_entry.action_type= 'd'; + table_log_entry.next_entry= 0; + table_log_entry.handler_type= "frm"; + table_log_entry.name= shadow_path; + + if (write_table_log_entry(&table_log_entry, &log_entry)) + break; + insert_part_info_log_entry_list(part_info, log_entry); + if (write_execute_table_log_entry(log_entry->entry_pos, &log_entry)) + break; + part_info->exec_log_entry= log_entry; + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); + DBUG_RETURN(TRUE); +} + + +/* + Log dropped partitions + SYNOPSIS + write_log_dropped_partitions() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, + const char *path) +{ + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + List_iterator part_it(part_info->partitions); + uint no_elements= part_info->partitions.elements; + DBUG_ENTER("write_log_dropped_partitions"); + + table_log_entry.action_type= 'd'; + do + { + partition_element part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED || + part_elem->part_state == PART_TO_BE_ADDED) + { + if (is_sub_partitioned(part_info)) + { + List_iterator sub_it(part_elem->subpartitions); + uint no_subparts= part_info->no_subparts; + do + { + partition_element *sub_elem= sub_it++; + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(sub_elem->engine_type); + create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME); + table_log_entry.name= tmp_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + insert_part_info_log_entry_list(part_info, log_entry); + } while (++i < no_subparts); + } + else + { + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(part_elem->engine_type); + create_partition_name(tmp_path, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE); + table_log_entry.name= tmp_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + insert_part_info_log_entry_list(part_info, log_entry); + } + } + } while (++i < no_elements); DBUG_RETURN(FALSE); +error: } @@ -5108,11 +5252,47 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char path[FN_LEN]; + uint next_entry= 0; + TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_partition"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); lock_global_table_log(); + do + { + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + break; + /* + At first we write an entry that installs the new frm file + */ + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); + table_log_entry.action_type= 'r'; + table_log_entry.next_entry= next_entry; + table_log_entry.handler_type= "frm"; + table_log_entry.name= path; + table_log_entry.from_name= tmp_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + break; + insert_part_info_log_entry_list(part_info, log_entry); + log_entry= part_info->exec_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_log_entry; unlock_global_table_log(); - DBUG_RETURN(FALSE); + DBUG_RETURN(TRUE); } @@ -5129,16 +5309,48 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DESCRIPTION Prepare entries to the table log indicating all partitions to drop and to remove the shadow frm file. + The removal of the shadow frm file is already in the log file so we only + need to link the new entries to the existing and carefully ensure that + the new linked list has first the dropped partitions and then the + drop of the shadow frm file. + We always inject entries backwards in the list in the table log since we + don't know the entry position until we have written it. */ bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_add_partition"); + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char path[FN_LEN]; + TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; + uint next_entry= old_log_entry->entry_pos; + /* Ensure we linked the existing entries at the back */ + DBUG_ENTER("write_log_add_partition"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); lock_global_table_log(); + do + { + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + break; + log_entry= part_info->first_log_entry; + /* Ensure first entry is the last dropped partition */ + if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_log_entry; unlock_global_table_log(); - DBUG_RETURN(FALSE); + DBUG_RETURN(TRUE); } @@ -6182,5 +6394,87 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) part_iter->field_vals.start++; return part_iter->part_info->get_subpartition_id(part_iter->part_info); } + + +/* + Create partition names + + SYNOPSIS + create_partition_name() + out:out Created partition name string + in1 First part + in2 Second part + name_variant Normal, temporary or renamed partition name + + RETURN VALUE + NONE + + DESCRIPTION + This method is used to calculate the partition name, service routine to + the del_ren_cre_table method. +*/ + +void +create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate) +{ + char transl_part_name[FN_REFLEN]; + const char *transl_part; + + if (translate) + { + tablename_to_filename(in2, transl_part_name, FN_REFLEN); + transl_part= transl_part_name; + } + else + transl_part= in2; + if (name_variant == NORMAL_PART_NAME) + strxmov(out, in1, "#P#", transl_part, NullS); + else if (name_variant == TEMP_PART_NAME) + strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); + else if (name_variant == RENAMED_PART_NAME) + strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); +} + + +/* + Create subpartition name + + SYNOPSIS + create_subpartition_name() + out:out Created partition name string + in1 First part + in2 Second part + in3 Third part + name_variant Normal, temporary or renamed partition name + + RETURN VALUE + NONE + + DESCRIPTION + This method is used to calculate the subpartition name, service routine to + the del_ren_cre_table method. +*/ + +void +create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant) +{ + char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; + + tablename_to_filename(in2, transl_part_name, FN_REFLEN); + tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); + if (name_variant == NORMAL_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, NullS); + else if (name_variant == TEMP_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#TMP#", NullS); + else if (name_variant == RENAMED_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#REN#", NullS); +} #endif diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f45ce41741a..c6c76a833ab 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -282,6 +282,7 @@ typedef struct st_global_table_log File file_id; uint name_len; uint handler_type_len; + uint io_size; } GLOBAL_TABLE_LOG; GLOBAL_TABLE_LOG global_table_log; @@ -361,6 +362,8 @@ write_table_log_header() int2store(&global_table_log.file_entry[4], const_var); const_var= 32; int2store(&global_table_log.file_entry[6], const_var); + const_var= IO_SIZE; + int4store(&global_table_log.file_entry[8], const_var); if (write_table_log_file_entry(0UL)) error= TRUE; DBUG_RETURN(error); @@ -384,9 +387,10 @@ read_table_log_file_entry(uint entry_no) bool error= FALSE; File file_id= global_table_log.file_id; char *file_entry= (char*)global_table_log.file_entry; + uint io_size= global_table_log.io_size; DBUG_ENTER("read_table_log_file_entry"); - if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) error= TRUE; DBUG_RETURN(error); } @@ -429,6 +433,7 @@ read_table_log_header() char *file_entry= (char*)global_table_log.file_entry; char file_name[FN_REFLEN]; uint entry_no; + bool successful_open= FALSE; DBUG_ENTER("read_table_log_header"); bzero(file_entry, sizeof(global_table_log.file_entry)); @@ -439,10 +444,14 @@ read_table_log_header() { /* Write message into error log */ } + else + successful_open= TRUE; } entry_no= uint4korr(&file_entry[0]); global_table_log.name_len= uint2korr(&file_entry[4]); global_table_log.handler_type_len= uint2korr(&file_entry[6]); + if (successful_open) + global_table_log.io_size= uint4korr(&file_entry[8]); global_table_log.first_free= NULL; global_table_log.first_used= NULL; global_table_log.no_entries= 0; From cd653ed9ec12bcd125a0852fb0c0a58f95b4c354 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 14:13:22 -0500 Subject: [PATCH 018/101] WL 2826: Error handling of ALTER TABLE for partitioning A number of fixes sql/handler.h: A numbre of fixes sql/mysql_priv.h: A numbre of fixes sql/share/errmsg.txt: A numbre of fixes sql/sql_partition.cc: A numbre of fixes sql/sql_table.cc: A numbre of fixes --- sql/handler.h | 7 ++++--- sql/mysql_priv.h | 1 + sql/share/errmsg.txt | 2 ++ sql/sql_partition.cc | 33 +++++++++++++++++++-------------- sql/sql_table.cc | 14 +++++++++----- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 205f137e28a..00bfaa77e91 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -799,7 +799,7 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, PARTITION_ITERATOR *part_iter); -struct TABLE_LOG_MEMORY_ENTRY; +struct st_table_log_memory_entry; class partition_info : public Sql_alloc { @@ -848,8 +848,8 @@ public: Item *item_free_list; - TABLE_LOG_MEMORY_ENTRY *first_log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry; + st_table_log_memory_entry *first_log_entry; + st_table_log_memory_entry *exec_log_entry; /* A bitmap of partitions used by the current query. Usage pattern: @@ -961,6 +961,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), + first_log_entry(NULL), exec_log_entry(NULL), list_array(NULL), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fe6babaea66..d22f894e43d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1164,6 +1164,7 @@ typedef struct st_lock_param_type uint key_count; uint db_options; uint pack_frm_len; + partition_info *part_info; } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 80910a8fd81..017b7f5db05 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5798,3 +5798,5 @@ ER_CANT_WRITE_LOCK_LOG_TABLE eng "You can't write-lock a log table. Only read access is possible." ER_CANT_READ_LOCK_LOG_TABLE eng "You can't use usual read lock with log tables. Try READ LOCAL instead." +ER_TABLE_LOG_ERROR + eng "Error in table log" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8c5c1016097..71d6d7b200c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5102,7 +5102,6 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) release_table_log_memory_entry(log_entry); log_entry= log_entry->next_log_entry; } - part_info->first_log_entry= NULL; DBUG_VOID_RETURN; } @@ -5129,6 +5128,7 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char shadow_path[FN_LEN]; DBUG_ENTER("write_log_shadow_frm"); @@ -5145,14 +5145,16 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, &log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) break; - part_info->exec_log_entry= log_entry; + part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= NULL; unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5179,12 +5181,13 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); uint no_elements= part_info->partitions.elements; + uint i; DBUG_ENTER("write_log_dropped_partitions"); table_log_entry.action_type= 'd'; do { - partition_element part_elem= part_it++; + partition_element *part_elem= part_it++; if (part_elem->part_state == PART_TO_BE_DROPPED || part_elem->part_state == PART_TO_BE_ADDED) { @@ -5230,7 +5233,6 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } } while (++i < no_elements); DBUG_RETURN(FALSE); -error: } @@ -5255,10 +5257,11 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; - TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_partition"); part_info->first_log_entry= NULL; @@ -5282,16 +5285,16 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - log_entry= part_info->exec_log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_log_entry; + part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5320,14 +5323,14 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - DBUG_ENTER("write_log_add_partition"); TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; - uint next_entry= old_log_entry->entry_pos; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + uint next_entry= old_first_log_entry->entry_pos; /* Ensure we linked the existing entries at the back */ DBUG_ENTER("write_log_add_partition"); @@ -5341,15 +5344,16 @@ write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) break; log_entry= part_info->first_log_entry; /* Ensure first entry is the last dropped partition */ - if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_log_entry; + part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5473,6 +5477,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, DBUG_ENTER("fast_alter_partition_table"); lpt->thd= thd; + lpt->part_info= part_info; lpt->create_info= create_info; lpt->create_list= create_list; lpt->key_list= key_list; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 37cd6397dbc..5699c404899 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -334,7 +334,8 @@ write_table_log_file_entry(uint entry_no) char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_table_log_file_entry"); - if (my_pwrite(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + if (my_pwrite(file_id, file_entry, + IO_SIZE, IO_SIZE * entry_no, MYF(0)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); } @@ -640,10 +641,10 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, table_log_entry->next_entry); strcpy(&global_table_log.file_entry[6], table_log_entry->name); if (table_log_entry->action_type == 'r') - global_table_log.file_entry[6 + FN_LEN]= 0; - else strcpy(&global_table_log.file_entry[6 + FN_LEN], table_log_entry->from_name); + else + global_table_log.file_entry[6 + FN_LEN]= 0; strcpy(&global_table_log.file_entry[6 + (2*FN_LEN)], table_log_entry->handler_type); if (get_free_table_log_entry(active_entry, &write_header)) @@ -700,9 +701,12 @@ write_execute_table_log_entry(uint first_entry, file_entry[6]= 0; file_entry[6 + FN_LEN]= 0; file_entry[6 + 2*FN_LEN]= 0; - if (get_free_table_log_entry(active_entry, &write_header)) + if (!(*active_entry)) { - DBUG_RETURN(TRUE); + if (get_free_table_log_entry(active_entry, &write_header)) + { + DBUG_RETURN(TRUE); + } } if (write_table_log_file_entry((*active_entry)->entry_pos)) { From d7bd607db0140960bc82415cc87c2d9b0cd824e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 14:20:20 -0500 Subject: [PATCH 019/101] WL 2826: Error handling of ALTER TABLE for partitioning More fixes sql/sql_partition.cc: More fixes --- sql/sql_partition.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 71d6d7b200c..c6498c6fa1b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5181,7 +5181,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); uint no_elements= part_info->partitions.elements; - uint i; + uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); table_log_entry.action_type= 'd'; @@ -5195,6 +5195,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, { List_iterator sub_it(part_elem->subpartitions); uint no_subparts= part_info->no_subparts; + uint j= 0; do { partition_element *sub_elem= sub_it++; @@ -5212,7 +5213,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } *next_entry= log_entry->entry_pos; insert_part_info_log_entry_list(part_info, log_entry); - } while (++i < no_subparts); + } while (++j < no_subparts); } else { From 392b82a10a0ce5ef960d079db84233d626e6a7f3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 20:20:21 +0100 Subject: [PATCH 020/101] WL 2826: Error handling of ALTER TABLE for partitioning A little more complete handling sql/mysql_priv.h: Complete flag sql/sql_table.cc: A little more complete handling sql/sql_partition.cc: A little more complete handling --- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 25 ++++++++++++++++++++----- sql/sql_table.cc | 12 ++++++++++-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d22f894e43d..cde050e877b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1190,6 +1190,7 @@ typedef struct st_table_log_memory_entry bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, TABLE_LOG_MEMORY_ENTRY **active_entry); bool write_execute_table_log_entry(uint first_entry, + bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry); void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); void release_table_log(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c6498c6fa1b..f0f22b4d927 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5100,7 +5100,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) while (log_entry) { release_table_log_memory_entry(log_entry); - log_entry= log_entry->next_log_entry; + log_entry= log_entry->next_active_log_entry; } DBUG_VOID_RETURN; } @@ -5145,7 +5145,8 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) break; part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); @@ -5286,7 +5287,8 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); @@ -5345,7 +5347,8 @@ write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) break; log_entry= part_info->first_log_entry; /* Ensure first entry is the last dropped partition */ - if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); @@ -5426,9 +5429,21 @@ static bool write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) { - DBUG_ENTER("write_log_ph2_change_partition"); + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; + DBUG_ENTER("write_log_completed"); lock_global_table_log(); + DBUG_ASSERT(part_info->exec_log_entry); + if (write_execute_table_log_entry(0UL, TRUE, &part_info->exec_log_entry)) + { + DBUG_RETURN(TRUE); + } + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= NULL; + part_info->exec_log_entry->next_active_log_entry= NULL; + release_part_info_log_entries(part_info->exec_log_entry); + part_info->exec_log_entry= NULL; unlock_global_table_log(); DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5699c404899..4568b6a92ae 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -367,6 +367,8 @@ write_table_log_header() int4store(&global_table_log.file_entry[8], const_var); if (write_table_log_file_entry(0UL)) error= TRUE; + if (!error) + error= sync_table_log(); DBUG_RETURN(error); } @@ -688,14 +690,20 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, bool write_execute_table_log_entry(uint first_entry, + bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry) { bool write_header; char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); - VOID(sync_table_log()); - file_entry[0]= 'e'; + if (!complete) + { + VOID(sync_table_log()); + file_entry[0]= 'e'; + } + else + file_entry[0]= 'i'; file_entry[1]= 0; /* Ignored for execute entries */ int4store(&file_entry[2], first_entry); file_entry[6]= 0; From ddb14e0f238d92cd55dcd594815ae6bfa8f3577e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 20:20:22 +0100 Subject: [PATCH 021/101] WL 2826: Error handling of ALTER TABLE for partitioning More work on table logging of ALTER TABLE for partitioning sql/mysql_priv.h: More work on table logging of ALTER TABLE for partitioning sql/sql_partition.cc: More work on table logging of ALTER TABLE for partitioning --- sql/mysql_priv.h | 6 - sql/sql_partition.cc | 362 ++++++++++++++++++++++++++++--------------- 2 files changed, 233 insertions(+), 135 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index cde050e877b..e0875b06a0a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1199,12 +1199,6 @@ bool execute_table_log_entry(uint first_entry); void lock_global_table_log(); void unlock_global_table_log(); -bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); -bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); -bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt); -bool write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); -bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); - #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f0f22b4d927..ea358154b1c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5107,56 +5107,48 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) /* - Write the log entry to ensure that the shadow frm file is removed at - crash. + Log an delete/rename frm file SYNOPSIS - write_log_shadow_frm() - lpt Struct containing parameters - install_frm Should we log action to install shadow frm or should - the action be to remove the shadow frm file. + write_log_rename_delete_frm() + lpt Struct for parameters + next_entry Next reference to use in log record + path Name to rename from + rename_flag TRUE if rename, else delete RETURN VALUES - TRUE Error - FALSE Success + TRUE Error + FALSE Success DESCRIPTION - Prepare an entry to the table log indicating a drop/install of the shadow frm - file and its corresponding handler file. + Support routine that writes a rename or delete of an frm file into the + table log. It also inserts an entry that keeps track of used space into + the partition info object */ bool -write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) +write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, + uint next_entry, + const char *from_path + const char *to_path, + bool rename_flag) { TABLE_LOG_ENTRY table_log_entry; - partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; - char shadow_path[FN_LEN]; - DBUG_ENTER("write_log_shadow_frm"); + DBUG_ENTER("write_log_rename_frm"); - lock_global_table_log(); - do - { - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); + if (rename_flag) + table_log_entry.action_type= 'r'; + else table_log_entry.action_type= 'd'; - table_log_entry.next_entry= 0; - table_log_entry.handler_type= "frm"; - table_log_entry.name= shadow_path; - - if (write_table_log_entry(&table_log_entry, &log_entry)) - break; - insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - part_info->exec_log_entry= exec_log_entry; - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); - release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; - unlock_global_table_log(); - my_error(ER_TABLE_LOG_ERROR, MYF(0)); - DBUG_RETURN(TRUE); + table_log_entry.next_entry= next_entry; + table_log_entry.handler_type= "frm"; + if (rename_flag) + table_log_entry.name= to_path; + table_log_entry.from_name= from_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + insert_part_info_log_entry_list(part_info, log_entry); + DBUG_RETURN(FALSE); } @@ -5174,24 +5166,41 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint *next_entry, - const char *path) + const char *path, + bool temp_list) { TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; 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 i= 0; DBUG_ENTER("write_log_dropped_partitions"); table_log_entry.action_type= 'd'; - do + if (temp_list) + no_elements= no_temp_partitions; + while (no_elements--) { - partition_element *part_elem= part_it++; + partition_element *part_elem; + if (temp_list) + part_elem= temp_it++; + else + part_elem= part_it++; if (part_elem->part_state == PART_TO_BE_DROPPED || - part_elem->part_state == PART_TO_BE_ADDED) + part_elem->part_state == PART_TO_BE_ADDED || + part_elem->part_state == PART_CHANGED) { + uint name_variant; + if (part_elem->part_state == PART_CHANGED || + (part_elem->part_state == PART_TO_BE_ADDED && + no_temp_partitions)) + name_variant= TEMP_PART_NAME; + else + name_variant= NORMAL_PART_NAME; if (is_sub_partitioned(part_info)) { List_iterator sub_it(part_elem->subpartitions); @@ -5202,11 +5211,11 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, partition_element *sub_elem= sub_it++; table_log_entry.next_entry= *next_entry; table_log_entry.handler_type= - ha_resolve_storage_engine_name(sub_elem->engine_type); + ha_resolve_storage_engine_name(sub_elem->engine_type); create_subpartition_name(tmp_path, path, part_elem->partition_name, sub_elem->partition_name, - NORMAL_PART_NAME); + name_variant); table_log_entry.name= tmp_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { @@ -5223,7 +5232,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ha_resolve_storage_engine_name(part_elem->engine_type); create_partition_name(tmp_path, path, part_elem->partition_name, - NORMAL_PART_NAME, TRUE); + name_variant, TRUE); table_log_entry.name= tmp_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { @@ -5233,11 +5242,112 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, insert_part_info_log_entry_list(part_info, log_entry); } } - } while (++i < no_elements); + } DBUG_RETURN(FALSE); } +/* + Write the log entry to ensure that the shadow frm file is removed at + crash. + SYNOPSIS + write_log_drop_shadow_frm() + lpt Struct containing parameters + install_frm Should we log action to install shadow frm or should + the action be to remove the shadow frm file. + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to the table log indicating a drop/install of the shadow frm + file and its corresponding handler file. +*/ + +static +bool +write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + char shadow_path[FN_LEN]; + DBUG_ENTER("write_log_drop_shadow_frm"); + + lock_global_table_log(); + do + { + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, 0UL, NULL, + (const char*)shadow_path, FALSE)) + break; + log_entry= part_info->first_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + break; + part_info->exec_log_entry= exec_log_entry; + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= NULL; + unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Log renaming of shadow frm to real frm name and dropping of old frm + SYNOPSIS + write_log_rename_frm() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to ensure that we complete the renaming of the frm + file if failure occurs in the middle of the rename process. +*/ + +static +bool +write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char shadow_path[FN_LEN]; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DBUG_ENTER("write_log_drop_shadow_frm"); + + lock_global_table_log(); + do + { + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + break; + log_entry= part_info->first_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_first_log_entry; + unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + /* Write the log entries to ensure that the drop partition command is completed even in the presence of a crash. @@ -5253,6 +5363,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, install the shadow frm file and remove the old frm file. */ +static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { @@ -5269,24 +5380,18 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), + FALSE) break; - /* - At first we write an entry that installs the new frm file - */ - build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, - lpt->table_name, "#"); - table_log_entry.action_type= 'r'; - table_log_entry.next_entry= next_entry; - table_log_entry.handler_type= "frm"; - table_log_entry.name= path; - table_log_entry.from_name= tmp_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + if (write_log_rename_delete_frm(lpt, next_entry, (const char*)path, + (const char*)tmp_path, TRUE)) break; - insert_part_info_log_entry_list(part_info, log_entry); + log_entry= part_info->first_log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5307,7 +5412,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) executed at all if a crash before it has completed SYNOPSIS - write_log_add_partition() + write_log_add_change_partition() lpt Struct containing parameters RETURN VALUES TRUE Error @@ -5315,85 +5420,55 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DESCRIPTION Prepare entries to the table log indicating all partitions to drop and to remove the shadow frm file. - The removal of the shadow frm file is already in the log file so we only - need to link the new entries to the existing and carefully ensure that - the new linked list has first the dropped partitions and then the - drop of the shadow frm file. We always inject entries backwards in the list in the table log since we don't know the entry position until we have written it. */ +static bool -write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *log_entry, *exec_log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; - uint next_entry= old_first_log_entry->entry_pos; - /* Ensure we linked the existing entries at the back */ - DBUG_ENTER("write_log_add_partition"); + uint next_entry= 0; + DBUG_ENTER("write_log_add_change_partition"); - part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), + FALSE) + break; + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, next_entry, tmp_path, + NULL, FALSE)) break; log_entry= part_info->first_log_entry; - /* Ensure first entry is the last dropped partition */ if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; - release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; + part_info->first_log_entry= NULL; unlock_global_table_log(); my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } -/* - Write indicator of how to abort in first phase of change partitions - SYNOPSIS - write_log_ph1_change_partition() - lpt Struct containing parameters - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Write the log entries to remove partitions in creation when changing - partitions in an ADD/REORGANIZE/COALESCE command. These commands will - abort the entire operation if the system crashes before the next phase - is done. -*/ - -bool -write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("write_log_ph1_change_partition"); - - lock_global_table_log(); - unlock_global_table_log(); - DBUG_RETURN(FALSE); -} - - /* Write description of how to complete the operation after first phase of change partitions. SYNOPSIS - write_log_ph2_change_partition() + write_log_final_change_partition() lpt Struct containing parameters RETURN VALUES TRUE Error @@ -5404,14 +5479,46 @@ write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) frm file. */ +static bool -write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - DBUG_ENTER("write_log_ph2_change_partition"); + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char shadow_path[FN_LEN]; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + uint next_entry= 0; + DBUG_ENTER("write_log_final_change_partition"); lock_global_table_log(); + do + { + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), + TRUE) + break; + if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) + break; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + break; + log_entry= part_info->first_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); - DBUG_RETURN(FALSE); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); } @@ -5425,6 +5532,7 @@ write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) TRUE Error FALSE Success */ + static bool write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) @@ -5641,7 +5749,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ - if (write_log_shadow_frm(lpt, FALSE) || + if (write_log_drop_shadow_frm(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_drop_partition_2") || @@ -5697,26 +5805,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 8) Remove entries from table log 9) Complete query */ - if (write_log_shadow_frm(lpt, FALSE) || + if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_2") || - write_log_add_partition(lpt) || - ERROR_INJECT_CRASH("crash_add_partition_3") || mysql_change_partitions(lpt) || - ERROR_INJECT_CRASH("crash_add_partition_4") || + ERROR_INJECT_CRASH("crash_add_partition_3") || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH("crash_add_partition_4") || + write_log_rename_frm(lpt) || ERROR_INJECT_CRASH("crash_add_partition_5") || - write_log_shadow_frm(lpt, TRUE) || - ERROR_INJECT_CRASH("crash_add_partition_6") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_add_partition_7") || + ERROR_INJECT_CRASH("crash_add_partition_6") || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECT_CRASH("crash_add_partition_8")) + ERROR_INJECT_CRASH("crash_add_partition_7")) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5778,33 +5884,31 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 14)Complete query */ - if (write_log_shadow_frm(lpt, FALSE) || + if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_2") || - write_log_ph1_change_partition(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_3") || mysql_change_partitions(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_3") || + write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || - write_log_ph2_change_partition(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_5") || abort_and_upgrade_lock(lpt) || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH("crash_change_partition_6") || + ERROR_INJECT_CRASH("crash_change_partition_5") || mysql_rename_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_7") || + ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_change_partition_8") || + ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_change_partition_9") || + ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_10") || + ERROR_INJECT_CRASH("crash_change_partition_9") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_11") || + ERROR_INJECT_CRASH("crash_change_partition_10") || write_log_completed(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_12") || + ERROR_INJECT_CRASH("crash_change_partition_11") || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); From 4bef9c0e0104d7fd2eca52275de070257e63aac3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 20:25:10 +0100 Subject: [PATCH 022/101] WL 2826: Error handling of ALTER TABLE for partitioning Error handling Crash if any error after reaching beyond certain point in ALTER TABLE processing sql/ha_partition.cc: Error handling Crash if any error after reaching beyond certain point in ALTER TABLE processing sql/sql_partition.cc: Error handling Crash if any error after reaching beyond certain point in ALTER TABLE processing --- sql/ha_partition.cc | 30 +++++++++++++++--------------- sql/sql_partition.cc | 27 +++++++++++++++++++-------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 80047d438e1..fade6803156 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -584,7 +584,7 @@ int ha_partition::drop_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; - int error= 1; + int error= 0; bool reorged_parts= (m_reorged_parts > 0); bool temp_partitions= (m_part_info->temp_partitions.elements > 0); DBUG_ENTER("ha_partition::drop_partitions"); @@ -632,7 +632,7 @@ int ha_partition::drop_partitions(const char *path) else file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); - error= file->delete_table((const char *) part_name_buff); + error+= file->delete_table((const char *) part_name_buff); } while (++j < no_subparts); } else @@ -645,7 +645,7 @@ int ha_partition::drop_partitions(const char *path) else file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - error= file->delete_table((const char *) part_name_buff); + error+= file->delete_table((const char *) part_name_buff); } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -687,7 +687,7 @@ int ha_partition::rename_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint j= 0; - int error= 1; + int error= 0; uint temp_partitions= m_part_info->temp_partitions.elements; handler *file; partition_element *part_elem, *sub_elem; @@ -715,8 +715,8 @@ int ha_partition::rename_partitions(const char *path) NORMAL_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } while (++j < no_subparts); } else @@ -730,8 +730,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } } while (++i < temp_partitions); } @@ -765,8 +765,8 @@ int ha_partition::rename_partitions(const char *path) RENAMED_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -775,8 +775,8 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - error= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + error+= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff); } while (++j < no_subparts); } else @@ -792,8 +792,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -801,7 +801,7 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - error= file->rename_table((const char *) part_name_buff, + error+= file->rename_table((const char *) part_name_buff, (const char *) norm_name_buff); } } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ea358154b1c..95bcc6279ac 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5749,12 +5749,14 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ + bool not_completed= TRUE; if (write_log_drop_shadow_frm(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || + (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -5763,7 +5765,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_5") || - table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || + (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_6") || mysql_drop_partitions(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_7") || @@ -5771,6 +5773,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { + if (!not_completed) + abort(); fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } @@ -5805,6 +5809,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 8) Remove entries from table log 9) Complete query */ + bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -5817,6 +5822,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_4") || write_log_rename_frm(lpt) || + (not_completed= FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_6") || @@ -5824,6 +5830,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_completed(lpt) || ERROR_INJECT_CRASH("crash_add_partition_7")) { + if (!not_completed) + abort(); fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } @@ -5883,7 +5891,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 13)Wait until all accesses using the old frm file has completed 14)Complete query */ - + bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -5892,14 +5900,15 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_3") || write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || + (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || - table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH("crash_change_partition_5") || - mysql_rename_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH("crash_change_partition_5") || + (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || + ERROR_INJECT_CRASH("crash_change_partition_6") || + mysql_rename_partitions(lpt) || ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_8") || @@ -5911,8 +5920,10 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_11") || (mysql_wait_completed_table(lpt, table), FALSE)) { - fast_alter_partition_error_handler(lpt); - DBUG_RETURN(TRUE); + if (!not_completed) + abort(); + fast_alter_partition_error_handler(lpt); + DBUG_RETURN(TRUE); } } /* From de3c77dfec05b6b7c8d985f46c2746bbe70e27bb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 21:23:45 -0500 Subject: [PATCH 023/101] WL 2826: Error handling of ALTER TABLE for partitioning Bug fixes sql/sql_partition.cc: Bug fixes --- sql/sql_partition.cc | 51 ++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ea358154b1c..98e13c1bca1 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5126,7 +5126,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) bool write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint next_entry, - const char *from_path + const char *from_path, const char *to_path, bool rename_flag) { @@ -5140,14 +5140,34 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, table_log_entry.action_type= 'd'; table_log_entry.next_entry= next_entry; table_log_entry.handler_type= "frm"; + table_log_entry.name= to_path; if (rename_flag) - table_log_entry.name= to_path; - table_log_entry.from_name= from_path; + table_log_entry.from_name= from_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } - insert_part_info_log_entry_list(part_info, log_entry); + insert_part_info_log_entry_list(lpt->part_info, log_entry); + DBUG_RETURN(FALSE); +} + + +/* + Log final partition changes in change partition + SYNOPSIS + write_log_changed_partitions() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, const char *path) +{ + DBUG_ENTER("write_log_changed_partitions"); DBUG_RETURN(FALSE); } @@ -5319,6 +5339,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char path[FN_LEN]; char shadow_path[FN_LEN]; TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_shadow_frm"); @@ -5385,8 +5406,8 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), - FALSE) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) break; if (write_log_rename_delete_frm(lpt, next_entry, (const char*)path, (const char*)tmp_path, TRUE)) @@ -5440,18 +5461,19 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), - FALSE) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) break; build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - if (write_log_rename_delete_frm(lpt, next_entry, tmp_path, - NULL, FALSE)) + if (write_log_rename_delete_frm(lpt, next_entry, NULL, tmp_path, + FALSE)) break; log_entry= part_info->first_log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; + part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); @@ -5487,6 +5509,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char path[FN_LEN]; char shadow_path[FN_LEN]; TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; uint next_entry= 0; @@ -5495,13 +5518,13 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), - TRUE) + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + TRUE)) break; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) break; - build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) From f99f322ea2df8932a551395b6b58623678d2b7c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 23:57:54 -0500 Subject: [PATCH 024/101] Bug fixes + debug stuff --- sql/sql_partition.cc | 12 ++++++++---- sql/sql_table.cc | 15 ++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f68c4d862d5..95ed97bda05 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5450,7 +5450,8 @@ bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry, *exec_log_entry; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; @@ -5779,7 +5780,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || - (not_completed= FALSE) || + ((not_completed= FALSE), FALSE) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -5796,6 +5797,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { + abort(); if (!not_completed) abort(); fast_alter_partition_error_handler(lpt); @@ -5845,7 +5847,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_4") || write_log_rename_frm(lpt) || - (not_completed= FALSE) || + ((not_completed= FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_6") || @@ -5853,6 +5855,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_completed(lpt) || ERROR_INJECT_CRASH("crash_add_partition_7")) { + abort(); if (!not_completed) abort(); fast_alter_partition_error_handler(lpt); @@ -5923,7 +5926,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_3") || write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || - (not_completed= FALSE) || + ((not_completed= FALSE), FALSE) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -5943,6 +5946,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_11") || (mysql_wait_completed_table(lpt, table), FALSE)) { + abort(); if (!not_completed) abort(); fast_alter_partition_error_handler(lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4568b6a92ae..260d1650f20 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -641,14 +641,19 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, global_table_log.file_entry[1]= table_log_entry->action_type; int4store(&global_table_log.file_entry[2], table_log_entry->next_entry); - strcpy(&global_table_log.file_entry[6], table_log_entry->name); + DBUG_ASSERT(strlen(table_log_entry->name) < FN_LEN); + strncpy(&global_table_log.file_entry[6], table_log_entry->name, FN_LEN); if (table_log_entry->action_type == 'r') - strcpy(&global_table_log.file_entry[6 + FN_LEN], - table_log_entry->from_name); + { + DBUG_ASSERT(strlen(table_log_entry->from_name) < FN_LEN); + strncpy(&global_table_log.file_entry[6 + FN_LEN], + table_log_entry->from_name, FN_LEN); + } else global_table_log.file_entry[6 + FN_LEN]= 0; - strcpy(&global_table_log.file_entry[6 + (2*FN_LEN)], - table_log_entry->handler_type); + DBUG_ASSERT(strlen(table_log_entry->handler_type) < FN_LEN); + strncpy(&global_table_log.file_entry[6 + (2*FN_LEN)], + table_log_entry->handler_type, FN_LEN); if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); From 2287cee6938cf4e1dcc461cac31ea9cdf74a65d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 12:30:51 +0100 Subject: [PATCH 025/101] WL 2826: Error handling of ALTER TABLE for partitioning New function to set exec_log_entry Moving code outside lock of table log Fixing some initialisations of list reference to avoid releasing wrong parts sql/sql_partition.cc: New function to set exec_log_entry Moving code outside lock of table log Fixing some initialisations of list reference to avoid releasing wrong parts sql/sql_table.cc: Initialisation of write_header needed --- sql/sql_partition.cc | 71 ++++++++++++++++++++++++++++---------------- sql/sql_table.cc | 2 +- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 95ed97bda05..770d2c4ab39 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5267,6 +5267,26 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } +/* + Set execute log entry in table log for this partitioned table + SYNOPSIS + set_part_info_exec_log_entry() + part_info Partition info object + exec_log_entry Log entry + RETURN VALUES + NONE +*/ + +static +void +set_part_info_exec_log_entry(partition_info *part_info, + TABLE_LOG_MEMORY_ENTRY *exec_log_entry) +{ + part_info->exec_log_entry= exec_log_entry; + exec_log_entry->next_active_log_entry= NULL; +} + + /* Write the log entry to ensure that the shadow frm file is removed at crash. @@ -5294,11 +5314,11 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) char shadow_path[FN_LEN]; DBUG_ENTER("write_log_drop_shadow_frm"); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) break; @@ -5306,13 +5326,13 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; - part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; unlock_global_table_log(); + part_info->first_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5342,15 +5362,16 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) char path[FN_LEN]; char shadow_path[FN_LEN]; TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; - DBUG_ENTER("write_log_drop_shadow_frm"); + DBUG_ENTER("write_log_rename_frm"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5362,8 +5383,8 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + part_info->first_log_entry= old_first_log_entry; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5421,8 +5442,8 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + part_info->first_log_entry= old_first_log_entry; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5459,14 +5480,14 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) break; - build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, next_entry, NULL, tmp_path, FALSE)) break; @@ -5474,13 +5495,13 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; - part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; unlock_global_table_log(); + part_info->first_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5516,18 +5537,19 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) uint next_entry= 0; DBUG_ENTER("write_log_final_change_partition"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, TRUE)) break; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) break; - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5539,8 +5561,8 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + part_info->first_log_entry= old_first_log_entry; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5565,18 +5587,17 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); + DBUG_ASSERT(log_entry); lock_global_table_log(); - DBUG_ASSERT(part_info->exec_log_entry); - if (write_execute_table_log_entry(0UL, TRUE, &part_info->exec_log_entry)) + if (write_execute_table_log_entry(0UL, TRUE, &log_entry)) { DBUG_RETURN(TRUE); } release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; - part_info->exec_log_entry->next_active_log_entry= NULL; release_part_info_log_entries(part_info->exec_log_entry); - part_info->exec_log_entry= NULL; unlock_global_table_log(); + part_info->exec_log_entry= NULL; + part_info->first_log_entry= NULL; DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 260d1650f20..285c848938e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -698,7 +698,7 @@ write_execute_table_log_entry(uint first_entry, bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry) { - bool write_header; + bool write_header= FALSE; char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); From 8ae7ef461665ce121aeb13999f33797250875b2b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 13:33:08 -0500 Subject: [PATCH 026/101] Don't use free'd memory, bad idea Free all memory with mutex and destroy mutex as final step --- sql/sql_table.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 285c848938e..130dd5b9002 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -864,20 +864,22 @@ release_table_log() TABLE_LOG_MEMORY_ENTRY *used_list= global_table_log.first_used; DBUG_ENTER("release_table_log"); - VOID(pthread_mutex_destroy(&LOCK_gtl)); + lock_global_table_log(); while (used_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= used_list; + TABLE_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; my_free((char*)used_list, MYF(0)); - used_list= tmp->next_log_entry; + used_list= tmp; } while (free_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= free_list; + TABLE_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; my_free((char*)free_list, MYF(0)); - free_list= tmp->next_log_entry; + free_list= tmp; } VOID(my_close(global_table_log.file_id, MYF(0))); + unlock_global_table_log(); + VOID(pthread_mutex_destroy(&LOCK_gtl)); DBUG_VOID_RETURN; } From c6d1dee7e3decd33735d593d23f0ff280655f016 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 22:36:01 +0100 Subject: [PATCH 027/101] WL 2826: Error handling of ALTER TABLE for partitioning Make lots of fixes to handle the most complex case of reorganising of partitions where two-phased processes are needed in some cases. sql/ha_partition.cc: Rewrote the rename partitions and drop partitions to align with how the table log handles things. sql/handler.h: Added new entry to partition_element to keep track of log entry for a partition during ALTER TABLE that reorganises existing partitions. sql/mysql_priv.h: Converted 'd', 'e' and so forth to constants with somewhat more descriptive names Added method to inactivate log entries sql/sql_partition.cc: Fix change of partitions sql/sql_table.cc: More constants with somewhat descriptive names Moved around some methods between internal part and external part Added new method to handle inactivation of log entries --- sql/ha_partition.cc | 132 +++++++++++++------------- sql/handler.h | 4 +- sql/mysql_priv.h | 13 +++ sql/sql_partition.cc | 103 +++++++++++++++++++-- sql/sql_table.cc | 214 +++++++++++++++++++++++++++++-------------- 5 files changed, 327 insertions(+), 139 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index fade6803156..22d092b486e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -577,7 +577,6 @@ int ha_partition::create(const char *name, TABLE *table_arg, int ha_partition::drop_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); - List_iterator temp_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; uint no_parts= m_part_info->partitions.elements; uint part_count= 0; @@ -585,37 +584,18 @@ int ha_partition::drop_partitions(const char *path) uint i= 0; uint name_variant; int error= 0; - bool reorged_parts= (m_reorged_parts > 0); - bool temp_partitions= (m_part_info->temp_partitions.elements > 0); DBUG_ENTER("ha_partition::drop_partitions"); - if (temp_partitions) - no_parts= m_part_info->temp_partitions.elements; do { - partition_element *part_elem; - if (temp_partitions) - { - /* - We need to remove the reorganised partitions that were put in the - temp_partitions-list. - */ - part_elem= temp_it++; - DBUG_ASSERT(part_elem->part_state == PART_TO_BE_DROPPED); - } - else - part_elem= part_it++; - if (part_elem->part_state == PART_TO_BE_DROPPED || - part_elem->part_state == PART_IS_CHANGED) + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED) { handler *file; /* This part is to be dropped, meaning the part or all its subparts. */ name_variant= NORMAL_PART_NAME; - if (part_elem->part_state == PART_IS_CHANGED || - (part_elem->part_state == PART_TO_BE_DROPPED && temp_partitions)) - name_variant= RENAMED_PART_NAME; if (m_is_sub_partitioned) { List_iterator sub_it(part_elem->subpartitions); @@ -627,10 +607,7 @@ int ha_partition::drop_partitions(const char *path) create_subpartition_name(part_name_buff, path, part_elem->partition_name, sub_elem->partition_name, name_variant); - if (reorged_parts) - file= m_reorged_file[part_count++]; - else - file= m_file[part]; + file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); error+= file->delete_table((const char *) part_name_buff); } while (++j < no_subparts); @@ -640,10 +617,7 @@ int ha_partition::drop_partitions(const char *path) create_partition_name(part_name_buff, path, part_elem->partition_name, name_variant, TRUE); - if (reorged_parts) - file= m_reorged_file[part_count++]; - else - file= m_file[i]; + file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); error+= file->delete_table((const char *) part_name_buff); } @@ -695,6 +669,14 @@ int ha_partition::rename_partitions(const char *path) if (temp_partitions) { + /* + These are the reorganised partitions that have already been copied. + We delete the partitions and log the delete by inactivating the + delete log entry in the table log. We only need to synchronise + these writes before moving to the next loop since there is no + interaction among reorganised partitions, they cannot have the + same name. + */ do { part_elem= temp_it++; @@ -705,39 +687,57 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; file= m_reorged_file[part_count++]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - RENAMED_PART_NAME); create_subpartition_name(norm_name_buff, path, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - DBUG_PRINT("info", ("Rename subpartition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; /* Indicate success */ } while (++j < no_subparts); } else { file= m_reorged_file[part_count++]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, RENAMED_PART_NAME, - TRUE); create_partition_name(norm_name_buff, path, part_elem->partition_name, NORMAL_PART_NAME, TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); + VOID(sync_table_log()); } i= 0; do { + /* + When state is PART_IS_CHANGED it means that we have created a new + TEMP partition that is to be renamed to normal partition name and + we are to delete the old partition with currently the normal name. + + We perform this operation by + 1) Delete old partition with normal partition name + 2) Signal this in table log entry + 3) Synch table log to ensure we have consistency in crashes + 4) Rename temporary partition name to normal partition name + 5) Signal this to table log entry + It is not necessary to synch the last state since a new rename + should not corrupt things if there was no temporary partition. + + The only other parts we need to cater for are new parts that + replace reorganised parts. The reorganised parts were deleted + by the code above that goes through the temp_partitions list. + Thus the synch above makes it safe to simply perform step 4 and 5 + for those entries. + */ part_elem= part_it++; if (part_elem->part_state == PART_IS_CHANGED || (part_elem->part_state == PART_IS_ADDED && temp_partitions)) @@ -759,14 +759,11 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - RENAMED_PART_NAME); - DBUG_PRINT("info", ("Rename subpartition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + VOID(synch_table_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -775,8 +772,12 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - error+= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + if (file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; } while (++j < no_subparts); } else @@ -787,13 +788,11 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, RENAMED_PART_NAME, - TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + VOID(synch_table_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -801,11 +800,16 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - error+= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + if (file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff) || + inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + else + part_elem->log_entry= NULL; } } } while (++i < no_parts); + VOID(synch_table_log()); DBUG_RETURN(error); } diff --git a/sql/handler.h b/sql/handler.h index 00bfaa77e91..b54e7ff129b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -667,6 +667,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; + TABLE_LOG_MEMORY_ENTRY *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -677,7 +678,8 @@ public: partition_element() : part_max_rows(0), part_min_rows(0), partition_name(NULL), - tablespace_name(NULL), range_value(0), part_comment(NULL), + tablespace_name(NULL), log_entry(0), + range_value(0), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL),part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e0875b06a0a..24c789a21e7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1177,6 +1177,8 @@ typedef struct st_table_log_entry uint next_entry; char action_type; char entry_type; + char phase; + char not_used; } TABLE_LOG_ENTRY; typedef struct st_table_log_memory_entry @@ -1187,11 +1189,22 @@ typedef struct st_table_log_memory_entry struct st_table_log_memory_entry *next_active_log_entry; } TABLE_LOG_MEMORY_ENTRY; +#define TLOG_EXECUTE_CODE 'e' +#define TLOG_LOG_ENTRY_CODE 'l' +#define TLOG_IGNORE_LOG_ENTRY_CODE 'i' + +#define TLOG_DELETE_ACTION_CODE 'd' +#define TLOG_RENAME_ACTION_CODE 'r' +#define TLOG_REPLACE_ACTION_CODE 's' + +#define TLOG_HANDLER_TYPE_LEN 32 + bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, TABLE_LOG_MEMORY_ENTRY **active_entry); bool write_execute_table_log_entry(uint first_entry, bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry); +bool inactivate_table_log_entry(uint entry_no); void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); void release_table_log(); void execute_table_log_recovery(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 770d2c4ab39..0e35a386f85 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5135,9 +5135,9 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_ENTER("write_log_rename_frm"); if (rename_flag) - table_log_entry.action_type= 'r'; + table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; else - table_log_entry.action_type= 'd'; + table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; table_log_entry.next_entry= next_entry; table_log_entry.handler_type= "frm"; table_log_entry.name= to_path; @@ -5160,6 +5160,18 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, RETURN VALUES TRUE Error FALSE Success + DESCRIPTION + This code is used to perform safe ADD PARTITION for HASH partitions + and COALESCE for HASH partitions and REORGANIZE for any type of + partitions. + We prepare entries for all partitions except the reorganised partitions + in REORGANIZE partition, those are handled by + write_log_dropped_partitions. For those partitions that are replaced + special care is needed to ensure that this is performed correctly and + this requires a two-phased approach with this log as a helper for this. + + This code is closely intertwined with the code in rename_partitions in + the partition handler. */ static @@ -5167,7 +5179,84 @@ bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint *next_entry, const char *path) { + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char normal_path[FN_LEN]; + List_iterator part_it(part_info->partitions); + uint temp_partitions= part_info->temp_partitions.elements; + uint no_elements= part_info->partitions.elements; + uint i= 0; DBUG_ENTER("write_log_changed_partitions"); + + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_IS_CHANGED || + (part_elem->part_state == PART_IS_ADDED && temp_partitions)) + { + if (is_sub_partitioned(part_info)) + { + List_iterator sub_it(part_elem->subpartitions); + uint no_subparts= part_info->no_subparts; + uint j= 0; + do + { + partition_element *sub_elem= sub_it++; + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(sub_elem->engine_type); + create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + TEMP_PART_NAME); + create_subpartition_name(normal_path, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME); + table_log_entry.name= norm_path; + table_log_entry.from_name= tmp_path; + if (part_elem->part_state == PART_IS_CHANGED) + table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + else + table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *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); + } + else + { + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(part_elem->engine_type); + create_partition_name(tmp_path, path, + part_elem->partition_name, + TEMP_PART_NAME, TRUE); + create_partition_name(normal_path, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE); + table_log_entry.name= normal_path; + table_log_entry.from_name= tmp_path; + if (part_elem->part_state == PART_IS_CHANGED) + table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + else + table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + part_elem->table_log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } + } + } while (++i < no_elements) DBUG_RETURN(FALSE); } @@ -5200,7 +5289,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); - table_log_entry.action_type= 'd'; + table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; if (temp_list) no_elements= no_temp_partitions; while (no_elements--) @@ -5242,6 +5331,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; + if (temp_list) + sub_elem->table_log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } while (++j < no_subparts); } @@ -5259,6 +5350,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; + if (temp_list) + part_elem->table_log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } @@ -5961,10 +6054,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_9") || - mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_10") || write_log_completed(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_11") || + ERROR_INJECT_CRASH("crash_change_partition_10") || (mysql_wait_completed_table(lpt, table), FALSE)) { abort(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 130dd5b9002..47a5693f374 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -289,28 +289,38 @@ GLOBAL_TABLE_LOG global_table_log; pthread_mutex_t LOCK_gtl; +#define TLOG_ENTRY_TYPE_POS 0 +#define TLOG_ACTION_TYPE_POS 1 +#define TLOG_PHASE_POS 2 +#define TLOG_NEXT_ENTRY_POS 4 + +#define TLOG_NO_ENTRY_POS 0 +#define TLOG_NAME_LEN_POS 4 +#define TLOG_HANDLER_TYPE_POS 8 +#define TLOG_IO_SIZE_POS 12 /* - Sync table log file + Read one entry from table log file SYNOPSIS - sync_table_log() + read_table_log_file_entry() + entry_no Entry number to read RETURN VALUES - TRUE Error - FALSE Success + TRUE Error + FALSE Success */ static bool -sync_table_log() +read_table_log_file_entry(uint entry_no) { bool error= FALSE; - DBUG_ENTER("sync_table_log"); + File file_id= global_table_log.file_id; + char *file_entry= (char*)global_table_log.file_entry; + uint io_size= global_table_log.io_size; + DBUG_ENTER("read_table_log_file_entry"); - if (my_sync(global_table_log.file_id, MYF(0))) - { - /* Write to error log */ + if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) error= TRUE; - } DBUG_RETURN(error); } @@ -358,13 +368,17 @@ write_table_log_header() bool error= FALSE; DBUG_ENTER("write_table_log_header"); - int4store(&global_table_log.file_entry[0], global_table_log.no_entries); + int4store(&global_table_log.file_entry[TLOG_NO_ENTRY_POS], + global_table_log.no_entries); const_var= FN_LEN; - int2store(&global_table_log.file_entry[4], const_var); - const_var= 32; - int2store(&global_table_log.file_entry[6], const_var); + int4store(&global_table_log.file_entry[TLOG_NAME_LEN_POS], + const_var); + const_var= TLOG_HANDLER_TYPE_LEN; + int4store(&global_table_log.file_entry[TLOG_HANDLER_TYPE_POS], + const_var); const_var= IO_SIZE; - int4store(&global_table_log.file_entry[8], const_var); + int4store(&global_table_log.file_entry[TLOG_IO_SIZE_POS], + const_var); if (write_table_log_file_entry(0UL)) error= TRUE; if (!error) @@ -373,32 +387,6 @@ write_table_log_header() } -/* - Read one entry from table log file - SYNOPSIS - read_table_log_file_entry() - entry_no Entry number to read - RETURN VALUES - TRUE Error - FALSE Success -*/ - -static -bool -read_table_log_file_entry(uint entry_no) -{ - bool error= FALSE; - File file_id= global_table_log.file_id; - char *file_entry= (char*)global_table_log.file_entry; - uint io_size= global_table_log.io_size; - DBUG_ENTER("read_table_log_file_entry"); - - if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) - error= TRUE; - DBUG_RETURN(error); -} - - /* Create table log file name SYNOPSIS @@ -450,11 +438,12 @@ read_table_log_header() else successful_open= TRUE; } - entry_no= uint4korr(&file_entry[0]); - global_table_log.name_len= uint2korr(&file_entry[4]); - global_table_log.handler_type_len= uint2korr(&file_entry[6]); + entry_no= uint4korr(&file_entry[TLOG_NO_ENTRY_POS]); + global_table_log.name_len= uint4korr(&file_entry[TLOG_NAME_LEN_POS]); + global_table_log.handler_type_len= + uint4korr(&file_entry[TLOG_HANDLER_TYPE_POS]); if (successful_open) - global_table_log.io_size= uint4korr(&file_entry[8]); + global_table_log.io_size= uint4korr(&file_entry[TLOG_IO_SIZE_POS]); global_table_log.first_free= NULL; global_table_log.first_used= NULL; global_table_log.no_entries= 0; @@ -488,11 +477,12 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) /* Error handling */ DBUG_RETURN(TRUE); } - table_log_entry->entry_type= file_entry[0]; - table_log_entry->action_type= file_entry[1]; - table_log_entry->next_entry= uint4korr(&file_entry[2]); - table_log_entry->name= &file_entry[6]; - inx= 6 + global_table_log.name_len; + table_log_entry->entry_type= file_entry[TLOG_ENTRY_TYPE_POS]; + table_log_entry->action_type= file_entry[TLOG_ACTION_TYPE_POS]; + table_log_entry->phase= file_entry[TLOG_PHASE_POS]; + table_log_entry->next_entry= uint4korr(&file_entry[TLOG_NEXT_ENTRY_POS]); + table_log_entry->name= &file_entry[TLOG_NAME_POS]; + inx= TLOG_NAME_POS + global_table_log.name_len; table_log_entry->from_name= &file_entry[inx]; inx+= global_table_log.name_len; table_log_entry->handler_type= &file_entry[inx]; @@ -637,23 +627,27 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, bool error, write_header; DBUG_ENTER("write_table_log_entry"); - global_table_log.file_entry[0]= 'i'; - global_table_log.file_entry[1]= table_log_entry->action_type; - int4store(&global_table_log.file_entry[2], + global_table_log.file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_LOG_ENTRY_CODE; + global_table_log.file_entry[TLOG_ACTION_TYPE_POS]= + table_log_entry->action_type; + global_table_log.file_entry[TLOG_PHASE_POS]= 0; + int4store(&global_table_log.file_entry[TLOG_NEXT_ENTRY_POS], table_log_entry->next_entry); DBUG_ASSERT(strlen(table_log_entry->name) < FN_LEN); - strncpy(&global_table_log.file_entry[6], table_log_entry->name, FN_LEN); - if (table_log_entry->action_type == 'r') + strncpy(&global_table_log.file_entry[TLOG_NAME_POS], + table_log_entry->name, FN_LEN); + if (table_log_entry->action_type == TLOG_RENAME_ACTION_CODE || + table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE) { DBUG_ASSERT(strlen(table_log_entry->from_name) < FN_LEN); - strncpy(&global_table_log.file_entry[6 + FN_LEN], + strncpy(&global_table_log.file_entry[TLOG_NAME_POS + FN_LEN], table_log_entry->from_name, FN_LEN); } else - global_table_log.file_entry[6 + FN_LEN]= 0; + global_table_log.file_entry[TLOG_NAME_POS + FN_LEN]= 0; DBUG_ASSERT(strlen(table_log_entry->handler_type) < FN_LEN); - strncpy(&global_table_log.file_entry[6 + (2*FN_LEN)], - table_log_entry->handler_type, FN_LEN); + strncpy(&global_table_log.file_entry[TLOG_NAME_POS + (2*FN_LEN)], + table_log_entry->handler_type, FN_LEN); if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); @@ -705,15 +699,16 @@ write_execute_table_log_entry(uint first_entry, if (!complete) { VOID(sync_table_log()); - file_entry[0]= 'e'; + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_EXECUTE_CODE; } else - file_entry[0]= 'i'; - file_entry[1]= 0; /* Ignored for execute entries */ - int4store(&file_entry[2], first_entry); - file_entry[6]= 0; - file_entry[6 + FN_LEN]= 0; - file_entry[6 + 2*FN_LEN]= 0; + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; + file_entry[TLOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ + file_entry[TLOG_PHASE_POS]= 0; + int4store(&file_entry[TLOG_NEXT_ENTRY_POS], first_entry); + file_entry[TLOG_NAME_POS]= 0; + file_entry[TLOG_NAME_POS + FN_LEN]= 0; + file_entry[TLOG_NAME_POS + 2*FN_LEN]= 0; if (!(*active_entry)) { if (get_free_table_log_entry(active_entry, &write_header)) @@ -739,6 +734,88 @@ write_execute_table_log_entry(uint first_entry, } +/* + For complex rename operations we need to inactivate individual entries. + SYNOPSIS + inactivate_table_log_entry() + entry_no Entry position of record to change + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + During replace operations where we start with an existing table called + t1 and a replacement table called t1#temp or something else and where + we want to delete t1 and rename t1#temp to t1 this is not possible to + do in a safe manner unless the table log is informed of the phases in + the change. + + Delete actions are 1-phase actions that can be ignored immediately after + being executed. + Rename actions from x to y is also a 1-phase action since there is no + interaction with any other handlers named x and y. + Replace action where drop y and x -> y happens needs to be a two-phase + action. Thus the first phase will drop y and the second phase will + rename x -> y. +*/ + +bool +inactivate_table_log_entry(uint entry_no) +{ + bool error= TRUE; + const char *file_entry= (const char*)global_table_log.file_entry + DBUG_ENTER("inactivate_table_log_entry"); + + if (!read_table_log_file_entry(entry_no)) + { + if (file_entry[TLOG_ENTRY_POS] == TLOG_LOG_ENTRY_CODE) + { + if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_DELETE_ACTION_CODE || + file_entry[TLOG_ACTION_TYPE_POS] == TLOG_RENAME_ACTION_CODE || + (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE && + file_entry[TLOG_PHASE_POS] == 1)) + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_POS; + else if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE) + { + DBUG_ASSERT(file_entry[TLOG_PHASE_POS] == 0); + file_entry[TLOG_PHASE_POS]= 1; + } + else + { + DBUG_ASSERT(0); + } + if (!write_table_log_file_entry(entry_no)) + error= FALSE; + } + } + DBUG_RETURN(error); +} + + +/* + Sync table log file + SYNOPSIS + sync_table_log() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +sync_table_log() +{ + bool error= FALSE; + DBUG_ENTER("sync_table_log"); + + if (my_sync(global_table_log.file_id, MYF(0))) + { + /* Write to error log */ + error= TRUE; + } + DBUG_RETURN(error); +} + + /* Release a log memory entry SYNOPSIS @@ -795,7 +872,8 @@ execute_table_log_entry(uint first_entry) /* Write to error log and continue with next log entry */ break; } - DBUG_ASSERT(table_log_entry.entry_type == 'i'); + DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || + table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); if (execute_table_log_action(&table_log_entry)) { DBUG_ASSERT(0); @@ -831,7 +909,7 @@ execute_table_log_recovery() /* Write to error log */ break; } - if (table_log_entry.entry_type == 'e') + if (table_log_entry.entry_type == TLOG_EXECUTE_CODE) { if (execute_table_log_entry(table_log_entry.next_entry)) { From b517dbf7183a16101b901f29f0a0d9acfac177ce Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 11 Feb 2006 00:41:52 -0500 Subject: [PATCH 028/101] Compile fixes --- sql/ha_partition.cc | 15 ++++++++------- sql/handler.h | 4 ++-- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 18 +++++++++--------- sql/sql_table.cc | 8 ++++---- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 22d092b486e..af6ce9cd1e0 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -101,7 +101,9 @@ handlerton partition_hton = { partition_flags, /* Partition flags */ alter_table_flags, /* Partition flags */ NULL, /* Alter Tablespace */ - HTON_NOT_USER_SELECTABLE | HTON_HIDDEN + HTON_NOT_USER_SELECTABLE | HTON_HIDDEN, + NULL, /* binlog function */ + NULL /* binlog query */ }; /* @@ -495,10 +497,9 @@ int ha_partition::create_handler_files(const char *path, { char name[FN_REFLEN]; char old_name[FN_REFLEN]; - char *par_str= ".par"; - strxmov(name, path, par_str, NullS); - strxmov(old_name, old_path, par_str, NullS); + strxmov(name, path, ha_par_ext, NullS); + strxmov(old_name, old_path, ha_par_ext, NullS); if (my_delete(name, MYF(MY_WME)) || my_rename(old_name, name, MYF(MY_WME))) { @@ -763,7 +764,7 @@ int ha_partition::rename_partitions(const char *path) if (file->delete_table((const char *) norm_name_buff) || inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; - VOID(synch_table_log()); + VOID(sync_table_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -792,7 +793,7 @@ int ha_partition::rename_partitions(const char *path) if (file->delete_table((const char *) norm_name_buff) || inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; - VOID(synch_table_log()); + VOID(sync_table_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -809,7 +810,7 @@ int ha_partition::rename_partitions(const char *path) } } } while (++i < no_parts); - VOID(synch_table_log()); + VOID(sync_table_log()); DBUG_RETURN(error); } diff --git a/sql/handler.h b/sql/handler.h index b54e7ff129b..543da947ebf 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -658,6 +658,7 @@ typedef struct { #define UNDEF_NODEGROUP 65535 class Item; +struct st_table_log_memory_entry; class partition_element :public Sql_alloc { public: @@ -667,7 +668,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; - TABLE_LOG_MEMORY_ENTRY *log_entry; + st_table_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -801,7 +802,6 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, PARTITION_ITERATOR *part_iter); -struct st_table_log_memory_entry; class partition_info : public Sql_alloc { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 24c789a21e7..bcff8d65483 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1206,6 +1206,7 @@ bool write_execute_table_log_entry(uint first_entry, TABLE_LOG_MEMORY_ENTRY **active_entry); bool inactivate_table_log_entry(uint entry_no); void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); +bool sync_table_log(); void release_table_log(); void execute_table_log_recovery(); bool execute_table_log_entry(uint first_entry); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 0e35a386f85..809bd0fcfce 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5215,12 +5215,12 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - table_log_entry.name= norm_path; + table_log_entry.name= normal_path; table_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; else - table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; if (write_table_log_entry(&table_log_entry, &log_entry)) { DBUG_RETURN(TRUE); @@ -5244,19 +5244,19 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, table_log_entry.name= normal_path; table_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; else - table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; if (write_table_log_entry(&table_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; - part_elem->table_log_entry= log_entry; + part_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } - } while (++i < no_elements) + } while (++i < no_elements); DBUG_RETURN(FALSE); } @@ -5332,7 +5332,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } *next_entry= log_entry->entry_pos; if (temp_list) - sub_elem->table_log_entry= log_entry; + sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } while (++j < no_subparts); } @@ -5351,7 +5351,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } *next_entry= log_entry->entry_pos; if (temp_list) - part_elem->table_log_entry= log_entry; + part_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 47a5693f374..a5ef2a90b5d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -293,6 +293,7 @@ pthread_mutex_t LOCK_gtl; #define TLOG_ACTION_TYPE_POS 1 #define TLOG_PHASE_POS 2 #define TLOG_NEXT_ENTRY_POS 4 +#define TLOG_NAME_POS 8 #define TLOG_NO_ENTRY_POS 0 #define TLOG_NAME_LEN_POS 4 @@ -762,18 +763,18 @@ bool inactivate_table_log_entry(uint entry_no) { bool error= TRUE; - const char *file_entry= (const char*)global_table_log.file_entry + char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("inactivate_table_log_entry"); if (!read_table_log_file_entry(entry_no)) { - if (file_entry[TLOG_ENTRY_POS] == TLOG_LOG_ENTRY_CODE) + if (file_entry[TLOG_ENTRY_TYPE_POS] == TLOG_LOG_ENTRY_CODE) { if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_DELETE_ACTION_CODE || file_entry[TLOG_ACTION_TYPE_POS] == TLOG_RENAME_ACTION_CODE || (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE && file_entry[TLOG_PHASE_POS] == 1)) - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_POS; + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; else if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE) { DBUG_ASSERT(file_entry[TLOG_PHASE_POS] == 0); @@ -800,7 +801,6 @@ inactivate_table_log_entry(uint entry_no) FALSE Success */ -static bool sync_table_log() { From 5d5eba2d3378f880331d439e4f3837b17f5f21e9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Feb 2006 13:52:23 +0100 Subject: [PATCH 029/101] WL 2826: Error handling of ALTER TABLE for partitioning Introduce log entry to handle replace of frm file sql/handler.h: Introduce log entry to handle replace of frm file sql/sql_partition.cc: Introduce log entry to handle replace of frm file sql/sql_table.cc: Introduce log entry to handle replace of frm file --- sql/handler.h | 3 ++- sql/sql_partition.cc | 22 ++++++++++++++-------- sql/sql_table.cc | 5 +++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 543da947ebf..6df6b48b83a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -852,6 +852,7 @@ public: st_table_log_memory_entry *first_log_entry; st_table_log_memory_entry *exec_log_entry; + st_table_log_memory_entry *frm_log_entry; /* A bitmap of partitions used by the current query. Usage pattern: @@ -963,7 +964,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), - first_log_entry(NULL), exec_log_entry(NULL), + first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 809bd0fcfce..6985adbac1a 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5109,7 +5109,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) /* Log an delete/rename frm file SYNOPSIS - write_log_rename_delete_frm() + write_log_replace_delete_frm() lpt Struct for parameters next_entry Next reference to use in log record path Name to rename from @@ -5118,30 +5118,30 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) TRUE Error FALSE Success DESCRIPTION - Support routine that writes a rename or delete of an frm file into the + Support routine that writes a replace or delete of an frm file into the table log. It also inserts an entry that keeps track of used space into the partition info object */ bool -write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, +write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint next_entry, const char *from_path, const char *to_path, - bool rename_flag) + bool replace_flag) { TABLE_LOG_ENTRY table_log_entry; TABLE_LOG_MEMORY_ENTRY *log_entry; - DBUG_ENTER("write_log_rename_frm"); + DBUG_ENTER("write_log_replace_frm"); - if (rename_flag) - table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; + if (replace_flag) + table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; else table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; table_log_entry.next_entry= next_entry; table_log_entry.handler_type= "frm"; table_log_entry.name= to_path; - if (rename_flag) + if (replace_flag) table_log_entry.from_name= from_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { @@ -5468,6 +5468,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5478,6 +5479,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5527,6 +5529,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) (const char*)tmp_path, TRUE)) break; log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5537,6 +5540,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5646,6 +5650,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5656,6 +5661,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a5ef2a90b5d..593ba5c35e4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1136,12 +1136,17 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || + inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || + sync_table_log() || my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) { error= 1; } VOID(pthread_mutex_unlock(&LOCK_open)); + inactivate_table_log_entry(part_info->frm_log_entry->entry_pos); + part_info->frm_log_entry= NULL; + VOID(sync_table_log()); } end: From 897dd4794d18ccd77926baa224d0b99c5f441dd5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 11:08:58 +0100 Subject: [PATCH 030/101] WL 2826: Error handling of ALTER TABLE for partitioning Added action code for recovery sql/mysql_priv.h: Added entry in table log struct sql/sql_partition.cc: Some renames to replace sql/sql_table.cc: Added action code for recovery --- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 12 +++--- sql/sql_table.cc | 99 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index bcff8d65483..4a67ab650d9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1175,6 +1175,7 @@ typedef struct st_table_log_entry const char *from_name; const char *handler_type; uint next_entry; + uint entry_pos; char action_type; char entry_type; char phase; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 6985adbac1a..56e64537fdf 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5132,7 +5132,7 @@ write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, { TABLE_LOG_ENTRY table_log_entry; TABLE_LOG_MEMORY_ENTRY *log_entry; - DBUG_ENTER("write_log_replace_frm"); + DBUG_ENTER("write_log_replace_delete_frm"); if (replace_flag) table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; @@ -5412,7 +5412,7 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_rename_delete_frm(lpt, 0UL, NULL, + if (write_log_replace_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5465,7 +5465,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; @@ -5525,7 +5525,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) break; - if (write_log_rename_delete_frm(lpt, next_entry, (const char*)path, + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, (const char*)tmp_path, TRUE)) break; log_entry= part_info->first_log_entry; @@ -5585,7 +5585,7 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) break; - if (write_log_rename_delete_frm(lpt, next_entry, NULL, tmp_path, + if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5647,7 +5647,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) break; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) break; - if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 593ba5c35e4..b2bd7494709 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -478,6 +478,7 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) /* Error handling */ DBUG_RETURN(TRUE); } + table_log_entry->entry_pos= read_entry; table_log_entry->entry_type= file_entry[TLOG_ENTRY_TYPE_POS]; table_log_entry->action_type= file_entry[TLOG_ACTION_TYPE_POS]; table_log_entry->phase= file_entry[TLOG_PHASE_POS]; @@ -544,8 +545,97 @@ static bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) { + bool frm_action= FALSE; + LEX_STRING handler_name; + handler *file; + MEMROOT mem_root; + bool= error= TRUE; + char path[FN_REFLEN]; + char from_path[FN_REFLEN]; + char *par_ext= ".par"; DBUG_ENTER("execute_table_log_action"); - DBUG_RETURN(FALSE); + + if (table_log_entry->entry_type == TLOG_IGNORE_LOG_ENTRY_CODE) + { + DBUG_RETURN(FALSE); + } + handler_name.str= table_log_entry->handler_type; + handler_name.length= strlen(table_log_entry->handler_type); + hton= ha_resolve_by_name(current_thd, handler_name); + if (!hton) + { + DBUG_RETURN(TRUE); + } + init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); + if (strcmp("frm", table_log_entry->handler_type)) + frm_action= TRUE; + else + { + file= get_new_handler(table_share, &mem_root, hton); + if (!file) + goto error; + } + switch (table_log_entry->action_type) + case TLOG_ACTION_DELETE_CODE: + case TLOG_ACTION_REPLACE_CODE: + if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE || + (table_log_entry->action_type == TLOG_ACTION_REPLACE_CODE && + table_log_entry->phase == 0UL)) + { + if (frm_action) + { + strxmov(path, table_log_entry->name, reg_ext, NullS); + VOID(my_delete(path, MYF(0))); + strxmov(path, table_log_entry->name, par_ext, NullS); + VOID(my_delete(path, MYF(0))); + } + else + { + if (file->delete_table(table_name)) + break; + } + if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && + (!sync_table_log())) + ; + else + error= FALSE; + break; + } + if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE) + break; + case TLOG_ACTION_RENAME_CODE: + error= TRUE; + if (frm_action) + { + strxmov(path, table_log_entry->name, reg_ext, NullS); + strxmov(from_path, table_log_entry->from_name, reg_ext, NullS); + if (my_rename(path, from_path, MYF(0))) + break; + strxmov(path, table_log_entry->name, par_ext, NullS); + strxmov(from_path, table_log_entry->from_name, par_ext, NullS); + if (my_rename(path, from_path, MYF(0))) + break; + } + else + { + if (file->rename_table(table_log_entry->name, + table_log_entry->from_name)) + break; + if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && + (!sync_table_log())) + ; + else + error= FALSE; + } + break; + default: + DBUG_ASSERT(0); + break; + } + delete file; +error: + free_root(&mem_root, MYF(0)); + DBUG_RETURN(error); } @@ -864,6 +954,7 @@ execute_table_log_entry(uint first_entry) uint read_entry= first_entry; DBUG_ENTER("execute_table_log_entry"); + lock_global_table_log(); do { if (read_table_log_entry(read_entry, &table_log_entry)) @@ -874,7 +965,8 @@ execute_table_log_entry(uint first_entry) } DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); - if (execute_table_log_action(&table_log_entry)) + + if (execute_table_log_action(file, &table_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ @@ -882,9 +974,11 @@ execute_table_log_entry(uint first_entry) } read_entry= table_log_entry.next_entry; } while (read_entry); + unlock_global_table_log(); DBUG_RETURN(FALSE); } + /* Execute the table log at recovery of MySQL Server SYNOPSIS @@ -922,6 +1016,7 @@ execute_table_log_recovery() } } } + release_handler_objects(); VOID(init_table_log()); DBUG_VOID_RETURN; } From 5cecd1734e8736a7d29b193b6a6649d10cf9b764 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 14:22:21 +0100 Subject: [PATCH 031/101] WL 2826: Error handling of ALTER TABLE for partitioning First step for handling errors in ALTER TABLE for partitioning sql/ha_partition.cc: First step for handling errors in ALTER TABLE for partitioning sql/sql_partition.cc: First step for handling errors in ALTER TABLE for partitioning sql/sql_table.cc: First step for handling errors in ALTER TABLE for partitioning --- sql/ha_partition.cc | 42 ++++++++++++++++++++++-------------- sql/sql_partition.cc | 51 ++++++++++++++++++++++++++++++++++++++------ sql/sql_table.cc | 44 ++++++++++++++++++++++++-------------- 3 files changed, 98 insertions(+), 39 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index af6ce9cd1e0..d65203e1b34 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -584,6 +584,7 @@ int ha_partition::drop_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; + int ret_error; int error= 0; DBUG_ENTER("ha_partition::drop_partitions"); @@ -610,7 +611,8 @@ int ha_partition::drop_partitions(const char *path) sub_elem->partition_name, name_variant); file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); - error+= file->delete_table((const char *) part_name_buff); + if ((ret_error= file->delete_table((const char *) part_name_buff))) + error= ret_error; } while (++j < no_subparts); } else @@ -620,7 +622,8 @@ int ha_partition::drop_partitions(const char *path) TRUE); file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - error+= file->delete_table((const char *) part_name_buff); + if ((ret_error= file->delete_table((const char *) part_name_buff))) + error= ret_error; } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -663,6 +666,7 @@ int ha_partition::rename_partitions(const char *path) uint i= 0; uint j= 0; int error= 0; + int ret_error; uint temp_partitions= m_part_info->temp_partitions.elements; handler *file; partition_element *part_elem, *sub_elem; @@ -693,8 +697,9 @@ int ha_partition::rename_partitions(const char *path) sub_elem->partition_name, NORMAL_PART_NAME); DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ @@ -707,8 +712,9 @@ int ha_partition::rename_partitions(const char *path) part_elem->partition_name, NORMAL_PART_NAME, TRUE); DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ @@ -761,8 +767,9 @@ int ha_partition::rename_partitions(const char *path) { file= m_reorged_file[part_count++]; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; VOID(sync_table_log()); } @@ -773,9 +780,10 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - if (file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; @@ -790,8 +798,9 @@ int ha_partition::rename_partitions(const char *path) { file= m_reorged_file[part_count++]; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; VOID(sync_table_log()); } @@ -801,9 +810,10 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - if (file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff) || - inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + if ((ret_error= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; else part_elem->log_entry= NULL; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 56e64537fdf..6a34fcaadde 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4975,14 +4975,17 @@ the generated partition syntax in a correct manner. static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) { char path[FN_REFLEN+1]; + int error; + handler *file= lpt->table->file; DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(lpt->table->file->change_partitions(lpt->create_info, path, - &lpt->copied, - &lpt->deleted, - lpt->pack_frm_data, - lpt->pack_frm_len)); + DBUG_RETURN(file->change_partitions(lpt->create_info, + path, + &lpt->copied, + &lpt->deleted, + lpt->pack_frm_data, + lpt->pack_frm_len)); } @@ -5008,10 +5011,17 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) { char path[FN_REFLEN+1]; + int error; DBUG_ENTER("mysql_rename_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(lpt->table->file->rename_partitions(path)); + if ((error= lpt->table->file->rename_partitions(path))) + { + if (error != 1) + lpt->table->file->print_error(error, MYF(0)); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -5042,11 +5052,13 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) List_iterator part_it(part_info->partitions); uint i= 0; uint remove_count= 0; + int error; DBUG_ENTER("mysql_drop_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - if (lpt->table->file->drop_partitions(path)) + if ((error= lpt->table->file->drop_partitions(path))) { + lpt->table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } do @@ -5920,6 +5932,31 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, abort(); if (!not_completed) abort(); + if (!part_info->first_log_entry && + execute_table_log_entry(part_info->first_log_entry)) + { + /* + We couldn't recover from error + */ + } + else + { + if (not_completed) + { + /* + We hit an error before things were completed but managed + to recover from the error. + */ + } + else + { + /* + We hit an error after we had completed most of the operation + and were successful in a second attempt so the operation + actually is successful now. + */ + } + } fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b2bd7494709..8391a976679 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -320,7 +320,8 @@ read_table_log_file_entry(uint entry_no) uint io_size= global_table_log.io_size; DBUG_ENTER("read_table_log_file_entry"); - if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) + if (my_pread(file_id, file_entry, io_size, io_size * entry_no, + MYF(MY_WME))) error= TRUE; DBUG_RETURN(error); } @@ -346,7 +347,7 @@ write_table_log_file_entry(uint entry_no) DBUG_ENTER("write_table_log_file_entry"); if (my_pwrite(file_id, file_entry, - IO_SIZE, IO_SIZE * entry_no, MYF(0)) != IO_SIZE) + IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); } @@ -383,7 +384,7 @@ write_table_log_header() if (write_table_log_file_entry(0UL)) error= TRUE; if (!error) - error= sync_table_log(); + VOID(sync_table_log()); DBUG_RETURN(error); } @@ -430,7 +431,7 @@ read_table_log_header() bzero(file_entry, sizeof(global_table_log.file_entry)); create_table_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(0)))) + if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(MY_WME)))) { if (read_table_log_file_entry(0UL)) { @@ -517,7 +518,7 @@ init_table_log() if ((global_table_log.file_id= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC | O_BINARY, - MYF(0))) < 0) + MYF(MY_WME))) < 0) { /* Couldn't create table log file, this is serious error */ abort(); @@ -564,6 +565,7 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) hton= ha_resolve_by_name(current_thd, handler_name); if (!hton) { + my_error(ER_ILLEGAL_HA, table_log_entry->handler_type); DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); @@ -573,7 +575,10 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) { file= get_new_handler(table_share, &mem_root, hton); if (!file) + { + mem_alloc_error(sizeof(handler)); goto error; + } } switch (table_log_entry->action_type) case TLOG_ACTION_DELETE_CODE: @@ -585,20 +590,24 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) if (frm_action) { strxmov(path, table_log_entry->name, reg_ext, NullS); - VOID(my_delete(path, MYF(0))); + if (my_delete(path, MYF(MY_WME))) + break; strxmov(path, table_log_entry->name, par_ext, NullS); - VOID(my_delete(path, MYF(0))); + if (my_delete(path, MYF(MY_WME))) + break; } else { if (file->delete_table(table_name)) break; } - if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && - (!sync_table_log())) + if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) ; else + { + VOID(sync_table_log()); error= FALSE; + } break; } if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE) @@ -609,11 +618,11 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) { strxmov(path, table_log_entry->name, reg_ext, NullS); strxmov(from_path, table_log_entry->from_name, reg_ext, NullS); - if (my_rename(path, from_path, MYF(0))) + if (my_rename(path, from_path, MYF(MY_WME))) break; strxmov(path, table_log_entry->name, par_ext, NullS); strxmov(from_path, table_log_entry->from_name, par_ext, NullS); - if (my_rename(path, from_path, MYF(0))) + if (my_rename(path, from_path, MYF(MY_WME))) break; } else @@ -621,11 +630,13 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) if (file->rename_table(table_log_entry->name, table_log_entry->from_name)) break; - if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && - (!sync_table_log())) + if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) ; else + { + VOID(sync_table_log()); error= FALSE; + } } break; default: @@ -662,7 +673,7 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, if (global_table_log.first_free == NULL) { if (!(used_entry= (TABLE_LOG_MEMORY_ENTRY*)my_malloc( - sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(0)))) + sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { DBUG_RETURN(TRUE); } @@ -748,7 +759,8 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, error= TRUE; if (write_header && !error) { - if (sync_table_log() || write_table_log_header()) + VOID(sync_table_log()); + if (write_table_log_header()) error= TRUE; } if (error) @@ -1232,7 +1244,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || - sync_table_log() || + (sync_table_log(), FALSE) || my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) { From c8db62f64c51f75bb8314a71b145ff4689ec2543 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 17:03:47 +0100 Subject: [PATCH 032/101] WL 2826: Error handling of ALTER TABLE for partitioning Some more error handling sql/sql_partition.cc: Some more error handling --- sql/sql_partition.cc | 74 ++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 6a34fcaadde..8f09edcf8cc 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5713,6 +5713,51 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Handle errors for ALTER TABLE for partitioning + SYNOPSIS + handle_alter_part_error() + lpt Struct carrying parameters + not_completed Was request in complete phase when error occurred + RETURN VALUES + NONE +*/ + +void +handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed) +{ + partition_info *part_info= lpt->part_info; + DBUG_ENTER("handle_alter_part_error"); + + if (!part_info->first_log_entry && + execute_table_log_entry(part_info->first_log_entry)) + { + /* + We couldn't recover from error + */ + } + else + { + if (not_completed) + { + /* + We hit an error before things were completed but managed + to recover from the error. + */ + } + else + { + /* + We hit an error after we had completed most of the operation + and were successful in a second attempt so the operation + actually is successful now. + */ + } + } + DBUG_VOID_RETURN; +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -5929,34 +5974,9 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { + handle_alter_part_error(lpt, not_completed); + DBUG_RETURN(TRUE); abort(); - if (!not_completed) - abort(); - if (!part_info->first_log_entry && - execute_table_log_entry(part_info->first_log_entry)) - { - /* - We couldn't recover from error - */ - } - else - { - if (not_completed) - { - /* - We hit an error before things were completed but managed - to recover from the error. - */ - } - else - { - /* - We hit an error after we had completed most of the operation - and were successful in a second attempt so the operation - actually is successful now. - */ - } - } fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } From e20cbe27de0b97ad585cc9a6cb002ecff05dea8a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2006 11:08:08 +0100 Subject: [PATCH 033/101] WL 2826: Error handling of ALTER TABLE for partitioning Started writing detailed error handler of ALTER TABLE for partitioning. Philosophical issue, should one always attempt to make recovery automatic or should one rely on manual means also. sql/mysql_priv.h: Flag to ensure we can't be killed in a very critical spot sql/sql_base.cc: Flag to ensure we can't be killed in a very critical spot sql/sql_partition.cc: Started writing detailed error handler of ALTER TABLE for partitioning. Philosophical issue, should one always attempt to make recovery automatic or should one rely on manual means also. --- sql/mysql_priv.h | 3 +- sql/sql_base.cc | 5 +- sql/sql_partition.cc | 177 +++++++++++++++++++++++++++++-------------- 3 files changed, 124 insertions(+), 61 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4a67ab650d9..efdeed8d084 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1218,7 +1218,8 @@ void unlock_global_table_log(); #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); +bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, + bool can_be_killed); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 44b3a22ec52..707b593b044 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6107,7 +6107,8 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, + bool can_be_killed) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; int error= FALSE; @@ -6117,7 +6118,7 @@ bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) VOID(pthread_mutex_lock(&LOCK_open)); mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); - if (lpt->thd->killed) + if (can_be_killed && lpt->thd->killed) { lpt->thd->no_warnings_for_error= 0; error= TRUE; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8f09edcf8cc..a1b9b226f39 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3910,27 +3910,6 @@ end: } -/* - SYNOPSIS - fast_alter_partition_error_handler() - lpt Container for parameters - - RETURN VALUES - None - - DESCRIPTION - Support routine to clean up after failures of on-line ALTER TABLE - for partition management. -*/ - -static void fast_alter_partition_error_handler(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("fast_alter_partition_error_handler"); - /* TODO: WL 2826 Error handling */ - DBUG_VOID_RETURN; -} - - /* SYNOPSIS fast_end_partition() @@ -3952,6 +3931,7 @@ static void fast_alter_partition_error_handler(ALTER_PARTITION_PARAM_TYPE *lpt) static int fast_end_partition(THD *thd, ulonglong copied, ulonglong deleted, + TABLE *table, TABLE_LIST *table_list, bool is_empty, ALTER_PARTITION_PARAM_TYPE *lpt, bool written_bin_log) @@ -3979,7 +3959,7 @@ static int fast_end_partition(THD *thd, ulonglong copied, send_ok(thd,copied+deleted,0L,tmp_name); DBUG_RETURN(FALSE); } - fast_alter_partition_error_handler(lpt); + table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } @@ -4202,7 +4182,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, after the change as before. Thus we can reply ok immediately without any changes at all. */ - DBUG_RETURN(fast_end_partition(thd, ULL(0), ULL(0), NULL, + DBUG_RETURN(fast_end_partition(thd, ULL(0), ULL(0), + table, NULL, TRUE, NULL, FALSE)); } else if (new_part_no > curr_part_no) @@ -5691,25 +5672,61 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) */ static -bool -write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) +void +write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) { partition_info *part_info= lpt->part_info; + uint count_loop= 0; + bool success; TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); DBUG_ASSERT(log_entry); lock_global_table_log(); - if (write_execute_table_log_entry(0UL, TRUE, &log_entry)) + do { - DBUG_RETURN(TRUE); + if (!(success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) + break; + my_sleep(1); + } while (count_loop++ < 20); + if (!success && !dont_crash) + { + /* + Failed to write 20 consecutive attempts to write. Bad... + We have completed the operation but have log records to REMOVE + stuff that shouldn't be removed. What clever things could one do + here? + */ + abort(); } release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); unlock_global_table_log(); part_info->exec_log_entry= NULL; part_info->first_log_entry= NULL; - DBUG_RETURN(FALSE); + DBUG_VOID_RETURN; +} + + +/* + Release all log entries + SYNOPSIS + release_log_entries() + part_info Partition info struct + RETURN VALUES + NONE +*/ + +static +void +release_log_entries(partition *part_info) +{ + lock_global_table_log(); + release_part_info_log_entries(part_info->first_log_entry); + release_part_info_log_entries(part_info->exec_log_entry); + unlock_global_table_log(); + part_info->first_log_entry= NULL; + part_info->exec_log_entry= NULL; } @@ -5724,36 +5741,87 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) */ void -handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed) +handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, + bool drop_partition, bool frm_install) { partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); +#if 0 if (!part_info->first_log_entry && execute_table_log_entry(part_info->first_log_entry)) { /* We couldn't recover from error */ + if (not_completed) + { + if (drop_partition) + { + /* Table is still ok, but we left a shadow frm file behind. */ + write_log_completed(lpt, TRUE); + release_log_entries(part_info); + push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, +"Operation was unsuccessful, table still intact, shadow frm file left behind" + ); + } + } + else + { + if (frm_install && drop_partition) + { + /* + Failed during install of shadow frm file, table isn't intact + and dropped partitions are still there + */ + } + else if (drop_partition) + { + /* + Table is ok, we have switched to new table but left dropped partitions + still in their places. We remove the log records and ask the user to + perform the action manually. We remove the log records and ask the user to + perform the action manually. + */ + char *text1= "Failed during drop of partitions, table is intact, "; + char *text2= "Manual drop of remaining partitions is required"; + write_log_completed(lpt, TRUE); + release_log_entries(part_info); + push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s\n%s", text1, text2); + } + else (frm_install) + { + } + } + } else { + release_log_entries(part_info); if (not_completed) { /* We hit an error before things were completed but managed - to recover from the error. + to recover from the error. An error occurred and we have + restored things to original so no need for further action. */ + ; } else { /* We hit an error after we had completed most of the operation and were successful in a second attempt so the operation - actually is successful now. + actually is successful now. We need to issue a warning that + even though we reported an error the operation was successfully + completed. */ + push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "Operation was successfully completed after failure of normal operation"); } } +#endif DBUG_VOID_RETURN; } @@ -5799,6 +5867,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ALTER_PARTITION_PARAM_TYPE lpt_obj; ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj; bool written_bin_log= TRUE; + bool not_completed= TRUE; + bool frm_install= FALSE; DBUG_ENTER("fast_alter_partition_table"); lpt->thd= thd; @@ -5844,7 +5914,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ((alter_info->flags & ALTER_REPAIR_PARTITION) && (table->file->repair_partitions(thd)))) { - fast_alter_partition_error_handler(lpt); + table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } } @@ -5892,7 +5962,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM) || mysql_change_partitions(lpt)) { - fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } } @@ -5950,7 +6019,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ - bool not_completed= TRUE; if (write_log_drop_shadow_frm(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -5958,26 +6026,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || ((not_completed= FALSE), FALSE) || - abort_and_upgrade_lock(lpt) || + (abort_and_upgrade_lock(lpt, FALSE), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_drop_partition_4") || - mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH("crash_drop_partition_5") || (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || + ERROR_INJECT_CRASH("crash_drop_partition_5") || + ((frm_install= TRUE), FALSE) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ((frm_install= FALSE), FALSE) || + (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_6") || mysql_drop_partitions(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_7") || - write_log_completed(lpt) || + (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { - handle_alter_part_error(lpt, not_completed); - DBUG_RETURN(TRUE); - abort(); - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, TRUE, frm_install); DBUG_RETURN(TRUE); } } @@ -6011,14 +6078,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 8) Remove entries from table log 9) Complete query */ - bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - abort_and_upgrade_lock(lpt) || + (abort_and_upgrade_lock(lpt, FALSE), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6026,16 +6092,14 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_rename_frm(lpt) || ((not_completed= FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || + ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_6") || (close_open_tables_and_downgrade(lpt), FALSE) || - write_log_completed(lpt) || + (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_7")) { - abort(); - if (!not_completed) - abort(); - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); } } @@ -6094,7 +6158,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 13)Wait until all accesses using the old frm file has completed 14)Complete query */ - bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -6104,7 +6167,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || ((not_completed= FALSE), FALSE) || - abort_and_upgrade_lock(lpt) || + (abort_and_upgrade_lock(lpt, FALSE), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6112,19 +6175,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_6") || mysql_rename_partitions(lpt) || + ((frm_install= TRUE), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_9") || - write_log_completed(lpt) || + (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_10") || (mysql_wait_completed_table(lpt, table), FALSE)) { - abort(); - if (!not_completed) - abort(); - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); } } @@ -6133,7 +6194,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, user */ DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted, - table_list, FALSE, lpt, + table, table_list, FALSE, lpt, written_bin_log)); } #endif From f52e37ada8bff017fdd1906d680240b7f4df360b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2006 14:05:15 +0100 Subject: [PATCH 034/101] WL 2826: Error handling of ALTER TABLE for partitioning Final part of the error handling of ALTER TABLE for partitioning sql/sql_partition.cc: Final part of the error handling of ALTER TABLE for partitioning --- sql/sql_partition.cc | 48 +++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a1b9b226f39..743bf4b56e5 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5747,51 +5747,72 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); -#if 0 if (!part_info->first_log_entry && execute_table_log_entry(part_info->first_log_entry)) { /* - We couldn't recover from error + We couldn't recover from error, most likely manual interaction is required. */ + write_log_completed(lpt, FALSE); + release_log_entries(part_info); if (not_completed) { + char *text1= "Operation was unsuccessful, table is still intact, "; if (drop_partition) { /* Table is still ok, but we left a shadow frm file behind. */ - write_log_completed(lpt, TRUE); - release_log_entries(part_info); - push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, -"Operation was unsuccessful, table still intact, shadow frm file left behind" - ); + char *text2= "but it is possible that a shadow frm file was left behind"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s", text1, text2); + } + else + { + char *text2= "but it is possible that a shadow frm file was left behind."; + char *text3= "It is also possible that temporary partitions are left behind, "; + char *text4= "these could be empty or more or less filled with records"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s \n %s \n %s", text1, text2, text3, text4); } } else { - if (frm_install && drop_partition) + if (frm_install) { /* Failed during install of shadow frm file, table isn't intact and dropped partitions are still there */ + char *text1= "Failed during alter of partitions, table is no longer intact, "; + char *text2= "The frm file is in an unknown state, and a backup"; + char *text3= " is required. + push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s%s\n", text1, text2, text3); } else if (drop_partition) { /* Table is ok, we have switched to new table but left dropped partitions still in their places. We remove the log records and ask the user to - perform the action manually. We remove the log records and ask the user to - perform the action manually. + perform the action manually. We remove the log records and ask the user + to perform the action manually. */ char *text1= "Failed during drop of partitions, table is intact, "; char *text2= "Manual drop of remaining partitions is required"; - write_log_completed(lpt, TRUE); - release_log_entries(part_info); push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, "%s\n%s", text1, text2); } - else (frm_install) + else { + /* + We failed during renaming of partitions. The table is most certainly in + a very bad state so we give user warning and disable the table by + writing an ancient frm version into it. + */ + char *text1= "Failed during renaming of partitions. We are now in a position" + char *text2= " where table is not reusable"; + char *text3= "Table is disabled by writing ancient frm file version into it"; + push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s%s\n%s", text1, text2, text3); } } @@ -5821,7 +5842,6 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, "Operation was successfully completed after failure of normal operation"); } } -#endif DBUG_VOID_RETURN; } From de717a9962e28df8541f7e0e0f92239ad697aeb7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Feb 2006 15:07:03 -0500 Subject: [PATCH 035/101] WL 2826: Error handling of ALTER TABLE for partitioning Fix compiler issues sql/ha_heap.cc: Fix compiler warnings sql/ha_myisammrg.cc: Fix compiler warnings sql/log.cc: Fix compiler warnings sql/sql_partition.cc: Fix compiler issues sql/sql_table.cc: Fix compiler issues --- sql/ha_heap.cc | 4 ++- sql/ha_myisammrg.cc | 4 ++- sql/log.cc | 4 ++- sql/sql_partition.cc | 67 +++++++++++++++++++++++++++----------------- sql/sql_table.cc | 48 ++++++++++++++++++++----------- 5 files changed, 81 insertions(+), 46 deletions(-) diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 2fe4bc7aeb5..d3ab7bd9d25 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -57,7 +57,9 @@ handlerton heap_hton= { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog func */ + NULL /* binlog query */ }; static handler *heap_create_handler(TABLE_SHARE *table) diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 36de3dc64e0..1720c9fe0e7 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -67,7 +67,9 @@ handlerton myisammrg_hton= { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog func */ + NULL /* binlog query */ }; static handler *myisammrg_create_handler(TABLE_SHARE *table) diff --git a/sql/log.cc b/sql/log.cc index f6fc6d5cd74..3254fd1712a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -101,7 +101,9 @@ handlerton binlog_hton = { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ - HTON_NOT_USER_SELECTABLE | HTON_HIDDEN + HTON_NOT_USER_SELECTABLE | HTON_HIDDEN, + NULL, /* binlog func */ + NULL /* binlog query */ }; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 743bf4b56e5..c7b75c6548c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5116,6 +5116,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) the partition info object */ +static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint next_entry, @@ -5719,7 +5720,7 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) static void -release_log_entries(partition *part_info) +release_log_entries(partition_info *part_info) { lock_global_table_log(); release_part_info_log_entries(part_info->first_log_entry); @@ -5748,7 +5749,7 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, DBUG_ENTER("handle_alter_part_error"); if (!part_info->first_log_entry && - execute_table_log_entry(part_info->first_log_entry)) + execute_table_log_entry(part_info->first_log_entry->entry_pos)) { /* We couldn't recover from error, most likely manual interaction is required. @@ -5757,19 +5758,24 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, release_log_entries(part_info); if (not_completed) { - char *text1= "Operation was unsuccessful, table is still intact, "; + char *text1= + (char*)"Operation was unsuccessful, table is still intact, "; if (drop_partition) { /* Table is still ok, but we left a shadow frm file behind. */ - char *text2= "but it is possible that a shadow frm file was left behind"; + char *text2= + (char*)"but it is possible that a shadow frm file was left behind"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, "%s \n %s", text1, text2); } else { - char *text2= "but it is possible that a shadow frm file was left behind."; - char *text3= "It is also possible that temporary partitions are left behind, "; - char *text4= "these could be empty or more or less filled with records"; + char *text2= + (char*)"but it is possible that a shadow frm file was left behind."; + char *text3= + (char*)"It is also possible that temporary partitions are left behind, "; + char *text4= + (char*)"these could be empty or more or less filled with records"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, "%s \n %s \n %s \n %s", text1, text2, text3, text4); } @@ -5782,11 +5788,14 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, Failed during install of shadow frm file, table isn't intact and dropped partitions are still there */ - char *text1= "Failed during alter of partitions, table is no longer intact, "; - char *text2= "The frm file is in an unknown state, and a backup"; - char *text3= " is required. - push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s%s\n", text1, text2, text3); + char *text1= + (char*)"Failed during alter of partitions, table is no longer intact, "; + char *text2= + (char*)"The frm file is in an unknown state, and a backup"; + char *text3= + (char*)" is required."; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s%s\n", text1, text2, text3); } else if (drop_partition) { @@ -5796,10 +5805,12 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, perform the action manually. We remove the log records and ask the user to perform the action manually. */ - char *text1= "Failed during drop of partitions, table is intact, "; - char *text2= "Manual drop of remaining partitions is required"; - push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s\n%s", text1, text2); + char *text1= + (char*)"Failed during drop of partitions, table is intact, "; + char *text2= + (char*)"Manual drop of remaining partitions is required"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s\n%s", text1, text2); } else { @@ -5808,11 +5819,14 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, a very bad state so we give user warning and disable the table by writing an ancient frm version into it. */ - char *text1= "Failed during renaming of partitions. We are now in a position" - char *text2= " where table is not reusable"; - char *text3= "Table is disabled by writing ancient frm file version into it"; - push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s%s\n%s", text1, text2, text3); + char *text1= + (char*)"Failed during renaming of partitions. We are now in a position"; + char *text2= + (char*)" where table is not reusable"; + char *text3= + (char*)"Table is disabled by writing ancient frm file version into it"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s%s\n%s", text1, text2, text3); } } @@ -5839,7 +5853,7 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, completed. */ push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "Operation was successfully completed after failure of normal operation"); + "Operation was successfully completed after failure of normal operation"); } } DBUG_VOID_RETURN; @@ -5924,15 +5938,16 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, In this case it is enough to call optimise_partitions, there is no need to change frm files or anything else. */ + int error; written_bin_log= FALSE; if (((alter_info->flags & ALTER_OPTIMIZE_PARTITION) && - (table->file->optimize_partitions(thd))) || + (error= table->file->optimize_partitions(thd))) || ((alter_info->flags & ALTER_ANALYZE_PARTITION) && - (table->file->analyze_partitions(thd))) || + (error= table->file->analyze_partitions(thd))) || ((alter_info->flags & ALTER_CHECK_PARTITION) && - (table->file->check_partitions(thd))) || + (error= table->file->check_partitions(thd))) || ((alter_info->flags & ALTER_REPAIR_PARTITION) && - (table->file->repair_partitions(thd)))) + (error= table->file->repair_partitions(thd)))) { table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8391a976679..963c8e5171e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -321,7 +321,7 @@ read_table_log_file_entry(uint entry_no) DBUG_ENTER("read_table_log_file_entry"); if (my_pread(file_id, file_entry, io_size, io_size * entry_no, - MYF(MY_WME))) + MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); } @@ -549,23 +549,24 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) bool frm_action= FALSE; LEX_STRING handler_name; handler *file; - MEMROOT mem_root; - bool= error= TRUE; + MEM_ROOT mem_root; + bool error= TRUE; char path[FN_REFLEN]; char from_path[FN_REFLEN]; - char *par_ext= ".par"; + char *par_ext= (char*)".par"; + handlerton *hton; DBUG_ENTER("execute_table_log_action"); if (table_log_entry->entry_type == TLOG_IGNORE_LOG_ENTRY_CODE) { DBUG_RETURN(FALSE); } - handler_name.str= table_log_entry->handler_type; + handler_name.str= (char*)table_log_entry->handler_type; handler_name.length= strlen(table_log_entry->handler_type); - hton= ha_resolve_by_name(current_thd, handler_name); + hton= ha_resolve_by_name(current_thd, &handler_name); if (!hton) { - my_error(ER_ILLEGAL_HA, table_log_entry->handler_type); + my_error(ER_ILLEGAL_HA, MYF(0), table_log_entry->handler_type); DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); @@ -573,7 +574,9 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) frm_action= TRUE; else { - file= get_new_handler(table_share, &mem_root, hton); + TABLE_SHARE dummy; + bzero(&dummy, sizeof(TABLE_SHARE)); + file= get_new_handler(&dummy, &mem_root, hton); if (!file) { mem_alloc_error(sizeof(handler)); @@ -581,10 +584,12 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } } switch (table_log_entry->action_type) - case TLOG_ACTION_DELETE_CODE: - case TLOG_ACTION_REPLACE_CODE: - if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE || - (table_log_entry->action_type == TLOG_ACTION_REPLACE_CODE && + { + case TLOG_DELETE_ACTION_CODE: + case TLOG_REPLACE_ACTION_CODE: + { + if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE || + (table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE && table_log_entry->phase == 0UL)) { if (frm_action) @@ -598,7 +603,7 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } else { - if (file->delete_table(table_name)) + if (file->delete_table(table_log_entry->name)) break; } if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) @@ -610,9 +615,11 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } break; } - if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE) + if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE) break; - case TLOG_ACTION_RENAME_CODE: + } + case TLOG_RENAME_ACTION_CODE: + { error= TRUE; if (frm_action) { @@ -639,6 +646,7 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } } break; + } default: DBUG_ASSERT(0); break; @@ -978,7 +986,7 @@ execute_table_log_entry(uint first_entry) DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); - if (execute_table_log_action(file, &table_log_entry)) + if (execute_table_log_action(&table_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ @@ -1028,7 +1036,6 @@ execute_table_log_recovery() } } } - release_handler_objects(); VOID(init_table_log()); DBUG_VOID_RETURN; } @@ -1231,6 +1238,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) } if (flags & WFRM_INSTALL_SHADOW) { +#ifdef WITH_PARTITION_STORAGE_ENGINE + partition_info *part_info= lpt->part_info; +#endif /* Build frm file name */ @@ -1243,17 +1253,21 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || +#ifdef WITH_PARTITION_STORAGE_ENGINE inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || (sync_table_log(), FALSE) || +#endif my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) { error= 1; } VOID(pthread_mutex_unlock(&LOCK_open)); +#ifdef WITH_PARTITION_STORAGE_ENGINE inactivate_table_log_entry(part_info->frm_log_entry->entry_pos); part_info->frm_log_entry= NULL; VOID(sync_table_log()); +#endif } end: From 5b6c6c49b8316d6d8b2f77abafc6743c372385d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Feb 2006 16:22:19 -0500 Subject: [PATCH 036/101] WL 2826: Error handling of ALTER TABLE for partitioning Bug fixes sql/ha_partition.cc: Bug fixes sql/sql_partition.cc: Bug fixes sql/sql_table.cc: Bug fixes --- sql/ha_partition.cc | 14 +++++++------- sql/sql_partition.cc | 6 +++--- sql/sql_table.cc | 5 ++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d65203e1b34..4bc0d4e3327 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -714,10 +714,10 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; else - sub_elem->log_entry= NULL; /* Indicate success */ + part_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); VOID(sync_table_log()); @@ -780,8 +780,8 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - if ((ret_error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff))) + if ((ret_error= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff))) error= ret_error; else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; @@ -797,7 +797,7 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) @@ -810,8 +810,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - if ((ret_error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff))) + if ((ret_error= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff))) error= ret_error; else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c7b75c6548c..6756d345cab 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5678,7 +5678,7 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) { partition_info *part_info= lpt->part_info; uint count_loop= 0; - bool success; + bool not_success; TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); @@ -5686,11 +5686,11 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) lock_global_table_log(); do { - if (!(success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) + if (!(not_success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) break; my_sleep(1); } while (count_loop++ < 20); - if (!success && !dont_crash) + if (not_success && !dont_crash) { /* Failed to write 20 consecutive attempts to write. Bad... diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 963c8e5171e..4db976c34fa 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -435,7 +435,7 @@ read_table_log_header() { if (read_table_log_file_entry(0UL)) { - /* Write message into error log */ + ; /* Write message into error log */ } else successful_open= TRUE; @@ -446,6 +446,8 @@ read_table_log_header() uint4korr(&file_entry[TLOG_HANDLER_TYPE_POS]); if (successful_open) global_table_log.io_size= uint4korr(&file_entry[TLOG_IO_SIZE_POS]); + else + global_table_log.io_size= IO_SIZE; global_table_log.first_free= NULL; global_table_log.first_used= NULL; global_table_log.no_entries= 0; @@ -513,6 +515,7 @@ init_table_log() char file_name[FN_REFLEN]; DBUG_ENTER("init_table_log"); + global_table_log.io_size= IO_SIZE; create_table_log_file_name(file_name); VOID(my_delete(file_name, MYF(0))); if ((global_table_log.file_id= my_create(file_name, From 0da06937929761146d591097bb21f3c3656836d6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Feb 2006 21:50:44 -0500 Subject: [PATCH 037/101] WL 2826: Error handling of ALTER TABLE for partitioning Merged error injects with dbug push sql/mysql_priv.h: Merged error injects with dbug push --- sql/mysql_priv.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0a229d5181b..202c04d0b1c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -625,9 +625,12 @@ struct Query_cache_query_flags inline bool my_error_inject_name(const char *dbug_str) { - if (_db_on_ && _db_strict_keyword_ (dbug_str)) + const char *extra_str= "-d,"; + char total_str[200]; + if (_db_strict_keyword_ (dbug_str)) { - DBUG_DEL_KEYWORD(dbug_str); + strxmov(total_str, extra_str, dbug_str, NullS); + DBUG_SET(total_str); return 1; } return 0; @@ -647,7 +650,7 @@ my_error_inject(int value) } #define ERROR_INJECT_CRASH(code) \ - DBUG_EXECUTE_COND(code, abort()) + DBUG_EVALUATE_IF(code, (abort(), 0), 0) #define ERROR_INJECT_ACTION(code, action) \ (my_error_inject_name(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ From a95646be8d1d56b8ee68ae991ba3c760d9071b94 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Feb 2006 07:49:25 -0500 Subject: [PATCH 038/101] WL 2826: Error handling of ALTER TABLE for partitioning Final fixes dbug/dbug_long.h: Removed patch from dbug_long.h (file not in use anymore) sql/mysql_priv.h: Removed error_inject_code variable --- dbug/dbug_long.h | 13 ------------- sql/mysql_priv.h | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h index 4035ca56b66..829df181ef1 100644 --- a/dbug/dbug_long.h +++ b/dbug/dbug_long.h @@ -127,11 +127,6 @@ # define DBUG_SETJMP setjmp # define DBUG_LONGJMP longjmp # define DBUG_DUMP(keyword,a1) -# define DBUG_EXECUTE_IF(keyword, a1) -# define DBUG_EXECUTE_COND(keyword, a1) 0 -# define DBUG_COND(keyword) 0 -# define DBUG_ADD_KEYWORD(key) -# define DBUG_DEL_KEYWORD(key) # else # define DBUG_ENTER(a) \ auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \ @@ -162,12 +157,4 @@ # define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) # define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) # define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) -# define DBUG_EXECUTE_IF(keyword,a1) \ - {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} -# define DBUG_EXECUTE_COND(keyword, a1) \ - (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) -# define DBUG_COND(keyword) \ - ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) -# define DBUG_ADD_KEYWORD(key) _db_add_strict_keyword_(key) -# define DBUG_DEL_KEYWORD(key) _db_del_strict_keyword_(key) # endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 202c04d0b1c..96576fd8eea 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1395,7 +1395,7 @@ extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; #ifdef ERROR_INJECT_SUPPORT -extern ulong error_inject_code, error_inject_value; +extern ulong error_inject_value; #endif extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; From d48cfa8ac7b7e240b883cbe2287c7f5729e37140 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Mar 2006 02:04:43 -0800 Subject: [PATCH 039/101] Bug #17043: Casting trimmed string to decimal loses precision Results of string functions were being converted to decimals by first being converted to integers, resulting in a loss of precision. mysql-test/r/func_str.result: Add new results mysql-test/t/func_str.test: Add new regression test sql/item_strfunc.cc: Convert string function results to decimal using string-to-decimal conversion sql/item_strfunc.h: Add Item_str_func::val_decimal() --- mysql-test/r/func_str.result | 10 ++++++++++ mysql-test/t/func_str.test | 9 ++++++++- sql/item_strfunc.cc | 14 ++++++++++++++ sql/item_strfunc.h | 1 + 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 911d6eea033..aed79e7f8fa 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1030,3 +1030,13 @@ c res y,abc abc y,abc abc drop table t1; +select cast(rtrim(' 20.06 ') as decimal(19,2)); +cast(rtrim(' 20.06 ') as decimal(19,2)) +20.06 +select cast(ltrim(' 20.06 ') as decimal(19,2)); +cast(ltrim(' 20.06 ') as decimal(19,2)) +20.06 +select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); +cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)) +20.06 +End of 5.0 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index ef20d766bce..85cedee0f4a 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -684,4 +684,11 @@ insert into t1 values ('y,abc'),('y,abc'); select c, substring_index(lcase(c), @q:=',', -1) as res from t1; drop table t1; -# End of 5.0 tests +# +# Bug #17043: Casting trimmed string to decimal loses precision +# +select cast(rtrim(' 20.06 ') as decimal(19,2)); +select cast(ltrim(' 20.06 ') as decimal(19,2)); +select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); + +--echo End of 5.0 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index a3e47154bc3..60183ac9b5a 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -80,6 +80,20 @@ String *Item_str_func::check_well_formed_result(String *str) } +my_decimal *Item_str_func::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + char buff[64]; + String *res, tmp(buff,sizeof(buff), &my_charset_bin); + res= val_str(&tmp); + if (!res) + return 0; + (void)str2my_decimal(E_DEC_FATAL_ERROR, (char*) res->ptr(), + res->length(), res->charset(), decimal_value); + return decimal_value; +} + + double Item_str_func::val_real() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6a95a9e5d1f..7d7b62df0dc 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -33,6 +33,7 @@ public: Item_str_func(List &list) :Item_func(list) {decimals=NOT_FIXED_DEC; } longlong val_int(); double val_real(); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return STRING_RESULT; } void left_right_max_length(); String *check_well_formed_result(String *str); From 1c6f84f8284a297c166c1a53ab117df9b9a5239c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Mar 2006 00:17:22 -0500 Subject: [PATCH 040/101] manual merge --- sql/partition_element.h | 6 +++++- sql/partition_info.h | 9 +++++++-- sql/sql_partition.cc | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sql/partition_element.h b/sql/partition_element.h index d20715d2408..f822f266d4c 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -36,6 +36,8 @@ enum partition_state { PART_IS_ADDED= 8 }; +struct st_table_log_memory_entry; + class partition_element :public Sql_alloc { public: List subpartitions; @@ -44,6 +46,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; + struct st_table_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -55,7 +58,8 @@ public: partition_element() : part_max_rows(0), part_min_rows(0), partition_name(NULL), - tablespace_name(NULL), range_value(0), part_comment(NULL), + tablespace_name(NULL), log_entry(NULL), + range_value(0), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL),part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE) diff --git a/sql/partition_info.h b/sql/partition_info.h index 69aef512a67..eec7db90ad0 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -28,7 +28,7 @@ typedef int (*get_part_id_func)(partition_info *part_info, longlong *func_value); typedef uint32 (*get_subpart_id_func)(partition_info *part_info); - +struct st_table_log_memory_entry; class partition_info : public Sql_alloc { @@ -76,7 +76,11 @@ public: Item *subpart_expr; Item *item_free_list; - + + struct st_table_log_memory_entry *first_log_entry; + struct st_table_log_memory_entry *exec_log_entry; + struct st_table_log_memory_entry *frm_log_entry; + /* A bitmap of partitions used by the current query. Usage pattern: @@ -191,6 +195,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(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), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a02216a113c..57e6a986987 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5157,7 +5157,7 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, if (part_elem->part_state == PART_IS_CHANGED || (part_elem->part_state == PART_IS_ADDED && temp_partitions)) { - if (is_sub_partitioned(part_info)) + if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); uint no_subparts= part_info->no_subparts; @@ -5271,7 +5271,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, name_variant= TEMP_PART_NAME; else name_variant= NORMAL_PART_NAME; - if (is_sub_partitioned(part_info)) + if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); uint no_subparts= part_info->no_subparts; From 81a463adeb9c5c3ed1dd6162cc097c93927156cb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Mar 2006 10:52:12 -0500 Subject: [PATCH 041/101] OPTIMIZE, ANALYZE, CHECK, REPAIR and REBUILD only supported if fast_alter_partition flag set mysql-test/r/ndb_partition_key.result: New test cases for BUG #16819, 16821, and 16822 mysql-test/t/ndb_partition_key.test: New test cases for BUG #16819, 16821, and 16822 sql/handler.h: ensure we don't get hanging after calling change_partition --- mysql-test/r/ndb_partition_key.result | 14 ++++++++++++++ mysql-test/t/ndb_partition_key.test | 19 +++++++++++++++++++ sql/handler.h | 2 +- sql/sql_partition.cc | 5 +++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ndb_partition_key.result b/mysql-test/r/ndb_partition_key.result index 87b019c83e2..121bbe45ead 100644 --- a/mysql-test/r/ndb_partition_key.result +++ b/mysql-test/r/ndb_partition_key.result @@ -165,3 +165,17 @@ ENGINE=NDB PARTITION BY KEY(c3) PARTITIONS 5; ALTER TABLE t1 COALESCE PARTITION 4; DROP TABLE t1; +CREATE TABLE t1 (a int primary key) +ENGINE=NDB +PARTITION BY KEY(a); +ALTER TABLE t1 OPTIMIZE PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 CHECK PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 REPAIR PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 ANALYZE PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 REBUILD PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; diff --git a/mysql-test/t/ndb_partition_key.test b/mysql-test/t/ndb_partition_key.test index d43dc7e49e4..0fd99f8674e 100644 --- a/mysql-test/t/ndb_partition_key.test +++ b/mysql-test/t/ndb_partition_key.test @@ -153,3 +153,22 @@ b'0', ALTER TABLE t1 COALESCE PARTITION 4; DROP TABLE t1; + +# +# Bug 16822: OPTIMIZE TABLE hangs test +# +CREATE TABLE t1 (a int primary key) +ENGINE=NDB +PARTITION BY KEY(a); +--error 1031 +ALTER TABLE t1 OPTIMIZE PARTITION p0; +--error 1031 +ALTER TABLE t1 CHECK PARTITION p0; +--error 1031 +ALTER TABLE t1 REPAIR PARTITION p0; +--error 1031 +ALTER TABLE t1 ANALYZE PARTITION p0; +--error 1031 +ALTER TABLE t1 REBUILD PARTITION p0; +DROP TABLE t1; + diff --git a/sql/handler.h b/sql/handler.h index a7a12c225d4..50088af1d28 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1387,7 +1387,7 @@ public: ulonglong *deleted, const void *pack_frm_data, uint pack_frm_len) - { return HA_ERR_WRONG_COMMAND; } + { print_error(HA_ERR_WRONG_COMMAND, MYF(0)); return TRUE; } virtual int drop_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } virtual int rename_partitions(const char *path) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 57e6a986987..552c99518b7 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4499,6 +4499,11 @@ that are reorganised. my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), ptr); DBUG_RETURN(TRUE); } + if (!(*fast_alter_partition)) + { + table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0)); + DBUG_RETURN(TRUE); + } } else if (alter_info->flags & ALTER_COALESCE_PARTITION) { From 3928d9620fcf96adc94c2d13a7fd216c338eb928 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Mar 2006 18:19:13 -0500 Subject: [PATCH 042/101] WL 2826: Error handling of ALTER TABLE for partitioning Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements 5.1.7 was released still with partition states in clear text Fixed io_size bug Fixed bug in open that TRUNCATED before reading :) file_entry => file_entry_buf Don't open DDL log until first write call to DDL log handler_type => handler_name no => num sql/ha_partition.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log sql/mysql_priv.h: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/mysqld.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/partition_element.h: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/partition_info.h: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/share/errmsg.txt: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/sql_base.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/sql_partition.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements sql/sql_table.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements Fixed io_size bug Fixed bug in open that TRUNCATED before reading :) file_entry => file_entry_buf Don't open DDL log until first write call to DDL log handler_type => handler_name no => num sql/table.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements 5.1.7 was released still with partition states in clear text Fixed io_size bug Fixed bug in open that TRUNCATED before reading :) file_entry => file_entry_buf Don't open DDL log until first write call to DDL log handler_type => handler_name no => num --- sql/ha_partition.cc | 20 +- sql/mysql_priv.h | 133 ++++++--- sql/mysqld.cc | 4 +- sql/partition_element.h | 4 +- sql/partition_info.h | 8 +- sql/share/errmsg.txt | 4 +- sql/sql_base.cc | 11 +- sql/sql_partition.cc | 496 ++++++++++++++----------------- sql/sql_table.cc | 628 ++++++++++++++++++++-------------------- sql/table.cc | 5 +- 10 files changed, 659 insertions(+), 654 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 8351e3e5d01..f3585ff9c5a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -701,7 +701,7 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ @@ -716,13 +716,13 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; else part_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); - VOID(sync_table_log()); + VOID(sync_ddl_log()); } i= 0; do @@ -771,9 +771,9 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; - VOID(sync_table_log()); + VOID(sync_ddl_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -785,7 +785,7 @@ int ha_partition::rename_partitions(const char *path) if ((ret_error= file->rename_table((const char *) part_name_buff, (const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; @@ -802,9 +802,9 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; - VOID(sync_table_log()); + VOID(sync_ddl_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -815,14 +815,14 @@ int ha_partition::rename_partitions(const char *path) if ((ret_error= file->rename_table((const char *) part_name_buff, (const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; else part_elem->log_entry= NULL; } } } while (++i < no_parts); - VOID(sync_table_log()); + VOID(sync_ddl_log()); DBUG_RETURN(error); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d8bac64faca..265d2840025 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -631,9 +631,6 @@ struct Query_cache_query_flags #else -#define SET_ERROR_INJECT_VALUE(x) \ - current_thd->error_inject_value= (x) - inline bool my_error_inject_name(const char *dbug_str) { @@ -661,6 +658,43 @@ my_error_inject(int value) 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) \ @@ -1186,57 +1220,86 @@ typedef struct st_lock_param_type void mem_alloc_error(size_t size); -typedef struct st_table_log_entry +enum ddl_log_entry_code +{ + /* + DDL_LOG_EXECUTE_CODE: + This is a code that indicates that this is a log entry to + be executed, from this entry a linked list of log entries + can be found and executed. + DDL_LOG_ENTRY_CODE: + An entry to be executed in a linked list from an execute log + entry. + DDL_IGNORE_LOG_ENTRY_CODE: + An entry that is to be ignored + */ + DDL_LOG_EXECUTE_CODE = 'e', + DDL_LOG_ENTRY_CODE = 'l', + DDL_IGNORE_LOG_ENTRY_CODE = 'i' +}; + +enum ddl_log_action_code +{ + /* + The type of action that a DDL_LOG_ENTRY_CODE entry is to + perform. + DDL_LOG_DELETE_ACTION: + Delete an entity + DDL_LOG_RENAME_ACTION: + Rename an entity + DDL_LOG_REPLACE_ACTION: + Rename an entity after removing the previous entry with the + new name, that is replace this entry. + */ + DDL_LOG_DELETE_ACTION = 'd', + DDL_LOG_RENAME_ACTION = 'r', + DDL_LOG_REPLACE_ACTION = 's' +}; + + +typedef struct st_ddl_log_entry { const char *name; const char *from_name; - const char *handler_type; + const char *handler_name; uint next_entry; uint entry_pos; - char action_type; - char entry_type; + enum ddl_log_entry_code entry_type; + enum ddl_log_action_code action_type; char phase; - char not_used; -} TABLE_LOG_ENTRY; +} DDL_LOG_ENTRY; -typedef struct st_table_log_memory_entry +typedef struct st_ddl_log_memory_entry { uint entry_pos; - struct st_table_log_memory_entry *next_log_entry; - struct st_table_log_memory_entry *prev_log_entry; - struct st_table_log_memory_entry *next_active_log_entry; -} TABLE_LOG_MEMORY_ENTRY; + struct st_ddl_log_memory_entry *next_log_entry; + struct st_ddl_log_memory_entry *prev_log_entry; + struct st_ddl_log_memory_entry *next_active_log_entry; +} DDL_LOG_MEMORY_ENTRY; -#define TLOG_EXECUTE_CODE 'e' -#define TLOG_LOG_ENTRY_CODE 'l' -#define TLOG_IGNORE_LOG_ENTRY_CODE 'i' -#define TLOG_DELETE_ACTION_CODE 'd' -#define TLOG_RENAME_ACTION_CODE 'r' -#define TLOG_REPLACE_ACTION_CODE 's' -#define TLOG_HANDLER_TYPE_LEN 32 +#define DDL_LOG_HANDLER_TYPE_LEN 32 -bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - TABLE_LOG_MEMORY_ENTRY **active_entry); -bool write_execute_table_log_entry(uint first_entry, +bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, + DDL_LOG_MEMORY_ENTRY **active_entry); +bool write_execute_ddl_log_entry(uint first_entry, bool complete, - TABLE_LOG_MEMORY_ENTRY **active_entry); -bool inactivate_table_log_entry(uint entry_no); -void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); -bool sync_table_log(); -void release_table_log(); -void execute_table_log_recovery(); -bool execute_table_log_entry(uint first_entry); -void lock_global_table_log(); -void unlock_global_table_log(); + DDL_LOG_MEMORY_ENTRY **active_entry); +bool deactivate_ddl_log_entry(uint entry_no); +void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry); +bool sync_ddl_log(); +void release_ddl_log(); +void execute_ddl_log_recovery(); +bool execute_ddl_log_entry(uint first_entry); +void lock_global_ddl_log(); +void unlock_global_ddl_log(); #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, - bool can_be_killed); +void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 41233849094..a262b369ae3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3665,7 +3665,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); unireg_abort(1); } } - execute_table_log_recovery(); + execute_ddl_log_recovery(); create_shutdown_thread(); create_maintenance_thread(); @@ -3696,7 +3696,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); - release_table_log(); + release_ddl_log(); #ifndef __WIN__ #ifdef EXTRA_DEBUG2 diff --git a/sql/partition_element.h b/sql/partition_element.h index f822f266d4c..13693934c0f 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -36,7 +36,7 @@ enum partition_state { PART_IS_ADDED= 8 }; -struct st_table_log_memory_entry; +struct st_ddl_log_memory_entry; class partition_element :public Sql_alloc { public: @@ -46,7 +46,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; - struct st_table_log_memory_entry *log_entry; + struct st_ddl_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; diff --git a/sql/partition_info.h b/sql/partition_info.h index eec7db90ad0..829f5f9b72c 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -28,7 +28,7 @@ typedef int (*get_part_id_func)(partition_info *part_info, longlong *func_value); typedef uint32 (*get_subpart_id_func)(partition_info *part_info); -struct st_table_log_memory_entry; +struct st_ddl_log_memory_entry; class partition_info : public Sql_alloc { @@ -77,9 +77,9 @@ public: Item *item_free_list; - struct st_table_log_memory_entry *first_log_entry; - struct st_table_log_memory_entry *exec_log_entry; - struct st_table_log_memory_entry *frm_log_entry; + struct st_ddl_log_memory_entry *first_log_entry; + struct st_ddl_log_memory_entry *exec_log_entry; + struct st_ddl_log_memory_entry *frm_log_entry; /* A bitmap of partitions used by the current query. diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index b05a57f714e..9aa4d2f74eb 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5826,5 +5826,5 @@ ER_NDB_CANT_SWITCH_BINLOG_FORMAT eng "The NDB cluster engine does not support changing the binlog format on the fly yet" ER_PARTITION_NO_TEMPORARY eng "Cannot create temporary table with partitions" -ER_TABLE_LOG_ERROR - eng "Error in table log" +ER_DDL_LOG_ERROR + eng "Error in DDL log" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5419416ef3c..ed893f35aec 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6124,24 +6124,17 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, - bool can_be_killed) +void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; - int error= FALSE; DBUG_ENTER("abort_and_upgrade_locks"); lpt->old_lock_type= lpt->table->reginfo.lock_type; VOID(pthread_mutex_lock(&LOCK_open)); mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); - if (can_be_killed && lpt->thd->killed) - { - lpt->thd->no_warnings_for_error= 0; - error= TRUE; - } VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_RETURN(error); + DBUG_VOID_RETURN; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 552c99518b7..682b9f783ba 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5037,10 +5037,8 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) NONE */ -static -void -insert_part_info_log_entry_list(partition_info *part_info, - TABLE_LOG_MEMORY_ENTRY *log_entry) +static void insert_part_info_log_entry_list(partition_info *part_info, + DDL_LOG_MEMORY_ENTRY *log_entry) { log_entry->next_active_log_entry= part_info->first_log_entry; part_info->first_log_entry= log_entry; @@ -5056,15 +5054,13 @@ insert_part_info_log_entry_list(partition_info *part_info, NONE */ -static -void -release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) +static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry) { DBUG_ENTER("release_part_info_log_entries"); while (log_entry) { - release_table_log_memory_entry(log_entry); + release_ddl_log_memory_entry(log_entry); log_entry= log_entry->next_active_log_entry; } DBUG_VOID_RETURN; @@ -5084,32 +5080,30 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) FALSE Success DESCRIPTION Support routine that writes a replace or delete of an frm file into the - table log. It also inserts an entry that keeps track of used space into + ddl log. It also inserts an entry that keeps track of used space into the partition info object */ -static -bool -write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, - uint next_entry, - const char *from_path, - const char *to_path, - bool replace_flag) +static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, + uint next_entry, + const char *from_path, + const char *to_path, + bool replace_flag) { - TABLE_LOG_ENTRY table_log_entry; - TABLE_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_ENTRY ddl_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; DBUG_ENTER("write_log_replace_delete_frm"); if (replace_flag) - table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; else - table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; - table_log_entry.next_entry= next_entry; - table_log_entry.handler_type= "frm"; - table_log_entry.name= to_path; + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; + ddl_log_entry.next_entry= next_entry; + ddl_log_entry.handler_name= "frm"; + ddl_log_entry.name= to_path; if (replace_flag) - table_log_entry.from_name= from_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.from_name= from_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5140,14 +5134,12 @@ write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, the partition handler. */ -static -bool -write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, - uint *next_entry, const char *path) +static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, const char *path) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; char normal_path[FN_LEN]; List_iterator part_it(part_info->partitions); @@ -5170,8 +5162,8 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, do { partition_element *sub_elem= sub_it++; - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); create_subpartition_name(tmp_path, path, part_elem->partition_name, @@ -5181,13 +5173,13 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - table_log_entry.name= normal_path; - table_log_entry.from_name= tmp_path; + ddl_log_entry.name= normal_path; + ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; else - table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5198,8 +5190,8 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } else { - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); create_partition_name(tmp_path, path, part_elem->partition_name, @@ -5207,13 +5199,13 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, create_partition_name(normal_path, path, part_elem->partition_name, NORMAL_PART_NAME, TRUE); - table_log_entry.name= normal_path; - table_log_entry.from_name= tmp_path; + ddl_log_entry.name= normal_path; + ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; else - table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5237,16 +5229,14 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, FALSE Success */ -static -bool -write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, - uint *next_entry, - const char *path, - bool temp_list) +static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, + const char *path, + bool temp_list) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); List_iterator temp_it(part_info->temp_partitions); @@ -5255,7 +5245,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); - table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; if (temp_list) no_elements= no_temp_partitions; while (no_elements--) @@ -5284,15 +5274,15 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, do { partition_element *sub_elem= sub_it++; - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); create_subpartition_name(tmp_path, path, part_elem->partition_name, sub_elem->partition_name, name_variant); - table_log_entry.name= tmp_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.name= tmp_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5304,14 +5294,14 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } else { - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); create_partition_name(tmp_path, path, part_elem->partition_name, name_variant, TRUE); - table_log_entry.name= tmp_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.name= tmp_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5327,7 +5317,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, /* - Set execute log entry in table log for this partitioned table + Set execute log entry in ddl log for this partitioned table SYNOPSIS set_part_info_exec_log_entry() part_info Partition info object @@ -5336,10 +5326,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, NONE */ -static -void -set_part_info_exec_log_entry(partition_info *part_info, - TABLE_LOG_MEMORY_ENTRY *exec_log_entry) +static void set_part_info_exec_log_entry(partition_info *part_info, + DDL_LOG_MEMORY_ENTRY *exec_log_entry) { part_info->exec_log_entry= exec_log_entry; exec_log_entry->next_active_log_entry= NULL; @@ -5358,41 +5346,38 @@ set_part_info_exec_log_entry(partition_info *part_info, TRUE Error FALSE Success DESCRIPTION - Prepare an entry to the table log indicating a drop/install of the shadow frm + Prepare an entry to the ddl log indicating a drop/install of the shadow frm file and its corresponding handler file. */ -static -bool -write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char shadow_path[FN_LEN]; DBUG_ENTER("write_log_drop_shadow_frm"); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_replace_delete_frm(lpt, 0UL, NULL, - (const char*)shadow_path, FALSE)) - break; - log_entry= part_info->first_log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - unlock_global_table_log(); - set_part_info_exec_log_entry(part_info, exec_log_entry); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_replace_delete_frm(lpt, 0UL, NULL, + (const char*)shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + unlock_global_ddl_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5410,17 +5395,15 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) file if failure occurs in the middle of the rename process. */ -static -bool -write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char path[FN_LEN]; char shadow_path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_rename_frm"); part_info->first_log_entry= NULL; @@ -5428,25 +5411,24 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) - break; - log_entry= part_info->first_log_entry; - part_info->frm_log_entry= log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - release_part_info_log_entries(old_first_log_entry); - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + unlock_global_ddl_log(); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5462,22 +5444,20 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) TRUE Error FALSE Success DESCRIPTION - Prepare entries to the table log indicating all partitions to drop and to + Prepare entries to the ddl log indicating all partitions to drop and to install the shadow frm file and remove the old frm file. */ -static -bool -write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_partition"); part_info->first_log_entry= NULL; @@ -5485,29 +5465,28 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - FALSE)) - break; - if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, - (const char*)tmp_path, TRUE)) - break; - log_entry= part_info->first_log_entry; - part_info->frm_log_entry= log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - release_part_info_log_entries(old_first_log_entry); - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) + goto error; + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, + (const char*)tmp_path, TRUE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + unlock_global_ddl_log(); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5523,19 +5502,17 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) TRUE Error FALSE Success DESCRIPTION - Prepare entries to the table log indicating all partitions to drop and to + Prepare entries to the ddl log indicating all partitions to drop and to remove the shadow frm file. - We always inject entries backwards in the list in the table log since we + We always inject entries backwards in the list in the ddl log since we don't know the entry position until we have written it. */ -static -bool -write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; @@ -5545,27 +5522,26 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - FALSE)) - break; - if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, - FALSE)) - break; - log_entry= part_info->first_log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - unlock_global_table_log(); - set_part_info_exec_log_entry(part_info, exec_log_entry); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) + goto error; + if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, + FALSE)) + goto error; + log_entry= part_info->first_log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + unlock_global_ddl_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5586,17 +5562,15 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) frm file. */ -static -bool -write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char path[FN_LEN]; char shadow_path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; uint next_entry= 0; DBUG_ENTER("write_log_final_change_partition"); @@ -5605,36 +5579,35 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - TRUE)) - break; - if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) - break; - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) - break; - log_entry= part_info->first_log_entry; - part_info->frm_log_entry= log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - release_part_info_log_entries(old_first_log_entry); - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + TRUE)) + goto error; + if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) + goto error; + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + unlock_global_ddl_log(); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } /* - Remove entry from table log and release resources for others to use + Remove entry from ddl log and release resources for others to use SYNOPSIS write_log_completed() @@ -5644,37 +5617,30 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE Success */ -static -void -write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) +static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, + bool dont_crash) { partition_info *part_info= lpt->part_info; uint count_loop= 0; bool not_success; - TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); DBUG_ASSERT(log_entry); - lock_global_table_log(); - do - { - if (!(not_success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) - break; - my_sleep(1); - } while (count_loop++ < 20); - if (not_success && !dont_crash) + lock_global_ddl_log(); + if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry)) { /* - Failed to write 20 consecutive attempts to write. Bad... + Failed to write, Bad... We have completed the operation but have log records to REMOVE stuff that shouldn't be removed. What clever things could one do here? */ - abort(); + ; } release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->exec_log_entry= NULL; part_info->first_log_entry= NULL; DBUG_VOID_RETURN; @@ -5690,14 +5656,12 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) NONE */ -static -void -release_log_entries(partition_info *part_info) +static void release_log_entries(partition_info *part_info) { - lock_global_table_log(); + lock_global_ddl_log(); release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= NULL; part_info->exec_log_entry= NULL; } @@ -5713,43 +5677,41 @@ release_log_entries(partition_info *part_info) NONE */ -void -handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, - bool drop_partition, bool frm_install) +void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, + bool not_completed, + bool drop_partition, + bool frm_install) { partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); if (!part_info->first_log_entry && - execute_table_log_entry(part_info->first_log_entry->entry_pos)) + execute_ddl_log_entry(part_info->first_log_entry->entry_pos)) { /* - We couldn't recover from error, most likely manual interaction is required. + We couldn't recover from error, most likely manual interaction + is required. */ write_log_completed(lpt, FALSE); release_log_entries(part_info); if (not_completed) { - char *text1= - (char*)"Operation was unsuccessful, table is still intact, "; if (drop_partition) { /* Table is still ok, but we left a shadow frm file behind. */ - char *text2= - (char*)"but it is possible that a shadow frm file was left behind"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s", text1, text2); + "%s %s", + "Operation was unsuccessful, table is still intact,", + "but it is possible that a shadow frm file was left behind"); } else { - char *text2= - (char*)"but it is possible that a shadow frm file was left behind."; - char *text3= - (char*)"It is also possible that temporary partitions are left behind, "; - char *text4= - (char*)"these could be empty or more or less filled with records"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s \n %s \n %s", text1, text2, text3, text4); + "%s %s %s %s", + "Operation was unsuccessful, table is still intact,", + "but it is possible that a shadow frm file was left behind.", + "It is also possible that temporary partitions are left behind,", + "these could be empty or more or less filled with records"); } } else @@ -5760,48 +5722,39 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, Failed during install of shadow frm file, table isn't intact and dropped partitions are still there */ - char *text1= - (char*)"Failed during alter of partitions, table is no longer intact, "; - char *text2= - (char*)"The frm file is in an unknown state, and a backup"; - char *text3= - (char*)" is required."; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s%s\n", text1, text2, text3); + "%s %s %s", + "Failed during alter of partitions, table is no longer intact.", + "The frm file is in an unknown state, and a backup", + "is required."); } else if (drop_partition) { /* - Table is ok, we have switched to new table but left dropped partitions - still in their places. We remove the log records and ask the user to - perform the action manually. We remove the log records and ask the user - to perform the action manually. + Table is ok, we have switched to new table but left dropped + partitions still in their places. We remove the log records and + ask the user to perform the action manually. We remove the log + records and ask the user to perform the action manually. */ - char *text1= - (char*)"Failed during drop of partitions, table is intact, "; - char *text2= - (char*)"Manual drop of remaining partitions is required"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s\n%s", text1, text2); + "%s %s", + "Failed during drop of partitions, table is intact.", + "Manual drop of remaining partitions is required"); } else { /* - We failed during renaming of partitions. The table is most certainly in - a very bad state so we give user warning and disable the table by - writing an ancient frm version into it. + We failed during renaming of partitions. The table is most + certainly in a very bad state so we give user warning and disable + the table by writing an ancient frm version into it. */ - char *text1= - (char*)"Failed during renaming of partitions. We are now in a position"; - char *text2= - (char*)" where table is not reusable"; - char *text3= - (char*)"Table is disabled by writing ancient frm file version into it"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s%s\n%s", text1, text2, text3); + "%s %s %s", + "Failed during renaming of partitions. We are now in a position", + "where table is not reusable", + "Table is disabled by writing ancient frm file version into it"); } } - } else { @@ -5824,8 +5777,9 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, even though we reported an error the operation was successfully completed. */ - push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "Operation was successfully completed after failure of normal operation"); + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,"%s %s", + "Operation was successfully completed by failure handling,", + "after failure of normal operation"); } } DBUG_VOID_RETURN; @@ -5999,7 +5953,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 0) Write an entry that removes the shadow frm file if crash occurs 1) Write the new frm file as a shadow frm - 2) Write the table log to ensure that the operation is completed + 2) Write the ddl log to ensure that the operation is completed even in the presence of a MySQL Server crash 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to the table have completed @@ -6010,8 +5964,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, where crashes make strange things occur. In this placement it can happen that the ALTER TABLE DROP PARTITION gets performed in the master but not in the slaves if we have a crash, after writing the - table log but before writing the binlog. A solution to this would - require writing the statement first in the table log and then + ddl log but before writing the binlog. A solution to this would + require writing the statement first in the ddl log and then when recovering from the crash read the binlog and insert it into the binlog if not written already. 5) Install the previously written shadow frm file @@ -6019,7 +5973,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, reached the abort lock do that before downgrading the lock. 7) Prepare MyISAM handlers for drop of partitions 8) Drop the partitions - 9) Remove entries from table log + 9) Remove entries from ddl log 10) Wait until all accesses using the old frm file has completed 11) Complete query @@ -6033,7 +5987,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt, FALSE), FALSE) || + (abort_and_upgrade_lock(lpt), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6070,7 +6024,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 0) Write an entry that removes the shadow frm file if crash occurs 1) Write the new frm file as a shadow frm file - 2) Log the changes to happen in table log + 2) Log the changes to happen in ddl log 2) Add the new partitions 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all @@ -6082,7 +6036,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 6) Install the new frm file of the table where the partitions are added to the table. 7) Wait until all accesses using the old frm file has completed - 8) Remove entries from table log + 8) Remove entries from ddl log 9) Complete query */ if (write_log_add_change_partition(lpt) || @@ -6091,7 +6045,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - (abort_and_upgrade_lock(lpt, FALSE), FALSE) || + (abort_and_upgrade_lock(lpt), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6174,7 +6128,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt, FALSE), FALSE) || + (abort_and_upgrade_lock(lpt), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7d2dfe6f78c..86a3259484a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -244,7 +244,7 @@ static int mysql_copy_key_list(List *orig_key, /* -------------------------------------------------------------------------- - MODULE: Table log + MODULE: DDL log ----------------- This module is used to ensure that we can recover from crashes that occur @@ -253,12 +253,12 @@ static int mysql_copy_key_list(List *orig_key, also that each table drop is entirely done and not "half-baked". To support this we create log entries for each meta-data statement in the - table log while we are executing. These entries are dropped when the + ddl log while we are executing. These entries are dropped when the operation is completed. At recovery those entries that were not completed will be executed. - There is only one table log in the system and it is protected by a mutex + There is only one ddl log in the system and it is protected by a mutex and there is a global struct that contains information about its current state. @@ -268,82 +268,79 @@ static int mysql_copy_key_list(List *orig_key, */ -typedef struct st_global_table_log +typedef struct st_global_ddl_log { - char file_entry[IO_SIZE]; + char file_entry_buf[4*IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; - TABLE_LOG_MEMORY_ENTRY *first_free; - TABLE_LOG_MEMORY_ENTRY *first_used; - uint no_entries; + DDL_LOG_MEMORY_ENTRY *first_free; + DDL_LOG_MEMORY_ENTRY *first_used; + uint num_entries; File file_id; uint name_len; - uint handler_type_len; + uint handler_name_len; uint io_size; -} GLOBAL_TABLE_LOG; + bool inited; +} GLOBAL_DDL_LOG; -GLOBAL_TABLE_LOG global_table_log; +GLOBAL_DDL_LOG global_ddl_log; -pthread_mutex_t LOCK_gtl; +pthread_mutex_t LOCK_gdl; -#define TLOG_ENTRY_TYPE_POS 0 -#define TLOG_ACTION_TYPE_POS 1 -#define TLOG_PHASE_POS 2 -#define TLOG_NEXT_ENTRY_POS 4 -#define TLOG_NAME_POS 8 +#define DDL_LOG_ENTRY_TYPE_POS 0 +#define DDL_LOG_ACTION_TYPE_POS 1 +#define DDL_LOG_PHASE_POS 2 +#define DDL_LOG_NEXT_ENTRY_POS 4 +#define DDL_LOG_NAME_POS 8 -#define TLOG_NO_ENTRY_POS 0 -#define TLOG_NAME_LEN_POS 4 -#define TLOG_HANDLER_TYPE_POS 8 -#define TLOG_IO_SIZE_POS 12 +#define DDL_LOG_NUM_ENTRY_POS 0 +#define DDL_LOG_NAME_LEN_POS 4 +#define DDL_LOG_HANDLER_TYPE_POS 8 +#define DDL_LOG_IO_SIZE_POS 12 /* - Read one entry from table log file + Read one entry from ddl log file SYNOPSIS - read_table_log_file_entry() + read_ddl_log_file_entry() entry_no Entry number to read RETURN VALUES TRUE Error FALSE Success */ -static -bool -read_table_log_file_entry(uint entry_no) +static bool read_ddl_log_file_entry(uint entry_no) { bool error= FALSE; - File file_id= global_table_log.file_id; - char *file_entry= (char*)global_table_log.file_entry; - uint io_size= global_table_log.io_size; - DBUG_ENTER("read_table_log_file_entry"); + File file_id= global_ddl_log.file_id; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + uint io_size= global_ddl_log.io_size; + DBUG_ENTER("read_ddl_log_file_entry"); - if (my_pread(file_id, file_entry, io_size, io_size * entry_no, - MYF(MY_WME)) != IO_SIZE) + if (my_pread(file_id, file_entry_buf, io_size, io_size * entry_no, + MYF(MY_WME)) != io_size) error= TRUE; DBUG_RETURN(error); } /* - Write one entry from table log file + Write one entry from ddl log file SYNOPSIS - write_table_log_file_entry() + write_ddl_log_file_entry() entry_no Entry number to read RETURN VALUES TRUE Error FALSE Success */ -static -bool -write_table_log_file_entry(uint entry_no) +static bool write_ddl_log_file_entry(uint entry_no) { bool error= FALSE; - File file_id= global_table_log.file_id; - char *file_entry= (char*)global_table_log.file_entry; - DBUG_ENTER("write_table_log_file_entry"); + File file_id= global_ddl_log.file_id; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("write_ddl_log_file_entry"); - if (my_pwrite(file_id, file_entry, + if (my_pwrite(file_id, file_entry_buf, IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); @@ -351,200 +348,197 @@ write_table_log_file_entry(uint entry_no) /* - Write table log header + Write ddl log header SYNOPSIS - write_table_log_header() + write_ddl_log_header() RETURN VALUES TRUE Error FALSE Success */ -static -bool -write_table_log_header() +static bool write_ddl_log_header() { uint16 const_var; bool error= FALSE; - DBUG_ENTER("write_table_log_header"); + DBUG_ENTER("write_ddl_log_header"); - int4store(&global_table_log.file_entry[TLOG_NO_ENTRY_POS], - global_table_log.no_entries); + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS], + global_ddl_log.num_entries); const_var= FN_LEN; - int4store(&global_table_log.file_entry[TLOG_NAME_LEN_POS], + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], const_var); - const_var= TLOG_HANDLER_TYPE_LEN; - int4store(&global_table_log.file_entry[TLOG_HANDLER_TYPE_POS], + const_var= DDL_LOG_HANDLER_TYPE_LEN; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_HANDLER_TYPE_POS], const_var); const_var= IO_SIZE; - int4store(&global_table_log.file_entry[TLOG_IO_SIZE_POS], + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], const_var); - if (write_table_log_file_entry(0UL)) + if (write_ddl_log_file_entry(0UL)) error= TRUE; if (!error) - VOID(sync_table_log()); + VOID(sync_ddl_log()); DBUG_RETURN(error); } /* - Create table log file name + Create ddl log file name SYNOPSIS - create_table_log_file_name() + create_ddl_log_file_name() file_name Filename setup RETURN VALUES NONE */ -static -void -create_table_log_file_name(char *file_name) +static inline void create_ddl_log_file_name(char *file_name) { - strxmov(file_name, mysql_data_home, "/", "table_log.log", NullS); + strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS); } /* - Read header of table log file + Read header of ddl log file SYNOPSIS - read_table_log_header() + read_ddl_log_header() RETURN VALUES - > 0 Last entry in table log - 0 No entries in table log + > 0 Last entry in ddl log + 0 No entries in ddl log DESCRIPTION - When we read the table log header we get information about maximum sizes - of names in the table log and we also get information about the number - of entries in the table log. + When we read the ddl log header we get information about maximum sizes + of names in the ddl log and we also get information about the number + of entries in the ddl log. */ -static -uint -read_table_log_header() +static uint read_ddl_log_header() { - char *file_entry= (char*)global_table_log.file_entry; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; char file_name[FN_REFLEN]; uint entry_no; bool successful_open= FALSE; - DBUG_ENTER("read_table_log_header"); + DBUG_ENTER("read_ddl_log_header"); - bzero(file_entry, sizeof(global_table_log.file_entry)); - create_table_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(MY_WME)))) + bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); + global_ddl_log.inited= FALSE; + create_ddl_log_file_name(file_name); + if (!(my_open(file_name, O_RDONLY | O_BINARY, MYF(MY_WME)))) { - if (read_table_log_file_entry(0UL)) + if (read_ddl_log_file_entry(0UL)) { ; /* Write message into error log */ } else successful_open= TRUE; } - entry_no= uint4korr(&file_entry[TLOG_NO_ENTRY_POS]); - global_table_log.name_len= uint4korr(&file_entry[TLOG_NAME_LEN_POS]); - global_table_log.handler_type_len= - uint4korr(&file_entry[TLOG_HANDLER_TYPE_POS]); + entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); + global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); + global_ddl_log.handler_name_len= + uint4korr(&file_entry_buf[DDL_LOG_HANDLER_TYPE_POS]); if (successful_open) - global_table_log.io_size= uint4korr(&file_entry[TLOG_IO_SIZE_POS]); + global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); else - global_table_log.io_size= IO_SIZE; - global_table_log.first_free= NULL; - global_table_log.first_used= NULL; - global_table_log.no_entries= 0; - VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); + global_ddl_log.io_size= IO_SIZE; + global_ddl_log.first_free= NULL; + global_ddl_log.first_used= NULL; + global_ddl_log.num_entries= 0; + VOID(pthread_mutex_init(&LOCK_gdl, MY_MUTEX_INIT_FAST)); DBUG_RETURN(entry_no); } /* - Read a table log entry + Read a ddl log entry SYNOPSIS - read_table_log_entry() + read_ddl_log_entry() read_entry Number of entry to read out:entry_info Information from entry RETURN VALUES TRUE Error FALSE Success DESCRIPTION - Read a specified entry in the table log + Read a specified entry in the ddl log */ -bool -read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) +bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) { - char *file_entry= (char*)&global_table_log.file_entry; + char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; uint inx; - DBUG_ENTER("read_table_log_entry"); + DBUG_ENTER("read_ddl_log_entry"); - if (read_table_log_file_entry(read_entry)) + if (read_ddl_log_file_entry(read_entry)) { /* Error handling */ DBUG_RETURN(TRUE); } - table_log_entry->entry_pos= read_entry; - table_log_entry->entry_type= file_entry[TLOG_ENTRY_TYPE_POS]; - table_log_entry->action_type= file_entry[TLOG_ACTION_TYPE_POS]; - table_log_entry->phase= file_entry[TLOG_PHASE_POS]; - table_log_entry->next_entry= uint4korr(&file_entry[TLOG_NEXT_ENTRY_POS]); - table_log_entry->name= &file_entry[TLOG_NAME_POS]; - inx= TLOG_NAME_POS + global_table_log.name_len; - table_log_entry->from_name= &file_entry[inx]; - inx+= global_table_log.name_len; - table_log_entry->handler_type= &file_entry[inx]; + ddl_log_entry->entry_pos= read_entry; + ddl_log_entry->entry_type= + (enum ddl_log_entry_code)file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; + ddl_log_entry->action_type= + (enum ddl_log_action_code)file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; + ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); + ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; + inx= DDL_LOG_NAME_POS + global_ddl_log.name_len; + ddl_log_entry->from_name= &file_entry_buf[inx]; + inx+= global_ddl_log.name_len; + ddl_log_entry->handler_name= &file_entry_buf[inx]; DBUG_RETURN(FALSE); } /* - Initialise table log + Initialise ddl log SYNOPSIS - init_table_log() + init_ddl_log() RETURN VALUES TRUE Error FALSE Success DESCRIPTION - Write the header of the table log file and length of names. Also set + Write the header of the ddl log file and length of names. Also set number of entries to zero. */ -static -bool -init_table_log() +static bool init_ddl_log() { bool error= FALSE; char file_name[FN_REFLEN]; - DBUG_ENTER("init_table_log"); + DBUG_ENTER("init_ddl_log"); - global_table_log.io_size= IO_SIZE; - create_table_log_file_name(file_name); - VOID(my_delete(file_name, MYF(0))); - if ((global_table_log.file_id= my_create(file_name, - CREATE_MODE, - O_RDWR | O_TRUNC | O_BINARY, - MYF(MY_WME))) < 0) + if (global_ddl_log.inited) { - /* Couldn't create table log file, this is serious error */ + DBUG_RETURN(FALSE); + } + global_ddl_log.io_size= IO_SIZE; + create_ddl_log_file_name(file_name); + VOID(my_delete(file_name, MYF(0))); + if ((global_ddl_log.file_id= my_create(file_name, + CREATE_MODE, + O_RDWR | O_TRUNC | O_BINARY, + MYF(MY_WME))) < 0) + { + /* Couldn't create ddl log file, this is serious error */ abort(); } - if (write_table_log_header()) + if (write_ddl_log_header()) { /* Write to error log */ error= TRUE; } + global_ddl_log.inited= TRUE; DBUG_RETURN(error); } /* - Execute one action in a table log entry + Execute one action in a ddl log entry SYNOPSIS - execute_table_log_action() - table_log_entry Information in action entry to execute + execute_ddl_log_action() + ddl_log_entry Information in action entry to execute RETURN VALUES TRUE Error FALSE Success */ -static -bool -execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) +static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; @@ -555,22 +549,22 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) char from_path[FN_REFLEN]; char *par_ext= (char*)".par"; handlerton *hton; - DBUG_ENTER("execute_table_log_action"); + DBUG_ENTER("execute_ddl_log_action"); - if (table_log_entry->entry_type == TLOG_IGNORE_LOG_ENTRY_CODE) + if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE) { DBUG_RETURN(FALSE); } - handler_name.str= (char*)table_log_entry->handler_type; - handler_name.length= strlen(table_log_entry->handler_type); + handler_name.str= (char*)ddl_log_entry->handler_name; + handler_name.length= strlen(ddl_log_entry->handler_name); hton= ha_resolve_by_name(current_thd, &handler_name); if (!hton) { - my_error(ER_ILLEGAL_HA, MYF(0), table_log_entry->handler_type); + my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - if (strcmp("frm", table_log_entry->handler_type)) + if (strcmp("frm", ddl_log_entry->handler_name)) frm_action= TRUE; else { @@ -583,65 +577,65 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) goto error; } } - switch (table_log_entry->action_type) + switch (ddl_log_entry->action_type) { - case TLOG_DELETE_ACTION_CODE: - case TLOG_REPLACE_ACTION_CODE: + case DDL_LOG_DELETE_ACTION: + case DDL_LOG_REPLACE_ACTION: { - if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE || - (table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE && - table_log_entry->phase == 0UL)) + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION || + (ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION && + ddl_log_entry->phase == 0UL)) { if (frm_action) { - strxmov(path, table_log_entry->name, reg_ext, NullS); + strxmov(path, ddl_log_entry->name, reg_ext, NullS); if (my_delete(path, MYF(MY_WME))) break; - strxmov(path, table_log_entry->name, par_ext, NullS); + strxmov(path, ddl_log_entry->name, par_ext, NullS); if (my_delete(path, MYF(MY_WME))) break; } else { - if (file->delete_table(table_log_entry->name)) + if (file->delete_table(ddl_log_entry->name)) break; } - if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) + if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) ; else { - VOID(sync_table_log()); + VOID(sync_ddl_log()); error= FALSE; } break; } - if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE) + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) break; } - case TLOG_RENAME_ACTION_CODE: + case DDL_LOG_RENAME_ACTION: { error= TRUE; if (frm_action) { - strxmov(path, table_log_entry->name, reg_ext, NullS); - strxmov(from_path, table_log_entry->from_name, reg_ext, NullS); + strxmov(path, ddl_log_entry->name, reg_ext, NullS); + strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); if (my_rename(path, from_path, MYF(MY_WME))) break; - strxmov(path, table_log_entry->name, par_ext, NullS); - strxmov(from_path, table_log_entry->from_name, par_ext, NullS); + strxmov(path, ddl_log_entry->name, par_ext, NullS); + strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); if (my_rename(path, from_path, MYF(MY_WME))) break; } else { - if (file->rename_table(table_log_entry->name, - table_log_entry->from_name)) + if (file->rename_table(ddl_log_entry->name, + ddl_log_entry->from_name)) break; - if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) + if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) ; else { - VOID(sync_table_log()); + VOID(sync_ddl_log()); error= FALSE; } } @@ -659,40 +653,38 @@ error: /* - Get a free entry in the table log + Get a free entry in the ddl log SYNOPSIS - get_free_table_log_entry() - out:active_entry A table log memory entry returned + get_free_ddl_log_entry() + out:active_entry A ddl log memory entry returned RETURN VALUES TRUE Error FALSE Success */ -static -bool -get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, - bool *write_header) +static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, + bool *write_header) { uint entry_no; - TABLE_LOG_MEMORY_ENTRY *used_entry; - TABLE_LOG_MEMORY_ENTRY *first_used= global_table_log.first_used; - DBUG_ENTER("get_free_table_log_entry"); + DDL_LOG_MEMORY_ENTRY *used_entry; + DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; + DBUG_ENTER("get_free_ddl_log_entry"); - if (global_table_log.first_free == NULL) + if (global_ddl_log.first_free == NULL) { - if (!(used_entry= (TABLE_LOG_MEMORY_ENTRY*)my_malloc( - sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(MY_WME)))) + if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( + sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { DBUG_RETURN(TRUE); } - global_table_log.no_entries++; - used_entry->entry_pos= entry_no= global_table_log.no_entries; + global_ddl_log.num_entries++; + used_entry->entry_pos= entry_no= global_ddl_log.num_entries; *write_header= TRUE; } else { - used_entry= global_table_log.first_free; - global_table_log.first_free= used_entry->next_log_entry; + used_entry= global_ddl_log.first_free; + global_ddl_log.first_free= used_entry->next_log_entry; entry_no= used_entry->entry_pos; *write_header= FALSE; } @@ -701,7 +693,7 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, */ used_entry->next_log_entry= first_used; used_entry->prev_log_entry= NULL; - global_table_log.first_used= used_entry; + global_ddl_log.first_used= used_entry; if (first_used) first_used->prev_log_entry= used_entry; @@ -711,76 +703,79 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, /* - External interface methods for the Table log Module + External interface methods for the DDL log Module --------------------------------------------------- */ /* SYNOPSIS - write_table_log_entry() - table_log_entry Information about log entry - out:entry_written Entry information written into + write_ddl_log_entry() + ddl_log_entry Information about log entry + out:entry_written Entry information written into RETURN VALUES TRUE Error FALSE Success DESCRIPTION - A careful write of the table log is performed to ensure that we can + A careful write of the ddl log is performed to ensure that we can handle crashes occurring during CREATE and ALTER TABLE processing. */ -bool -write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - TABLE_LOG_MEMORY_ENTRY **active_entry) +bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, + DDL_LOG_MEMORY_ENTRY **active_entry) { bool error, write_header; - DBUG_ENTER("write_table_log_entry"); + DBUG_ENTER("write_ddl_log_entry"); - global_table_log.file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_LOG_ENTRY_CODE; - global_table_log.file_entry[TLOG_ACTION_TYPE_POS]= - table_log_entry->action_type; - global_table_log.file_entry[TLOG_PHASE_POS]= 0; - int4store(&global_table_log.file_entry[TLOG_NEXT_ENTRY_POS], - table_log_entry->next_entry); - DBUG_ASSERT(strlen(table_log_entry->name) < FN_LEN); - strncpy(&global_table_log.file_entry[TLOG_NAME_POS], - table_log_entry->name, FN_LEN); - if (table_log_entry->action_type == TLOG_RENAME_ACTION_CODE || - table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE) + if (init_ddl_log()) { - DBUG_ASSERT(strlen(table_log_entry->from_name) < FN_LEN); - strncpy(&global_table_log.file_entry[TLOG_NAME_POS + FN_LEN], - table_log_entry->from_name, FN_LEN); + DBUG_RETURN(TRUE); + } + global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_ENTRY_CODE; + global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= + ddl_log_entry->action_type; + global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], + ddl_log_entry->next_entry); + DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN); + strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], + ddl_log_entry->name, FN_LEN); + if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION || + ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION) + { + DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN); + strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], + ddl_log_entry->from_name, FN_LEN); } else - global_table_log.file_entry[TLOG_NAME_POS + FN_LEN]= 0; - DBUG_ASSERT(strlen(table_log_entry->handler_type) < FN_LEN); - strncpy(&global_table_log.file_entry[TLOG_NAME_POS + (2*FN_LEN)], - table_log_entry->handler_type, FN_LEN); - if (get_free_table_log_entry(active_entry, &write_header)) + global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; + DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN); + strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], + ddl_log_entry->handler_name, FN_LEN); + if (get_free_ddl_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } error= FALSE; - if (write_table_log_file_entry((*active_entry)->entry_pos)) + if (write_ddl_log_file_entry((*active_entry)->entry_pos)) error= TRUE; if (write_header && !error) { - VOID(sync_table_log()); - if (write_table_log_header()) + VOID(sync_ddl_log()); + if (write_ddl_log_header()) error= TRUE; } if (error) - release_table_log_memory_entry(*active_entry); + release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(error); } /* - Write final entry in the table log + Write final entry in the ddl log SYNOPSIS - write_execute_table_log_entry() + write_execute_ddl_log_entry() first_entry First entry in linked list of entries to execute, if 0 = NULL it means that the entry is removed and the entries @@ -794,50 +789,53 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, FALSE Success DESCRIPTION - This is the last write in the table log. The previous log entries have + This is the last write in the ddl log. The previous log entries have already been written but not yet synched to disk. */ -bool -write_execute_table_log_entry(uint first_entry, - bool complete, - TABLE_LOG_MEMORY_ENTRY **active_entry) +bool write_execute_ddl_log_entry(uint first_entry, + bool complete, + DDL_LOG_MEMORY_ENTRY **active_entry) { bool write_header= FALSE; - char *file_entry= (char*)global_table_log.file_entry; - DBUG_ENTER("write_execute_table_log_entry"); + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("write_execute_ddl_log_entry"); + if (init_ddl_log()) + { + DBUG_RETURN(TRUE); + } if (!complete) { - VOID(sync_table_log()); - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_EXECUTE_CODE; + VOID(sync_ddl_log()); + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_EXECUTE_CODE; } else - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; - file_entry[TLOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ - file_entry[TLOG_PHASE_POS]= 0; - int4store(&file_entry[TLOG_NEXT_ENTRY_POS], first_entry); - file_entry[TLOG_NAME_POS]= 0; - file_entry[TLOG_NAME_POS + FN_LEN]= 0; - file_entry[TLOG_NAME_POS + 2*FN_LEN]= 0; + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ + file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); + file_entry_buf[DDL_LOG_NAME_POS]= 0; + file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; + file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0; if (!(*active_entry)) { - if (get_free_table_log_entry(active_entry, &write_header)) + if (get_free_ddl_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } } - if (write_table_log_file_entry((*active_entry)->entry_pos)) + if (write_ddl_log_file_entry((*active_entry)->entry_pos)) { - release_table_log_memory_entry(*active_entry); + release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } - VOID(sync_table_log()); + VOID(sync_ddl_log()); if (write_header) { - if (write_table_log_header()) + if (write_ddl_log_header()) { - release_table_log_memory_entry(*active_entry); + release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } } @@ -846,9 +844,9 @@ write_execute_table_log_entry(uint first_entry, /* - For complex rename operations we need to inactivate individual entries. + For complex rename operations we need to deactivate individual entries. SYNOPSIS - inactivate_table_log_entry() + deactivate_ddl_log_entry() entry_no Entry position of record to change RETURN VALUES TRUE Error @@ -857,7 +855,7 @@ write_execute_table_log_entry(uint first_entry, During replace operations where we start with an existing table called t1 and a replacement table called t1#temp or something else and where we want to delete t1 and rename t1#temp to t1 this is not possible to - do in a safe manner unless the table log is informed of the phases in + do in a safe manner unless the ddl log is informed of the phases in the change. Delete actions are 1-phase actions that can be ignored immediately after @@ -869,32 +867,31 @@ write_execute_table_log_entry(uint first_entry, rename x -> y. */ -bool -inactivate_table_log_entry(uint entry_no) +bool deactivate_ddl_log_entry(uint entry_no) { bool error= TRUE; - char *file_entry= (char*)global_table_log.file_entry; - DBUG_ENTER("inactivate_table_log_entry"); + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("deactivate_ddl_log_entry"); - if (!read_table_log_file_entry(entry_no)) + if (!read_ddl_log_file_entry(entry_no)) { - if (file_entry[TLOG_ENTRY_TYPE_POS] == TLOG_LOG_ENTRY_CODE) + if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE) { - if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_DELETE_ACTION_CODE || - file_entry[TLOG_ACTION_TYPE_POS] == TLOG_RENAME_ACTION_CODE || - (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE && - file_entry[TLOG_PHASE_POS] == 1)) - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; - else if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE) + if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION || + file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION || + (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION && + file_entry_buf[DDL_LOG_PHASE_POS] == 1)) + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION) { - DBUG_ASSERT(file_entry[TLOG_PHASE_POS] == 0); - file_entry[TLOG_PHASE_POS]= 1; + DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0); + file_entry_buf[DDL_LOG_PHASE_POS]= 1; } else { DBUG_ASSERT(0); } - if (!write_table_log_file_entry(entry_no)) + if (!write_ddl_log_file_entry(entry_no)) error= FALSE; } } @@ -903,21 +900,24 @@ inactivate_table_log_entry(uint entry_no) /* - Sync table log file + Sync ddl log file SYNOPSIS - sync_table_log() + sync_ddl_log() RETURN VALUES TRUE Error FALSE Success */ -bool -sync_table_log() +bool sync_ddl_log() { bool error= FALSE; - DBUG_ENTER("sync_table_log"); + DBUG_ENTER("sync_ddl_log"); - if (my_sync(global_table_log.file_id, MYF(0))) + if (init_ddl_log()) + { + DBUG_RETURN(TRUE); + } + if (my_sync(global_ddl_log.file_id, MYF(0))) { /* Write to error log */ error= TRUE; @@ -929,27 +929,26 @@ sync_table_log() /* Release a log memory entry SYNOPSIS - release_table_log_memory_entry() + release_ddl_log_memory_entry() log_memory_entry Log memory entry to release RETURN VALUES NONE */ -void -release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) +void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) { - TABLE_LOG_MEMORY_ENTRY *first_free= global_table_log.first_free; - TABLE_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; - TABLE_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; - DBUG_ENTER("release_table_log_memory_entry"); + DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free; + DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; + DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; + DBUG_ENTER("release_ddl_log_memory_entry"); - global_table_log.first_free= log_entry; + global_ddl_log.first_free= log_entry; log_entry->next_log_entry= first_free; if (prev_log_entry) prev_log_entry->next_log_entry= next_log_entry; else - global_table_log.first_used= next_log_entry; + global_ddl_log.first_used= next_log_entry; if (next_log_entry) next_log_entry->prev_log_entry= prev_log_entry; DBUG_VOID_RETURN; @@ -957,75 +956,73 @@ release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) /* - Execute one entry in the table log. Executing an entry means executing + Execute one entry in the ddl log. Executing an entry means executing a linked list of actions. SYNOPSIS - execute_table_log_entry() + execute_ddl_log_entry() first_entry Reference to first action in entry RETURN VALUES TRUE Error FALSE Success */ -bool -execute_table_log_entry(uint first_entry) +bool execute_ddl_log_entry(uint first_entry) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; uint read_entry= first_entry; - DBUG_ENTER("execute_table_log_entry"); + DBUG_ENTER("execute_ddl_log_entry"); - lock_global_table_log(); + lock_global_ddl_log(); do { - if (read_table_log_entry(read_entry, &table_log_entry)) + if (read_ddl_log_entry(read_entry, &ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ break; } - DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || - table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); + DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || + ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); - if (execute_table_log_action(&table_log_entry)) + if (execute_ddl_log_action(&ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ break; } - read_entry= table_log_entry.next_entry; + read_entry= ddl_log_entry.next_entry; } while (read_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); DBUG_RETURN(FALSE); } /* - Execute the table log at recovery of MySQL Server + Execute the ddl log at recovery of MySQL Server SYNOPSIS - execute_table_log_recovery() + execute_ddl_log_recovery() RETURN VALUES NONE */ -void -execute_table_log_recovery() +void execute_ddl_log_recovery() { - uint no_entries, i; - TABLE_LOG_ENTRY table_log_entry; - DBUG_ENTER("execute_table_log_recovery"); + uint num_entries, i; + DDL_LOG_ENTRY ddl_log_entry; + DBUG_ENTER("execute_ddl_log_recovery"); - no_entries= read_table_log_header(); - for (i= 0; i < no_entries; i++) + num_entries= read_ddl_log_header(); + for (i= 0; i < num_entries; i++) { - if (read_table_log_entry(i, &table_log_entry)) + if (read_ddl_log_entry(i, &ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log */ break; } - if (table_log_entry.entry_type == TLOG_EXECUTE_CODE) + if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { - if (execute_table_log_entry(table_log_entry.next_entry)) + if (execute_ddl_log_entry(ddl_log_entry.next_entry)) { /* Currently errors are either crashing or ignored so we should @@ -1036,78 +1033,75 @@ execute_table_log_recovery() } } } - VOID(init_table_log()); + VOID(init_ddl_log()); DBUG_VOID_RETURN; } /* - Release all memory allocated to the table log + Release all memory allocated to the ddl log SYNOPSIS - release_table_log() + release_ddl_log() RETURN VALUES NONE */ -void -release_table_log() +void release_ddl_log() { - TABLE_LOG_MEMORY_ENTRY *free_list= global_table_log.first_free; - TABLE_LOG_MEMORY_ENTRY *used_list= global_table_log.first_used; - DBUG_ENTER("release_table_log"); + DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free; + DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; + DBUG_ENTER("release_ddl_log"); - lock_global_table_log(); + lock_global_ddl_log(); while (used_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; + DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; my_free((char*)used_list, MYF(0)); used_list= tmp; } while (free_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; + DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; my_free((char*)free_list, MYF(0)); free_list= tmp; } - VOID(my_close(global_table_log.file_id, MYF(0))); - unlock_global_table_log(); - VOID(pthread_mutex_destroy(&LOCK_gtl)); + VOID(my_close(global_ddl_log.file_id, MYF(0))); + unlock_global_ddl_log(); + VOID(pthread_mutex_destroy(&LOCK_gdl)); DBUG_VOID_RETURN; } /* - Lock mutex for global table log + Lock mutex for global ddl log SYNOPSIS - lock_global_table_log() + lock_global_ddl_log() RETURN VALUES NONE */ -void -lock_global_table_log() +void lock_global_ddl_log() { - DBUG_ENTER("lock_global_table_log"); + DBUG_ENTER("lock_global_ddl_log"); - VOID(pthread_mutex_lock(&LOCK_gtl)); + VOID(pthread_mutex_lock(&LOCK_gdl)); DBUG_VOID_RETURN; } /* - Unlock mutex for global table log + Unlock mutex for global ddl log SYNOPSIS - unlock_global_table_log() + unlock_global_ddl_log() RETURN VALUES NONE */ -void -unlock_global_table_log() +void unlock_global_ddl_log() { - DBUG_ENTER("unlock_global_table_log"); + DBUG_ENTER("unlock_global_ddl_log"); - VOID(pthread_mutex_unlock(&LOCK_gtl)); + VOID(pthread_mutex_unlock(&LOCK_gdl)); DBUG_VOID_RETURN; } @@ -1115,7 +1109,7 @@ unlock_global_table_log() /* --------------------------------------------------------------------------- - END MODULE Table log + END MODULE DDL log -------------------- --------------------------------------------------------------------------- @@ -1254,8 +1248,8 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE - inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || - (sync_table_log(), FALSE) || + deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || + (sync_ddl_log(), FALSE) || #endif my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) @@ -1264,9 +1258,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) } VOID(pthread_mutex_unlock(&LOCK_open)); #ifdef WITH_PARTITION_STORAGE_ENGINE - inactivate_table_log_entry(part_info->frm_log_entry->entry_pos); + deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos); part_info->frm_log_entry= NULL; - VOID(sync_table_log()); + VOID(sync_ddl_log()); #endif } diff --git a/sql/table.cc b/sql/table.cc index f2cde30c14b..20c985040fa 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -667,8 +667,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } -#if 0 - if (share->mysql_version == 50106) +#if 1 + if (share->mysql_version == 50106 || + share->mysql_version == 50107) { /* Partition state array was here in version 5.1.6, this code makes From 79ec84f98abcc94ec267c232207f36a1669b7125 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 1 Apr 2006 16:37:36 +0200 Subject: [PATCH 043/101] WL 2826: Error handling of ALTER TABLE for partitioning More review fixes sql/mysql_priv.h: More review fixes sql/sql_partition.cc: More review fixes sql/sql_table.cc: More review fixes --- sql/mysql_priv.h | 6 ++ sql/sql_partition.cc | 3 +- sql/sql_table.cc | 157 ++++++++++++++++++++++++++++--------------- 3 files changed, 111 insertions(+), 55 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 265d2840025..a39b1209319 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1266,6 +1266,12 @@ typedef struct st_ddl_log_entry uint entry_pos; enum ddl_log_entry_code entry_type; enum ddl_log_action_code action_type; + /* + Most actions have only one phase. REPLACE does however have two + phases. The first phase removes the file with the new name if + there was one there before and the second phase renames the + old name to the new name. + */ char phase; } DDL_LOG_ENTRY; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 682b9f783ba..c093466effa 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5634,7 +5634,8 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, Failed to write, Bad... We have completed the operation but have log records to REMOVE stuff that shouldn't be removed. What clever things could one do - here? + here? An error output was written to the error output by the + above method so we don't do anything here. */ ; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 86a3259484a..7a4bd2e1608 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -281,6 +281,7 @@ typedef struct st_global_ddl_log uint handler_name_len; uint io_size; bool inited; + bool recovery_phase; } GLOBAL_DDL_LOG; GLOBAL_DDL_LOG global_ddl_log; @@ -374,9 +375,11 @@ static bool write_ddl_log_header() int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], const_var); if (write_ddl_log_file_entry(0UL)) - error= TRUE; - if (!error) - VOID(sync_ddl_log()); + { + sql_print_error("Error writing ddl log header"); + DBUG_RETURN(TRUE); + } + VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -419,16 +422,20 @@ static uint read_ddl_log_header() bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); global_ddl_log.inited= FALSE; + global_ddl_log.recovery_phase= TRUE; create_ddl_log_file_name(file_name); - if (!(my_open(file_name, O_RDONLY | O_BINARY, MYF(MY_WME)))) + if (!(my_open(file_name, O_RDWR | O_BINARY, MYF(MY_WME)))) { if (read_ddl_log_file_entry(0UL)) { - ; /* Write message into error log */ + /* Write message into error log */ + sql_print_error("Failed to read ddl log file in recovery"); } else successful_open= TRUE; } + else + sql_print_error("Failed to open ddl log file in recovery"); entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); global_ddl_log.handler_name_len= @@ -436,7 +443,10 @@ static uint read_ddl_log_header() if (successful_open) global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); else + { global_ddl_log.io_size= IO_SIZE; + entry_no= 0; + } global_ddl_log.first_free= NULL; global_ddl_log.first_used= NULL; global_ddl_log.num_entries= 0; @@ -466,7 +476,6 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) if (read_ddl_log_file_entry(read_entry)) { - /* Error handling */ DBUG_RETURN(TRUE); } ddl_log_entry->entry_pos= read_entry; @@ -508,23 +517,21 @@ static bool init_ddl_log() DBUG_RETURN(FALSE); } global_ddl_log.io_size= IO_SIZE; - create_ddl_log_file_name(file_name); - VOID(my_delete(file_name, MYF(0))); if ((global_ddl_log.file_id= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC | O_BINARY, MYF(MY_WME))) < 0) { /* Couldn't create ddl log file, this is serious error */ - abort(); + sql_print_error("Failed to open ddl log file"); + DBUG_RETURN(TRUE); } if (write_ddl_log_header()) { - /* Write to error log */ - error= TRUE; + DBUG_RETURN(TRUE); } global_ddl_log.inited= TRUE; - DBUG_RETURN(error); + DBUG_RETURN(FALSE); } @@ -538,7 +545,7 @@ static bool init_ddl_log() FALSE Success */ -static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) +static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; @@ -557,7 +564,7 @@ static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) } handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); - hton= ha_resolve_by_name(current_thd, &handler_name); + hton= ha_resolve_by_name(thd, &handler_name); if (!hton) { my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); @@ -579,38 +586,40 @@ static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) } switch (ddl_log_entry->action_type) { - case DDL_LOG_DELETE_ACTION: case DDL_LOG_REPLACE_ACTION: + case DDL_LOG_DELETE_ACTION: { - if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION || - (ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION && - ddl_log_entry->phase == 0UL)) + if (ddl_log_entry->phase == 0) { if (frm_action) { strxmov(path, ddl_log_entry->name, reg_ext, NullS); if (my_delete(path, MYF(MY_WME))) break; +#ifdef WITH_PARTITION_STORAGE_ENGINE strxmov(path, ddl_log_entry->name, par_ext, NullS); - if (my_delete(path, MYF(MY_WME))) - break; + VOID(my_delete(path, MYF(MY_WME))); +#endif } else { if (file->delete_table(ddl_log_entry->name)) break; } - if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - ; - else + if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) { VOID(sync_ddl_log()); error= FALSE; } - break; + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) + break; } - if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) - break; + DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION); + /* + Fall through and perform the rename action of the replace + action. We have already indicated the success of the delete + action in the log entry by stepping up the phase. + */ } case DDL_LOG_RENAME_ACTION: { @@ -621,23 +630,22 @@ static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); if (my_rename(path, from_path, MYF(MY_WME))) break; +#ifdef WITH_PARTITION_STORAGE_ENGINE strxmov(path, ddl_log_entry->name, par_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); - if (my_rename(path, from_path, MYF(MY_WME))) - break; + VOID(my_rename(path, from_path, MYF(MY_WME))); +#endif } else { if (file->rename_table(ddl_log_entry->name, ddl_log_entry->from_name)) break; - if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - ; - else - { - VOID(sync_ddl_log()); - error= FALSE; - } + } + if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) + { + VOID(sync_ddl_log()); + error= FALSE; } break; } @@ -665,7 +673,6 @@ error: static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, bool *write_header) { - uint entry_no; DDL_LOG_MEMORY_ENTRY *used_entry; DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; DBUG_ENTER("get_free_ddl_log_entry"); @@ -675,17 +682,17 @@ static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { + sql_print_error("Failed to allocate memory for ddl log free list"); DBUG_RETURN(TRUE); } global_ddl_log.num_entries++; - used_entry->entry_pos= entry_no= global_ddl_log.num_entries; + used_entry->entry_pos= global_ddl_log.num_entries; *write_header= TRUE; } else { used_entry= global_ddl_log.first_free; global_ddl_log.first_free= used_entry->next_log_entry; - entry_no= used_entry->entry_pos; *write_header= FALSE; } /* @@ -759,12 +766,17 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, } error= FALSE; if (write_ddl_log_file_entry((*active_entry)->entry_pos)) + { error= TRUE; + sql_print_error("Failed to write entry_no = %u", + (*active_entry)->entry_pos); + } if (write_header && !error) { VOID(sync_ddl_log()); if (write_ddl_log_header()) error= TRUE; + VOID(sync_ddl_log()); } if (error) release_ddl_log_memory_entry(*active_entry); @@ -791,6 +803,10 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, DESCRIPTION This is the last write in the ddl log. The previous log entries have already been written but not yet synched to disk. + We write a couple of log entries that describes action to perform. + This entries are set-up in a linked list, however only when a first + execute entry is put as the first entry these will be executed. + This routine writes this first */ bool write_execute_ddl_log_entry(uint first_entry, @@ -807,6 +823,12 @@ bool write_execute_ddl_log_entry(uint first_entry, } if (!complete) { + /* + We haven't synched the log entries yet, we synch them now before + writing the execute entry. If complete is true we haven't written + any log entries before, we are only here to write the execute + entry to indicate it is done. + */ VOID(sync_ddl_log()); file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_EXECUTE_CODE; } @@ -827,6 +849,7 @@ bool write_execute_ddl_log_entry(uint first_entry, } if (write_ddl_log_file_entry((*active_entry)->entry_pos)) { + sql_print_error("Error writing execute entry in ddl log"); release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } @@ -838,6 +861,7 @@ bool write_execute_ddl_log_entry(uint first_entry, release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } + VOID(sync_ddl_log()); } DBUG_RETURN(FALSE); } @@ -869,7 +893,6 @@ bool write_execute_ddl_log_entry(uint first_entry, bool deactivate_ddl_log_entry(uint entry_no) { - bool error= TRUE; char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; DBUG_ENTER("deactivate_ddl_log_entry"); @@ -891,11 +914,20 @@ bool deactivate_ddl_log_entry(uint entry_no) { DBUG_ASSERT(0); } - if (!write_ddl_log_file_entry(entry_no)) - error= FALSE; + if (write_ddl_log_file_entry(entry_no)) + { + sql_print_error("Error in deactivating log entry. Position = %u", + entry_no); + DBUG_RETURN(TRUE); + } } } - DBUG_RETURN(error); + else + { + sql_print_error("Failed in reading entry before deactivating it"); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -913,13 +945,15 @@ bool sync_ddl_log() bool error= FALSE; DBUG_ENTER("sync_ddl_log"); - if (init_ddl_log()) + if ((!global_ddl_log.recovery_phase) && + init_ddl_log()) { DBUG_RETURN(TRUE); } if (my_sync(global_ddl_log.file_id, MYF(0))) { /* Write to error log */ + sql_print_error("Failed to sync ddl log"); error= TRUE; } DBUG_RETURN(error); @@ -966,7 +1000,7 @@ void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) FALSE Success */ -bool execute_ddl_log_entry(uint first_entry) +bool execute_ddl_log_entry(THD *thd, uint first_entry) { DDL_LOG_ENTRY ddl_log_entry; uint read_entry= first_entry; @@ -979,15 +1013,19 @@ bool execute_ddl_log_entry(uint first_entry) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ + sql_print_error("Failed to read entry = %u from ddl log", + read_entry); break; } DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); - if (execute_ddl_log_action(&ddl_log_entry)) + if (execute_ddl_log_action(thd, &ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ + sql_print_error("Failed to execute action for entry = %u from ddl log", + read_entry); break; } read_entry= ddl_log_entry.next_entry; @@ -1011,29 +1049,40 @@ void execute_ddl_log_recovery() DDL_LOG_ENTRY ddl_log_entry; DBUG_ENTER("execute_ddl_log_recovery"); + /* + To be able to run this from boot, we allocate a temporary THD + */ + if (!(thd=new THD)) + DBUG_VOID_RETURN; + thd->thread_stack= (char*) &thd; + thd->store_globals(); + num_entries= read_ddl_log_header(); for (i= 0; i < num_entries; i++) { if (read_ddl_log_entry(i, &ddl_log_entry)) { DBUG_ASSERT(0); - /* Write to error log */ - break; + sql_print_error("Failed to read entry no = %u from ddl log", + i); + continue; } if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { if (execute_ddl_log_entry(ddl_log_entry.next_entry)) { - /* - Currently errors are either crashing or ignored so we should - never end up here - */ - abort(); - DBUG_VOID_RETURN; + /* Real unpleasant scenario but we continue anyways. */ + DBUG_ASSERT(0); + continue; } } } - VOID(init_ddl_log()); + create_ddl_log_file_name(file_name); + VOID(my_delete(file_name, MYF(0))); + global_ddl_log.recovery_phase= FALSE; + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); DBUG_VOID_RETURN; } From b7b95ecf2d6bfde1ffda21809f356773f8630cdc Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Apr 2006 12:26:35 -0400 Subject: [PATCH 044/101] Fixes --- sql/mysql_priv.h | 2 +- sql/sql_partition.cc | 3 ++- sql/sql_table.cc | 11 +++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index df7a88ccfbb..dbc1093c01a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1299,7 +1299,7 @@ void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry); bool sync_ddl_log(); void release_ddl_log(); void execute_ddl_log_recovery(); -bool execute_ddl_log_entry(uint first_entry); +bool execute_ddl_log_entry(THD *thd, uint first_entry); void lock_global_ddl_log(); void unlock_global_ddl_log(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 351ed0dd5a6..f038c2232cf 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5342,7 +5342,8 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_ENTER("handle_alter_part_error"); if (!part_info->first_log_entry && - execute_ddl_log_entry(part_info->first_log_entry->entry_pos)) + execute_ddl_log_entry(current_thd, + part_info->first_log_entry->entry_pos)) { /* We couldn't recover from error, most likely manual interaction diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 90251184120..e8f5fffd88b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -434,8 +434,6 @@ static uint read_ddl_log_header() else successful_open= TRUE; } - else - sql_print_error("Failed to open ddl log file in recovery"); entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); global_ddl_log.handler_name_len= @@ -526,11 +524,12 @@ static bool init_ddl_log() sql_print_error("Failed to open ddl log file"); DBUG_RETURN(TRUE); } + global_ddl_log.inited= TRUE; if (write_ddl_log_header()) { + global_ddl_log.inited= FALSE; DBUG_RETURN(TRUE); } - global_ddl_log.inited= TRUE; DBUG_RETURN(FALSE); } @@ -776,7 +775,6 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, VOID(sync_ddl_log()); if (write_ddl_log_header()) error= TRUE; - VOID(sync_ddl_log()); } if (error) release_ddl_log_memory_entry(*active_entry); @@ -861,7 +859,6 @@ bool write_execute_ddl_log_entry(uint first_entry, release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } - VOID(sync_ddl_log()); } DBUG_RETURN(FALSE); } @@ -1046,7 +1043,9 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) void execute_ddl_log_recovery() { uint num_entries, i; + THD *thd; DDL_LOG_ENTRY ddl_log_entry; + char file_name[FN_REFLEN]; DBUG_ENTER("execute_ddl_log_recovery"); /* @@ -1069,7 +1068,7 @@ void execute_ddl_log_recovery() } if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { - if (execute_ddl_log_entry(ddl_log_entry.next_entry)) + if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) { /* Real unpleasant scenario but we continue anyways. */ DBUG_ASSERT(0); From cab73a600927b82470d71b96f6d01232e0cf6e87 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Apr 2006 15:30:40 +0400 Subject: [PATCH 045/101] Bug#15933: max_used_connections is wrong after FLUSH STATUS if connections are cached After FLUSH STATUS max_used_connections was reset to 0, and haven't been updated while cached threads were reused, until the moment a new thread was created. The first suggested fix from original bug report was implemented: a) On flushing the status, set max_used_connections to threads_connected, not to 0. b) Check if it is necessary to increment max_used_connections when taking a thread from the cache as well as when creating new threads mysql-test/r/status.result: Add result for bug#15933. mysql-test/t/status.test: Add test case for bug#15933. Fixed typo. sql/mysql_priv.h: Add declaration of refresh_status(), which is now external. sql/mysqld.cc: Remove start_cached_thread() (code moved directly into create_new_thread()). Add comment for create_new_thread (). In create_new_thread() update max_used_connections when creating new thread and when reusing the cached one. Move refresh_status() from sql/sql_parse.cc here, on refresh set max_used_connections to the current number of connections. sql/sql_parse.cc: refresh_status() moved to sql/mysqld.cc. --- mysql-test/r/status.result | 20 +++++++++++ mysql-test/t/status.test | 65 ++++++++++++++++++++++++++++++++- sql/mysql_priv.h | 1 + sql/mysqld.cc | 73 +++++++++++++++++++++++++++++--------- sql/sql_parse.cc | 22 ------------ 5 files changed, 142 insertions(+), 39 deletions(-) diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 5461e4dd563..4e5489191c9 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -23,3 +23,23 @@ select 1; show status like 'last_query_cost'; Variable_name Value Last_query_cost 0.000000 +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 3 +SET @save_thread_cache_size=@@thread_cache_size; +SET GLOBAL thread_cache_size=3; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 5 +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 4 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 5 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 6 +SET GLOBAL thread_cache_size=@save_thread_cache_size; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 929a0cb5877..79a46a38550 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -39,8 +39,71 @@ drop table t1; # End of 4.1 tests # -# lost_query_cost +# last_query_cost # select 1; show status like 'last_query_cost'; + +# +# Test for Bug #15933 max_used_connections is wrong after FLUSH STATUS +# if connections are cached +# +# +# The first suggested fix from the bug report was chosen +# (see http://bugs.mysql.com/bug.php?id=15933): +# +# a) On flushing the status, set max_used_connections to +# threads_connected, not to 0. +# +# b) Check if it is necessary to increment max_used_connections when +# taking a thread from the cache as well as when creating new threads +# + +# Previous test uses con1, con2. If we disconnect them, there will be +# a race on when exactly this will happen, so we better leave them as +# is. +connection default; + +# Reset max_used_connections from previous tests. +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; + +# Save original setting. +SET @save_thread_cache_size=@@thread_cache_size; +SET GLOBAL thread_cache_size=3; + +connect (con3,localhost,root,,); +connect (con4,localhost,root,,); + +connection con3; +disconnect con4; + +# Check that max_used_connections still reflects maximum value. +SHOW STATUS LIKE 'max_used_connections'; + +# Check that after flush max_used_connections equals to current number +# of connections. +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; + +# Check that max_used_connections is updated when cached thread is +# reused... +connect (con4,localhost,root,,); +SHOW STATUS LIKE 'max_used_connections'; + +# ...and when new thread is created. +connect (con5,localhost,root,,); +SHOW STATUS LIKE 'max_used_connections'; + +# Restore original setting. +connection default; +SET GLOBAL thread_cache_size=@save_thread_cache_size; + +disconnect con5; +disconnect con4; +disconnect con3; +disconnect con2; +disconnect con1; + +# End of 5.0 tests diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ca7801039c5..03121383d8a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1097,6 +1097,7 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, /* mysqld.cc */ extern void MYSQLerror(const char*); +void refresh_status(THD *thd); /* item_func.cc */ extern bool check_reserved_words(LEX_STRING *name); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e9ff220a6a1..81b5be42a69 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1639,17 +1639,6 @@ void end_thread(THD *thd, bool put_in_cache) } -/* Start a cached thread. LOCK_thread_count is locked on entry */ - -static void start_cached_thread(THD *thd) -{ - thread_cache.append(thd); - wake_thread++; - thread_count++; - pthread_cond_signal(&COND_thread_cache); -} - - void flush_thread_cache() { (void) pthread_mutex_lock(&LOCK_thread_count); @@ -3780,6 +3769,25 @@ static bool read_init_file(char *file_name) #ifndef EMBEDDED_LIBRARY +/* + Create new thread to handle incoming connection. + + SYNOPSIS + create_new_thread() + thd in/out Thread handle of future thread. + + DESCRIPTION + This function will create new thread to handle the incoming + connection. If there are idle cached threads one will be used. + 'thd' will be pushed into 'threads'. + + In single-threaded mode (#define ONE_THREAD) connection will be + handled inside this function. + + RETURN VALUE + none +*/ + static void create_new_thread(THD *thd) { DBUG_ENTER("create_new_thread"); @@ -3803,11 +3811,12 @@ static void create_new_thread(THD *thd) thd->real_id=pthread_self(); // Keep purify happy /* Start a new thread to handle connection */ + thread_count++; + #ifdef ONE_THREAD if (test_flags & TEST_NO_THREADS) // For debugging under Linux { thread_cache_size=0; // Safety - thread_count++; threads.append(thd); thd->real_id=pthread_self(); (void) pthread_mutex_unlock(&LOCK_thread_count); @@ -3816,18 +3825,20 @@ static void create_new_thread(THD *thd) else #endif { + if (thread_count-delayed_insert_threads > max_used_connections) + max_used_connections=thread_count-delayed_insert_threads; + if (cached_thread_count > wake_thread) { - start_cached_thread(thd); + thread_cache.append(thd); + wake_thread++; + pthread_cond_signal(&COND_thread_cache); } else { int error; - thread_count++; thread_created++; threads.append(thd); - if (thread_count-delayed_insert_threads > max_used_connections) - max_used_connections=thread_count-delayed_insert_threads; DBUG_PRINT("info",(("creating thread %d"), thd->thread_id)); thd->connect_time = time(NULL); if ((error=pthread_create(&thd->real_id,&connection_attrib, @@ -7393,6 +7404,36 @@ static void create_pid_file() } +/* Clear most status variables */ +void refresh_status(THD *thd) +{ + pthread_mutex_lock(&LOCK_status); + + /* We must update the global status before cleaning up the thread */ + add_to_status(&global_status_var, &thd->status_var); + bzero((char*) &thd->status_var, sizeof(thd->status_var)); + + for (struct show_var_st *ptr=status_vars; ptr->name; ptr++) + { + if (ptr->type == SHOW_LONG) + *(ulong*) ptr->value= 0; + } + /* Reset the counters of all key caches (default and named). */ + process_key_caches(reset_key_cache_counters); + pthread_mutex_unlock(&LOCK_status); + + /* + Set max_used_connections to the number of currently open + connections. Lock LOCK_thread_count out of LOCK_status to avoid + deadlocks. Status reset becomes not atomic, but status data is + not exact anyway. + */ + pthread_mutex_lock(&LOCK_thread_count); + max_used_connections= thread_count-delayed_insert_threads; + pthread_mutex_unlock(&LOCK_thread_count); +} + + /***************************************************************************** Instantiate have_xyx for missing storage engines *****************************************************************************/ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f9d04fc873e..114673430e2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -74,7 +74,6 @@ static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_multi_update_lock(THD *thd); static void remove_escape(char *name); -static void refresh_status(THD *thd); static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); @@ -6709,27 +6708,6 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query) } -/* Clear most status variables */ - -static void refresh_status(THD *thd) -{ - pthread_mutex_lock(&LOCK_status); - - /* We must update the global status before cleaning up the thread */ - add_to_status(&global_status_var, &thd->status_var); - bzero((char*) &thd->status_var, sizeof(thd->status_var)); - - for (struct show_var_st *ptr=status_vars; ptr->name; ptr++) - { - if (ptr->type == SHOW_LONG) - *(ulong*) ptr->value= 0; - } - /* Reset the counters of all key caches (default and named). */ - process_key_caches(reset_key_cache_counters); - pthread_mutex_unlock(&LOCK_status); -} - - /* If pointer is not a null pointer, append filename to it */ static bool append_file_to_dir(THD *thd, const char **filename_ptr, From 148cf113e590e4f465c5c1c608ba4cf848abc388 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Apr 2006 16:53:15 +0200 Subject: [PATCH 046/101] Renaming sp_pcontext members and methods; less cryptic and more consistent. Also added comments, and fixing some coding style (mostly in comments too). There are no functional changes, so no tests or documentation needed. (This was originally part of a bugfix, but it was decided to not include this in that patch; instead it's done separately.) sql/sp_head.cc: Renaming sp_pcontext members and methods; less cryptic and more consistent. sql/sp_head.h: Renaming sp_pcontext members and methods; less cryptic and more consistent. sql/sp_pcontext.cc: Renaming sp_pcontext members and methods; less cryptic and more consistent. Also added comments, and fixing some coding style (mostly in comments too). sql/sp_pcontext.h: Renaming sp_pcontext members and methods; less cryptic and more consistent. Also added comments, and fixing some coding style (mostly in comments too). sql/sp_rcontext.cc: Renaming sp_pcontext members and methods; less cryptic and more consistent. sql/sp_rcontext.h: Renaming sp_pcontext members and methods; less cryptic and more consistent. sql/sql_yacc.yy: Renaming sp_pcontext members and methods; less cryptic and more consistent. --- sql/sp_head.cc | 22 +++---- sql/sp_head.h | 6 +- sql/sp_pcontext.cc | 161 +++++++++++++++++++++++---------------------- sql/sp_pcontext.h | 130 +++++++++++++++++++++--------------- sql/sp_rcontext.cc | 24 +++---- sql/sp_rcontext.h | 8 +-- sql/sql_yacc.yy | 86 ++++++++++++------------ 7 files changed, 233 insertions(+), 204 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bba9479c8f3..15d621b1d6d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1214,7 +1214,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, DBUG_ENTER("sp_head::execute_function"); DBUG_PRINT("info", ("function %s", m_name.str)); - params = m_pcont->context_pvars(); + params = m_pcont->context_var_count(); /* Check that the function is called with all specified arguments. @@ -1391,7 +1391,7 @@ bool sp_head::execute_procedure(THD *thd, List *args) { bool err_status= FALSE; - uint params = m_pcont->context_pvars(); + uint params = m_pcont->context_var_count(); sp_rcontext *save_spcont, *octx; sp_rcontext *nctx = NULL; DBUG_ENTER("sp_head::execute_procedure"); @@ -1443,15 +1443,15 @@ sp_head::execute_procedure(THD *thd, List *args) for (uint i= 0 ; i < params ; i++) { Item *arg_item= it_args++; - sp_pvar_t *pvar= m_pcont->find_pvar(i); + sp_variable_t *spvar= m_pcont->find_variable(i); if (!arg_item) break; - if (!pvar) + if (!spvar) continue; - if (pvar->mode != sp_param_in) + if (spvar->mode != sp_param_in) { if (!arg_item->is_splocal() && !item_is_user_var(arg_item)) { @@ -1461,7 +1461,7 @@ sp_head::execute_procedure(THD *thd, List *args) } } - if (pvar->mode == sp_param_out) + if (spvar->mode == sp_param_out) { Item_null *null_item= new Item_null(); @@ -1521,9 +1521,9 @@ sp_head::execute_procedure(THD *thd, List *args) if (!arg_item) break; - sp_pvar_t *pvar= m_pcont->find_pvar(i); + sp_variable_t *spvar= m_pcont->find_variable(i); - if (pvar->mode == sp_param_in) + if (spvar->mode == sp_param_in) continue; if (arg_item->is_splocal()) @@ -2388,7 +2388,7 @@ sp_instr_set::print(String *str) { /* set name@offset ... */ int rsrv = SP_INSTR_UINT_MAXLEN+6; - sp_pvar_t *var = m_ctx->find_pvar(m_offset); + sp_variable_t *var = m_ctx->find_variable(m_offset); /* 'var' should always be non-null, but just in case... */ if (var) @@ -3004,8 +3004,8 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) void sp_instr_cfetch::print(String *str) { - List_iterator_fast li(m_varlist); - sp_pvar_t *pv; + List_iterator_fast li(m_varlist); + sp_variable_t *pv; LEX_STRING n; my_bool found= m_ctx->find_cursor(m_cursor, &n); /* cfetch name@offset vars... */ diff --git a/sql/sp_head.h b/sql/sp_head.h index 64d9167fb17..17a5d1ae528 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -44,7 +44,7 @@ class sp_instr; class sp_instr_opt_meta; class sp_instr_jump_if_not; struct sp_cond_type; -struct sp_pvar; +struct sp_variable; class sp_name : public Sql_alloc { @@ -1074,7 +1074,7 @@ public: virtual void print(String *str); - void add_to_varlist(struct sp_pvar *var) + void add_to_varlist(struct sp_variable *var) { m_varlist.push_back(var); } @@ -1082,7 +1082,7 @@ public: private: uint m_cursor; - List m_varlist; + List m_varlist; }; // class sp_instr_cfetch : public sp_instr diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index f69053a7c88..448df908a32 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -27,10 +27,10 @@ #include "sp_head.h" /* - * Sanity check for SQLSTATEs. Will not check if it's really an existing - * state (there are just too many), but will check length and bad characters. - * Returns TRUE if it's ok, FALSE if it's bad. - */ + Sanity check for SQLSTATEs. Will not check if it's really an existing + state (there are just too many), but will check length and bad characters. + Returns TRUE if it's ok, FALSE if it's bad. +*/ bool sp_cond_check(LEX_STRING *sqlstate) { @@ -51,25 +51,25 @@ sp_cond_check(LEX_STRING *sqlstate) } sp_pcontext::sp_pcontext(sp_pcontext *prev) - :Sql_alloc(), m_total_pvars(0), m_csubsize(0), m_hsubsize(0), - m_handlers(0), m_parent(prev), m_pboundary(0) + :Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0), + m_context_handlers(0), m_parent(prev), m_pboundary(0) { - VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *), 16, 8)); VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8)); - VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); - VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8)); - VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING), 16, 8)); + VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *), 16, 8)); m_label.empty(); m_children.empty(); if (!prev) { - m_poffset= m_coffset= 0; + m_var_offset= m_cursor_offset= 0; m_num_case_exprs= 0; } else { - m_poffset= prev->m_poffset + prev->m_total_pvars; - m_coffset= prev->current_cursors(); + m_var_offset= prev->m_var_offset + prev->m_max_var_index; + m_cursor_offset= prev->current_cursor_count(); m_num_case_exprs= prev->get_num_case_exprs(); } } @@ -85,11 +85,11 @@ sp_pcontext::destroy() m_children.empty(); m_label.empty(); - delete_dynamic(&m_pvar); + delete_dynamic(&m_vars); delete_dynamic(&m_case_expr_id_lst); - delete_dynamic(&m_cond); - delete_dynamic(&m_cursor); - delete_dynamic(&m_handler); + delete_dynamic(&m_conds); + delete_dynamic(&m_cursors); + delete_dynamic(&m_handlers); } sp_pcontext * @@ -105,15 +105,15 @@ sp_pcontext::push_context() sp_pcontext * sp_pcontext::pop_context() { - m_parent->m_total_pvars= m_parent->m_total_pvars + m_total_pvars; + m_parent->m_max_var_index+= m_max_var_index; - uint submax= max_handlers(); - if (submax > m_parent->m_hsubsize) - m_parent->m_hsubsize= submax; + uint submax= max_handler_index(); + if (submax > m_parent->m_max_handler_index) + m_parent->m_max_handler_index= submax; - submax= max_cursors(); - if (submax > m_parent->m_csubsize) - m_parent->m_csubsize= submax; + submax= max_cursor_index(); + if (submax > m_parent->m_max_cursor_index) + m_parent->m_max_cursor_index= submax; if (m_num_case_exprs > m_parent->m_num_case_exprs) m_parent->m_num_case_exprs= m_num_case_exprs; @@ -130,12 +130,12 @@ sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive) while (pctx && pctx != ctx) { - n+= pctx->m_handlers; + n+= pctx->m_context_handlers; last_ctx= pctx; pctx= pctx->parent_context(); } if (pctx) - return (exclusive && last_ctx ? n - last_ctx->m_handlers : n); + return (exclusive && last_ctx ? n - last_ctx->m_context_handlers : n); return 0; // Didn't find ctx } @@ -148,32 +148,33 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive) while (pctx && pctx != ctx) { - n+= pctx->m_cursor.elements; + n+= pctx->m_cursors.elements; last_ctx= pctx; pctx= pctx->parent_context(); } if (pctx) - return (exclusive && last_ctx ? n - last_ctx->m_cursor.elements : n); + return (exclusive && last_ctx ? n - last_ctx->m_cursors.elements : n); return 0; // Didn't find ctx } -/* This does a linear search (from newer to older variables, in case -** we have shadowed names). -** It's possible to have a more efficient allocation and search method, -** but it might not be worth it. The typical number of parameters and -** variables will in most cases be low (a handfull). -** ...and, this is only called during parsing. +/* + This does a linear search (from newer to older variables, in case + we have shadowed names). + It's possible to have a more efficient allocation and search method, + but it might not be worth it. The typical number of parameters and + variables will in most cases be low (a handfull). + ...and, this is only called during parsing. */ -sp_pvar_t * -sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) +sp_variable_t * +sp_pcontext::find_variable(LEX_STRING *name, my_bool scoped) { - uint i= m_pvar.elements - m_pboundary; + uint i= m_vars.elements - m_pboundary; while (i--) { - sp_pvar_t *p; + sp_variable_t *p; - get_dynamic(&m_pvar, (gptr)&p, i); + get_dynamic(&m_vars, (gptr)&p, i); if (my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, (const uchar *)p->name.str, p->name.length) == 0) @@ -182,7 +183,7 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) } } if (!scoped && m_parent) - return m_parent->find_pvar(name, scoped); + return m_parent->find_variable(name, scoped); return NULL; } @@ -192,40 +193,40 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) - When evaluating parameters at the beginning, and setting out parameters at the end, of invokation. (Top frame only, so no recursion then.) - For printing of sp_instr_set. (Debug mode only.) - */ -sp_pvar_t * -sp_pcontext::find_pvar(uint offset) +*/ +sp_variable_t * +sp_pcontext::find_variable(uint offset) { - if (m_poffset <= offset && offset < m_poffset + m_pvar.elements) + if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements) { // This frame - sp_pvar_t *p; + sp_variable_t *p; - get_dynamic(&m_pvar, (gptr)&p, offset - m_poffset); + get_dynamic(&m_vars, (gptr)&p, offset - m_var_offset); return p; } if (m_parent) - return m_parent->find_pvar(offset); // Some previous frame + return m_parent->find_variable(offset); // Some previous frame return NULL; // index out of bounds } -sp_pvar_t * -sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type, - sp_param_mode_t mode) +sp_variable_t * +sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type, + sp_param_mode_t mode) { - sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t)); + sp_variable_t *p= (sp_variable_t *)sql_alloc(sizeof(sp_variable_t)); if (!p) return NULL; - ++m_total_pvars; + ++m_max_var_index; p->name.str= name->str; p->name.length= name->length; p->type= type; p->mode= mode; - p->offset= current_pvars(); + p->offset= current_var_count(); p->dflt= NULL; - insert_dynamic(&m_pvar, (gptr)&p); + insert_dynamic(&m_vars, (gptr)&p); return p; } @@ -272,23 +273,23 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val) p->name.str= name->str; p->name.length= name->length; p->val= val; - insert_dynamic(&m_cond, (gptr)&p); + insert_dynamic(&m_conds, (gptr)&p); } } /* - * See comment for find_pvar() above - */ + See comment for find_variable() above +*/ sp_cond_type_t * sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped) { - uint i= m_cond.elements; + uint i= m_conds.elements; while (i--) { sp_cond_t *p; - get_dynamic(&m_cond, (gptr)&p, i); + get_dynamic(&m_conds, (gptr)&p, i); if (my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, (const uchar *)p->name.str, p->name.length) == 0) @@ -302,20 +303,20 @@ sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped) } /* - * This only searches the current context, for error checking of - * duplicates. - * Returns TRUE if found. - */ + This only searches the current context, for error checking of + duplicates. + Returns TRUE if found. +*/ bool sp_pcontext::find_handler(sp_cond_type_t *cond) { - uint i= m_handler.elements; + uint i= m_handlers.elements; while (i--) { sp_cond_type_t *p; - get_dynamic(&m_handler, (gptr)&p, i); + get_dynamic(&m_handlers, (gptr)&p, i); if (cond->type == p->type) { switch (p->type) @@ -341,31 +342,31 @@ sp_pcontext::push_cursor(LEX_STRING *name) { LEX_STRING n; - if (m_cursor.elements == m_csubsize) - m_csubsize+= 1; + if (m_cursors.elements == m_max_cursor_index) + m_max_cursor_index+= 1; n.str= name->str; n.length= name->length; - insert_dynamic(&m_cursor, (gptr)&n); + insert_dynamic(&m_cursors, (gptr)&n); } /* - * See comment for find_pvar() above - */ + See comment for find_variable() above +*/ my_bool sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) { - uint i= m_cursor.elements; + uint i= m_cursors.elements; while (i--) { LEX_STRING n; - get_dynamic(&m_cursor, (gptr)&n, i); + get_dynamic(&m_cursors, (gptr)&n, i); if (my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, (const uchar *)n.str, n.length) == 0) { - *poff= m_coffset + i; + *poff= m_cursor_offset + i; return TRUE; } } @@ -380,10 +381,10 @@ sp_pcontext::retrieve_field_definitions(List *field_def_lst) { /* Put local/context fields in the result list. */ - for (uint i = 0; i < m_pvar.elements; ++i) + for (uint i = 0; i < m_vars.elements; ++i) { - sp_pvar_t *var_def; - get_dynamic(&m_pvar, (gptr) &var_def, i); + sp_variable_t *var_def; + get_dynamic(&m_vars, (gptr) &var_def, i); field_def_lst->push_back(&var_def->field_def); } @@ -400,17 +401,17 @@ sp_pcontext::retrieve_field_definitions(List *field_def_lst) /* Find a cursor by offset from the top. This is only used for debugging. - */ +*/ my_bool sp_pcontext::find_cursor(uint offset, LEX_STRING *n) { - if (m_coffset <= offset && offset < m_coffset + m_cursor.elements) + if (m_cursor_offset <= offset && + offset < m_cursor_offset + m_cursors.elements) { // This frame - get_dynamic(&m_cursor, (gptr)n, offset - m_coffset); + get_dynamic(&m_cursors, (gptr)n, offset - m_cursor_offset); return TRUE; } if (m_parent) return m_parent->find_cursor(offset, n); // Some previous frame return FALSE; // index out of bounds } - diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 872c7c1d505..e61057537da 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -29,22 +29,23 @@ typedef enum sp_param_inout } sp_param_mode_t; -typedef struct sp_pvar +typedef struct sp_variable { LEX_STRING name; enum enum_field_types type; sp_param_mode_t mode; /* - offset -- basically, this is an index of variable in the scope of root - parsing context. This means, that all variables in a stored routine - have distinct indexes/offsets. + offset -- this the index to the variable's value in the runtime frame. + This is calculated during parsing and used when creating sp_instr_set + instructions and Item_splocal items. + I.e. values are set/referred by array indexing in runtime. */ uint offset; Item *dflt; create_field field_def; -} sp_pvar_t; +} sp_variable_t; #define SP_LAB_REF 0 // Unresolved reference (for goto) @@ -76,9 +77,10 @@ typedef struct sp_cond_type uint mysqlerr; } sp_cond_type_t; -/* Sanity check for SQLSTATEs. Will not check if it's really an existing - * state (there are just too many), but will check length bad characters. - */ +/* + Sanity check for SQLSTATEs. Will not check if it's really an existing + state (there are just too many), but will check length bad characters. +*/ extern bool sp_cond_check(LEX_STRING *sqlstate); @@ -90,7 +92,17 @@ typedef struct sp_cond /* - This seems to be an "SP parsing context" or something. + The parse-time context, used to keep track on declared variables/parameters, + conditions, handlers, cursors and labels, during parsing. + sp_contexts are organized as a tree, with one object for each begin-end + block, plus a root-context for the parameters. + This is used during parsing for looking up defined names (e.g. declared + variables and visible labels), for error checking, and to calculate offsets + to be used at runtime. (During execution variable values, active handlers + and cursors, etc, are referred to by an index in a stack.) + The pcontext tree is also kept during execution and is used for error + checking (e.g. correct number of parameters), and in the future, used by + the debugger. */ class sp_pcontext : public Sql_alloc @@ -134,50 +146,64 @@ class sp_pcontext : public Sql_alloc // Parameters and variables // + /* + The maximum number of variables used in this and all child contexts + In the root, this gives us the number of slots needed for variables + during execution. + */ inline uint - total_pvars() + max_var_index() { - return m_total_pvars; + return m_max_var_index; } + /* + The current number of variables used in the parents (from the root), + including this context. + */ inline uint - current_pvars() + current_var_count() { - return m_poffset + m_pvar.elements; + return m_var_offset + m_vars.elements; } + /* The number of variables in this context alone */ inline uint - context_pvars() + context_var_count() { - return m_pvar.elements; + return m_vars.elements; } + /* Map index in this pcontext to runtime offset */ inline uint - pvar_context2index(uint i) + var_context2runtime(uint i) { - return m_poffset + i; + return m_var_offset + i; } + /* Set type of variable. 'i' is the offset from the top */ inline void set_type(uint i, enum enum_field_types type) { - sp_pvar_t *p= find_pvar(i); + sp_variable_t *p= find_variable(i); if (p) p->type= type; } + /* Set default value of variable. 'i' is the offset from the top */ inline void set_default(uint i, Item *it) { - sp_pvar_t *p= find_pvar(i); + sp_variable_t *p= find_variable(i); if (p) p->dflt= it; } - sp_pvar_t * - push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode); + sp_variable_t * + push_variable(LEX_STRING *name, enum enum_field_types type, + sp_param_mode_t mode); /* Retrieve definitions of fields from the current context and its @@ -187,12 +213,12 @@ class sp_pcontext : public Sql_alloc retrieve_field_definitions(List *field_def_lst); // Find by name - sp_pvar_t * - find_pvar(LEX_STRING *name, my_bool scoped=0); + sp_variable_t * + find_variable(LEX_STRING *name, my_bool scoped=0); - // Find by offset - sp_pvar_t * - find_pvar(uint offset); + // Find by offset (from the top) + sp_variable_t * + find_variable(uint offset); /* Set the current scope boundary (for default values). @@ -280,7 +306,7 @@ class sp_pcontext : public Sql_alloc pop_cond(uint num) { while (num--) - pop_dynamic(&m_cond); + pop_dynamic(&m_conds); } sp_cond_type_t * @@ -293,22 +319,22 @@ class sp_pcontext : public Sql_alloc inline void push_handler(sp_cond_type_t *cond) { - insert_dynamic(&m_handler, (gptr)&cond); + insert_dynamic(&m_handlers, (gptr)&cond); } bool find_handler(sp_cond_type *cond); inline uint - max_handlers() + max_handler_index() { - return m_hsubsize + m_handlers; + return m_max_handler_index + m_context_handlers; } inline void add_handlers(uint n) { - m_handlers+= n; + m_context_handlers+= n; } // @@ -326,51 +352,51 @@ class sp_pcontext : public Sql_alloc find_cursor(uint offset, LEX_STRING *n); inline uint - max_cursors() + max_cursor_index() { - return m_csubsize + m_cursor.elements; + return m_max_cursor_index + m_cursors.elements; } inline uint - current_cursors() + current_cursor_count() { - return m_coffset + m_cursor.elements; + return m_cursor_offset + m_cursors.elements; } protected: /* - m_total_pvars -- number of variables (including all types of arguments) + m_max_var_index -- number of variables (including all types of arguments) in this context including all children contexts. - m_total_pvars >= m_pvar.elements. + m_max_var_index >= m_vars.elements. - m_total_pvars of the root parsing context contains number of all + m_max_var_index of the root parsing context contains number of all variables (including arguments) in all enclosed contexts. */ - uint m_total_pvars; + uint m_max_var_index; // The maximum sub context's framesizes - uint m_csubsize; - uint m_hsubsize; - uint m_handlers; // No. of handlers in this context + uint m_max_cursor_index; + uint m_max_handler_index; + uint m_context_handlers; // No. of handlers in this context private: sp_pcontext *m_parent; // Parent context /* - m_poffset -- basically, this is an index of the first variable in this - parsing context. + m_var_offset -- this is an index of the first variable in this + parsing context. - m_poffset is 0 for root context. + m_var_offset is 0 for root context. Since now each variable is stored in separate place, no reuse is done, - so m_poffset is different for all enclosed contexts. + so m_var_offset is different for all enclosed contexts. */ - uint m_poffset; + uint m_var_offset; - uint m_coffset; // Cursor offset for this context + uint m_cursor_offset; // Cursor offset for this context /* Boundary for finding variables in this context. This is the number @@ -382,11 +408,11 @@ private: int m_num_case_exprs; - DYNAMIC_ARRAY m_pvar; // Parameters/variables + DYNAMIC_ARRAY m_vars; // Parameters/variables DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */ - DYNAMIC_ARRAY m_cond; // Conditions - DYNAMIC_ARRAY m_cursor; // Cursors - DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates + DYNAMIC_ARRAY m_conds; // Conditions + DYNAMIC_ARRAY m_cursors; // Cursors + DYNAMIC_ARRAY m_handlers; // Handlers, for checking for duplicates List m_label; // The label list diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index af4e41c29be..38b6de0e75a 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -73,16 +73,16 @@ bool sp_rcontext::init(THD *thd) return !(m_handler= - (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handlers() * + (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() * sizeof(sp_handler_t))) || !(m_hstack= - (uint*)thd->alloc(m_root_parsing_ctx->max_handlers() * + (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * sizeof(uint))) || !(m_in_handler= - (uint*)thd->alloc(m_root_parsing_ctx->max_handlers() * + (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * sizeof(uint))) || !(m_cstack= - (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursors() * + (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() * sizeof(sp_cursor*))) || !(m_case_expr_holders= (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() * @@ -105,12 +105,12 @@ sp_rcontext::init_var_table(THD *thd) { List field_def_lst; - if (!m_root_parsing_ctx->total_pvars()) + if (!m_root_parsing_ctx->max_var_index()) return FALSE; m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst); - DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->total_pvars()); + DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index()); if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst))) return TRUE; @@ -134,7 +134,7 @@ bool sp_rcontext::init_var_items() { uint idx; - uint num_vars= m_root_parsing_ctx->total_pvars(); + uint num_vars= m_root_parsing_ctx->max_var_index(); if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *)))) return TRUE; @@ -381,7 +381,7 @@ sp_cursor::destroy() int -sp_cursor::fetch(THD *thd, List *vars) +sp_cursor::fetch(THD *thd, List *vars) { if (! server_side_cursor) { @@ -528,9 +528,9 @@ int Select_fetch_into_spvars::prepare(List &fields, SELECT_LEX_UNIT *u) bool Select_fetch_into_spvars::send_data(List &items) { - List_iterator_fast pv_iter(*spvar_list); + List_iterator_fast spvar_iter(*spvar_list); List_iterator_fast item_iter(items); - sp_pvar_t *pv; + sp_variable_t *spvar; Item *item; /* Must be ensured by the caller */ @@ -540,9 +540,9 @@ bool Select_fetch_into_spvars::send_data(List &items) Assign the row fetched from a server side cursor to stored procedure variables. */ - for (; pv= pv_iter++, item= item_iter++; ) + for (; spvar= spvar_iter++, item= item_iter++; ) { - if (thd->spcont->set_variable(thd, pv->offset, item)) + if (thd->spcont->set_variable(thd, spvar->offset, item)) return TRUE; } return FALSE; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index e7393902e72..20aaea3b7c1 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -24,7 +24,7 @@ struct sp_cond_type; class sp_cursor; -struct sp_pvar; +struct sp_variable; class sp_lex_keeper; class sp_instr_cpush; @@ -265,12 +265,12 @@ private: class Select_fetch_into_spvars: public select_result_interceptor { - List *spvar_list; + List *spvar_list; uint field_count; public: Select_fetch_into_spvars() {} /* Remove gcc warning */ uint get_field_count() { return field_count; } - void set_spvar_list(List *vars) { spvar_list= vars; } + void set_spvar_list(List *vars) { spvar_list= vars; } virtual bool send_eof() { return FALSE; } virtual bool send_data(List &items); @@ -307,7 +307,7 @@ public: } int - fetch(THD *, List *vars); + fetch(THD *, List *vars); inline sp_instr_cpush * get_instr() diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ddc267eb970..37f72c351e5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1461,22 +1461,23 @@ sp_fdparam: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$1, TRUE)) + if (spc->find_variable(&$1, TRUE)) { my_error(ER_SP_DUP_PARAM, MYF(0), $1.str); YYABORT; } - sp_pvar_t *pvar= spc->push_pvar(&$1, (enum enum_field_types)$3, - sp_param_in); + sp_variable_t *spvar= spc->push_variable(&$1, + (enum enum_field_types)$3, + sp_param_in); if (lex->sphead->fill_field_definition(YYTHD, lex, (enum enum_field_types) $3, - &pvar->field_def)) + &spvar->field_def)) { YYABORT; } - pvar->field_def.field_name= pvar->name.str; - pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + spvar->field_def.field_name= spvar->name.str; + spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; } ; @@ -1497,22 +1498,23 @@ sp_pdparam: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$3, TRUE)) + if (spc->find_variable(&$3, TRUE)) { my_error(ER_SP_DUP_PARAM, MYF(0), $3.str); YYABORT; } - sp_pvar_t *pvar= spc->push_pvar(&$3, (enum enum_field_types)$4, - (sp_param_mode_t)$1); + sp_variable_t *spvar= spc->push_variable(&$3, + (enum enum_field_types)$4, + (sp_param_mode_t)$1); if (lex->sphead->fill_field_definition(YYTHD, lex, (enum enum_field_types) $4, - &pvar->field_def)) + &spvar->field_def)) { YYABORT; } - pvar->field_def.field_name= pvar->name.str; - pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + spvar->field_def.field_name= spvar->name.str; + spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; } ; @@ -1576,7 +1578,7 @@ sp_decl: { LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; - uint num_vars= pctx->context_pvars(); + uint num_vars= pctx->context_var_count(); enum enum_field_types var_type= (enum enum_field_types) $4; Item *dflt_value_item= $5; create_field *create_field_op; @@ -1589,23 +1591,23 @@ sp_decl: for (uint i = num_vars-$2 ; i < num_vars ; i++) { - uint var_idx= pctx->pvar_context2index(i); - sp_pvar_t *pvar= pctx->find_pvar(var_idx); + uint var_idx= pctx->var_context2runtime(i); + sp_variable_t *spvar= pctx->find_variable(var_idx); - if (!pvar) + if (!spvar) YYABORT; - pvar->type= var_type; - pvar->dflt= dflt_value_item; + spvar->type= var_type; + spvar->dflt= dflt_value_item; if (lex->sphead->fill_field_definition(YYTHD, lex, var_type, - &pvar->field_def)) + &spvar->field_def)) { YYABORT; } - pvar->field_def.field_name= pvar->name.str; - pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + spvar->field_def.field_name= spvar->name.str; + spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; /* The last instruction is responsible for freeing LEX. */ @@ -1642,7 +1644,7 @@ sp_decl: sp_pcontext *ctx= lex->spcont; sp_instr_hpush_jump *i= new sp_instr_hpush_jump(sp->instructions(), ctx, $2, - ctx->current_pvars()); + ctx->current_var_count()); sp->add_instr(i); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); @@ -1659,7 +1661,7 @@ sp_decl: if ($2 == SP_HANDLER_CONTINUE) { i= new sp_instr_hreturn(sp->instructions(), ctx, - ctx->current_pvars()); + ctx->current_var_count()); sp->add_instr(i); } else @@ -1690,7 +1692,7 @@ sp_decl: YYABORT; } i= new sp_instr_cpush(sp->instructions(), ctx, $5, - ctx->current_cursors()); + ctx->current_cursor_count()); sp->add_instr(i); ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; @@ -1845,12 +1847,12 @@ sp_decl_idents: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$1, TRUE)) + if (spc->find_variable(&$1, TRUE)) { my_error(ER_SP_DUP_VAR, MYF(0), $1.str); YYABORT; } - spc->push_pvar(&$1, (enum_field_types)0, sp_param_in); + spc->push_variable(&$1, (enum_field_types)0, sp_param_in); $$= 1; } | sp_decl_idents ',' ident @@ -1860,12 +1862,12 @@ sp_decl_idents: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$3, TRUE)) + if (spc->find_variable(&$3, TRUE)) { my_error(ER_SP_DUP_VAR, MYF(0), $3.str); YYABORT; } - spc->push_pvar(&$3, (enum_field_types)0, sp_param_in); + spc->push_variable(&$3, (enum_field_types)0, sp_param_in); $$= $1 + 1; } ; @@ -2198,9 +2200,9 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; - if (!spc || !(spv = spc->find_pvar(&$1))) + if (!spc || !(spv = spc->find_variable(&$1))) { my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); YYABORT; @@ -2219,9 +2221,9 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; - if (!spc || !(spv = spc->find_pvar(&$3))) + if (!spc || !(spv = spc->find_variable(&$3))) { my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str); YYABORT; @@ -5868,9 +5870,9 @@ select_var_ident: | ident_or_text { LEX *lex=Lex; - sp_pvar_t *t; + sp_variable_t *t; - if (!lex->spcont || !(t=lex->spcont->find_pvar(&$1))) + if (!lex->spcont || !(t=lex->spcont->find_variable(&$1))) { my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); YYABORT; @@ -7200,10 +7202,10 @@ order_ident: simple_ident: ident { - sp_pvar_t *spv; + sp_variable_t *spv; LEX *lex = Lex; sp_pcontext *spc = lex->spcont; - if (spc && (spv = spc->find_pvar(&$1))) + if (spc && (spv = spc->find_variable(&$1))) { /* We're compiling a stored procedure and found a variable */ Item_splocal *splocal; @@ -7947,7 +7949,7 @@ sys_option_value: { /* An SP local variable */ sp_pcontext *ctx= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; sp_instr_set *sp_set; Item *it; if ($1) @@ -7956,7 +7958,7 @@ sys_option_value: YYABORT; } - spv= ctx->find_pvar(&$2.base_name); + spv= ctx->find_variable(&$2.base_name); if ($4) it= $4; @@ -8006,7 +8008,7 @@ option_value: names.str= (char *)"names"; names.length= 5; - if (spc && spc->find_pvar(&names)) + if (spc && spc->find_variable(&names)) my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); else yyerror(ER(ER_SYNTAX_ERROR)); @@ -8036,7 +8038,7 @@ option_value: pw.str= (char *)"password"; pw.length= 8; - if (spc && spc->find_pvar(&pw)) + if (spc && spc->find_variable(&pw)) { my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); YYABORT; @@ -8058,10 +8060,10 @@ internal_variable_name: { LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; /* We have to lookup here since local vars can shadow sysvars */ - if (!spc || !(spv = spc->find_pvar(&$1))) + if (!spc || !(spv = spc->find_variable(&$1))) { /* Not an SP local variable */ sys_var *tmp=find_sys_var($1.str, $1.length); From 89af53f8c5dd58e89d6f9f7f96488f7bb300329c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 8 Apr 2006 23:19:52 +0300 Subject: [PATCH 047/101] Check tinfo library presence and use it. (BUG#18912) acinclude.m4: Check tinfo library presence and use it. --- acinclude.m4 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acinclude.m4 b/acinclude.m4 index f36940670a6..ddc50d2972b 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -373,7 +373,8 @@ AC_CACHE_VAL(mysql_cv_termcap_lib, [AC_CHECK_LIB(ncurses, tgetent, mysql_cv_termcap_lib=libncurses, [AC_CHECK_LIB(curses, tgetent, mysql_cv_termcap_lib=libcurses, [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap, - mysql_cv_termcap_lib=NOT_FOUND)])])]) + [AC_CHECK_LIB(tinfo, tgetent, mysql_cv_termcap_lib=libtinfo, + mysql_cv_termcap_lib=NOT_FOUND)])])])]) AC_MSG_CHECKING(for termcap functions library) if test "$mysql_cv_termcap_lib" = "NOT_FOUND"; then AC_MSG_ERROR([No curses/termcap library found]) @@ -381,6 +382,8 @@ elif test "$mysql_cv_termcap_lib" = "libtermcap"; then TERMCAP_LIB=-ltermcap elif test "$mysql_cv_termcap_lib" = "libncurses"; then TERMCAP_LIB=-lncurses +elif test "$mysql_cv_termcap_lib" = "libtinfo"; then +TERMCAP_LIB=-ltinfo else TERMCAP_LIB=-lcurses fi From 4a2eef5c7440df6fb39f29f8bc5a7e6e7bd6e5d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 10 Apr 2006 21:57:29 +0300 Subject: [PATCH 048/101] Avoid trying to include when it doesn't work in C++ code. (Bug #13621) configure.in: Test whether atomic_add() and atomic_sub() are available in C++ code, since that is primarily where we will be using them. --- configure.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.in b/configure.in index df4b0fbd5af..0445f7a05e9 100644 --- a/configure.in +++ b/configure.in @@ -830,6 +830,9 @@ AC_SUBST(WRAPLIBS) if test "$IS_LINUX" = "true"; then AC_MSG_CHECKING([for atomic operations]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + atom_ops= AC_TRY_RUN([ #include @@ -859,6 +862,8 @@ int main() if test -z "$atom_ops"; then atom_ops="no"; fi AC_MSG_RESULT($atom_ops) + AC_LANG_RESTORE + AC_ARG_WITH(pstack, [ --with-pstack Use the pstack backtrace library], [ USE_PSTACK=$withval ], From d7caa2a02aedec5a294bbb0c64aed048f23dc6be Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 11 Apr 2006 15:26:18 +0500 Subject: [PATCH 049/101] after merge fix. --- mysql-test/t/func_op.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index 6521349a558..0a4f5034f4c 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -21,7 +21,9 @@ select -1 >> 1, -1 << 1; # Bug 13044: wrong bit_count() results # +--disable_warnings drop table if exists t1,t2; +--enable_warnings create table t1(a int); create table t2(a int, b int); insert into t1 values (1), (2), (3); From 0e19aa9e4e62b7f21302bd4aecc79709d4c9614e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Apr 2006 12:50:12 +0300 Subject: [PATCH 050/101] #BUG18715 create view with replicate*ignore-table Fixed in parser. rpl_view gained no changes but rpl_view-slave.opt. sql/sql_yacc.yy: UPDATING option for create/alter view is added for tables_ok to finds the view's TABLE_LIST.updating as true. FIXME: Regarding to UPDATING option `create view' should not have any difference from `create table'. mysql-test/t/rpl_view-slave.opt: The option is needed to force slave executes tables_ok which must return OK in conditions of this tests (no table foo is used. --- mysql-test/t/rpl_view-slave.opt | 5 +++++ sql/sql_yacc.yy | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 mysql-test/t/rpl_view-slave.opt diff --git a/mysql-test/t/rpl_view-slave.opt b/mysql-test/t/rpl_view-slave.opt new file mode 100644 index 00000000000..55b3aeb3bda --- /dev/null +++ b/mysql-test/t/rpl_view-slave.opt @@ -0,0 +1,5 @@ +# +# BUG18715 create view with replicate*ignore-table +# The option is needed to force slave executes tables_ok +# which must return OK in conditions of this tests (no table foo is used) +--replicate-ignore-table=test.foo diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ddc267eb970..e566fdf7241 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3390,7 +3390,7 @@ alter: lex->sql_command= SQLCOM_CREATE_VIEW; lex->create_view_mode= VIEW_ALTER; /* first table in list is target VIEW name */ - lex->select_lex.add_table_to_list(thd, $6, NULL, 0); + lex->select_lex.add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING); } view_list_opt AS view_select view_check_option {} @@ -9025,7 +9025,7 @@ view_tail: LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; /* first table in list is target VIEW name */ - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING)) YYABORT; } view_list_opt AS view_select view_check_option From 51a3d3668fdbfd25588dd92038f6d82dc7eb8306 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Apr 2006 17:37:57 +0400 Subject: [PATCH 051/101] In test for bug#15933 we have to wait for all disconnects to finish to avoid a race between updating and checking Max_used_connections. This is done in a loop until either disconnect finished or timeout expired. In a latter case the test will fail. mysql-test/r/status.result: Update result to match changes in test case. mysql-test/t/status.test: Close extra conections in previous test. In test for bug#15933 we have to wait for all disconnects to finish to avoid a race between updating and checking Max_used_connections. This is done in a loop until either disconnect finished or timeout expired. In a latter case the test will fail. Use con1, con2, con3 instead of con3, con4, con5. --- mysql-test/r/status.result | 16 +++++----- mysql-test/t/status.test | 65 ++++++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 4e5489191c9..ca21b333a6a 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -26,20 +26,20 @@ Last_query_cost 0.000000 FLUSH STATUS; SHOW STATUS LIKE 'max_used_connections'; Variable_name Value -Max_used_connections 3 +Max_used_connections 1 SET @save_thread_cache_size=@@thread_cache_size; SET GLOBAL thread_cache_size=3; SHOW STATUS LIKE 'max_used_connections'; Variable_name Value -Max_used_connections 5 +Max_used_connections 3 FLUSH STATUS; SHOW STATUS LIKE 'max_used_connections'; Variable_name Value +Max_used_connections 2 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 3 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value Max_used_connections 4 -SHOW STATUS LIKE 'max_used_connections'; -Variable_name Value -Max_used_connections 5 -SHOW STATUS LIKE 'max_used_connections'; -Variable_name Value -Max_used_connections 6 SET GLOBAL thread_cache_size=@save_thread_cache_size; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 79a46a38550..1a71425d2a7 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -36,6 +36,10 @@ reap; show status like 'Table_lock%'; drop table t1; +disconnect con2; +disconnect con1; +connection default; + # End of 4.1 tests # @@ -60,48 +64,81 @@ show status like 'last_query_cost'; # taking a thread from the cache as well as when creating new threads # -# Previous test uses con1, con2. If we disconnect them, there will be -# a race on when exactly this will happen, so we better leave them as -# is. -connection default; +# Wait for at most $disconnect_timeout seconds for disconnects to finish. +let $disconnect_timeout = 10; -# Reset max_used_connections from previous tests. +# Wait for any previous disconnects to finish. FLUSH STATUS; +--disable_query_log +--disable_result_log +eval SET @wait_left = $disconnect_timeout; +let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; +eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; +let $wait_more = `SELECT @max_used_connections != 1 && @wait_left > 0`; +while ($wait_more) +{ + sleep 1; + FLUSH STATUS; + SET @wait_left = @wait_left - 1; + let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; + eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; + let $wait_more = `SELECT @max_used_connections != 1 && @wait_left > 0`; +} +--enable_query_log +--enable_result_log + +# Prerequisite. SHOW STATUS LIKE 'max_used_connections'; # Save original setting. SET @save_thread_cache_size=@@thread_cache_size; SET GLOBAL thread_cache_size=3; -connect (con3,localhost,root,,); -connect (con4,localhost,root,,); +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); -connection con3; -disconnect con4; +connection con1; +disconnect con2; # Check that max_used_connections still reflects maximum value. SHOW STATUS LIKE 'max_used_connections'; # Check that after flush max_used_connections equals to current number -# of connections. +# of connections. First wait for previous disconnect to finish. FLUSH STATUS; +--disable_query_log +--disable_result_log +eval SET @wait_left = $disconnect_timeout; +let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; +eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; +let $wait_more = `SELECT @max_used_connections != 2 && @wait_left > 0`; +while ($wait_more) +{ + sleep 1; + FLUSH STATUS; + SET @wait_left = @wait_left - 1; + let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; + eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; + let $wait_more = `SELECT @max_used_connections != 2 && @wait_left > 0`; +} +--enable_query_log +--enable_result_log +# Check that we don't count disconnected thread any longer. SHOW STATUS LIKE 'max_used_connections'; # Check that max_used_connections is updated when cached thread is # reused... -connect (con4,localhost,root,,); +connect (con2,localhost,root,,); SHOW STATUS LIKE 'max_used_connections'; # ...and when new thread is created. -connect (con5,localhost,root,,); +connect (con3,localhost,root,,); SHOW STATUS LIKE 'max_used_connections'; # Restore original setting. connection default; SET GLOBAL thread_cache_size=@save_thread_cache_size; -disconnect con5; -disconnect con4; disconnect con3; disconnect con2; disconnect con1; From 886a35bd82c153253007040202116b5f634705f4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Apr 2006 19:31:00 +0400 Subject: [PATCH 052/101] Bug#16461: connection_id() does not work properly inside trigger CONNECTION_ID() was implemented as a constant Item, i.e. an instance of Item_static_int_func class holding value computed at creation time. Since Items are created on parsing, and trigger statements are parsed on table open, the first connection to open a particular table would effectively set its own CONNECTION_ID() inside trigger statements for that table. Re-implement CONNECTION_ID() as a class derived from Item_int_func, and compute connection_id on every call to fix_fields(). mysql-test/r/trigger.result: Add result for bug#16461. mysql-test/t/trigger.test: Add test case for bug#16461. sql/item.cc: Remove now unused class Item_static_int_func. sql/item.h: Remove now unused class Item_static_int_func. sql/item_create.cc: Use new implementation of CONNECTION_ID(). sql/item_func.cc: Re-implement CONNECTION_ID() as Item_func_connection_id (was Item_static_int_func). Set max_length to 10, as it was before. Compute connection_id dynamically on every call to fix_fields(). sql/item_func.h: Re-implement CONNECTION_ID() as Item_func_connection_id (was Item_static_int_func). --- mysql-test/r/trigger.result | 13 +++++++++++++ mysql-test/t/trigger.test | 28 ++++++++++++++++++++++++++++ sql/item.cc | 16 ---------------- sql/item.h | 12 ------------ sql/item_create.cc | 10 ++-------- sql/item_func.cc | 25 +++++++++++++++++++++++++ sql/item_func.h | 12 ++++++++++++ 7 files changed, 80 insertions(+), 36 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 828db549b05..681b805f547 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -952,3 +952,16 @@ load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1(); drop table t1; drop function f1; drop function f2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +conn_id INT, +trigger_conn_id INT +); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +SET NEW.trigger_conn_id = CONNECTION_ID(); +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); +SELECT * FROM t1 WHERE conn_id != trigger_conn_id; +conn_id trigger_conn_id +DROP TRIGGER t1_bi; +DROP TABLE t1; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index c5925bbd9d5..a0b67b2204d 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1114,3 +1114,31 @@ load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1(); drop table t1; drop function f1; drop function f2; + +# +# Test for Bug #16461 connection_id() does not work properly inside trigger +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 ( + conn_id INT, + trigger_conn_id INT +); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + SET NEW.trigger_conn_id = CONNECTION_ID(); + +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); + +connect (con1,localhost,root,,); +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); +connection default; +disconnect con1; + +SELECT * FROM t1 WHERE conn_id != trigger_conn_id; + +DROP TRIGGER t1_bi; +DROP TABLE t1; + +# End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index 45a6b0cef31..4d3ce6071eb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -644,22 +644,6 @@ Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs) } -Item *Item_static_int_func::safe_charset_converter(CHARSET_INFO *tocs) -{ - Item_string *conv; - char buf[64]; - String *s, tmp(buf, sizeof(buf), &my_charset_bin); - s= val_str(&tmp); - if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(), - s->charset()))) - { - conv->str_value.copy(); - conv->str_value.mark_as_const(); - } - return conv; -} - - Item *Item_static_float_func::safe_charset_converter(CHARSET_INFO *tocs) { Item_string *conv; diff --git a/sql/item.h b/sql/item.h index 3b96091af38..d33e0ae34be 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1387,18 +1387,6 @@ public: }; -class Item_static_int_func :public Item_int -{ - const char *func_name; -public: - Item_static_int_func(const char *str_arg, longlong i, uint length) - :Item_int(NullS, i, length), func_name(str_arg) - {} - Item *safe_charset_converter(CHARSET_INFO *tocs); - void print(String *str) { str->append(func_name); } -}; - - class Item_uint :public Item_int { public: diff --git a/sql/item_create.cc b/sql/item_create.cc index 342ef245a76..bfcb2101d60 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -71,14 +71,8 @@ Item *create_func_ceiling(Item* a) Item *create_func_connection_id(void) { - THD *thd=current_thd; - thd->lex->safe_to_cache_query= 0; - return new Item_static_int_func("connection_id()", - (longlong) - ((thd->slave_thread) ? - thd->variables.pseudo_thread_id : - thd->thread_id), - 10); + current_thd->lex->safe_to_cache_query= 0; + return new Item_func_connection_id(); } Item *create_func_conv(Item* a, Item *b, Item *c) diff --git a/sql/item_func.cc b/sql/item_func.cc index f40f868f75f..d4a0e607fc2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -559,6 +559,31 @@ String *Item_int_func::val_str(String *str) } +void Item_func_connection_id::fix_length_and_dec() +{ + Item_int_func::fix_length_and_dec(); + max_length= 10; +} + + +bool Item_func_connection_id::fix_fields(THD *thd, Item **ref) +{ + if (Item_int_func::fix_fields(thd, ref)) + return TRUE; + + /* + To replicate CONNECTION_ID() properly we should use + pseudo_thread_id on slave, which contains the value of thread_id + on master. + */ + value= ((thd->slave_thread) ? + thd->variables.pseudo_thread_id : + thd->thread_id); + + return FALSE; +} + + /* Check arguments here to determine result's type for a numeric function of two arguments. diff --git a/sql/item_func.h b/sql/item_func.h index ccbbbab1df4..ed5924e8fe1 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -279,6 +279,18 @@ public: }; +class Item_func_connection_id :public Item_int_func +{ + longlong value; + +public: + const char *func_name() const { return "connection_id"; } + void fix_length_and_dec(); + bool fix_fields(THD *thd, Item **ref); + longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } +}; + + class Item_func_signed :public Item_int_func { public: From 5c0c1dcc3d7f46f30d144e80fc88a3ef1a4bcd1e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 10:55:48 +0500 Subject: [PATCH 053/101] Bug#18691: Converting number to UNICODE string returns invalid result. Conversion from int and real numbers to UCS2 didn't work fine: CONVERT(100, CHAR(50) UNICODE) CONVERT(103.9, CHAR(50) UNICODE) The problem appeared because numbers have binary charset, so, simple charset recast binary->ucs2 was performed instead of real conversion. Fixed to make numbers pretend to be non-binary. mysql-test/r/ctype_ucs.result: Adding test case mysql-test/t/ctype_ucs.test: Adding test case sql/item_timefunc.cc: Adding new member from_cs, to replace my_charset_bin to a non-binary charset when converting from numbers to UCS2 sql/item_timefunc.h: Adding new member from_cs, to replace my_charset_bin to a non-binary charset when converting from numbers to UCS2 --- mysql-test/r/ctype_ucs.result | 12 ++++++++++++ mysql-test/t/ctype_ucs.test | 8 ++++++++ sql/item_timefunc.cc | 28 +++++++++++++++++++++++----- sql/item_timefunc.h | 2 +- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 0e12ec88662..8869604b128 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -666,6 +666,18 @@ Warnings: Warning 1265 Data truncated for column 'Field1' at row 1 DROP TABLE t1; SET NAMES latin1; +SELECT CONVERT(103, CHAR(50) UNICODE); +CONVERT(103, CHAR(50) UNICODE) +103 +SELECT CONVERT(103.0, CHAR(50) UNICODE); +CONVERT(103.0, CHAR(50) UNICODE) +103.0 +SELECT CONVERT(-103, CHAR(50) UNICODE); +CONVERT(-103, CHAR(50) UNICODE) +-103 +SELECT CONVERT(-103.0, CHAR(50) UNICODE); +CONVERT(-103.0, CHAR(50) UNICODE) +-103.0 CREATE TABLE t1 ( a varchar(255) NOT NULL default '', KEY a (a) diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index bd37d008173..2cbabf88ee0 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -407,6 +407,14 @@ INSERT INTO t1 VALUES ('-1'); DROP TABLE t1; SET NAMES latin1; +# +# Bug#18691 Converting number to UNICODE string returns invalid result +# +SELECT CONVERT(103, CHAR(50) UNICODE); +SELECT CONVERT(103.0, CHAR(50) UNICODE); +SELECT CONVERT(-103, CHAR(50) UNICODE); +SELECT CONVERT(-103.0, CHAR(50) UNICODE); + # # Bug#9557 MyISAM utf8 table crash # diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d6b57464d59..f3d6858755c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2221,8 +2221,8 @@ String *Item_char_typecast::val_str(String *str) // Convert character set if differ uint dummy_errors; if (!(res= args[0]->val_str(&tmp_value)) || - str->copy(res->ptr(), res->length(), res->charset(), - cast_cs, &dummy_errors)) + str->copy(res->ptr(), res->length(), from_cs, + cast_cs, &dummy_errors)) { null_value= 1; return 0; @@ -2261,14 +2261,32 @@ void Item_char_typecast::fix_length_and_dec() For single-byte character sets we allow just to copy from the argument. A single-byte character sets string is always well-formed. + + There is a special trick to convert form a number to ucs2. + As numbers have my_charset_bin as their character set, + it wouldn't do conversion to ucs2 without an additional action. + To force conversion, we should pretend to be non-binary. + Let's choose from_cs this way: + - If the argument in a number and cast_cs is ucs2 (i.e. mbminlen > 1), + then from_cs is set to latin1, to perform latin1 -> ucs2 conversion. + - If the argument is a number and cast_cs is ASCII-compatible + (i.e. mbminlen == 1), then from_cs is set to cast_cs, + which allows just to take over the args[0]->val_str() result + and thus avoid unnecessary character set conversion. + - If the argument is not a number, then from_cs is set to + the argument's charset. */ + from_cs= (args[0]->result_type() == INT_RESULT || + args[0]->result_type() == REAL_RESULT) ? + (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) : + args[0]->collation.collation; charset_conversion= (cast_cs->mbmaxlen > 1) || - !my_charset_same(args[0]->collation.collation, cast_cs) && - args[0]->collation.collation != &my_charset_bin && + !my_charset_same(from_cs, cast_cs) && + from_cs != &my_charset_bin && cast_cs != &my_charset_bin; collation.set(cast_cs, DERIVATION_IMPLICIT); char_length= (cast_length >= 0) ? cast_length : - args[0]->max_length/args[0]->collation.collation->mbmaxlen; + args[0]->max_length/from_cs->mbmaxlen; max_length= char_length * cast_cs->mbmaxlen; } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index ce9d6b0a7aa..163b1591e52 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -681,7 +681,7 @@ public: class Item_char_typecast :public Item_typecast { int cast_length; - CHARSET_INFO *cast_cs; + CHARSET_INFO *cast_cs, *from_cs; bool charset_conversion; String tmp_value; public: From ce33555014b52d43b1f6911b24abf6ac0da62550 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 17:20:33 +0930 Subject: [PATCH 054/101] foo1 sql/ha_innodb.cc: Import patch foo1 sql/ha_innodb.h: Import patch foo1 sql/handler.cc: Import patch foo1 sql/handler.h: Import patch foo1 sql/mysqld.cc: Import patch foo1 sql/set_var.cc: Import patch foo1 sql/sql_class.h: Import patch foo1 sql/sql_repl.cc: Import patch foo1 --- sql/ha_innodb.cc | 278 +++++++++++++++++++++++------------------------ sql/ha_innodb.h | 16 +-- sql/handler.cc | 76 ++++++------- sql/handler.h | 26 ++--- sql/mysqld.cc | 96 ++++++++-------- sql/set_var.cc | 50 ++++----- sql/sql_class.h | 48 ++++---- sql/sql_repl.cc | 18 +-- 8 files changed, 304 insertions(+), 304 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 41f017e6405..98fb6b69ab3 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -153,7 +153,7 @@ longlong innobase_buffer_pool_size, innobase_log_file_size; /* The default values for the following char* start-up parameters are determined in innobase_init below: */ - + char* innobase_data_home_dir = NULL; char* innobase_data_file_path = NULL; char* innobase_log_group_home_dir = NULL; @@ -205,7 +205,7 @@ static int innobase_release_savepoint(THD* thd, void *savepoint); handlerton innobase_hton = { "InnoDB", SHOW_OPTION_YES, - "Supports transactions, row-level locking, and foreign keys", + "Supports transactions, row-level locking, and foreign keys", DB_TYPE_INNODB, innobase_init, 0, /* slot */ @@ -394,7 +394,7 @@ innobase_release_temporary_latches( trx_t* trx; if (!innodb_inited) { - + return; } @@ -612,7 +612,7 @@ innobase_mysql_print_thd( /* Points to buf or dyn_str. */ char* str = buf; - + if (max_query_len == 0) { /* ADDITIONAL SAFETY: the default is to print at @@ -623,7 +623,7 @@ innobase_mysql_print_thd( safe */ max_query_len = 300; } - + len = min(thd->query_length, max_query_len); if (len > (sizeof(buf) - 1)) @@ -975,7 +975,7 @@ innobase_query_caching_of_table_permitted( if (thd->variables.tx_isolation == ISO_SERIALIZABLE) { /* In the SERIALIZABLE mode we add LOCK IN SHARE MODE to every plain SELECT if AUTOCOMMIT is not on. */ - + return((my_bool)FALSE); } @@ -1022,7 +1022,7 @@ innobase_query_caching_of_table_permitted( return((my_bool)TRUE); } - + /* Normalize the table name to InnoDB format */ memcpy(norm_name, full_name, full_name_len); @@ -1306,12 +1306,12 @@ innobase_init(void) /* -------------- Log files ---------------------------*/ /* The default dir for log files is the datadir of MySQL */ - + if (!innobase_log_group_home_dir) { innobase_log_group_home_dir = default_path; } -#ifdef UNIV_LOG_ARCHIVE +#ifdef UNIV_LOG_ARCHIVE /* Since innodb_log_arch_dir has no relevance under MySQL, starting from 4.0.6 we always set it the same as innodb_log_group_home_dir: */ @@ -1353,14 +1353,14 @@ innobase_init(void) if (innobase_buffer_pool_awe_mem_mb == 0) { /* Careful here: we first convert the signed long int to ulint and only after that divide */ - + srv_pool_size = ((ulint) innobase_buffer_pool_size) / 1024; } else { srv_use_awe = TRUE; srv_pool_size = (ulint) (1024 * innobase_buffer_pool_awe_mem_mb); srv_awe_window_size = (ulint) innobase_buffer_pool_size; - + /* Note that what the user specified as innodb_buffer_pool_size is actually the AWE memory window size in this case, and the real buffer pool size is @@ -1379,7 +1379,7 @@ innobase_init(void) os_use_large_pages = (ibool) innobase_use_large_pages; os_large_page_size = (ulint) innobase_large_page_size; - + srv_file_per_table = (ibool) innobase_file_per_table; srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog; @@ -1439,7 +1439,7 @@ innobase_init(void) THIS DOES NOT WORK CURRENTLY because replication seems to initialize glob_mi also after innobase_init. */ - + /* if (trx_sys_mysql_master_log_pos != -1) { ut_memcpy(glob_mi.log_file_name, trx_sys_mysql_master_log_name, 1 + ut_strlen(trx_sys_mysql_master_log_name)); @@ -1613,7 +1613,7 @@ innobase_commit( if (trx->has_search_latch) { trx_search_latch_release_if_reserved(trx); } - + /* The flag trx->active_trans is set to 1 in 1. ::external_lock(), @@ -1631,13 +1631,13 @@ innobase_commit( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - + sql_print_error("trx->active_trans == 0, but trx->conc_state != " "TRX_NOT_STARTED"); } if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { - + /* We were instructed to commit the whole transaction, or this is an SQL statement end and autocommit is on */ @@ -1658,7 +1658,7 @@ retry: else pthread_mutex_unlock(&commit_cond_m); } - + trx->mysql_log_file_name = mysql_bin_log.get_log_fname(); trx->mysql_log_offset = (ib_longlong)mysql_bin_log.get_log_file()->pos_in_file; @@ -1672,14 +1672,14 @@ retry: pthread_cond_signal(&commit_cond); pthread_mutex_unlock(&commit_cond_m); } - + if (trx->active_trans == 2) { pthread_mutex_unlock(&prepare_commit_mutex); } - + trx->active_trans = 0; - + } else { /* We just mark the SQL statement ended and do not do a transaction commit */ @@ -1687,7 +1687,7 @@ retry: if (trx->auto_inc_lock) { /* If we had reserved the auto-inc lock for some table in this SQL statement we release it now */ - + row_unlock_table_autoinc_for_mysql(trx); } /* Store the current undo_no of the transaction so that we @@ -2074,7 +2074,7 @@ innobase_rollback( /* If we had reserved the auto-inc lock for some table (if we come here to roll back the latest SQL statement) we release it now before a possibly lengthy rollback */ - + row_unlock_table_autoinc_for_mysql(trx); } @@ -2114,7 +2114,7 @@ innobase_rollback_trx( /* If we had reserved the auto-inc lock for some table (if we come here to roll back the latest SQL statement) we release it now before a possibly lengthy rollback */ - + row_unlock_table_autoinc_for_mysql(trx); } @@ -2249,7 +2249,7 @@ innobase_close_connection( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - + sql_print_error("trx->active_trans == 0, but trx->conc_state != " "TRX_NOT_STARTED"); } @@ -2478,7 +2478,7 @@ ha_innobase::open( that may be NULL. ref_length must be as exact as possible to save space, because all row reference buffers are allocated based on ref_length. */ - + ref_length = table->key_info[primary_key].key_length; } else { if (primary_key != MAX_KEY) { @@ -2505,7 +2505,7 @@ ha_innobase::open( that key_used_on_scan is the undefined value MAX_KEY. The column is the row id in the automatical generation case, and it will never be updated anyway. */ - + if (key_used_on_scan != MAX_KEY) { sql_print_warning("Table %s key_used_on_scan is %lu even " "though there is no primary key inside " @@ -2914,7 +2914,7 @@ ha_innobase::store_key_val_for_row( if (is_null) { buff += key_len + 2; - + continue; } cs = field->charset(); @@ -2922,7 +2922,7 @@ ha_innobase::store_key_val_for_row( lenlen = (ulint) (((Field_varstring*)field)->length_bytes); - data = row_mysql_read_true_varchar(&len, + data = row_mysql_read_true_varchar(&len, (byte*) (record + (ulint)get_field_offset(table, field)), lenlen); @@ -2936,7 +2936,7 @@ ha_innobase::store_key_val_for_row( true_len = (ulint) cs->cset->well_formed_len(cs, (const char *) data, (const char *) data + len, - key_len / cs->mbmaxlen, + key_len / cs->mbmaxlen, &error); } @@ -2982,10 +2982,10 @@ ha_innobase::store_key_val_for_row( if (is_null) { buff += key_len + 2; - + continue; } - + cs = field->charset(); blob_data = row_mysql_read_blob_ref(&blob_len, @@ -3000,11 +3000,11 @@ ha_innobase::store_key_val_for_row( /* For multi byte character sets we need to calculate the true length of the key */ - + if (blob_len > 0 && cs->mbmaxlen > 1) { true_len = (ulint) cs->cset->well_formed_len(cs, (const char *) blob_data, - (const char *) blob_data + (const char *) blob_data + blob_len, key_len / cs->mbmaxlen, &error); @@ -3048,7 +3048,7 @@ ha_innobase::store_key_val_for_row( if (is_null) { buff += key_len; - + continue; } @@ -3061,22 +3061,22 @@ ha_innobase::store_key_val_for_row( type is not enum or set. For these fields check if character set is multi byte. */ - if (real_type != FIELD_TYPE_ENUM + if (real_type != FIELD_TYPE_ENUM && real_type != FIELD_TYPE_SET && ( mysql_type == MYSQL_TYPE_VAR_STRING || mysql_type == MYSQL_TYPE_STRING)) { cs = field->charset(); - /* For multi byte character sets we need to + /* For multi byte character sets we need to calculate the true length of the key */ if (key_len > 0 && cs->mbmaxlen > 1) { - true_len = (ulint) + true_len = (ulint) cs->cset->well_formed_len(cs, (const char *)src_start, - (const char *)src_start + (const char *)src_start + key_len, key_len / cs->mbmaxlen, &error); @@ -3086,9 +3086,9 @@ ha_innobase::store_key_val_for_row( memcpy(buff, src_start, true_len); buff += true_len; - /* Pad the unused space with spaces. Note that no - padding is ever needed for UCS-2 because in MySQL, - all UCS2 characters are 2 bytes, as MySQL does not + /* Pad the unused space with spaces. Note that no + padding is ever needed for UCS-2 because in MySQL, + all UCS2 characters are 2 bytes, as MySQL does not support surrogate pairs, which are needed to represent characters in the range U+10000 to U+10FFFF. */ @@ -3286,7 +3286,7 @@ include_field: templ->mysql_length_bytes = (ulint) (((Field_varstring*)field)->length_bytes); } - + templ->charset = dtype_get_charset_coll_noninline( index->table->cols[i].type.prtype); templ->mbminlen = index->table->cols[i].type.mbminlen; @@ -3595,7 +3595,7 @@ calc_row_difference( o_ptr = (byte*) old_row + get_field_offset(table, field); n_ptr = (byte*) new_row + get_field_offset(table, field); - + /* Use new_mysql_row_col and col_pack_len save the values */ new_mysql_row_col = n_ptr; @@ -3605,10 +3605,10 @@ calc_row_difference( n_len = col_pack_len; /* We use o_ptr and n_ptr to dig up the actual data for - comparison. */ + comparison. */ field_mysql_type = field->type(); - + col_type = prebuilt->table->cols[i].type.mtype; switch (col_type) { @@ -3626,12 +3626,12 @@ calc_row_difference( /* This is a >= 5.0.3 type true VARCHAR where the real payload data length is stored in 1 or 2 bytes */ - + o_ptr = row_mysql_read_true_varchar( &o_len, o_ptr, (ulint) (((Field_varstring*)field)->length_bytes)); - + n_ptr = row_mysql_read_true_varchar( &n_len, n_ptr, (ulint) @@ -3660,7 +3660,7 @@ calc_row_difference( /* The field has changed */ ufield = uvect->fields + n_changed; - + /* Let us use a dummy dfield to make the conversion from the MySQL column format to the InnoDB format */ @@ -3812,7 +3812,7 @@ ha_innobase::delete_row( } /************************************************************************** -Removes a new lock set on a row. This method does nothing unless the +Removes a new lock set on a row. This method does nothing unless the option innodb_locks_unsafe_for_binlog is set.*/ void @@ -4496,10 +4496,10 @@ ha_innobase::position( /* We assume that the 'ref' value len is always fixed for the same table. */ - + if (len != ref_length) { sql_print_error("Stored ref len is %lu, but table ref len is %lu", - (ulong) len, (ulong) ref_length); + (ulong) len, (ulong) ref_length); } } @@ -4568,7 +4568,7 @@ create_table_def( binary_type = 0; } - charset_no = 0; + charset_no = 0; if (dtype_is_string_type(col_type)) { @@ -4587,7 +4587,7 @@ create_table_def( for a true VARCHAR. Let us subtract that, so that the InnoDB column length in the InnoDB data dictionary is the real maximum byte length of the actual data. */ - + long_true_varchar = 0; if (field->type() == MYSQL_TYPE_VARCHAR) { @@ -4601,7 +4601,7 @@ create_table_def( dict_mem_table_add_col(table, (char*) field->field_name, col_type, - dtype_form_prtype( + dtype_form_prtype( (ulint)field->type() | nulls_allowed | unsigned_type | binary_type | long_true_varchar, @@ -4642,7 +4642,7 @@ create_index( ulint i; ulint j; ulint* field_lengths; - + DBUG_ENTER("create_index"); key = form->key_info + key_num; @@ -4667,7 +4667,7 @@ create_index( field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields, MYF(MY_FAE)); - + for (i = 0; i < n_fields; i++) { key_part = key->key_part + i; @@ -4676,7 +4676,7 @@ create_index( bytes of the column to the index field.) The flag does not seem to be properly set by MySQL. Let us fall back on testing the length of the key part versus the column. */ - + field = NULL; for (j = 0; j < form->s->fields; j++) { @@ -4715,7 +4715,7 @@ create_index( "name %s, column name %s.", table_name, key_part->field->field_name); - + prefix_len = 0; } } else { @@ -4740,7 +4740,7 @@ create_index( error = convert_error_code_to_mysql(error, NULL); my_free((gptr) field_lengths, MYF(0)); - + DBUG_RETURN(error); } @@ -4804,20 +4804,20 @@ ha_innobase::create( but we play safe here */ DBUG_RETURN(HA_ERR_TO_BIG_ROW); - } + } /* Get the transaction associated with the current thd, or create one if not yet created */ - + parent_trx = check_trx_exists(current_thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ - trx_search_latch_release_if_reserved(parent_trx); + trx_search_latch_release_if_reserved(parent_trx); trx = trx_allocate_for_mysql(); - + trx->mysql_thd = thd; trx->mysql_query_str = &((*thd).query); @@ -4858,7 +4858,7 @@ ha_innobase::create( /* Look for a primary key */ primary_key_no= (table->s->primary_key != MAX_KEY ? - (int) table->s->primary_key : + (int) table->s->primary_key : -1); /* Our function row_get_mysql_key_number_for_index assumes @@ -4907,7 +4907,7 @@ ha_innobase::create( current_thd->query_length, current_thd->charset())) { error = HA_ERR_OUT_OF_MEM; - + goto cleanup; } @@ -4939,7 +4939,7 @@ ha_innobase::create( if ((create_info->used_fields & HA_CREATE_USED_AUTO) && (create_info->auto_increment_value != 0)) { - /* Query was ALTER TABLE...AUTO_INCREMENT = x; or + /* Query was ALTER TABLE...AUTO_INCREMENT = x; or CREATE TABLE ...AUTO_INCREMENT = x; Find out a table definition from the dictionary and get the current value of the auto increment field. Set a new value to the @@ -4961,9 +4961,9 @@ ha_innobase::create( cleanup: innobase_commit_low(trx); - + row_mysql_unlock_data_dictionary(trx); - + trx_free_for_mysql(trx); DBUG_RETURN(error); @@ -5067,13 +5067,13 @@ ha_innobase::delete_table( /* Get the transaction associated with the current thd, or create one if not yet created */ - + parent_trx = check_trx_exists(current_thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ - trx_search_latch_release_if_reserved(parent_trx); + trx_search_latch_release_if_reserved(parent_trx); if (lower_case_table_names) { srv_lower_case_table_names = TRUE; @@ -5149,13 +5149,13 @@ innobase_drop_database( /* Get the transaction associated with the current thd, or create one if not yet created */ - + parent_trx = check_trx_exists(current_thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ - trx_search_latch_release_if_reserved(parent_trx); + trx_search_latch_release_if_reserved(parent_trx); ptr = strend(path) - 2; @@ -5225,13 +5225,13 @@ ha_innobase::rename_table( /* Get the transaction associated with the current thd, or create one if not yet created */ - + parent_trx = check_trx_exists(current_thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ - trx_search_latch_release_if_reserved(parent_trx); + trx_search_latch_release_if_reserved(parent_trx); if (lower_case_table_names) { srv_lower_case_table_names = TRUE; @@ -5439,7 +5439,7 @@ ha_innobase::scan_time() searches, we pretend that a sequential read takes the same time as a random disk read, that is, we do not divide the following by 10, which would be physically realistic. */ - + return((double) (prebuilt->table->stat_clustered_index_size)); } @@ -5457,9 +5457,9 @@ ha_innobase::read_time( { ha_rows total_rows; double time_for_scan; - + if (index != table->s->primary_key) { - /* Not clustered */ + /* Not clustered */ return(handler::read_time(index, ranges, rows)); } @@ -5543,14 +5543,14 @@ ha_innobase::info( ".ibd"); unpack_filename(path,path); } else { - my_snprintf(path, sizeof(path), "%s/%s%s", + my_snprintf(path, sizeof(path), "%s/%s%s", mysql_data_home, ib_table->name, reg_ext); - + unpack_filename(path,path); } - /* Note that we do not know the access time of the table, + /* Note that we do not know the access time of the table, nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ if (os_file_get_status(path,&stat_info)) { @@ -5689,7 +5689,7 @@ ha_innobase::info( the auto-inc counter, and the second call is guaranteed to succeed. */ - ret = innobase_read_and_init_auto_inc(&auto_inc); + ret = innobase_read_and_init_auto_inc(&auto_inc); if (ret != 0) { ret = innobase_read_and_init_auto_inc(&auto_inc); @@ -5702,7 +5702,7 @@ ha_innobase::info( auto_inc = 0; } } - + auto_increment_value = auto_inc; } @@ -5717,7 +5717,7 @@ each index tree. This does NOT calculate exact statistics on the table. */ int ha_innobase::analyze( -/*=================*/ +/*=================*/ /* out: returns always 0 (success) */ THD* thd, /* in: connection thread handle */ HA_CHECK_OPT* check_opt) /* in: currently ignored */ @@ -5775,7 +5775,7 @@ ha_innobase::check( return(HA_ADMIN_OK); } - return(HA_ADMIN_CORRUPT); + return(HA_ADMIN_CORRUPT); } /***************************************************************** @@ -5917,7 +5917,7 @@ ha_innobase::get_foreign_key_create_info(void) } -int +int ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list) { dict_foreign_t* foreign; @@ -5931,7 +5931,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list) mutex_enter_noninline(&(dict_sys->mutex)); foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list); - while (foreign != NULL) + while (foreign != NULL) { uint i; FOREIGN_KEY_INFO f_key_info; @@ -5952,7 +5952,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list) f_key_info.referenced_db= make_lex_string(thd, 0, tmp_buff, i, 1); tmp_buff+= i + 1; - f_key_info.referenced_table= make_lex_string(thd, 0, tmp_buff, + f_key_info.referenced_table= make_lex_string(thd, 0, tmp_buff, (uint) strlen(tmp_buff), 1); for (i= 0;;) @@ -5972,7 +5972,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list) { length=17; tmp_buff= "ON DELETE CASCADE"; - } + } else if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) { length=18; @@ -6002,7 +6002,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list) f_key_info.constraint_method, tmp_buff, length, 1); - FOREIGN_KEY_INFO *pf_key_info= ((FOREIGN_KEY_INFO *) + FOREIGN_KEY_INFO *pf_key_info= ((FOREIGN_KEY_INFO *) thd->memdup((gptr) &f_key_info, sizeof(FOREIGN_KEY_INFO))); f_key_list->push_back(pf_key_info); @@ -6187,13 +6187,13 @@ ha_innobase::start_stmt( this same LOCK TABLES; since MySQL does NOT call external_lock in this case, we must use x-row locks inside InnoDB to be prepared for an update of a row */ - + prebuilt->select_lock_type = LOCK_X; } else { if (trx->isolation_level != TRX_ISO_SERIALIZABLE && thd->lex->sql_command == SQLCOM_SELECT && lock_type == TL_READ) { - + /* For other than temporary tables, we obtain no lock for consistent read (plain SELECT). */ @@ -6203,8 +6203,8 @@ ha_innobase::start_stmt( select_lock_type value. The value of stored_select_lock_type was decided in: 1) ::store_lock(), - 2) ::external_lock(), - 3) ::init_table_handle_for_HANDLER(), and + 2) ::external_lock(), + 3) ::init_table_handle_for_HANDLER(), and 4) :.transactional_table_lock(). */ prebuilt->select_lock_type = @@ -6254,9 +6254,9 @@ innobase_map_isolation_level( case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE); case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED); default: ut_a(0); return(0); - } + } } - + /********************************************************************** As MySQL will execute an external lock for every new table it uses when it starts to process an SQL statement (an exception is when MySQL calls @@ -6301,7 +6301,7 @@ ha_innobase::external_lock( /* MySQL is setting a new table lock */ trx->detailed_error[0] = '\0'; - + /* Set the MySQL flag to mark that there is an active transaction */ if (trx->active_trans == 0) { @@ -6342,7 +6342,7 @@ ha_innobase::external_lock( TABLES if AUTOCOMMIT=1. It does not make much sense to acquire an InnoDB table lock if it is released immediately at the end of LOCK TABLES, and InnoDB's table locks in that case cause - VERY easily deadlocks. + VERY easily deadlocks. We do not set InnoDB table locks if user has not explicitly requested a table lock. Note that thd->in_lock_tables @@ -6385,7 +6385,7 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked = 0; prebuilt->used_in_HANDLER = FALSE; - + /* Release a possible FIFO ticket and search latch. Since we may reserve the kernel mutex, we have to release the search system latch first to obey the latching order. */ @@ -6491,8 +6491,8 @@ ha_innobase::transactional_table_lock( if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - /* Store the current undo_no of the transaction - so that we know where to roll back if we have + /* Store the current undo_no of the transaction + so that we know where to roll back if we have to roll back the next SQL statement */ trx_mark_sql_stat_end(trx); @@ -6735,7 +6735,7 @@ static INNOBASE_SHARE *get_share(const char *table_name) INNOBASE_SHARE *share; pthread_mutex_lock(&innobase_share_mutex); uint length=(uint) strlen(table_name); - + if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables, (mysql_byte*) table_name, length))) { @@ -6751,17 +6751,17 @@ static INNOBASE_SHARE *get_share(const char *table_name) (mysql_byte*) share)) { pthread_mutex_unlock(&innobase_share_mutex); my_free((gptr) share,0); - + return 0; } - + thr_lock_init(&share->lock); pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); } - + share->use_count++; pthread_mutex_unlock(&innobase_share_mutex); - + return share; } @@ -6808,7 +6808,7 @@ ha_innobase::store_lock( Be careful to ignore TL_IGNORE if we are going to do something with only 'real' locks! */ - if ((lock_type == TL_READ && thd->in_lock_tables) || + if ((lock_type == TL_READ && thd->in_lock_tables) || (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || lock_type == TL_READ_WITH_SHARED_LOCKS || lock_type == TL_READ_NO_INSERT || @@ -6894,7 +6894,7 @@ ha_innobase::store_lock( } /* If we are not doing a LOCK TABLE, DISCARD/IMPORT - TABLESPACE or TRUNCATE TABLE then allow multiple + TABLESPACE or TRUNCATE TABLE then allow multiple writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ < TL_WRITE_CONCURRENT_INSERT. @@ -6903,7 +6903,7 @@ ha_innobase::store_lock( stored function call (MySQL does have thd->in_lock_tables TRUE there). */ - if ((lock_type >= TL_WRITE_CONCURRENT_INSERT + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && lock_type <= TL_WRITE) && !(thd->in_lock_tables && thd->lex->sql_command == SQLCOM_LOCK_TABLES) @@ -6919,19 +6919,19 @@ ha_innobase::store_lock( MySQL would use the lock TL_READ_NO_INSERT on t2, and that would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts to t2. Convert the lock to a normal read lock to allow - concurrent inserts to t2. + concurrent inserts to t2. - We especially allow concurrent inserts if MySQL is at the - start of a stored procedure call (SQLCOM_CALL) + We especially allow concurrent inserts if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) (MySQL does have thd->in_lock_tables TRUE there). */ - + if (lock_type == TL_READ_NO_INSERT && (!thd->in_lock_tables || thd->lex->sql_command == SQLCOM_CALL)) { lock_type = TL_READ; } - + lock.type = lock_type; } @@ -6963,7 +6963,7 @@ ha_innobase::innobase_read_and_init_auto_inc( ut_a(prebuilt->trx == (trx_t*) current_thd->ha_data[innobase_hton.slot]); ut_a(prebuilt->table); - + if (prebuilt->trx->conc_state == TRX_NOT_STARTED) { trx_was_not_started = TRUE; } @@ -6978,7 +6978,7 @@ ha_innobase::innobase_read_and_init_auto_inc( if (auto_inc != 0) { /* Already initialized */ *ret = auto_inc; - + error = 0; goto func_exit_early; @@ -6990,14 +6990,14 @@ ha_innobase::innobase_read_and_init_auto_inc( error = convert_error_code_to_mysql(error, user_thd); goto func_exit_early; - } + } /* Check again if someone has initialized the counter meanwhile */ auto_inc = dict_table_autoinc_read(prebuilt->table); if (auto_inc != 0) { *ret = auto_inc; - + error = 0; goto func_exit_early; @@ -7014,7 +7014,7 @@ ha_innobase::innobase_read_and_init_auto_inc( accept this flaw, since the deadlocks were a bigger trouble. */ /* Fetch all the columns in the key */ - + prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; old_select_lock_type = prebuilt->select_lock_type; @@ -7093,14 +7093,14 @@ ha_innobase::get_auto_increment() { longlong nr; int error; - + error = innobase_read_and_init_auto_inc(&nr); if (error) { /* This should never happen in the current (5.0.6) code, since we call this function only after the counter has been initialized. */ - + ut_print_timestamp(stderr); sql_print_error("Error %lu in ::get_auto_increment()", (ulong) error); @@ -7125,7 +7125,7 @@ ha_innobase::reset_auto_increment(ulonglong value) error = convert_error_code_to_mysql(error, user_thd); DBUG_RETURN(error); - } + } dict_table_autoinc_initialize(prebuilt->table, value); @@ -7190,7 +7190,7 @@ ha_innobase::cmp_ref( || mysql_type == FIELD_TYPE_MEDIUM_BLOB || mysql_type == FIELD_TYPE_BLOB || mysql_type == FIELD_TYPE_LONG_BLOB) { - + /* In the MySQL key value format, a column prefix of a BLOB is preceded by a 2-byte length field */ @@ -7296,7 +7296,7 @@ innobase_get_at_most_n_mbchars( str + data_len, (int) n_chars); if (char_length > data_len) { char_length = data_len; - } + } } else { if (data_len < prefix_len) { char_length = data_len; @@ -7311,15 +7311,15 @@ innobase_get_at_most_n_mbchars( extern "C" { /********************************************************************** -This function returns true if +This function returns true if 1) SQL-query in the current thread -is either REPLACE or LOAD DATA INFILE REPLACE. +is either REPLACE or LOAD DATA INFILE REPLACE. 2) SQL-query in the current thread is INSERT ON DUPLICATE KEY UPDATE. -NOTE that /mysql/innobase/row/row0ins.c must contain the +NOTE that /mysql/innobase/row/row0ins.c must contain the prototype for this function ! */ ibool @@ -7327,9 +7327,9 @@ innobase_query_is_update(void) /*==========================*/ { THD* thd; - + thd = (THD *)innobase_current_thd(); - + if (thd->lex->sql_command == SQLCOM_REPLACE || thd->lex->sql_command == SQLCOM_REPLACE_SELECT || (thd->lex->sql_command == SQLCOM_LOAD && @@ -7351,7 +7351,7 @@ innobase_query_is_update(void) /*********************************************************************** This function is used to prepare X/Open XA distributed transaction */ -int +int innobase_xa_prepare( /*================*/ /* out: 0 or error number */ @@ -7444,10 +7444,10 @@ innobase_xa_prepare( /*********************************************************************** This function is used to recover X/Open XA distributed transactions */ -int +int innobase_xa_recover( /*================*/ - /* out: number of prepared transactions + /* out: number of prepared transactions stored in xid_list */ XID* xid_list, /* in/out: prepared transactions */ uint len) /* in: number of slots in xid_list */ @@ -7464,7 +7464,7 @@ innobase_xa_recover( This function is used to commit one X/Open XA distributed transaction which is in the prepared state */ -int +int innobase_commit_by_xid( /*===================*/ /* out: 0 or error number */ @@ -7476,7 +7476,7 @@ innobase_commit_by_xid( if (trx) { innobase_commit_low(trx); - + return(XA_OK); } else { return(XAER_NOTA); @@ -7487,7 +7487,7 @@ innobase_commit_by_xid( This function is used to rollback one X/Open XA distributed transaction which is in the prepared state */ -int +int innobase_rollback_by_xid( /*=====================*/ /* out: 0 or error number */ @@ -7507,7 +7507,7 @@ innobase_rollback_by_xid( /*********************************************************************** Create a consistent view for a cursor based on current transaction which is created if the corresponding MySQL thread still lacks one. -This consistent view is then used inside of MySQL when accessing records +This consistent view is then used inside of MySQL when accessing records using a cursor. */ void* @@ -7521,7 +7521,7 @@ innobase_create_cursor_view(void) /*********************************************************************** Close the given consistent cursor view of a transaction and restore -global read view to a transaction read view. Transaction is created if the +global read view to a transaction read view. Transaction is created if the corresponding MySQL thread still lacks one. */ void @@ -7534,8 +7534,8 @@ innobase_close_cursor_view( } /*********************************************************************** -Set the given consistent cursor view to a transaction which is created -if the corresponding MySQL thread still lacks one. If the given +Set the given consistent cursor view to a transaction which is created +if the corresponding MySQL thread still lacks one. If the given consistent cursor view is NULL global read view of a transaction is restored to a transaction read view. */ @@ -7544,7 +7544,7 @@ innobase_set_cursor_view( /*=====================*/ void* curview)/* in: Consistent cursor view to be set */ { - read_cursor_set_for_mysql(check_trx_exists(current_thd), + read_cursor_set_for_mysql(check_trx_exists(current_thd), (cursor_view_t*) curview); } diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index fb93b2abb0e..7ab252f97dd 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -165,15 +165,15 @@ class ha_innobase: public handler int get_foreign_key_list(THD *thd, List *f_key_list); bool can_switch_engines(); uint referenced_by_foreign_key(); - void free_foreign_key_create_info(char* str); + void free_foreign_key_create_info(char* str); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); - void init_table_handle_for_HANDLER(); + void init_table_handle_for_HANDLER(); ulonglong get_auto_increment(); int reset_auto_increment(ulonglong value); virtual bool get_error_message(int error, String *buf); - + uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; } /* ask handler about permission to cache table during query registration @@ -280,7 +280,7 @@ This function is used to recover X/Open XA distributed transactions */ int innobase_xa_recover( /*====================*/ - /* out: number of prepared transactions + /* out: number of prepared transactions stored in xid_list */ XID* xid_list, /* in/out: prepared transactions */ uint len); /* in: number of slots in xid_list */ @@ -309,7 +309,7 @@ int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, /*********************************************************************** Create a consistent view for a cursor based on current transaction which is created if the corresponding MySQL thread still lacks one. -This consistent view is then used inside of MySQL when accessing records +This consistent view is then used inside of MySQL when accessing records using a cursor. */ void* @@ -319,7 +319,7 @@ innobase_create_cursor_view(void); /*********************************************************************** Close the given consistent cursor view of a transaction and restore -global read view to a transaction read view. Transaction is created if the +global read view to a transaction read view. Transaction is created if the corresponding MySQL thread still lacks one. */ void @@ -328,8 +328,8 @@ innobase_close_cursor_view( void* curview); /* in: Consistent read view to be closed */ /*********************************************************************** -Set the given consistent cursor view to a transaction which is created -if the corresponding MySQL thread still lacks one. If the given +Set the given consistent cursor view to a transaction which is created +if the corresponding MySQL thread still lacks one. If the given consistent cursor view is NULL global read view of a transaction is restored to a transaction read view. */ diff --git a/sql/handler.cc b/sql/handler.cc index 006a0eb2407..627117a65a5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -35,9 +35,9 @@ #include "ha_berkeley.h" extern handlerton berkeley_hton; #else -handlerton berkeley_hton = { "BerkeleyDB", SHOW_OPTION_NO, - "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB, NULL, - 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +handlerton berkeley_hton = { "BerkeleyDB", SHOW_OPTION_NO, + "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB, NULL, + 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_BLACKHOLE_DB @@ -46,8 +46,8 @@ extern handlerton blackhole_hton; #else handlerton blackhole_hton = { "BLACKHOLE", SHOW_OPTION_NO, "/dev/null storage engine (anything you write to it disappears)", - DB_TYPE_BLACKHOLE_DB, NULL, 0, 0, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + DB_TYPE_BLACKHOLE_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_EXAMPLE_DB @@ -55,9 +55,9 @@ handlerton blackhole_hton = { "BLACKHOLE", SHOW_OPTION_NO, extern handlerton example_hton; #else handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO, - "Example storage engine", - DB_TYPE_EXAMPLE_DB, NULL, 0, 0, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Example storage engine", + DB_TYPE_EXAMPLE_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #if defined(HAVE_ARCHIVE_DB) @@ -65,17 +65,17 @@ handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO, extern handlerton archive_hton; #else handlerton archive_hton = { "ARCHIVE", SHOW_OPTION_NO, - "Archive storage engine", DB_TYPE_ARCHIVE_DB, NULL, 0, 0, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Archive storage engine", DB_TYPE_ARCHIVE_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_CSV_DB #include "examples/ha_tina.h" extern handlerton tina_hton; #else -handlerton tina_hton = { "CSV", SHOW_OPTION_NO, "CSV storage engine", - DB_TYPE_CSV_DB, NULL, 0, 0, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +handlerton tina_hton = { "CSV", SHOW_OPTION_NO, "CSV storage engine", + DB_TYPE_CSV_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_INNOBASE_DB @@ -83,9 +83,9 @@ handlerton tina_hton = { "CSV", SHOW_OPTION_NO, "CSV storage engine", extern handlerton innobase_hton; #else handlerton innobase_hton = { "InnoDB", SHOW_OPTION_NO, - "Supports transactions, row-level locking, and foreign keys", - DB_TYPE_INNODB, NULL, 0, 0, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Supports transactions, row-level locking, and foreign keys", + DB_TYPE_INNODB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_NDBCLUSTER_DB @@ -93,18 +93,18 @@ handlerton innobase_hton = { "InnoDB", SHOW_OPTION_NO, extern handlerton ndbcluster_hton; #else handlerton ndbcluster_hton = { "ndbcluster", SHOW_OPTION_NO, - "Clustered, fault-tolerant, memory-based tables", - DB_TYPE_NDBCLUSTER, NULL, 0, 0, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Clustered, fault-tolerant, memory-based tables", + DB_TYPE_NDBCLUSTER, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_FEDERATED_DB #include "ha_federated.h" extern handlerton federated_hton; #else -handlerton federated_hton = { "FEDERATED", SHOW_OPTION_NO, - "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB, NULL, 0, 0, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +handlerton federated_hton = { "FEDERATED", SHOW_OPTION_NO, + "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB, NULL, 0, 0, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif #include @@ -118,8 +118,8 @@ extern handlerton binlog_hton; /* Obsolete */ -handlerton isam_hton = { "ISAM", SHOW_OPTION_NO, "Obsolete storage engine", - DB_TYPE_ISAM, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +handlerton isam_hton = { "ISAM", SHOW_OPTION_NO, "Obsolete storage engine", + DB_TYPE_ISAM, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; @@ -283,7 +283,7 @@ enum db_type ha_checktype(THD *thd, enum db_type database_type, default: break; } - + return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ? (enum db_type) thd->variables.table_type : ((enum db_type) global_system_variables.table_type != @@ -481,7 +481,7 @@ int ha_init() for (types= sys_table_types; *types; types++) { if (!(*types)->init || !(*types)->init()) - ha_was_inited_ok(types); + ha_was_inited_ok(types); else (*types)->state= SHOW_OPTION_DISABLED; } @@ -1144,7 +1144,7 @@ int ha_release_temporary_latches(THD *thd) } -/* +/* Export statistics for different engines. Currently we use it only for InnoDB. */ @@ -1480,7 +1480,7 @@ next_insert_id(ulonglong nr,struct system_variables *variables) RETURN 0 ok 1 get_auto_increment() was called and returned ~(ulonglong) 0 - + IMPLEMENTATION @@ -2323,8 +2323,8 @@ int ha_discover(THD *thd, const char *db, const char *name, /* - Call this function in order to give the handler the possiblity - to ask engine if there are any new tables that should be written to disk + Call this function in order to give the handler the possiblity + to ask engine if there are any new tables that should be written to disk or any dropped tables that need to be removed from disk */ @@ -2334,7 +2334,7 @@ ha_find_files(THD *thd,const char *db,const char *path, { int error= 0; DBUG_ENTER("ha_find_files"); - DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d", + DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d", db, path, wild, dir)); #ifdef HAVE_NDBCLUSTER_DB if (have_ndbcluster == SHOW_OPTION_YES) @@ -2500,7 +2500,7 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) read_range_first() start_key Start key. Is 0 if no min range end_key End key. Is 0 if no max range - eq_range_arg Set to 1 if start_key == end_key + eq_range_arg Set to 1 if start_key == end_key sorted Set to 1 if result should be sorted per key NOTES @@ -2538,7 +2538,7 @@ int handler::read_range_first(const key_range *start_key, start_key->length, start_key->flag); if (result) - DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND) ? HA_ERR_END_OF_FILE : result); @@ -2586,7 +2586,7 @@ int handler::read_range_next() SYNOPSIS compare_key range range to compare to row. May be 0 for no range - + NOTES See key.cc::key_cmp() for details @@ -2626,7 +2626,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key, SYNOPSIS ha_known_exts() - + NOTES No mutexes, worst case race is a minor surplus memory allocation We have to recreate the extension map if mysqld is restarted (for example @@ -2673,7 +2673,7 @@ TYPELIB *ha_known_exts(void) ext= (const char **) my_once_alloc(sizeof(char *)* (found_exts.elements+1), MYF(MY_WME | MY_FAE)); - + DBUG_ASSERT(ext != 0); known_extensions.count= found_exts.elements; known_extensions.type_names= ext; @@ -2702,7 +2702,7 @@ TYPELIB *ha_known_exts(void) Only works for InnoDB at the moment RETURN VALUE - Always 0 (= success) + Always 0 (= success) */ int ha_repl_report_sent_binlog(THD *thd, char *log_file_name, @@ -2727,7 +2727,7 @@ int ha_repl_report_sent_binlog(THD *thd, char *log_file_name, Does nothing at the moment RETURN VALUE - Always 0 (= success) + Always 0 (= success) PARAMETERS */ diff --git a/sql/handler.h b/sql/handler.h index 977bd77a54e..8270849348a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -106,7 +106,7 @@ Index scan will not return records in rowid order. Not guaranteed to be set for unordered (e.g. HASH) indexes. */ -#define HA_KEY_SCAN_NOT_ROR 128 +#define HA_KEY_SCAN_NOT_ROR 128 /* operations for disable/enable indexes */ @@ -231,7 +231,7 @@ struct xid_t { long bqual_length; char data[XIDDATASIZE]; // not \0-terminated ! - xid_t() {} /* Remove gcc warning */ + xid_t() {} /* Remove gcc warning */ bool eq(struct xid_t *xid) { return eq(xid->gtrid_length, xid->bqual_length, xid->data); } bool eq(long g, long b, const char *d) @@ -319,7 +319,7 @@ typedef struct const char *name; /* - Historical marker for if the engine is available of not + Historical marker for if the engine is available of not */ SHOW_COMP_OPTION state; @@ -333,7 +333,7 @@ typedef struct This is going away and new engines will just use "name" for this. */ enum db_type db_type; - /* + /* Method that initizlizes a storage engine */ bool (*init)(); @@ -573,7 +573,7 @@ public: virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; } virtual bool has_transactions(){ return 0;} virtual uint extra_rec_buf_length() { return 0; } - + /* Return upper bound of current number of records in the table (max. of how many records one will retrieve when doing a full table scan) @@ -726,7 +726,7 @@ public: int check_old_types(); /* to be actually called to get 'check()' functionality*/ int ha_check(THD *thd, HA_CHECK_OPT *check_opt); - + virtual int backup(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } /* @@ -815,7 +815,7 @@ public: */ virtual int rename_table(const char *from, const char *to); virtual int delete_table(const char *name); - + virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; /* lock_count() can be more than one if the table is a MERGE */ @@ -829,7 +829,7 @@ public: /* ask handler about permission to cache table when query is to be cached */ virtual my_bool register_query_cache_table(THD *thd, char *table_key, uint key_length, - qc_engine_callback + qc_engine_callback *engine_callback, ulonglong *engine_data) { @@ -847,7 +847,7 @@ public: { return memcmp(ref1, ref2, ref_length); } - + /* Condition pushdown to storage engines */ @@ -856,7 +856,7 @@ public: Push condition down to the table handler. SYNOPSIS cond_push() - cond Condition to be pushed. The condition tree must not be + cond Condition to be pushed. The condition tree must not be modified by the by the caller. RETURN The 'remainder' condition that caller must use to filter out records. @@ -865,14 +865,14 @@ public: NOTES The pushed conditions form a stack (from which one can remove the last pushed condition using cond_pop). - The table handler filters out rows using (pushed_cond1 AND pushed_cond2 + The table handler filters out rows using (pushed_cond1 AND pushed_cond2 AND ... AND pushed_condN) or less restrictive condition, depending on handler's capabilities. - + handler->extra(HA_EXTRA_RESET) call empties the condition stack. Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the condition stack. - */ + */ virtual const COND *cond_push(const COND *cond) { return cond; }; /* Pop the top condition from the condition stack of the handler instance. diff --git a/sql/mysqld.cc b/sql/mysqld.cc index eed43f91d36..2690b2f6852 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -165,7 +165,7 @@ static void registerwithneb(); static void getvolumename(); static void getvolumeID(BYTE *volumeName); #endif /* __NETWARE__ */ - + #ifdef _AIX41 int initgroups(const char *,unsigned int); @@ -960,18 +960,18 @@ static void __cdecl kill_server(int sig_ptr) else sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */ -#if defined(HAVE_SMEM) && defined(__WIN__) - /* - Send event to smem_event_connect_request for aborting - */ - if (!SetEvent(smem_event_connect_request)) - { +#if defined(HAVE_SMEM) && defined(__WIN__) + /* + Send event to smem_event_connect_request for aborting + */ + if (!SetEvent(smem_event_connect_request)) + { DBUG_PRINT("error", ("Got error: %ld from SetEvent of smem_event_connect_request", - GetLastError())); + GetLastError())); } -#endif - +#endif + #if defined(__NETWARE__) || (defined(USE_ONE_SIGNAL_HAND) && !defined(__WIN__) && !defined(OS2)) my_thread_init(); // If this is a new thread #endif @@ -1453,7 +1453,7 @@ static void network_init(void) if (Service.IsNT() && mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe) { - + pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */ strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\", mysqld_unix_port, NullS); @@ -1804,7 +1804,7 @@ static void registerwithneb() { ConsumerRegistrationInfo reg_info; - + /* Clear NEB registration structure */ bzero((char*) ®_info, sizeof(struct ConsumerRegistrationInfo)); @@ -1820,7 +1820,7 @@ static void registerwithneb() reg_info.CRIOwnerID= (LoadDefinitionStructure *)getnlmhandle(); reg_info.CRIConsumerESR= NULL; // No consumer ESR required reg_info.CRISecurityToken= 0; // No security token for the event - reg_info.CRIConsumerFlags= 0; // SMP_ENABLED_BIT; + reg_info.CRIConsumerFlags= 0; // SMP_ENABLED_BIT; reg_info.CRIFilterName= 0; // No event filtering reg_info.CRIFilterDataLength= 0; // No filtering data reg_info.CRIFilterData= 0; // No filtering data @@ -1845,7 +1845,7 @@ static void registerwithneb() Get the NSS volume ID of the MySQL Data volume. Volume ID is stored in a global variable */ - getvolumeID((BYTE*) datavolname); + getvolumeID((BYTE*) datavolname); } @@ -1910,7 +1910,7 @@ static void getvolumeID(BYTE *volumeName) strxmov(path, (const char *) ADMIN_VOL_PATH, (const char *) volumeName, NullS); - if ((status= zOpen(rootKey, zNSS_TASK, zNSPACE_LONG|zMODE_UTF8, + if ((status= zOpen(rootKey, zNSS_TASK, zNSPACE_LONG|zMODE_UTF8, (BYTE *) path, zRR_READ_ACCESS, &fileKey)) != zOK) { consoleprintf("\nGetNSSVolumeProperties - Failed to get file, status: %d\n.", (int) status); @@ -1918,7 +1918,7 @@ static void getvolumeID(BYTE *volumeName) } getInfoMask= zGET_IDS | zGET_VOLUME_INFO ; - if ((status= zGetInfo(fileKey, getInfoMask, sizeof(info), + if ((status= zGetInfo(fileKey, getInfoMask, sizeof(info), zINFO_VERSION_A, &info)) != zOK) { consoleprintf("\nGetNSSVolumeProperties - Failed in zGetInfo, status: %d\n.", (int) status); @@ -2041,7 +2041,7 @@ or misconfigured. This error can also be caused by malfunctioning hardware.\n", We will try our best to scrape up some info that will hopefully help diagnose\n\ the problem, but since we have already crashed, something is definitely wrong\n\ and this may fail.\n\n"); - fprintf(stderr, "key_buffer_size=%lu\n", + fprintf(stderr, "key_buffer_size=%lu\n", (ulong) dflt_key_cache->key_cache_mem_size); fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size); fprintf(stderr, "max_used_connections=%lu\n", max_used_connections); @@ -2385,7 +2385,7 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) thd->spcont->find_handler(error, MYSQL_ERROR::WARN_LEVEL_ERROR)) { if (! thd->spcont->found_handler_here()) - thd->net.report_error= 1; /* Make "select" abort correctly */ + thd->net.report_error= 1; /* Make "select" abort correctly */ DBUG_RETURN(0); } @@ -2588,13 +2588,13 @@ static int init_common_variables(const char *conf_file_name, int argc, } #endif /* - We set SYSTEM time zone as reasonable default and + We set SYSTEM time zone as reasonable default and also for failure of my_tz_init() and bootstrap mode. If user explicitly set time zone with --default-time-zone option we will change this value in my_tz_init(). */ global_system_variables.time_zone= my_tz_SYSTEM; - + /* Init mutexes for the global MYSQL_LOG objects. As safe_mutex depends on what MY_INIT() does, we can't init the mutexes of @@ -2604,7 +2604,7 @@ static int init_common_variables(const char *conf_file_name, int argc, mysql_log.init_pthread_objects(); mysql_slow_log.init_pthread_objects(); mysql_bin_log.init_pthread_objects(); - + if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0) strmov(glob_hostname,"mysql"); strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5); @@ -2699,7 +2699,7 @@ static int init_common_variables(const char *conf_file_name, int argc, global_system_variables.character_set_client= default_charset_info; global_system_variables.collation_connection= default_charset_info; - if (!(character_set_filesystem= + if (!(character_set_filesystem= get_charset_by_csname(character_set_filesystem_name, MY_CS_PRIMARY, MYF(MY_WME)))) return 1; @@ -2798,7 +2798,7 @@ static int init_thread_environment() openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(openssl_lock_t)); for (int i= 0; i < CRYPTO_num_locks(); ++i) - (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL); + (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL); CRYPTO_set_dynlock_create_callback(openssl_dynlock_create); CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy); CRYPTO_set_dynlock_lock_callback(openssl_lock); @@ -2839,20 +2839,20 @@ static int init_thread_environment() #if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) static unsigned long openssl_id_function() -{ +{ return (unsigned long) pthread_self(); -} +} static openssl_lock_t *openssl_dynlock_create(const char *file, int line) -{ +{ openssl_lock_t *lock= new openssl_lock_t; my_rwlock_init(&lock->lock, NULL); return lock; } -static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file, +static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file, int line) { rwlock_destroy(&lock->lock); @@ -2872,7 +2872,7 @@ static void openssl_lock_function(int mode, int n, const char *file, int line) } -static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, +static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, int line) { int err; @@ -2897,7 +2897,7 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, sql_print_error("Fatal: OpenSSL interface problem (mode=0x%x)", mode); abort(); } - if (err) + if (err) { sql_print_error("Fatal: can't %s OpenSSL %s lock", what); abort(); @@ -3204,7 +3204,7 @@ static void create_shutdown_thread() if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0)) sql_print_warning("Can't create thread to handle shutdown requests"); #endif -#endif // EMBEDDED_LIBRARY +#endif // EMBEDDED_LIBRARY } @@ -3259,7 +3259,7 @@ static void handle_connections_methods() handler_count--; } } -#endif +#endif while (handler_count > 0) pthread_cond_wait(&COND_handler_count,&LOCK_thread_count); @@ -3353,7 +3353,7 @@ int main(int argc, char **argv) #endif #ifdef __NETWARE__ /* Increasing stacksize of threads on NetWare */ - + pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE); #endif @@ -3445,7 +3445,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); #ifndef __NETWARE__ (void) pthread_kill(signal_thread, MYSQL_KILL_SIGNAL); #endif /* __NETWARE__ */ - + if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(MY_WME)); // Not needed anymore @@ -3513,7 +3513,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); #endif /* __NT__ */ /* (void) pthread_attr_destroy(&connection_attrib); */ - + DBUG_PRINT("quit",("Exiting main thread")); #ifndef __WIN__ @@ -3549,7 +3549,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); wait_for_signal_thread_to_end(); clean_up_mutexes(); my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); - + exit(0); return(0); /* purecov: deadcode */ } @@ -3993,7 +3993,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) size_socket length=sizeof(struct sockaddr_in); new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr), &length); -#ifdef __NETWARE__ +#ifdef __NETWARE__ // TODO: temporary fix, waiting for TCP/IP fix - DEFECT000303149 if ((new_sock == INVALID_SOCKET) && (socket_errno == EINVAL)) { @@ -4397,7 +4397,7 @@ errorconn: NullS); sql_perror(buff); } - if (handle_client_file_map) + if (handle_client_file_map) CloseHandle(handle_client_file_map); if (handle_client_map) UnmapViewOfFile(handle_client_map); @@ -4442,8 +4442,8 @@ error: enum options_mysqld { - OPT_ISAM_LOG=256, OPT_SKIP_NEW, - OPT_SKIP_GRANT, OPT_SKIP_LOCK, + OPT_ISAM_LOG=256, OPT_SKIP_NEW, + OPT_SKIP_GRANT, OPT_SKIP_LOCK, OPT_ENABLE_LOCK, OPT_USE_LOCKING, OPT_SOCKET, OPT_UPDATE_LOG, OPT_BIN_LOG, OPT_SKIP_RESOLVE, @@ -4622,7 +4622,7 @@ enum options_mysqld struct my_option my_long_options[] = { - {"help", '?', "Display this help and exit.", + {"help", '?', "Display this help and exit.", (gptr*) &opt_help, (gptr*) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION @@ -4957,7 +4957,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, (gptr*) &myisam_log_filename, (gptr*) &myisam_log_filename, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-long-format", '0', - "Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.", + "Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES, "Log queries that are executed without benefit of any index to the slow log if it is open.", @@ -5353,7 +5353,7 @@ log and this option does nothing anymore.", 0, 0, 0, 0, 0}, {"timed_mutexes", OPT_TIMED_MUTEXES, "Specify whether to time mutexes (only InnoDB mutexes are currently supported)", - (gptr*) &timed_mutexes, (gptr*) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0, + (gptr*) &timed_mutexes, (gptr*) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Path for temporary files. Several paths may be specified, separated by a " @@ -5588,7 +5588,7 @@ log and this option does nothing anymore.", "This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache", (gptr*) &dflt_key_cache_var.param_age_threshold, (gptr*) 0, - 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, + 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, 300, 100, ~0L, 0, 100, 0}, {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "The default size of key cache blocks", @@ -6003,7 +6003,7 @@ struct show_var_st status_vars[]= { {"Com_drop_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_INDEX]), SHOW_LONG_STATUS}, {"Com_drop_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_TABLE]), SHOW_LONG_STATUS}, {"Com_drop_user", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_USER]), SHOW_LONG_STATUS}, - {"Com_execute_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_EXECUTE]), SHOW_LONG_STATUS}, + {"Com_execute_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_EXECUTE]), SHOW_LONG_STATUS}, {"Com_flush", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_FLUSH]), SHOW_LONG_STATUS}, {"Com_grant", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_GRANT]), SHOW_LONG_STATUS}, {"Com_ha_close", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_CLOSE]), SHOW_LONG_STATUS}, @@ -6356,7 +6356,7 @@ static void mysql_init_variables(void) master_password= master_host= 0; master_info_file= (char*) "master.info", relay_log_info_file= (char*) "relay-log.info"; - master_ssl_key= master_ssl_cert= master_ssl_ca= + master_ssl_key= master_ssl_cert= master_ssl_ca= master_ssl_capath= master_ssl_cipher= 0; report_user= report_password = report_host= 0; /* TO BE DELETED */ opt_relay_logname= opt_relaylog_index_name= 0; @@ -6377,7 +6377,7 @@ static void mysql_init_variables(void) global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; - + /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal when collecting index statistics for MyISAM tables. @@ -7006,7 +7006,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), exit(1); } switch (method-1) { - case 0: + case 0: method_conv= MI_STATS_METHOD_NULLS_EQUAL; break; case 1: @@ -7420,7 +7420,7 @@ static void create_pid_file() (void) my_close(file, MYF(0)); } sql_perror("Can't start server: can't create PID file"); - exit(1); + exit(1); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 47a4b26f010..762b8d7ec60 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -205,7 +205,7 @@ sys_var_bool_ptr sys_local_infile("local_infile", sys_var_trust_routine_creators sys_trust_routine_creators("log_bin_trust_routine_creators", &trust_function_creators); -sys_var_bool_ptr +sys_var_bool_ptr sys_trust_function_creators("log_bin_trust_function_creators", &trust_function_creators); sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings); @@ -742,7 +742,7 @@ sys_var *sys_variables[]= &sys_innodb_thread_concurrency, &sys_innodb_commit_concurrency, &sys_innodb_flush_log_at_trx_commit, -#endif +#endif &sys_trust_routine_creators, &sys_trust_function_creators, &sys_engine_condition_pushdown, @@ -803,7 +803,7 @@ struct show_var_st init_vars[]= { {sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS}, {sys_delayed_queue_size.name,(char*) &sys_delayed_queue_size, SHOW_SYS}, {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, - {sys_engine_condition_pushdown.name, + {sys_engine_condition_pushdown.name, (char*) &sys_engine_condition_pushdown, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, @@ -931,9 +931,9 @@ struct show_var_st init_vars[]= { {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, - + {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS}, - + #ifdef __NT__ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL}, #endif @@ -1204,7 +1204,7 @@ static void fix_tx_isolation(THD *thd, enum_var_type type) thd->variables.tx_isolation); } -static void fix_completion_type(THD *thd __attribute__(unused), +static void fix_completion_type(THD *thd __attribute__(unused), enum_var_type type __attribute__(unused)) {} static int check_completion_type(THD *thd, set_var *var) @@ -1272,7 +1272,7 @@ static void fix_query_cache_size(THD *thd, enum_var_type type) #ifdef HAVE_QUERY_CACHE static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type) { - query_cache_min_res_unit= + query_cache_min_res_unit= query_cache.set_min_res_unit(query_cache_min_res_unit); } #endif @@ -1336,7 +1336,7 @@ static int check_max_delayed_threads(THD *thd, set_var *var) static void fix_max_connections(THD *thd, enum_var_type type) { #ifndef EMBEDDED_LIBRARY - resize_thr_alarm(max_connections + + resize_thr_alarm(max_connections + global_system_variables.max_insert_delayed_threads + 10); #endif } @@ -1514,7 +1514,7 @@ bool sys_var_thd_ha_rows::update(THD *thd, set_var *var) if (var->type == OPT_GLOBAL) { /* Lock is needed to make things safe on 32 bit systems */ - pthread_mutex_lock(&LOCK_global_system_variables); + pthread_mutex_lock(&LOCK_global_system_variables); global_system_variables.*offset= (ha_rows) tmp; pthread_mutex_unlock(&LOCK_global_system_variables); } @@ -1888,7 +1888,7 @@ bool sys_var_thd_date_time_format::check(THD *thd, set_var *var) my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, res->c_ptr()); return 1; } - + /* We must copy result to thread space to not get a memory leak if update is aborted @@ -1945,7 +1945,7 @@ typedef struct old_names_map_st const char *new_name; } my_old_conv; -static my_old_conv old_conv[]= +static my_old_conv old_conv[]= { { "cp1251_koi8" , "cp1251" }, { "cp1250_latin2" , "cp1250" }, @@ -1963,7 +1963,7 @@ static my_old_conv old_conv[]= CHARSET_INFO *get_old_charset_by_name(const char *name) { my_old_conv *conv; - + for (conv= old_conv; conv->old_name; conv++) { if (!my_strcasecmp(&my_charset_latin1, name, conv->old_name)) @@ -2344,7 +2344,7 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) pthread_mutex_lock(&LOCK_global_system_variables); key_cache= get_key_cache(base_name); - + if (!key_cache) { /* Key cache didn't exists */ @@ -2381,7 +2381,7 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) Move tables using this key cache to the default key cache and clear the old key cache. */ - NAMED_LIST *list; + NAMED_LIST *list; key_cache= (KEY_CACHE *) find_named(&key_caches, base_name->str, base_name->length, &list); key_cache->in_init= 1; @@ -2410,7 +2410,7 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) error= (bool)(ha_resize_key_cache(key_cache)); pthread_mutex_lock(&LOCK_global_system_variables); - key_cache->in_init= 0; + key_cache->in_init= 0; end: pthread_mutex_unlock(&LOCK_global_system_variables); @@ -2459,7 +2459,7 @@ bool sys_var_key_cache_long::update(THD *thd, set_var *var) error= (bool) (ha_resize_key_cache(key_cache)); pthread_mutex_lock(&LOCK_global_system_variables); - key_cache->in_init= 0; + key_cache->in_init= 0; end: pthread_mutex_unlock(&LOCK_global_system_variables); @@ -2632,7 +2632,7 @@ bool sys_var_thd_time_zone::update(THD *thd, set_var *var) byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { - /* + /* We can use ptr() instead of c_ptr() here because String contaning time zone name is guaranteed to be zero ended. */ @@ -2786,7 +2786,7 @@ static bool set_log_update(THD *thd, set_var *var) See sql/mysqld.cc/, comments in function init_server_components() for an explaination of the different warnings we send below */ - + if (opt_sql_bin_update) { ((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG | @@ -2838,7 +2838,7 @@ static byte *get_warning_count(THD *thd) static byte *get_error_count(THD *thd) { - thd->sys_var_tmp.long_value= + thd->sys_var_tmp.long_value= thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR]; return (byte*) &thd->sys_var_tmp.long_value; } @@ -2878,7 +2878,7 @@ static byte *get_prepared_stmt_count(THD *thd) ptr pointer to option structure */ -static struct my_option *find_option(struct my_option *opt, const char *name) +static struct my_option *find_option(struct my_option *opt, const char *name) { uint length=strlen(name); for (; opt->name; opt++) @@ -3286,7 +3286,7 @@ void sys_var_thd_table_type::warn_deprecated(THD *thd) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), "table_type", - "storage_engine"); + "storage_engine"); } void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type) @@ -3385,7 +3385,7 @@ void fix_sql_mode_var(THD *thd, enum_var_type type) ulong fix_sql_mode(ulong sql_mode) { /* - Note that we dont set + Note that we dont set MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS to allow one to get full use of MySQL in this mode. */ @@ -3394,7 +3394,7 @@ ulong fix_sql_mode(ulong sql_mode) { sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE); - /* + /* MODE_ONLY_FULL_GROUP_BY removed from ANSI mode because it is currently overly restrictive (see BUG#8510). */ @@ -3479,7 +3479,7 @@ static KEY_CACHE *create_key_cache(const char *name, uint length) KEY_CACHE *key_cache; DBUG_ENTER("create_key_cache"); DBUG_PRINT("enter",("name: %.*s", length, name)); - + if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE), MYF(MY_ZEROFILL | MY_WME)))) { @@ -3546,7 +3546,7 @@ void sys_var_trust_routine_creators::warn_deprecated(THD *thd) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), "log_bin_trust_routine_creators", - "log_bin_trust_function_creators"); + "log_bin_trust_function_creators"); } void sys_var_trust_routine_creators::set_default(THD *thd, enum_var_type type) diff --git a/sql/sql_class.h b/sql/sql_class.h index 7c74ff6fa93..ed116a16f4f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -755,7 +755,7 @@ class Server_side_cursor; - prepared, that is, contain placeholders, - opened as cursors. We maintain 1 to 1 relationship between statement and cursor - if user wants to create another cursor for his - query, we create another statement for it. + query, we create another statement for it. To perform some action with statement we reset THD part to the state of that statement, do the action, and then save back modified state from THD to the statement. It will be changed in near future, and Statement will @@ -778,7 +778,7 @@ public: ulong id; /* - - if set_query_id=1, we set field->query_id for all fields. In that case + - if set_query_id=1, we set field->query_id for all fields. In that case field list can not contain duplicates. */ bool set_query_id; @@ -803,7 +803,7 @@ public: it. We will see the query_length field as either 0, or the right value for it. Assuming that the write and read of an n-bit memory field in an n-bit - computer is atomic, we can avoid races in the above way. + computer is atomic, we can avoid races in the above way. This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB STATUS. */ @@ -1152,7 +1152,7 @@ public: /* One thread can hold up to one named user-level lock. This variable points to a lock object if the lock is present. See item_func.cc and - chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK. + chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK. */ User_level_lock *ull; #ifndef DBUG_OFF @@ -1355,10 +1355,10 @@ public: long long_value; ulong ulong_value; } sys_var_tmp; - + struct { - /* - If true, mysql_bin_log::write(Log_event) call will not write events to + /* + If true, mysql_bin_log::write(Log_event) call will not write events to binlog, and maintain 2 below variables instead (use mysql_bin_log.start_union_events to turn this on) */ @@ -1369,19 +1369,19 @@ public: */ bool unioned_events; /* - If TRUE, at least one mysql_bin_log::write(Log_event e), where - e.cache_stmt == TRUE call has been made after last + If TRUE, at least one mysql_bin_log::write(Log_event e), where + e.cache_stmt == TRUE call has been made after last mysql_bin_log.start_union_events() call. */ bool unioned_events_trans; - - /* + + /* 'queries' (actually SP statements) that run under inside this binlog union have thd->query_id >= first_query_id. */ query_id_t first_query_id; } binlog_evt_union; - + THD(); ~THD(); @@ -1393,7 +1393,7 @@ public: killing mysqld) where it's vital to not allocate excessive and not used memory. Note, that we still don't return error from init_for_queries(): if preallocation fails, we should notice that at the first call to - alloc_root. + alloc_root. */ void init_for_queries(); void change_user(void); @@ -1589,7 +1589,7 @@ public: #define SYSTEM_THREAD_SLAVE_SQL 4 /* - Used to hold information about file and file structure in exchainge + Used to hold information about file and file structure in exchainge via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) XXX: We never call destructor for objects of this class. */ @@ -1771,8 +1771,8 @@ public: #include -/* - Param to create temporary tables when doing SELECT:s +/* + Param to create temporary tables when doing SELECT:s NOTE This structure is copied using memcpy as a part of JOIN. */ @@ -1800,8 +1800,8 @@ public: uint quick_group; bool using_indirect_summary_function; /* If >0 convert all blob fields to varchar(convert_blob_length) */ - uint convert_blob_length; - CHARSET_INFO *table_charset; + uint convert_blob_length; + CHARSET_INFO *table_charset; bool schema_table; /* True if GROUP BY and its aggregate functions are already computed @@ -1932,12 +1932,12 @@ class Table_ident :public Sql_alloc else db= db_arg; } - inline Table_ident(LEX_STRING table_arg) + inline Table_ident(LEX_STRING table_arg) :table(table_arg), sel((SELECT_LEX_UNIT *)0) { db.str=0; } - inline Table_ident(SELECT_LEX_UNIT *s) : sel(s) + inline Table_ident(SELECT_LEX_UNIT *s) : sel(s) { /* We must have a table name here as this is used with add_table_to_list */ db.str=0; table.str= internal_table_name; table.length=1; @@ -1967,7 +1967,7 @@ class user_var_entry }; /* - Unique -- class for unique (removing of duplicates). + Unique -- class for unique (removing of duplicates). Puts all values to the TREE. If the tree becomes too big, it's dumped to the file. User can request sorted values, or just iterate through them. In the last case tree merging is performed in @@ -2000,12 +2000,12 @@ public: } bool get(TABLE *table); - static double get_use_cost(uint *buffer, uint nkeys, uint key_size, + static double get_use_cost(uint *buffer, uint nkeys, uint key_size, ulong max_in_memory_size); - inline static int get_cost_calc_buff_size(ulong nkeys, uint key_size, + inline static int get_cost_calc_buff_size(ulong nkeys, uint key_size, ulong max_in_memory_size) { - register ulong max_elems_in_tree= + register ulong max_elems_in_tree= (1 + max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size)); return sizeof(uint)*(1 + nkeys/max_elems_in_tree); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 85d93767486..76e458783c4 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -705,7 +705,7 @@ impossible position"; if (loop_breaker) break; - + end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); @@ -854,7 +854,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) /* Issuing warning then started without --skip-slave-start */ if (!opt_skip_slave_start) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_MISSING_SKIP_SLAVE, + ER_MISSING_SKIP_SLAVE, ER(ER_MISSING_SKIP_SLAVE)); } @@ -880,7 +880,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING, ER(ER_SLAVE_WAS_RUNNING)); } - + unlock_slave_threads(mi); if (slave_errno) @@ -1040,7 +1040,7 @@ err: slave_server_id the slave's server id */ - + void kill_zombie_dump_threads(uint32 slave_server_id) { @@ -1105,9 +1105,9 @@ bool change_master(THD* thd, MASTER_INFO* mi) */ /* - If the user specified host or port without binlog or position, + If the user specified host or port without binlog or position, reset binlog's name to FIRST and position to 4. - */ + */ if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos) { @@ -1134,7 +1134,7 @@ 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->ssl != LEX_MASTER_INFO::SSL_UNCHANGED) mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE); if (lex_mi->ssl_ca) @@ -1150,7 +1150,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) #ifndef HAVE_OPENSSL if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath || lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS)); #endif @@ -1510,7 +1510,7 @@ bool show_binlogs(THD* thd) } field_list.push_back(new Item_empty_string("Log_name", 255)); - field_list.push_back(new Item_return_int("File_size", 20, + field_list.push_back(new Item_return_int("File_size", 20, MYSQL_TYPE_LONGLONG)); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) From 365f6f6f03a247976eabd64fe9d8510b456647f4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 17:22:56 +0930 Subject: [PATCH 055/101] foo2 sql/ha_innodb.cc: Import patch foo2 sql/ha_innodb.h: Import patch foo2 sql/handler.cc: Import patch foo2 sql/handler.h: Import patch foo2 sql/mysqld.cc: Import patch foo2 sql/set_var.cc: Import patch foo2 sql/sql_class.h: Import patch foo2 sql/sql_repl.cc: Import patch foo2 --- sql/ha_innodb.cc | 231 +---------------------------------------------- sql/ha_innodb.h | 3 - sql/handler.cc | 53 ----------- sql/handler.h | 5 - sql/mysqld.cc | 17 ---- sql/set_var.cc | 25 ----- sql/sql_class.h | 6 +- sql/sql_repl.cc | 21 ----- 8 files changed, 2 insertions(+), 359 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 98fb6b69ab3..934437e0c91 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1741,25 +1741,6 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; -#ifdef HAVE_REPLICATION - if (thd->variables.sync_replication) { - /* 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. */ - - if (trx->repl_wait_binlog_name == NULL) { - - trx->repl_wait_binlog_name = - (char*)mem_alloc_noninline(FN_REFLEN + 100); - } - - ut_a(strlen(log_file_name) < FN_REFLEN + 100); - - strcpy(trx->repl_wait_binlog_name, log_file_name); - - trx->repl_wait_binlog_pos = (ib_longlong)end_offset; - } -#endif /* HAVE_REPLICATION */ trx->flush_log_later = TRUE; innobase_commit(thd, TRUE); @@ -1828,219 +1809,9 @@ innobase_commit_complete( trx_commit_complete_for_mysql(trx); } -#ifdef HAVE_REPLICATION - if (thd->variables.sync_replication - && trx->repl_wait_binlog_name - && innobase_repl_state != 0) { - - struct timespec abstime; - int cmp; - int ret; - - /* In synchronous replication, let us wait until the MySQL - replication has sent the relevant binlog segment to the - replication slave. */ - - pthread_mutex_lock(&innobase_repl_cond_mutex); -try_again: - if (innobase_repl_state == 0) { - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - return(0); - } - - cmp = strcmp(innobase_repl_file_name, - trx->repl_wait_binlog_name); - if (cmp > 0 - || (cmp == 0 && innobase_repl_pos - >= (my_off_t)trx->repl_wait_binlog_pos)) { - /* We have already sent the relevant binlog to the - slave: no need to wait here */ - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - -/* printf("Binlog now sent\n"); */ - - return(0); - } - - /* Let us update the info about the minimum binlog position - of waiting threads in the innobase_repl_... variables */ - - if (innobase_repl_wait_file_name_inited != 0) { - cmp = strcmp(trx->repl_wait_binlog_name, - innobase_repl_wait_file_name); - if (cmp < 0 - || (cmp == 0 && (my_off_t)trx->repl_wait_binlog_pos - <= innobase_repl_wait_pos)) { - /* This thd has an even lower position, let - us update the minimum info */ - - strcpy(innobase_repl_wait_file_name, - trx->repl_wait_binlog_name); - - innobase_repl_wait_pos = - trx->repl_wait_binlog_pos; - } - } else { - strcpy(innobase_repl_wait_file_name, - trx->repl_wait_binlog_name); - - innobase_repl_wait_pos = trx->repl_wait_binlog_pos; - - innobase_repl_wait_file_name_inited = 1; - } - set_timespec(abstime, thd->variables.sync_replication_timeout); - - /* Let us suspend this thread to wait on the condition; - when replication has progressed far enough, we will release - these waiting threads. The following call - pthread_cond_timedwait also atomically unlocks - innobase_repl_cond_mutex. */ - - innobase_repl_n_wait_threads++; - -/* printf("Waiting for binlog to be sent\n"); */ - - ret = pthread_cond_timedwait(&innobase_repl_cond, - &innobase_repl_cond_mutex, &abstime); - innobase_repl_n_wait_threads--; - - if (ret != 0) { - ut_print_timestamp(stderr); - - sql_print_error("MySQL synchronous replication was " - "not able to send the binlog to the " - "slave within the timeout %lu. We " - "assume that the slave has become " - "inaccessible, and switch off " - "synchronous replication until the " - "communication to the slave works " - "again. MySQL synchronous replication " - "has sent binlog to the slave up to " - "file %s, position %lu. This " - "transaction needs it to be sent up " - "to file %s, position %lu.", - thd->variables.sync_replication_timeout, - innobase_repl_file_name, - (ulong) innobase_repl_pos, - trx->repl_wait_binlog_name, - (ulong) trx->repl_wait_binlog_pos); - - innobase_repl_state = 0; - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - return(0); - } - - goto try_again; - } -#endif // HAVE_REPLICATION return(0); } -#ifdef HAVE_REPLICATION -/********************************************************************* -In synchronous replication, reports to InnoDB up to which binlog position -we have sent the binlog to the slave. Note that replication is synchronous -for one slave only. For other slaves, we do nothing in this function. This -function is used in a replication master. */ - -int -innobase_repl_report_sent_binlog( -/*=============================*/ - /* out: 0 */ - THD* thd, /* in: thread doing the binlog communication to - the slave */ - char* log_file_name, /* in: binlog file name */ - my_off_t end_offset) /* in: the offset in the binlog file up to - which we sent the contents to the slave */ -{ - int cmp; - ibool can_release_threads = 0; - - /* If synchronous replication is not switched on, or this thd is - sending binlog to a slave where we do not need synchronous replication, - then return immediately */ - - if (thd->server_id != thd->variables.sync_replication_slave_id) { - - /* Do nothing */ - - return(0); - } - - pthread_mutex_lock(&innobase_repl_cond_mutex); - - if (innobase_repl_state == 0) { - - ut_print_timestamp(stderr); - sql_print_warning("Switching MySQL synchronous replication on " - "again at binlog file %s, position %lu", - log_file_name, (ulong) end_offset); - - innobase_repl_state = 1; - } - - /* The position should increase monotonically, since just one thread - is sending the binlog to the slave for which we want synchronous - replication. Let us check this, and print an error to the .err log - if that is not the case. */ - - if (innobase_repl_file_name_inited) { - cmp = strcmp(log_file_name, innobase_repl_file_name); - - if (cmp < 0 - || (cmp == 0 && end_offset < innobase_repl_pos)) { - - ut_print_timestamp(stderr); - sql_print_error("MySQL synchronous replication has " - "sent binlog to the slave up to file " - "%s, position %lu, but now MySQL " - "reports that it sent the binlog only " - "up to file %s, position %lu", - innobase_repl_file_name, - (ulong) innobase_repl_pos, - log_file_name, (ulong) end_offset); - } - } - - strcpy(innobase_repl_file_name, log_file_name); - innobase_repl_pos = end_offset; - innobase_repl_file_name_inited = 1; - - if (innobase_repl_n_wait_threads > 0) { - /* Let us check if some of the waiting threads doing a trx - commit can now proceed */ - - cmp = strcmp(innobase_repl_file_name, - innobase_repl_wait_file_name); - if (cmp > 0 - || (cmp == 0 && innobase_repl_pos - >= innobase_repl_wait_pos)) { - - /* Yes, at least one waiting thread can now proceed: - let us release all waiting threads with a broadcast */ - - can_release_threads = 1; - - innobase_repl_wait_file_name_inited = 0; - } - } - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - if (can_release_threads) { - - pthread_cond_broadcast(&innobase_repl_cond); - } - - return(0); -} -#endif /* HAVE_REPLICATION */ - /********************************************************************* Rolls back a transaction or the latest SQL statement. */ @@ -4815,7 +4586,7 @@ ha_innobase::create( possible adaptive hash latch to avoid deadlocks of threads */ trx_search_latch_release_if_reserved(parent_trx); - + trx = trx_allocate_for_mysql(); trx->mysql_thd = thd; diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 7ab252f97dd..5dd6a92c4b0 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -303,9 +303,6 @@ int innobase_rollback_by_xid( XID *xid); /* in : X/Open XA Transaction Identification */ -int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, - my_off_t end_offset); - /*********************************************************************** Create a consistent view for a cursor based on current transaction which is created if the corresponding MySQL thread still lacks one. diff --git a/sql/handler.cc b/sql/handler.cc index 627117a65a5..b40934ea194 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2684,56 +2684,3 @@ TYPELIB *ha_known_exts(void) } return &known_extensions; } - - -#ifdef HAVE_REPLICATION -/* - Reports to table handlers up to which position we have sent the binlog - to a slave in replication - - SYNOPSIS - ha_repl_report_sent_binlog() - thd thread doing the binlog communication to the slave - log_file_name binlog file name - end_offse t the offset in the binlog file up to which we sent the - contents to the slave - - NOTES - Only works for InnoDB at the moment - - RETURN VALUE - Always 0 (= success) -*/ - -int ha_repl_report_sent_binlog(THD *thd, char *log_file_name, - my_off_t end_offset) -{ -#ifdef HAVE_INNOBASE_DB - return innobase_repl_report_sent_binlog(thd,log_file_name,end_offset); -#else - return 0; -#endif -} - - -/* - Reports to table handlers that we stop replication to a specific slave - - SYNOPSIS - ha_repl_report_replication_stop() - thd thread doing the binlog communication to the slave - - NOTES - Does nothing at the moment - - RETURN VALUE - Always 0 (= success) - - PARAMETERS -*/ - -int ha_repl_report_replication_stop(THD *thd) -{ - return 0; -} -#endif /* HAVE_REPLICATION */ diff --git a/sql/handler.h b/sql/handler.h index 8270849348a..e531a3f1077 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -965,8 +965,3 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht); */ #define trans_need_2pc(thd, all) ((total_ha_2pc > 1) && \ !((all ? &thd->transaction.all : &thd->transaction.stmt)->no_2pc)) - -/* semi-synchronous replication */ -int ha_repl_report_sent_binlog(THD *thd, char *log_file_name, - my_off_t end_offset); -int ha_repl_report_replication_stop(THD *thd); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2690b2f6852..83722b1c6a7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5899,23 +5899,6 @@ The minimum value for this variable is 4096.", {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"sync-replication", OPT_SYNC_REPLICATION, - "Enable synchronous replication.", - (gptr*) &global_system_variables.sync_replication, - (gptr*) &global_system_variables.sync_replication, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, 1, 0, 1, 0}, - {"sync-replication-slave-id", OPT_SYNC_REPLICATION_SLAVE_ID, - "Synchronous replication is wished for this slave.", - (gptr*) &global_system_variables.sync_replication_slave_id, - (gptr*) &global_system_variables.sync_replication_slave_id, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, - {"sync-replication-timeout", OPT_SYNC_REPLICATION_TIMEOUT, - "Synchronous replication timeout.", - (gptr*) &global_system_variables.sync_replication_timeout, - (gptr*) &global_system_variables.sync_replication_timeout, - 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, -#endif /* HAVE_REPLICATION */ {"table_cache", OPT_TABLE_CACHE, "The number of open tables for all threads.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L, diff --git a/sql/set_var.cc b/sql/set_var.cc index 762b8d7ec60..a0b60251354 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -376,17 +376,6 @@ sys_var_thd_table_type sys_table_type("table_type", &SV::table_type); sys_var_thd_storage_engine sys_storage_engine("storage_engine", &SV::table_type); -#ifdef HAVE_REPLICATION -sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", &sync_binlog_period); -sys_var_thd_ulong sys_sync_replication("sync_replication", - &SV::sync_replication); -sys_var_thd_ulong sys_sync_replication_slave_id( - "sync_replication_slave_id", - &SV::sync_replication_slave_id); -sys_var_thd_ulong sys_sync_replication_timeout( - "sync_replication_timeout", - &SV::sync_replication_timeout); -#endif sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm); sys_var_long_ptr sys_table_cache_size("table_cache", &table_cache_size); @@ -708,12 +697,6 @@ sys_var *sys_variables[]= &sys_sql_warnings, &sys_sql_notes, &sys_storage_engine, -#ifdef HAVE_REPLICATION - &sys_sync_binlog_period, - &sys_sync_replication, - &sys_sync_replication_slave_id, - &sys_sync_replication_timeout, -#endif &sys_sync_frm, &sys_table_cache_size, &sys_table_lock_wait_timeout, @@ -1009,15 +992,7 @@ struct show_var_st init_vars[]= { {"sql_notes", (char*) &sys_sql_notes, SHOW_BOOL}, {"sql_warnings", (char*) &sys_sql_warnings, SHOW_BOOL}, {sys_storage_engine.name, (char*) &sys_storage_engine, SHOW_SYS}, -#ifdef HAVE_REPLICATION - {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, -#endif {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS}, -#ifdef HAVE_REPLICATION - {sys_sync_replication.name, (char*) &sys_sync_replication, SHOW_SYS}, - {sys_sync_replication_slave_id.name, (char*) &sys_sync_replication_slave_id,SHOW_SYS}, - {sys_sync_replication_timeout.name, (char*) &sys_sync_replication_timeout,SHOW_SYS}, -#endif #ifdef HAVE_TZNAME {"system_time_zone", system_time_zone, SHOW_CHAR}, #endif diff --git a/sql/sql_class.h b/sql/sql_class.h index ed116a16f4f..0ddba0e6f05 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -552,11 +552,7 @@ struct system_variables my_bool new_mode; my_bool query_cache_wlock_invalidate; my_bool engine_condition_pushdown; -#ifdef HAVE_REPLICATION - ulong sync_replication; - ulong sync_replication_slave_id; - ulong sync_replication_timeout; -#endif /* HAVE_REPLICATION */ + #ifdef HAVE_INNOBASE_DB my_bool innodb_table_locks; my_bool innodb_support_xa; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 76e458783c4..ccda69522c7 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -385,9 +385,6 @@ impossible position"; goto err; } - if (thd->variables.sync_replication) - ha_repl_report_sent_binlog(thd, log_file_name, pos); - /* We need to start a packet with something other than 255 to distinguish it from error @@ -480,9 +477,6 @@ impossible position"; goto err; } - if (thd->variables.sync_replication) - ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); - /* No need to save this event. We are only doing simple reads (no real parsing of the events) so we don't need it. And so @@ -541,9 +535,6 @@ impossible position"; goto err; } - if (thd->variables.sync_replication) - ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); - DBUG_PRINT("info", ("log event code %d", (*packet)[LOG_EVENT_OFFSET+1] )); if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) @@ -657,9 +648,6 @@ impossible position"; goto err; } - if (thd->variables.sync_replication) - ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); - if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) { if (send_file(thd)) @@ -726,18 +714,12 @@ impossible position"; goto err; } - if (thd->variables.sync_replication) - ha_repl_report_sent_binlog(thd, log_file_name, 0); - packet->length(0); packet->append('\0'); } } end: - if (thd->variables.sync_replication) - ha_repl_report_replication_stop(thd); - end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); @@ -749,9 +731,6 @@ end: DBUG_VOID_RETURN; err: - if (thd->variables.sync_replication) - ha_repl_report_replication_stop(thd); - thd->proc_info = "Waiting to finalize termination"; end_io_cache(&log); /* From d316b8b10b3b430efef3d429b1588c93e1667e67 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 14:37:03 +0500 Subject: [PATCH 056/101] BUG#17917 - SELECT from compressed MyISAM table crashes MySQL server Retrieving data from compressed MyISAM table which is bigger than 4G on 32-bit box with mmap() support results in server crash. mmap() accepts length of bytes to be mapped in second param, which is 32-bit size_t. But we pass data_file_length, which is 64-bit my_off_t. As a result only first data_file_length % 4G were mapped. This fix adds additional condition for mmap() usage, that is use mmap() for compressed table which size is no more than 4G on 32-bit platform. myisam/mi_packrec.c: Use mmap() for compressed table which size is no more than 4G on 32-bit platform. --- myisam/mi_packrec.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 322420b71db..bd2d162d100 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -1158,16 +1158,22 @@ my_bool _mi_memmap_file(MI_INFO *info) MYISAM_SHARE *share=info->s; DBUG_ENTER("mi_memmap_file"); - if (!info->s->file_map) + if (!share->file_map) { + my_off_t data_file_length= share->state.state.data_file_length; + if (data_file_length > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN) + { + DBUG_PRINT("warning", ("File is too large for mmap")); + DBUG_RETURN(0); + } if (my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) < - share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN) + data_file_length + MEMMAP_EXTRA_MARGIN) { DBUG_PRINT("warning",("File isn't extended for memmap")); DBUG_RETURN(0); } file_map=(byte*) - mmap(0,share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ, + mmap(0, data_file_length + MEMMAP_EXTRA_MARGIN, PROT_READ, MAP_SHARED | MAP_NORESERVE,info->dfile,0L); if (file_map == (byte*) MAP_FAILED) { @@ -1175,7 +1181,7 @@ my_bool _mi_memmap_file(MI_INFO *info) my_errno=errno; DBUG_RETURN(0); } - info->s->file_map=file_map; + share->file_map= file_map; } info->opt_flag|= MEMMAP_USED; info->read_record=share->read_record=_mi_read_mempack_record; From 403e6783f5c3f57f9dd56af0f5f7d583e91d417e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 14:06:46 +0400 Subject: [PATCH 057/101] Fix a typo in the help message. sql/mysqld.cc: Fix a typo. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e68762868a4..740e1a419c7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5253,7 +5253,7 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0}, {"max_prepared_stmt_count", OPT_MAX_PREPARED_STMT_COUNT, - "Maximum numbrer of prepared statements in the server.", + "Maximum number of prepared statements in the server.", (gptr*) &max_prepared_stmt_count, (gptr*) &max_prepared_stmt_count, 0, GET_ULONG, REQUIRED_ARG, 16382, 0, 1*1024*1024, 0, 1, 0}, {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE, From 72a803dedf6aac8531c9b79d61f86b74391ed089 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 16:06:52 +0300 Subject: [PATCH 058/101] postmerge fix: added tinfo support. --- config/ac-macros/misc.m4 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4 index 5346b81fb03..d8199f5970e 100644 --- a/config/ac-macros/misc.m4 +++ b/config/ac-macros/misc.m4 @@ -361,7 +361,8 @@ AC_CACHE_VAL(mysql_cv_termcap_lib, [AC_CHECK_LIB(ncurses, tgetent, mysql_cv_termcap_lib=libncurses, [AC_CHECK_LIB(curses, tgetent, mysql_cv_termcap_lib=libcurses, [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap, - mysql_cv_termcap_lib=NOT_FOUND)])])]) + [AC_CHECK_LIB(tinfo, tgetent, mysql_cv_termcap_lib=libtinfo, + mysql_cv_termcap_lib=NOT_FOUND)])])])]) AC_MSG_CHECKING(for termcap functions library) if test "$mysql_cv_termcap_lib" = "NOT_FOUND"; then AC_MSG_ERROR([No curses/termcap library found]) @@ -369,6 +370,8 @@ elif test "$mysql_cv_termcap_lib" = "libtermcap"; then TERMCAP_LIB=-ltermcap elif test "$mysql_cv_termcap_lib" = "libncurses"; then TERMCAP_LIB=-lncurses +elif test "$mysql_cv_termcap_lib" = "libtinfo"; then +TERMCAP_LIB=-ltinfo else TERMCAP_LIB=-lcurses fi From 8dbb580748e75c4f516e572f5846041299652bf2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Apr 2006 23:12:26 +0300 Subject: [PATCH 059/101] The check for recursive view definitions added. (BUG#14308) mysql-test/r/view.result: BUG#14308 test suite. mysql-test/t/view.test: BUG#14308 test suite. sql/share/errmsg.txt: New error message about a recursive view. sql/sql_view.cc: The check of view recursion. --- mysql-test/r/view.result | 23 +++++++++++++++++++++++ mysql-test/t/view.test | 31 +++++++++++++++++++++++++++++++ sql/share/errmsg.txt | 2 ++ sql/sql_view.cc | 20 +++++++++++++++++++- 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 7519b8022f0..b52e6b58c0e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2600,3 +2600,26 @@ id td 5 2005-01-04 DROP VIEW v1; DROP TABLE t1; +create table t1 (a int); +create view v1 as select * from t1; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +select * from v1; +ERROR HY000: `test`.`v1` contain view recursion +drop view t1, v1; +create table t1 (a int); +create function f1() returns int +begin +declare mx int; +select max(a) from t1 into mx; +return mx; +end// +create view v1 as select f1() as a; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +select * from v1; +ERROR HY000: Recursive stored functions and triggers are not allowed. +drop function f1; +drop view t1, v1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7ef1f82dbd3..81fb161b69a 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2454,3 +2454,34 @@ SELECT * FROM v1 WHERE td BETWEEN '2005.01.02' AND '2005.01.04'; DROP VIEW v1; DROP TABLE t1; + +# +# BUG#14308: Recursive view definitions +# +# using view only +create table t1 (a int); +create view v1 as select * from t1; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +-- error ER_VIEW_RECURSIVE +select * from v1; +drop view t1, v1; +# using SP function +create table t1 (a int); +delimiter //; +create function f1() returns int +begin + declare mx int; + select max(a) from t1 into mx; + return mx; +end// +delimiter ;// +create view v1 as select f1() as a; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +-- error ER_SP_NO_RECURSION +select * from v1; +drop function f1; +drop view t1, v1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a1f70fca8df..9519e77903d 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5613,3 +5613,5 @@ ER_SP_NO_AGGREGATE 42000 eng "AGGREGATE is not supported for stored functions" ER_MAX_PREPARED_STMT_COUNT_REACHED 42000 eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)" +ER_VIEW_RECURSIVE + eng "`%-.64s`.`%-.64s` contain view recursion" diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 39d1ae5c9fb..cdb6c581565 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -771,6 +771,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) SELECT_LEX *end, *view_select; LEX *old_lex, *lex; Query_arena *arena, backup; + TABLE_LIST *top_view= table->top_table(); int res; bool result; DBUG_ENTER("mysql_make_view"); @@ -798,6 +799,24 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) DBUG_RETURN(0); } + /* check loop via view definition */ + for (TABLE_LIST *precedent= table->referencing_view; + precedent; + precedent= precedent->referencing_view) + { + if (precedent->view_name.length == table->table_name_length && + precedent->view_db.length == table->db_length && + my_strcasecmp(system_charset_info, + precedent->view_name.str, table->table_name) == 0 && + my_strcasecmp(system_charset_info, + precedent->view_db.str, table->db) == 0) + { + my_error(ER_VIEW_RECURSIVE, MYF(0), + top_view->view_db.str, top_view->view_name.str); + DBUG_RETURN(TRUE); + } + } + /* For now we assume that tables will not be changed during PS life (it will be TRUE as far as we make new table cache). @@ -896,7 +915,6 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) } if (!res && !thd->is_fatal_error) { - TABLE_LIST *top_view= table->top_table(); TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables_tail= 0; TABLE_LIST *tbl; From ac0ec77832ddff5508d5a99a81b51c46d6038b9b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Apr 2006 12:13:26 +0300 Subject: [PATCH 060/101] Bug#19097: rpl_view failed on some platforms removing comments from the opt file. mysql-test/t/rpl_view-slave.opt: removing `#' comments --- mysql-test/t/rpl_view-slave.opt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mysql-test/t/rpl_view-slave.opt b/mysql-test/t/rpl_view-slave.opt index 55b3aeb3bda..79b3bf6174b 100644 --- a/mysql-test/t/rpl_view-slave.opt +++ b/mysql-test/t/rpl_view-slave.opt @@ -1,5 +1 @@ -# -# BUG18715 create view with replicate*ignore-table -# The option is needed to force slave executes tables_ok -# which must return OK in conditions of this tests (no table foo is used) --replicate-ignore-table=test.foo From 9a40c5bf33b0ae9bec790ed1f8ae44a809285e72 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 15 Apr 2006 21:49:13 -0400 Subject: [PATCH 061/101] WL 2826: Error handling of ALTER TABLE for partitioning After review changes mysql-test/r/ndb_partition_key.result: Fixed result file sql/ha_ndbcluster.cc: Fixed interface to create_handler_files sql/ha_ndbcluster.h: Fixed interface to create_handler_files sql/ha_partition.cc: Fixed interface to create_handler_files and made it two-stage for rename Removed print_error and now it's used by MySQL Server parts instead sql/ha_partition.h: Fixed interface to create_handler_files sql/mysql_priv.h: Fixed error injects Externalised Global DDL log mutex Some interface changes sql/mysqld.cc: Moved close of DDL log until all user threads been closed sql/sql_base.cc: Interface changes sql/sql_partition.cc: Moved print_error to mysql server part sql/sql_table.cc: Lots of after review changes sql/table.cc: Fixed upgrade code --- mysql-test/r/ndb_partition_key.result | 1 + sql/ha_ndbcluster.cc | 4 +- sql/ha_ndbcluster.h | 2 +- sql/ha_partition.cc | 24 ++++---- sql/ha_partition.h | 2 +- sql/mysql_priv.h | 21 ++++--- sql/mysqld.cc | 2 +- sql/sql_base.cc | 9 ++- sql/sql_partition.cc | 81 ++++++++++++++------------- sql/sql_table.cc | 79 +++++++++----------------- sql/table.cc | 15 ++--- 11 files changed, 107 insertions(+), 133 deletions(-) diff --git a/mysql-test/r/ndb_partition_key.result b/mysql-test/r/ndb_partition_key.result index 743453eb912..503283df532 100644 --- a/mysql-test/r/ndb_partition_key.result +++ b/mysql-test/r/ndb_partition_key.result @@ -178,6 +178,7 @@ ALTER TABLE t1 ANALYZE PARTITION p0; ERROR HY000: Table storage engine for 't1' doesn't have this option ALTER TABLE t1 REBUILD PARTITION p0; ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; CREATE TABLE t1 ( c1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 4310f8d1c12..62c751e1aef 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4689,7 +4689,7 @@ int ha_ndbcluster::create(const char *name, int ha_ndbcluster::create_handler_files(const char *file, const char *old_name, - bool rename_flag) + int action_flag) { const char *name; Ndb* ndb; @@ -4700,7 +4700,7 @@ int ha_ndbcluster::create_handler_files(const char *file, DBUG_ENTER("create_handler_files"); - if (rename_flag) + if (action_flag) { DBUG_RETURN(FALSE); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 70f0c79bd20..3a46f4f702f 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -612,7 +612,7 @@ class ha_ndbcluster: public handler int delete_table(const char *name); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); int create_handler_files(const char *file, const char *old_name, - bool rename_flag); + int action_flag); int get_default_no_partitions(ulonglong max_rows); bool get_no_parts(const char *name, uint *no_parts); void set_auto_partitions(partition_info *part_info); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 15224a9bc55..e7340f327a9 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -495,7 +495,7 @@ int ha_partition::rename_table(const char *from, const char *to) int ha_partition::create_handler_files(const char *path, const char *old_path, - bool rename_flag) + int action_flag) { DBUG_ENTER("ha_partition::create_handler_files()"); @@ -503,15 +503,17 @@ int ha_partition::create_handler_files(const char *path, We need to update total number of parts since we might write the handler file as part of a partition management command */ - if (rename_flag) + if (action_flag) { char name[FN_REFLEN]; char old_name[FN_REFLEN]; strxmov(name, path, ha_par_ext, NullS); strxmov(old_name, old_path, ha_par_ext, NullS); - if (my_delete(name, MYF(MY_WME)) || - my_rename(old_name, name, MYF(MY_WME))) + if ((action_flag == CHF_DELETE_FLAG && + my_delete(name, MYF(MY_WME))) || + (action_flag == CHF_RENAME_FLAG && + my_rename(old_name, name, MYF(MY_WME)))) { DBUG_RETURN(TRUE); } @@ -1153,7 +1155,6 @@ int ha_partition::prepare_new_partition(TABLE *table, error: if (create_flag) VOID(file->delete_table(part_name)); - print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -1280,7 +1281,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (m_reorged_parts + 1)))) { mem_alloc_error(sizeof(partition_element*)*(m_reorged_parts+1)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } /* @@ -1312,7 +1313,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (2*(no_remain_partitions + 1))))) { mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } m_added_file= &new_file_array[no_remain_partitions + 1]; @@ -1384,7 +1385,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->engine_type))) { mem_alloc_error(sizeof(handler)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } } while (++j < no_subparts); } @@ -1432,7 +1433,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (const char *)part_name_buff))) { cleanup_new_partition(part_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[part]; } while (++j < no_subparts); @@ -1448,7 +1449,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (const char *)part_name_buff))) { cleanup_new_partition(part_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[i]; } @@ -1554,8 +1555,7 @@ int ha_partition::copy_partitions(ulonglong *copied, ulonglong *deleted) } DBUG_RETURN(FALSE); error: - print_error(result, MYF(0)); - DBUG_RETURN(TRUE); + DBUG_RETURN(result); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 1a592bab340..ba223d5becf 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -180,7 +180,7 @@ public: virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); virtual int create_handler_files(const char *name, - const char *old_name, bool rename_flag); + const char *old_name, int action_flag); virtual void update_create_info(HA_CREATE_INFO *create_info); virtual char *update_table_comment(const char *comment); virtual int change_partitions(HA_CREATE_INFO *create_info, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dbc1093c01a..587069c65cb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -633,8 +633,7 @@ struct Query_cache_query_flags #else -inline bool -my_error_inject_name(const char *dbug_str) +inline bool check_and_unset_keyword(const char *dbug_str) { const char *extra_str= "-d,"; char total_str[200]; @@ -649,7 +648,7 @@ my_error_inject_name(const char *dbug_str) inline bool -my_error_inject(int value) +check_and_unset_inject_value(int value) { THD *thd= current_thd; if (thd->error_inject_value == (uint)value) @@ -700,15 +699,15 @@ my_error_inject(int value) #define ERROR_INJECT_CRASH(code) \ DBUG_EVALUATE_IF(code, (abort(), 0), 0) #define ERROR_INJECT_ACTION(code, action) \ - (my_error_inject_name(code) ? ((action), 0) : 0) + (check_and_unset_keyword(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ - my_error_inject_name(code) + check_and_unset_keyword(code) #define ERROR_INJECT_VALUE(value) \ - my_error_inject(value) + check_and_unset_inject_value(value) #define ERROR_INJECT_VALUE_ACTION(value,action) \ - (my_error_inject(value) ? (action) : 0) + (check_and_unset_inject_value(value) ? (action) : 0) #define ERROR_INJECT_VALUE_CRASH(value) \ - (my_error_inject(value) ? abort() : 0) + ERROR_INJECT_VALUE_ACTION(value, (abort(), 0)) #endif @@ -1300,14 +1299,14 @@ bool sync_ddl_log(); void release_ddl_log(); void execute_ddl_log_recovery(); bool execute_ddl_log_entry(THD *thd, uint first_entry); -void lock_global_ddl_log(); -void unlock_global_ddl_log(); + +extern pthread_mutex_t LOCK_gdl; #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); +int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 73990a950eb..47df3c43d4b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3696,7 +3696,6 @@ we force server id to 2, but this MySQL server will not act as a slave."); /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); - release_ddl_log(); #ifndef __WIN__ #ifdef EXTRA_DEBUG2 @@ -3718,6 +3717,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); pthread_cond_wait(&COND_thread_count,&LOCK_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count); + release_ddl_log(); #if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) if (Service.IsNT() && start_mode) Service.Stop(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4d5eb070d51..5d9b9e70269 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6140,9 +6140,8 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) abort_and_upgrade_lock() lpt Parameter passing struct All parameters passed through the ALTER_PARTITION_PARAM_TYPE object - RETURN VALUES - TRUE Failure - FALSE Success + RETURN VALUE + 0 DESCRIPTION Remember old lock level (for possible downgrade later on), abort all waiting threads and ensure that all keeping locks currently are @@ -6156,7 +6155,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; DBUG_ENTER("abort_and_upgrade_locks"); @@ -6166,7 +6165,7 @@ void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_VOID_RETURN; + DBUG_RETURN(0); } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f038c2232cf..df404b11240 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4588,12 +4588,17 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(file->change_partitions(lpt->create_info, - path, - &lpt->copied, - &lpt->deleted, - lpt->pack_frm_data, - lpt->pack_frm_len)); + if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied, + &lpt->deleted, lpt->pack_frm_data, + lpt->pack_frm_len))) + { + if (error != ER_OUTOFMEMORY) + file->print_error(error, MYF(0)); + else + lpt->thd->fatal_error(); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -5016,7 +5021,7 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) goto error; @@ -5024,13 +5029,13 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_ddl_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) goto error; - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); @@ -5066,7 +5071,7 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) goto error; log_entry= part_info->first_log_entry; @@ -5075,12 +5080,12 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE, &exec_log_entry)) goto error; release_part_info_log_entries(old_first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); @@ -5120,7 +5125,7 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) goto error; @@ -5133,12 +5138,12 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE, &exec_log_entry)) goto error; release_part_info_log_entries(old_first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); @@ -5177,7 +5182,7 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) goto error; @@ -5188,13 +5193,13 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_ddl_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) goto error; - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); @@ -5234,7 +5239,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, TRUE)) goto error; @@ -5248,12 +5253,12 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE, &exec_log_entry)) goto error; release_part_info_log_entries(old_first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); @@ -5282,7 +5287,7 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_ENTER("write_log_completed"); DBUG_ASSERT(log_entry); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry)) { /* @@ -5296,7 +5301,7 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, } release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->exec_log_entry= NULL; part_info->first_log_entry= NULL; DBUG_VOID_RETURN; @@ -5314,10 +5319,10 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, static void release_log_entries(partition_info *part_info) { - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= NULL; part_info->exec_log_entry= NULL; } @@ -5643,8 +5648,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || - ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt), FALSE) || + (not_completed= FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -5702,13 +5707,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - (abort_and_upgrade_lock(lpt), FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_4") || write_log_rename_frm(lpt) || - ((not_completed= FALSE), FALSE) || + (not_completed= FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || @@ -5784,8 +5789,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_3") || write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || - ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt), FALSE) || + (not_completed= FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6455,10 +6460,9 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) the del_ren_cre_table method. */ -void -create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate) +void create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate) { char transl_part_name[FN_REFLEN]; const char *transl_part; @@ -6498,10 +6502,9 @@ create_partition_name(char *out, const char *in1, the del_ren_cre_table method. */ -void -create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant) +void create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant) { char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e8f5fffd88b..8e8d430f894 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -270,6 +270,12 @@ static int mysql_copy_key_list(List *orig_key, typedef struct st_global_ddl_log { + /* + We need to adjust buffer size to be able to handle downgrades/upgrades + where IO_SIZE has changed. We'll set the buffer size such that we can + handle that the buffer size was upto 4 times bigger in the version + that wrote the DDL log. + */ char file_entry_buf[4*IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; @@ -278,7 +284,6 @@ typedef struct st_global_ddl_log uint num_entries; File file_id; uint name_len; - uint handler_name_len; uint io_size; bool inited; bool recovery_phase; @@ -296,8 +301,7 @@ pthread_mutex_t LOCK_gdl; #define DDL_LOG_NUM_ENTRY_POS 0 #define DDL_LOG_NAME_LEN_POS 4 -#define DDL_LOG_HANDLER_TYPE_POS 8 -#define DDL_LOG_IO_SIZE_POS 12 +#define DDL_LOG_IO_SIZE_POS 8 /* Read one entry from ddl log file @@ -368,9 +372,6 @@ static bool write_ddl_log_header() const_var= FN_LEN; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], const_var); - const_var= DDL_LOG_HANDLER_TYPE_LEN; - int4store(&global_ddl_log.file_entry_buf[DDL_LOG_HANDLER_TYPE_POS], - const_var); const_var= IO_SIZE; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], const_var); @@ -424,7 +425,8 @@ static uint read_ddl_log_header() global_ddl_log.inited= FALSE; global_ddl_log.recovery_phase= TRUE; create_ddl_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_BINARY, MYF(MY_WME)))) + if (!(global_ddl_log.file_id= my_open(file_name, + O_RDWR | O_BINARY, MYF(MY_WME)))) { if (read_ddl_log_file_entry(0UL)) { @@ -436,10 +438,12 @@ static uint read_ddl_log_header() } entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); - global_ddl_log.handler_name_len= - uint4korr(&file_entry_buf[DDL_LOG_HANDLER_TYPE_POS]); - if (successful_open) + if (successful_open) + { global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); + DBUG_ASSERT(global_ddl_log.io_size <= + sizeof(global_ddl_log.file_entry_buf)); + } else { global_ddl_log.io_size= IO_SIZE; @@ -790,7 +794,9 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, to execute, if 0 = NULL it means that the entry is removed and the entries are put into the free list. - in:out:exec_entry Entry to execute, 0 = NULL if the entry + complete Flag indicating we are simply writing + info about that entry has been completed + in:out:active_entry Entry to execute, 0 = NULL if the entry is written first time and needs to be returned. In this case the entry written is returned in this parameter @@ -1003,12 +1009,11 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) uint read_entry= first_entry; DBUG_ENTER("execute_ddl_log_entry"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); do { if (read_ddl_log_entry(read_entry, &ddl_log_entry)) { - DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ sql_print_error("Failed to read entry = %u from ddl log", read_entry); @@ -1019,7 +1024,6 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) if (execute_ddl_log_action(thd, &ddl_log_entry)) { - DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ sql_print_error("Failed to execute action for entry = %u from ddl log", read_entry); @@ -1027,7 +1031,7 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) } read_entry= ddl_log_entry.next_entry; } while (read_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); } @@ -1061,7 +1065,6 @@ void execute_ddl_log_recovery() { if (read_ddl_log_entry(i, &ddl_log_entry)) { - DBUG_ASSERT(0); sql_print_error("Failed to read entry no = %u from ddl log", i); continue; @@ -1071,7 +1074,6 @@ void execute_ddl_log_recovery() if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) { /* Real unpleasant scenario but we continue anyways. */ - DBUG_ASSERT(0); continue; } } @@ -1100,7 +1102,7 @@ void release_ddl_log() DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; DBUG_ENTER("release_ddl_log"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); while (used_list) { DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; @@ -1114,46 +1116,12 @@ void release_ddl_log() free_list= tmp; } VOID(my_close(global_ddl_log.file_id, MYF(0))); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); VOID(pthread_mutex_destroy(&LOCK_gdl)); DBUG_VOID_RETURN; } -/* - Lock mutex for global ddl log - SYNOPSIS - lock_global_ddl_log() - RETURN VALUES - NONE -*/ - -void lock_global_ddl_log() -{ - DBUG_ENTER("lock_global_ddl_log"); - - VOID(pthread_mutex_lock(&LOCK_gdl)); - DBUG_VOID_RETURN; -} - - -/* - Unlock mutex for global ddl log - SYNOPSIS - unlock_global_ddl_log() - RETURN VALUES - NONE -*/ - -void unlock_global_ddl_log() -{ - DBUG_ENTER("unlock_global_ddl_log"); - - VOID(pthread_mutex_unlock(&LOCK_gdl)); - DBUG_VOID_RETURN; -} - - /* --------------------------------------------------------------------------- @@ -1296,11 +1264,14 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE + lpt->table->file->create_handler_files(path, shadow_path, + CHF_DELETE_FLAG) || deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || (sync_ddl_log(), FALSE) || #endif my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || - lpt->table->file->create_handler_files(path, shadow_path, TRUE)) + lpt->table->file->create_handler_files(path, shadow_path, + CHF_RENAME_FLAG)) { error= 1; } diff --git a/sql/table.cc b/sql/table.cc index d8d5b841e21..20ab550bf66 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -667,15 +667,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } -#if 1 - if (share->mysql_version == 50106 || - share->mysql_version == 50107) +#if MYSQL_VERSION_ID < 50200 + if (share->mysql_version >= 50106 && share->mysql_version <= 50109) { /* - Partition state array was here in version 5.1.6, this code makes - it possible to load a 5.1.6 table in later versions. Can most - likely be removed at some point in time. - */ + Partition state array was here in version 5.1.6 to 5.1.9, this code + makes it possible to load a 5.1.6 table in later versions. Can most + likely be removed at some point in time. Will only be used for + upgrades within 5.1 series of versions. Upgrade to 5.2 can only be + done from newer 5.1 versions. + */ next_chunk+= 4; } #endif From 1e2bde0d443b19145ec460292d6a96e647fad2e7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Apr 2006 17:17:36 -0400 Subject: [PATCH 062/101] Only expand the empty string to the letters "NULL" if the column does not have "NOT NULL" attribute set. Also, calculate the padding characters more safely, so that a negative number doesn't cause it to print MAXINT-n spaces. mysql-test/r/mysql.result: Add test result. mysql-test/t/mysql.test: Add test. --- client/mysql.cc | 18 ++++++++++-------- mysql-test/r/mysql.result | 12 ++++++++++++ mysql-test/t/mysql.test | 5 +++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index cd4cbf49918..8589bdb05ed 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2268,8 +2268,10 @@ print_table_data(MYSQL_RES *result) MYSQL_ROW cur; MYSQL_FIELD *field; bool *num_flag; + bool *not_null_flag; num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); + not_null_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); if (info_flag) { print_field_types(result); @@ -2287,7 +2289,7 @@ print_table_data(MYSQL_RES *result) length=max(length,field->max_length); if (length < 4 && !IS_NOT_NULL(field->flags)) length=4; // Room for "NULL" - field->max_length=length+1; + field->max_length=length; separator.fill(separator.length()+length+2,'-'); separator.append('+'); } @@ -2299,10 +2301,11 @@ print_table_data(MYSQL_RES *result) (void) tee_fputs("|", PAGER); for (uint off=0; (field = mysql_fetch_field(result)) ; off++) { - tee_fprintf(PAGER, " %-*s|",(int) min(field->max_length, + tee_fprintf(PAGER, " %-*s |",(int) min(field->max_length, MAX_COLUMN_LENGTH), field->name); num_flag[off]= IS_NUM(field->type); + not_null_flag[off]= IS_NOT_NULL(field->flags); } (void) tee_fputs("\n", PAGER); tee_puts((char*) separator.ptr(), PAGER); @@ -2322,7 +2325,8 @@ print_table_data(MYSQL_RES *result) uint visible_length; uint extra_padding; - if (lengths[off] == 0) + /* If this column may have a null value, use "NULL" for empty. */ + if (! not_null_flag[off] && (lengths[off] == 0)) { buffer= "NULL"; data_length= 4; @@ -2362,6 +2366,7 @@ print_table_data(MYSQL_RES *result) } tee_puts((char*) separator.ptr(), PAGER); my_afree((gptr) num_flag); + my_afree((gptr) not_null_flag); } @@ -2376,11 +2381,8 @@ tee_print_sized_data(const char *data, unsigned int data_length, unsigned int to unsigned int i; const char *p; - total_bytes_to_send -= 1; - /* Off by one, perhaps mistakenly accounting for a terminating NUL. */ - if (right_justified) - for (i= 0; i < (total_bytes_to_send - data_length); i++) + for (i= data_length; i < total_bytes_to_send; i++) tee_putc((int)' ', PAGER); for (i= 0, p= data; i < data_length; i+= 1, p+= 1) @@ -2392,7 +2394,7 @@ tee_print_sized_data(const char *data, unsigned int data_length, unsigned int to } if (! right_justified) - for (i= 0; i < (total_bytes_to_send - data_length); i++) + for (i= data_length; i < total_bytes_to_send; i++) tee_putc((int)' ', PAGER); } diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index ae50c714bba..a067d3ad0f8 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -85,3 +85,15 @@ c_cp932 | NULL | NULL | Τη γλώσσα | | NULL | NULL | á›–áš´ áš·á›–á› | +------+------+---------------------------+ ++------+---+------+ +| i | j | k | ++------+---+------+ +| NULL | 1 | NULL | ++------+---+------+ ++-------+---------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------+---------+------+-----+---------+-------+ +| i | int(11) | YES | | NULL | | +| j | int(11) | NO | | NULL | | +| k | int(11) | YES | | NULL | | ++-------+---------+------+-----+---------+-------+ diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 95cba2743da..e76553f42e7 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -67,3 +67,8 @@ drop table t1; # --exec $MYSQL -t --default-character-set utf8 test -e "create table t1 (i int, j int, k char(25) charset utf8); insert into t1 (i) values (1); insert into t1 (k) values ('<----------------------->'); insert into t1 (k) values ('<-----'); insert into t1 (k) values ('Τη γλώσσα'); insert into t1 (k) values ('á›–áš´ áš·á›–á›'); select * from t1; DROP TABLE t1;" +# +# "DESCRIBE" commands may return strange NULLness flags. +# +--exec $MYSQL -t --default-character-set utf8 test -e "create table t1 (i int, j int not null, k int); insert into t1 values (null, 1, null); select * from t1; describe t1; drop table t1;" + From 591cfbff308032fd5863a4aff30e5ae3d1b2d05c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Apr 2006 15:36:25 +0500 Subject: [PATCH 063/101] item_timefunc.cc: 5.0 additional fix for b#18691 Handle DECIMAL the same with INT and REAL. sql/item_timefunc.cc: 5.0 additional fix for b#18691 Handle DECIMAL the same with INT and REAL. --- sql/item_timefunc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 84e532ba4bc..200541f22a7 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2457,6 +2457,7 @@ void Item_char_typecast::fix_length_and_dec() the argument's charset. */ from_cs= (args[0]->result_type() == INT_RESULT || + args[0]->result_type() == DECIMAL_RESULT || args[0]->result_type() == REAL_RESULT) ? (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) : args[0]->collation.collation; From 7b14ac64bcd56f6276890a2e6b67edead06ad6fe Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Apr 2006 16:46:56 +0300 Subject: [PATCH 064/101] BUG#17152: Wrong result with BINARY comparison on aliased column Testsuite added --- mysql-test/r/innodb.result | 35 +++++++++++++++++++++++++++++++++++ mysql-test/t/innodb.test | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 9a190557211..75e41e7a94f 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3241,3 +3241,38 @@ where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; a a 2005-10-01 2005-10-01 drop table t1, t2; +CREATE TABLE t1 ( +a BIGINT(20) NOT NULL, +PRIMARY KEY (a) +) ENGINE=INNODB DEFAULT CHARSET=UTF8; +CREATE TABLE t2 ( +a BIGINT(20) NOT NULL, +b VARCHAR(128) NOT NULL, +c TEXT NOT NULL, +PRIMARY KEY (a,b), +KEY idx_t2_b_c (b,c(200)), +CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) +ON DELETE CASCADE +) ENGINE=INNODB DEFAULT CHARSET=UTF8; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1, 'bar', 'vbar'); +INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); +INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); +INSERT INTO t2 VALUES (1, 'customer_over', '1'); +SELECT * FROM t2 WHERE b = 'customer_over'; +a b c +1 customer_over 1 +SELECT * FROM t2 WHERE BINARY b = 'customer_over'; +a b c +1 customer_over 1 +SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; +a +1 +/* Bang: Empty result set, above was expected: */ +SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +a +1 +SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +a +1 +drop table t2, t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index b0835cd8419..fe5da58d4e7 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2139,3 +2139,37 @@ insert into t2 values('2005-10-01'); select * from t1, t2 where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; drop table t1, t2; + +# +# Bug #17152: Wrong result with BINARY comparison on aliased column +# + +CREATE TABLE t1 ( + a BIGINT(20) NOT NULL, + PRIMARY KEY (a) + ) ENGINE=INNODB DEFAULT CHARSET=UTF8; + +CREATE TABLE t2 ( + a BIGINT(20) NOT NULL, + b VARCHAR(128) NOT NULL, + c TEXT NOT NULL, + PRIMARY KEY (a,b), + KEY idx_t2_b_c (b,c(200)), + CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) + ON DELETE CASCADE + ) ENGINE=INNODB DEFAULT CHARSET=UTF8; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1, 'bar', 'vbar'); +INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); +INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); +INSERT INTO t2 VALUES (1, 'customer_over', '1'); + +SELECT * FROM t2 WHERE b = 'customer_over'; +SELECT * FROM t2 WHERE BINARY b = 'customer_over'; +SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; +/* Bang: Empty result set, above was expected: */ +SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; + +drop table t2, t1; From 4624982ecb152616c88f18e52d4d2896ff4522b0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 18 Apr 2006 16:58:12 +0200 Subject: [PATCH 065/101] WL 2826: Error handling of ALTER TABLE for partitioning Use \0 to indicate frm-file Add more comments Add more #ifdef code missing previously sql/sql_partition.cc: Use \0 to indicate frm-file sql/sql_table.cc: Use \0 to indicate frm-file Add more comments Add more #ifdef code missing previously --- sql/sql_partition.cc | 2 +- sql/sql_table.cc | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index df404b11240..7bc654c787d 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4759,7 +4759,7 @@ static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, else ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; ddl_log_entry.next_entry= next_entry; - ddl_log_entry.handler_name= "frm"; + ddl_log_entry.handler_name[0]= 0; ddl_log_entry.name= to_path; if (replace_flag) ddl_log_entry.from_name= from_path; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8e8d430f894..45f25b51f21 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -574,7 +574,7 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - if (strcmp("frm", ddl_log_entry->handler_name)) + if (ddl_log_entry->handler_name[0] == 0) frm_action= TRUE; else { @@ -1260,6 +1260,12 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) /* When we are changing to use new frm file we need to ensure that we don't collide with another thread in process to open the frm file. + We start by deleting the .frm file and possible .par file. Then we + write to the DDL log that we have completed the delete phase by + increasing the phase of the log entry. Next step is to rename the + new .frm file and the new .par file to the real name. After + completing this we write a new phase to the log entry that will + deactivate it. */ VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || @@ -1269,9 +1275,13 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || (sync_ddl_log(), FALSE) || #endif +#ifdef WITH_PARTITION_STORAGE_ENGINE my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, CHF_RENAME_FLAG)) +#else + my_rename(shadow_frm_name, frm_name, MYF(MY_WME))) +#endif { error= 1; } From c1b8cff03f9826efc168b683797c5646f3a0c014 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 12:05:44 -0400 Subject: [PATCH 066/101] WL 2826: Error handling of ALTER TABLE for partitioning Moved error inject from being flags to compiler to being part of config.h Also error inject only defined if debug is also defined +Small fixes configure.in: Moved error inject from being flags to compiler to being part of config.h Also error inject only defined if debug is also defined sql/handler.h: Small fixes --- configure.in | 27 +++++++++++++++------------ sql/handler.h | 12 +++++++----- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/configure.in b/configure.in index bfd2ec21869..157d2549d62 100644 --- a/configure.in +++ b/configure.in @@ -1588,18 +1588,6 @@ then DEBUG_OPTIMIZE_CXX="" fi -# If we should allow error injection tests -AC_ARG_WITH(error-inject, - [ --with-error-inject Enable error injection in MySQL Server], - [ with_error_inject=$withval ], - [ with_error_inject=no ]) - -if test "$with_error_inject" = "yes" -then - CFLAGS="-DERROR_INJECT_SUPPORT $CFLAGS" - CXXFLAGS="-DERROR_INJECT_SUPPORT $CXXFLAGS" -fi - AC_ARG_WITH(debug, [ --with-debug Add debug code --with-debug=full Add debug code (adds memory checker, very slow)], @@ -1621,6 +1609,21 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS" fi +# If we should allow error injection tests +AC_ARG_WITH(error-inject, + [ --with-error-inject Enable error injection in MySQL Server], + [ with_error_inject=$withval ], + [ with_error_inject=no ]) + +if test $with_debug != "no" +then + if test "$with_error_inject" = "yes" + then + AC_DEFINE([ERROR_INJECT_SUPPORT], [1], + [Enable error injection in MySQL Server]) + fi +fi + AC_ARG_WITH([fast-mutexes], AC_HELP_STRING([--with-fast-mutexes], [Compile with fast mutexes (default is disabled)]), diff --git a/sql/handler.h b/sql/handler.h index 5cc2aa126c4..2e96e74afd4 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1378,11 +1378,13 @@ public: virtual void drop_table(const char *name); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; + +#define CHF_DELETE_FLAG 1 +#define CHF_RENAME_FLAG 2 + virtual int create_handler_files(const char *name, const char *old_name, - bool rename_flag) - { - return FALSE; - } + int action_flag) + { return FALSE; } virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, @@ -1390,7 +1392,7 @@ public: ulonglong *deleted, const void *pack_frm_data, uint pack_frm_len) - { print_error(HA_ERR_WRONG_COMMAND, MYF(0)); return TRUE; } + { return HA_ERR_WRONG_COMMAND; } virtual int drop_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } virtual int rename_partitions(const char *path) From c0d1c190f8e08ed5ba431447be8b98abbbfec2ff Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 16:08:59 -0400 Subject: [PATCH 067/101] WL 2826: Error handling of ALTER TABLE for partitioning Fixed a number of bugs sql/sql_table.cc: Fixed a number of bugs --- sql/sql_table.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8e8d430f894..850f473a4c6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -424,9 +424,10 @@ static uint read_ddl_log_header() bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); global_ddl_log.inited= FALSE; global_ddl_log.recovery_phase= TRUE; + global_ddl_log.io_size= IO_SIZE; create_ddl_log_file_name(file_name); - if (!(global_ddl_log.file_id= my_open(file_name, - O_RDWR | O_BINARY, MYF(MY_WME)))) + if ((global_ddl_log.file_id= my_open(file_name, + O_RDWR | O_BINARY, MYF(MY_WME))) >= 0) { if (read_ddl_log_file_entry(0UL)) { @@ -446,7 +447,6 @@ static uint read_ddl_log_header() } else { - global_ddl_log.io_size= IO_SIZE; entry_no= 0; } global_ddl_log.first_free= NULL; @@ -519,6 +519,7 @@ static bool init_ddl_log() DBUG_RETURN(FALSE); } global_ddl_log.io_size= IO_SIZE; + create_ddl_log_file_name(file_name); if ((global_ddl_log.file_id= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC | O_BINARY, @@ -567,18 +568,19 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) } handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); - hton= ha_resolve_by_name(thd, &handler_name); - if (!hton) - { - my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); - DBUG_RETURN(TRUE); - } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); if (strcmp("frm", ddl_log_entry->handler_name)) frm_action= TRUE; else { TABLE_SHARE dummy; + + hton= ha_resolve_by_name(thd, &handler_name); + if (!hton) + { + my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); + goto error; + } bzero(&dummy, sizeof(TABLE_SHARE)); file= get_new_handler(&dummy, &mem_root, hton); if (!file) From 319c5da1523a0b1915ed75ec5e4ae7136e81c1eb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 20:04:00 -0400 Subject: [PATCH 068/101] WL 2826: Error handling of ALTER TABLE for partitioning Various bug fixes (mostly mixed to and from in replace methods) sql/sql_partition.cc: Various bug fixes (mostly mixed to and from in replace methods) sql/sql_table.cc: Various bug fixes (mostly mixed to and from in replace methods) --- sql/sql_partition.cc | 15 ++++----- sql/sql_table.cc | 72 ++++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 7bc654c787d..792a6d33a87 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4733,8 +4733,9 @@ static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry) write_log_replace_delete_frm() lpt Struct for parameters next_entry Next reference to use in log record - path Name to rename from - rename_flag TRUE if rename, else delete + from_path Name to rename from + to_path Name to rename to + replace_flag TRUE if replace, else delete RETURN VALUES TRUE Error FALSE Success @@ -4759,7 +4760,7 @@ static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, else ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; ddl_log_entry.next_entry= next_entry; - ddl_log_entry.handler_name[0]= 0; + ddl_log_entry.handler_name= reg_ext; ddl_log_entry.name= to_path; if (replace_flag) ddl_log_entry.from_name= from_path; @@ -5072,7 +5073,7 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); pthread_mutex_lock(&LOCK_gdl); - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) goto error; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; @@ -5129,8 +5130,8 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) goto error; - if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, - (const char*)tmp_path, TRUE)) + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)tmp_path, + (const char*)path, TRUE)) goto error; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; @@ -5245,7 +5246,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) goto error; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) goto error; - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) goto error; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 096e5c54834..09a54a14b91 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -474,6 +474,7 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) { char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; uint inx; + uchar single_char; DBUG_ENTER("read_ddl_log_entry"); if (read_ddl_log_file_entry(read_entry)) @@ -481,10 +482,10 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) DBUG_RETURN(TRUE); } ddl_log_entry->entry_pos= read_entry; - ddl_log_entry->entry_type= - (enum ddl_log_entry_code)file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; - ddl_log_entry->action_type= - (enum ddl_log_action_code)file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; + ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char; + single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + ddl_log_entry->action_type= (enum ddl_log_action_code)single_char; ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; @@ -553,10 +554,10 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; - handler *file; + handler *file= NULL; MEM_ROOT mem_root; bool error= TRUE; - char path[FN_REFLEN]; + char to_path[FN_REFLEN]; char from_path[FN_REFLEN]; char *par_ext= (char*)".par"; handlerton *hton; @@ -569,7 +570,7 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - if (ddl_log_entry->handler_name[0] == 0) + if (!strcmp(ddl_log_entry->handler_name, reg_ext)) frm_action= TRUE; else { @@ -598,24 +599,29 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { if (frm_action) { - strxmov(path, ddl_log_entry->name, reg_ext, NullS); - if (my_delete(path, MYF(MY_WME))) - break; + strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); + if ((error= my_delete(to_path, MYF(MY_WME)))) + { + if (error != ENOENT) + break; + } #ifdef WITH_PARTITION_STORAGE_ENGINE - strxmov(path, ddl_log_entry->name, par_ext, NullS); - VOID(my_delete(path, MYF(MY_WME))); + strxmov(to_path, ddl_log_entry->name, par_ext, NullS); + VOID(my_delete(to_path, MYF(MY_WME))); #endif } else { - if (file->delete_table(ddl_log_entry->name)) - break; + if ((error= file->delete_table(ddl_log_entry->name))) + { + if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE) + break; + } } if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - { - VOID(sync_ddl_log()); - error= FALSE; - } + break; + VOID(sync_ddl_log()); + error= FALSE; if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) break; } @@ -631,27 +637,26 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) error= TRUE; if (frm_action) { - strxmov(path, ddl_log_entry->name, reg_ext, NullS); + strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); - if (my_rename(path, from_path, MYF(MY_WME))) + if (my_rename(from_path, to_path, MYF(MY_WME))) break; #ifdef WITH_PARTITION_STORAGE_ENGINE - strxmov(path, ddl_log_entry->name, par_ext, NullS); + strxmov(to_path, ddl_log_entry->name, par_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); - VOID(my_rename(path, from_path, MYF(MY_WME))); + VOID(my_rename(from_path, to_path, MYF(MY_WME))); #endif } else { - if (file->rename_table(ddl_log_entry->name, - ddl_log_entry->from_name)) + if (file->rename_table(ddl_log_entry->from_name, + ddl_log_entry->name)) break; } if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - { - VOID(sync_ddl_log()); - error= FALSE; - } + break; + VOID(sync_ddl_log()); + error= FALSE; break; } default: @@ -744,9 +749,10 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, { DBUG_RETURN(TRUE); } - global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_ENTRY_CODE; + global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= + (char)DDL_LOG_ENTRY_CODE; global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= - ddl_log_entry->action_type; + (char)ddl_log_entry->action_type; global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], ddl_log_entry->next_entry); @@ -836,10 +842,10 @@ bool write_execute_ddl_log_entry(uint first_entry, entry to indicate it is done. */ VOID(sync_ddl_log()); - file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_EXECUTE_CODE; + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE; } else - file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE; file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ file_entry_buf[DDL_LOG_PHASE_POS]= 0; int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); @@ -1063,7 +1069,7 @@ void execute_ddl_log_recovery() thd->store_globals(); num_entries= read_ddl_log_header(); - for (i= 0; i < num_entries; i++) + for (i= 1; i < num_entries + 1; i++) { if (read_ddl_log_entry(i, &ddl_log_entry)) { From 66e73768cf9d75c47ec6f8cb17226d213724fa7a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 20:57:42 -0400 Subject: [PATCH 069/101] WL2826: Error handling of ALTER TABLE for partitioning Actual error reported in my_errno from my_delete sql/sql_table.cc: Actual error reported in my_errno from my_delete --- sql/sql_table.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 09a54a14b91..17d3fa909d5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -550,13 +550,13 @@ static bool init_ddl_log() FALSE Success */ -static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) +static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; handler *file= NULL; MEM_ROOT mem_root; - bool error= TRUE; + int error= TRUE; char to_path[FN_REFLEN]; char from_path[FN_REFLEN]; char *par_ext= (char*)".par"; @@ -602,7 +602,7 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); if ((error= my_delete(to_path, MYF(MY_WME)))) { - if (error != ENOENT) + if (my_errno != ENOENT) break; } #ifdef WITH_PARTITION_STORAGE_ENGINE From d9347545b2e475cd92a91a7f0a2a03e03760af07 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 21:43:30 -0400 Subject: [PATCH 070/101] WL 2826: Error handling of ALTER TABLE for partitioning Fixed up create_handler_files call sql/ha_ndbcluster.cc: Fixed up create_handler_files call sql/ha_partition.cc: Fixed up create_handler_files call sql/handler.h: Fixed up create_handler_files call sql/sql_table.cc: Fixed up create_handler_files call sql/unireg.cc: Fixed up create_handler_files call --- sql/ha_ndbcluster.cc | 2 +- sql/ha_partition.cc | 5 +++-- sql/handler.h | 2 ++ sql/sql_table.cc | 13 +++++++------ sql/unireg.cc | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index acb3c109641..ea1ad190570 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4726,7 +4726,7 @@ int ha_ndbcluster::create_handler_files(const char *file, DBUG_ENTER("create_handler_files"); - if (action_flag) + if (action_flag != CHF_INDEX_FLAG) { DBUG_RETURN(FALSE); } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 6dfccca0854..1ab2c4270fd 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -505,7 +505,8 @@ int ha_partition::create_handler_files(const char *path, We need to update total number of parts since we might write the handler file as part of a partition management command */ - if (action_flag) + if (action_flag == CHF_DELETE_FLAG || + action_flag == CHF_RENAME_FLAG) { char name[FN_REFLEN]; char old_name[FN_REFLEN]; @@ -520,7 +521,7 @@ int ha_partition::create_handler_files(const char *path, DBUG_RETURN(TRUE); } } - else + else if (action_flag == CHF_CREATE_FLAG) { if (create_handler_file(path)) { diff --git a/sql/handler.h b/sql/handler.h index 14fa3831b9b..c7c3aa54c3b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1380,8 +1380,10 @@ public: virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; +#define CHF_CREATE_FLAG 0 #define CHF_DELETE_FLAG 1 #define CHF_RENAME_FLAG 2 +#define CHF_INDEX_FLAG 3 virtual int create_handler_files(const char *name, const char *old_name, int action_flag, HA_CREATE_INFO *info) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2b12fc332f2..9fb65451a70 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1233,7 +1233,8 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) lpt->table_name, lpt->create_info, lpt->new_create_list, lpt->key_count, lpt->key_info_buffer, lpt->table->file)) || - lpt->table->file->create_handler_files(shadow_path, NULL, FALSE, + lpt->table->file->create_handler_files(shadow_path, NULL, + CHF_CREATE_FLAG, lpt->create_info)) { my_delete(shadow_frm_name, MYF(0)); @@ -1287,14 +1288,14 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE lpt->table->file->create_handler_files(path, shadow_path, - CHF_DELETE_FLAG) || + CHF_DELETE_FLAG, NULL) || deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || (sync_ddl_log(), FALSE) || #endif #ifdef WITH_PARTITION_STORAGE_ENGINE my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, - CHF_RENAME_FLAG)) + CHF_RENAME_FLAG, NULL)) #else my_rename(shadow_frm_name, frm_name, MYF(MY_WME))) #endif @@ -5717,7 +5718,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(reg_path, NULL, FALSE, + table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, create_info)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) @@ -5764,7 +5765,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(reg_path, NULL, FALSE, + table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, create_info)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) @@ -5989,7 +5990,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); } /* Tell the handler that a new frm file is in place. */ - if (table->file->create_handler_files(reg_path, NULL, FALSE, + if (table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, create_info)) { VOID(pthread_mutex_unlock(&LOCK_open)); diff --git a/sql/unireg.cc b/sql/unireg.cc index ce9d03e3053..bbb4d970d37 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -323,7 +323,7 @@ int rea_create_table(THD *thd, const char *path, // Make sure mysql_create_frm din't remove extension DBUG_ASSERT(*fn_rext(frm_name)); - if (file->create_handler_files(path, NULL, FALSE, create_info)) + if (file->create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) goto err_handler; if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, create_info,0)) From 66ee876ba3b50fba4ed159eb23587bf02fc2d44b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Apr 2006 23:09:49 +0400 Subject: [PATCH 071/101] Applied innodb-4.1-ss22 snapshot. Fix BUG#16814: "SHOW INNODB STATUS format error in LATEST FOREIGN KEY ERROR section" Add a missing newline to the LAST FOREIGN KEY ERROR section in SHOW INNODB STATUS output. Fix BUG#18934: "InnoDB crashes when table uses column names like DB_ROW_ID". Refuse tables that use reserved column names. innobase/dict/dict0dict.c: Applied innodb-4.1-ss22 snapshot. dict_foreign_error_report(): Always print a newline after invoking dict_print_info_on_foreign_key_in_create_format() (Bug#16814). Refuse tables that use reserved column names (Bug#18934). innobase/dict/dict0mem.c: Applied innodb-4.1-ss22 snapshot. Refuse tables that use reserved column names (Bug#18934). innobase/include/dict0dict.h: Applied innodb-4.1-ss22 snapshot. Refuse tables that use reserved column names (Bug#18934). innobase/include/dict0mem.h: Applied innodb-4.1-ss22 snapshot. Refuse tables that use reserved column names (Bug#18934). innobase/include/univ.i: Applied innodb-4.1-ss22 snapshot. innobase/row/row0mysql.c: Applied innodb-4.1-ss22 snapshot. Refuse tables that use reserved column names (Bug#18934). --- innobase/dict/dict0dict.c | 35 ++++++++++++++++++++++++++++++++++- innobase/dict/dict0mem.c | 15 +++++++++++++++ innobase/include/dict0dict.h | 9 +++++++++ innobase/include/dict0mem.h | 7 +++++++ innobase/include/univ.i | 3 +++ innobase/row/row0mysql.c | 14 ++++++++++++++ 6 files changed, 82 insertions(+), 1 deletion(-) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 093df5118af..4b23ce047b2 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -1377,6 +1377,38 @@ dict_col_reposition_in_cache( HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); } +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE.*/ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name) /* in: column name */ +{ + /* This check reminds that if a new system column is added to + the program, it should be dealt with here. */ +#if DATA_N_SYS_COLS != 4 +#error "DATA_N_SYS_COLS != 4" +#endif + + static const char* reserved_names[] = { + "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR", "DB_MIX_ID" + }; + + ulint i; + + for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { + if (strcmp(name, reserved_names[i]) == 0) { + + return(TRUE); + } + } + + return(FALSE); +} + /************************************************************************** Adds an index to the dictionary cache. */ @@ -2160,8 +2192,9 @@ dict_foreign_error_report( fputs(msg, file); fputs(" Constraint:\n", file); dict_print_info_on_foreign_key_in_create_format(file, NULL, fk); + putc('\n', file); if (fk->foreign_index) { - fputs("\nThe index in the foreign key in table is ", file); + fputs("The index in the foreign key in table is ", file); ut_print_name(file, NULL, fk->foreign_index->name); fputs( "\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c index 1d45585aac1..5a2b2e005d0 100644 --- a/innobase/dict/dict0mem.c +++ b/innobase/dict/dict0mem.c @@ -94,6 +94,21 @@ dict_mem_table_create( return(table); } +/******************************************************************** +Free a table memory object. */ + +void +dict_mem_table_free( +/*================*/ + dict_table_t* table) /* in: table */ +{ + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + mutex_free(&(table->autoinc_mutex)); + mem_heap_free(table->heap); +} + /************************************************************************** Creates a cluster memory object. */ diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index bf1382e8bb2..1226055e135 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -98,6 +98,15 @@ ulint dict_col_get_clust_pos( /*===================*/ dict_col_t* col); +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name); /* in: column name */ /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index 1e496a25477..5c3a4ed76d4 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -55,6 +55,13 @@ dict_mem_table_create( is ignored if the table is made a member of a cluster */ ulint n_cols); /* in: number of columns */ +/******************************************************************** +Free a table memory object. */ + +void +dict_mem_table_free( +/*================*/ + dict_table_t* table); /* in: table */ /************************************************************************** Creates a cluster memory object. */ diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 625978ffc38..6939edbcaf8 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -242,6 +242,9 @@ contains the sum of the following flag and the locally stored len. */ #define UNIV_EXTERN_STORAGE_FIELD (UNIV_SQL_NULL - UNIV_PAGE_SIZE) +/* Compile-time constant of the given array's size. */ +#define UT_ARR_SIZE(a) (sizeof(a) / sizeof((a)[0])) + #include #include "ut0dbg.h" #include "ut0ut.h" diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index ba50e6a3511..23d019b6f78 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1474,6 +1474,7 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; + ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1510,6 +1511,19 @@ row_create_table_for_mysql( return(DB_ERROR); } + /* Check that no reserved column names are used. */ + for (i = 0; i < dict_table_get_n_user_cols(table); i++) { + dict_col_t* col = dict_table_get_nth_col(table, i); + + if (dict_col_name_is_reserved(col->name)) { + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + return(DB_ERROR); + } + } + trx_start_if_not_started(trx); if (row_mysql_is_recovered_tmp_table(table->name)) { From 7ee05d7c713c0958cd56248b7b7397d72fea3941 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 01:07:37 +0400 Subject: [PATCH 072/101] Applied innodb-5.0-ss476 snapshot. Fix BUG#18934: "InnoDB crashes when table uses column like DB_ROW_ID". Also, fix memory leaks in row_create_table_for_mysql() in rare corner cases. innobase/dict/dict0dict.c: Applied innodb-5.0-ss476 snapshot. Refuse tables that use reserved column names (Bug#18934). innobase/dict/dict0load.c: Applied innodb-5.0-ss476 snapshot. dict_load_table(): Refuse to load tables with other TYPE than DICT_TABLE_ORDINARY. innobase/dict/dict0mem.c: Applied innodb-5.0-ss476 snapshot. Add dict_mem_table_free(), use it instead of duplicating the code everywhere. innobase/ibuf/ibuf0ibuf.c: Applied innodb-5.0-ss476 snapshot. innobase/include/dict0dict.h: Applied innodb-5.0-ss476 snapshot. Refuse tables that use reserved column name (Bug#18934). innobase/include/dict0mem.h: Applied innodb-5.0-ss476 snapshot. Add dict_mem_table_free(), use it instead of duplicating the code everywhere. innobase/include/univ.i: Applied innodb-5.0-ss476 snapshot. innobase/log/log0recv.c: Applied innodb-5.0-ss476 snapshot. innobase/row/row0mysql.c: Applied innodb-5.0-ss476 snapshot. Refuse tables that use reserved column names (Bug#18934). mysql-test/r/innodb.result: Applied innodb-5.0-ss476 snapshot. Fix result for test case for Bug#18934. (Other changes are to be restored by the next cset). mysql-test/t/innodb.test: Applied innodb-5.0-ss476 snapshot. Fix result for test case for Bug#18934. (Removed test case for Bug#14360 is to be restored by the next cset). --- innobase/dict/dict0dict.c | 38 ++++++++++++++++++++++++++++++++---- innobase/dict/dict0load.c | 17 ++++++++++------ innobase/dict/dict0mem.c | 18 +++++++++++++++++ innobase/ibuf/ibuf0ibuf.c | 6 +++--- innobase/include/dict0dict.h | 9 +++++++++ innobase/include/dict0mem.h | 7 +++++++ innobase/include/univ.i | 3 +++ innobase/log/log0recv.c | 6 +++--- innobase/row/row0mysql.c | 18 +++++++++++++++++ mysql-test/r/innodb.result | 13 +++--------- mysql-test/t/innodb.test | 14 +++---------- 11 files changed, 112 insertions(+), 37 deletions(-) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 653addd9ede..bad8886d0be 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -1249,15 +1249,13 @@ dict_table_remove_from_cache( /* Remove table from LRU list of tables */ UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); - mutex_free(&(table->autoinc_mutex)); - size = mem_heap_get_size(table->heap); ut_ad(dict_sys->size >= size); dict_sys->size -= size; - mem_heap_free(table->heap); + dict_mem_table_free(table); } /************************************************************************** @@ -1378,6 +1376,38 @@ dict_col_reposition_in_cache( HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); } +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name) /* in: column name */ +{ + /* This check reminds that if a new system column is added to + the program, it should be dealt with here. */ +#if DATA_N_SYS_COLS != 4 +#error "DATA_N_SYS_COLS != 4" +#endif + + static const char* reserved_names[] = { + "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR", "DB_MIX_ID" + }; + + ulint i; + + for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { + if (strcmp(name, reserved_names[i]) == 0) { + + return(TRUE); + } + } + + return(FALSE); +} + /************************************************************************** Adds an index to the dictionary cache. */ @@ -1551,7 +1581,7 @@ dict_index_remove_from_cache( dict_sys->size -= size; - mem_heap_free(index->heap); + dict_mem_index_free(index); } /*********************************************************************** diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 6415cc56b61..bd93a719f6c 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -767,7 +767,7 @@ dict_load_table( if (!btr_pcur_is_on_user_rec(&pcur, &mtr) || rec_get_deleted_flag(rec, sys_tables->comp)) { /* Not found */ - + err_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); @@ -779,11 +779,8 @@ dict_load_table( /* Check if the table name in record is the searched one */ if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); + + goto err_exit; } ut_a(0 == ut_strcmp("SPACE", @@ -844,6 +841,14 @@ dict_load_table( field = rec_get_nth_field_old(rec, 5, &len); table->type = mach_read_from_4(field); + if (UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: table %s: unknown table type %lu\n", + name, (ulong) table->type); + goto err_exit; + } + if (table->type == DICT_TABLE_CLUSTER_MEMBER) { ut_error; #if 0 /* clustered tables have not been implemented yet */ diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c index eec35310039..98ef44a4969 100644 --- a/innobase/dict/dict0mem.c +++ b/innobase/dict/dict0mem.c @@ -97,6 +97,21 @@ dict_mem_table_create( return(table); } +/******************************************************************** +Free a table memory object. */ + +void +dict_mem_table_free( +/*================*/ + dict_table_t* table) /* in: table */ +{ + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + mutex_free(&(table->autoinc_mutex)); + mem_heap_free(table->heap); +} + /************************************************************************** Creates a cluster memory object. */ @@ -290,5 +305,8 @@ dict_mem_index_free( /*================*/ dict_index_t* index) /* in: index */ { + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + mem_heap_free(index->heap); } diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c index d7fa48b6e66..e4694ed52ae 100644 --- a/innobase/ibuf/ibuf0ibuf.c +++ b/innobase/ibuf/ibuf0ibuf.c @@ -1160,9 +1160,9 @@ ibuf_dummy_index_free( dict_index_t* index) /* in: dummy index */ { dict_table_t* table = index->table; - mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - mem_heap_free(table->heap); + + dict_mem_index_free(index); + dict_mem_table_free(table); } /************************************************************************* diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 4396611e529..642037494b5 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -98,6 +98,15 @@ ulint dict_col_get_clust_pos( /*===================*/ dict_col_t* col); +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name); /* in: column name */ /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index 7eec86d0bcb..3c10e82342b 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -56,6 +56,13 @@ dict_mem_table_create( a member of a cluster */ ulint n_cols, /* in: number of columns */ ibool comp); /* in: TRUE=compact page format */ +/******************************************************************** +Free a table memory object. */ + +void +dict_mem_table_free( +/*================*/ + dict_table_t* table); /* in: table */ /************************************************************************** Creates a cluster memory object. */ diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 04b254a8221..bc3bd031f0c 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -261,6 +261,9 @@ it is read or written. */ /* Tell the compiler that cond is unlikely to hold */ #define UNIV_UNLIKELY(cond) UNIV_EXPECT(cond, FALSE) +/* Compile-time constant of the given array's size. */ +#define UT_ARR_SIZE(a) (sizeof(a) / sizeof((a)[0])) + #include #include "ut0dbg.h" #include "ut0ut.h" diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 42e854398ba..7c56fe35d48 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -890,9 +890,9 @@ recv_parse_or_apply_log_rec_body( ut_ad(!page || ptr); if (index) { dict_table_t* table = index->table; - mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - mem_heap_free(table->heap); + + dict_mem_index_free(index); + dict_mem_table_free(table); } return(ptr); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 937056c300e..89b82882d93 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1673,7 +1673,9 @@ row_mysql_recover_tmp_table( if (!ptr) { /* table name does not begin with "/rsql" */ + dict_mem_table_free(table); trx_commit_for_mysql(trx); + return(DB_ERROR); } else { @@ -1785,6 +1787,7 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; + ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1802,6 +1805,7 @@ row_create_table_for_mysql( "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); + dict_mem_table_free(table); trx_commit_for_mysql(trx); return(DB_ERROR); @@ -1816,11 +1820,25 @@ row_create_table_for_mysql( "InnoDB: MySQL system tables must be of the MyISAM type!\n", table->name); + dict_mem_table_free(table); trx_commit_for_mysql(trx); return(DB_ERROR); } + /* Check that no reserved column names are used. */ + for (i = 0; i < dict_table_get_n_user_cols(table); i++) { + dict_col_t* col = dict_table_get_nth_col(table, i); + + if (dict_col_name_is_reserved(col->name)) { + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + return(DB_ERROR); + } + } + trx_start_if_not_started(trx); if (row_mysql_is_recovered_tmp_table(table->name)) { diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 9a190557211..e8953a18a2e 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1821,7 +1821,7 @@ Variable_name Value innodb_sync_spin_loops 20 show variables like "innodb_thread_concurrency"; Variable_name Value -innodb_thread_concurrency 8 +innodb_thread_concurrency 0 set global innodb_thread_concurrency=1001; show variables like "innodb_thread_concurrency"; Variable_name Value @@ -3232,12 +3232,5 @@ drop trigger t2t; drop trigger t3t; drop trigger t4t; drop table t1, t2, t3, t4, t5; -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 -where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -a a -2005-10-01 2005-10-01 -drop table t1, t2; +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table './test/t1.frm' (errno: -1) diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index b0835cd8419..df3b473dcc0 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2128,14 +2128,6 @@ connection default; disconnect a; disconnect b; -# -# Bug #14360: problem with intervals -# - -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 - where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -drop table t1, t2; +# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID" +--error 1005 +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; From 43690501264081229fc91f66600e1b11b40994cc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 01:37:31 +0400 Subject: [PATCH 073/101] Restoring changes erroneously removed by applying the innodb-5.0-ss476 snapshot. --- mysql-test/r/innodb.result | 11 ++++++++++- mysql-test/t/innodb.test | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index e8953a18a2e..27e527c43ee 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1821,7 +1821,7 @@ Variable_name Value innodb_sync_spin_loops 20 show variables like "innodb_thread_concurrency"; Variable_name Value -innodb_thread_concurrency 0 +innodb_thread_concurrency 8 set global innodb_thread_concurrency=1001; show variables like "innodb_thread_concurrency"; Variable_name Value @@ -3232,5 +3232,14 @@ drop trigger t2t; drop trigger t3t; drop trigger t4t; drop table t1, t2, t3, t4, t5; +create table t1(a date) engine=innodb; +create table t2(a date, key(a)) engine=innodb; +insert into t1 values('2005-10-01'); +insert into t2 values('2005-10-01'); +select * from t1, t2 +where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; +a a +2005-10-01 2005-10-01 +drop table t1, t2; CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; ERROR HY000: Can't create table './test/t1.frm' (errno: -1) diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index df3b473dcc0..ccd2be5cdba 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2128,6 +2128,18 @@ connection default; disconnect a; disconnect b; +# +# Bug #14360: problem with intervals +# + +create table t1(a date) engine=innodb; +create table t2(a date, key(a)) engine=innodb; +insert into t1 values('2005-10-01'); +insert into t2 values('2005-10-01'); +select * from t1, t2 + where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; +drop table t1, t2; + # bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID" --error 1005 CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; From 6d8f22effea7422160191ea87f017ee1f1110b85 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 06:40:47 +0200 Subject: [PATCH 074/101] ndb - fix memory corruption in event-api maybe bug fix for 18621, 19154, 19172, 19174 storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: Make sure that nasty c++ features arent run on Gci_container as it's supposed to be POD! storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp: Make sure that nasty c++ features arent run on Gci_container as it's supposed to be POD! --- .../ndb/src/ndbapi/NdbEventOperationImpl.cpp | 34 +++++++++++++------ .../ndb/src/ndbapi/NdbEventOperationImpl.hpp | 7 +++- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index 25fc62937c4..36037fba9ed 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -46,7 +46,7 @@ #include extern EventLogger g_eventLogger; -static Gci_container g_empty_gci_container; +static Gci_container_pod g_empty_gci_container; static const Uint32 ACTIVE_GCI_DIRECTORY_SIZE = 4; static const Uint32 ACTIVE_GCI_MASK = ACTIVE_GCI_DIRECTORY_SIZE - 1; @@ -1223,12 +1223,22 @@ operator<<(NdbOut& out, const Gci_container& gci) return out; } +static +NdbOut& +operator<<(NdbOut& out, const Gci_container_pod& gci) +{ + Gci_container* ptr = (Gci_container*)&gci; + out << *ptr; + return out; +} + + static Gci_container* -find_bucket_chained(Vector * active, Uint64 gci) +find_bucket_chained(Vector * active, Uint64 gci) { Uint32 pos = (gci & ACTIVE_GCI_MASK); - Gci_container *bucket= active->getBase() + pos; + Gci_container *bucket= ((Gci_container*)active->getBase()) + pos; if(gci > bucket->m_gci) { @@ -1237,8 +1247,9 @@ find_bucket_chained(Vector * active, Uint64 gci) do { active->fill(move_pos, g_empty_gci_container); - bucket = active->getBase() + pos; // Needs to recomputed after fill - move = active->getBase() + move_pos; + // Needs to recomputed after fill + bucket = ((Gci_container*)active->getBase()) + pos; + move = ((Gci_container*)active->getBase()) + move_pos; if(move->m_gcp_complete_rep_count == 0) { memcpy(move, bucket, sizeof(Gci_container)); @@ -1269,10 +1280,10 @@ find_bucket_chained(Vector * active, Uint64 gci) inline Gci_container* -find_bucket(Vector * active, Uint64 gci) +find_bucket(Vector * active, Uint64 gci) { Uint32 pos = (gci & ACTIVE_GCI_MASK); - Gci_container *bucket= active->getBase() + pos; + Gci_container *bucket= ((Gci_container*)active->getBase()) + pos; if(likely(gci == bucket->m_gci)) return bucket; @@ -1370,7 +1381,8 @@ NdbEventBuffer::execSUB_GCP_COMPLETE_REP(const SubGcpCompleteRep * const rep) { /** out of order something */ ndbout_c("out of order bucket: %d gci: %lld m_latestGCI: %lld", - bucket-m_active_gci.getBase(), gci, m_latestGCI); + bucket-(Gci_container*)m_active_gci.getBase(), + gci, m_latestGCI); bucket->m_state = Gci_container::GC_COMPLETE; bucket->m_gcp_complete_rep_count = 1; // Prevent from being reused m_latest_complete_GCI = gci; @@ -1387,7 +1399,7 @@ NdbEventBuffer::complete_outof_order_gcis() Uint64 stop_gci = m_latest_complete_GCI; const Uint32 size = m_active_gci.size(); - Gci_container* array= m_active_gci.getBase(); + Gci_container* array= (Gci_container*)m_active_gci.getBase(); ndbout_c("complete_outof_order_gcis"); for(Uint32 i = 0; i; +template class Vector; template class Vector; diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp index bffc2174be5..8d413cc8d14 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp @@ -272,6 +272,11 @@ struct Gci_container EventBufData_hash m_data_hash; }; +struct Gci_container_pod +{ + char data[sizeof(Gci_container)]; +}; + class NdbEventOperationImpl : public NdbEventOperation { public: NdbEventOperationImpl(NdbEventOperation &f, @@ -365,7 +370,7 @@ public: ~NdbEventBuffer(); const Uint32 &m_system_nodes; - Vector m_active_gci; + Vector m_active_gci; NdbEventOperation *createEventOperation(const char* eventName, NdbError &); NdbEventOperationImpl *createEventOperation(NdbEventImpl& evnt, From 3cb33e444a0acbafb3bf506ae456a04822c314fd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 06:51:58 +0200 Subject: [PATCH 075/101] ndb - fix bug#19244, dd page got locked in page cache likely fix bug 18780 storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp: Fix so that insert/delete on DD does not lock page forever in memory storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp: Set page to dirty when aborting prealloc --- .../src/kernel/blocks/dbtup/DbtupCommit.cpp | 33 ++++++++++++++++--- .../kernel/blocks/dbtup/DbtupDiskAlloc.cpp | 8 +++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp index 782679eac18..fc3419e694a 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp @@ -473,13 +473,16 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) ptrCheckGuard(regTabPtr, no_of_tablerec, tablerec); PagePtr page; - Tuple_header* tuple_ptr= 0; + Tuple_header* tuple_ptr= (Tuple_header*) + get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p); + + bool get_page = false; if(regOperPtr.p->op_struct.m_load_diskpage_on_commit) { + Page_cache_client::Request req; ndbassert(regOperPtr.p->is_first_operation() && regOperPtr.p->is_last_operation()); - Page_cache_client::Request req; /** * Check for page */ @@ -490,15 +493,33 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) memcpy(&req.m_page, tmp->get_disk_ref_ptr(regTabPtr.p), sizeof(Local_key)); + + if (unlikely(regOperPtr.p->op_struct.op_type == ZDELETE && + tmp->m_header_bits & Tuple_header::DISK_ALLOC)) + { + jam(); + /** + * Insert+Delete + */ + regOperPtr.p->op_struct.m_load_diskpage_on_commit = 0; + regOperPtr.p->op_struct.m_wait_log_buffer = 0; + disk_page_abort_prealloc(signal, regFragPtr.p, + &req.m_page, req.m_page.m_page_idx); + + c_lgman->free_log_space(regFragPtr.p->m_logfile_group_id, + regOperPtr.p->m_undo_buffer_space); + ndbout_c("insert+delete"); + goto skip_disk; + } } else { // initial delete ndbassert(regOperPtr.p->op_struct.op_type == ZDELETE); - tuple_ptr= (Tuple_header*) - get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p); memcpy(&req.m_page, tuple_ptr->get_disk_ref_ptr(regTabPtr.p), sizeof(Local_key)); + + ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); } req.m_callback.m_callbackData= regOperPtr.i; req.m_callback.m_callbackFunction = @@ -522,6 +543,7 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) ndbrequire("NOT YET IMPLEMENTED" == 0); break; } + get_page = true; disk_page_set_dirty(*(Ptr*)&m_pgman.m_ptr); regOperPtr.p->m_commit_disk_callback_page= res; regOperPtr.p->op_struct.m_load_diskpage_on_commit= 0; @@ -555,6 +577,7 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) tuple_ptr = (Tuple_header*) get_ptr(&page, ®OperPtr.p->m_tuple_location,regTabPtr.p); } +skip_disk: req_struct.m_tuple_ptr = tuple_ptr; if(get_tuple_state(regOperPtr.p) == TUPLE_PREPARED) @@ -599,6 +622,8 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) else { removeActiveOpList(regOperPtr.p, tuple_ptr); + if (get_page) + ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); dealloc_tuple(signal, gci, page.p, tuple_ptr, regOperPtr.p, regFragPtr.p, regTabPtr.p); } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp index d74e4b6811e..ec3231f55f5 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp @@ -1053,6 +1053,7 @@ Dbtup::disk_page_abort_prealloc_callback(Signal* signal, Ptr fragPtr; getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p); + disk_page_set_dirty(pagePtr); disk_page_abort_prealloc_callback_1(signal, fragPtr.p, pagePtr, sz); } @@ -1074,6 +1075,13 @@ Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, ddassert(alloc.calc_page_free_bits(free - used) == old_idx); Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz); +#ifdef VM_TRACE + Local_key key; + key.m_page_no = pagePtr.p->m_page_no; + key.m_file_no = pagePtr.p->m_file_no; + ndbout << "disk_page_abort_prealloc_callback_1" << key << endl; +#endif + Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); if (old_idx != new_idx) From 7aaeb9f97a1ea422c237b5ab51ee8b132acb0c33 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 08:53:25 +0200 Subject: [PATCH 076/101] added missing install paths for new files --- mysql-test/Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 8ddf7668844..f8738f83267 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -43,6 +43,8 @@ dist-hook: $(distdir)/r \ $(distdir)/include \ $(distdir)/std_data \ + $(distdir)/std_data/ndb_backup50 \ + $(distdir)/std_data/ndb_backup51 \ $(distdir)/lib -$(INSTALL_DATA) $(srcdir)/t/*.def $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t @@ -63,6 +65,8 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(distdir)/std_data/ndb_backup50 + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(distdir)/std_data/ndb_backup51 $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(distdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib @@ -98,6 +102,8 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(testdir)/std_data/ndb_backup50 + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(testdir)/std_data/ndb_backup51 $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib From 4a90a6583b66a31cd930eaf26cd1bffc40831e6b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 09:09:33 +0200 Subject: [PATCH 077/101] ndb - bug#19245 A-insert/B-insert/A-rollback/B-rollback leads to node crash, as bits in tuple header gets incorrectly assigned in second insert this also likely fixes bug 18589 and explains 18808 storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp: remove debug printout storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp: Make sure that alloc bit is set if insert and first_op storage/ndb/test/ndbapi/testBasic.cpp: testcase for bug#19245 storage/ndb/test/run-test/daily-basic-tests.txt: testcase for bug#19245 --- .../src/kernel/blocks/dbtup/DbtupAbort.cpp | 1 - .../kernel/blocks/dbtup/DbtupExecQuery.cpp | 4 ++ storage/ndb/test/ndbapi/testBasic.cpp | 39 +++++++++++++++++++ .../ndb/test/run-test/daily-basic-tests.txt | 4 ++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp index 4e507d1b690..273ccb9e1e6 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp @@ -170,7 +170,6 @@ void Dbtup::execTUP_ABORTREQ(Signal* signal) /** * Aborting last operation that performed ALLOC */ - ndbout_c("clearing ALLOC"); tuple_ptr->m_header_bits &= ~(Uint32)Tuple_header::ALLOC; tuple_ptr->m_header_bits |= Tuple_header::FREED; } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 7305827b6ac..de497ed2c2d 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1407,6 +1407,8 @@ int Dbtup::handleInsertReq(Signal* signal, } req_struct->m_use_rowid = false; base->m_header_bits &= ~(Uint32)Tuple_header::FREE; + base->m_header_bits |= Tuple_header::ALLOC & + (regOperPtr.p->is_first_operation() ? ~0 : 1); } else { @@ -1415,6 +1417,8 @@ int Dbtup::handleInsertReq(Signal* signal, { ndbout_c("no mem insert but rowid (same)"); base->m_header_bits &= ~(Uint32)Tuple_header::FREE; + base->m_header_bits |= Tuple_header::ALLOC & + (regOperPtr.p->is_first_operation() ? ~0 : 1); } else { diff --git a/storage/ndb/test/ndbapi/testBasic.cpp b/storage/ndb/test/ndbapi/testBasic.cpp index 879a4979220..69f3d8daef6 100644 --- a/storage/ndb/test/ndbapi/testBasic.cpp +++ b/storage/ndb/test/ndbapi/testBasic.cpp @@ -1034,6 +1034,38 @@ runMassiveRollback2(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int +runMassiveRollback3(NDBT_Context* ctx, NDBT_Step* step){ + + int result = NDBT_OK; + HugoOperations hugoOps(*ctx->getTab()); + Ndb* pNdb = GETNDB(step); + + const Uint32 BATCH = 10; + const Uint32 OPS_TOTAL = 20; + const Uint32 LOOPS = 100; + + for(Uint32 loop = 0; loop Date: Fri, 21 Apr 2006 09:43:21 +0200 Subject: [PATCH 078/101] added one more missing install path for new files --- mysql-test/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index f8738f83267..d8a95115d4e 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -78,6 +78,8 @@ install-data-local: $(DESTDIR)$(testdir)/r \ $(DESTDIR)$(testdir)/include \ $(DESTDIR)$(testdir)/std_data \ + $(DESTDIR)$(testdir)/std_data/ndb_backup50 \ + $(DESTDIR)$(testdir)/std_data/ndb_backup51 \ $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir) -$(INSTALL_DATA) $(srcdir)/t/*.def $(DESTDIR)$(testdir)/t From 8e7d5f789acf37c49671ceb42d4f114ae3414b3a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 11:26:21 +0200 Subject: [PATCH 079/101] bug#18594 ndb_restore log boken in 5.1 - corrected previous patch - read log entry variables out into explicit variables for siimpler code (and backwards compatability code) --- storage/ndb/tools/restore/Restore.cpp | 86 ++++++++++++--------------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/storage/ndb/tools/restore/Restore.cpp b/storage/ndb/tools/restore/Restore.cpp index 6bb790b2d69..7e240976067 100644 --- a/storage/ndb/tools/restore/Restore.cpp +++ b/storage/ndb/tools/restore/Restore.cpp @@ -961,15 +961,15 @@ RestoreLogIterator::RestoreLogIterator(const RestoreMetaData & md) const LogEntry * RestoreLogIterator::getNextLogEntry(int & res) { // Read record length - typedef BackupFormat::LogFile::LogEntry LogE; - typedef BackupFormat::LogFile::LogEntry_no_fragid LogE_no_fragid; - const Uint32 offset= 3; - assert(offset == (offsetof(LogE, Data) >> 2) - 1); - LogE * logE= 0; - Uint32 len= ~0; const Uint32 stopGCP = m_metaData.getStopGCP(); - NdbAutoPtr ap1; + Uint32 tableId; + Uint32 triggerEvent; + Uint32 frag_id; + Uint32 *attr_data; + Uint32 attr_data_len; do { + Uint32 len; + Uint32 *logEntryPtr; if (buffer_read_ahead(&len, sizeof(Uint32), 1) != 1){ res= -1; return 0; @@ -977,7 +977,7 @@ RestoreLogIterator::getNextLogEntry(int & res) { len= ntohl(len); Uint32 data_len = sizeof(Uint32) + len*4; - if (buffer_get_ptr((void **)(&logE), 1, data_len) != data_len) { + if (buffer_get_ptr((void **)(&logEntryPtr), 1, data_len) != data_len) { res= -2; return 0; } @@ -986,7 +986,8 @@ RestoreLogIterator::getNextLogEntry(int & res) { res= 0; return 0; } - if (m_metaData.getFileHeader().NdbVersion < NDBD_FRAGID_VERSION) + + if (unlikely(m_metaData.getFileHeader().NdbVersion < NDBD_FRAGID_VERSION)) { /* FragId was introduced in LogEntry in version @@ -994,48 +995,39 @@ RestoreLogIterator::getNextLogEntry(int & res) { We set FragId to 0 in older versions (these versions do not support restore of user defined partitioned tables. - - These log entries miss one Uint32 FragId, hence missing_len=1 - - Reconstruct a new log entry with old. */ - const Uint32 missing_len= 1; - assert((offsetof(LogE, Data) - offsetof(LogE_no_fragid, Data)) >> 2 == - missing_len); - LogE_no_fragid * logE_no_fragid= (LogE_no_fragid *)logE; - - int i; - LogE *tmpLogE= (LogE*)NdbMem_Allocate(data_len + missing_len*4); - if (!tmpLogE) - { - res = -2; - return 0; - } - ap1.reset((char*)tmpLogE); - bzero(tmpLogE, data_len + missing_len*4); - /* correct len to reflect new logEntry version length */ - len+= missing_len; - tmpLogE->Length = logE_no_fragid->Length; - tmpLogE->TableId = logE_no_fragid->TableId; - tmpLogE->TriggerEvent = logE_no_fragid->TriggerEvent; - for (i = 0; i < len - offset; i++) - tmpLogE->Data[i] = logE_no_fragid->Data[i]; - logE= tmpLogE; + typedef BackupFormat::LogFile::LogEntry_no_fragid LogE_no_fragid; + LogE_no_fragid * logE_no_fragid= (LogE_no_fragid *)logEntryPtr; + tableId= ntohl(logE_no_fragid->TableId); + triggerEvent= ntohl(logE_no_fragid->TriggerEvent); + frag_id= 0; + attr_data= &logE_no_fragid->Data[0]; + attr_data_len= len - ((offsetof(LogE_no_fragid, Data) >> 2) - 1); + } + else /* normal case */ + { + typedef BackupFormat::LogFile::LogEntry LogE; + LogE * logE= (LogE *)logEntryPtr; + tableId= ntohl(logE->TableId); + triggerEvent= ntohl(logE->TriggerEvent); + frag_id= ntohl(logE->FragId); + attr_data= &logE->Data[0]; + attr_data_len= len - ((offsetof(LogE, Data) >> 2) - 1); } - logE->TableId= ntohl(logE->TableId); - logE->TriggerEvent= ntohl(logE->TriggerEvent); - - const bool hasGcp= (logE->TriggerEvent & 0x10000) != 0; - logE->TriggerEvent &= 0xFFFF; + const bool hasGcp= (triggerEvent & 0x10000) != 0; + triggerEvent &= 0xFFFF; + if(hasGcp){ + // last attr_data is gci info + attr_data_len--; len--; - m_last_gci = ntohl(logE->Data[len-offset]); + m_last_gci = ntohl(*(attr_data + attr_data_len)); } } while(m_last_gci > stopGCP + 1); - - m_logEntry.m_table = m_metaData.getTable(logE->TableId); - switch(logE->TriggerEvent){ + + m_logEntry.m_table = m_metaData.getTable(tableId); + switch(triggerEvent){ case TriggerEvent::TE_INSERT: m_logEntry.m_type = LogEntry::LE_INSERT; break; @@ -1053,10 +1045,10 @@ RestoreLogIterator::getNextLogEntry(int & res) { const TableS * tab = m_logEntry.m_table; m_logEntry.clear(); - AttributeHeader * ah = (AttributeHeader *)&logE->Data[0]; - AttributeHeader *end = (AttributeHeader *)&logE->Data[len - offset]; + AttributeHeader * ah = (AttributeHeader *)attr_data; + AttributeHeader *end = (AttributeHeader *)(attr_data + attr_data_len); AttributeS * attr; - m_logEntry.m_frag_id = ntohl(logE->FragId); + m_logEntry.m_frag_id = frag_id; while(ah < end){ attr= m_logEntry.add_attr(); if(attr == NULL) { From f5c2191c713c6bc3f49a652098a9f6b82c6f800b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 13:51:58 +0200 Subject: [PATCH 080/101] ndb: corrected install dir ndb: corrected initialization of records mysql-test/Makefile.am: ndb: corrected install dir sql/ha_ndbcluster.cc: ndb: corrected initialization of records --- mysql-test/Makefile.am | 4 ++-- sql/ha_ndbcluster.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index d8a95115d4e..5aaddf36aa3 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -104,8 +104,8 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data - $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(testdir)/std_data/ndb_backup50 - $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(testdir)/std_data/ndb_backup51 + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup50 + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup51 $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 3d0e6df2831..c664d0b4590 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -384,14 +384,14 @@ Thd_ndb::get_open_table(THD *thd, const void *key) thd_ndb_share->key= key; thd_ndb_share->stat.last_count= count; thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records == ~(ha_rows)0; + thd_ndb_share->stat.records= ~(ha_rows)0; my_hash_insert(&open_tables, (byte *)thd_ndb_share); } else if (thd_ndb_share->stat.last_count != count) { thd_ndb_share->stat.last_count= count; thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records == ~(ha_rows)0; + thd_ndb_share->stat.records= ~(ha_rows)0; } DBUG_PRINT("exit", ("thd_ndb_share: 0x%x key: 0x%x", thd_ndb_share, key)); DBUG_RETURN(thd_ndb_share); From 0a22763fa621e0d376e3e72febe2ad5df008a202 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 13:53:48 +0200 Subject: [PATCH 081/101] Bug #17230 Can't change character-sets-dir for ndbd --- mysql-test/mysql-test-run.pl | 3 ++- mysql-test/mysql-test-run.sh | 2 +- mysql-test/ndb/ndbcluster.sh | 6 +++++- ndb/include/util/ndb_opts.h | 6 +++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index a045441e046..ea0e11a69d9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1457,7 +1457,8 @@ sub ndbcluster_start ($) { # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", - "--data-dir=$opt_vardir"], + "--data-dir=$opt_vardir", + "--character-sets-dir=$path_charsetsdir"], "", "/dev/null", "", "") ) { mtr_error("Error ndbcluster_start"); diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index d7e976f9d49..ba4d922413c 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -1241,7 +1241,7 @@ start_ndbcluster() else NDBCLUSTER_EXTRA_OPTS="--small" fi - ./ndb/ndbcluster $NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --initial || NDB_STATUS_OK=0 + ./ndb/ndbcluster $NDBCLUSTER_OPTS --character-sets-dir=$CHARSETSDIR $NDBCLUSTER_EXTRA_OPTS --initial || NDB_STATUS_OK=0 if [ x$NDB_STATUS_OK != x1 ] ; then if [ x$FORCE != x1 ] ; then exit 1 diff --git a/mysql-test/ndb/ndbcluster.sh b/mysql-test/ndb/ndbcluster.sh index c09c013552e..ad01f6574cf 100644 --- a/mysql-test/ndb/ndbcluster.sh +++ b/mysql-test/ndb/ndbcluster.sh @@ -60,6 +60,7 @@ ndb_imem=24M NDB_MGM_EXTRA_OPTS= NDB_MGMD_EXTRA_OPTS= NDBD_EXTRA_OPTS= +CHARSETSDIR= while test $# -gt 0; do case "$1" in @@ -106,6 +107,9 @@ while test $# -gt 0; do --ndbd-extra-opts=*) NDBD_EXTRA_OPTS=`echo "$1" | sed -e "s;--ndbd-extra-opts=;;"` ;; + --character-sets-dir=*) + CHARSETSDIR=`echo "$1" | sed -e "s;--character-sets-dir=;;"` + ;; -- ) shift; break ;; --* ) $ECHO "Unrecognized option: $1"; exit 1 ;; * ) break ;; @@ -135,7 +139,7 @@ fi exec_mgmtclient="$exec_mgmtclient --no-defaults $NDB_MGM_EXTRA_OPTS" exec_mgmtsrvr="$exec_mgmtsrvr --no-defaults $NDB_MGMD_EXTRA_OPTS" -exec_ndb="$exec_ndb --no-defaults $NDBD_EXTRA_OPTS" +exec_ndb="$exec_ndb --no-defaults $NDBD_EXTRA_OPTS --character-sets-dir=$CHARSETSDIR" exec_waiter="$exec_waiter --no-defaults" ndb_host="localhost" diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index 787c32f06fd..08ab4a2e9df 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -84,7 +84,10 @@ const char *opt_debug= 0; 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ { "core-file", OPT_WANT_CORE, "Write core on errors.",\ (gptr*) &opt_core, (gptr*) &opt_core, 0,\ - GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0} + GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0},\ + {"character-sets-dir", OPT_CHARSETS_DIR,\ + "Directory where character sets are.", (gptr*) &charsets_dir,\ + (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}\ #ifndef DBUG_OFF #define NDB_STD_OPTS(prog_name) \ @@ -111,6 +114,7 @@ enum ndb_std_options { OPT_WANT_CORE, OPT_NDB_MGMD, OPT_NDB_NODEID, + OPT_CHARSETS_DIR, NDB_STD_OPTIONS_LAST /* should always be last in this enum */ }; From 86b74da608b1ce58f4351abd88ff3ba5567f5313 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 13:58:55 +0200 Subject: [PATCH 082/101] ndb - Fix error handling when out of diskspace storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp: Fix error handling when out of diskspace --- .../ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index de497ed2c2d..ff917c8482d 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1382,8 +1382,9 @@ int Dbtup::handleInsertReq(Signal* signal, regOperPtr.p->userpointer, ®OperPtr.p->m_tuple_location); - ((Tuple_header*)ptr)->m_operation_ptr_i= regOperPtr.i; - ((Tuple_header*)ptr)->m_header_bits= Tuple_header::ALLOC | + base = (Tuple_header*)ptr; + base->m_operation_ptr_i= regOperPtr.i; + base->m_header_bits= Tuple_header::ALLOC | (varsize ? Tuple_header::CHAINED_ROW : 0); regOperPtr.p->m_tuple_location.m_page_no = real_page_id; } @@ -1471,7 +1472,7 @@ int Dbtup::handleInsertReq(Signal* signal, size_change_error: jam(); terrorCode = ZMEM_NOMEM_ERROR; - goto disk_prealloc_error; + goto exit_error; undo_buffer_error: jam(); @@ -1505,9 +1506,13 @@ update_error: regOperPtr.p->op_struct.in_active_list = false; regOperPtr.p->m_tuple_location.setNull(); } -disk_prealloc_error: +exit_error: tupkeyErrorLab(signal); return -1; + +disk_prealloc_error: + base->m_header_bits |= Tuple_header::FREED; + goto exit_error; } /* ---------------------------------------------------------------- */ From 3cd43eb425c30dca2f140c0e0caa0e15f8a3ad20 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 14:13:19 +0200 Subject: [PATCH 083/101] ndb - bug#19141, bug#18575 Maek sure global dict lock is taken during create/drop file/filegroup storage/ndb/include/kernel/signaldata/DropFilegroup.hpp: Fix error code storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Fix c_blockState lock for createdrop file/filegroup storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp: Fix not master for create/drop file --- .../kernel/signaldata/DropFilegroup.hpp | 1 + .../ndb/src/kernel/blocks/dbdict/Dbdict.cpp | 83 +++++++++++++++++-- storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp | 4 +- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp b/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp index 7cf275b1f9e..c1dbc95380c 100644 --- a/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp +++ b/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp @@ -150,6 +150,7 @@ struct DropFileRef { enum ErrorCode { NoError = 0, Busy = 701, + NotMaster = 702, NoSuchFile = 766, DropUndoFileNotSupported = 769, InvalidSchemaObjectVersion = 774 diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 87bd1d7c53b..57aa9890f24 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -13396,6 +13396,24 @@ Dbdict::execCREATE_FILE_REQ(Signal* signal){ Uint32 requestInfo = req->requestInfo; do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + ref->errorCode = CreateFileRef::NotMaster; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + ref->errorCode = CreateFileRef::Busy; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + Ptr trans_ptr; if (! c_Trans.seize(trans_ptr)){ ref->errorCode = CreateFileRef::Busy; @@ -13455,6 +13473,9 @@ Dbdict::execCREATE_FILE_REQ(Signal* signal){ tmp.init(rg, GSN_CREATE_OBJ_REF, trans_key); sendSignal(rg, GSN_CREATE_OBJ_REQ, signal, CreateObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13480,15 +13501,6 @@ Dbdict::execCREATE_FILEGROUP_REQ(Signal* signal){ Uint32 type = req->objType; do { - Ptr trans_ptr; - if (! c_Trans.seize(trans_ptr)){ - ref->errorCode = CreateFilegroupRef::Busy; - ref->status = 0; - ref->errorKey = 0; - ref->errorLine = __LINE__; - break; - } - if(getOwnNodeId() != c_masterNodeId){ jam(); ref->errorCode = CreateFilegroupRef::NotMaster; @@ -13506,6 +13518,15 @@ Dbdict::execCREATE_FILEGROUP_REQ(Signal* signal){ ref->errorLine = __LINE__; break; } + + Ptr trans_ptr; + if (! c_Trans.seize(trans_ptr)){ + ref->errorCode = CreateFilegroupRef::Busy; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } const Uint32 trans_key = ++c_opRecordSequence; trans_ptr.p->key = trans_key; @@ -13554,6 +13575,9 @@ Dbdict::execCREATE_FILEGROUP_REQ(Signal* signal){ tmp.init(rg, GSN_CREATE_OBJ_REF, trans_key); sendSignal(rg, GSN_CREATE_OBJ_REQ, signal, CreateObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13581,6 +13605,22 @@ Dbdict::execDROP_FILE_REQ(Signal* signal) Uint32 version = req->file_version; do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + ref->errorCode = DropFileRef::NotMaster; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + ref->errorCode = DropFileRef::Busy; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + Ptr file_ptr; if (!c_file_hash.find(file_ptr, objId)) { @@ -13636,6 +13676,9 @@ Dbdict::execDROP_FILE_REQ(Signal* signal) tmp.init(rg, GSN_DROP_OBJ_REF, trans_key); sendSignal(rg, GSN_DROP_OBJ_REQ, signal, DropObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13663,6 +13706,22 @@ Dbdict::execDROP_FILEGROUP_REQ(Signal* signal) Uint32 version = req->filegroup_version; do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + ref->errorCode = DropFilegroupRef::NotMaster; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + ref->errorCode = DropFilegroupRef::Busy; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + Ptr filegroup_ptr; if (!c_filegroup_hash.find(filegroup_ptr, objId)) { @@ -13718,6 +13777,9 @@ Dbdict::execDROP_FILEGROUP_REQ(Signal* signal) tmp.init(rg, GSN_DROP_OBJ_REF, trans_key); sendSignal(rg, GSN_DROP_OBJ_REQ, signal, DropObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13892,6 +13954,7 @@ Dbdict::trans_commit_complete_done(Signal* signal, //@todo check api failed sendSignal(trans_ptr.p->m_senderRef, GSN_CREATE_FILEGROUP_CONF, signal, CreateFilegroupConf::SignalLength, JBB); + break; } case GSN_CREATE_FILE_REQ:{ @@ -13935,6 +13998,7 @@ Dbdict::trans_commit_complete_done(Signal* signal, } c_Trans.release(trans_ptr); + ndbrequire(c_blockState == BS_CREATE_TAB); c_blockState = BS_IDLE; return; } @@ -14047,6 +14111,7 @@ Dbdict::trans_abort_complete_done(Signal* signal, } c_Trans.release(trans_ptr); + ndbrequire(c_blockState == BS_CREATE_TAB); c_blockState = BS_IDLE; return; } diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index a1a270c724a..ce010d75672 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -4397,7 +4397,7 @@ NdbDictInterface::create_file(const NdbFileImpl & file, ptr[0].p = (Uint32*)m_buffer.get_data(); ptr[0].sz = m_buffer.length() / 4; - int err[] = { CreateFileRef::Busy, 0}; + int err[] = { CreateFileRef::Busy, CreateFileRef::NotMaster, 0}; /* Send signal without time-out since creating files can take a very long time if the file is very big. @@ -4441,7 +4441,7 @@ NdbDictInterface::drop_file(const NdbFileImpl & file){ req->file_id = file.m_id; req->file_version = file.m_version; - int err[] = { DropFileRef::Busy, 0}; + int err[] = { DropFileRef::Busy, DropFileRef::NotMaster, 0}; DBUG_RETURN(dictSignal(&tSignal, 0, 0, 0, // master WAIT_CREATE_INDX_REQ, From b71afda5f75fb74be73231217396ce1258ca535a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 08:35:25 -0400 Subject: [PATCH 084/101] WL 2826: Error handling of ALTER TABLE for partitioning Final review fixes sql/mysql_priv.h: Final review fixes sql/sql_table.cc: Final review fixes --- sql/mysql_priv.h | 6 ------ sql/sql_table.cc | 12 ++++++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 694814aee5d..24014170590 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1282,9 +1282,6 @@ typedef struct st_ddl_log_memory_entry } DDL_LOG_MEMORY_ENTRY; - -#define DDL_LOG_HANDLER_TYPE_LEN 32 - bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, DDL_LOG_MEMORY_ENTRY **active_entry); bool write_execute_ddl_log_entry(uint first_entry, @@ -1474,9 +1471,6 @@ extern ulong delayed_insert_timeout; extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; -#ifdef ERROR_INJECT_SUPPORT -extern ulong error_inject_value; -#endif extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; extern ulong slow_launch_threads, slow_launch_time; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9fb65451a70..1ed6e5c5cf2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -764,20 +764,20 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], ddl_log_entry->next_entry); DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN); - strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], - ddl_log_entry->name, FN_LEN); + strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], + ddl_log_entry->name, FN_LEN - 1); if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION || ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION) { DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN); - strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], - ddl_log_entry->from_name, FN_LEN); + strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], + ddl_log_entry->from_name, FN_LEN - 1); } else global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN); - strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], - ddl_log_entry->handler_name, FN_LEN); + strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], + ddl_log_entry->handler_name, FN_LEN - 1); if (get_free_ddl_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); From c71763722762b354397b99b6e6193b5dfe7370d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 15:36:10 +0200 Subject: [PATCH 085/101] Bug #19255 ndb: restore of ndb backup from different endian does not work + removed not needed -- mysql-test/mysql-test-run.pl: post merge fix --- mysql-test/mysql-test-run.pl | 2 +- storage/ndb/tools/restore/Restore.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c9d4fb1cb43..a095b4535fe 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1524,7 +1524,7 @@ sub ndbcluster_start ($) { if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", "--data-dir=$opt_vardir", - "--character-sets-dir=$path_charsetsdir"], + "--character-sets-dir=$path_charsetsdir", "--verbose=2", "--core"], "", "/dev/null", "", "") ) diff --git a/storage/ndb/tools/restore/Restore.cpp b/storage/ndb/tools/restore/Restore.cpp index 7e240976067..7762785ef61 100644 --- a/storage/ndb/tools/restore/Restore.cpp +++ b/storage/ndb/tools/restore/Restore.cpp @@ -1021,7 +1021,6 @@ RestoreLogIterator::getNextLogEntry(int & res) { if(hasGcp){ // last attr_data is gci info attr_data_len--; - len--; m_last_gci = ntohl(*(attr_data + attr_data_len)); } } while(m_last_gci > stopGCP + 1); @@ -1057,6 +1056,9 @@ RestoreLogIterator::getNextLogEntry(int & res) { return 0; } + if(unlikely(!m_hostByteOrder)) + *(Uint32*)ah = Twiddle32(*(Uint32*)ah); + attr->Desc = (* tab)[ah->getAttributeId()]; assert(attr->Desc != 0); From d8b3299d9b1d4100e21fd6ebbfddf8ad36d3b123 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 16:05:42 +0200 Subject: [PATCH 086/101] added skip create option to bank test program --- storage/ndb/test/ndbapi/bank/Bank.hpp | 2 ++ storage/ndb/test/ndbapi/bank/BankLoad.cpp | 4 ++-- storage/ndb/test/ndbapi/bank/bankCreator.cpp | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/storage/ndb/test/ndbapi/bank/Bank.hpp b/storage/ndb/test/ndbapi/bank/Bank.hpp index 60ec7745b59..494f39930eb 100644 --- a/storage/ndb/test/ndbapi/bank/Bank.hpp +++ b/storage/ndb/test/ndbapi/bank/Bank.hpp @@ -29,6 +29,7 @@ public: Bank(Ndb_cluster_connection&, bool init = true, const char *dbase="BANK"); + int setSkipCreate(bool skip) { m_skip_create = skip; } int createAndLoadBank(bool overWrite, bool disk= false, int num_accounts=10); int dropBank(); @@ -140,6 +141,7 @@ private: Ndb m_ndb; int m_maxAccount; bool m_initialized; + bool m_skip_create; }; #endif diff --git a/storage/ndb/test/ndbapi/bank/BankLoad.cpp b/storage/ndb/test/ndbapi/bank/BankLoad.cpp index 45d6a860a3d..5a81a4d2498 100644 --- a/storage/ndb/test/ndbapi/bank/BankLoad.cpp +++ b/storage/ndb/test/ndbapi/bank/BankLoad.cpp @@ -58,7 +58,7 @@ int Bank::createAndLoadBank(bool ovrWrt, bool disk, int num_accounts){ m_ndb.init(); if (m_ndb.waitUntilReady() != 0) return NDBT_FAILED; - + const NdbDictionary::Table* pSysValTab = m_ndb.getDictionary()->getTable("SYSTEM_VALUES"); if (pSysValTab != NULL){ @@ -69,7 +69,7 @@ int Bank::createAndLoadBank(bool ovrWrt, bool disk, int num_accounts){ } } - if (createTables(disk) != NDBT_OK) + if (!m_skip_create && createTables(disk) != NDBT_OK) return NDBT_FAILED; if (clearTables() != NDBT_OK) diff --git a/storage/ndb/test/ndbapi/bank/bankCreator.cpp b/storage/ndb/test/ndbapi/bank/bankCreator.cpp index 39e4920867f..30c024d799c 100644 --- a/storage/ndb/test/ndbapi/bank/bankCreator.cpp +++ b/storage/ndb/test/ndbapi/bank/bankCreator.cpp @@ -31,10 +31,12 @@ int main(int argc, const char** argv){ int _help = 0; char * _database = "BANK"; int disk = 0; + int skip_create = 0; struct getargs args[] = { { "database", 'd', arg_string, &_database, "Database name", ""}, { "disk", 0, arg_flag, &disk, "Use disk tables", "" }, + { "skip-create", 0, arg_flag, &skip_create, "Skip create", "" }, { "usage", '?', arg_flag, &_help, "Print help", "" } }; int num_args = sizeof(args) / sizeof(args[0]); @@ -55,6 +57,7 @@ int main(int argc, const char** argv){ Bank bank(con,_database); int overWriteExisting = true; + bank.setSkipCreate(skip_create); if (bank.createAndLoadBank(overWriteExisting, disk) != NDBT_OK) return NDBT_ProgramExit(NDBT_FAILED); return NDBT_ProgramExit(NDBT_OK); From e98e6883402ec8e2f8082e7ca06435cfca28401a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 17:28:45 +0200 Subject: [PATCH 087/101] disabled.def cleanup storage/ndb/test/ndbapi/bank/Bank.cpp: added skip create option to bank test program --- mysql-test/t/disabled.def | 17 ++--------------- storage/ndb/test/ndbapi/bank/Bank.cpp | 3 ++- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index cec913ac320..8766e9f3f6a 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -24,13 +24,12 @@ rpl_deadlock_innodb : BUG#16920 2006-04-12 kent fails in show slave stat rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_auto_inc : BUG#17086 2006-02-16 jmiller CR: auto_increment_increment and auto_increment_offset produce duplicate key er -rpl_ndb_ddl : result file needs update + test needs to checked +rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on solaris +rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked rpl_ndb_innodb2ndb : BUG#17400 2006-04-19 tomas Cluster Replication: delete & update of rows in table without pk fails on slave. rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ rpl_ndb_myisam2ndb : BUG#17400 2006-04-19 tomas Cluster Replication: delete & update of rows in table without pk fails on slave. -#rpl_ndb_relay_space : BUG#16993 2006-02-16 jmiller RBR: ALTER TABLE ZEROFILL AUTO_INCREMENT is not replicated correctly rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian -#rpl_row_basic_7ndb : BUG#17400 2006-04-09 brian Cluster Replication: delete & update of rows in table without pk fails on slave. rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed rpl_row_inexist_tbl : BUG#18948 2006-03-09 mats Disabled since patch makes this test wait forever @@ -42,15 +41,3 @@ udf : BUG#18564 2006-03-27 ian (Permission by Brian) # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open #ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second binlog may miss schema log events - -# the below ndb failures have not been objerved for > 5 push builds, close bugs -#ndb_gis : BUG#18600 2006-03-28 brian ndb_gis test failure -#ndb_load : BUG#17233 2006-02-16 jmiller failed load data from infile causes mysqld dbug_assert, binlog not flushed -#rpl_ndb_basic : BUG#18592 2006-03-28 brian rpl_ndb_basic failure -#rpl_ndb_dd_advance : BUG#18924 2006-04-09 brian rpl_ndb_dd_advance failure -rpl_ndb_dd_partitions : fails on solaris -#rpl_ndb_dd_basic : BUG#18569 2006-03-28 brian rpl_ndb_dd_basic failure -#rpl_ndb_insert_ignore : BUG#18567 2006-03-28 brian rpl_ndb_insert_ignore failure -#rpl_ndb_multi_update2 : BUG#18928 2006-04-09 brian rpl_ndb_multi_update2 failed -#rpl_ndb_multi_update3 : BUG#18627 2006-03-29 monty Cluster Replication: rpl_ndb_multi_update3 fails on Intel 64 bit -#rpl_ndb_trig004 : BUG#18977 2006-04-10 kent Test fails randomly diff --git a/storage/ndb/test/ndbapi/bank/Bank.cpp b/storage/ndb/test/ndbapi/bank/Bank.cpp index 5ef01533e07..80edbef7e74 100644 --- a/storage/ndb/test/ndbapi/bank/Bank.cpp +++ b/storage/ndb/test/ndbapi/bank/Bank.cpp @@ -22,7 +22,8 @@ Bank::Bank(Ndb_cluster_connection& con, bool _init, const char * dbase): m_ndb(&con, dbase), m_maxAccount(-1), - m_initialized(false) + m_initialized(false), + m_skip_create(false) { if(_init) init(); From 78907f348886175be427789f936cf0a5128ffc3f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 18:28:00 +0200 Subject: [PATCH 088/101] ndb: minor modification in replication timer code added missing setting of latest applied epoch --- sql/ha_ndbcluster_binlog.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index c2b95d27aef..a39d92ae7a5 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -3095,6 +3095,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) Thd_ndb *thd_ndb=0; int ndb_update_binlog_index= 1; injector *inj= injector::instance(); +#ifdef RUN_NDB_BINLOG_TIMER + Timer main_timer; +#endif pthread_mutex_lock(&injector_mutex); /* @@ -3233,9 +3236,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) thd->db= db; } -#ifdef RUN_NDB_BINLOG_TIMER - Timer main_timer; -#endif for ( ; !((abort_loop || do_ndbcluster_binlog_close_connection) && ndb_latest_handled_binlog_epoch >= g_latest_trans_gci); ) { @@ -3316,15 +3316,16 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) if (res > 0) { DBUG_PRINT("info", ("pollEvents res: %d", res)); -#ifdef RUN_NDB_BINLOG_TIMER - Timer gci_timer, write_timer; - int event_count= 0; -#endif thd->proc_info= "Processing events"; NdbEventOperation *pOp= i_ndb->nextEvent(); Binlog_index_row row; while (pOp != NULL) { +#ifdef RUN_NDB_BINLOG_TIMER + Timer gci_timer, write_timer; + int event_count= 0; + gci_timer.start(); +#endif gci= pOp->getGCI(); DBUG_PRINT("info", ("Handling gci: %d", (unsigned)gci)); // sometimes get TE_ALTER with invalid table @@ -3503,6 +3504,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) DBUG_PRINT("info", ("COMMIT gci: %lld", gci)); if (ndb_update_binlog_index) ndb_add_binlog_index(thd, &row); + ndb_latest_applied_binlog_epoch= gci; } ndb_latest_handled_binlog_epoch= gci; #ifdef RUN_NDB_BINLOG_TIMER From 377968d21e4eb90335edc7eb985425ef7bc99913 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 09:30:16 -0700 Subject: [PATCH 089/101] Delete some more NDB cruft. BitKeeper/deleted/.del-Linuxmkisofs~c3340108ee428bfd: Delete: storage/ndb/home/bin/Linuxmkisofs BitKeeper/deleted/.del-Solarismkisofs~f2352aa3eb74bf81: Delete: storage/ndb/home/bin/Solarismkisofs BitKeeper/deleted/.del-cvs2cl.pl~f6dd53614cca3bd7: Delete: storage/ndb/home/bin/cvs2cl.pl BitKeeper/deleted/.del-fix-cvs-root~85b114dffe4dcd71: Delete: storage/ndb/home/bin/fix-cvs-root BitKeeper/deleted/.del-import-from-bk.sh~fd7b3609d1cb93cc: Delete: storage/ndb/home/bin/import-from-bk.sh BitKeeper/deleted/.del-ndb_deploy~1d70ed639d03fc07: Delete: storage/ndb/home/bin/ndb_deploy BitKeeper/deleted/.del-funcs.sh~19e11fb1f65b19e1: Delete: storage/ndb/home/lib/funcs.sh BitKeeper/deleted/.del-ndbdoxy.pl~cc153c886e5d1085: Delete: storage/ndb/home/bin/ndbdoxy.pl BitKeeper/deleted/.del-ngcalc~9f8fb4a518060935: Delete: storage/ndb/home/bin/ngcalc BitKeeper/deleted/.del-parseConfigFile.awk~17f70292f412959a: Delete: storage/ndb/home/bin/parseConfigFile.awk BitKeeper/deleted/.del-setup-test.sh~57acbf006ee61516: Delete: storage/ndb/home/bin/setup-test.sh BitKeeper/deleted/.del-signallog2html.sh~11f078f3616cece4: Delete: storage/ndb/home/bin/signallog2html.sh BitKeeper/deleted/.del-signallog2list.awk~9e3c7272618f8a3e: Delete: storage/ndb/home/bin/signallog2html.lib/signallog2list.awk BitKeeper/deleted/.del-stripcr~87d0d3d45e5dcf97: Delete: storage/ndb/home/bin/stripcr BitKeeper/deleted/.del-uniq_blocks.awk~c98f28fca67bec81: Delete: storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk --- storage/ndb/home/bin/Linuxmkisofs | Bin 503146 -> 0 bytes storage/ndb/home/bin/Solarismkisofs | Bin 634084 -> 0 bytes storage/ndb/home/bin/cvs2cl.pl | 1865 ----------------- storage/ndb/home/bin/fix-cvs-root | 17 - storage/ndb/home/bin/import-from-bk.sh | 158 -- storage/ndb/home/bin/ndb_deploy | 27 - storage/ndb/home/bin/ndbdoxy.pl | 184 -- storage/ndb/home/bin/ngcalc | 78 - storage/ndb/home/bin/parseConfigFile.awk | 98 - storage/ndb/home/bin/setup-test.sh | 272 --- .../bin/signallog2html.lib/signallog2list.awk | 102 - .../bin/signallog2html.lib/uniq_blocks.awk | 29 - storage/ndb/home/bin/signallog2html.sh | 349 --- storage/ndb/home/bin/stripcr | 90 - storage/ndb/home/lib/funcs.sh | 294 --- 15 files changed, 3563 deletions(-) delete mode 100755 storage/ndb/home/bin/Linuxmkisofs delete mode 100755 storage/ndb/home/bin/Solarismkisofs delete mode 100755 storage/ndb/home/bin/cvs2cl.pl delete mode 100755 storage/ndb/home/bin/fix-cvs-root delete mode 100755 storage/ndb/home/bin/import-from-bk.sh delete mode 100755 storage/ndb/home/bin/ndb_deploy delete mode 100755 storage/ndb/home/bin/ndbdoxy.pl delete mode 100755 storage/ndb/home/bin/ngcalc delete mode 100644 storage/ndb/home/bin/parseConfigFile.awk delete mode 100755 storage/ndb/home/bin/setup-test.sh delete mode 100644 storage/ndb/home/bin/signallog2html.lib/signallog2list.awk delete mode 100644 storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk delete mode 100755 storage/ndb/home/bin/signallog2html.sh delete mode 100755 storage/ndb/home/bin/stripcr delete mode 100644 storage/ndb/home/lib/funcs.sh diff --git a/storage/ndb/home/bin/Linuxmkisofs b/storage/ndb/home/bin/Linuxmkisofs deleted file mode 100755 index a531f4cca7b776ccfd46f5bfafcbdaa67bdedf6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 503146 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 _x#a-V(|Er*GfZyf}P@c=T^;ch`)L=#r?zVSkT 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�BM^aOxT)DtQB244Pjf1Yajaor5(``P?! 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 diff --git a/storage/ndb/home/bin/Solarismkisofs b/storage/ndb/home/bin/Solarismkisofs deleted file mode 100755 index b239eaed6adeb40fcbe8f5e6511250b28cb17500..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 634084 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 a;GX@n`6zR|d@ug%Ao$vSn+e~N@Bafw&h, under the GNU GPL. -## -## (Extensively hacked on by Melissa O'Neill .) -## -## cvs2cl.pl 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; either version 2, or (at your option) -## any later version. -## -## cvs2cl.pl 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 may have received a copy of the GNU General Public License -## along with cvs2cl.pl; see the file COPYING. If not, write to the -## Free Software Foundation, Inc., 59 Temple Place - Suite 330, -## Boston, MA 02111-1307, USA. - - - -use strict; -use Text::Wrap; -use Time::Local; -use File::Basename; - - -# The Plan: -# -# Read in the logs for multiple files, spit out a nice ChangeLog that -# mirrors the information entered during `cvs commit'. -# -# The problem presents some challenges. In an ideal world, we could -# detect files with the same author, log message, and checkin time -- -# each would be a changelog entry. -# We'd sort them; and spit them out. Unfortunately, CVS is *not atomic* -# so checkins can span a range of times. Also, the directory structure -# could be hierarchical. -# -# Another question is whether we really want to have the ChangeLog -# exactly reflect commits. An author could issue two related commits, -# with different log entries, reflecting a single logical change to the -# source. GNU style ChangeLogs group these under a single author/date. -# We try to do the same. -# -# So, we parse the output of `cvs log', storing log messages in a -# multilevel hash that stores the mapping: -# directory => author => time => message => filelist -# As we go, we notice "nearby" commit times and store them together -# (i.e., under the same timestamp), so they appear in the same log -# entry. -# -# When we've read all the logs, we twist this mapping into -# a time => author => message => filelist mapping for each directory. -# -# If we're not using the `--distributed' flag, the directory is always -# considered to be `./', even as descend into subdirectories. - - -############### Globals ################ - - -# What we run to generate it: -my $Log_Source_Command = "cvs log"; - -# In case we have to print it out: -my $VERSION = '$Revision: 2.38 $'; -$VERSION =~ s/\S+\s+(\S+)\s+\S+/$1/; - -## Vars set by options: - -# Print debugging messages? -my $Debug = 0; - -# Just show version and exit? -my $Print_Version = 0; - -# Just print usage message and exit? -my $Print_Usage = 0; - -# Single top-level ChangeLog, or one per subdirectory? -my $Distributed = 0; - -# What file should we generate (defaults to "ChangeLog")? -my $Log_File_Name = "ChangeLog"; - -# Grab most recent entry date from existing ChangeLog file, just add -# to that ChangeLog. -my $Cumulative = 0; - -# Expand usernames to email addresses based on a map file? -my $User_Map_File = ""; - -# Output to a file or to stdout? -my $Output_To_Stdout = 0; - -# Eliminate empty log messages? -my $Prune_Empty_Msgs = 0; - -# Don't call Text::Wrap on the body of the message -my $No_Wrap = 0; - -# Separates header from log message. Code assumes it is either " " or -# "\n\n", so if there's ever an option to set it to something else, -# make sure to go through all conditionals that use this var. -my $After_Header = " "; - -# Format more for programs than for humans. -my $XML_Output = 0; - -# Do some special tweaks for log data that was written in FSF -# ChangeLog style. -my $FSF_Style = 0; - -# Show times in UTC instead of local time -my $UTC_Times = 0; - -# Show day of week in output? -my $Show_Day_Of_Week = 0; - -# Show revision numbers in output? -my $Show_Revisions = 0; - -# Show tags (symbolic names) in output? -my $Show_Tags = 0; - -# Show branches by symbolic name in output? -my $Show_Branches = 0; - -# Show only revisions on these branches or their ancestors. -my @Follow_Branches; - -# Don't bother with files matching this regexp. -my @Ignore_Files; - -# How exactly we match entries. We definitely want "o", -# and user might add "i" by using --case-insensitive option. -my $Case_Insensitive = 0; - -# Maybe only show log messages matching a certain regular expression. -my $Regexp_Gate = ""; - -# Pass this global option string along to cvs, to the left of `log': -my $Global_Opts = ""; - -# Pass this option string along to the cvs log subcommand: -my $Command_Opts = ""; - -# Read log output from stdin instead of invoking cvs log? -my $Input_From_Stdin = 0; - -# Don't show filenames in output. -my $Hide_Filenames = 0; - -# Max checkin duration. CVS checkin is not atomic, so we may have checkin -# times that span a range of time. We assume that checkins will last no -# longer than $Max_Checkin_Duration seconds, and that similarly, no -# checkins will happen from the same users with the same message less -# than $Max_Checkin_Duration seconds apart. -my $Max_Checkin_Duration = 180; - -# What to put at the front of [each] ChangeLog. -my $ChangeLog_Header = ""; - -## end vars set by options. - -# In 'cvs log' output, one long unbroken line of equal signs separates -# files: -my $file_separator = "=======================================" - . "======================================"; - -# In 'cvs log' output, a shorter line of dashes separates log messages -# within a file: -my $logmsg_separator = "----------------------------"; - - -############### End globals ############ - - - - -&parse_options (); -&derive_change_log (); - - - -### Everything below is subroutine definitions. ### - -# If accumulating, grab the boundary date from pre-existing ChangeLog. -sub maybe_grab_accumulation_date () -{ - if (! $Cumulative) { - return ""; - } - - # else - - open (LOG, "$Log_File_Name") - or die ("trouble opening $Log_File_Name for reading ($!)"); - - my $boundary_date; - while () - { - if (/^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)/) - { - $boundary_date = "$1"; - last; - } - } - - close (LOG); - return $boundary_date; -} - - -# Fills up a ChangeLog structure in the current directory. -sub derive_change_log () -{ - # See "The Plan" above for a full explanation. - - my %grand_poobah; - - my $file_full_path; - my $time; - my $revision; - my $author; - my $msg_txt; - my $detected_file_separator; - - # Might be adding to an existing ChangeLog - my $accumulation_date = &maybe_grab_accumulation_date (); - if ($accumulation_date) { - $Log_Source_Command .= " -d\'>${accumulation_date}\'"; - } - - # We might be expanding usernames - my %usermap; - - # In general, it's probably not very maintainable to use state - # variables like this to tell the loop what it's doing at any given - # moment, but this is only the first one, and if we never have more - # than a few of these, it's okay. - my $collecting_symbolic_names = 0; - my %symbolic_names; # Where tag names get stored. - my %branch_names; # We'll grab branch names while we're at it. - my %branch_numbers; # Save some revisions for @Follow_Branches - my @branch_roots; # For showing which files are branch ancestors. - - # Bleargh. Compensate for a deficiency of custom wrapping. - if (($After_Header ne " ") and $FSF_Style) - { - $After_Header .= "\t"; - } - - if (! $Input_From_Stdin) { - open (LOG_SOURCE, "$Log_Source_Command |") - or die "unable to run \"${Log_Source_Command}\""; - } - else { - open (LOG_SOURCE, "-") or die "unable to open stdin for reading"; - } - - %usermap = &maybe_read_user_map_file (); - - while () - { - # If on a new file and don't see filename, skip until we find it, and - # when we find it, grab it. - if ((! (defined $file_full_path)) and /^Working file: (.*)/) - { - $file_full_path = $1; - if (@Ignore_Files) - { - my $base; - ($base, undef, undef) = fileparse ($file_full_path); - # Ouch, I wish trailing operators in regexps could be - # evaluated on the fly! - if ($Case_Insensitive) { - if (grep ($file_full_path =~ m|$_|i, @Ignore_Files)) { - undef $file_full_path; - } - } - elsif (grep ($file_full_path =~ m|$_|, @Ignore_Files)) { - undef $file_full_path; - } - } - next; - } - - # Just spin wheels if no file defined yet. - next if (! $file_full_path); - - # Collect tag names in case we're asked to print them in the output. - if (/^symbolic names:$/) { - $collecting_symbolic_names = 1; - next; # There's no more info on this line, so skip to next - } - if ($collecting_symbolic_names) - { - # All tag names are listed with whitespace in front in cvs log - # output; so if see non-whitespace, then we're done collecting. - if (/^\S/) { - $collecting_symbolic_names = 0; - } - else # we're looking at a tag name, so parse & store it - { - # According to the Cederqvist manual, in node "Tags", tag - # names must start with an uppercase or lowercase letter and - # can contain uppercase and lowercase letters, digits, `-', - # and `_'. However, it's not our place to enforce that, so - # we'll allow anything CVS hands us to be a tag: - /^\s+([^:]+): ([\d.]+)$/; - my $tag_name = $1; - my $tag_rev = $2; - - # A branch number either has an odd number of digit sections - # (and hence an even number of dots), or has ".0." as the - # second-to-last digit section. Test for these conditions. - my $real_branch_rev = ""; - if (($tag_rev =~ /^(\d+\.\d+\.)+\d+$/) # Even number of dots... - and (! ($tag_rev =~ /^(1\.)+1$/))) # ...but not "1.[1.]1" - { - $real_branch_rev = $tag_rev; - } - elsif ($tag_rev =~ /(\d+\.(\d+\.)+)0.(\d+)/) # Has ".0." - { - $real_branch_rev = $1 . $3; - } - # If we got a branch, record its number. - if ($real_branch_rev) - { - $branch_names{$real_branch_rev} = $tag_name; - if (@Follow_Branches) { - if (grep ($_ eq $tag_name, @Follow_Branches)) { - $branch_numbers{$tag_name} = $real_branch_rev; - } - } - } - else { - # Else it's just a regular (non-branch) tag. - push (@{$symbolic_names{$tag_rev}}, $tag_name); - } - } - } - # End of code for collecting tag names. - - # If have file name, but not revision, and see revision, then grab - # it. (We collect unconditionally, even though we may or may not - # ever use it.) - if ((! (defined $revision)) and (/^revision (\d+\.[\d.]+)/)) - { - $revision = $1; - - if (@Follow_Branches) - { - foreach my $branch (@Follow_Branches) - { - # Special case for following trunk revisions - if (($branch =~ /^trunk$/i) and ($revision =~ /^[0-9]+\.[0-9]+$/)) - { - goto dengo; - } - - my $branch_number = $branch_numbers{$branch}; - if ($branch_number) - { - # Are we on one of the follow branches or an ancestor of - # same? - # - # If this revision is a prefix of the branch number, or - # possibly is less in the minormost number, OR if this - # branch number is a prefix of the revision, then yes. - # Otherwise, no. - # - # So below, we determine if any of those conditions are - # met. - - # Trivial case: is this revision on the branch? - # (Compare this way to avoid regexps that screw up Emacs - # indentation, argh.) - if ((substr ($revision, 0, ((length ($branch_number)) + 1))) - eq ($branch_number . ".")) - { - goto dengo; - } - # Non-trivial case: check if rev is ancestral to branch - elsif ((length ($branch_number)) > (length ($revision))) - { - $revision =~ /^((?:\d+\.)+)(\d+)$/; - my $r_left = $1; # still has the trailing "." - my $r_end = $2; - - $branch_number =~ /^((?:\d+\.)+)(\d+)\.\d+$/; - my $b_left = $1; # still has trailing "." - my $b_mid = $2; # has no trailing "." - - if (($r_left eq $b_left) - && ($r_end <= $b_mid)) - { - goto dengo; - } - } - } - } - } - else # (! @Follow_Branches) - { - next; - } - - # Else we are following branches, but this revision isn't on the - # path. So skip it. - undef $revision; - dengo: - next; - } - - # If we don't have a revision right now, we couldn't possibly - # be looking at anything useful. - if (! (defined ($revision))) { - $detected_file_separator = /^$file_separator$/o; - if ($detected_file_separator) { - # No revisions for this file; can happen, e.g. "cvs log -d DATE" - goto CLEAR; - } - else { - next; - } - } - - # If have file name but not date and author, and see date or - # author, then grab them: - unless (defined $time) - { - if (/^date: .*/) - { - ($time, $author) = &parse_date_and_author ($_); - if (defined ($usermap{$author}) and $usermap{$author}) { - $author = $usermap{$author}; - } - } - else { - $detected_file_separator = /^$file_separator$/o; - if ($detected_file_separator) { - # No revisions for this file; can happen, e.g. "cvs log -d DATE" - goto CLEAR; - } - } - # If the date/time/author hasn't been found yet, we couldn't - # possibly care about anything we see. So skip: - next; - } - - # A "branches: ..." line here indicates that one or more branches - # are rooted at this revision. If we're showing branches, then we - # want to show that fact as well, so we collect all the branches - # that this is the latest ancestor of and store them in - # @branch_roots. Just for reference, the format of the line we're - # seeing at this point is: - # - # branches: 1.5.2; 1.5.4; ...; - # - # Okay, here goes: - - if (/^branches:\s+(.*);$/) - { - if ($Show_Branches) - { - my $lst = $1; - $lst =~ s/(1\.)+1;|(1\.)+1$//; # ignore the trivial branch 1.1.1 - if ($lst) { - @branch_roots = split (/;\s+/, $lst); - } - else { - undef @branch_roots; - } - next; - } - else - { - # Ugh. This really bothers me. Suppose we see a log entry - # like this: - # - # ---------------------------- - # revision 1.1 - # date: 1999/10/17 03:07:38; author: jrandom; state: Exp; - # branches: 1.1.2; - # Intended first line of log message begins here. - # ---------------------------- - # - # The question is, how we can tell the difference between that - # log message and a *two*-line log message whose first line is - # - # "branches: 1.1.2;" - # - # See the problem? The output of "cvs log" is inherently - # ambiguous. - # - # For now, we punt: we liberally assume that people don't - # write log messages like that, and just toss a "branches:" - # line if we see it but are not showing branches. I hope no - # one ever loses real log data because of this. - next; - } - } - - # If have file name, time, and author, then we're just grabbing - # log message texts: - $detected_file_separator = /^$file_separator$/o; - if ($detected_file_separator && ! (defined $revision)) { - # No revisions for this file; can happen, e.g. "cvs log -d DATE" - goto CLEAR; - } - unless ($detected_file_separator || /^$logmsg_separator$/o) - { - $msg_txt .= $_; # Normally, just accumulate the message... - next; - } - # ... until a msg separator is encountered: - # Ensure the message contains something: - if ((! $msg_txt) - || ($msg_txt =~ /^\s*\.\s*$|^\s*$/) - || ($msg_txt =~ /\*\*\* empty log message \*\*\*/)) - { - if ($Prune_Empty_Msgs) { - goto CLEAR; - } - # else - $msg_txt = "[no log message]\n"; - } - - ### Store it all in the Grand Poobah: - { - my $dir_key; # key into %grand_poobah - my %qunk; # complicated little jobbie, see below - - # Each revision of a file has a little data structure (a `qunk') - # associated with it. That data structure holds not only the - # file's name, but any additional information about the file - # that might be needed in the output, such as the revision - # number, tags, branches, etc. The reason to have these things - # arranged in a data structure, instead of just appending them - # textually to the file's name, is that we may want to do a - # little rearranging later as we write the output. For example, - # all the files on a given tag/branch will go together, followed - # by the tag in parentheses (so trunk or otherwise non-tagged - # files would go at the end of the file list for a given log - # message). This rearrangement is a lot easier to do if we - # don't have to reparse the text. - # - # A qunk looks like this: - # - # { - # filename => "hello.c", - # revision => "1.4.3.2", - # time => a timegm() return value (moment of commit) - # tags => [ "tag1", "tag2", ... ], - # branch => "branchname" # There should be only one, right? - # branchroots => [ "branchtag1", "branchtag2", ... ] - # } - - if ($Distributed) { - # Just the basename, don't include the path. - ($qunk{'filename'}, $dir_key, undef) = fileparse ($file_full_path); - } - else { - $dir_key = "./"; - $qunk{'filename'} = $file_full_path; - } - - # This may someday be used in a more sophisticated calculation - # of what other files are involved in this commit. For now, we - # don't use it, because the common-commit-detection algorithm is - # hypothesized to be "good enough" as it stands. - $qunk{'time'} = $time; - - # We might be including revision numbers and/or tags and/or - # branch names in the output. Most of the code from here to - # loop-end deals with organizing these in qunk. - - $qunk{'revision'} = $revision; - - # Grab the branch, even though we may or may not need it: - $qunk{'revision'} =~ /((?:\d+\.)+)\d+/; - my $branch_prefix = $1; - $branch_prefix =~ s/\.$//; # strip off final dot - if ($branch_names{$branch_prefix}) { - $qunk{'branch'} = $branch_names{$branch_prefix}; - } - - # If there's anything in the @branch_roots array, then this - # revision is the root of at least one branch. We'll display - # them as branch names instead of revision numbers, the - # substitution for which is done directly in the array: - if (@branch_roots) { - my @roots = map { $branch_names{$_} } @branch_roots; - $qunk{'branchroots'} = \@roots; - } - - # Save tags too. - if (defined ($symbolic_names{$revision})) { - $qunk{'tags'} = $symbolic_names{$revision}; - delete $symbolic_names{$revision}; - } - - # Add this file to the list - # (We use many spoonfuls of autovivication magic. Hashes and arrays - # will spring into existence if they aren't there already.) - - &debug ("(pushing log msg for ${dir_key}$qunk{'filename'})\n"); - - # Store with the files in this commit. Later we'll loop through - # again, making sure that revisions with the same log message - # and nearby commit times are grouped together as one commit. - push (@{$grand_poobah{$dir_key}{$author}{$time}{$msg_txt}}, \%qunk); - } - - CLEAR: - # Make way for the next message - undef $msg_txt; - undef $time; - undef $revision; - undef $author; - undef @branch_roots; - - # Maybe even make way for the next file: - if ($detected_file_separator) { - undef $file_full_path; - undef %branch_names; - undef %branch_numbers; - undef %symbolic_names; - } - } - - close (LOG_SOURCE); - - ### Process each ChangeLog - - while (my ($dir,$authorhash) = each %grand_poobah) - { - &debug ("DOING DIR: $dir\n"); - - # Here we twist our hash around, from being - # author => time => message => filelist - # in %$authorhash to - # time => author => message => filelist - # in %changelog. - # - # This is also where we merge entries. The algorithm proceeds - # through the timeline of the changelog with a sliding window of - # $Max_Checkin_Duration seconds; within that window, entries that - # have the same log message are merged. - # - # (To save space, we zap %$authorhash after we've copied - # everything out of it.) - - my %changelog; - while (my ($author,$timehash) = each %$authorhash) - { - my $lasttime; - my %stamptime; - foreach my $time (sort {$main::a <=> $main::b} (keys %$timehash)) - { - my $msghash = $timehash->{$time}; - while (my ($msg,$qunklist) = each %$msghash) - { - my $stamptime = $stamptime{$msg}; - if ((defined $stamptime) - and (($time - $stamptime) < $Max_Checkin_Duration) - and (defined $changelog{$stamptime}{$author}{$msg})) - { - push(@{$changelog{$stamptime}{$author}{$msg}}, @$qunklist); - } - else { - $changelog{$time}{$author}{$msg} = $qunklist; - $stamptime{$msg} = $time; - } - } - } - } - undef (%$authorhash); - - ### Now we can write out the ChangeLog! - - my ($logfile_here, $logfile_bak, $tmpfile); - - if (! $Output_To_Stdout) { - $logfile_here = $dir . $Log_File_Name; - $logfile_here =~ s/^\.\/\//\//; # fix any leading ".//" problem - $tmpfile = "${logfile_here}.cvs2cl$$.tmp"; - $logfile_bak = "${logfile_here}.bak"; - - open (LOG_OUT, ">$tmpfile") or die "Unable to open \"$tmpfile\""; - } - else { - open (LOG_OUT, ">-") or die "Unable to open stdout for writing"; - } - - print LOG_OUT $ChangeLog_Header; - - if ($XML_Output) { - print LOG_OUT "\n\n" - . "\n\n"; - } - - foreach my $time (sort {$main::b <=> $main::a} (keys %changelog)) - { - my $authorhash = $changelog{$time}; - while (my ($author,$mesghash) = each %$authorhash) - { - # If XML, escape in outer loop to avoid compound quoting: - if ($XML_Output) { - $author = &xml_escape ($author); - } - - while (my ($msg,$qunklist) = each %$mesghash) - { - my $files = &pretty_file_list ($qunklist); - my $header_line; # date and author - my $body; # see below - my $wholething; # $header_line + $body - - # Set up the date/author line. - # kff todo: do some more XML munging here, on the header - # part of the entry: - my ($ignore,$min,$hour,$mday,$mon,$year,$wday) - = $UTC_Times ? gmtime($time) : localtime($time); - - # XML output includes everything else, we might as well make - # it always include Day Of Week too, for consistency. - if ($Show_Day_Of_Week or $XML_Output) { - $wday = ("Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday")[$wday]; - $wday = ($XML_Output) ? "${wday}\n" : " $wday"; - } - else { - $wday = ""; - } - - if ($XML_Output) { - $header_line = - sprintf ("%4u-%02u-%02u\n" - . "${wday}" - . "\n" - . "%s\n", - $year+1900, $mon+1, $mday, $hour, $min, $author); - } - else { - $header_line = - sprintf ("%4u-%02u-%02u${wday} %02u:%02u %s\n\n", - $year+1900, $mon+1, $mday, $hour, $min, $author); - } - - # Reshape the body according to user preferences. - if ($XML_Output) - { - $msg = &preprocess_msg_text ($msg); - $body = $files . $msg; - } - elsif ($No_Wrap) - { - $msg = &preprocess_msg_text ($msg); - $files = wrap ("\t", " ", "$files"); - $msg =~ s/\n(.*)/\n\t$1/g; - unless ($After_Header eq " ") { - $msg =~ s/^(.*)/\t$1/g; - } - $body = $files . $After_Header . $msg; - } - else # do wrapping, either FSF-style or regular - { - if ($FSF_Style) - { - $files = wrap ("\t", " ", "$files"); - - my $files_last_line_len = 0; - if ($After_Header eq " ") - { - $files_last_line_len = &last_line_len ($files); - $files_last_line_len += 1; # for $After_Header - } - - $msg = &wrap_log_entry - ($msg, "\t", 69 - $files_last_line_len, 69); - $body = $files . $After_Header . $msg; - } - else # not FSF-style - { - $msg = &preprocess_msg_text ($msg); - $body = $files . $After_Header . $msg; - $body = wrap ("\t", " ", "$body"); - } - } - - $wholething = $header_line . $body; - - if ($XML_Output) { - $wholething = "\n${wholething}\n"; - } - - # One last check: make sure it passes the regexp test, if the - # user asked for that. We have to do it here, so that the - # test can match against information in the header as well - # as in the text of the log message. - - # How annoying to duplicate so much code just because I - # can't figure out a way to evaluate scalars on the trailing - # operator portion of a regular expression. Grrr. - if ($Case_Insensitive) { - unless ($Regexp_Gate && ($wholething !~ /$Regexp_Gate/oi)) { - print LOG_OUT "${wholething}\n"; - } - } - else { - unless ($Regexp_Gate && ($wholething !~ /$Regexp_Gate/o)) { - print LOG_OUT "${wholething}\n"; - } - } - } - } - } - - if ($XML_Output) { - print LOG_OUT "\n"; - } - - close (LOG_OUT); - - if (! $Output_To_Stdout) - { - # If accumulating, append old data to new before renaming. But - # don't append the most recent entry, since it's already in the - # new log due to CVS's idiosyncratic interpretation of "log -d". - if ($Cumulative && -f $logfile_here) - { - open (NEW_LOG, ">>$tmpfile") - or die "trouble appending to $tmpfile ($!)"; - - open (OLD_LOG, "<$logfile_here") - or die "trouble reading from $logfile_here ($!)"; - - my $started_first_entry = 0; - my $passed_first_entry = 0; - while () - { - if (! $passed_first_entry) - { - if ((! $started_first_entry) - && /^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)/) { - $started_first_entry = 1; - } - elsif (/^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)/) { - $passed_first_entry = 1; - print NEW_LOG $_; - } - } - else { - print NEW_LOG $_; - } - } - - close (NEW_LOG); - close (OLD_LOG); - } - - if (-f $logfile_here) { - rename ($logfile_here, $logfile_bak); - } - rename ($tmpfile, $logfile_here); - } - } -} - - -sub parse_date_and_author () -{ - # Parses the date/time and author out of a line like: - # - # date: 1999/02/19 23:29:05; author: apharris; state: Exp; - - my $line = shift; - - my ($year, $mon, $mday, $hours, $min, $secs, $author) = $line =~ - m#(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+);\s+author:\s+([^;]+);# - or die "Couldn't parse date ``$line''"; - die "Bad date or Y2K issues" unless ($year > 1969 and $year < 2258); - # Kinda arbitrary, but useful as a sanity check - my $time = timegm($secs,$min,$hours,$mday,$mon-1,$year-1900); - - return ($time, $author); -} - - -# Here we take a bunch of qunks and convert them into printed -# summary that will include all the information the user asked for. -sub pretty_file_list () -{ - if ($Hide_Filenames and (! $XML_Output)) { - return ""; - } - - my $qunksref = shift; - my @qunkrefs = @$qunksref; - my @filenames; - my $beauty = ""; # The accumulating header string for this entry. - my %non_unanimous_tags; # Tags found in a proper subset of qunks - my %unanimous_tags; # Tags found in all qunks - my %all_branches; # Branches found in any qunk - my $common_dir = undef; # Dir prefix common to all files ("" if none) - my $fbegun = 0; # Did we begin printing filenames yet? - - # First, loop over the qunks gathering all the tag/branch names. - # We'll put them all in non_unanimous_tags, and take out the - # unanimous ones later. - foreach my $qunkref (@qunkrefs) - { - # Keep track of whether all the files in this commit were in the - # same directory, and memorize it if so. We can make the output a - # little more compact by mentioning the directory only once. - if ((scalar (@qunkrefs)) > 1) - { - if (! (defined ($common_dir))) - { - my ($base, $dir); - ($base, $dir, undef) = fileparse ($$qunkref{'filename'}); - - if ((! (defined ($dir))) # this first case is sheer paranoia - or ($dir eq "") - or ($dir eq "./") - or ($dir eq ".\\")) - { - $common_dir = ""; - } - else - { - $common_dir = $dir; - } - } - elsif ($common_dir ne "") - { - # Already have a common dir prefix, so how much of it can we preserve? - $common_dir = &common_path_prefix ($$qunkref{'filename'}, $common_dir); - } - } - else # only one file in this entry anyway, so common dir not an issue - { - $common_dir = ""; - } - - if (defined ($$qunkref{'branch'})) { - $all_branches{$$qunkref{'branch'}} = 1; - } - if (defined ($$qunkref{'tags'})) { - foreach my $tag (@{$$qunkref{'tags'}}) { - $non_unanimous_tags{$tag} = 1; - } - } - } - - # Any tag held by all qunks will be printed specially... but only if - # there are multiple qunks in the first place! - if ((scalar (@qunkrefs)) > 1) { - foreach my $tag (keys (%non_unanimous_tags)) { - my $everyone_has_this_tag = 1; - foreach my $qunkref (@qunkrefs) { - if ((! (defined ($$qunkref{'tags'}))) - or (! (grep ($_ eq $tag, @{$$qunkref{'tags'}})))) { - $everyone_has_this_tag = 0; - } - } - if ($everyone_has_this_tag) { - $unanimous_tags{$tag} = 1; - delete $non_unanimous_tags{$tag}; - } - } - } - - if ($XML_Output) - { - # If outputting XML, then our task is pretty simple, because we - # don't have to detect common dir, common tags, branch prefixing, - # etc. We just output exactly what we have, and don't worry about - # redundancy or readability. - - foreach my $qunkref (@qunkrefs) - { - my $filename = $$qunkref{'filename'}; - my $revision = $$qunkref{'revision'}; - my $tags = $$qunkref{'tags'}; - my $branch = $$qunkref{'branch'}; - my $branchroots = $$qunkref{'branchroots'}; - - $filename = &xml_escape ($filename); # probably paranoia - $revision = &xml_escape ($revision); # definitely paranoia - - $beauty .= "\n"; - $beauty .= "${filename}\n"; - $beauty .= "${revision}\n"; - if ($branch) { - $branch = &xml_escape ($branch); # more paranoia - $beauty .= "${branch}\n"; - } - foreach my $tag (@$tags) { - $tag = &xml_escape ($tag); # by now you're used to the paranoia - $beauty .= "${tag}\n"; - } - foreach my $root (@$branchroots) { - $root = &xml_escape ($root); # which is good, because it will continue - $beauty .= "${root}\n"; - } - $beauty .= "\n"; - } - - # Theoretically, we could go home now. But as long as we're here, - # let's print out the common_dir and utags, as a convenience to - # the receiver (after all, earlier code calculated that stuff - # anyway, so we might as well take advantage of it). - - if ((scalar (keys (%unanimous_tags))) > 1) { - foreach my $utag ((keys (%unanimous_tags))) { - $utag = &xml_escape ($utag); # the usual paranoia - $beauty .= "${utag}\n"; - } - } - if ($common_dir) { - $common_dir = &xml_escape ($common_dir); - $beauty .= "${common_dir}\n"; - } - - # That's enough for XML, time to go home: - return $beauty; - } - - # Else not XML output, so complexly compactify for chordate - # consumption. At this point we have enough global information - # about all the qunks to organize them non-redundantly for output. - - if ($common_dir) { - # Note that $common_dir still has its trailing slash - $beauty .= "$common_dir: "; - } - - if ($Show_Branches) - { - # For trailing revision numbers. - my @brevisions; - - foreach my $branch (keys (%all_branches)) - { - foreach my $qunkref (@qunkrefs) - { - if ((defined ($$qunkref{'branch'})) - and ($$qunkref{'branch'} eq $branch)) - { - if ($fbegun) { - # kff todo: comma-delimited in XML too? Sure. - $beauty .= ", "; - } - else { - $fbegun = 1; - } - my $fname = substr ($$qunkref{'filename'}, length ($common_dir)); - $beauty .= $fname; - $$qunkref{'printed'} = 1; # Just setting a mark bit, basically - - if ($Show_Tags && (defined @{$$qunkref{'tags'}})) { - my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}}); - if (@tags) { - $beauty .= " (tags: "; - $beauty .= join (', ', @tags); - $beauty .= ")"; - } - } - - if ($Show_Revisions) { - # Collect the revision numbers' last components, but don't - # print them -- they'll get printed with the branch name - # later. - $$qunkref{'revision'} =~ /.+\.([\d]+)$/; - push (@brevisions, $1); - - # todo: we're still collecting branch roots, but we're not - # showing them anywhere. If we do show them, it would be - # nifty to just call them revision "0" on a the branch. - # Yeah, that's the ticket. - } - } - } - $beauty .= " ($branch"; - if (@brevisions) { - if ((scalar (@brevisions)) > 1) { - $beauty .= ".["; - $beauty .= (join (',', @brevisions)); - $beauty .= "]"; - } - else { - $beauty .= ".$brevisions[0]"; - } - } - $beauty .= ")"; - } - } - - # Okay; any qunks that were done according to branch are taken care - # of, and marked as printed. Now print everyone else. - - foreach my $qunkref (@qunkrefs) - { - next if (defined ($$qunkref{'printed'})); # skip if already printed - - if ($fbegun) { - $beauty .= ", "; - } - else { - $fbegun = 1; - } - $beauty .= substr ($$qunkref{'filename'}, length ($common_dir)); - # todo: Shlomo's change was this: - # $beauty .= substr ($$qunkref{'filename'}, - # (($common_dir eq "./") ? "" : length ($common_dir))); - $$qunkref{'printed'} = 1; # Set a mark bit. - - if ($Show_Revisions || $Show_Tags) - { - my $started_addendum = 0; - - if ($Show_Revisions) { - $started_addendum = 1; - $beauty .= " ("; - $beauty .= "$$qunkref{'revision'}"; - } - if ($Show_Tags && (defined $$qunkref{'tags'})) { - my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}}); - if ((scalar (@tags)) > 0) { - if ($started_addendum) { - $beauty .= ", "; - } - else { - $beauty .= " (tags: "; - } - $beauty .= join (', ', @tags); - $started_addendum = 1; - } - } - if ($started_addendum) { - $beauty .= ")"; - } - } - } - - # Unanimous tags always come last. - if ($Show_Tags && %unanimous_tags) - { - $beauty .= " (utags: "; - $beauty .= join (', ', keys (%unanimous_tags)); - $beauty .= ")"; - } - - # todo: still have to take care of branch_roots? - - $beauty = "* $beauty:"; - - return $beauty; -} - - -sub common_path_prefix () -{ - my $path1 = shift; - my $path2 = shift; - - my ($dir1, $dir2); - (undef, $dir1, undef) = fileparse ($path1); - (undef, $dir2, undef) = fileparse ($path2); - - # Transmogrify Windows filenames to look like Unix. - # (It is far more likely that someone is running cvs2cl.pl under - # Windows than that they would genuinely have backslashes in their - # filenames.) - $dir1 =~ tr#\\#/#; - $dir2 =~ tr#\\#/#; - - my $accum1 = ""; - my $accum2 = ""; - my $last_common_prefix = ""; - - while ($accum1 eq $accum2) - { - $last_common_prefix = $accum1; - last if ($accum1 eq $dir1); - my ($tmp1) = split (/\//, (substr ($dir1, length ($accum1)))); - my ($tmp2) = split (/\//, (substr ($dir2, length ($accum2)))); - $accum1 .= "$tmp1/" if ((defined ($tmp1)) and $tmp1); - $accum2 .= "$tmp2/" if ((defined ($tmp2)) and $tmp2); - } - - return $last_common_prefix; -} - - -sub preprocess_msg_text () -{ - my $text = shift; - - # Strip out carriage returns (as they probably result from DOSsy editors). - $text =~ s/\r\n/\n/g; - - # If it *looks* like two newlines, make it *be* two newlines: - $text =~ s/\n\s*\n/\n\n/g; - - if ($XML_Output) - { - $text = &xml_escape ($text); - $text = "${text}\n"; - } - elsif (! $No_Wrap) - { - # Strip off lone newlines, but only for lines that don't begin with - # whitespace or a mail-quoting character, since we want to preserve - # that kind of formatting. Also don't strip newlines that follow a - # period; we handle those specially next. And don't strip - # newlines that precede an open paren. - 1 while ($text =~ s/(^|\n)([^>\s].*[^.\n])\n([^>\n])/$1$2 $3/g); - - # If a newline follows a period, make sure that when we bring up the - # bottom sentence, it begins with two spaces. - 1 while ($text =~ s/(^|\n)([^>\s].*)\n([^>\n])/$1$2 $3/g); - } - - return $text; -} - - -sub last_line_len () -{ - my $files_list = shift; - my @lines = split (/\n/, $files_list); - my $last_line = pop (@lines); - return length ($last_line); -} - - -# A custom wrap function, sensitive to some common constructs used in -# log entries. -sub wrap_log_entry () -{ - my $text = shift; # The text to wrap. - my $left_pad_str = shift; # String to pad with on the left. - - # These do NOT take left_pad_str into account: - my $length_remaining = shift; # Amount left on current line. - my $max_line_length = shift; # Amount left for a blank line. - - my $wrapped_text = ""; # The accumulating wrapped entry. - my $user_indent = ""; # Inherited user_indent from prev line. - - my $first_time = 1; # First iteration of the loop? - my $suppress_line_start_match = 0; # Set to disable line start checks. - - my @lines = split (/\n/, $text); - while (@lines) # Don't use `foreach' here, it won't work. - { - my $this_line = shift (@lines); - chomp $this_line; - - if ($this_line =~ /^(\s+)/) { - $user_indent = $1; - } - else { - $user_indent = ""; - } - - # If it matches any of the line-start regexps, print a newline now... - if ($suppress_line_start_match) - { - $suppress_line_start_match = 0; - } - elsif (($this_line =~ /^(\s*)\*\s+[a-zA-Z0-9]/) - || ($this_line =~ /^(\s*)\* [a-zA-Z0-9_\.\/\+-]+/) - || ($this_line =~ /^(\s*)\([a-zA-Z0-9_\.\/\+-]+(\)|,\s*)/) - || ($this_line =~ /^(\s+)(\S+)/) - || ($this_line =~ /^(\s*)- +/) - || ($this_line =~ /^()\s*$/) - || ($this_line =~ /^(\s*)\*\) +/) - || ($this_line =~ /^(\s*)[a-zA-Z0-9](\)|\.|\:) +/)) - { - # Make a line break immediately, unless header separator is set - # and this line is the first line in the entry, in which case - # we're getting the blank line for free already and shouldn't - # add an extra one. - unless (($After_Header ne " ") and ($first_time)) - { - if ($this_line =~ /^()\s*$/) { - $suppress_line_start_match = 1; - $wrapped_text .= "\n${left_pad_str}"; - } - - $wrapped_text .= "\n${left_pad_str}"; - } - - $length_remaining = $max_line_length - (length ($user_indent)); - } - - # Now that any user_indent has been preserved, strip off leading - # whitespace, so up-folding has no ugly side-effects. - $this_line =~ s/^\s*//; - - # Accumulate the line, and adjust parameters for next line. - my $this_len = length ($this_line); - if ($this_len == 0) - { - # Blank lines should cancel any user_indent level. - $user_indent = ""; - $length_remaining = $max_line_length; - } - elsif ($this_len >= $length_remaining) # Line too long, try breaking it. - { - # Walk backwards from the end. At first acceptable spot, break - # a new line. - my $idx = $length_remaining - 1; - if ($idx < 0) { $idx = 0 }; - while ($idx > 0) - { - if (substr ($this_line, $idx, 1) =~ /\s/) - { - my $line_now = substr ($this_line, 0, $idx); - my $next_line = substr ($this_line, $idx); - $this_line = $line_now; - - # Clean whitespace off the end. - chomp $this_line; - - # The current line is ready to be printed. - $this_line .= "\n${left_pad_str}"; - - # Make sure the next line is allowed full room. - $length_remaining = $max_line_length - (length ($user_indent)); - - # Strip next_line, but then preserve any user_indent. - $next_line =~ s/^\s*//; - - # Sneak a peek at the user_indent of the upcoming line, so - # $next_line (which will now precede it) can inherit that - # indent level. Otherwise, use whatever user_indent level - # we currently have, which might be none. - my $next_next_line = shift (@lines); - if ((defined ($next_next_line)) && ($next_next_line =~ /^(\s+)/)) { - $next_line = $1 . $next_line if (defined ($1)); - # $length_remaining = $max_line_length - (length ($1)); - $next_next_line =~ s/^\s*//; - } - else { - $next_line = $user_indent . $next_line; - } - if (defined ($next_next_line)) { - unshift (@lines, $next_next_line); - } - unshift (@lines, $next_line); - - # Our new next line might, coincidentally, begin with one of - # the line-start regexps, so we temporarily turn off - # sensitivity to that until we're past the line. - $suppress_line_start_match = 1; - - last; - } - else - { - $idx--; - } - } - - if ($idx == 0) - { - # We bottomed out because the line is longer than the - # available space. But that could be because the space is - # small, or because the line is longer than even the maximum - # possible space. Handle both cases below. - - if ($length_remaining == ($max_line_length - (length ($user_indent)))) - { - # The line is simply too long -- there is no hope of ever - # breaking it nicely, so just insert it verbatim, with - # appropriate padding. - $this_line = "\n${left_pad_str}${this_line}"; - } - else - { - # Can't break it here, but may be able to on the next round... - unshift (@lines, $this_line); - $length_remaining = $max_line_length - (length ($user_indent)); - $this_line = "\n${left_pad_str}"; - } - } - } - else # $this_len < $length_remaining, so tack on what we can. - { - # Leave a note for the next iteration. - $length_remaining = $length_remaining - $this_len; - - if ($this_line =~ /\.$/) - { - $this_line .= " "; - $length_remaining -= 2; - } - else # not a sentence end - { - $this_line .= " "; - $length_remaining -= 1; - } - } - - # Unconditionally indicate that loop has run at least once. - $first_time = 0; - - $wrapped_text .= "${user_indent}${this_line}"; - } - - # One last bit of padding. - $wrapped_text .= "\n"; - - return $wrapped_text; -} - - -sub xml_escape () -{ - my $txt = shift; - $txt =~ s/&/&/g; - $txt =~ s//>/g; - return $txt; -} - - -sub maybe_read_user_map_file () -{ - my %expansions; - - if ($User_Map_File) - { - open (MAPFILE, "<$User_Map_File") - or die ("Unable to open $User_Map_File ($!)"); - - while () - { - next if /^\s*#/; # Skip comment lines. - next if not /:/; # Skip lines without colons. - - # It is now safe to split on ':'. - my ($username, $expansion) = split ':'; - chomp $expansion; - $expansion =~ s/^'(.*)'$/$1/; - $expansion =~ s/^"(.*)"$/$1/; - - # If it looks like the expansion has a real name already, then - # we toss the username we got from CVS log. Otherwise, keep - # it to use in combination with the email address. - - if ($expansion =~ /^\s*<{0,1}\S+@.*/) { - # Also, add angle brackets if none present - if (! ($expansion =~ /<\S+@\S+>/)) { - $expansions{$username} = "$username <$expansion>"; - } - else { - $expansions{$username} = "$username $expansion"; - } - } - else { - $expansions{$username} = $expansion; - } - } - - close (MAPFILE); - } - - return %expansions; -} - - -sub parse_options () -{ - # Check this internally before setting the global variable. - my $output_file; - - # If this gets set, we encountered unknown options and will exit at - # the end of this subroutine. - my $exit_with_admonishment = 0; - - while (my $arg = shift (@ARGV)) - { - if ($arg =~ /^-h$|^-help$|^--help$|^--usage$|^-?$/) { - $Print_Usage = 1; - } - elsif ($arg =~ /^--debug$/) { # unadvertised option, heh - $Debug = 1; - } - elsif ($arg =~ /^--version$/) { - $Print_Version = 1; - } - elsif ($arg =~ /^-g$|^--global-opts$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - # Don't assume CVS is called "cvs" on the user's system: - $Log_Source_Command =~ s/(^\S*)/$1 $narg/; - } - elsif ($arg =~ /^-l$|^--log-opts$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $Log_Source_Command .= " $narg"; - } - elsif ($arg =~ /^-f$|^--file$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $output_file = $narg; - } - elsif ($arg =~ /^--accum$/) { - $Cumulative = 1; - } - elsif ($arg =~ /^--fsf$/) { - $FSF_Style = 1; - } - elsif ($arg =~ /^-U$|^--usermap$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $User_Map_File = $narg; - } - elsif ($arg =~ /^-W$|^--window$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $Max_Checkin_Duration = $narg; - } - elsif ($arg =~ /^-I$|^--ignore$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - push (@Ignore_Files, $narg); - } - elsif ($arg =~ /^-C$|^--case-insensitive$/) { - $Case_Insensitive = 1; - } - elsif ($arg =~ /^-R$|^--regexp$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $Regexp_Gate = $narg; - } - elsif ($arg =~ /^--stdout$/) { - $Output_To_Stdout = 1; - } - elsif ($arg =~ /^--version$/) { - $Print_Version = 1; - } - elsif ($arg =~ /^-d$|^--distributed$/) { - $Distributed = 1; - } - elsif ($arg =~ /^-P$|^--prune$/) { - $Prune_Empty_Msgs = 1; - } - elsif ($arg =~ /^-S$|^--separate-header$/) { - $After_Header = "\n\n"; - } - elsif ($arg =~ /^--no-wrap$/) { - $No_Wrap = 1; - } - elsif ($arg =~ /^--gmt$|^--utc$/) { - $UTC_Times = 1; - } - elsif ($arg =~ /^-w$|^--day-of-week$/) { - $Show_Day_Of_Week = 1; - } - elsif ($arg =~ /^-r$|^--revisions$/) { - $Show_Revisions = 1; - } - elsif ($arg =~ /^-t$|^--tags$/) { - $Show_Tags = 1; - } - elsif ($arg =~ /^-b$|^--branches$/) { - $Show_Branches = 1; - } - elsif ($arg =~ /^-F$|^--follow$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - push (@Follow_Branches, $narg); - } - elsif ($arg =~ /^--stdin$/) { - $Input_From_Stdin = 1; - } - elsif ($arg =~ /^--header$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $ChangeLog_Header = &slurp_file ($narg); - if (! defined ($ChangeLog_Header)) { - $ChangeLog_Header = ""; - } - } - elsif ($arg =~ /^--xml$/) { - $XML_Output = 1; - } - elsif ($arg =~ /^--hide-filenames$/) { - $Hide_Filenames = 1; - $After_Header = ""; - } - else { - # Just add a filename as argument to the log command - $Log_Source_Command .= " $arg"; - } - } - - ## Check for contradictions... - - if ($Output_To_Stdout && $Distributed) { - print STDERR "cannot pass both --stdout and --distributed\n"; - $exit_with_admonishment = 1; - } - - if ($Output_To_Stdout && $output_file) { - print STDERR "cannot pass both --stdout and --file\n"; - $exit_with_admonishment = 1; - } - - if ($XML_Output && $Cumulative) { - print STDERR "cannot pass both --xml and --accum\n"; - $exit_with_admonishment = 1; - } - - # Or if any other error message has already been printed out, we - # just leave now: - if ($exit_with_admonishment) { - &usage (); - exit (1); - } - elsif ($Print_Usage) { - &usage (); - exit (0); - } - elsif ($Print_Version) { - &version (); - exit (0); - } - - ## Else no problems, so proceed. - - if ($output_file) { - $Log_File_Name = $output_file; - } -} - - -sub slurp_file () -{ - my $filename = shift || die ("no filename passed to slurp_file()"); - my $retstr; - - open (SLURPEE, "<${filename}") or die ("unable to open $filename ($!)"); - my $saved_sep = $/; - undef $/; - $retstr = ; - $/ = $saved_sep; - close (SLURPEE); - return $retstr; -} - - -sub debug () -{ - if ($Debug) { - my $msg = shift; - print STDERR $msg; - } -} - - -sub version () -{ - print "cvs2cl.pl version ${VERSION}; distributed under the GNU GPL.\n"; -} - - -sub usage () -{ - &version (); - print <<'END_OF_INFO'; -Generate GNU-style ChangeLogs in CVS working copies. - -Notes about the output format(s): - - The default output of cvs2cl.pl is designed to be compact, formally - unambiguous, but still easy for humans to read. It is largely - self-explanatory, I hope; the one abbreviation that might not be - obvious is "utags". That stands for "universal tags" -- a - universal tag is one held by all the files in a given change entry. - - If you need output that's easy for a program to parse, use the - --xml option. Note that with XML output, just about all available - information is included with each change entry, whether you asked - for it or not, on the theory that your parser can ignore anything - it's not looking for. - -Notes about the options and arguments (the actual options are listed -last in this usage message): - - * The -I and -F options may appear multiple times. - - * To follow trunk revisions, use "-F trunk" ("-F TRUNK" also works). - This is okay because no would ever, ever be crazy enough to name a - branch "trunk", right? Right. - - * For the -U option, the UFILE should be formatted like - CVSROOT/users. That is, each line of UFILE looks like this - jrandom:jrandom@red-bean.com - or maybe even like this - jrandom:'Jesse Q. Random ' - Don't forget to quote the portion after the colon if necessary. - - * Many people want to filter by date. To do so, invoke cvs2cl.pl - like this: - cvs2cl.pl -l "-d'DATESPEC'" - where DATESPEC is any date specification valid for "cvs log -d". - (Note that CVS 1.10.7 and below requires there be no space between - -d and its argument). - -Options/Arguments: - - -h, -help, --help, or -? Show this usage and exit - --version Show version and exit - -r, --revisions Show revision numbers in output - -b, --branches Show branch names in revisions when possible - -t, --tags Show tags (symbolic names) in output - --stdin Read from stdin, don't run cvs log - --stdout Output to stdout not to ChangeLog - -d, --distributed Put ChangeLogs in subdirs - -f FILE, --file FILE Write to FILE instead of "ChangeLog" - --fsf Use this if log data is in FSF ChangeLog style - -W SECS, --window SECS Window of time within which log entries unify - -U UFILE, --usermap UFILE Expand usernames to email addresses from UFILE - -R REGEXP, --regexp REGEXP Include only entries that match REGEXP - -I REGEXP, --ignore REGEXP Ignore files whose names match REGEXP - -C, --case-insensitive Any regexp matching is done case-insensitively - -F BRANCH, --follow BRANCH Show only revisions on or ancestral to BRANCH - -S, --separate-header Blank line between each header and log message - --no-wrap Don't auto-wrap log message (recommend -S also) - --gmt, --utc Show times in GMT/UTC instead of local time - --accum Add to an existing ChangeLog (incompat w/ --xml) - -w, --day-of-week Show day of week - --header FILE Get ChangeLog header from FILE ("-" means stdin) - --xml Output XML instead of ChangeLog format - --hide-filenames Don't show filenames (ignored for XML output) - -P, --prune Don't show empty log messages - -g OPTS, --global-opts OPTS Invoke like this "cvs OPTS log ..." - -l OPTS, --log-opts OPTS Invoke like this "cvs ... log OPTS" - FILE1 [FILE2 ...] Show only log information for the named FILE(s) - -See http://www.red-bean.com/cvs2cl for maintenance and bug info. -END_OF_INFO -} - -__END__ - -=head1 NAME - -cvs2cl.pl - produces GNU-style ChangeLogs in CVS working copies, by - running "cvs log" and parsing the output. Shared log entries are - unified in an intuitive way. - -=head1 DESCRIPTION - -This script generates GNU-style ChangeLog files from CVS log -information. Basic usage: just run it inside a working copy and a -ChangeLog will appear. It requires repository access (i.e., 'cvs log' -must work). Run "cvs2cl.pl --help" to see more advanced options. - -See http://www.red-bean.com/cvs2cl for updates, and for instructions -on getting anonymous CVS access to this script. - -Maintainer: Karl Fogel -Please report bugs to . - -=head1 README - -This script generates GNU-style ChangeLog files from CVS log -information. Basic usage: just run it inside a working copy and a -ChangeLog will appear. It requires repository access (i.e., 'cvs log' -must work). Run "cvs2cl.pl --help" to see more advanced options. - -See http://www.red-bean.com/cvs2cl for updates, and for instructions -on getting anonymous CVS access to this script. - -Maintainer: Karl Fogel -Please report bugs to . - -=head1 PREREQUISITES - -This script requires C, C, and -C. -It also seems to require C or higher. - -=pod OSNAMES - -any - -=pod SCRIPT CATEGORIES - -Version_Control/CVS - -=cut - - --*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- - -Note about a bug-slash-opportunity: ------------------------------------ - -There's a bug in Text::Wrap, which affects cvs2cl. This script -reveals it: - - #!/usr/bin/perl -w - - use Text::Wrap; - - my $test_text = - "This script demonstrates a bug in Text::Wrap. The very long line - following this paragraph will be relocated relative to the surrounding - text: - - ==================================================================== - - See? When the bug happens, we'll get the line of equal signs below - this paragraph, even though it should be above."; - - - # Print out the test text with no wrapping: - print "$test_text"; - print "\n"; - print "\n"; - - # Now print it out wrapped, and see the bug: - print wrap ("\t", " ", "$test_text"); - print "\n"; - print "\n"; - -If the line of equal signs were one shorter, then the bug doesn't -happen. Interesting. - -Anyway, rather than fix this in Text::Wrap, we might as well write a -new wrap() which has the following much-needed features: - -* initial indentation, like current Text::Wrap() -* subsequent line indentation, like current Text::Wrap() -* user chooses among: force-break long words, leave them alone, or die()? -* preserve existing indentation: chopped chunks from an indented line - are indented by same (like this line, not counting the asterisk!) -* optional list of things to preserve on line starts, default ">" - -Note that the last two are essentially the same concept, so unify in -implementation and give a good interface to controlling them. - -And how about: - -Optionally, when encounter a line pre-indented by same as previous -line, then strip the newline and refill, but indent by the same. -Yeah... diff --git a/storage/ndb/home/bin/fix-cvs-root b/storage/ndb/home/bin/fix-cvs-root deleted file mode 100755 index 2c4f158f825..00000000000 --- a/storage/ndb/home/bin/fix-cvs-root +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/sh - -# change all CVS/Root to current CVSROOT - -[ "$CVSROOT" ] || { echo "no CVSROOT in environment" >&2; exit 1; } - -echo "changing all CVS/Root files under `pwd`" -sleep 1 - -find . -path '*/CVS/Root' -print | -while read file; do - echo "$file" - chmod +w $file || exit 1 - echo $CVSROOT >$file || exit 1 -done - -echo "done" diff --git a/storage/ndb/home/bin/import-from-bk.sh b/storage/ndb/home/bin/import-from-bk.sh deleted file mode 100755 index 4e3957be6d5..00000000000 --- a/storage/ndb/home/bin/import-from-bk.sh +++ /dev/null @@ -1,158 +0,0 @@ -#! /bin/sh - -# XXX does not delete files -# XXX does not handle nested new dirs -# this script screams for perl, no time now -# look for bk2cvs on the net - -PATH=/usr/local/bin:$PATH; export PATH -LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH - -batch=n -if [ "$1" = "-batch" ]; then - batch=y - shift -fi - -say() { - echo "$*" -} - -die() { - case $# in - 0) set -- "command failed" ;; - esac - say "$* -- aborted" >&2 - exit 1 -} - -usage() { - die "usage: $0 [-batch] top -- copy from mysql/ndb to another NDB_TOP" -} - -doit() { - cmd="$*" - if [ $batch = n ]; then - echo -n "$cmd [y]" - read junk - sh -c "$cmd" - return 0 - else - echo "$cmd" - sh -c "$cmd" - return $? - fi -} - -say "======================" -say "`date`" - -case $# in -1) [ -d $1/src/CVS ] || die "$1 is not an NDB_TOP" - top=$1 ;; -*) usage ;; -esac - -if ! fgrep ndb_kernel_version.h $top/include/kernel/CVS/Entries >/dev/null 2>&1; then - die "$top is not an NDB_TOP" -fi - -if find $top -path '*/CVS/Tag' -print | grep . >/dev/null; then - die "$top: contains CVS/Tag files, not accepted" -fi - -if [ ! -f include/SCCS/s.ndb_version.h ]; then - die "current dir ($PWD) is not an NDB_TOP" -fi - -doit "bk pull" || exit 1 -doit "bk -r clean" -doit "bk -r get -q" - -files=`bk -r. sfiles -g | - fgrep -v ' ' | - fgrep -v /.cvsignore` - -n=0 -files2= -for f in $files; do - if [ ! -f $f ]; then - die "$f: no such file" - fi - if [ -w $f ]; then - say "$f: is writable, accept anyway" - fi - files2="$files2 $f" - n=$((n+1)) -done -files=$files2 -say "$n files..." - -adddirs= addfiles= updfiles= -for f in $files; do - d=`dirname $f` - b=`basename $f` - if [ ! -f $top/$d/CVS/Entries ]; then - found=n - for x in $adddirs; do - if [ $x = $d ]; then found=y; break; fi - done - if [ $found = n ]; then - say "$d: to create dir" - adddirs="$adddirs $d" - fi - addfiles="$addfiles $f" - say "$f: to create" - elif ! fgrep "/$b/" $top/$d/CVS/Entries >/dev/null; then - addfiles="$addfiles $f" - say "$f: to create" - else - cmp $f $top/$f >/dev/null - case $? in - 0) continue ;; - 1) ;; - *) die "$f: unknown error" ;; - esac - updfiles="$updfiles $f" - say "$f: to update" - fi -done - -for d in $adddirs; do - doit "cd $top && mkdir -p $d" || die -done - -for f in $addfiles $updfiles; do - doit "cp -fp $f $top/$f" || die -done - -for d in $adddirs; do - # fix 1 level up - d2=`dirname $d` - if [ ! -d $top/$d2/CVS ]; then - doit "cd $top && cvs add $d2" || die - fi - doit "cd $top && cvs add $d" || die -done - -for f in $addfiles; do - kb= - if echo $f | perl -nle "print(-B $_)" | grep 1 >/dev/null; then - kb="-kb" - fi - doit "cd $top && cvs add $kb $f" || die -done - -tag=import_bk_`date +%Y_%m_%d` - -doit "cd $top && cvs commit -m $tag" || die -doit "cd $top && cvs tag -F $tag" || die - -env="NDB_TOP=$top; export NDB_TOP" -env="$env; USER_FLAGS='-DAPI_TRACE -fmessage-length=0'; export USER_FLAGS" -doit "$env; cd $top && ./configure" -doit "$env; cd $top && sh config/GuessConfig.sh" -doit "$env; cd $top && make clean nuke-deps vim-tags" -doit "$env; cd $top && make" || die - -say "imported ok" diff --git a/storage/ndb/home/bin/ndb_deploy b/storage/ndb/home/bin/ndb_deploy deleted file mode 100755 index 773fc9b8fd7..00000000000 --- a/storage/ndb/home/bin/ndb_deploy +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -if [ $# -eq 0 ] -then - for i in $DEPLOY_DST - do - rsync -r -v --exclude '*.a' $NDB_TOP/bin $NDB_TOP/lib $i/ - done -else - while [ $# -gt 0 ] - do - arg=$1 - shift; - if [ `echo $arg | grep -c lib` -eq 0 ] - then - dst=bin/ - else - dst=lib/ - fi - - for i in $DEPLOY_DST - do - rsync -v $arg $i/$dst - done - done -fi - diff --git a/storage/ndb/home/bin/ndbdoxy.pl b/storage/ndb/home/bin/ndbdoxy.pl deleted file mode 100755 index 89b7de8440e..00000000000 --- a/storage/ndb/home/bin/ndbdoxy.pl +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/local/bin/perl -# -# ndbdoxy.pl Executes doxygen on a checked out version of NDB Cluster -# -# Written by Lars Thalmann, 2003. - -use strict; -umask 000; - -# ----------------------------------------------------------------------------- -# Settings -# ----------------------------------------------------------------------------- - -my $root = "/home/elathal/public_html/cvsdoxy"; - -$ENV{LD_LIBRARY_PATH} = "/usr/local/lib:/opt/as/local/lib"; -$ENV{LD_LIBRARY_PATH} = $ENV{LD_LIBRARY_PATH} . ":/opt/as/forte6/SUNWspro/lib"; -$ENV{PATH} = $ENV{PATH} . ":/usr/local/bin:/opt/as/local/bin"; -$ENV{PATH} = $ENV{PATH} . ":/opt/as/local/teTeX/bin/sparc-sun-solaris2.8"; - -my $DOXYGEN = "doxygen"; -my $PDFLATEX = "pdflatex"; -my $MAKEINDEX = "makeindex"; - -# ----------------------------------------------------------------------------- -# Argument handling -# ----------------------------------------------------------------------------- - -if (@ARGV != 3) { - print< <version> - - where - <module> is cvsdoxy module to doxgenify - <title> is title of report - <version> is version of NDB Cluster -END - exit; -} -my $module = $ARGV[0]; -my $title = $ARGV[1]; -my $version = $ARGV[2]; -my $destdir = "."; - -# ----------------------------------------------------------------------------- -# Execute Doxygen -g -# ----------------------------------------------------------------------------- - -if (-r "${root}/doxyfiles/${module}.doxyfile") { - system("cd ${destdir}; \ - cp ${root}/doxyfiles/${module}.doxyfile Doxyfile"); -} elsif (-r "${root}/doxyfiles/default.doxyfile") { - system("cd ${destdir}; \ - cp ${root}/doxyfiles/default.doxyfile Doxyfile"); -} else { - system("cd ${destdir}; $DOXYGEN -g"); -} - -# ----------------------------------------------------------------------------- -# HTML Footer -# ----------------------------------------------------------------------------- - -if (-r "${root}/doxyfiles/htmlfooter") { - system("cd ${destdir}; \ - cp ${root}/doxyfiles/htmlfooter footer.html"); - - open (INFILE, "< ${destdir}/footer.html") - or die "Error opening ${destdir}/footer.html.\n"; - open (OUTFILE, "> ${destdir}/footer.html.new") - or die "Error opening ${destdir}/footer.html.new.\n"; - while (<INFILE>) { - if (/(.*)DATE(.*)$/) { - print OUTFILE $1 . localtime() . $2; - } else { - print OUTFILE; - } - } - close INFILE; - close OUTFILE; - - system("mv ${destdir}/footer.html.new ${destdir}/footer.html"); -} else { - print("Warning: No ${root}/doxyfiles/${module}.htmlfooter"); -} - -# ----------------------------------------------------------------------------- -# Execute Doxygen -# ----------------------------------------------------------------------------- - -system("cd ${destdir}; $DOXYGEN"); - -# ----------------------------------------------------------------------------- -# Change a little in refman.tex -# ----------------------------------------------------------------------------- - -open (INFILE, "< ${destdir}/latex/refman.tex") - or die "Error opening ${destdir}/latex/refman.tex.\n"; -open (OUTFILE, "> ${destdir}/latex/refman.tex.new") - or die "Error opening ${destdir}/latex/refman.tex.new.\n"; - -while (<INFILE>) -{ - if (/(.*)Reference Manual(.*)$/) { - print OUTFILE $1 . - "\\mbox{}\\vspace{-3cm}\\mbox{}" . - "\\hrule\\bigskip\\bigskip\\bigskip\\bigskip" . - "\\Huge{" . $title . "}" . $2; - } elsif (/(.*)Generated by Doxygen 1.2.1[0-9](.*)$/) { - print OUTFILE $1 . - "\\begin{center}" . - "\\LARGE{MySQL AB}" . - "\\end{center}". - "\\hfill\\bigskip\\bigskip\\bigskip\\hrule" . - "\\bigskip\\bigskip\\bigskip\\bigskip\\bigskip" . - "\\bigskip\\bigskip\\bigskip\\bigskip\\bigskip" . - "\\bigskip\\bigskip NDB Cluster Release " . $version . - "\\bigskip\\bigskip\\bigskip\\bigskip\\bigskip\\hfill" . - $2; - } elsif (/\\chapter\{File Index\}/) { - print OUTFILE "\%\\chapter{File Index}\n"; - } elsif (/\\input{files}/) { - print OUTFILE "\%\\input{files}\n"; - } elsif (/\\chapter\{Page Index\}/) { - print OUTFILE "\%\\chapter{Page Index}\n"; - } elsif (/\\input{pages}/) { - print OUTFILE "\%\\input{pages}\n"; - } else { - print OUTFILE; - } -} - -close INFILE; -close OUTFILE; - -system("mv ${destdir}/latex/refman.tex.new ${destdir}/latex/refman.tex"); - -# ----------------------------------------------------------------------------- -# Change a little in doxygen.sty -# ----------------------------------------------------------------------------- - -open (INFILE, "< ${destdir}/latex/doxygen.sty") - or die "Error opening INFILE.\n"; -open (OUTFILE, "> ${destdir}/latex/doxygen.sty.new") - or die "Error opening OUTFILE.\n"; - -while (<INFILE>) -{ - if (/\\rfoot/) { - print OUTFILE "\\rfoot[\\fancyplain{}{\\bfseries\\small \\copyright~Copyright 2003 MySQL AB\\hfill support-cluster\@mysql.com}]{}\n"; - } elsif (/\\lfoot/) { - print OUTFILE "\\lfoot[]{\\fancyplain{}{\\bfseries\\small support-cluster\@mysql.com\\hfill \\copyright~Copyright 2003 MySQL AB}}\n"; - } else { - print OUTFILE; - } -} - -close INFILE; -close OUTFILE; - -system("mv ${destdir}/latex/doxygen.sty.new ${destdir}/latex/doxygen.sty"); - -# ----------------------------------------------------------------------------- -# Other -# ----------------------------------------------------------------------------- - -#system("cd ${root}/tmp/${module}; \ -# mkdir html.tar; \ -# cd html.tar; \ -# cp -r ../html ${module}; \ -# tar cf ${module}.html.tar ${module}; \ -# /usr/local/bin/gzip ${module}.html.tar; \ -# /bin/rm -rf ${root}/tmp/${module}/html.tar/${module}"); - -#system("cd ${destdir}/latex/; \ -# $PDFLATEX refman.tex \ -# $MAKEINDEX refman.idx \ -# $PDFLATEX refman.tex \ -# mv -f refman.pdf ${module}.pdf"); - -print<<END; -Execute: - latex refman; makeindex refman; latex refman -END diff --git a/storage/ndb/home/bin/ngcalc b/storage/ndb/home/bin/ngcalc deleted file mode 100755 index a289d384db9..00000000000 --- a/storage/ndb/home/bin/ngcalc +++ /dev/null @@ -1,78 +0,0 @@ -#! /usr/local/bin/perl - -use strict; -use Getopt::Long; - -sub usage { - print <<END; -ngcalc -- calculate node groups and table fragments -usage: ngcalc [ options ] f1 f2 ... --g num number of node groups (default 2) --r num number of replicas (default 2) --n list comma-separated list of db nodes (default 1,2,...) -fX number of fragments per node group in table X (e.g. 1,2,8) - (all replicas count as same fragment) -END - exit(1); -}; - -use vars qw($cnoOfNodeGroups $cnoReplicas $nodeArray); - -$cnoOfNodeGroups = 2; -$cnoReplicas = 2; -GetOptions( - "g=i" => \$cnoOfNodeGroups, - "r=i" => \$cnoReplicas, - "n=s" => \$nodeArray, -) or &usage; - -my @tableList = @ARGV; - -$cnoOfNodeGroups > 0 or &usage; -$cnoReplicas > 0 or &usage; -if (! defined($nodeArray)) { - $nodeArray = join(',', 1..($cnoOfNodeGroups*$cnoReplicas)); -} -$nodeArray =~ /^\d+(,\d+)*$/ or &usage; -my @nodeArray = split(/,/, $nodeArray); -@nodeArray == $cnoOfNodeGroups*$cnoReplicas or &usage; - -my @nodeGroupRecord; -for (my $i = 0; $i < $cnoOfNodeGroups; $i++) { - my $rec = {}; - my $nodes = []; - for (my $j = 0; $j < $cnoReplicas; $j++) { - push(@$nodes, $nodeArray[$i * $cnoReplicas + $j]); - } - $rec->{nodesInGroup} = $nodes; - $rec->{nodeCount} = $cnoReplicas; - $rec->{nextReplicaNode} = 0; - $nodeGroupRecord[$i] = $rec; - print "NG $i: ", join(" ", @{$rec->{nodesInGroup}}), "\n"; -} - -# see Dbdih::execCREATE_FRAGMENTATION_REQ - -my $c_nextNodeGroup = 0; -for (my $t = 0; $t < @tableList; $t++) { - use integer; - my $f = $tableList[$t]; - my $ng = $c_nextNodeGroup++; - $c_nextNodeGroup = 0 if $c_nextNodeGroup == $cnoOfNodeGroups; - my $noOfFragments = $f * $cnoOfNodeGroups; - my @fragments; - for (my $fragNo = 0; $fragNo < $noOfFragments; $fragNo++) { - my $rec = $nodeGroupRecord[$ng]; - my $max = $rec->{nodeCount}; - my $ind = $rec->{nextReplicaNode}; - $rec->{nextReplicaNode} = ($ind + 1 >= $max ? 0 : $ind + 1); - for (my $replicaNo = 0; $replicaNo < $cnoReplicas; $replicaNo++) { - my $nodeId = $rec->{nodesInGroup}[$ind++]; - push(@fragments, $nodeId); - $ind = ($ind == $max ? 0 : $ind); - } - $ng++; - $ng = ($ng == $cnoOfNodeGroups ? 0 : $ng); - } - printf "%02d %s\n", $t, join(" ", @fragments); -} diff --git a/storage/ndb/home/bin/parseConfigFile.awk b/storage/ndb/home/bin/parseConfigFile.awk deleted file mode 100644 index 6903949156c..00000000000 --- a/storage/ndb/home/bin/parseConfigFile.awk +++ /dev/null @@ -1,98 +0,0 @@ -BEGIN{ - where=0; - n_hosts=0; - n_api=0; - n_ndb=0; - n_mgm=0; - n_ports=0; -} -/COMPUTERS/ { - where=1; -} -/\[[ \t]*COMPUTER[ \t]*\]/ { - where=1; -} -/PROCESSES/ { - where=2; -} -/Type: MGMT/ { - if(where!=1){ - where=2; - n_mgm++; - } -} -/\[[ \t]*MGM[ \t]*\]/ { - where=2; - n_mgm++; -} -/Type: DB/ { - if(where!=1){ - where=3; - n_ndb++; - } -} -/\[[ \t]*DB[ \t]*\]/ { - where=3; - n_ndb++; -} -/Type: API/ { - if(where!=1){ - where=4; - n_api++; - } -} -/\[[ \t]*API[ \t]*\]/ { - where=4; - n_api++; -} -/HostName:/ { - host_names[host_ids[n_hosts]]=$2; -} - -/FileSystemPath:/ { - if (where==3){ - ndb_fs[ndb_ids[n_ndb]]=$2; - } -} - -/Id:/{ - if(where==1){ - n_hosts++; - host_ids[n_hosts]=$2; - } - if(where==2){ - mgm_ids[n_mgm]=$2; - } - if(where==3){ - ndb_ids[n_ndb]=$2; - } - if(where==4){ - api_ids[n_api]=$2; - } -} -/ExecuteOnComputer:/{ - if(where==2){ - mgm_hosts[mgm_ids[n_mgm]]=host_names[$2]; - } - if(where==3){ - ndb_hosts[ndb_ids[n_ndb]]=host_names[$2]; - } - if(where==4){ - api_hosts[api_ids[n_api]]=host_names[$2]; - } -} -END { - for(i=1; i<=n_mgm; i++){ - printf("mgm_%d=%s\n", mgm_ids[i], mgm_hosts[mgm_ids[i]]); - } - for(i=1; i<=n_ndb; i++){ - printf("ndb_%d=%s\n", ndb_ids[i], ndb_hosts[ndb_ids[i]]); - printf("ndbfs_%d=%s\n", ndb_ids[i], ndb_fs[ndb_ids[i]]); - } - for(i=1; i<=n_api; i++){ - printf("api_%d=%s\n", api_ids[i], api_hosts[api_ids[i]]); - } - printf("mgm_nodes=%d\n", n_mgm); - printf("ndb_nodes=%d\n", n_ndb); - printf("api_nodes=%d\n", n_api); -} diff --git a/storage/ndb/home/bin/setup-test.sh b/storage/ndb/home/bin/setup-test.sh deleted file mode 100755 index 61097c30027..00000000000 --- a/storage/ndb/home/bin/setup-test.sh +++ /dev/null @@ -1,272 +0,0 @@ -#!/bin/sh - -# NAME -# run-test.sh - Run a test program -# -# SYNOPSIS -# setup-test.sh [ -n <ndb dir>] [ -r <run dir>] -# -# DESCRIPTION -# run a test -# -# OPTIONS -# -# EXAMPLES -# -# ENVIRONMENT -# NDB_PROJ_HOME Home dir for ndb -# -# FILES -# $NDB_PROJ_HOME/lib/funcs.sh shell script functions -# -# DIAGNOSTICTS -# -# VERSION -# 1.01 -# -# AUTHOR -# Jonas Oreland -# -# - -progname=`basename $0` -synopsis="setup-test.sh [-x xterm] [ -n <ndb dir>] [ -r <run dir>]" - -: ${NDB_PROJ_HOME:?} # If undefined, exit with error message - -: ${RUN_NDB_NODE_OPTIONS:=--} # If undef, set to --. Keeps getopts happy. - # You may have to experiment a bit - # to get quoting right (if you need it). - - -. $NDB_PROJ_HOME/lib/funcs.sh # Load some good stuff - -# defaults for options related variables -# - -verbose=yes -options="" -ndb_dir=$NDB_TOP -if [ -z "$ndb_dir" ] -then - ndb_dir=`pwd` -fi - -local_dir=`pwd` -own_host=`hostname` -uniq_id=$$.$$ - -_xterm=$XTERM -_rlogin="ssh -X" - -# used if error when parsing the options environment variable -# -env_opterr="options environment variable: <<$options>>" - - -# Option parsing, for the options variable as well as the command line. -# -# We want to be able to set options in an environment variable, -# as well as on the command line. In order not to have to repeat -# the same getopts information twice, we loop two times over the -# getopts while loop. The first time, we process options from -# the options environment variable, the second time we process -# options from the command line. -# -# The things to change are the actual options and what they do. -# -# -for optstring in "$options" "" # 1. options variable 2. cmd line -do - while getopts n:r:x: i $optstring # optstring empty => no arg => cmd line - do - case $i in - - n) ndb_dir=$OPTARG;; # Ndb dir - r) run_dir=$OPTARG;; # Run dir - x) _xterm=$OPTARG;; - \?) syndie $env_opterr;; # print synopsis and exit - - esac - done - - [ -n "$optstring" ] && OPTIND=1 # Reset for round 2, cmdline options - - env_opterr= # Round 2 should not use the value - -done -shift `expr $OPTIND - 1` - -# --- option parsing done --- - -ndb_dir=`abspath $ndb_dir` -run_dir=`abspath $run_dir` - -trace "Verifying arguments" - -if [ ! -d $ndb_dir/bin ] || [ ! -d $ndb_dir/lib ] -then - msg "Ndb home path seems incorrect either $ndb_dir/bin or $ndb_dir/lib not found" - exit 1004 -fi - -ndb_bin=$ndb_dir/bin/ndb -mgm_bin=$ndb_dir/bin/mgmtsrvr -api_lib=$ndb_dir/lib/libNDB_API.so - -if [ ! -x $ndb_bin ] -then - msg "Ndb path seems incorrect ndb binary not found: $ndb_bin" - exit 1004 -fi - -if [ ! -x $mgm_bin ] -then - msg "Ndb path seems incorrect management server binary not found: $mgm_bin" - exit 1004 -fi - -init_config=$run_dir/mgm.1/initconfig.txt -local_config=$run_dir/mgm.1/localcfg.txt -if [ ! -r $init_config ] || [ ! -r $local_config ] -then - msg "Run path seems incorrect $init_config or $local_config not found" - exit 1004 -fi - -trace "Parsing $init_config" -awk -f $NDB_PROJ_HOME/bin/parseConfigFile.awk $init_config > /tmp/run-test.$uniq_id -. /tmp/run-test.$uniq_id -cat /tmp/run-test.$uniq_id -rm -f /tmp/run-test.$uniq_id - -trace "Parsing $local_config" -MgmPort=`grep -v "OwnProcessId" $local_config | cut -d " " -f 2` - -trace "Verifying that mgm port is empty" -telnet $mgm_1 $MgmPort > /tmp/mgm_port.$uniq_id 2>&1 <<EOF -EOF - -if [ 0 -lt `grep -c -i connected /tmp/mgm_port.$uniq_id` ] -then - rm /tmp/mgm_port.$uniq_id - msg "There is already something using port $mgm_1:$MgmPort" - exit 1003 -fi -rm /tmp/mgm_port.$uniq_id - -fixhost(){ - if [ "$1" != localhost ] - then - echo $1 - else - uname -n - fi -} - -do_xterm(){ - title=$1 - shift - xterm -fg black -title "$title" -e $* -} - -save_profile(){ - cp $HOME/.profile /tmp/.profile.$uniq_id -} - -wait_restore_profile(){ - while [ -r /tmp/.profile.$uniq_id ] - do - sleep 1 - done -} - -start_mgm(){ - trace "Starting Management server on: $mgm_1" - save_profile - mgm_1=`fixhost $mgm_1` - - ( - echo "PATH=$ndb_dir/bin:\$PATH" - echo "LD_LIBRARY_PATH=$ndb_dir/lib:\$LD_LIBRARY_PATH" - echo "export PATH LD_LIBRARY_PATH" - echo "cd $run_dir/mgm.1" - echo "ulimit -Sc unlimited" - echo "mv /tmp/.profile.$uniq_id $HOME/.profile" - ) >> $HOME/.profile - do_xterm "Mmg on $mgm_1" ${_rlogin} $mgm_1 & - wait_restore_profile -} - -start_ndb_node(){ - node_id=$1 - dir=$run_dir/ndb.$1 - ndb_host=`eval echo "\$"ndb_$node_id` - ndb_host=`fixhost $ndb_host` - ndb_fs=`eval echo "\$"ndbfs_$node_id` - - trace "Starting Ndb node $node_id on $ndb_host" - save_profile - - ( - echo "PATH=$ndb_dir/bin:\$PATH" - echo "LD_LIBRARY_PATH=$ndb_dir/lib:\$LD_LIBRARY_PATH" - echo "mkdir -p $ndb_fs" - echo "export PATH LD_LIBRARY_PATH" - echo "cd $dir" - echo "ulimit -Sc unlimited" - echo "mv /tmp/.profile.$uniq_id $HOME/.profile" - ) >> $HOME/.profile - do_xterm "Ndb: $node_id on $ndb_host" ${_rlogin} $ndb_host & - wait_restore_profile -} - -start_api_node(){ - node_id=$1 - dir=$run_dir/api.$1 - api_host=`eval echo "\$"api_$node_id` - api_host=`fixhost $api_host` - - trace "Starting api node $node_id on $api_host" - save_profile - - ( - echo "PATH=$ndb_dir/bin:\$PATH" - echo "LD_LIBRARY_PATH=$ndb_dir/lib:\$LD_LIBRARY_PATH" - echo "export PATH LD_LIBRARY_PATH NDB_PROJ_HOME" - echo "cd $dir" - echo "ulimit -Sc unlimited" - echo "mv /tmp/.profile.$uniq_id $HOME/.profile" - ) >> $HOME/.profile - do_xterm "API: $node_id on $api_host" ${_rlogin} $api_host & - wait_restore_profile -} - -for_each_ndb_node(){ - i=1 - j=`expr $mgm_nodes + 1` - while [ $i -le $ndb_nodes ] - do - $* $j - j=`expr $j + 1` - i=`expr $i + 1` - done -} - -for_each_api_node(){ - i=1 - j=`expr $mgm_nodes + $ndb_nodes + 1` - while [ $i -le $api_nodes ] - do - $* $j - j=`expr $j + 1` - i=`expr $i + 1` - done -} - -start_mgm -for_each_ndb_node start_ndb_node -for_each_api_node start_api_node - -exit 0 - diff --git a/storage/ndb/home/bin/signallog2html.lib/signallog2list.awk b/storage/ndb/home/bin/signallog2html.lib/signallog2list.awk deleted file mode 100644 index 9839f314556..00000000000 --- a/storage/ndb/home/bin/signallog2html.lib/signallog2list.awk +++ /dev/null @@ -1,102 +0,0 @@ -BEGIN{ - PRINT=0; - SIGNAL_ARRAY[0]=""; - BLOCK_ID=0; - SIGNAL_ID=-22; -} -{ - SIGNAL_ARRAY[SIGNAL_ID]=SIGNAL_ID; -} - -/^---- Send ----- Signal ----------------/ { - DIRECTION="S"; - SENDER=""; - SENDPROCESS=""; - RECEIVER=""; - RECPROCESS=""; - SIGNAL=""; - RECSIGID="?"; - SIGID="?"; - DELAY="N/A"; -} - -/^---- Send delay Signal/ { - DIRECTION="SD"; - SENDER=""; - SENDPROCESS=""; - RECEIVER=""; - RECPROCESS=""; - SIGNAL=""; - RECSIGID="?"; - SIGID="?"; - DELAY=$5; - - LEN=length(DELAY); - DELAY=substr(DELAY,2,LEN); -} - -/^---- Received - Signal ----------------/ { - DIRECTION="R"; - SENDER=""; - SENDPROCESS=""; - RECEIVER=""; - RECPROCESS=""; - SIGNAL=""; - RECSIGID="?"; - SIGID="?"; - DELAY="N/A"; -} - -/r.bn:/{ - - RECEIVER=$3; - RECPROCESS=$5; - - if(DIRECTION == "R"){ - SIGNAL=$10; - RECSIGID=$7; - } - else - SIGNAL=$8; -} - -/s.bn:/{ - - SENDER=$3; - SIGID=$7; - - if(SIGID == SIGNAL_ARRAY[SIGID]){ - PRINT=1; - if(DIRECTION == "R"){ - SIGNAL_ARRAY[RECSIGID]=RECSIGID; - }; - } - - SENDPROCESS=$5; - - LEN=length(RECEIVER); - RECEIVER=substr(RECEIVER,2,LEN-3); - - if(BLOCK_ID == "ALL" || RECEIVER==BLOCK_ID){PRINT=1; } - - LEN=length(SENDER); - SENDER=substr(SENDER,2,LEN-3); - if(BLOCK_ID == "ALL" || SENDER == BLOCK_ID){ PRINT=1;} - - LEN=length(SIGNAL); - SIGNAL=substr(SIGNAL,2,LEN-2); - - LEN=length(SENDPROCESS); - SENDPROCESS=substr(SENDPROCESS,1,LEN-1); - - LEN=length(RECPROCESS); - RECPROCESS=substr(RECPROCESS,1,LEN-1); - - if( PRINT == 1){ - print DIRECTION" "SENDPROCESS" "SENDER" "RECPROCESS" "RECEIVER" "SIGNAL" "SIGID" "RECSIGID" "DELAY; - } - - PRINT=0; -} - - diff --git a/storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk b/storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk deleted file mode 100644 index 43f48d1cde1..00000000000 --- a/storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk +++ /dev/null @@ -1,29 +0,0 @@ -BEGIN{ - NAMES[""]=""; - ORDER[0]=""; - NUM=0; -} - -{ - if(NAMES[$2$3]!=$2$3){ - NAMES[$2$3]=$2$3; - ORDER[NUM]=$2$3; - NUM++; - } - - if(NAMES[$4$5]!=$4$5){ - NAMES[$4$5]=$4$5; - ORDER[NUM]=$4$5; - NUM++; - } - - -} -END{ - for(i=0; i<NUM; i++){ - LIST=ORDER[i]" "LIST; - - } - print LIST; -} - diff --git a/storage/ndb/home/bin/signallog2html.sh b/storage/ndb/home/bin/signallog2html.sh deleted file mode 100755 index 5665275807c..00000000000 --- a/storage/ndb/home/bin/signallog2html.sh +++ /dev/null @@ -1,349 +0,0 @@ -#!/bin/sh -# NAME -# signallog2html.sh -# -# SYNOPSIS -# signallog2html.sh [ -b <block_name | ALL> ] [ -s <signal_id> ] -f signal_log_file -# -# DESCRIPTION -# Creates a signal sequence diagram in HTML format that can be -# viewed from a web browser. The HTML file is created from a signal -# log file and it contains a big table with jpeg files in every -# table cell. Every row in the table is a signal. The block_name -# could be one of the following: CMVMI MISSRA NDBFS NDBCNTR DBACC -# DBDICT DBLQH DBDIH DBTC DBTUP QMGR ALL. The signal_id is a -# number. If no block_name or signal_id is given the default -# block_name "ALL" is used. -# -# -# -# OPTIONS -# -# EXAMPLES -# -# -# ENVIRONMENT -# NDB_PROJ_HOME Home dir for ndb -# -# FILES -# $NDB_PROJ_HOME/lib/funcs.sh General shell script functions. -# uniq_blocks.awk Creates a list of unique blocks -# in the signal_log_file. -# signallog2list.awk Creates a list file from the signal_log_file. -# empty.JPG Jpeg file, must exist in the HTML file -# directory for viewing. -# left_line.JPG -# line.JPG -# right_line.JPG -# self_line.JPG -# -# -# SEE ALSO -# -# DIAGNOSTICTS -# -# VERSION -# 1.0 -# -# DATE -# 011029 -# -# AUTHOR -# Jan Markborg -# - -progname=`basename $0` -synopsis="signallog2html.sh [ -b <block_name | ALL> ] [ -s <signal_id> ] -f signal_log_file" -block_name="" -signal_id="" -verbose=yes -signal_log_file="" - -: ${NDB_PROJ_HOME:?} # If undefined, exit with error message - -: ${NDB_LOCAL_BUILD_OPTIONS:=--} # If undef, set to --. Keeps getopts happy. - # You may have to experiment a bit - # to get quoting right (if you need it). - - -. $NDB_PROJ_HOME/lib/funcs.sh # Load some good stuff - -# defaults for options related variables -# -report_date=`date '+%Y-%m-%d'` - -# Option parsing for the the command line. -# - -while getopts f:b:s: i -do - case $i in - f) signal_log_file=$OPTARG;; - b) block_name=$OPTARG;; - s) signal_id=$OPTARG;; - \?) syndie ;; # print synopsis and exit - esac -done - -# -- Verify -trace "Verifying signal_log_file $signal_log_file" - -if [ x$signal_log_file = "x" ] -then - syndie "Invalid signal_log_file name: $signal_log_file not found" -fi - - -if [ ! -r $signal_log_file ] -then - syndie "Invalid signal_log_file name: $signal_log_file not found" -fi - - - -if [ blocknameSET = 1 ] -then - - trace "Verifying block_name" - case $block_name in - CMVMI| MISSRA| NDBFS| NDBCNTR| DBACC| DBDICT| DBLQH| DBDIH| DBTC| DBTUP| QMGR);; - ALL) trace "Signals to/from every block will be traced!";; - *) syndie "Unknown block name: $block_name";; - esac -fi - -if [ block_name="" -a signal_id="" ] -then - block_name=ALL - trace "block_name = $block_name" -fi - -trace "Arguments OK" - -### -# -# General html functions -header(){ - cat <<EOF -<html><head><title>$* - -EOF -} - -footer(){ - cat < -EOF -} - -heading(){ - h=$1; shift - cat <$* -EOF -} - -table(){ - echo "" -} - -table_header(){ - echo "" -} - -end_table(){ - echo "
$*
" -} - -row(){ - echo "" -} - -end_row(){ - echo "" -} - -c_column(){ - cat <$* -EOF -} - -bold(){ - cat <$*
-EOF -} - -column(){ - cat <$* -EOF -} - -para(){ - cat <

-EOF -} - -hr(){ - cat < -EOF -} - -img_column(){ - cat <
<$* height=100% width=100%>
-EOF -} - -# Check the direction of arrow. -# arrowDirection(){ $columnarray $sendnode$sendblock $recnode$recblock -arrowDirection(){ -if [ $2 = $3 ] -then - arrow=SELF - return; -else - for x in $1 - do - if [ $x = $2 ] - then - arrow=RIGHT - break - elif [ $x = $3 ] - then - arrow=LEFT - break - fi - done -fi -} - -drawImages(){ -for x in $columnarray -do - case $arrow in - SELF) - if [ $x = $sendnode$sendblock ] - then - img_column img SRC=\"self_line.JPG\" - else - img_column img SRC=\"empty.JPG\" - fi;; - - RIGHT) - if [ $x = $recnode$recblock ] - then - img_column img SRC=\"right_line.JPG\" - weHavePassedRec=1 - elif [ $x = $sendnode$sendblock ] - then - img_column img SRC=\"empty.JPG\" - weHavePassedSen=1 - elif [ $weHavePassedRec = 1 -o $weHavePassedSen = 0 ] - then - img_column img SRC=\"empty.JPG\" - elif [ $weHavePassedRec = 0 -a $weHavePassedSen = 1 ] - then - img_column img SRC=\"line.JPG\" - fi;; - - LEFT) - if [ $x = $recnode$recblock ] - then - img_column img SRC=\"empty.JPG\" - weHaveJustPassedRec=1 - weHavePassedRec=1 - continue - fi - if [ $x = $sendnode$sendblock -a $weHaveJustPassedRec = 1 ] - then - img_column img SRC=\"left_line.JPG\" - weHaveJustPassedRec=0 - weHavePassedSen=1 - continue - fi - if [ $x = $sendnode$sendblock ] - then - img_column img SRC=\"line.JPG\" - weHavePassedSen=1 - continue - fi - if [ $weHaveJustPassedRec = 1 ] - then - img_column img SRC=\"left_line.JPG\" - weHaveJustPassedRec=0 - continue - fi - if [ $weHavePassedSen = 1 -o $weHavePassedRec = 0 ] - then - img_column img SRC=\"empty.JPG\" - continue - fi - - if [ $weHavePassedRec = 1 -a $weHavePassedSen = 0 ] - then - img_column img SRC=\"line.JPG\" - continue - - fi - column ERROR;; - - *) - echo ERROR;; - esac -done -column $signal -} - -### Main -trace "Making HTML file" -( - header "Signal sequence diagram $report_date" - heading 1 "Signal sequence diagram $report_date" - - trace "Making list file" - #make a signal list file from the signal log file. - `awk -f /home/ndb/bin/signallog2html.lib/signallog2list.awk SIGNAL_ID=$signal_id BLOCK_ID=$block_name $signal_log_file > $signal_log_file.list` - - COLUMNS=`awk -f /home/ndb/bin/signallog2html.lib/uniq_blocks.awk $signal_log_file.list | wc -w` - - table "border=0 cellspacing=0 cellpadding=0 cols=`expr $COLUMNS + 1`" - - columnarray=`awk -f /home/ndb/bin/signallog2html.lib/uniq_blocks.awk $signal_log_file.list` - - row - column #make an empty first column! - for col in $columnarray - do - table_header $col - done - - grep "" $signal_log_file.list | \ - while read direction sendnode sendblock recnode recblock signal sigid recsigid delay - do - if [ $direction = "R" ] - then - row - weHavePassedRec=0 - weHavePassedSen=0 - weHaveJustPassedRec=0 - arrow="" - - # calculate the direction of the arrow. - arrowDirection "$columnarray" "$sendnode$sendblock" "$recnode$recblock" - - # Draw the arrow images. - drawImages - end_row - fi - done - end_table - - footer -) > $signal_log_file.html - -exit 0 diff --git a/storage/ndb/home/bin/stripcr b/storage/ndb/home/bin/stripcr deleted file mode 100755 index 540418f88cf..00000000000 --- a/storage/ndb/home/bin/stripcr +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/sh - - -# NAME -# stripcr - a program for removing carriage return chars from dos-files. -# -# SYNOPSIS -# stripcr [file...] -# -# DESCRIPTION -# stripcr deletes all CR characters from the given files. -# The files are edited in place. -# If no files are given, stdin and stdout are used instead. -# -# OPTIONS -# -s extension Make a copy of the original of each file, and -# give it the given extension (.bak, .orig, -bak, ...). -# -# EXAMPLES -# stripcr file.txt innerloop.cc -# stripcr -i.bak *.cc -# -# ENVIRONMENT -# NDB_PROJ_HOME Home dir for ndb -# -# FILES -# $NDB_PROJ_HOME/lib/funcs.sh Some userful functions for safe execution -# of commands, printing, and tracing. -# -# VERSION -# 1.0 -# -# AUTHOR -# Jonas Mölsä -# - - -progname=`basename $0` -synopsis="stripcr [-s extension] [file...]" - - -: ${NDB_PROJ_HOME:?} # If undefined, exit with error message - -: ${STRIPCR_OPTIONS:=--} # If undefined, set to --, to keep getopts happy. - # You may have to experiment, to get quoting right. - -. $NDB_PROJ_HOME/lib/funcs.sh - - -# defaults for options related variables -# -extension= -options="$STRIPCR_OPTIONS" - -# used if error when parsing the options environment variable -# -env_opterr="options environment variable: <<$options>>" - - - -# We want to be able to set options in an environment variable, -# as well as on the command line. In order not to have to repeat -# the same getopts information twice, we loop two times over the -# getopts while loop. The first time, we process options from -# the options environment variable, the second time we process -# options from the command line. -# -# The things to change are the actual options and what they do. -# -# -for optstring in "$options" "" # 1. options variable 2. cmd line -do - while getopts s: i $optstring # optstring empty => no arg => cmd line - do - case $i in - - s) extension="$OPTARG";; - \?) syndie $env_opterr;; # print synopsis and exit - - esac - done - - [ -n "$optstring" ] && OPTIND=1 # Reset for round 2, cmd line options - - env_opterr= # Round 2 should not use the value -done -shift `expr $OPTIND - 1` - - -safe perl -i$extension -lpe 'tr/\r//d' $* diff --git a/storage/ndb/home/lib/funcs.sh b/storage/ndb/home/lib/funcs.sh deleted file mode 100644 index b7d8914035e..00000000000 --- a/storage/ndb/home/lib/funcs.sh +++ /dev/null @@ -1,294 +0,0 @@ -# NAME -# safe, safe_eval, die, rawdie, syndie, msg, errmsg, -# rawmsg, rawerrmsg, trace, errtrace, is_wordmatch -# - functions for safe execution and convenient printing and tracing -# -# abspath - make a path absolute -# -# SYNOPSIS -# . funcs.sh -# -# is_wordmatch requires perl. -# -# DESCRIPTION -# Funcs.sh is a collection of somewhat related functions. -# The main categories and their respective functions are: -# Controlled execution - safe, safe_eval -# Exiting with a message - die, rawdie, syndie -# Printing messages - msg, errmsg, rawmsg, rawerrmsg -# Tracing - trace, errtrace -# Pattern matching - is_wordmatch -# -# -# ENVIRONMENT -# These variables are not exported, but they are still visible -# to, and used by, these functions. -# -# progname basename of $0 -# verbose empty or non-emtpy, used for tracing -# synopsis string describing the syntax of $progname -# -# VERSION -# 2.0 -# -# AUTHOR -# Jonas Mvlsd -# Jonas Oreland - added abspath - - - - - -# Safely executes the given command and exits -# with the given commands exit code if != 0, -# else the return value ("the functions exit -# code") is 0. Eg: safely cd $install_dir -# -safely () -{ - "$@" - safely_code__=$? - [ $safely_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safely_code__."; - exit $safely_code__; } - - : # return "exit code" 0 from function -} - - - - -# Safely_eval executes "eval command" and exits -# with the given commands exit code if != 0, -# else the return value (the functions "exit -# code") is 0. -# -# Safely_eval is just like like safely, but safely_eval does -# "eval command" instead of just "command" -# -# Safely_eval even works with pipes etc., but you have to quote -# the special characters. Eg: safely_eval ls \| wc \> tst.txt 2\>\&1 -# -# -safely_eval () -{ - eval "$@" - safely_eval_code__=$? - [ $safely_eval_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safely_eval_code__."; - exit $safely_eval_code__; } - - : # return "exit code" 0 from function -} - - - - - - -# -# safe and safe_eval are deprecated, use safely and safely_eval instead -# - -# Safe executes the given command and exits -# with the given commands exit code if != 0, -# else the return value ("the functions exit -# code") is 0. -# -safe () -{ - "$@" - safe_code__=$? - [ $safe_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safe_code__."; - exit $safe_code__; } - - : # return "exit code" 0 from function -} - - - - -# Safe_eval executes "eval command" and exits -# with the given commands exit code if != 0, -# else the return value (the functions "exit -# code") is 0. -# -# Safe_eval is just like like safe, but safe_eval does -# "eval command" instead of just "command" -# -# Safe_eval even works with pipes etc., but you have to quote -# the special characters. Eg: safe_eval ls \| wc \> tst.txt 2\>\&1 -# -# -safe_eval () -{ - eval "$@" - safe_eval_code__=$? - [ $safe_eval_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safe_eval_code__."; - exit $safe_eval_code__; } - - : # return "exit code" 0 from function -} - - - - - - -# die prints the supplied message to stderr, -# prefixed with the program name, and exits -# with the exit code given by "-e num" or -# 1, if no -e option is present. -# -die () -{ - die_code__=1 - [ "X$1" = X-e ] && { die_code__=$2; shift 2; } - [ "X$1" = X-- ] && shift - errmsg "$@" - exit $die_code__ -} - - - -# rawdie prints the supplied message to stderr. -# It then exits with the exit code given with "-e num" -# or 1, if no -e option is present. -# -rawdie () -{ - rawdie_code__=1 - [ "X$1" = X-e ] && { rawdie_code__=$2; shift 2; } - [ "X$1" = X-- ] && shift - rawerrmsg "$@" - exit $rawdie_code__ -} - - - - -# Syndie prints the supplied message (if present) to stderr, -# prefixed with the program name, on the first line. -# On the second line, it prints $synopsis. -# It then exits with the exit code given with "-e num" -# or 1, if no -e option is present. -# -syndie () -{ - syndie_code__=1 - [ "X$1" = X-e ] && { syndie_code__=$2; shift 2; } - [ "X$1" = X-- ] && shift - [ -n "$*" ] && msg "$*" - rawdie -e $syndie_code__ "Synopsis: $synopsis" -} - - - - -# msg prints the supplied message to stdout, -# prefixed with the program name. -# -msg () -{ - echo "${progname:-}:" "$@" -} - - - -# msg prints the supplied message to stderr, -# prefixed with the program name. -# -errmsg () -{ - echo "${progname:-}:" "$@" >&2 -} - - - -rawmsg () { echo "$*"; } # print the supplied message to stdout -rawerrmsg () { echo "$*" >&2; } # print the supplied message to stderr - - - -# trace prints the supplied message to stdout if verbose is non-null -# -trace () -{ - [ -n "$verbose" ] && msg "$@" -} - - -# errtrace prints the supplied message to stderr if verbose is non-null -# -errtrace () -{ - [ -n "$verbose" ] && msg "$@" >&2 -} - - - -# SYNTAX -# is_wordmatch candidatelist wordlist -# -# DESCRIPTION -# is_wordmatch returns true if any of the words (candidates) -# in candidatelist is present in wordlist, otherwise it -# returns false. -# -# EXAMPLES -# is_wordmatch "tuareg nixdorf low content" "xx yy zz low fgj turn roff sd" -# returns true, since "low" in candidatelist is present in wordlist. -# -# is_wordmatch "tuareg nixdorf low content" "xx yy zz slow fgj turn roff sd" -# returns false, since none of the words in candidatelist occurs in wordlist. -# -# is_wordmatch "tuareg nixdorf low content" "xx yy zz low fgj tuareg roff" -# returns true, since "low" and "tuareg" in candidatelist occurs in wordlist. -# -is_wordmatch () -{ - is_wordmatch_pattern__=`echo $1 | - sed 's/^/\\\\b/; - s/[ ][ ]*/\\\\b|\\\\b/g; - s/$/\\\\b/;'` - shift - echo "$*" | - perl -lne "m/$is_wordmatch_pattern__/ || exit 1" -} - -# -# abspath -# -# Stolen from http://oase-shareware.org/shell/shelltips/script_programmer.html -# -abspath() -{ - __abspath_D=`dirname "$1"` - __abspath_B=`basename "$1"` - echo "`cd \"$__abspath_D\" 2>/dev/null && pwd || echo \"$__abspath_D\"`/$__abspath_B" -} - -# -# -# NdbExit -# -# -NdbExit() -{ - echo "NdbExit: $1" - exit $1 -} - -NdbGetExitCode() -{ - __res__=`echo $* | awk '{if($1=="NdbExit:") print $2;}'` - if [ -n $__res__ ] - then - echo $__res__ - else - echo 255 - fi -} - From e0f275ecb4bea77f85c615b6950e0f1fdf6abe69 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 14:21:17 -0400 Subject: [PATCH 090/101] After merge fixes. --- sql/ha_innodb.cc | 130 ----------------------------------------------- sql/ha_innodb.h | 3 -- sql/mysqld.cc | 17 ------- sql/set_var.cc | 13 ----- sql/sql_class.h | 5 -- 5 files changed, 168 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1b0f4c34acc..19d47aa15f2 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1769,25 +1769,6 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; -#ifdef HAVE_REPLICATION - if (thd->variables.sync_replication) { - /* 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. */ - - if (trx->repl_wait_binlog_name == NULL) { - - trx->repl_wait_binlog_name = - (char*)mem_alloc_noninline(FN_REFLEN + 100); - } - - ut_a(strlen(log_file_name) < FN_REFLEN + 100); - - strcpy(trx->repl_wait_binlog_name, log_file_name); - - trx->repl_wait_binlog_pos = (ib_longlong)end_offset; - } -#endif /* HAVE_REPLICATION */ trx->flush_log_later = TRUE; innobase_commit(thd, TRUE); @@ -1856,117 +1837,6 @@ innobase_commit_complete( trx_commit_complete_for_mysql(trx); } -#ifdef HAVE_REPLICATION - if (thd->variables.sync_replication - && trx->repl_wait_binlog_name - && innobase_repl_state != 0) { - - struct timespec abstime; - int cmp; - int ret; - - /* In synchronous replication, let us wait until the MySQL - replication has sent the relevant binlog segment to the - replication slave. */ - - pthread_mutex_lock(&innobase_repl_cond_mutex); -try_again: - if (innobase_repl_state == 0) { - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - return(0); - } - - cmp = strcmp(innobase_repl_file_name, - trx->repl_wait_binlog_name); - if (cmp > 0 - || (cmp == 0 && innobase_repl_pos - >= (my_off_t)trx->repl_wait_binlog_pos)) { - /* We have already sent the relevant binlog to the - slave: no need to wait here */ - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - -/* printf("Binlog now sent\n"); */ - - return(0); - } - - /* Let us update the info about the minimum binlog position - of waiting threads in the innobase_repl_... variables */ - - if (innobase_repl_wait_file_name_inited != 0) { - cmp = strcmp(trx->repl_wait_binlog_name, - innobase_repl_wait_file_name); - if (cmp < 0 - || (cmp == 0 - && (my_off_t)trx->repl_wait_binlog_pos - <= innobase_repl_wait_pos)) { - /* This thd has an even lower position, let - us update the minimum info */ - - strcpy(innobase_repl_wait_file_name, - trx->repl_wait_binlog_name); - - innobase_repl_wait_pos = - trx->repl_wait_binlog_pos; - } - } else { - strcpy(innobase_repl_wait_file_name, - trx->repl_wait_binlog_name); - - innobase_repl_wait_pos = trx->repl_wait_binlog_pos; - - innobase_repl_wait_file_name_inited = 1; - } - set_timespec(abstime, thd->variables.sync_replication_timeout); - - /* Let us suspend this thread to wait on the condition; - when replication has progressed far enough, we will release - these waiting threads. The following call - pthread_cond_timedwait also atomically unlocks - innobase_repl_cond_mutex. */ - - innobase_repl_n_wait_threads++; - -/* printf("Waiting for binlog to be sent\n"); */ - - ret = pthread_cond_timedwait(&innobase_repl_cond, - &innobase_repl_cond_mutex, &abstime); - innobase_repl_n_wait_threads--; - - if (ret != 0) { - ut_print_timestamp(stderr); - - sql_print_error("MySQL synchronous replication was " - "not able to send the binlog to the " - "slave within the timeout %lu. We " - "assume that the slave has become " - "inaccessible, and switch off " - "synchronous replication until the " - "communication to the slave works " - "again. MySQL synchronous replication " - "has sent binlog to the slave up to " - "file %s, position %lu. This " - "transaction needs it to be sent up " - "to file %s, position %lu.", - thd->variables.sync_replication_timeout, - innobase_repl_file_name, - (ulong) innobase_repl_pos, - trx->repl_wait_binlog_name, - (ulong) trx->repl_wait_binlog_pos); - - innobase_repl_state = 0; - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - return(0); - } - - goto try_again; - } -#endif // HAVE_REPLICATION return(0); } diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 6bbe3a562d7..4f0c9eb151b 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -316,9 +316,6 @@ int innobase_rollback_by_xid( XID *xid); /* in : X/Open XA Transaction Identification */ -int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, - my_off_t end_offset); - /*********************************************************************** Create a consistent view for a cursor based on current transaction which is created if the corresponding MySQL thread still lacks one. diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 73bd0d57eb3..357e9cb7a1d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6160,23 +6160,6 @@ The minimum value for this variable is 4096.", {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"sync-replication", OPT_SYNC_REPLICATION, - "Enable synchronous replication.", - (gptr*) &global_system_variables.sync_replication, - (gptr*) &global_system_variables.sync_replication, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, 1, 0, 1, 0}, - {"sync-replication-slave-id", OPT_SYNC_REPLICATION_SLAVE_ID, - "Synchronous replication is wished for this slave.", - (gptr*) &global_system_variables.sync_replication_slave_id, - (gptr*) &global_system_variables.sync_replication_slave_id, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, - {"sync-replication-timeout", OPT_SYNC_REPLICATION_TIMEOUT, - "Synchronous replication timeout.", - (gptr*) &global_system_variables.sync_replication_timeout, - (gptr*) &global_system_variables.sync_replication_timeout, - 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, -#endif /* HAVE_REPLICATION */ {"table_cache", OPT_TABLE_OPEN_CACHE, "Deprecated; use --table_open_cache instead.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, diff --git a/sql/set_var.cc b/sql/set_var.cc index 59e0c7b6ff7..16a0c752639 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -436,14 +436,6 @@ sys_var_thd_storage_engine sys_storage_engine("storage_engine", &SV::table_type); #ifdef HAVE_REPLICATION sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", &sync_binlog_period); -sys_var_thd_ulong sys_sync_replication("sync_replication", - &SV::sync_replication); -sys_var_thd_ulong sys_sync_replication_slave_id( - "sync_replication_slave_id", - &SV::sync_replication_slave_id); -sys_var_thd_ulong sys_sync_replication_timeout( - "sync_replication_timeout", - &SV::sync_replication_timeout); #endif sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm); sys_var_long_ptr sys_table_def_size("table_definition_cache", @@ -966,11 +958,6 @@ SHOW_VAR init_vars[]= { {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, #endif {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS}, -#ifdef HAVE_REPLICATION - {sys_sync_replication.name, (char*) &sys_sync_replication, SHOW_SYS}, - {sys_sync_replication_slave_id.name, (char*) &sys_sync_replication_slave_id,SHOW_SYS}, - {sys_sync_replication_timeout.name, (char*) &sys_sync_replication_timeout,SHOW_SYS}, -#endif #ifdef HAVE_TZNAME {"system_time_zone", system_time_zone, SHOW_CHAR}, #endif diff --git a/sql/sql_class.h b/sql/sql_class.h index 53712aaf69e..d5f36a1efed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -241,11 +241,6 @@ struct system_variables my_bool new_mode; my_bool query_cache_wlock_invalidate; my_bool engine_condition_pushdown; -#ifdef HAVE_REPLICATION - ulong sync_replication; - ulong sync_replication_slave_id; - ulong sync_replication_timeout; -#endif /* HAVE_REPLICATION */ my_bool innodb_table_locks; my_bool innodb_support_xa; my_bool ndb_force_send; From fd40f0dd1de97b1c5a303a4d336ac9771bc90068 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2006 04:38:19 -0400 Subject: [PATCH 091/101] WL 2826: Error handling of ALTER TABLE for partitioning Fixed merge issue sql/sql_partition.cc: Added some debug printouts sql/sql_table.cc: Fixed merge issue --- sql/sql_partition.cc | 4 ++++ sql/sql_table.cc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 741f1414e3b..0442ad724d2 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4532,6 +4532,7 @@ the generated partition syntax in a correct manner. /* Make sure change of engine happens to all partitions. */ + DBUG_PRINT("info", ("partition changed")); set_engine_all_partitions(thd->work_part_info, create_info->db_type); *partition_changed= TRUE; } @@ -4546,7 +4547,10 @@ the generated partition syntax in a correct manner. using the partition handler. */ if (thd->work_part_info != table->part_info) + { + DBUG_PRINT("info", ("partition changed")); *partition_changed= TRUE; + } if (create_info->db_type == &partition_hton) part_info->default_engine_type= table->part_info->default_engine_type; else diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1ed6e5c5cf2..b0e5a0b111a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5990,7 +5990,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); } /* Tell the handler that a new frm file is in place. */ - if (table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, + if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG, create_info)) { VOID(pthread_mutex_unlock(&LOCK_open)); From a0aea60d0e3ea05b8e4d9f58e6ad1d98203eb175 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2006 04:38:22 -0400 Subject: [PATCH 092/101] Post merge fix. mysql-test/t/rpl_view-slave.opt: Post-merge fix --- mysql-test/t/rpl_view-slave.opt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mysql-test/t/rpl_view-slave.opt b/mysql-test/t/rpl_view-slave.opt index 55b3aeb3bda..79b3bf6174b 100644 --- a/mysql-test/t/rpl_view-slave.opt +++ b/mysql-test/t/rpl_view-slave.opt @@ -1,5 +1 @@ -# -# BUG18715 create view with replicate*ignore-table -# The option is needed to force slave executes tables_ok -# which must return OK in conditions of this tests (no table foo is used) --replicate-ignore-table=test.foo From c6a0bfbae3dd72f16a47ede1f706aabab1eb8c10 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2006 13:29:05 +0200 Subject: [PATCH 093/101] Fix windows compile problem --- sql/sql_table.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b0e5a0b111a..ca13fb27f96 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -328,7 +328,7 @@ static bool read_ddl_log_file_entry(uint entry_no) uint io_size= global_ddl_log.io_size; DBUG_ENTER("read_ddl_log_file_entry"); - if (my_pread(file_id, file_entry_buf, io_size, io_size * entry_no, + if (my_pread(file_id, (byte*)file_entry_buf, io_size, io_size * entry_no, MYF(MY_WME)) != io_size) error= TRUE; DBUG_RETURN(error); @@ -352,7 +352,7 @@ static bool write_ddl_log_file_entry(uint entry_no) char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; DBUG_ENTER("write_ddl_log_file_entry"); - if (my_pwrite(file_id, file_entry_buf, + if (my_pwrite(file_id, (byte*)file_entry_buf, IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); From 04f93ca02ab3715d6b16d36dcfda7b6d8c8d791c Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 23 Apr 2006 04:09:56 +0400 Subject: [PATCH 094/101] A post-merge fix. --- sql/mysqld.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ed10286f91e..923eb530099 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8071,8 +8071,9 @@ void refresh_status(THD *thd) add_to_status(&global_status_var, &thd->status_var); bzero((char*) &thd->status_var, sizeof(thd->status_var)); - for (struct show_var_st *ptr=status_vars; ptr->name; ptr++) + for (SHOW_VAR *ptr= status_vars; ptr->name; ptr++) { + /* Note that SHOW_LONG_NOFLUSH variables are not reset */ if (ptr->type == SHOW_LONG) *(ulong*) ptr->value= 0; } From ca9b46f71a55e53f85ae2f8e28f0d88126a44307 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 23 Apr 2006 12:48:31 +0400 Subject: [PATCH 095/101] Applied innodb-5.1-ss475 snapshot. * Fix BUG#15650: "DELETE with LEFT JOIN crashes server with innodb_locks_unsafe_for binlog" * Fix BUG#17134: "Partitions: uncommitted changes are visible" * Fix BUG#17992: "Partitions: InnoDB, somehow rotten table after UPDATE" row0ins.c: MySQL's partitioned table code does not set preduilt->sql_stat_start right if it does an insert in the same statement after doing a search first in the same partition table. We now write trx id always to the buffer, not just when flag sql_stat_start is on. This will waste CPU time very sightly. * Fix BUG#18077: "InnoDB uses full explicit table locks in stored FUNCTION" * Fix BUG#18238: "When locks exhaust the buffer pool, InnoDB does not roll back the trx" * Fix BUG#18252" "Disk space leak in updates of InnoDB BLOB rows in 5.0 and 5.1" * Fix BUG#18283: "When InnoDB returns error 'lock table full', MySQL can write to binlog too much" * Fix BUG#18350: "Use consistent read in CREATE ... SELECT ... if innodb_locks_unsafe_for_binlog" * Fix BUG#18384: "InnoDB memory leak on duplicate key errors in 5.0 if row has many columns" * Fix BUG#18934: "InnoDB crashes when table uses column names like DB_ROW_ID" Refuse tables that use reserved column names. * InnoDB's SQL parser: - Add support for UNSIGNED types, EXIT keyword, quoted identifiers, user-function callbacks for processing results of FETCH statements, bound literals, DATA_VARCHAR for bound literals. - Allow bound literals of type non-INTEGER to be of length 0. - Add make_flex.sh and update lexer/parser generation documentation. - Add comment clarifying the difference between 'alias' and 'indirection' fields in sym_node_t. - Remove never reached duplicate code in pars_set_dfield_type(). - Rewrite pars_info datatypes and APIs, add a few helper functions. - Since the functions definitions in pars_info_t are accessed after pars_sql() returns in the query graph execution stage, we can't free pars_info_t in pars_sql(). Instead, make pars_sql() transfer ownership of pars_info_t to the created query graph, and make que_graph_free() free it if needed. - Allow access to system columns like DB_ROW_ID. * Use bound literals in row_truncate_table_for_mysql, row_drop_table_for_mysql, row_discard_tablespace_for_mysql, and row_rename_table_for_mysql. * Setting an isolation level of the transaction to read committed weakens the locks for this session similarly like the option innodb_locks_unsafe_for binlog. This patch removes alnost all gap locking (used in next-key locking) and makes MySQL to release the row locks on the rows which does not belong to result set. Additionally, nonlocking selects on INSERT INTO SELECT, UPDATE ... (SELECT ...), and CREATE ... SELECT ... use a nonlocking consistent read. If a binlog is used, then binlog format should be set to row based binloging to make the execution of the complex SQL statements. * Disable the statistic variables btr_search_n_hash_fail and n_hash_succ, n_hash_fail, n_patt_succ, and n_searches of btr_search_t in builds without #ifdef UNIV_SEARCH_PERF_STAT. * Make innodb.test faster. Group all consistent read test cases to a one test case and wait their lock timeout after all have been send to the server. Decrease amount of rows inserted in a certain test - this has no effect on the effectiveness of the test and reduces the running time by ~10 sec. Remove temporary work-arounds from innodb.result now that ALTER TABLE DROP FOREIGN KEY works once again. * Make innodb_unsafe_binlog.test faster. Grout all consistent read test cases to a one test case amd wait their lock timeout after all have been sent to the server. Remove unnecessary option --loose_innodb_lock_wait_timeout. * Print dictionary memory size in SHOW INNODB STATUS. * Fix memory leaks in row_create_table_for_mysql() in rare corner cases. * Remove code related to clustered tables. They were never implemented, and the implementation would be challenging with ROW_FORMAT=COMPACT. Remove the table types DICT_TABLE_CLUSTER_MEMBER and DICT_TABLE_CLUSTER and all related tests and functions. dict_table_t: Remove mix_id, mix_len, mix_id_len, mix_id_buf, and cluster_name. plan_t: Remove mixed_index. dict_create_sys_tables_tuple(): Set MIX_ID=0, MIX_LEN=0, CLUSTER_NAME=NULL when inserting into SYS_TABLES. dict_tree_check_search_tuple(): Enclose in #ifdef UNIV_DEBUG. * Move calling of thr_local_free() from trx_free_for_mysql() to innobase_close_connection(). mysql-test/r/innodb.result: Applied innodb-5.1-ss475 snapshot. mysql-test/r/innodb_unsafe_binlog.result: Applied innodb-5.1-ss475 snapshot. mysql-test/t/innodb-master.opt: Applied innodb-5.1-ss475 snapshot. mysql-test/t/innodb.test: Applied innodb-5.1-ss475 snapshot. mysql-test/t/innodb_unsafe_binlog-master.opt: Applied innodb-5.1-ss475 snapshot. mysql-test/t/innodb_unsafe_binlog.test: Applied innodb-5.1-ss475 snapshot. sql/ha_innodb.cc: Applied innodb-5.1-ss475 snapshot. Do not use inlined functions in ha_innodb.cc. Remove assertion ut_error which crashes the mysqld server if it prints a warning about the adaptive latch. storage/innobase/Makefile.am: Applied innodb-5.1-ss475 snapshot. storage/innobase/btr/btr0btr.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/btr/btr0cur.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/btr/btr0pcur.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/btr/btr0sea.c: Applied innodb-5.1-ss475 snapshot. Fix compilation problem with non-C99 compilers. storage/innobase/buf/buf0lru.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/cmakelists.txt: Applied innodb-5.1-ss475 snapshot. storage/innobase/configure.in: Applied innodb-5.1-ss475 snapshot. Add disabled-by-default logic to switch GCC to a strict C89-mode. Add -Werror-implicit-function_declaration to CFLAGS when using gcc. storage/innobase/data/data0type.c: Applied innodb-5.1-ss475 snapshot. dtype_print(): Recognize DATA_FIXBINARY and DATA_BLOB types. Print known flags from prtype. Use a switch statement instead of else-if chain. storage/innobase/dict/dict0crea.c: Applied innodb-5.1-ss475 snapshot. Use bound literals in all SQL statements instead of elaborately constructing correctly allocated and quoted strings to pass the data in ASCII form. storage/innobase/dict/dict0dict.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/dict/dict0load.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/dict/dict0mem.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/eval/eval0proc.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/ibuf/ibuf0ibuf.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/btr0cur.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/btr0cur.ic: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/btr0sea.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/buf0lru.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/dict0dict.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/dict0dict.ic: Applied innodb-5.1-ss475 snapshot. Remove too strict assertions from some dict_table_t accessor functions. storage/innobase/include/dict0mem.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/eval0proc.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/hash0hash.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/lock0lock.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/mem0mem.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/page0page.ic: Applied innodb-5.1-ss475 snapshot. Remove UNIV_RELEASE_NOT_YET_STABLE and related checks. storage/innobase/include/pars0grm.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/pars0pars.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/pars0sym.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/pars0types.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/que0que.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/row0mysql.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/row0sel.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/row0upd.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/trx0trx.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/univ.i: Applied innodb-5.1-ss475 snapshot. Remove UNIV_RELEASE_NOT_YET_STABLE and related checks. When using GCC, use __inline__ instead of inline. storage/innobase/include/ut0mem.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/lock/lock0lock.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/log/log0recv.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/mem/mem0dbg.c: Applied innodb-5.1-ss475 snapshot. Add (void*) cast when using the %p printf format specifier. storage/innobase/mem/mem0mem.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/os/os0sync.c: Applied innodb-5.1-ss475 snapshot. Add (void*) cast when using the %p printf format specifier. storage/innobase/pars/lexyy.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/make_bison.sh: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0grm.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0grm.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0grm.y: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0lex.l: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0opt.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0pars.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/pars0sym.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/que/que0que.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/row/row0ins.c: Applied innodb-5.1-ss475 snapshot. Remove a memory leak when trying to insert a duplicate record to a clustered inedx comprising more than about 90 columns (Bug#18384). row_ins_duplicate_error_in_clust(): Call mem_heap_free(heap) at func_exit if needed. storage/innobase/row/row0mysql.c: Applied innodb-5.1-ss475 snapshot. row_mysql_is_system_table(): Use strncmp, not memcmp, since we don't know how long the input string is. storage/innobase/row/row0sel.c: Applied innodb-5.1-ss475 snapshot. Remove UNIV_RELEASE_NOT_YET_STABLE and related checks. row_sel_field_store_in_mysql_format(): Turn the assertions on mbminlen, mbmaxlen, and templ->type into debug assertions. fetch_step(): Print a more usefull error message when the cursor is closed. storage/innobase/row/row0upd.c: Applied innodb-5.1-ss475 snapshot. row_upd_index_replace_new_col_vals_index_pos(): Add a parameter order_only for limiting the replacement to the ordering fields of the index. storage/innobase/srv/srv0srv.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/sync/sync0arr.c: Applied innodb-5.1-ss475 snapshot. Add (void*) cast when using the %p printf format specifier. storage/innobase/sync/sync0rw.c: Applied innodb-5.1-ss475 snapshot. Add (void*) cast when using the %p printf format specifier. storage/innobase/sync/sync0sync.c: Applied innodb-5.1-ss475 snapshot. Add (void*) cast when using the %p printf format specifier. storage/innobase/trx/trx0trx.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/ut/Makefile.am: Applied innodb-5.1-ss475 snapshot. storage/innobase/ut/ut0mem.c: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/ut0vec.h: Applied innodb-5.1-ss475 snapshot. storage/innobase/include/ut0vec.ic: Applied innodb-5.1-ss475 snapshot. storage/innobase/pars/make_flex.sh: Applied innodb-5.1-ss475 snapshot. storage/innobase/ut/ut0vec.c: Applied innodb-5.1-ss475 snapshot. --- mysql-test/r/innodb.result | 158 +- mysql-test/r/innodb_unsafe_binlog.result | 87 +- mysql-test/t/innodb-master.opt | 2 +- mysql-test/t/innodb.test | 278 ++- mysql-test/t/innodb_unsafe_binlog-master.opt | 2 +- mysql-test/t/innodb_unsafe_binlog.test | 199 +- sql/ha_innodb.cc | 121 +- storage/innobase/Makefile.am | 3 +- storage/innobase/btr/btr0btr.c | 29 +- storage/innobase/btr/btr0cur.c | 23 +- storage/innobase/btr/btr0pcur.c | 5 +- storage/innobase/btr/btr0sea.c | 30 +- storage/innobase/buf/buf0lru.c | 20 +- storage/innobase/cmakelists.txt | 2 +- storage/innobase/configure.in | 19 + storage/innobase/data/data0type.c | 49 +- storage/innobase/dict/dict0crea.c | 372 ++-- storage/innobase/dict/dict0dict.c | 274 +-- storage/innobase/dict/dict0load.c | 38 +- storage/innobase/dict/dict0mem.c | 50 +- storage/innobase/eval/eval0proc.c | 32 + storage/innobase/ibuf/ibuf0ibuf.c | 6 +- storage/innobase/include/btr0cur.h | 5 +- storage/innobase/include/btr0cur.ic | 6 +- storage/innobase/include/btr0sea.h | 4 +- storage/innobase/include/buf0lru.h | 4 +- storage/innobase/include/dict0dict.h | 55 +- storage/innobase/include/dict0dict.ic | 2 - storage/innobase/include/dict0mem.h | 55 +- storage/innobase/include/eval0proc.h | 8 + storage/innobase/include/hash0hash.h | 26 + storage/innobase/include/lock0lock.h | 9 + storage/innobase/include/mem0mem.h | 11 + storage/innobase/include/page0page.ic | 13 - storage/innobase/include/pars0grm.h | 342 ++-- storage/innobase/include/pars0pars.h | 173 +- storage/innobase/include/pars0sym.h | 25 + storage/innobase/include/pars0types.h | 4 + storage/innobase/include/que0que.h | 20 +- storage/innobase/include/row0mysql.h | 3 +- storage/innobase/include/row0sel.h | 36 +- storage/innobase/include/row0upd.h | 4 + storage/innobase/include/trx0trx.h | 4 +- storage/innobase/include/univ.i | 19 +- storage/innobase/include/ut0mem.h | 24 + storage/innobase/include/ut0vec.h | 73 + storage/innobase/include/ut0vec.ic | 26 + storage/innobase/lock/lock0lock.c | 60 +- storage/innobase/log/log0recv.c | 6 +- storage/innobase/mem/mem0dbg.c | 2 +- storage/innobase/mem/mem0mem.c | 25 + storage/innobase/os/os0sync.c | 2 +- storage/innobase/pars/lexyy.c | 1173 ++++++----- storage/innobase/pars/make_bison.sh | 3 +- storage/innobase/pars/make_flex.sh | 20 + storage/innobase/pars/pars0grm.c | 1934 +++++++++--------- storage/innobase/pars/pars0grm.h | 342 ++-- storage/innobase/pars/pars0grm.y | 61 +- storage/innobase/pars/pars0lex.l | 87 +- storage/innobase/pars/pars0opt.c | 50 +- storage/innobase/pars/pars0pars.c | 338 ++- storage/innobase/pars/pars0sym.c | 71 +- storage/innobase/que/que0que.c | 126 +- storage/innobase/row/row0ins.c | 58 +- storage/innobase/row/row0mysql.c | 703 +++---- storage/innobase/row/row0sel.c | 213 +- storage/innobase/row/row0upd.c | 18 +- storage/innobase/srv/srv0srv.c | 2 + storage/innobase/sync/sync0arr.c | 10 +- storage/innobase/sync/sync0rw.c | 17 +- storage/innobase/sync/sync0sync.c | 12 +- storage/innobase/trx/trx0trx.c | 5 +- storage/innobase/ut/Makefile.am | 2 +- storage/innobase/ut/ut0mem.c | 93 + storage/innobase/ut/ut0vec.c | 54 + 75 files changed, 5052 insertions(+), 3185 deletions(-) create mode 100644 storage/innobase/include/ut0vec.h create mode 100644 storage/innobase/include/ut0vec.ic create mode 100755 storage/innobase/pars/make_flex.sh create mode 100644 storage/innobase/ut/ut0vec.c diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 04e280fad3e..e6031fe92c0 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1295,22 +1295,14 @@ insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; select count(*) from t1; count(*) -29267 -explain select * from t1 where c between 1 and 10000; +623 +explain select * from t1 where c between 1 and 2500; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range c c 5 NULL # Using where update t1 set c=a; -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL c NULL NULL NULL # Using where drop table t1,t2; @@ -1775,21 +1767,6 @@ select count(*) from t1 where x = 18446744073709551601; count(*) 1 drop table t1; -show status like "Innodb_buffer_pool_pages_total"; -Variable_name Value -Innodb_buffer_pool_pages_total 512 -show status like "Innodb_page_size"; -Variable_name Value -Innodb_page_size 16384 -show status like "Innodb_rows_deleted"; -Variable_name Value -Innodb_rows_deleted 2070 -show status like "Innodb_rows_inserted"; -Variable_name Value -Innodb_rows_inserted 31727 -show status like "Innodb_rows_updated"; -Variable_name Value -Innodb_rows_updated 29530 show status like "Innodb_row_lock_waits"; Variable_name Value Innodb_row_lock_waits 0 @@ -3291,3 +3268,132 @@ where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; a a 2005-10-01 2005-10-01 drop table t1, t2; +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +id f_id f +drop table t1,t2; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t1 set b = 5 where b = 1; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +select * from t1 where a = 7 and b = 3 for update; +a b +7 3 +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +a b +1 1 +2 2 +3 1 +4 2 +5 1 +6 2 +update t1 set b = 5 where b = 1; +set autocommit = 0; +select * from t1 where a = 2 and b = 2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +d e +3 1 +8 6 +12 1 +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +commit; +drop table t1, t2, t3; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +a b +3 1 +8 6 +12 1 +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +insert into t1 select * from t2; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +update t3 set b = (select b from t2 where a = d); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t5 (select * from t2 lock in share mode); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t6 set e = (select b from t2 where a = d lock in share mode); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t8 (select * from t2 for update); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t9 set e = (select b from t2 where a = d for update); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +drop table t1, t2, t3, t5, t6, t8, t9; +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.t1' (errno: -1) diff --git a/mysql-test/r/innodb_unsafe_binlog.result b/mysql-test/r/innodb_unsafe_binlog.result index e741fbb75a4..38f0c2a12fa 100644 --- a/mysql-test/r/innodb_unsafe_binlog.result +++ b/mysql-test/r/innodb_unsafe_binlog.result @@ -15,7 +15,7 @@ where mm.id is null lock in share mode; id f_id f drop table t1,t2; create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); commit; set autocommit = 0; select * from t1 lock in share mode; @@ -26,6 +26,7 @@ a b 4 2 5 1 6 2 +7 3 update t1 set b = 5 where b = 1; set autocommit = 0; select * from t1 where a = 2 and b = 2 for update; @@ -33,3 +34,87 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction commit; commit; drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +update t1 set b = 5 where b = 1; +set autocommit = 0; +select * from t1 where a = 7 and b = 3 for update; +a b +7 3 +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +d e +3 1 +8 6 +12 1 +set autocommit = 0; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +commit; +drop table t1, t2, t3; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +a b +3 1 +8 6 +12 1 +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +insert into t1 select * from t2; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +update t3 set b = (select b from t2 where a = d); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +set autocommit = 0; +insert into t5 (select * from t2 lock in share mode); +set autocommit = 0; +update t6 set e = (select b from t2 where a = d lock in share mode); +set autocommit = 0; +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +set autocommit = 0; +insert into t8 (select * from t2 for update); +set autocommit = 0; +update t9 set e = (select b from t2 where a = d for update); +set autocommit = 0; +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +drop table t1, t2, t3, t5, t6, t8, t9; diff --git a/mysql-test/t/innodb-master.opt b/mysql-test/t/innodb-master.opt index 4cb927540bf..4901efb416c 100644 --- a/mysql-test/t/innodb-master.opt +++ b/mysql-test/t/innodb-master.opt @@ -1 +1 @@ ---binlog_cache_size=32768 +--binlog_cache_size=32768 --innodb_lock_wait_timeout=1 diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 18b47c39a10..bcd80c18326 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -891,20 +891,12 @@ insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; select count(*) from t1; --replace_column 9 # -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; update t1 set c=a; --replace_column 9 # -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; drop table t1,t2; # @@ -1290,15 +1282,6 @@ select * from t1 where x > -16; select count(*) from t1 where x = 18446744073709551601; drop table t1; - -# Test for testable InnoDB status variables. This test -# uses previous ones(pages_created, rows_deleted, ...). -show status like "Innodb_buffer_pool_pages_total"; -show status like "Innodb_page_size"; -show status like "Innodb_rows_deleted"; -show status like "Innodb_rows_inserted"; -show status like "Innodb_rows_updated"; - # Test for row locks InnoDB status variables. show status like "Innodb_row_lock_waits"; show status like "Innodb_row_lock_current_waits"; @@ -2182,15 +2165,268 @@ show create table t1; # drop table t1, t2; - # # Bug #14360: problem with intervals # create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; +create table t2(a date, key(a)) engine=innodb; insert into t1 values('2005-10-01'); insert into t2 values('2005-10-01'); select * from t1, t2 where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; drop table t1, t2; + +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +drop table t1,t2; + +# +# Test case where X-locks on unused rows should be released in a +# update (because READ COMMITTED isolation level) +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +# +# X-lock to record (7,3) should be released in a update +# +select * from t1 where a = 7 and b = 3 for update; +connection a; +commit; +connection b; +commit; +drop table t1; +connection default; +disconnect a; +disconnect b; + +# +# Test case where no locks should be released (because we are not +# using READ COMMITTED isolation level) +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +# +# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update +# +--error 1205 +select * from t1 where a = 2 and b = 2 for update; +# +# X-lock to record (1,1),(3,1),(5,1) should not be released in a update +# +--error 1205 +connection a; +commit; +connection b; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1; + +# +# Consistent read should be used in following selects +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +connection a; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1, t2, t3; + +# +# Consistent read should not be used if +# +# (a) isolation level is serializable OR +# (b) select ... lock in share mode OR +# (c) select ... for update +# +# in following queries: +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connect (c,localhost,root,,); +connect (d,localhost,root,,); +connect (e,localhost,root,,); +connect (f,localhost,root,,); +connect (g,localhost,root,,); +connect (h,localhost,root,,); +connect (i,localhost,root,,); +connect (j,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +insert into t1 select * from t2; +connection c; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +update t3 set b = (select b from t2 where a = d); +connection d; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +connection e; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +insert into t5 (select * from t2 lock in share mode); +connection f; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +update t6 set e = (select b from t2 where a = d lock in share mode); +connection g; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +connection h; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +insert into t8 (select * from t2 for update); +connection i; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +update t9 set e = (select b from t2 where a = d for update); +connection j; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; + +connection b; +--error 1205 +reap; + +connection c; +--error 1205 +reap; + +connection d; +--error 1205 +reap; + +connection e; +--error 1205 +reap; + +connection f; +--error 1205 +reap; + +connection g; +--error 1205 +reap; + +connection h; +--error 1205 +reap; + +connection i; +--error 1205 +reap; + +connection j; +--error 1205 +reap; + +connection a; +commit; + +connection default; +disconnect a; +disconnect b; +disconnect c; +disconnect d; +disconnect e; +disconnect f; +disconnect g; +disconnect h; +disconnect i; +disconnect j; +drop table t1, t2, t3, t5, t6, t8, t9; + +# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID" +--error 1005 +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; diff --git a/mysql-test/t/innodb_unsafe_binlog-master.opt b/mysql-test/t/innodb_unsafe_binlog-master.opt index 503c8457b2c..9581c225d6d 100644 --- a/mysql-test/t/innodb_unsafe_binlog-master.opt +++ b/mysql-test/t/innodb_unsafe_binlog-master.opt @@ -1 +1 @@ ---innodb_locks_unsafe_for_binlog=true +--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=1 diff --git a/mysql-test/t/innodb_unsafe_binlog.test b/mysql-test/t/innodb_unsafe_binlog.test index e4cb683e59d..af1091e4421 100644 --- a/mysql-test/t/innodb_unsafe_binlog.test +++ b/mysql-test/t/innodb_unsafe_binlog.test @@ -1,7 +1,9 @@ -- source include/have_innodb.inc # -# Note that these tests uses a innodb_locks_unsafe_for_binlog option. -# +# Note that these tests uses options +# innodb_locks_unsafe_for_binlog = true +# innodb_lock_timeout = 5 + # # Test cases for a bug #15650 # @@ -33,7 +35,7 @@ connect (a,localhost,root,,); connect (b,localhost,root,,); connection a; create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); commit; set autocommit = 0; select * from t1 lock in share mode; @@ -50,6 +52,197 @@ commit; connection b; commit; drop table t1; +connection default; disconnect a; disconnect b; +# +# unlock row test +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +# +# X-lock to record (7,3) should be released in a update +# +select * from t1 where a = 7 and b = 3 for update; +commit; +connection a; +commit; +drop table t1; +connection default; +disconnect a; +disconnect b; + + +# +# Consistent read should be used in following selects +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +connection a; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1, t2, t3; + +# +# Consistent read should not be used if +# +# (a) isolation level is serializable OR +# (b) select ... lock in share mode OR +# (c) select ... for update +# +# in following queries: +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connect (c,localhost,root,,); +connect (d,localhost,root,,); +connect (e,localhost,root,,); +connect (f,localhost,root,,); +connect (g,localhost,root,,); +connect (h,localhost,root,,); +connect (i,localhost,root,,); +connect (j,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +insert into t1 select * from t2; +connection c; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +update t3 set b = (select b from t2 where a = d); +connection d; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +connection e; +set autocommit = 0; +--send +insert into t5 (select * from t2 lock in share mode); +connection f; +set autocommit = 0; +--send +update t6 set e = (select b from t2 where a = d lock in share mode); +connection g; +set autocommit = 0; +--send +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +connection h; +set autocommit = 0; +--send +insert into t8 (select * from t2 for update); +connection i; +set autocommit = 0; +--send +update t9 set e = (select b from t2 where a = d for update); +connection j; +set autocommit = 0; +--send +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; + +connection b; +--error 1205 +reap; + +connection c; +--error 1205 +reap; + +connection d; +--error 1205 +reap; + +connection e; +--error 1205 +reap; + +connection f; +--error 1205 +reap; + +connection g; +--error 1205 +reap; + +connection h; +--error 1205 +reap; + +connection i; +--error 1205 +reap; + +connection j; +--error 1205 +reap; + +connection a; +commit; + +connection default; +disconnect a; +disconnect b; +disconnect c; +disconnect d; +disconnect e; +disconnect f; +disconnect g; +disconnect h; +disconnect i; +disconnect j; +drop table t1, t2, t3, t5, t6, t8, t9; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1b0f4c34acc..a24a083ec8a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -132,6 +132,7 @@ extern "C" { #include "../storage/innobase/include/sync0sync.h" #include "../storage/innobase/include/fil0fil.h" #include "../storage/innobase/include/trx0xa.h" +#include "../storage/innobase/include/thr0loc.h" } #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */ @@ -237,7 +238,7 @@ handlerton innobase_hton = { NULL, /* Fill FILES table */ HTON_NO_FLAGS, NULL, /* binlog_func */ - NULL, /* binlog_log_query */ + NULL, /* binlog_log_query */ innobase_release_temporary_latches }; @@ -535,18 +536,18 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CORRUPTION) { - return(HA_ERR_CRASHED); - } else if (error == (int) DB_NO_SAVEPOINT) { + return(HA_ERR_CRASHED); + } else if (error == (int) DB_NO_SAVEPOINT) { - return(HA_ERR_NO_SAVEPOINT); - } else if (error == (int) DB_LOCK_TABLE_FULL) { - /* Since we rolled back the whole transaction, we must - tell it also to MySQL so that MySQL knows to empty the - cached binlog for this transaction */ + return(HA_ERR_NO_SAVEPOINT); + } else if (error == (int) DB_LOCK_TABLE_FULL) { + /* Since we rolled back the whole transaction, we must + tell it also to MySQL so that MySQL knows to empty the + cached binlog for this transaction */ - if (thd) { - ha_rollback(thd); - } + if (thd) { + ha_rollback(thd); + } return(HA_ERR_LOCK_TABLE_FULL); } else { @@ -1014,7 +1015,6 @@ innobase_query_caching_of_table_permitted( mutex_enter_noninline(&kernel_mutex); trx_print(stderr, trx, 1024); mutex_exit_noninline(&kernel_mutex); - ut_error; } innobase_release_stat_resources(trx); @@ -1970,7 +1970,6 @@ try_again: return(0); } - /********************************************************************* Rolls back a transaction or the latest SQL statement. */ @@ -2196,6 +2195,7 @@ innobase_close_connection( innobase_rollback_trx(trx); + thr_local_free(trx->mysql_thread_id); trx_free_for_mysql(trx); return(0); @@ -2216,7 +2216,7 @@ ha_innobase::get_row_type() const row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; if (prebuilt && prebuilt->table) { - if (innodb_dict_table_is_comp(prebuilt->table)) { + if (dict_table_is_comp_noninline(prebuilt->table)) { return(ROW_TYPE_COMPACT); } else { return(ROW_TYPE_REDUNDANT); @@ -3609,7 +3609,8 @@ calc_row_difference( TRUE, new_mysql_row_col, col_pack_len, - innodb_dict_table_is_comp(prebuilt->table)); + dict_table_is_comp_noninline( + prebuilt->table)); ufield->new_val.data = dfield.data; ufield->new_val.len = dfield.len; } else { @@ -3769,9 +3770,17 @@ ha_innobase::unlock_row(void) ut_error; } + /* Consistent read does not take any locks, thus there is + nothing to unlock. */ + + if (prebuilt->select_lock_type == LOCK_NONE) { + DBUG_VOID_RETURN; + } + switch (prebuilt->row_read_type) { case ROW_READ_WITH_LOCKS: - if (!srv_locks_unsafe_for_binlog) { + if (!srv_locks_unsafe_for_binlog + || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED) { break; } /* fall through */ @@ -3803,7 +3812,13 @@ ha_innobase::try_semi_consistent_read(bool yes) { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - if (yes && srv_locks_unsafe_for_binlog) { + /* Row read type is set to semi consistent read if this was + requested by the MySQL and either innodb_locks_unsafe_for_binlog + option is used or this session is using READ COMMITTED isolation + level. */ + + if (yes && (srv_locks_unsafe_for_binlog + || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) { prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; } else { prebuilt->row_read_type = ROW_READ_WITH_LOCKS; @@ -6286,12 +6301,6 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use++; prebuilt->mysql_has_locked = TRUE; - if (trx->n_mysql_tables_in_use == 1) { - trx->isolation_level = innobase_map_isolation_level( - (enum_tx_isolation) - thd->variables.tx_isolation); - } - if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE && (thd->options @@ -6765,11 +6774,22 @@ ha_innobase::store_lock( TL_IGNORE */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + trx_t* trx = prebuilt->trx; /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE! Be careful to ignore TL_IGNORE if we are going to do something with only 'real' locks! */ + /* If no MySQL tables is use we need to set isolation level + of the transaction. */ + + if (lock_type != TL_IGNORE + && trx->n_mysql_tables_in_use == 0) { + trx->isolation_level = innobase_map_isolation_level( + (enum_tx_isolation) + thd->variables.tx_isolation); + } + if ((lock_type == TL_READ && thd->in_lock_tables) || (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || lock_type == TL_READ_WITH_SHARED_LOCKS || @@ -6794,18 +6814,26 @@ ha_innobase::store_lock( unexpected if an obsolete consistent read view would be used. */ - if (srv_locks_unsafe_for_binlog && - prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE && - (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && - (thd->lex->sql_command == SQLCOM_INSERT_SELECT || - thd->lex->sql_command == SQLCOM_UPDATE)) { + ulint isolation_level; - /* In case we have innobase_locks_unsafe_for_binlog - option set and isolation level of the transaction + isolation_level = trx->isolation_level; + + if ((srv_locks_unsafe_for_binlog + || isolation_level == TRX_ISO_READ_COMMITTED) + && isolation_level != TRX_ISO_SERIALIZABLE + && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) + && (thd->lex->sql_command == SQLCOM_INSERT_SELECT + || thd->lex->sql_command == SQLCOM_UPDATE + || thd->lex->sql_command == SQLCOM_CREATE_TABLE)) { + + /* If we either have innobase_locks_unsafe_for_binlog + option set or this session is using READ COMMITTED + isolation level and isolation level of the transaction is not set to serializable and MySQL is doing - INSERT INTO...SELECT or UPDATE ... = (SELECT ...) - without FOR UPDATE or IN SHARE MODE in select, then - we use consistent read for select. */ + INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or + CREATE ... SELECT... without FOR UPDATE or + IN SHARE MODE in select, then we use consistent + read for select. */ prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = LOCK_NONE; @@ -6854,25 +6882,26 @@ ha_innobase::store_lock( } /* If we are not doing a LOCK TABLE, DISCARD/IMPORT - TABLESPACE or TRUNCATE TABLE then allow multiple + TABLESPACE or TRUNCATE TABLE then allow multiple writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ < TL_WRITE_CONCURRENT_INSERT. - We especially allow multiple writers if MySQL is at the - start of a stored procedure call (SQLCOM_CALL) - (MySQL does have thd->in_lock_tables TRUE there). */ + We especially allow multiple writers if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) or a + stored function call (MySQL does have thd->in_lock_tables + TRUE there). */ - if ((lock_type >= TL_WRITE_CONCURRENT_INSERT - && lock_type <= TL_WRITE) - && !(thd->in_lock_tables - && thd->lex->sql_command == SQLCOM_LOCK_TABLES) - && !thd->tablespace_op - && thd->lex->sql_command != SQLCOM_TRUNCATE - && thd->lex->sql_command != SQLCOM_OPTIMIZE - && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT + && lock_type <= TL_WRITE) + && !(thd->in_lock_tables + && thd->lex->sql_command == SQLCOM_LOCK_TABLES) + && !thd->tablespace_op + && thd->lex->sql_command != SQLCOM_TRUNCATE + && thd->lex->sql_command != SQLCOM_OPTIMIZE + && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { lock_type = TL_WRITE_ALLOW_WRITE; - } + } /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... MySQL would use the lock TL_READ_NO_INSERT on t2, and that diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am index 22796b45882..dfc3a511d52 100644 --- a/storage/innobase/Makefile.am +++ b/storage/innobase/Makefile.am @@ -76,8 +76,7 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \ include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \ include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \ - include/ut0sort.h include/ut0ut.h include/ut0ut.ic \ - cmakelists.txt + include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 4ece0e36b19..5e338f97982 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -144,7 +144,7 @@ btr_root_get( root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr); ut_a((ibool)!!page_is_comp(root) == - dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table)); + dict_table_is_comp(tree->tree_index->table)); return(root); } @@ -259,7 +259,7 @@ btr_page_create( ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); page_create(page, mtr, - dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table)); + dict_table_is_comp(tree->tree_index->table)); buf_block_align(page)->check_index_page_at_flush = TRUE; btr_page_set_index_id(page, tree->id, mtr); @@ -574,7 +574,7 @@ btr_page_get_father_for_rec( tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap, btr_page_get_level(page, mtr)); - index = UT_LIST_GET_FIRST(tree->tree_indexes); + index = tree->tree_index; /* In the following, we choose just any index from the tree as the first parameter for btr_cur_search_to_nth_level. */ @@ -1073,8 +1073,7 @@ btr_root_raise_and_insert( /* fprintf(stderr, "Root raise new page no %lu\n", buf_frame_get_page_no(new_page)); */ - ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), - new_page); + ibuf_reset_free_bits(tree->tree_index, new_page); /* Reposition the cursor to the child node */ page_cur_search(new_page, cursor->index, tuple, PAGE_CUR_LE, page_cursor); @@ -1415,7 +1414,7 @@ btr_insert_on_non_leaf_level( /* In the following, choose just any index from the tree as the first parameter for btr_cur_search_to_nth_level. */ - btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes), + btr_cur_search_to_nth_level(tree->tree_index, level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE, &cursor, 0, mtr); @@ -1479,7 +1478,7 @@ btr_attach_half_pages( btr_node_ptr_set_child_page_no(node_ptr, rec_get_offsets(node_ptr, - UT_LIST_GET_FIRST(tree->tree_indexes), + tree->tree_index, NULL, ULINT_UNDEFINED, &heap), lower_page_no, mtr); mem_heap_empty(heap); @@ -1768,8 +1767,8 @@ func_start: buf_frame_get_page_no(left_page), buf_frame_get_page_no(right_page)); */ - ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes))); - ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes))); + ut_ad(page_validate(left_page, tree->tree_index)); + ut_ad(page_validate(right_page, tree->tree_index)); mem_heap_free(heap); return(rec); @@ -1910,8 +1909,7 @@ btr_node_ptr_delete( node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); - btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr, - &cursor); + btr_cur_position(tree->tree_index, node_ptr, &cursor); compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE, mtr); ut_a(err == DB_SUCCESS); @@ -1947,7 +1945,7 @@ btr_lift_page_up( btr_page_get_father_node_ptr(tree, page, mtr)); page_level = btr_page_get_level(page, mtr); - index = UT_LIST_GET_FIRST(tree->tree_indexes); + index = tree->tree_index; btr_search_drop_page_hash_index(page); @@ -2180,8 +2178,7 @@ btr_discard_only_page_on_level( btr_page_empty(father_page, mtr); /* We play safe and reset the free bits for the father */ - ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), - father_page); + ibuf_reset_free_bits(tree->tree_index, father_page); } else { ut_ad(page_get_n_recs(father_page) == 1); @@ -2449,7 +2446,7 @@ btr_check_node_ptr( ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr, rec_get_offsets(node_ptr, - dict_tree_find_index(tree, node_ptr), + tree->tree_index, NULL, ULINT_UNDEFINED, &heap)) == 0); mem_heap_free(heap); @@ -2692,7 +2689,7 @@ btr_validate_level( space = buf_frame_get_space_id(page); - index = UT_LIST_GET_FIRST(tree->tree_indexes); + index = tree->tree_index; while (level != btr_page_get_level(page, &mtr)) { diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 14e991bb3c6..deba3e23487 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1606,7 +1606,7 @@ btr_cur_optimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update, - NULL); + FALSE, NULL); old_rec_size = rec_offs_size(offsets); new_rec_size = rec_get_converted_size(index, new_entry); @@ -1846,7 +1846,7 @@ btr_cur_pessimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update, - heap); + FALSE, heap); if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr); @@ -1915,13 +1915,13 @@ btr_cur_pessimistic_update( ut_a(rec || optim_err != DB_UNDERFLOW); if (rec) { - offsets = rec_get_offsets(rec, index, offsets, - ULINT_UNDEFINED, &heap); - lock_rec_restore_from_page_infimum(rec, page); rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr); + offsets = rec_get_offsets(rec, index, offsets, + ULINT_UNDEFINED, &heap); + if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) { /* The new inserted record owns its possible externally stored fields */ @@ -2371,8 +2371,7 @@ btr_cur_compress( ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(btr_cur_get_tree(cursor)), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0); @@ -2398,8 +2397,7 @@ btr_cur_compress_if_useful( ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(btr_cur_get_tree(cursor)), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); if (btr_cur_compress_recommendation(cursor, mtr)) { @@ -2437,7 +2435,7 @@ btr_cur_optimistic_delete( ibool no_compress_needed; *offsets_ = (sizeof offsets_) / sizeof *offsets_; - ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); /* This is intended only for leaf page deletions */ @@ -3330,7 +3328,10 @@ btr_store_big_rec_extern_fields( dict_index_t* index, /* in: index of rec; the index tree MUST be X-latched */ rec_t* rec, /* in: record */ - const ulint* offsets, /* in: rec_get_offsets(rec, index) */ + const ulint* offsets, /* in: rec_get_offsets(rec, index); + the "external storage" flags in offsets + will not correspond to rec when + this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ mtr_t* local_mtr __attribute__((unused))) /* in: mtr diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c index e3ba50a2d5b..85a6577bafb 100644 --- a/storage/innobase/btr/btr0pcur.c +++ b/storage/innobase/btr/btr0pcur.c @@ -259,10 +259,7 @@ btr_pcur_restore_position( cursor->latch_mode = latch_mode; #ifdef UNIV_DEBUG rec = btr_pcur_get_rec(cursor); - index = dict_tree_find_index( - btr_cur_get_tree( - btr_pcur_get_btr_cur(cursor)), - rec); + index = btr_pcur_get_btr_cur(cursor)->index; heap = mem_heap_create(256); offsets1 = rec_get_offsets(cursor->old_rec, diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index 428b4d9a6b7..be7bb7c421f 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -24,8 +24,8 @@ ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the #ifdef UNIV_SEARCH_PERF_STAT ulint btr_search_n_succ = 0; -#endif /* UNIV_SEARCH_PERF_STAT */ ulint btr_search_n_hash_fail = 0; +#endif /* UNIV_SEARCH_PERF_STAT */ byte btr_sea_pad1[64]; /* padding to prevent other memory update hotspots from residing on the same memory @@ -59,9 +59,6 @@ before hash index building is started */ #define BTR_SEARCH_BUILD_LIMIT 100 -/* How many cells to check before temporarily releasing btr_search_latch */ -#define BTR_CHUNK_SIZE 10000 - /************************************************************************ Builds a hash index on a page with the given parameters. If the page already has a hash index with different parameters, the old hash index is removed. @@ -172,10 +169,12 @@ btr_search_info_create( info->last_hash_succ = FALSE; +#ifdef UNIV_SEARCH_PERF_STAT info->n_hash_succ = 0; info->n_hash_fail = 0; info->n_patt_succ = 0; info->n_searches = 0; +#endif /* UNIV_SEARCH_PERF_STAT */ /* Set some sensible values */ info->n_fields = 1; @@ -487,7 +486,9 @@ btr_search_info_update_slow( if (cursor->flag == BTR_CUR_HASH_FAIL) { /* Update the hash node reference, if appropriate */ +#ifdef UNIV_SEARCH_PERF_STAT btr_search_n_hash_fail++; +#endif /* UNIV_SEARCH_PERF_STAT */ rw_lock_x_lock(&btr_search_latch); @@ -872,11 +873,11 @@ failure_unlock: rw_lock_s_unlock(&btr_search_latch); } failure: - info->n_hash_fail++; - cursor->flag = BTR_CUR_HASH_FAIL; #ifdef UNIV_SEARCH_PERF_STAT + info->n_hash_fail++; + if (info->n_hash_succ > 0) { info->n_hash_succ--; } @@ -1607,21 +1608,26 @@ btr_search_validate(void) mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; + + /* How many cells to check before temporarily releasing + btr_search_latch. */ + ulint chunk_size = 10000; + *offsets_ = (sizeof offsets_) / sizeof *offsets_; rw_lock_x_lock(&btr_search_latch); cell_count = hash_get_n_cells(btr_search_sys->hash_index); - + for (i = 0; i < cell_count; i++) { /* We release btr_search_latch every once in a while to give other queries a chance to run. */ - if ((i != 0) && ((i % BTR_CHUNK_SIZE) == 0)) { + if ((i != 0) && ((i % chunk_size) == 0)) { rw_lock_x_unlock(&btr_search_latch); os_thread_yield(); rw_lock_x_lock(&btr_search_latch); } - + node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node; while (node != NULL) { @@ -1675,9 +1681,9 @@ btr_search_validate(void) } } - for (i = 0; i < cell_count; i += BTR_CHUNK_SIZE) { - ulint end_index = ut_min(i + BTR_CHUNK_SIZE - 1, cell_count - 1); - + for (i = 0; i < cell_count; i += chunk_size) { + ulint end_index = ut_min(i + chunk_size - 1, cell_count - 1); + /* We release btr_search_latch every once in a while to give other queries a chance to run. */ if (i != 0) { diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 3b6c47a21e9..08be5811a4b 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -294,14 +294,14 @@ buf_LRU_try_free_flushed_blocks(void) } /********************************************************************** -Returns TRUE if less than 15 % of the buffer pool is available. This can be +Returns TRUE if less than 25 % of the buffer pool is available. This can be used in heuristics to prevent huge transactions eating up the whole buffer pool for their locks. */ ibool buf_LRU_buf_pool_running_out(void) /*==============================*/ - /* out: TRUE if less than 15 % of buffer pool + /* out: TRUE if less than 25 % of buffer pool left */ { ibool ret = FALSE; @@ -309,7 +309,7 @@ buf_LRU_buf_pool_running_out(void) mutex_enter(&(buf_pool->mutex)); if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 7) { + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) { ret = TRUE; } @@ -340,11 +340,11 @@ loop: mutex_enter(&(buf_pool->mutex)); if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) { + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 20) { ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: ERROR: over 9 / 10 of the buffer pool is occupied by\n" +" InnoDB: ERROR: over 95 percent of the buffer pool is occupied by\n" "InnoDB: lock heaps or the adaptive hash index! Check that your\n" "InnoDB: transactions do not set too many row locks.\n" "InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n" @@ -356,17 +356,17 @@ loop: ut_error; } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) { + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 3) { if (!buf_lru_switched_on_innodb_mon) { - /* Over 80 % of the buffer pool is occupied by lock + /* Over 67 % of the buffer pool is occupied by lock heaps or the adaptive hash index. This may be a memory leak! */ ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n" +" InnoDB: WARNING: over 67 percent of the buffer pool is occupied by\n" "InnoDB: lock heaps or the adaptive hash index! Check that your\n" "InnoDB: transactions do not set too many row locks.\n" "InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n" @@ -881,10 +881,10 @@ buf_LRU_block_remove_hashed_page( if (buf_page_hash_get(block->space, block->offset)) { fprintf(stderr, "InnoDB: From hash table we find block %p of %lu %lu which is not %p\n", - buf_page_hash_get(block->space, block->offset), + (void*) buf_page_hash_get(block->space, block->offset), (ulong) buf_page_hash_get(block->space, block->offset)->space, (ulong) buf_page_hash_get(block->space, block->offset)->offset, - block); + (void*) block); } #ifdef UNIV_DEBUG diff --git a/storage/innobase/cmakelists.txt b/storage/innobase/cmakelists.txt index de46430e2ab..def51873725 100644 --- a/storage/innobase/cmakelists.txt +++ b/storage/innobase/cmakelists.txt @@ -32,4 +32,4 @@ ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c thr/thr0loc.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c usr/usr0sess.c - ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c) + ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c) diff --git a/storage/innobase/configure.in b/storage/innobase/configure.in index e0521471c2f..91afcc1c9b3 100644 --- a/storage/innobase/configure.in +++ b/storage/innobase/configure.in @@ -89,6 +89,25 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS -DDEBUG_OFF" fi +# NOTE: The flags below are disabled by default since we can't easily get +# rid of the "string over 509 characters in length" warnings, and thus can't +# add -Werror. But it's a good idea to enable these for a test compile +# before shipping a new snapshot to MySQL to catch errors that could make +# the compile fail on non-C99 compilers. + +# If using gcc, disallow usage of C99 features to avoid accidentally +# introducing problems on compilers that only implement C89. +#if test "$ac_cv_prog_gcc" = "yes" +#then +# CFLAGS="$CFLAGS -std=c89 -ansi -pedantic -Wno-long-long" +#fi + +# If using gcc, add some extra warning flags. +if test "$ac_cv_prog_gcc" = "yes" +then + CFLAGS="$CFLAGS -Werror-implicit-function-declaration" +fi + case "$target_os" in lin*) CFLAGS="$CFLAGS -DUNIV_LINUX";; diff --git a/storage/innobase/data/data0type.c b/storage/innobase/data/data0type.c index 3ac1139d952..2f36e7250fc 100644 --- a/storage/innobase/data/data0type.c +++ b/storage/innobase/data/data0type.c @@ -216,20 +216,43 @@ dtype_print( mtype = type->mtype; prtype = type->prtype; - if (mtype == DATA_VARCHAR) { + + switch (mtype) { + case DATA_VARCHAR: fputs("DATA_VARCHAR", stderr); - } else if (mtype == DATA_CHAR) { + break; + + case DATA_CHAR: fputs("DATA_CHAR", stderr); - } else if (mtype == DATA_BINARY) { + break; + + case DATA_BINARY: fputs("DATA_BINARY", stderr); - } else if (mtype == DATA_INT) { + break; + + case DATA_FIXBINARY: + fputs("DATA_FIXBINARY", stderr); + break; + + case DATA_BLOB: + fputs("DATA_BLOB", stderr); + break; + + case DATA_INT: fputs("DATA_INT", stderr); - } else if (mtype == DATA_MYSQL) { + break; + + case DATA_MYSQL: fputs("DATA_MYSQL", stderr); - } else if (mtype == DATA_SYS) { + break; + + case DATA_SYS: fputs("DATA_SYS", stderr); - } else { + break; + + default: fprintf(stderr, "type %lu", (ulong) mtype); + break; } len = type->len; @@ -254,6 +277,18 @@ dtype_print( } else { fprintf(stderr, "prtype %lu", (ulong) prtype); } + } else { + if (prtype & DATA_UNSIGNED) { + fputs(" DATA_UNSIGNED", stderr); + } + + if (prtype & DATA_BINARY_TYPE) { + fputs(" DATA_BINARY_TYPE", stderr); + } + + if (prtype & DATA_NOT_NULL) { + fputs(" DATA_NOT_NULL", stderr); + } } fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec); diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 6f0a81296ac..4233cb05773 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -24,6 +24,7 @@ Created 1/8/1996 Heikki Tuuri #include "pars0pars.h" #include "trx0roll.h" #include "usr0sess.h" +#include "ut0vec.h" /********************************************************************* Based on a table object, this function builds the entry to be inserted @@ -74,14 +75,14 @@ dict_create_sys_tables_tuple( dfield = dtuple_get_nth_field(entry, 3); ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->type); + mach_write_to_4(ptr, DICT_TABLE_ORDINARY); dfield_set_data(dfield, ptr, 4); /* 6: MIX_ID ---------------------------*/ dfield = dtuple_get_nth_field(entry, 4); ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, table->mix_id); + memset(ptr, 0, 8); dfield_set_data(dfield, ptr, 8); /* 7: MIX_LEN --------------------------*/ @@ -89,19 +90,13 @@ dict_create_sys_tables_tuple( dfield = dtuple_get_nth_field(entry, 5); ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->mix_len); + memset(ptr, 0, 4); dfield_set_data(dfield, ptr, 4); /* 8: CLUSTER_NAME ---------------------*/ dfield = dtuple_get_nth_field(entry, 6); + dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */ - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - dfield_set_data(dfield, table->cluster_name, - ut_strlen(table->cluster_name)); - ut_error; /* Oracle-style clusters are not supported yet */ - } else { - dfield_set_data(dfield, NULL, UNIV_SQL_NULL); - } /* 9: SPACE ----------------------------*/ dfield = dtuple_get_nth_field(entry, 7); @@ -207,7 +202,6 @@ dict_build_table_def_step( tab_node_t* node) /* in: table create node */ { dict_table_t* table; - dict_table_t* cluster_table; dtuple_t* row; ulint error; const char* path_or_name; @@ -235,23 +229,6 @@ dict_build_table_def_step( return(DB_TOO_BIG_RECORD); } - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - cluster_table = dict_table_get_low(table->cluster_name); - - if (cluster_table == NULL) { - - return(DB_CLUSTER_NOT_FOUND); - } - - /* Inherit space and mix len from the cluster */ - - table->space = cluster_table->space; - table->mix_len = cluster_table->mix_len; - - table->mix_id = dict_hdr_get_new_id(DICT_HDR_MIX_ID); - } - if (srv_file_per_table) { /* We create a new single-table tablespace for the table. We initially let it be 4 pages: @@ -614,15 +591,6 @@ dict_create_index_tree_step( sys_indexes = dict_sys->sys_indexes; - if (index->type & DICT_CLUSTERED - && table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* Do not create a new index tree: entries are put to the - cluster tree */ - - return(DB_SUCCESS); - } - /* Run a mini-transaction in which the index tree is allocated for the index and its root address is written to the index entry in sys_indexes */ @@ -1159,11 +1127,8 @@ dict_create_or_check_foreign_constraint_tables(void) { dict_table_t* table1; dict_table_t* table2; - que_thr_t* thr; - que_t* graph; ulint error; trx_t* trx; - const char* str; mutex_enter(&(dict_sys->mutex)); @@ -1215,7 +1180,7 @@ dict_create_or_check_foreign_constraint_tables(void) VARBINARY, like in other InnoDB system tables, to get a clean design. */ - str = + error = que_eval_sql(NULL, "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" "BEGIN\n" "CREATE TABLE\n" @@ -1227,22 +1192,8 @@ dict_create_or_check_foreign_constraint_tables(void) "SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n" "COMMIT WORK;\n" - "END;\n"; - - graph = pars_sql(str); - - ut_a(graph); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - error = trx->error_state; + "END;\n" + , trx); if (error != DB_SUCCESS) { fprintf(stderr, "InnoDB: error %lu in creation\n", @@ -1261,8 +1212,6 @@ dict_create_or_check_foreign_constraint_tables(void) error = DB_MUST_GET_MORE_FILE_SPACE; } - que_graph_free(graph); - trx->op_info = ""; row_mysql_unlock_data_dictionary(trx); @@ -1277,150 +1226,23 @@ dict_create_or_check_foreign_constraint_tables(void) return(error); } -/************************************************************************ -Adds foreign key definitions to data dictionary tables in the database. We -look at table->foreign_list, and also generate names to constraints that were -not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_, where the numbers start from 1, and are -given locally for this table, that is, the number is not global, as in the -old format constraints < 4.0.18 it used to be. */ +/******************************************************************** +Evaluate the given foreign key SQL statement. */ ulint -dict_create_add_foreigns_to_dictionary( -/*===================================*/ +dict_foreign_eval_sql( +/*==================*/ /* out: error code or DB_SUCCESS */ - ulint start_id,/* in: if we are actually doing ALTER TABLE - ADD CONSTRAINT, we want to generate constraint - numbers which are bigger than in the table so - far; we number the constraints from - start_id + 1 up; start_id should be set to 0 if - we are creating a new table, or if the table - so far has no constraints for which the name - was generated here */ + pars_info_t* info, /* in: info struct, or NULL */ + const char* sql, /* in: SQL string to evaluate */ dict_table_t* table, /* in: table */ + dict_foreign_t* foreign,/* in: foreign */ trx_t* trx) /* in: transaction */ { - dict_foreign_t* foreign; - que_thr_t* thr; - que_t* graph; - ulint number = start_id + 1; - ulint len; ulint error; FILE* ef = dict_foreign_err_file; - ulint i; - char* sql; - char* sqlend; - /* This procedure builds an InnoDB stored procedure which will insert - the necessary rows into SYS_FOREIGN and SYS_FOREIGN_COLS. */ - static const char str1[] = "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n" - "BEGIN\n" - "INSERT INTO SYS_FOREIGN VALUES("; - static const char str2[] = ");\n"; - static const char str3[] = - "INSERT INTO SYS_FOREIGN_COLS VALUES("; - static const char str4[] = - "COMMIT WORK;\n" - "END;\n"; -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - if (NULL == dict_table_get_low("SYS_FOREIGN")) { - fprintf(stderr, -"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); - - return(DB_ERROR); - } - - foreign = UT_LIST_GET_FIRST(table->foreign_list); -loop: - if (foreign == NULL) { - - return(DB_SUCCESS); - } - - if (foreign->id == NULL) { - /* Generate a new constraint id */ - ulint namelen = strlen(table->name); - char* id = mem_heap_alloc(foreign->heap, namelen + 20); - /* no overflow if number < 1e13 */ - sprintf(id, "%s_ibfk_%lu", table->name, (ulong) number++); - foreign->id = id; - } - - len = (sizeof str1) + (sizeof str2) + (sizeof str4) - 3 - + 9/* ' and , chars */ + 10/* 32-bit integer */ - + ut_strlenq(foreign->id, '\'') * (foreign->n_fields + 1) - + ut_strlenq(table->name, '\'') - + ut_strlenq(foreign->referenced_table_name, '\''); - - for (i = 0; i < foreign->n_fields; i++) { - len += 9/* ' and , chars */ + 10/* 32-bit integer */ - + (sizeof str3) + (sizeof str2) - 2 - + ut_strlenq(foreign->foreign_col_names[i], '\'') - + ut_strlenq(foreign->referenced_col_names[i], '\''); - } - - sql = sqlend = mem_alloc(len + 1); - - /* INSERT INTO SYS_FOREIGN VALUES(...); */ - memcpy(sqlend, str1, (sizeof str1) - 1); - sqlend += (sizeof str1) - 1; - *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->id); - *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', table->name); - *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->referenced_table_name); - *sqlend++ = '\'', *sqlend++ = ','; - sqlend += sprintf(sqlend, "%010lu", - foreign->n_fields + (foreign->type << 24)); - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - - for (i = 0; i < foreign->n_fields; i++) { - /* INSERT INTO SYS_FOREIGN_COLS VALUES(...); */ - memcpy(sqlend, str3, (sizeof str3) - 1); - sqlend += (sizeof str3) - 1; - *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->id); - *sqlend++ = '\''; *sqlend++ = ','; - sqlend += sprintf(sqlend, "%010lu", (ulong) i); - *sqlend++ = ','; *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', - foreign->foreign_col_names[i]); - *sqlend++ = '\''; *sqlend++ = ','; *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', - foreign->referenced_col_names[i]); - *sqlend++ = '\''; - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - } - - memcpy(sqlend, str4, sizeof str4); - sqlend += sizeof str4; - - ut_a(sqlend == sql + len + 1); - - graph = pars_sql(sql); - - ut_a(graph); - - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - error = trx->error_state; - - que_graph_free(graph); + error = que_eval_sql(info, sql, trx); if (error == DB_DUPLICATE_KEY) { mutex_enter(&dict_foreign_err_mutex); @@ -1466,7 +1288,163 @@ loop: return(error); } - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - - goto loop; + return(DB_SUCCESS); +} + +/************************************************************************ +Add a single foreign key field definition to the data dictionary tables in +the database. */ +static +ulint +dict_create_add_foreign_field_to_dictionary( +/*========================================*/ + /* out: error code or DB_SUCCESS */ + ulint field_nr, /* in: foreign field number */ + dict_table_t* table, /* in: table */ + dict_foreign_t* foreign, /* in: foreign */ + trx_t* trx) /* in: transaction */ +{ + pars_info_t* info = pars_info_create(); + + pars_info_add_str_literal(info, "id", foreign->id); + + pars_info_add_int4_literal(info, "pos", field_nr); + + pars_info_add_str_literal(info, "for_col_name", + foreign->foreign_col_names[field_nr]); + + pars_info_add_str_literal(info, "ref_col_name", + foreign->referenced_col_names[field_nr]); + + return dict_foreign_eval_sql(info, + "PROCEDURE P () IS\n" + "BEGIN\n" + "INSERT INTO SYS_FOREIGN_COLS VALUES" + "(:id, :pos, :for_col_name, :ref_col_name);\n" + "END;\n" + , table, foreign, trx); +} + +/************************************************************************ +Add a single foreign key definition to the data dictionary tables in the +database. We also generate names to constraints that were not named by the +user. A generated constraint has a name of the format +databasename/tablename_ibfk_, where the numbers start from 1, and +are given locally for this table, that is, the number is not global, as in +the old format constraints < 4.0.18 it used to be. */ +static +ulint +dict_create_add_foreign_to_dictionary( +/*==================================*/ + /* out: error code or DB_SUCCESS */ + ulint* id_nr, /* in/out: number to use in id generation; + incremented if used */ + dict_table_t* table, /* in: table */ + dict_foreign_t* foreign,/* in: foreign */ + trx_t* trx) /* in: transaction */ +{ + ulint error; + ulint i; + + pars_info_t* info = pars_info_create(); + + if (foreign->id == NULL) { + /* Generate a new constraint id */ + ulint namelen = strlen(table->name); + char* id = mem_heap_alloc(foreign->heap, namelen + 20); + /* no overflow if number < 1e13 */ + sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); + foreign->id = id; + } + + pars_info_add_str_literal(info, "id", foreign->id); + + pars_info_add_str_literal(info, "for_name", table->name); + + pars_info_add_str_literal(info, "ref_name", + foreign->referenced_table_name); + + pars_info_add_int4_literal(info, "n_cols", + foreign->n_fields + (foreign->type << 24)); + + error = dict_foreign_eval_sql(info, + "PROCEDURE P () IS\n" + "BEGIN\n" + "INSERT INTO SYS_FOREIGN VALUES" + "(:id, :for_name, :ref_name, :n_cols);\n" + "END;\n" + , table, foreign, trx); + + if (error != DB_SUCCESS) { + + return(error); + } + + for (i = 0; i < foreign->n_fields; i++) { + error = dict_create_add_foreign_field_to_dictionary(i, + table, foreign, trx); + + if (error != DB_SUCCESS) { + + return(error); + } + } + + error = dict_foreign_eval_sql(NULL, + "PROCEDURE P () IS\n" + "BEGIN\n" + "COMMIT WORK;\n" + "END;\n" + , table, foreign, trx); + + return(error); +} + +/************************************************************************ +Adds foreign key definitions to data dictionary tables in the database. */ + +ulint +dict_create_add_foreigns_to_dictionary( +/*===================================*/ + /* out: error code or DB_SUCCESS */ + ulint start_id,/* in: if we are actually doing ALTER TABLE + ADD CONSTRAINT, we want to generate constraint + numbers which are bigger than in the table so + far; we number the constraints from + start_id + 1 up; start_id should be set to 0 if + we are creating a new table, or if the table + so far has no constraints for which the name + was generated here */ + dict_table_t* table, /* in: table */ + trx_t* trx) /* in: transaction */ +{ + dict_foreign_t* foreign; + ulint number = start_id + 1; + ulint error; + +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(dict_sys->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + if (NULL == dict_table_get_low("SYS_FOREIGN")) { + fprintf(stderr, +"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); + + return(DB_ERROR); + } + + for (foreign = UT_LIST_GET_FIRST(table->foreign_list); + foreign; + foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + + error = dict_create_add_foreign_to_dictionary(&number, + table, foreign, trx); + + if (error != DB_SUCCESS) { + + return(error); + } + } + + return(DB_SUCCESS); } diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 1fac5e26fa9..877d4afe8f0 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -657,6 +657,19 @@ dict_table_get_nth_col_pos( n)); } +/************************************************************************ +Check whether the table uses the compact page format. */ + +ibool +dict_table_is_comp_noninline( +/*=========================*/ + /* out: TRUE if table uses the + compact page format */ + const dict_table_t* table) /* in: table */ +{ + return(dict_table_is_comp(table)); +} + /************************************************************************ Checks if a column is in the ordering columns of the clustered index of a table. Column prefixes are treated like whole columns. */ @@ -870,13 +883,6 @@ dict_table_add_to_cache( ut_a(table2 == NULL); } - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - table->mix_id_len = mach_dulint_get_compressed_size( - table->mix_id); - mach_dulint_write_compressed(table->mix_id_buf, table->mix_id); - } - /* Add the columns to the column hash table */ for (i = 0; i < table->n_cols; i++) { dict_col_add_to_cache(table, dict_table_get_nth_col(table, i)); @@ -1251,15 +1257,13 @@ dict_table_remove_from_cache( /* Remove table from LRU list of tables */ UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); - mutex_free(&(table->autoinc_mutex)); - size = mem_heap_get_size(table->heap); ut_ad(dict_sys->size >= size); dict_sys->size -= size; - mem_heap_free(table->heap); + dict_mem_table_free(table); } /************************************************************************** @@ -1380,6 +1384,38 @@ dict_col_reposition_in_cache( HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); } +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name) /* in: column name */ +{ + /* This check reminds that if a new system column is added to + the program, it should be dealt with here. */ +#if DATA_N_SYS_COLS != 4 +#error "DATA_N_SYS_COLS != 4" +#endif + + static const char* reserved_names[] = { + "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR", "DB_MIX_ID" + }; + + ulint i; + + for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { + if (strcmp(name, reserved_names[i]) == 0) { + + return(TRUE); + } + } + + return(FALSE); +} + /************************************************************************** Adds an index to the dictionary cache. */ @@ -1394,7 +1430,6 @@ dict_index_add_to_cache( { dict_index_t* new_index; dict_tree_t* tree; - dict_table_t* cluster; dict_field_t* field; ulint n_ord; ibool success; @@ -1468,21 +1503,11 @@ dict_index_add_to_cache( dict_field_get_col(field)->ord_part++; } - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - /* The index tree is found from the cluster object */ + /* Create an index tree memory object for the index */ + tree = dict_tree_create(new_index, page_no); + ut_ad(tree); - cluster = dict_table_get_low(table->cluster_name); - - tree = dict_index_get_tree( - UT_LIST_GET_FIRST(cluster->indexes)); - new_index->tree = tree; - } else { - /* Create an index tree memory object for the index */ - tree = dict_tree_create(new_index, page_no); - ut_ad(tree); - - new_index->tree = tree; - } + new_index->tree = tree; if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) { @@ -1500,7 +1525,7 @@ dict_index_add_to_cache( } /* Add the index to the list of indexes stored in the tree */ - UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); + tree->tree_index = new_index; /* If the dictionary cache grows too big, trim the table LRU list */ @@ -1532,7 +1557,7 @@ dict_index_remove_from_cache( ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ - ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1); + ut_ad(index->tree->tree_index); dict_tree_free(index->tree); /* Decrement the ord_part counts in columns which are ordering */ @@ -1553,7 +1578,7 @@ dict_index_remove_from_cache( dict_sys->size -= size; - mem_heap_free(index->heap); + dict_mem_index_free(index); } /*********************************************************************** @@ -1699,8 +1724,6 @@ dict_table_copy_types( dtype_t* type; ulint i; - ut_ad(!(table->type & DICT_UNIVERSAL)); - for (i = 0; i < dtuple_get_n_fields(tuple); i++) { dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); @@ -1749,22 +1772,8 @@ dict_index_build_internal_clust( new_index->id = index->id; - if (table->type != DICT_TABLE_ORDINARY) { - /* The index is mixed: copy common key prefix fields */ - - dict_index_copy(new_index, index, 0, table->mix_len); - - /* Add the mix id column */ - dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_MIX_ID), 0); - - /* Copy the rest of fields */ - dict_index_copy(new_index, index, table->mix_len, - index->n_fields); - } else { - /* Copy the fields of index */ - dict_index_copy(new_index, index, 0, index->n_fields); - } + /* Copy the fields of index */ + dict_index_copy(new_index, index, 0, index->n_fields); if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) { /* No fixed number of fields determines an entry uniquely */ @@ -3641,7 +3650,7 @@ dict_tree_create( tree->id = index->id; - UT_LIST_INIT(tree->tree_indexes); + tree->tree_index = NULL; tree->magic_n = DICT_TREE_MAGIC_N; @@ -3667,135 +3676,7 @@ dict_tree_free( mem_free(tree); } -/************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ -UNIV_INLINE -dict_index_t* -dict_tree_find_index_low( -/*=====================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec) /* in: record for which to find correct - index */ -{ - dict_index_t* index; - dict_table_t* table; - dulint mix_id; - ulint len; - - index = UT_LIST_GET_FIRST(tree->tree_indexes); - ut_ad(index); - table = index->table; - - if ((index->type & DICT_CLUSTERED) - && UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) { - - /* Get the mix id of the record */ - ut_a(!dict_table_is_comp(table)); - - mix_id = mach_dulint_read_compressed( - rec_get_nth_field_old(rec, table->mix_len, &len)); - - while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { - - index = UT_LIST_GET_NEXT(tree_indexes, index); - table = index->table; - ut_ad(index); - } - } - - return(index); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ - -dict_index_t* -dict_tree_find_index( -/*=================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec) /* in: record for which to find correct - index */ -{ - dict_index_t* index; - - index = dict_tree_find_index_low(tree, rec); - - return(index); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a dtuple which is used -in a search to a tree. */ - -dict_index_t* -dict_tree_find_index_for_tuple( -/*===========================*/ - /* out: index; NULL if the tuple does not - contain the mix id field in a mixed tree */ - dict_tree_t* tree, /* in: index tree */ - dtuple_t* tuple) /* in: tuple for which to find index */ -{ - dict_index_t* index; - dict_table_t* table; - dulint mix_id; - - ut_ad(dtuple_check_typed(tuple)); - - if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) { - - return(UT_LIST_GET_FIRST(tree->tree_indexes)); - } - - index = UT_LIST_GET_FIRST(tree->tree_indexes); - ut_ad(index); - table = index->table; - - if (dtuple_get_n_fields(tuple) <= table->mix_len) { - - return(NULL); - } - - /* Get the mix id of the record */ - - mix_id = mach_dulint_read_compressed( - dfield_get_data( - dtuple_get_nth_field(tuple, table->mix_len))); - - while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { - - index = UT_LIST_GET_NEXT(tree_indexes, index); - table = index->table; - ut_ad(index); - } - - return(index); -} - -/*********************************************************************** -Checks if a table which is a mixed cluster member owns a record. */ - -ibool -dict_is_mixed_table_rec( -/*====================*/ - /* out: TRUE if the record belongs to this - table */ - dict_table_t* table, /* in: table in a mixed cluster */ - rec_t* rec) /* in: user record in the clustered index */ -{ - byte* mix_id_field; - ulint len; - - ut_ad(!dict_table_is_comp(table)); - - mix_id_field = rec_get_nth_field_old(rec, - table->mix_len, &len); - - return(len == table->mix_id_len - && !ut_memcmp(table->mix_id_buf, mix_id_field, len)); -} - +#ifdef UNIV_DEBUG /************************************************************************** Checks that a tuple has n_fields_cmp value in a sensible range, so that no comparison can occur with the page number field in a node pointer. */ @@ -3807,19 +3688,14 @@ dict_tree_check_search_tuple( dict_tree_t* tree, /* in: index tree */ dtuple_t* tuple) /* in: tuple used in a search */ { - dict_index_t* index; - - index = dict_tree_find_index_for_tuple(tree, tuple); - - if (index == NULL) { - - return(TRUE); - } + dict_index_t* index = tree->tree_index; + ut_a(index); ut_a(dtuple_get_n_fields_cmp(tuple) <= dict_index_get_n_unique_in_tree(index)); return(TRUE); } +#endif /* UNIV_DEBUG */ /************************************************************************** Builds a node pointer out of a physical record and a page number. */ @@ -3842,7 +3718,7 @@ dict_tree_build_node_ptr( byte* buf; ulint n_unique; - ind = dict_tree_find_index_low(tree, rec); + ind = tree->tree_index; if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) { /* In a universal index tree, we take the whole record as @@ -3910,7 +3786,7 @@ dict_tree_copy_rec_order_prefix( ulint n; UNIV_PREFETCH_R(rec); - index = dict_tree_find_index_low(tree, rec); + index = tree->tree_index; if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) { ut_a(!dict_table_is_comp(index->table)); @@ -3938,7 +3814,7 @@ dict_tree_build_data_tuple( dtuple_t* tuple; dict_index_t* ind; - ind = dict_tree_find_index_low(tree, rec); + ind = tree->tree_index; ut_ad(dict_table_is_comp(ind->table) || n_fields <= rec_get_n_fields_old(rec)); @@ -4096,6 +3972,18 @@ dict_update_statistics( dict_update_statistics_low(table, FALSE); } +/************************************************************************** +A noninlined version of dict_table_get_low. */ + +dict_table_t* +dict_table_get_low_noninlined( +/*==========================*/ + /* out: table, NULL if not found */ + const char* table_name) /* in: table name */ +{ + return(dict_table_get_low(table_name)); +} + /************************************************************************** Prints info of a foreign key constraint. */ static @@ -4520,15 +4408,3 @@ dict_index_name_print( fputs(" of table ", file); ut_print_name(file, trx, index->table_name); } - -/************************************************************************ -Export an inlined function for use in ha_innodb.c. */ -ibool -innodb_dict_table_is_comp( -/*===============*/ - /* out: TRUE if table uses the - compact page format */ - const dict_table_t* table) /* in: table */ -{ - return dict_table_is_comp(table); -} diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 09935c03288..4779e50f176 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -768,7 +768,7 @@ dict_load_table( if (!btr_pcur_is_on_user_rec(&pcur, &mtr) || rec_get_deleted_flag(rec, 0)) { /* Not found */ - + err_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); @@ -780,11 +780,8 @@ dict_load_table( /* Check if the table name in record is the searched one */ if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - return(NULL); + goto err_exit; } ut_a(0 == ut_strcmp("SPACE", @@ -848,36 +845,17 @@ dict_load_table( table->id = mach_read_from_8(field); field = rec_get_nth_field_old(rec, 5, &len); - table->type = mach_read_from_4(field); - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - ut_error; -#if 0 /* clustered tables have not been implemented yet */ - field = rec_get_nth_field_old(rec, 6, &len); - table->mix_id = mach_read_from_8(field); - - field = rec_get_nth_field_old(rec, 8, &len); - table->cluster_name = mem_heap_strdupl(heap, (char*) field, len); -#endif - } - - if ((table->type == DICT_TABLE_CLUSTER) - || (table->type == DICT_TABLE_CLUSTER_MEMBER)) { - - field = rec_get_nth_field_old(rec, 7, &len); - ut_a(len == 4); - table->mix_len = mach_read_from_4(field); + if (UNIV_UNLIKELY(mach_read_from_4(field) != DICT_TABLE_ORDINARY)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: table %s: unknown table type %lu\n", + name, (ulong) mach_read_from_4(field)); + goto err_exit; } btr_pcur_close(&pcur); mtr_commit(&mtr); - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - /* Load the cluster table definition if not yet in - memory cache */ - dict_table_get_low(table->cluster_name); - } - dict_load_columns(table, heap); dict_table_add_to_cache(table); diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index d9f0ad3d84e..fe21890adc8 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -50,7 +50,6 @@ dict_mem_table_create( table->heap = heap; - table->type = DICT_TABLE_ORDINARY; table->flags = flags; table->name = mem_heap_strdup(heap, name); table->dir_path_of_temp_table = NULL; @@ -66,9 +65,6 @@ dict_mem_table_create( table->cached = FALSE; - table->mix_id = ut_dulint_zero; - table->mix_len = 0; - table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) * sizeof(dict_col_t)); UT_LIST_INIT(table->indexes); @@ -97,42 +93,19 @@ dict_mem_table_create( return(table); } -/************************************************************************** -Creates a cluster memory object. */ - -dict_table_t* -dict_mem_cluster_create( -/*====================*/ - /* out, own: cluster object */ - const char* name, /* in: cluster name */ - ulint space, /* in: space where the clustered indexes - of the member tables are placed */ - ulint n_cols, /* in: number of columns */ - ulint mix_len)/* in: length of the common key prefix in the - cluster */ -{ - dict_table_t* cluster; - - /* Clustered tables cannot work with the compact record format. */ - cluster = dict_mem_table_create(name, space, n_cols, 0); - - cluster->type = DICT_TABLE_CLUSTER; - cluster->mix_len = mix_len; - - return(cluster); -} - -/************************************************************************** -Declares a non-published table as a member in a cluster. */ +/******************************************************************** +Free a table memory object. */ void -dict_mem_table_make_cluster_member( -/*===============================*/ - dict_table_t* table, /* in: non-published table */ - const char* cluster_name) /* in: cluster name */ +dict_mem_table_free( +/*================*/ + dict_table_t* table) /* in: table */ { - table->type = DICT_TABLE_CLUSTER_MEMBER; - table->cluster_name = cluster_name; + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + mutex_free(&(table->autoinc_mutex)); + mem_heap_free(table->heap); } /************************************************************************** @@ -286,5 +259,8 @@ dict_mem_index_free( /*================*/ dict_index_t* index) /* in: index */ { + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + mem_heap_free(index->heap); } diff --git a/storage/innobase/eval/eval0proc.c b/storage/innobase/eval/eval0proc.c index dcbdc0da5fc..96b8ef75955 100644 --- a/storage/innobase/eval/eval0proc.c +++ b/storage/innobase/eval/eval0proc.c @@ -212,6 +212,38 @@ for_step( return(thr); } +/************************************************************************** +Performs an execution step of an exit statement node. */ + +que_thr_t* +exit_step( +/*======*/ + /* out: query thread to run next or NULL */ + que_thr_t* thr) /* in: query thread */ +{ + exit_node_t* node; + que_node_t* loop_node; + + ut_ad(thr); + + node = thr->run_node; + + ut_ad(que_node_get_type(node) == QUE_NODE_EXIT); + + /* Loops exit by setting thr->run_node as the loop node's parent, so + find our containing loop node and get its parent. */ + + loop_node = que_node_get_containing_loop_node(node); + + /* If someone uses an EXIT statement outside of a loop, this will + trigger. */ + ut_a(loop_node); + + thr->run_node = que_node_get_parent(loop_node); + + return(thr); +} + /************************************************************************** Performs an execution step of a return-statement node. */ diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 36cc97e5e0e..3263a0efd5b 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1170,9 +1170,9 @@ ibuf_dummy_index_free( dict_index_t* index) /* in: dummy index */ { dict_table_t* table = index->table; - mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - mem_heap_free(table->heap); + + dict_mem_index_free(index); + dict_mem_table_free(table); } /************************************************************************* diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index cb6cb1b1a4d..d5dd4f3010a 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -459,7 +459,10 @@ btr_store_big_rec_extern_fields( dict_index_t* index, /* in: index of rec; the index tree MUST be X-latched */ rec_t* rec, /* in: record */ - const ulint* offsets, /* in: rec_get_offsets(rec, index) */ + const ulint* offsets, /* in: rec_get_offsets(rec, index); + the "external storage" flags in offsets + will not correspond to rec when + this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ mtr_t* local_mtr); /* in: mtr containing the latch to diff --git a/storage/innobase/include/btr0cur.ic b/storage/innobase/include/btr0cur.ic index 5d2ae768416..a199c3d4d32 100644 --- a/storage/innobase/include/btr0cur.ic +++ b/storage/innobase/include/btr0cur.ic @@ -98,8 +98,7 @@ btr_cur_compress_recommendation( { page_t* page; - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); page = btr_cur_get_page(cursor); @@ -142,8 +141,7 @@ btr_cur_can_delete_without_compress( { page_t* page; - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); page = btr_cur_get_page(cursor); diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index b64d5e62e03..62b1d2db559 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -180,12 +180,14 @@ struct btr_search_struct{ the same prefix should be indexed in the hash index */ /*----------------------*/ +#ifdef UNIV_SEARCH_PERF_STAT ulint n_hash_succ; /* number of successful hash searches thus far */ ulint n_hash_fail; /* number of failed hash searches */ ulint n_patt_succ; /* number of successful pattern searches thus far */ ulint n_searches; /* number of searches */ +#endif /* UNIV_SEARCH_PERF_STAT */ }; #define BTR_SEARCH_MAGIC_N 1112765 @@ -218,8 +220,8 @@ extern rw_lock_t* btr_search_latch_temp; #ifdef UNIV_SEARCH_PERF_STAT extern ulint btr_search_n_succ; -#endif /* UNIV_SEARCH_PERF_STAT */ extern ulint btr_search_n_hash_fail; +#endif /* UNIV_SEARCH_PERF_STAT */ /* After change in n_fields or n_bytes in info, this many rounds are waited before starting the hash analysis again: this is to save CPU time when there diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index f8150db0437..6d26fd4d3b2 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -26,14 +26,14 @@ void buf_LRU_try_free_flushed_blocks(void); /*==================================*/ /********************************************************************** -Returns TRUE if less than 15 % of the buffer pool is available. This can be +Returns TRUE if less than 25 % of the buffer pool is available. This can be used in heuristics to prevent huge transactions eating up the whole buffer pool for their locks. */ ibool buf_LRU_buf_pool_running_out(void); /*==============================*/ - /* out: TRUE if less than 15 % of buffer pool + /* out: TRUE if less than 25 % of buffer pool left */ /*####################################################################### diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 9de5c5b52d5..39cde5bfb55 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -100,6 +100,15 @@ ulint dict_col_get_clust_pos( /*===================*/ dict_col_t* col); +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name); /* in: column name */ /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ @@ -321,6 +330,14 @@ dict_table_get_low( /* out: table, NULL if not found */ const char* table_name); /* in: table name */ /************************************************************************** +A noninlined version of dict_table_get_low. */ + +dict_table_t* +dict_table_get_low_noninlined( +/*==========================*/ + /* out: table, NULL if not found */ + const char* table_name); /* in: table name */ +/************************************************************************** Returns an index object. */ UNIV_INLINE dict_index_t* @@ -496,10 +513,11 @@ dict_table_is_comp( compact page format */ const dict_table_t* table); /* in: table */ /************************************************************************ -Non inlined version of 'dict_table_is_comp' above. */ +Check whether the table uses the compact page format. */ + ibool -innodb_dict_table_is_comp( -/*===============*/ +dict_table_is_comp_noninline( +/*=========================*/ /* out: TRUE if table uses the compact page format */ const dict_table_t* table); /* in: table */ @@ -725,33 +743,6 @@ dict_tree_free( /************************************************************************** In an index tree, finds the index corresponding to a record in the tree. */ -dict_index_t* -dict_tree_find_index( -/*=================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec); /* in: record for which to find correct index */ -/************************************************************************** -In an index tree, finds the index corresponding to a dtuple which is used -in a search to a tree. */ - -dict_index_t* -dict_tree_find_index_for_tuple( -/*===========================*/ - /* out: index; NULL if the tuple does not - contain the mix id field in a mixed tree */ - dict_tree_t* tree, /* in: index tree */ - dtuple_t* tuple); /* in: tuple for which to find index */ -/*********************************************************************** -Checks if a table which is a mixed cluster member owns a record. */ - -ibool -dict_is_mixed_table_rec( -/*====================*/ - /* out: TRUE if the record belongs to this - table */ - dict_table_t* table, /* in: table in a mixed cluster */ - rec_t* rec); /* in: user record in the clustered index */ /************************************************************************** Returns an index object if it is found in the dictionary cache. */ @@ -760,6 +751,7 @@ dict_index_get_if_in_cache( /*=======================*/ /* out: index, NULL if not found */ dulint index_id); /* in: index id */ +#ifdef UNIV_DEBUG /************************************************************************** Checks that a tuple has n_fields_cmp value in a sensible range, so that no comparison can occur with the page number field in a node pointer. */ @@ -770,6 +762,7 @@ dict_tree_check_search_tuple( /* out: TRUE if ok */ dict_tree_t* tree, /* in: index tree */ dtuple_t* tuple); /* in: tuple used in a search */ +#endif /* UNIV_DEBUG */ /************************************************************************** Builds a node pointer out of a physical record and a page number. */ @@ -916,7 +909,6 @@ dict_tables_have_same_db( dbname '/' tablename */ const char* name2); /* in: table name in the form dbname '/' tablename */ - /************************************************************************* Scans from pointer onwards. Stops if is at the start of a copy of 'string' where characters are compared without case sensitivity. Stops @@ -928,7 +920,6 @@ dict_scan_to( /* out: scanned up to this */ const char* ptr, /* in: scan from */ const char* string);/* in: look for this */ - /* Buffers for storing detailed information about the latest foreign key and unique key errors */ extern FILE* dict_foreign_err_file; diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index b99ca7815a8..0b5a23e9380 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -92,7 +92,6 @@ dict_table_get_n_user_cols( { ut_ad(table); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(table->cached); return(table->n_cols - DATA_N_SYS_COLS); } @@ -126,7 +125,6 @@ dict_table_get_n_cols( { ut_ad(table); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(table->cached); return(table->n_cols); } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index ab07213de3b..0135ba3874d 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -35,9 +35,11 @@ combination of types */ /* Types for a table object */ #define DICT_TABLE_ORDINARY 1 +#if 0 /* not implemented */ #define DICT_TABLE_CLUSTER_MEMBER 2 #define DICT_TABLE_CLUSTER 3 /* this means that the table is really a cluster definition */ +#endif /* Table flags */ #define DICT_TF_COMPACT 1 /* compact page format */ @@ -56,29 +58,13 @@ dict_mem_table_create( a member of a cluster */ ulint n_cols, /* in: number of columns */ ulint flags); /* in: table flags */ -/************************************************************************** -Creates a cluster memory object. */ - -dict_cluster_t* -dict_mem_cluster_create( -/*====================*/ - /* out, own: cluster object (where the - type dict_cluster_t == dict_table_t) */ - const char* name, /* in: cluster name */ - ulint space, /* in: space where the clustered - indexes of the member tables are - placed */ - ulint n_cols, /* in: number of columns */ - ulint mix_len); /* in: length of the common key prefix - in the cluster */ -/************************************************************************** -Declares a non-published table as a member in a cluster. */ +/******************************************************************** +Free a table memory object. */ void -dict_mem_table_make_cluster_member( -/*===============================*/ - dict_table_t* table, /* in: non-published table */ - const char* cluster_name); /* in: cluster name */ +dict_mem_table_free( +/*================*/ + dict_table_t* table); /* in: table */ /************************************************************************** Adds a column definition to a table. */ @@ -176,9 +162,7 @@ struct dict_field_struct{ /* Data structure for an index tree */ struct dict_tree_struct{ ulint type; /* tree type */ - dulint id; /* id of the index stored in the tree, in the - case of a mixed index, the id of the clustered - index of the cluster table */ + dulint id; /* id of the index stored in the tree */ ulint space; /* space of index tree */ ulint page; /* index tree root page number */ byte pad[64];/* Padding to prevent other memory hotspots on @@ -189,13 +173,8 @@ struct dict_tree_struct{ struct has been memoryfixed (by mini- transactions wanting to access the index tree) */ - UT_LIST_BASE_NODE_T(dict_index_t) - tree_indexes; /* list of indexes stored in the - index tree: if the tree is not of the - mixed type there is only one index in - the list; if the tree is of the mixed - type, the first index in the list is the - index of the cluster which owns the tree */ + dict_index_t* tree_index; /* the index stored in the + index tree */ ulint magic_n;/* magic number */ }; @@ -301,8 +280,7 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */ /* Data structure for a database table */ struct dict_table_struct{ - dulint id; /* id of the table or cluster */ - ulint type; /* DICT_TABLE_ORDINARY, ... */ + dulint id; /* id of the table */ ulint flags; /* DICT_TF_COMPACT, ... */ mem_heap_t* heap; /* memory heap */ const char* name; /* table name */ @@ -371,17 +349,6 @@ struct dict_table_struct{ UT_LIST_BASE_NODE_T(lock_t) locks; /* list of locks on the table */ /*----------------------*/ - dulint mix_id; /* if the table is a member in a cluster, - this is its mix id */ - ulint mix_len;/* if the table is a cluster or a member - this is the common key prefix lenght */ - ulint mix_id_len;/* mix id length in a compressed form */ - byte mix_id_buf[12]; - /* mix id of a mixed table written in - a compressed form */ - const char* cluster_name; /* if the table is a member in a - cluster, this is the name of the cluster */ - /*----------------------*/ ibool does_not_fit_in_memory; /* this field is used to specify in simulations tables which are so big that disk should be diff --git a/storage/innobase/include/eval0proc.h b/storage/innobase/include/eval0proc.h index 2cf98f26265..8416551d0ba 100644 --- a/storage/innobase/include/eval0proc.h +++ b/storage/innobase/include/eval0proc.h @@ -63,6 +63,14 @@ proc_eval_step( /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /************************************************************************** +Performs an execution step of an exit statement node. */ + +que_thr_t* +exit_step( +/*======*/ + /* out: query thread to run next or NULL */ + que_thr_t* thr); /* in: query thread */ +/************************************************************************** Performs an execution step of a return-statement node. */ que_thr_t* diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index a5cd32d956f..31c5c57ae35 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -222,6 +222,32 @@ do {\ mem_heap_free_top(hash_get_heap(TABLE, fold111), sizeof(TYPE));\ } while (0) +/******************************************************************** +Move all hash table entries from OLD_TABLE to NEW_TABLE.*/ + +#define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, FOLD_FUNC) \ +do {\ + ulint i2222;\ + ulint cell_count2222;\ +\ + cell_count2222 = hash_get_n_cells(OLD_TABLE);\ +\ + for (i2222 = 0; i2222 < cell_count2222; i2222++) {\ + NODE_TYPE* node2222 = HASH_GET_FIRST((OLD_TABLE), i2222);\ +\ + while (node2222) {\ + NODE_TYPE* next2222 = node2222->PTR_NAME;\ + ulint fold2222 = FOLD_FUNC(node2222);\ +\ + HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE),\ + fold2222, node2222);\ +\ + node2222 = next2222;\ + }\ + }\ +} while (0) + + /**************************************************************** Gets the mutex index for a fold value in a hash table. */ UNIV_INLINE diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 3dda3a7cca8..6b863e32183 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -595,6 +595,15 @@ ibool lock_validate(void); /*===============*/ /* out: TRUE if ok */ +/************************************************************************* +Return approximate number or record locks (bits set in the bitmap) for +this transaction. Since delete-marked records ma ybe removed, the +record count will not be precise. */ + +ulint +lock_number_of_rows_locked( +/*=======================*/ + trx_t* trx); /* in: transaction */ /* The lock system */ extern lock_sys_t* lock_sys; diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index e2f8be98b01..f9342e962f2 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -311,6 +311,17 @@ mem_heap_strdupl( const char* str, /* in: string to be copied */ ulint len); /* in: length of str, in bytes */ +/************************************************************************** +Concatenate two strings and return the result, using a memory heap. */ + +char* +mem_heap_strcat( +/*============*/ + /* out, own: the result */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* s1, /* in: string 1 */ + const char* s2); /* in: string 2 */ + #ifdef MEM_PERIODIC_CHECK /********************************************************************** Goes through the list of all allocated mem blocks, checks their magic diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index 2f651b40319..b33eeaceb1c 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -175,19 +175,6 @@ page_rec_is_comp( /* out: nonzero if in compact format */ const rec_t* rec) /* in: record */ { -#ifdef UNIV_RELEASE_NOT_YET_STABLE - if (UNIV_UNLIKELY((ulint)rec < (ulint)(buf_pool->frame_zero)) - || UNIV_UNLIKELY((ulint)rec >= (ulint)(buf_pool->high_end))) { - - ut_print_timestamp(stderr); - fprintf(stderr, -"InnoDB: Error: trying to read a stray page rec %p\n" -"InnoDB: buf pool start is at %p, end at %p\n", - rec, buf_pool->frame_zero, - buf_pool->high_end); - ut_error; - } -#endif return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE))); } diff --git a/storage/innobase/include/pars0grm.h b/storage/innobase/include/pars0grm.h index e35fcf47692..996fc37f13b 100644 --- a/storage/innobase/include/pars0grm.h +++ b/storage/innobase/include/pars0grm.h @@ -32,177 +32,187 @@ PARS_INT_LIT = 258, PARS_FLOAT_LIT = 259, PARS_STR_LIT = 260, - PARS_NULL_LIT = 261, - PARS_ID_TOKEN = 262, - PARS_AND_TOKEN = 263, - PARS_OR_TOKEN = 264, - PARS_NOT_TOKEN = 265, - PARS_GE_TOKEN = 266, - PARS_LE_TOKEN = 267, - PARS_NE_TOKEN = 268, - PARS_PROCEDURE_TOKEN = 269, - PARS_IN_TOKEN = 270, - PARS_OUT_TOKEN = 271, - PARS_BINARY_TOKEN = 272, - PARS_BLOB_TOKEN = 273, - PARS_INT_TOKEN = 274, - PARS_INTEGER_TOKEN = 275, - PARS_FLOAT_TOKEN = 276, - PARS_CHAR_TOKEN = 277, - PARS_IS_TOKEN = 278, - PARS_BEGIN_TOKEN = 279, - PARS_END_TOKEN = 280, - PARS_IF_TOKEN = 281, - PARS_THEN_TOKEN = 282, - PARS_ELSE_TOKEN = 283, - PARS_ELSIF_TOKEN = 284, - PARS_LOOP_TOKEN = 285, - PARS_WHILE_TOKEN = 286, - PARS_RETURN_TOKEN = 287, - PARS_SELECT_TOKEN = 288, - PARS_SUM_TOKEN = 289, - PARS_COUNT_TOKEN = 290, - PARS_DISTINCT_TOKEN = 291, - PARS_FROM_TOKEN = 292, - PARS_WHERE_TOKEN = 293, - PARS_FOR_TOKEN = 294, - PARS_DDOT_TOKEN = 295, - PARS_CONSISTENT_TOKEN = 296, - PARS_READ_TOKEN = 297, - PARS_ORDER_TOKEN = 298, - PARS_BY_TOKEN = 299, - PARS_ASC_TOKEN = 300, - PARS_DESC_TOKEN = 301, - PARS_INSERT_TOKEN = 302, - PARS_INTO_TOKEN = 303, - PARS_VALUES_TOKEN = 304, - PARS_UPDATE_TOKEN = 305, - PARS_SET_TOKEN = 306, - PARS_DELETE_TOKEN = 307, - PARS_CURRENT_TOKEN = 308, - PARS_OF_TOKEN = 309, - PARS_CREATE_TOKEN = 310, - PARS_TABLE_TOKEN = 311, - PARS_INDEX_TOKEN = 312, - PARS_UNIQUE_TOKEN = 313, - PARS_CLUSTERED_TOKEN = 314, - PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315, - PARS_ON_TOKEN = 316, - PARS_ASSIGN_TOKEN = 317, - PARS_DECLARE_TOKEN = 318, - PARS_CURSOR_TOKEN = 319, - PARS_SQL_TOKEN = 320, - PARS_OPEN_TOKEN = 321, - PARS_FETCH_TOKEN = 322, - PARS_CLOSE_TOKEN = 323, - PARS_NOTFOUND_TOKEN = 324, - PARS_TO_CHAR_TOKEN = 325, - PARS_TO_NUMBER_TOKEN = 326, - PARS_TO_BINARY_TOKEN = 327, - PARS_BINARY_TO_NUMBER_TOKEN = 328, - PARS_SUBSTR_TOKEN = 329, - PARS_REPLSTR_TOKEN = 330, - PARS_CONCAT_TOKEN = 331, - PARS_INSTR_TOKEN = 332, - PARS_LENGTH_TOKEN = 333, - PARS_SYSDATE_TOKEN = 334, - PARS_PRINTF_TOKEN = 335, - PARS_ASSERT_TOKEN = 336, - PARS_RND_TOKEN = 337, - PARS_RND_STR_TOKEN = 338, - PARS_ROW_PRINTF_TOKEN = 339, - PARS_COMMIT_TOKEN = 340, - PARS_ROLLBACK_TOKEN = 341, - PARS_WORK_TOKEN = 342, - NEG = 343 + PARS_FIXBINARY_LIT = 261, + PARS_BLOB_LIT = 262, + PARS_NULL_LIT = 263, + PARS_ID_TOKEN = 264, + PARS_AND_TOKEN = 265, + PARS_OR_TOKEN = 266, + PARS_NOT_TOKEN = 267, + PARS_GE_TOKEN = 268, + PARS_LE_TOKEN = 269, + PARS_NE_TOKEN = 270, + PARS_PROCEDURE_TOKEN = 271, + PARS_IN_TOKEN = 272, + PARS_OUT_TOKEN = 273, + PARS_BINARY_TOKEN = 274, + PARS_BLOB_TOKEN = 275, + PARS_INT_TOKEN = 276, + PARS_INTEGER_TOKEN = 277, + PARS_FLOAT_TOKEN = 278, + PARS_CHAR_TOKEN = 279, + PARS_IS_TOKEN = 280, + PARS_BEGIN_TOKEN = 281, + PARS_END_TOKEN = 282, + PARS_IF_TOKEN = 283, + PARS_THEN_TOKEN = 284, + PARS_ELSE_TOKEN = 285, + PARS_ELSIF_TOKEN = 286, + PARS_LOOP_TOKEN = 287, + PARS_WHILE_TOKEN = 288, + PARS_RETURN_TOKEN = 289, + PARS_SELECT_TOKEN = 290, + PARS_SUM_TOKEN = 291, + PARS_COUNT_TOKEN = 292, + PARS_DISTINCT_TOKEN = 293, + PARS_FROM_TOKEN = 294, + PARS_WHERE_TOKEN = 295, + PARS_FOR_TOKEN = 296, + PARS_DDOT_TOKEN = 297, + PARS_CONSISTENT_TOKEN = 298, + PARS_READ_TOKEN = 299, + PARS_ORDER_TOKEN = 300, + PARS_BY_TOKEN = 301, + PARS_ASC_TOKEN = 302, + PARS_DESC_TOKEN = 303, + PARS_INSERT_TOKEN = 304, + PARS_INTO_TOKEN = 305, + PARS_VALUES_TOKEN = 306, + PARS_UPDATE_TOKEN = 307, + PARS_SET_TOKEN = 308, + PARS_DELETE_TOKEN = 309, + PARS_CURRENT_TOKEN = 310, + PARS_OF_TOKEN = 311, + PARS_CREATE_TOKEN = 312, + PARS_TABLE_TOKEN = 313, + PARS_INDEX_TOKEN = 314, + PARS_UNIQUE_TOKEN = 315, + PARS_CLUSTERED_TOKEN = 316, + PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317, + PARS_ON_TOKEN = 318, + PARS_ASSIGN_TOKEN = 319, + PARS_DECLARE_TOKEN = 320, + PARS_CURSOR_TOKEN = 321, + PARS_SQL_TOKEN = 322, + PARS_OPEN_TOKEN = 323, + PARS_FETCH_TOKEN = 324, + PARS_CLOSE_TOKEN = 325, + PARS_NOTFOUND_TOKEN = 326, + PARS_TO_CHAR_TOKEN = 327, + PARS_TO_NUMBER_TOKEN = 328, + PARS_TO_BINARY_TOKEN = 329, + PARS_BINARY_TO_NUMBER_TOKEN = 330, + PARS_SUBSTR_TOKEN = 331, + PARS_REPLSTR_TOKEN = 332, + PARS_CONCAT_TOKEN = 333, + PARS_INSTR_TOKEN = 334, + PARS_LENGTH_TOKEN = 335, + PARS_SYSDATE_TOKEN = 336, + PARS_PRINTF_TOKEN = 337, + PARS_ASSERT_TOKEN = 338, + PARS_RND_TOKEN = 339, + PARS_RND_STR_TOKEN = 340, + PARS_ROW_PRINTF_TOKEN = 341, + PARS_COMMIT_TOKEN = 342, + PARS_ROLLBACK_TOKEN = 343, + PARS_WORK_TOKEN = 344, + PARS_UNSIGNED_TOKEN = 345, + PARS_EXIT_TOKEN = 346, + PARS_FUNCTION_TOKEN = 347, + NEG = 348 }; #endif #define PARS_INT_LIT 258 #define PARS_FLOAT_LIT 259 #define PARS_STR_LIT 260 -#define PARS_NULL_LIT 261 -#define PARS_ID_TOKEN 262 -#define PARS_AND_TOKEN 263 -#define PARS_OR_TOKEN 264 -#define PARS_NOT_TOKEN 265 -#define PARS_GE_TOKEN 266 -#define PARS_LE_TOKEN 267 -#define PARS_NE_TOKEN 268 -#define PARS_PROCEDURE_TOKEN 269 -#define PARS_IN_TOKEN 270 -#define PARS_OUT_TOKEN 271 -#define PARS_BINARY_TOKEN 272 -#define PARS_BLOB_TOKEN 273 -#define PARS_INT_TOKEN 274 -#define PARS_INTEGER_TOKEN 275 -#define PARS_FLOAT_TOKEN 276 -#define PARS_CHAR_TOKEN 277 -#define PARS_IS_TOKEN 278 -#define PARS_BEGIN_TOKEN 279 -#define PARS_END_TOKEN 280 -#define PARS_IF_TOKEN 281 -#define PARS_THEN_TOKEN 282 -#define PARS_ELSE_TOKEN 283 -#define PARS_ELSIF_TOKEN 284 -#define PARS_LOOP_TOKEN 285 -#define PARS_WHILE_TOKEN 286 -#define PARS_RETURN_TOKEN 287 -#define PARS_SELECT_TOKEN 288 -#define PARS_SUM_TOKEN 289 -#define PARS_COUNT_TOKEN 290 -#define PARS_DISTINCT_TOKEN 291 -#define PARS_FROM_TOKEN 292 -#define PARS_WHERE_TOKEN 293 -#define PARS_FOR_TOKEN 294 -#define PARS_DDOT_TOKEN 295 -#define PARS_CONSISTENT_TOKEN 296 -#define PARS_READ_TOKEN 297 -#define PARS_ORDER_TOKEN 298 -#define PARS_BY_TOKEN 299 -#define PARS_ASC_TOKEN 300 -#define PARS_DESC_TOKEN 301 -#define PARS_INSERT_TOKEN 302 -#define PARS_INTO_TOKEN 303 -#define PARS_VALUES_TOKEN 304 -#define PARS_UPDATE_TOKEN 305 -#define PARS_SET_TOKEN 306 -#define PARS_DELETE_TOKEN 307 -#define PARS_CURRENT_TOKEN 308 -#define PARS_OF_TOKEN 309 -#define PARS_CREATE_TOKEN 310 -#define PARS_TABLE_TOKEN 311 -#define PARS_INDEX_TOKEN 312 -#define PARS_UNIQUE_TOKEN 313 -#define PARS_CLUSTERED_TOKEN 314 -#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315 -#define PARS_ON_TOKEN 316 -#define PARS_ASSIGN_TOKEN 317 -#define PARS_DECLARE_TOKEN 318 -#define PARS_CURSOR_TOKEN 319 -#define PARS_SQL_TOKEN 320 -#define PARS_OPEN_TOKEN 321 -#define PARS_FETCH_TOKEN 322 -#define PARS_CLOSE_TOKEN 323 -#define PARS_NOTFOUND_TOKEN 324 -#define PARS_TO_CHAR_TOKEN 325 -#define PARS_TO_NUMBER_TOKEN 326 -#define PARS_TO_BINARY_TOKEN 327 -#define PARS_BINARY_TO_NUMBER_TOKEN 328 -#define PARS_SUBSTR_TOKEN 329 -#define PARS_REPLSTR_TOKEN 330 -#define PARS_CONCAT_TOKEN 331 -#define PARS_INSTR_TOKEN 332 -#define PARS_LENGTH_TOKEN 333 -#define PARS_SYSDATE_TOKEN 334 -#define PARS_PRINTF_TOKEN 335 -#define PARS_ASSERT_TOKEN 336 -#define PARS_RND_TOKEN 337 -#define PARS_RND_STR_TOKEN 338 -#define PARS_ROW_PRINTF_TOKEN 339 -#define PARS_COMMIT_TOKEN 340 -#define PARS_ROLLBACK_TOKEN 341 -#define PARS_WORK_TOKEN 342 -#define NEG 343 +#define PARS_FIXBINARY_LIT 261 +#define PARS_BLOB_LIT 262 +#define PARS_NULL_LIT 263 +#define PARS_ID_TOKEN 264 +#define PARS_AND_TOKEN 265 +#define PARS_OR_TOKEN 266 +#define PARS_NOT_TOKEN 267 +#define PARS_GE_TOKEN 268 +#define PARS_LE_TOKEN 269 +#define PARS_NE_TOKEN 270 +#define PARS_PROCEDURE_TOKEN 271 +#define PARS_IN_TOKEN 272 +#define PARS_OUT_TOKEN 273 +#define PARS_BINARY_TOKEN 274 +#define PARS_BLOB_TOKEN 275 +#define PARS_INT_TOKEN 276 +#define PARS_INTEGER_TOKEN 277 +#define PARS_FLOAT_TOKEN 278 +#define PARS_CHAR_TOKEN 279 +#define PARS_IS_TOKEN 280 +#define PARS_BEGIN_TOKEN 281 +#define PARS_END_TOKEN 282 +#define PARS_IF_TOKEN 283 +#define PARS_THEN_TOKEN 284 +#define PARS_ELSE_TOKEN 285 +#define PARS_ELSIF_TOKEN 286 +#define PARS_LOOP_TOKEN 287 +#define PARS_WHILE_TOKEN 288 +#define PARS_RETURN_TOKEN 289 +#define PARS_SELECT_TOKEN 290 +#define PARS_SUM_TOKEN 291 +#define PARS_COUNT_TOKEN 292 +#define PARS_DISTINCT_TOKEN 293 +#define PARS_FROM_TOKEN 294 +#define PARS_WHERE_TOKEN 295 +#define PARS_FOR_TOKEN 296 +#define PARS_DDOT_TOKEN 297 +#define PARS_CONSISTENT_TOKEN 298 +#define PARS_READ_TOKEN 299 +#define PARS_ORDER_TOKEN 300 +#define PARS_BY_TOKEN 301 +#define PARS_ASC_TOKEN 302 +#define PARS_DESC_TOKEN 303 +#define PARS_INSERT_TOKEN 304 +#define PARS_INTO_TOKEN 305 +#define PARS_VALUES_TOKEN 306 +#define PARS_UPDATE_TOKEN 307 +#define PARS_SET_TOKEN 308 +#define PARS_DELETE_TOKEN 309 +#define PARS_CURRENT_TOKEN 310 +#define PARS_OF_TOKEN 311 +#define PARS_CREATE_TOKEN 312 +#define PARS_TABLE_TOKEN 313 +#define PARS_INDEX_TOKEN 314 +#define PARS_UNIQUE_TOKEN 315 +#define PARS_CLUSTERED_TOKEN 316 +#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317 +#define PARS_ON_TOKEN 318 +#define PARS_ASSIGN_TOKEN 319 +#define PARS_DECLARE_TOKEN 320 +#define PARS_CURSOR_TOKEN 321 +#define PARS_SQL_TOKEN 322 +#define PARS_OPEN_TOKEN 323 +#define PARS_FETCH_TOKEN 324 +#define PARS_CLOSE_TOKEN 325 +#define PARS_NOTFOUND_TOKEN 326 +#define PARS_TO_CHAR_TOKEN 327 +#define PARS_TO_NUMBER_TOKEN 328 +#define PARS_TO_BINARY_TOKEN 329 +#define PARS_BINARY_TO_NUMBER_TOKEN 330 +#define PARS_SUBSTR_TOKEN 331 +#define PARS_REPLSTR_TOKEN 332 +#define PARS_CONCAT_TOKEN 333 +#define PARS_INSTR_TOKEN 334 +#define PARS_LENGTH_TOKEN 335 +#define PARS_SYSDATE_TOKEN 336 +#define PARS_PRINTF_TOKEN 337 +#define PARS_ASSERT_TOKEN 338 +#define PARS_RND_TOKEN 339 +#define PARS_RND_STR_TOKEN 340 +#define PARS_ROW_PRINTF_TOKEN 341 +#define PARS_COMMIT_TOKEN 342 +#define PARS_ROLLBACK_TOKEN 343 +#define PARS_WORK_TOKEN 344 +#define PARS_UNSIGNED_TOKEN 345 +#define PARS_EXIT_TOKEN 346 +#define PARS_FUNCTION_TOKEN 347 +#define NEG 348 diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h index 2ae2d6cff74..68b8ae41cc0 100644 --- a/storage/innobase/include/pars0pars.h +++ b/storage/innobase/include/pars0pars.h @@ -15,6 +15,13 @@ Created 11/19/1996 Heikki Tuuri #include "pars0types.h" #include "row0types.h" #include "trx0types.h" +#include "ut0vec.h" + +/* Type of the user functions. The first argument is always InnoDB-supplied +and varies in type, while 'user_arg' is a user-supplied argument. The +meaning of the return type also varies. See the individual use cases, e.g. +the FETCH statement, for details on them. */ +typedef void* (*pars_user_func_cb_t)(void* arg, void* user_arg); extern int yydebug; @@ -77,6 +84,7 @@ que_t* pars_sql( /*=====*/ /* out, own: the query graph */ + pars_info_t* info, /* in: extra information, or NULL */ const char* str); /* in: SQL string */ /***************************************************************** Retrieves characters to the lexical analyzer. */ @@ -157,6 +165,15 @@ pars_cursor_declaration( table */ sel_node_t* select_node); /* in: select node */ /************************************************************************* +Parses a function declaration. */ + +que_node_t* +pars_function_declaration( +/*======================*/ + /* out: sym_node */ + sym_node_t* sym_node); /* in: function id node in the symbol + table */ +/************************************************************************* Parses a select statement. */ sel_node_t* @@ -269,6 +286,13 @@ pars_while_statement( que_node_t* cond, /* in: while-condition */ que_node_t* stat_list); /* in: statement list */ /************************************************************************* +Parses an exit statement. */ + +exit_node_t* +pars_exit_statement(void); +/*=====================*/ + /* out: exit statement node */ +/************************************************************************* Parses a return-statement. */ return_node_t* @@ -294,14 +318,16 @@ pars_assignment_statement( sym_node_t* var, /* in: variable to assign */ que_node_t* val); /* in: value to assign */ /************************************************************************* -Parses a fetch statement. */ +Parses a fetch statement. into_list or user_func (but not both) must be +non-NULL. */ fetch_node_t* pars_fetch_statement( /*=================*/ /* out: fetch statement node */ sym_node_t* cursor, /* in: cursor node */ - sym_node_t* into_list); /* in: variables to set */ + sym_node_t* into_list, /* in: variables to set, or NULL */ + sym_node_t* user_func); /* in: user function name, or NULL */ /************************************************************************* Parses an open or close cursor statement. */ @@ -345,6 +371,8 @@ pars_column_def( pars_res_word_t* type, /* in: data type */ sym_node_t* len, /* in: length of column, or NULL */ + void* is_unsigned, /* in: if not NULL, column + is of type UNSIGNED. */ void* is_not_null); /* in: if not NULL, column is of type NOT NULL. */ /************************************************************************* @@ -418,6 +446,142 @@ pars_complete_graph_for_exec( trx_t* trx, /* in: transaction handle */ mem_heap_t* heap); /* in: memory heap from which allocated */ +/******************************************************************** +Create parser info struct.*/ + +pars_info_t* +pars_info_create(void); +/*==================*/ + /* out, own: info struct */ + +/******************************************************************** +Free info struct and everything it contains.*/ + +void +pars_info_free( +/*===========*/ + pars_info_t* info); /* in: info struct */ + +/******************************************************************** +Add bound literal. */ + +void +pars_info_add_literal( +/*==================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const void* address, /* in: address */ + ulint length, /* in: length of data */ + ulint type, /* in: type, e.g. DATA_FIXBINARY */ + ulint prtype); /* in: precise type, e.g. + DATA_UNSIGNED */ + +/******************************************************************** +Equivalent to pars_info_add_literal(info, name, str, strlen(str), +DATA_VARCHAR, DATA_ENGLISH). */ + +void +pars_info_add_str_literal( +/*======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const char* str); /* in: string */ + +/******************************************************************** +Equivalent to: + +char buf[4]; +mach_write_to_4(buf, val); +pars_info_add_literal(info, name, buf, 4, DATA_INT, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_int4_literal( +/*=======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + lint val); /* in: value */ + +/******************************************************************** +Equivalent to: + +char buf[8]; +mach_write_to_8(buf, val); +pars_info_add_literal(info, name, buf, 8, DATA_BINARY, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_dulint_literal( +/*=========================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + dulint val); /* in: value */ +/******************************************************************** +Add user function. */ + +void +pars_info_add_function( +/*===================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: function name */ + pars_user_func_cb_t func, /* in: function address */ + void* arg); /* in: user-supplied argument */ + +/******************************************************************** +Get user function with the given name.*/ + +pars_user_func_t* +pars_info_get_user_func( +/*====================*/ + /* out: user func, or NULL if not + found */ + pars_info_t* info, /* in: info struct */ + const char* name); /* in: function name to find*/ + +/******************************************************************** +Get bound literal with the given name.*/ + +pars_bound_lit_t* +pars_info_get_bound_lit( +/*====================*/ + /* out: bound literal, or NULL if + not found */ + pars_info_t* info, /* in: info struct */ + const char* name); /* in: bound literal name to find */ + + +/* Extra information supplied for pars_sql(). */ +struct pars_info_struct { + mem_heap_t* heap; /* our own memory heap */ + + ib_vector_t* funcs; /* user functions, or NUll + (pars_user_func_t*) */ + ib_vector_t* bound_lits; /* bound literals, or NULL + (pars_bound_lit_t*) */ + + ibool graph_owns_us; /* if TRUE (which is the default), + que_graph_free() will free us */ +}; + +/* User-supplied function and argument. */ +struct pars_user_func_struct { + const char* name; /* function name */ + pars_user_func_cb_t func; /* function address */ + void* arg; /* user-supplied argument */ +}; + +/* Bound literal. */ +struct pars_bound_lit_struct { + const char* name; /* name */ + const void* address; /* address */ + ulint length; /* length of data */ + ulint type; /* type, e.g. DATA_FIXBINARY */ + ulint prtype; /* precise type, e.g. DATA_UNSIGNED */ +}; /* Struct used to denote a reserved word in a parsing tree */ struct pars_res_word_struct{ @@ -498,6 +662,11 @@ struct for_node_struct{ que_node_t* stat_list; /* statement list */ }; +/* exit statement node */ +struct exit_node_struct{ + que_common_t common; /* type: QUE_NODE_EXIT */ +}; + /* return-statement node */ struct return_node_struct{ que_common_t common; /* type: QUE_NODE_RETURN */ diff --git a/storage/innobase/include/pars0sym.h b/storage/innobase/include/pars0sym.h index a10d70d48b6..14f762d5b7a 100644 --- a/storage/innobase/include/pars0sym.h +++ b/storage/innobase/include/pars0sym.h @@ -54,6 +54,16 @@ sym_tab_add_str_lit( it */ ulint len); /* in: string length */ /********************************************************************** +Add a bound literal to a symbol table. */ + +sym_node_t* +sym_tab_add_bound_lit( +/*==================*/ + /* out: symbol table node */ + sym_tab_t* sym_tab, /* in: symbol table */ + const char* name, /* in: name of bound literal */ + ulint* lit_type); /* out: type of literal (PARS_*_LIT) */ +/********************************************************************** Adds an SQL null literal to a symbol table. */ sym_node_t* @@ -83,6 +93,19 @@ struct sym_node_struct{ been allocated from dynamic memory and it should be freed when the symbol table is discarded */ + /* 'alias' and 'indirection' are almost the same, but not quite. + 'alias' always points to the primary instance of the variable, while + 'indirection' does the same only if we should use the primary + instance's values for the node's data. This is usually the case, but + when initializing a cursor (e.g., "DECLARE CURSOR c IS SELECT * FROM + t WHERE id = x;"), we copy the values from the primary instance to + the cursor's instance so that they are fixed for the duration of the + cursor, and set 'indirection' to NULL. If we did not, the value of + 'x' could change between fetches and things would break horribly. + + TODO: It would be cleaner to make 'indirection' a boolean field and + always use 'alias' to refer to the primary node. */ + sym_node_t* indirection; /* pointer to another symbol table node which contains @@ -158,6 +181,7 @@ struct sym_tab_struct{ /* position of the next character in sql_string to give to the lexical analyzer */ + pars_info_t* info; /* extra information, or NULL */ sym_node_list_t sym_list; /* list of symbol nodes in the symbol table */ @@ -180,6 +204,7 @@ struct sym_tab_struct{ #define SYM_CURSOR 96 /* named cursor */ #define SYM_PROCEDURE_NAME 97 /* stored procedure name */ #define SYM_INDEX 98 /* database index name */ +#define SYM_FUNCTION 99 /* user function name */ #ifndef UNIV_NONINL #include "pars0sym.ic" diff --git a/storage/innobase/include/pars0types.h b/storage/innobase/include/pars0types.h index cf62617e066..6fcfaf23024 100644 --- a/storage/innobase/include/pars0types.h +++ b/storage/innobase/include/pars0types.h @@ -9,6 +9,9 @@ Created 1/11/1998 Heikki Tuuri #ifndef pars0types_h #define pars0types_h +typedef struct pars_info_struct pars_info_t; +typedef struct pars_user_func_struct pars_user_func_t; +typedef struct pars_bound_lit_struct pars_bound_lit_t; typedef struct sym_node_struct sym_node_t; typedef struct sym_tab_struct sym_tab_t; typedef struct pars_res_word_struct pars_res_word_t; @@ -19,6 +22,7 @@ typedef struct elsif_node_struct elsif_node_t; typedef struct if_node_struct if_node_t; typedef struct while_node_struct while_node_t; typedef struct for_node_struct for_node_t; +typedef struct exit_node_struct exit_node_t; typedef struct return_node_struct return_node_t; typedef struct assign_node_struct assign_node_t; typedef struct col_assign_node_struct col_assign_node_t; diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index 4e31e2db4b7..c3314a1167b 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -277,6 +277,15 @@ que_node_get_parent( /*================*/ /* out: parent node or NULL */ que_node_t* node); /* in: node */ +/******************************************************************** +Get the first containing loop node (e.g. while_node_t or for_node_t) for the +given node, or NULL if the node is not within a loop. */ + +que_node_t* +que_node_get_containing_loop_node( +/*==============================*/ + /* out: containing loop node, or NULL. */ + que_node_t* node); /* in: node */ /************************************************************************* Catenates a query graph node to a list of them, possible empty list. */ UNIV_INLINE @@ -322,8 +331,15 @@ void que_node_print_info( /*================*/ que_node_t* node); /* in: query graph node */ +/************************************************************************* +Evaluate the given SQL */ - +ulint +que_eval_sql( +/*=========*/ + pars_info_t* info, /* out: error code or DB_SUCCESS */ + const char* sql, /* in: info struct, or NULL */ + trx_t* trx); /* in: trx */ /* Query graph query thread node: the fields are protected by the kernel mutex with the exceptions named below */ @@ -388,6 +404,7 @@ struct que_fork_struct{ sym_tab_t* sym_tab; /* symbol table of the query, generated by the parser, or NULL if the graph was created 'by hand' */ + pars_info_t* info; /* in: info struct, or NULL */ /* The following cur_... fields are relevant only in a select graph */ ulint cur_end; /* QUE_CUR_NOT_DEFINED, QUE_CUR_START, @@ -469,6 +486,7 @@ struct que_fork_struct{ #define QUE_NODE_ROW_PRINTF 29 #define QUE_NODE_ELSIF 30 #define QUE_NODE_CALL 31 +#define QUE_NODE_EXIT 32 /* Query thread states */ #define QUE_THR_RUNNING 1 diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 8ff8a0476a1..48fb7432b54 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -244,7 +244,8 @@ row_update_for_mysql( row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL handle */ /************************************************************************* -This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +This can only be used when srv_locks_unsafe_for_binlog is TRUE or +session is using a READ COMMITTED isolation level. Before calling this function we must use trx_reset_new_rec_lock_info() and trx_register_new_rec_lock() to store the information which new record locks really were set. This function removes a newly set lock under prebuilt->pcur, diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h index c9f2389d3dd..70b08d82994 100644 --- a/storage/innobase/include/row0sel.h +++ b/storage/innobase/include/row0sel.h @@ -78,6 +78,26 @@ fetch_step( /*=======*/ /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ +/******************************************************************** +Sample callback function for fetch that prints each row.*/ + +void* +row_fetch_print( +/*============*/ + /* out: always returns non-NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg); /* in: not used */ +/******************************************************************** +Callback function for fetch that stores an unsigned 4 byte integer to the +location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length += 4. */ + +void* +row_fetch_store_uint4( +/*==================*/ + /* out: always returns NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg); /* in: data pointer */ /*************************************************************** Prints a row in a select result. */ @@ -204,8 +224,6 @@ struct plan_struct{ ulint first_prefetched;/* index of the first cached row in select buffer arrays for each column */ ibool no_prefetch; /* no prefetch for this table */ - ibool mixed_index; /* TRUE if index is a clustered index - in a mixed cluster */ sym_node_list_t columns; /* symbol table nodes for the columns to retrieve from the table */ UT_LIST_BASE_NODE_T(func_node_t) @@ -311,6 +329,20 @@ struct fetch_node_struct{ que_common_t common; /* type: QUE_NODE_FETCH */ sel_node_t* cursor_def; /* cursor definition */ sym_node_t* into_list; /* variables to set */ + + pars_user_func_t* + func; /* User callback function or NULL. + The first argument to the function + is a sel_node_t*, containing the + results of the SELECT operation for + one row. If the function returns + NULL, it is not interested in + further rows and the cursor is + modified so (cursor % NOTFOUND) is + true. If it returns not-NULL, + continue normally. See + row_fetch_print() for an example + (and a useful debugging tool). */ }; /* Open or close cursor statement node */ diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 41cce851d87..efbc6d6facf 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -185,6 +185,10 @@ row_upd_index_replace_new_col_vals_index_pos( upd_t* update, /* in: an update vector built for the index so that the field number in an upd_field is the index position */ + ibool order_only, + /* in: if TRUE, limit the replacement to + ordering fields of index; note that this + does not work for non-clustered indexes. */ mem_heap_t* heap); /* in: memory heap to which we allocate and copy the new values, set this as NULL if you do not want allocation */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 4278d602675..838b5b546c7 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -544,7 +544,9 @@ struct trx_struct{ the transaction; note that it is also in the lock list trx_locks */ dict_index_t* new_rec_locks[2];/* these are normally NULL; if - srv_locks_unsafe_for_binlog is TRUE, + srv_locks_unsafe_for_binlog is TRUE + or session is using READ COMMITTED + isolation level, in a cursor search, if we set a new record lock on an index, this is set to point to the index; this is diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index de57f6f07b8..5b294ae0769 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -82,10 +82,6 @@ memory is read outside the allocated blocks. */ /* Make a non-inline debug version */ -/* You can remove this define when the release is stable. This define adds -some consistency checks to code. They use a little CPU time. */ -#define UNIV_RELEASE_NOT_YET_STABLE - /* #define UNIV_DEBUG #define UNIV_MEM_DEBUG @@ -128,7 +124,7 @@ by one. */ #ifdef __WIN__ #define UNIV_INLINE __inline #else -#define UNIV_INLINE static inline +#define UNIV_INLINE static __inline__ #endif #else @@ -178,6 +174,16 @@ management to ensure correct alignment for doubles etc. */ /* Note that inside MySQL 'byte' is defined as char on Linux! */ #define byte unsigned char +/* Define an unsigned integer type that is exactly 32 bits. */ + +#if SIZEOF_INT == 4 +typedef unsigned int ib_uint32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long ib_uint32_t; +#else +#error "Neither int or long is 4 bytes" +#endif + /* Another basic type we use is unsigned long integer which should be equal to the word size of the machine, that is on a 32-bit platform 32 bits, and on a 64-bit platform 64 bits. We also give the printf format for the type as a @@ -205,9 +211,6 @@ typedef longlong ib_longlong; #endif #endif -/* The following type should be at least a 64-bit floating point number */ -typedef double utfloat; - /* The 'undefined' value for a ulint */ #define ULINT_UNDEFINED ((ulint)(-1)) diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index 6e4a265349f..90c16f4fad5 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -181,6 +181,30 @@ ut_memcpyq( const char* src, /* in: string to be quoted */ ulint len); /* in: length of src */ +/************************************************************************** +Return the number of times s2 occurs in s1. Overlapping instances of s2 +are only counted once. */ + +ulint +ut_strcount( +/*========*/ + /* out: the number of times s2 occurs in s1 */ + const char* s1, /* in: string to search in */ + const char* s2); /* in: string to search for */ + +/************************************************************************** +Replace every occurrence of s1 in str with s2. Overlapping instances of s1 +are only replaced once. */ + +char * +ut_strreplace( +/*==========*/ + /* out, own: modified string, must be + freed with mem_free() */ + const char* str, /* in: string to operate on */ + const char* s1, /* in: string to replace */ + const char* s2); /* in: string to replace s1 with */ + #ifndef UNIV_NONINL #include "ut0mem.ic" #endif diff --git a/storage/innobase/include/ut0vec.h b/storage/innobase/include/ut0vec.h new file mode 100644 index 00000000000..e0cc4dfb009 --- /dev/null +++ b/storage/innobase/include/ut0vec.h @@ -0,0 +1,73 @@ +#ifndef IB_VECTOR_H +#define IB_VECTOR_H + +#include "univ.i" +#include "mem0mem.h" + +typedef struct ib_vector_struct ib_vector_t; + +/* An automatically resizing vector datatype with the following properties: + + -Contains void* items. + + -The items are owned by the caller. + + -All memory allocation is done through a heap owned by the caller, who is + responsible for freeing it when done with the vector. + + -When the vector is resized, the old memory area is left allocated since it + uses the same heap as the new memory area, so this is best used for + relatively small or short-lived uses. +*/ + +/******************************************************************** +Create a new vector with the given initial size. */ + +ib_vector_t* +ib_vector_create( +/*=============*/ + /* out: vector */ + mem_heap_t* heap, /* in: heap */ + ulint size); /* in: initial size */ + +/******************************************************************** +Push a new element to the vector, increasing its size if necessary. */ + +void +ib_vector_push( +/*===========*/ + ib_vector_t* vec, /* in: vector */ + void* elem); /* in: data element */ + +/******************************************************************** +Get the number of elements in the vector. */ +UNIV_INLINE +ulint +ib_vector_size( +/*===========*/ + /* out: number of elements in vector */ + ib_vector_t* vec); /* in: vector */ + +/******************************************************************** +Get the n'th element. */ +UNIV_INLINE +void* +ib_vector_get( +/*==========*/ + /* out: n'th element */ + ib_vector_t* vec, /* in: vector */ + ulint n); /* in: element index to get */ + +/* See comment at beginning of file. */ +struct ib_vector_struct { + mem_heap_t* heap; /* heap */ + void** data; /* data elements */ + ulint used; /* number of elements currently used */ + ulint total; /* number of elements allocated */ +}; + +#ifndef UNIV_NONINL +#include "ut0vec.ic" +#endif + +#endif diff --git a/storage/innobase/include/ut0vec.ic b/storage/innobase/include/ut0vec.ic new file mode 100644 index 00000000000..417a17d951f --- /dev/null +++ b/storage/innobase/include/ut0vec.ic @@ -0,0 +1,26 @@ +/******************************************************************** +Get number of elements in vector. */ +UNIV_INLINE +ulint +ib_vector_size( +/*===========*/ + /* out: number of elements in vector */ + ib_vector_t* vec) /* in: vector */ +{ + return(vec->used); +} + +/******************************************************************** +Get n'th element. */ +UNIV_INLINE +void* +ib_vector_get( +/*==========*/ + /* out: n'th element */ + ib_vector_t* vec, /* in: vector */ + ulint n) /* in: element index to get */ +{ + ut_a(n < vec->used); + + return(vec->data[n]); +} diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 1152e0c89ea..34e3296c9bc 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -1698,6 +1698,40 @@ lock_sec_rec_some_has_impl_off_kernel( return(row_vers_impl_x_locked_off_kernel(rec, index, offsets)); } +/************************************************************************* +Return approximate number or record locks (bits set in the bitmap) for +this transaction. Since delete-marked records may be removed, the +record count will not be precise. */ + +ulint +lock_number_of_rows_locked( +/*=======================*/ + trx_t* trx) /* in: transaction */ +{ + lock_t* lock; + ulint n_records = 0; + ulint n_bits; + ulint n_bit; + + lock = UT_LIST_GET_FIRST(trx->trx_locks); + + while (lock) { + if (lock_get_type(lock) == LOCK_REC) { + n_bits = lock_rec_get_n_bits(lock); + + for (n_bit = 0; n_bit < n_bits; n_bit++) { + if (lock_rec_get_nth_bit(lock, n_bit)) { + n_records++; + } + } + } + + lock = UT_LIST_GET_NEXT(trx_locks, lock); + } + + return (n_records); +} + /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ /************************************************************************* @@ -2001,7 +2035,8 @@ lock_rec_lock_fast( if (!impl) { lock_rec_create(mode, rec, index, trx); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } @@ -2027,7 +2062,8 @@ lock_rec_lock_fast( if (!lock_rec_get_nth_bit(lock, heap_no)) { lock_rec_set_nth_bit(lock, heap_no); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } @@ -2087,7 +2123,8 @@ lock_rec_lock_slow( err = lock_rec_enqueue_waiting(mode, rec, index, thr); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } else { @@ -2096,7 +2133,8 @@ lock_rec_lock_slow( lock_rec_add_to_queue(LOCK_REC | mode, rec, index, trx); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } @@ -2436,15 +2474,18 @@ lock_rec_inherit_to_gap( lock = lock_rec_get_first(rec); - /* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set + /* If srv_locks_unsafe_for_binlog is TRUE or session is using + READ COMMITTED isolation level, we do not want locks set by an UPDATE or a DELETE to be inherited as gap type locks. But we DO want S-locks set by a consistency constraint to be inherited also then. */ while (lock != NULL) { if (!lock_rec_get_insert_intention(lock) - && !(srv_locks_unsafe_for_binlog - && lock_get_mode(lock) == LOCK_X)) { + && !((srv_locks_unsafe_for_binlog + || lock->trx->isolation_level == + TRX_ISO_READ_COMMITTED) + && lock_get_mode(lock) == LOCK_X)) { lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) | LOCK_GAP, @@ -4320,6 +4361,10 @@ loop: (ulong) ut_dulint_get_low(trx->read_view->up_limit_id)); } + fprintf(file, + "Trx has approximately %lu row locks\n", + (ulong) lock_number_of_rows_locked(trx)); + if (trx->que_state == TRX_QUE_LOCK_WAIT) { fprintf(file, "------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n", @@ -5167,3 +5212,4 @@ lock_clust_rec_read_check_and_lock_alt( } return(ret); } + diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index f210afe6b5d..2457ca76e72 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -897,9 +897,9 @@ recv_parse_or_apply_log_rec_body( ut_ad(!page || ptr); if (index) { dict_table_t* table = index->table; - mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - mem_heap_free(table->heap); + + dict_mem_index_free(index); + dict_mem_table_free(table); } return(ptr); diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index 86d5beb9c80..86c33a22531 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -445,7 +445,7 @@ mem_heap_validate_or_print( && (mem_block_get_len(block) > UNIV_PAGE_SIZE)) { fprintf(stderr, -"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", block, +"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", (void*) block, (ulong) mem_block_get_len(block)); /* error */ diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index 90d3f4fa6b1..5e7c48d3d3d 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -114,6 +114,31 @@ mem_heap_strdup( return(memcpy(mem_heap_alloc(heap, len), str, len)); } +/************************************************************************** +Concatenate two strings and return the result, using a memory heap. */ + +char* +mem_heap_strcat( +/*============*/ + /* out, own: the result */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* s1, /* in: string 1 */ + const char* s2) /* in: string 2 */ +{ + char* s; + ulint s1_len = strlen(s1); + ulint s2_len = strlen(s2); + + s = mem_heap_alloc(heap, s1_len + s2_len + 1); + + memcpy(s, s1, s1_len); + memcpy(s + s1_len, s2, s2_len); + + s[s1_len + s2_len] = '\0'; + + return(s); +} + /******************************************************************* Creates a memory heap block where data can be allocated. */ diff --git a/storage/innobase/os/os0sync.c b/storage/innobase/os/os0sync.c index 706c10ac613..eceedcb66b2 100644 --- a/storage/innobase/os/os0sync.c +++ b/storage/innobase/os/os0sync.c @@ -641,7 +641,7 @@ os_fast_mutex_free( " InnoDB: error: return value %lu when calling\n" "InnoDB: pthread_mutex_destroy().\n", (ulint)ret); fprintf(stderr, -"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex); +"InnoDB: Byte contents of the pthread mutex at %p:\n", (void*) fast_mutex); ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t)); fprintf(stderr, "\n"); } diff --git a/storage/innobase/pars/lexyy.c b/storage/innobase/pars/lexyy.c index d64ecbbfcbc..bbe78db1613 100644 --- a/storage/innobase/pars/lexyy.c +++ b/storage/innobase/pars/lexyy.c @@ -1,7 +1,7 @@ - -#line 3 "lex.yy.c" - #include "univ.i" +#line 2 "_flex_tmp.c" + +#line 4 "_flex_tmp.c" #define YY_INT_ALIGNED short int @@ -356,8 +356,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 109 -#define YY_END_OF_BUFFER 110 +#define YY_NUM_RULES 116 +#define YY_END_OF_BUFFER 117 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -365,48 +365,52 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[370] = +static yyconst flex_int16_t yy_accept[394] = { 0, - 0, 0, 104, 104, 0, 0, 110, 108, 107, 107, - 99, 3, 88, 94, 97, 95, 92, 96, 108, 98, - 1, 108, 93, 91, 89, 90, 102, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 100, 101, 104, 105, 4, - 5, 107, 83, 103, 2, 1, 84, 85, 87, 86, - 82, 82, 82, 82, 82, 82, 40, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 23, 12, 20, 82, 82, 82, 82, 50, 57, - 82, 9, 82, 82, 82, 82, 82, 82, 82, 82, + 0, 0, 111, 111, 0, 0, 0, 0, 117, 115, + 114, 114, 7, 106, 4, 95, 101, 104, 102, 99, + 103, 115, 105, 1, 115, 100, 98, 96, 97, 109, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 107, 108, + 111, 112, 5, 6, 8, 9, 114, 90, 110, 2, + 1, 3, 91, 92, 94, 93, 89, 89, 89, 89, + 89, 89, 44, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 27, + 16, 24, 89, 89, 89, 89, 54, 61, 89, 13, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 104, - 105, 105, 106, 4, 5, 2, 8, 41, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 22, 82, 82, 36, - 82, 82, 82, 16, 82, 82, 10, 82, 82, 82, - 13, 82, 82, 82, 82, 82, 76, 82, 82, 82, - 47, 7, 82, 31, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 15, 19, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 42, 82, 82, 25, 82, 82, 82, 34, 82, 82, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 111, 112, 112, + 113, 5, 6, 8, 9, 2, 12, 45, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 26, 89, 89, 89, + 40, 89, 89, 89, 89, 20, 89, 89, 14, 89, + 89, 89, 17, 89, 89, 89, 89, 89, 80, 89, + 89, 89, 51, 11, 89, 35, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 19, 23, 89, 89, 89, 89, 89, 89, 89, 89, - 82, 82, 44, 82, 27, 82, 6, 60, 82, 82, - 82, 38, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 24, 82, 82, 82, 82, 82, 82, 82, 82, - 81, 82, 21, 82, 62, 82, 82, 82, 82, 32, - 82, 82, 82, 82, 82, 82, 82, 26, 61, 18, - 53, 82, 71, 82, 82, 82, 39, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 52, 82, 82, - 82, 82, 82, 82, 35, 28, 75, 14, 82, 79, - 70, 82, 51, 82, 59, 82, 48, 82, 82, 43, - 82, 72, 82, 74, 82, 82, 29, 82, 82, 82, + 89, 89, 89, 46, 89, 89, 29, 89, 87, 89, + 89, 38, 89, 89, 89, 89, 89, 48, 89, 31, + 89, 10, 64, 89, 89, 89, 42, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 28, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 85, 89, 25, 89, + 66, 89, 89, 89, 89, 36, 89, 89, 89, 89, + 89, 89, 89, 30, 65, 22, 89, 57, 89, 75, + 89, 89, 89, 43, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 56, 89, 89, 89, 89, 89, + 89, 89, 39, 32, 79, 18, 89, 83, 74, 89, + + 55, 89, 63, 89, 52, 89, 89, 89, 47, 89, + 76, 89, 78, 89, 89, 33, 89, 89, 89, 34, + 72, 89, 89, 89, 89, 58, 89, 50, 49, 89, + 89, 89, 53, 62, 89, 89, 89, 21, 89, 89, + 73, 81, 89, 89, 77, 89, 68, 89, 89, 89, + 89, 89, 37, 89, 88, 67, 89, 84, 89, 89, + 89, 86, 89, 59, 89, 89, 15, 89, 70, 69, + 89, 41, 89, 82, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 71, 89, 89, 89, 89, 89, + 89, 60, 0 - 30, 68, 82, 82, 82, 82, 54, 46, 45, 82, - 82, 82, 49, 58, 82, 82, 17, 82, 82, 69, - 77, 82, 82, 73, 82, 64, 82, 82, 82, 82, - 33, 82, 63, 82, 80, 82, 82, 82, 82, 55, - 82, 82, 11, 82, 66, 65, 82, 37, 82, 78, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 67, 82, 82, 82, 82, 82, 82, 56, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -414,17 +418,17 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 1, 1, 1, 4, 1, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 15, 16, 17, - 18, 19, 20, 1, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 30, - 1, 1, 1, 1, 46, 1, 30, 30, 30, 30, + 1, 2, 1, 4, 1, 1, 5, 1, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 17, 18, + 19, 20, 21, 1, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 31, + 1, 1, 1, 1, 47, 1, 31, 31, 31, 31, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 47, 1, 48, 1, 1, 1, 1, 1, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 48, 1, 49, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -441,209 +445,229 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[49] = +static yyconst flex_int32_t yy_meta[50] = { 0, - 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, - 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 1, 1 + 1, 1, 1, 2, 1, 3, 1, 1, 4, 1, + 1, 1, 1, 1, 5, 1, 1, 1, 6, 1, + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 1, 1 } ; -static yyconst flex_int16_t yy_base[376] = +static yyconst flex_int16_t yy_base[403] = { 0, - 0, 0, 390, 389, 391, 390, 394, 399, 47, 49, - 399, 399, 399, 399, 399, 399, 399, 399, 381, 384, - 41, 373, 399, 38, 399, 372, 399, 20, 33, 32, - 46, 29, 44, 0, 46, 49, 42, 60, 351, 65, - 66, 67, 32, 367, 69, 399, 399, 0, 79, 0, - 382, 103, 399, 399, 372, 96, 399, 399, 399, 399, - 0, 361, 70, 357, 349, 347, 0, 360, 77, 80, - 355, 341, 92, 339, 352, 337, 351, 334, 338, 334, - 336, 0, 93, 0, 336, 334, 328, 335, 0, 0, - 341, 341, 324, 87, 98, 339, 93, 88, 330, 104, + 0, 0, 434, 433, 435, 434, 435, 434, 437, 444, + 48, 50, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 423, 426, 41, 415, 444, 38, 444, 414, 444, + 20, 33, 32, 46, 40, 44, 0, 54, 52, 48, + 60, 393, 65, 66, 74, 27, 409, 69, 444, 444, + 0, 97, 0, 424, 0, 425, 111, 444, 444, 413, + 54, 408, 444, 444, 444, 444, 0, 401, 69, 397, + 389, 387, 0, 400, 79, 82, 395, 381, 94, 379, + 392, 377, 391, 385, 373, 377, 373, 375, 375, 0, + 82, 0, 374, 372, 366, 373, 0, 0, 379, 379, - 322, 338, 334, 312, 328, 332, 323, 98, 316, 0, - 122, 131, 399, 0, 348, 338, 0, 0, 326, 321, - 328, 326, 309, 307, 306, 311, 106, 309, 321, 102, - 309, 315, 316, 298, 298, 117, 0, 313, 314, 0, - 301, 308, 118, 122, 305, 295, 304, 297, 294, 302, - 0, 292, 302, 300, 291, 281, 275, 288, 273, 293, - 0, 0, 278, 0, 292, 283, 280, 126, 276, 291, - 270, 272, 277, 277, 269, 272, 267, 0, 0, 279, - 263, 273, 280, 271, 259, 258, 272, 261, 274, 254, - 0, 264, 246, 0, 265, 262, 249, 0, 244, 249, + 362, 89, 98, 377, 93, 95, 368, 106, 360, 376, + 372, 350, 101, 371, 362, 112, 355, 0, 134, 135, + 444, 0, 387, 0, 388, 376, 0, 0, 364, 359, + 366, 364, 347, 345, 344, 349, 106, 347, 359, 93, + 347, 353, 354, 336, 336, 121, 0, 334, 350, 351, + 0, 338, 347, 344, 119, 126, 341, 331, 340, 333, + 330, 338, 0, 328, 338, 336, 327, 317, 311, 324, + 309, 329, 0, 0, 314, 0, 328, 319, 316, 130, + 312, 319, 326, 305, 307, 312, 312, 304, 307, 302, + 0, 0, 314, 298, 308, 315, 306, 294, 293, 307, - 248, 258, 0, 244, 0, 248, 0, 0, 244, 241, - 255, 0, 240, 240, 238, 254, 239, 251, 233, 251, - 246, 0, 241, 241, 227, 226, 226, 240, 239, 238, - 0, 222, 0, 216, 0, 235, 219, 218, 218, 0, - 231, 221, 216, 215, 227, 217, 216, 0, 0, 0, - 0, 209, 0, 223, 219, 205, 0, 219, 220, 203, - 208, 201, 219, 201, 198, 199, 196, 0, 201, 213, - 200, 207, 206, 191, 0, 0, 0, 183, 190, 0, - 0, 187, 0, 186, 0, 200, 0, 201, 188, 0, - 184, 0, 187, 0, 179, 181, 0, 180, 194, 187, + 296, 309, 289, 0, 299, 281, 0, 300, 0, 297, + 284, 0, 283, 278, 283, 282, 292, 0, 278, 0, + 282, 0, 0, 278, 275, 289, 0, 274, 274, 272, + 288, 273, 285, 267, 285, 280, 0, 275, 275, 261, + 260, 273, 259, 273, 272, 271, 0, 255, 0, 249, + 0, 268, 252, 251, 251, 0, 264, 254, 249, 248, + 260, 250, 249, 0, 0, 0, 253, 0, 241, 0, + 255, 251, 237, 0, 251, 252, 235, 240, 233, 251, + 233, 230, 231, 228, 0, 233, 245, 232, 239, 229, + 237, 222, 0, 0, 0, 214, 221, 0, 0, 218, - 0, 0, 190, 193, 175, 190, 0, 0, 0, 171, - 185, 184, 0, 0, 168, 167, 0, 182, 167, 0, - 0, 173, 169, 0, 164, 0, 176, 165, 175, 164, - 0, 151, 0, 171, 0, 155, 149, 155, 146, 0, - 151, 164, 0, 163, 0, 0, 154, 0, 158, 0, - 145, 145, 151, 137, 160, 152, 153, 137, 121, 110, - 0, 122, 129, 120, 117, 113, 105, 0, 399, 160, - 164, 85, 168, 172, 176 + 0, 217, 0, 231, 0, 232, 219, 218, 0, 214, + 0, 217, 0, 209, 211, 0, 210, 224, 217, 0, + 0, 220, 223, 205, 220, 0, 216, 0, 0, 200, + 214, 213, 0, 0, 197, 196, 201, 0, 210, 195, + 0, 0, 201, 197, 0, 192, 0, 204, 204, 192, + 202, 191, 0, 178, 0, 0, 198, 0, 182, 176, + 182, 0, 173, 0, 178, 191, 0, 190, 0, 0, + 181, 0, 185, 0, 172, 172, 178, 164, 187, 175, + 174, 154, 125, 116, 0, 127, 133, 124, 121, 117, + 109, 0, 444, 165, 171, 177, 179, 145, 185, 191, + + 197, 203 } ; -static yyconst flex_int16_t yy_def[376] = +static yyconst flex_int16_t yy_def[403] = { 0, - 369, 1, 370, 370, 371, 371, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 369, 369, 373, 374, 375, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, + 393, 1, 394, 394, 395, 395, 396, 396, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 397, 393, 393, 393, 393, 393, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 393, 393, + 399, 400, 401, 393, 402, 393, 393, 393, 393, 393, + 393, 397, 393, 393, 393, 393, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, - 374, 374, 369, 375, 369, 369, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 399, 400, 400, + 393, 401, 393, 402, 393, 393, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 0, 369, - 369, 369, 369, 369, 369 + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 0, 393, 393, 393, 393, 393, 393, 393, + + 393, 393 } ; -static yyconst flex_int16_t yy_nxt[448] = +static yyconst flex_int16_t yy_nxt[494] = { 0, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 34, 35, 34, - 34, 36, 34, 37, 38, 39, 34, 40, 41, 42, - 43, 44, 45, 34, 34, 34, 46, 47, 52, 52, - 52, 52, 55, 62, 56, 58, 59, 64, 63, 68, - 76, 65, 77, 69, 66, 105, 70, 106, 78, 71, - 73, 82, 72, 85, 74, 79, 87, 67, 80, 83, - 75, 81, 88, 86, 84, 89, 112, 102, 61, 95, - 98, 113, 118, 90, 103, 91, 108, 92, 96, 97, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, + 37, 37, 39, 37, 40, 41, 42, 37, 43, 44, + 45, 46, 47, 48, 37, 37, 37, 49, 50, 57, + 57, 57, 57, 60, 68, 61, 64, 65, 70, 69, + 74, 113, 71, 114, 75, 72, 60, 76, 61, 85, + 77, 79, 82, 78, 83, 80, 86, 93, 73, 87, + 90, 81, 88, 95, 84, 89, 97, 94, 91, 96, + 103, 106, 128, 92, 98, 110, 99, 116, 100, 104, - 93, 104, 99, 109, 52, 52, 100, 55, 119, 56, - 101, 124, 126, 127, 131, 152, 142, 125, 154, 160, - 128, 153, 172, 132, 158, 163, 173, 161, 183, 369, - 133, 143, 144, 155, 369, 159, 164, 156, 112, 187, - 188, 194, 200, 113, 184, 195, 202, 223, 224, 368, - 367, 366, 365, 364, 363, 362, 203, 201, 361, 225, - 48, 48, 48, 48, 50, 50, 50, 50, 110, 110, - 360, 110, 111, 111, 111, 111, 114, 359, 114, 114, - 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, - 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, + 105, 101, 111, 107, 117, 120, 154, 108, 129, 112, + 121, 109, 57, 57, 134, 136, 137, 141, 164, 166, + 135, 155, 156, 138, 165, 170, 142, 172, 175, 196, + 181, 200, 201, 143, 167, 173, 171, 185, 168, 176, + 182, 186, 393, 120, 215, 197, 207, 393, 121, 67, + 208, 217, 238, 239, 392, 391, 390, 389, 388, 216, + 387, 218, 386, 385, 240, 51, 51, 51, 51, 51, + 51, 53, 53, 53, 53, 53, 53, 55, 55, 55, + 55, 55, 55, 62, 62, 118, 118, 118, 384, 118, + 118, 119, 119, 119, 119, 119, 119, 122, 122, 383, - 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, - 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, - 318, 317, 316, 315, 314, 313, 312, 311, 310, 309, - 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, - 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, - 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, - 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, - 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, - 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, - 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, + 122, 122, 122, 124, 382, 124, 124, 124, 124, 381, + 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, + 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, + 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, + 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, + 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, + 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, + 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, + 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, + 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, - 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, - 228, 227, 226, 222, 221, 220, 219, 218, 217, 216, - 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, - 205, 204, 199, 198, 197, 196, 193, 192, 191, 190, - 189, 186, 185, 182, 181, 180, 179, 178, 177, 176, - 175, 116, 115, 174, 171, 170, 169, 168, 167, 166, - 165, 162, 157, 151, 150, 149, 148, 147, 146, 145, - 141, 140, 139, 138, 137, 136, 135, 134, 130, 129, - 123, 122, 121, 120, 117, 116, 115, 107, 94, 60, - 57, 54, 53, 369, 51, 51, 49, 49, 7, 369, + 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, + 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, + 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, + 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, + 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, + 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, + 227, 226, 225, 224, 223, 222, 221, 220, 219, 214, + 213, 212, 211, 210, 209, 206, 205, 204, 203, 202, + 199, 198, 195, 194, 193, 192, 191, 190, 189, 188, + 126, 125, 123, 187, 184, 183, 180, 179, 178, 177, + + 174, 169, 163, 162, 161, 160, 159, 158, 157, 153, + 152, 151, 150, 149, 148, 147, 146, 145, 144, 140, + 139, 133, 132, 131, 130, 127, 393, 126, 125, 123, + 115, 102, 66, 63, 59, 58, 393, 56, 56, 54, + 54, 52, 52, 9, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393 - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369 } ; -static yyconst flex_int16_t yy_chk[448] = +static yyconst flex_int16_t yy_chk[494] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, - 10, 10, 21, 28, 21, 24, 24, 29, 28, 30, - 32, 29, 32, 30, 29, 43, 30, 43, 33, 30, - 31, 35, 30, 36, 31, 33, 37, 29, 33, 35, - 31, 33, 37, 36, 35, 38, 49, 42, 372, 40, - 41, 49, 63, 38, 42, 38, 45, 38, 40, 40, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, + 11, 12, 12, 24, 31, 24, 27, 27, 32, 31, + 33, 46, 32, 46, 33, 32, 61, 33, 61, 36, + 33, 34, 35, 33, 35, 34, 36, 39, 32, 36, + 38, 34, 36, 40, 35, 36, 41, 39, 38, 40, + 43, 44, 69, 38, 41, 45, 41, 48, 41, 43, - 38, 42, 41, 45, 52, 52, 41, 56, 63, 56, - 41, 69, 70, 70, 73, 94, 83, 69, 95, 98, - 70, 94, 108, 73, 97, 100, 108, 98, 127, 111, - 73, 83, 83, 95, 111, 97, 100, 95, 112, 130, - 130, 136, 143, 112, 127, 136, 144, 168, 168, 367, - 366, 365, 364, 363, 362, 360, 144, 143, 359, 168, - 370, 370, 370, 370, 371, 371, 371, 371, 373, 373, - 358, 373, 374, 374, 374, 374, 375, 357, 375, 375, - 356, 355, 354, 353, 352, 351, 349, 347, 344, 342, - 341, 339, 338, 337, 336, 334, 332, 330, 329, 328, + 43, 41, 45, 44, 48, 52, 91, 44, 69, 45, + 52, 44, 57, 57, 75, 76, 76, 79, 102, 103, + 75, 91, 91, 76, 102, 105, 79, 106, 108, 137, + 113, 140, 140, 79, 103, 106, 105, 116, 103, 108, + 113, 116, 119, 120, 155, 137, 146, 119, 120, 398, + 146, 156, 180, 180, 391, 390, 389, 388, 387, 155, + 386, 156, 384, 383, 180, 394, 394, 394, 394, 394, + 394, 395, 395, 395, 395, 395, 395, 396, 396, 396, + 396, 396, 396, 397, 397, 399, 399, 399, 382, 399, + 399, 400, 400, 400, 400, 400, 400, 401, 401, 381, - 327, 325, 323, 322, 319, 318, 316, 315, 312, 311, - 310, 306, 305, 304, 303, 300, 299, 298, 296, 295, - 293, 291, 289, 288, 286, 284, 282, 279, 278, 274, - 273, 272, 271, 270, 269, 267, 266, 265, 264, 263, - 262, 261, 260, 259, 258, 256, 255, 254, 252, 247, - 246, 245, 244, 243, 242, 241, 239, 238, 237, 236, - 234, 232, 230, 229, 228, 227, 226, 225, 224, 223, - 221, 220, 219, 218, 217, 216, 215, 214, 213, 211, - 210, 209, 206, 204, 202, 201, 200, 199, 197, 196, - 195, 193, 192, 190, 189, 188, 187, 186, 185, 184, + 401, 401, 401, 402, 380, 402, 402, 402, 402, 379, + 378, 377, 376, 375, 373, 371, 368, 366, 365, 363, + 361, 360, 359, 357, 354, 352, 351, 350, 349, 348, + 346, 344, 343, 340, 339, 337, 336, 335, 332, 331, + 330, 327, 325, 324, 323, 322, 319, 318, 317, 315, + 314, 312, 310, 308, 307, 306, 304, 302, 300, 297, + 296, 292, 291, 290, 289, 288, 287, 286, 284, 283, + 282, 281, 280, 279, 278, 277, 276, 275, 273, 272, + 271, 269, 267, 263, 262, 261, 260, 259, 258, 257, + 255, 254, 253, 252, 250, 248, 246, 245, 244, 243, - 183, 182, 181, 180, 177, 176, 175, 174, 173, 172, - 171, 170, 169, 167, 166, 165, 163, 160, 159, 158, - 157, 156, 155, 154, 153, 152, 150, 149, 148, 147, - 146, 145, 142, 141, 139, 138, 135, 134, 133, 132, - 131, 129, 128, 126, 125, 124, 123, 122, 121, 120, - 119, 116, 115, 109, 107, 106, 105, 104, 103, 102, - 101, 99, 96, 93, 92, 91, 88, 87, 86, 85, - 81, 80, 79, 78, 77, 76, 75, 74, 72, 71, - 68, 66, 65, 64, 62, 55, 51, 44, 39, 26, - 22, 20, 19, 7, 6, 5, 4, 3, 369, 369, + 242, 241, 240, 239, 238, 236, 235, 234, 233, 232, + 231, 230, 229, 228, 226, 225, 224, 221, 219, 217, + 216, 215, 214, 213, 211, 210, 208, 206, 205, 203, + 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, + 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, + 179, 178, 177, 175, 172, 171, 170, 169, 168, 167, + 166, 165, 164, 162, 161, 160, 159, 158, 157, 154, + 153, 152, 150, 149, 148, 145, 144, 143, 142, 141, + 139, 138, 136, 135, 134, 133, 132, 131, 130, 129, + 126, 125, 123, 117, 115, 114, 112, 111, 110, 109, + + 107, 104, 101, 100, 99, 96, 95, 94, 93, 89, + 88, 87, 86, 85, 84, 83, 82, 81, 80, 78, + 77, 74, 72, 71, 70, 68, 62, 60, 56, 54, + 47, 42, 29, 25, 23, 22, 9, 8, 7, 6, + 5, 4, 3, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393 - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369 } ; static yy_state_type yy_last_accepting_state; @@ -675,34 +699,16 @@ not automatically generate them from pars0grm.y and pars0lex.l. How to make the InnoDB parser and lexer C files: -1. First do - bison -d pars0grm.y - That generates pars0grm.tab.c and pars0grm.tab.h. +1. Run ./make_flex.sh to generate lexer files. -2. Rename pars0grm.tab.c to pars0grm.c and pars0grm.tab.h to pars0grm.h. +2. Run ./make_bison.sh to generate parser files. -3. Copy pars0grm.h also to /innobase/include - -4. Do - flex pars0lex.l - That generates lex.yy.c. - -5. Rename lex.yy.c to lexyy.c. - -6. Remove the #include of unistd.h from about line 2500 of lexyy.c - -7. Add '#include "univ.i"' before #include in lexyy.c - (Needed for AIX) - -8. Add a type cast to int to the assignment below the comment - 'need more input.' (Removes a warning on Win64) - -These instructions seem to work at least with bison-1.28 and flex-2.5.4 on +These instructions seem to work at least with bison-1.875d and flex-2.5.31 on Linux. *******************************************************/ #define YY_NO_INPUT 1 #define YY_NO_UNISTD_H 1 -#line 56 "pars0lex.l" +#line 38 "pars0lex.l" #define YYSTYPE que_node_t* #include "univ.i" @@ -749,11 +755,13 @@ string_append( -#line 751 "lex.yy.c" + +#line 759 "_flex_tmp.c" #define INITIAL 0 #define comment 1 #define quoted 2 +#define id 3 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way @@ -900,10 +908,10 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -#line 106 "pars0lex.l" +#line 91 "pars0lex.l" -#line 905 "lex.yy.c" +#line 914 "_flex_tmp.c" if ( (yy_init) ) { @@ -956,13 +964,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 370 ) + if ( yy_current_state >= 394 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 369 ); + while ( yy_current_state != 393 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -984,7 +992,7 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 108 "pars0lex.l" +#line 93 "pars0lex.l" { yylval = sym_tab_add_int_lit(pars_sym_tab_global, atoi(yytext)); @@ -993,7 +1001,7 @@ YY_RULE_SETUP YY_BREAK case 2: YY_RULE_SETUP -#line 114 "pars0lex.l" +#line 99 "pars0lex.l" { ut_error; /* not implemented */ @@ -1002,7 +1010,19 @@ YY_RULE_SETUP YY_BREAK case 3: YY_RULE_SETUP -#line 120 "pars0lex.l" +#line 105 "pars0lex.l" +{ + ulint type; + + yylval = sym_tab_add_bound_lit(pars_sym_tab_global, + yytext + 1, &type); + + return(type); +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 114 "pars0lex.l" { /* Quoted character string literals are handled in an explicit start state 'quoted'. This state is entered and the buffer for @@ -1013,19 +1033,19 @@ In the state 'quoted', only two actions are possible (defined below). */ stringbuf_len = 0; } YY_BREAK -case 4: -/* rule 4 can match eol */ +case 5: +/* rule 5 can match eol */ YY_RULE_SETUP -#line 129 "pars0lex.l" +#line 123 "pars0lex.l" { /* Got a sequence of characters other than "'": append to string buffer */ string_append(yytext, yyleng); } YY_BREAK -case 5: +case 6: YY_RULE_SETUP -#line 134 "pars0lex.l" +#line 128 "pars0lex.l" { /* Got a sequence of "'" characters: append half of them to string buffer, @@ -1050,18 +1070,69 @@ YY_RULE_SETUP } } YY_BREAK -case 6: +case 7: YY_RULE_SETUP -#line 158 "pars0lex.l" +#line 152 "pars0lex.l" +{ +/* Quoted identifiers are handled in an explicit start state 'id'. +This state is entered and the buffer for the scanned string is emptied +upon encountering a starting quote. + +In the state 'id', only two actions are possible (defined below). */ + BEGIN(id); + stringbuf_len = 0; +} + YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +#line 161 "pars0lex.l" +{ + /* Got a sequence of characters other than '"': + append to string buffer */ + string_append(yytext, yyleng); +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 166 "pars0lex.l" +{ + /* Got a sequence of '"' characters: + append half of them to string buffer, + as '""' represents a single '"'. + We apply truncating division, + so that '"""' will result in '"'. */ + + string_append(yytext, yyleng / 2); + + /* If we got an odd number of quotes, then the + last quote we got is the terminating quote. + At the end of the string, we return to the + initial start state and report the scanned + identifier. */ + + if (yyleng % 2) { + BEGIN(INITIAL); + yylval = sym_tab_add_id( + pars_sym_tab_global, + (byte*) stringbuf, stringbuf_len); + + return(PARS_ID_TOKEN); + } +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 191 "pars0lex.l" { yylval = sym_tab_add_null_lit(pars_sym_tab_global); return(PARS_NULL_LIT); } YY_BREAK -case 7: +case 11: YY_RULE_SETUP -#line 164 "pars0lex.l" +#line 197 "pars0lex.l" { /* Implicit cursor name */ yylval = sym_tab_add_str_lit(pars_sym_tab_global, @@ -1069,527 +1140,548 @@ YY_RULE_SETUP return(PARS_SQL_TOKEN); } YY_BREAK -case 8: +case 12: YY_RULE_SETUP -#line 171 "pars0lex.l" +#line 204 "pars0lex.l" { return(PARS_AND_TOKEN); } YY_BREAK -case 9: +case 13: YY_RULE_SETUP -#line 175 "pars0lex.l" +#line 208 "pars0lex.l" { return(PARS_OR_TOKEN); } YY_BREAK -case 10: +case 14: YY_RULE_SETUP -#line 179 "pars0lex.l" +#line 212 "pars0lex.l" { return(PARS_NOT_TOKEN); } YY_BREAK -case 11: +case 15: YY_RULE_SETUP -#line 183 "pars0lex.l" +#line 216 "pars0lex.l" { return(PARS_PROCEDURE_TOKEN); } YY_BREAK -case 12: +case 16: YY_RULE_SETUP -#line 187 "pars0lex.l" +#line 220 "pars0lex.l" { return(PARS_IN_TOKEN); } YY_BREAK -case 13: +case 17: YY_RULE_SETUP -#line 191 "pars0lex.l" +#line 224 "pars0lex.l" { return(PARS_OUT_TOKEN); } YY_BREAK -case 14: +case 18: YY_RULE_SETUP -#line 195 "pars0lex.l" +#line 228 "pars0lex.l" { return(PARS_BINARY_TOKEN); } YY_BREAK -case 15: +case 19: YY_RULE_SETUP -#line 199 "pars0lex.l" +#line 232 "pars0lex.l" { return(PARS_BLOB_TOKEN); } YY_BREAK -case 16: -YY_RULE_SETUP -#line 203 "pars0lex.l" -{ - return(PARS_INT_TOKEN); -} - YY_BREAK -case 17: -YY_RULE_SETUP -#line 207 "pars0lex.l" -{ - return(PARS_INT_TOKEN); -} - YY_BREAK -case 18: -YY_RULE_SETUP -#line 211 "pars0lex.l" -{ - return(PARS_FLOAT_TOKEN); -} - YY_BREAK -case 19: -YY_RULE_SETUP -#line 215 "pars0lex.l" -{ - return(PARS_CHAR_TOKEN); -} - YY_BREAK case 20: YY_RULE_SETUP -#line 219 "pars0lex.l" +#line 236 "pars0lex.l" { - return(PARS_IS_TOKEN); + return(PARS_INT_TOKEN); } YY_BREAK case 21: YY_RULE_SETUP -#line 223 "pars0lex.l" +#line 240 "pars0lex.l" { - return(PARS_BEGIN_TOKEN); + return(PARS_INT_TOKEN); } YY_BREAK case 22: YY_RULE_SETUP -#line 227 "pars0lex.l" +#line 244 "pars0lex.l" { - return(PARS_END_TOKEN); + return(PARS_FLOAT_TOKEN); } YY_BREAK case 23: YY_RULE_SETUP -#line 231 "pars0lex.l" +#line 248 "pars0lex.l" { - return(PARS_IF_TOKEN); + return(PARS_CHAR_TOKEN); } YY_BREAK case 24: YY_RULE_SETUP -#line 235 "pars0lex.l" +#line 252 "pars0lex.l" { - return(PARS_THEN_TOKEN); + return(PARS_IS_TOKEN); } YY_BREAK case 25: YY_RULE_SETUP -#line 239 "pars0lex.l" +#line 256 "pars0lex.l" { - return(PARS_ELSE_TOKEN); + return(PARS_BEGIN_TOKEN); } YY_BREAK case 26: YY_RULE_SETUP -#line 243 "pars0lex.l" +#line 260 "pars0lex.l" { - return(PARS_ELSIF_TOKEN); + return(PARS_END_TOKEN); } YY_BREAK case 27: YY_RULE_SETUP -#line 247 "pars0lex.l" +#line 264 "pars0lex.l" { - return(PARS_LOOP_TOKEN); + return(PARS_IF_TOKEN); } YY_BREAK case 28: YY_RULE_SETUP -#line 251 "pars0lex.l" +#line 268 "pars0lex.l" { - return(PARS_WHILE_TOKEN); + return(PARS_THEN_TOKEN); } YY_BREAK case 29: YY_RULE_SETUP -#line 255 "pars0lex.l" +#line 272 "pars0lex.l" { - return(PARS_RETURN_TOKEN); + return(PARS_ELSE_TOKEN); } YY_BREAK case 30: YY_RULE_SETUP -#line 259 "pars0lex.l" +#line 276 "pars0lex.l" { - return(PARS_SELECT_TOKEN); + return(PARS_ELSIF_TOKEN); } YY_BREAK case 31: YY_RULE_SETUP -#line 263 "pars0lex.l" +#line 280 "pars0lex.l" { - return(PARS_SUM_TOKEN); + return(PARS_LOOP_TOKEN); } YY_BREAK case 32: YY_RULE_SETUP -#line 267 "pars0lex.l" +#line 284 "pars0lex.l" { - return(PARS_COUNT_TOKEN); + return(PARS_WHILE_TOKEN); } YY_BREAK case 33: YY_RULE_SETUP -#line 271 "pars0lex.l" +#line 288 "pars0lex.l" { - return(PARS_DISTINCT_TOKEN); + return(PARS_RETURN_TOKEN); } YY_BREAK case 34: YY_RULE_SETUP -#line 275 "pars0lex.l" +#line 292 "pars0lex.l" { - return(PARS_FROM_TOKEN); + return(PARS_SELECT_TOKEN); } YY_BREAK case 35: YY_RULE_SETUP -#line 279 "pars0lex.l" +#line 296 "pars0lex.l" { - return(PARS_WHERE_TOKEN); + return(PARS_SUM_TOKEN); } YY_BREAK case 36: YY_RULE_SETUP -#line 283 "pars0lex.l" +#line 300 "pars0lex.l" { - return(PARS_FOR_TOKEN); + return(PARS_COUNT_TOKEN); } YY_BREAK case 37: YY_RULE_SETUP -#line 287 "pars0lex.l" +#line 304 "pars0lex.l" { - return(PARS_CONSISTENT_TOKEN); + return(PARS_DISTINCT_TOKEN); } YY_BREAK case 38: YY_RULE_SETUP -#line 291 "pars0lex.l" +#line 308 "pars0lex.l" { - return(PARS_READ_TOKEN); + return(PARS_FROM_TOKEN); } YY_BREAK case 39: YY_RULE_SETUP -#line 295 "pars0lex.l" +#line 312 "pars0lex.l" { - return(PARS_ORDER_TOKEN); + return(PARS_WHERE_TOKEN); } YY_BREAK case 40: YY_RULE_SETUP -#line 299 "pars0lex.l" +#line 316 "pars0lex.l" { - return(PARS_BY_TOKEN); + return(PARS_FOR_TOKEN); } YY_BREAK case 41: YY_RULE_SETUP -#line 303 "pars0lex.l" +#line 320 "pars0lex.l" { - return(PARS_ASC_TOKEN); + return(PARS_CONSISTENT_TOKEN); } YY_BREAK case 42: YY_RULE_SETUP -#line 307 "pars0lex.l" +#line 324 "pars0lex.l" { - return(PARS_DESC_TOKEN); + return(PARS_READ_TOKEN); } YY_BREAK case 43: YY_RULE_SETUP -#line 311 "pars0lex.l" +#line 328 "pars0lex.l" { - return(PARS_INSERT_TOKEN); + return(PARS_ORDER_TOKEN); } YY_BREAK case 44: YY_RULE_SETUP -#line 315 "pars0lex.l" +#line 332 "pars0lex.l" { - return(PARS_INTO_TOKEN); + return(PARS_BY_TOKEN); } YY_BREAK case 45: YY_RULE_SETUP -#line 319 "pars0lex.l" +#line 336 "pars0lex.l" { - return(PARS_VALUES_TOKEN); + return(PARS_ASC_TOKEN); } YY_BREAK case 46: YY_RULE_SETUP -#line 323 "pars0lex.l" +#line 340 "pars0lex.l" { - return(PARS_UPDATE_TOKEN); + return(PARS_DESC_TOKEN); } YY_BREAK case 47: YY_RULE_SETUP -#line 327 "pars0lex.l" +#line 344 "pars0lex.l" { - return(PARS_SET_TOKEN); + return(PARS_INSERT_TOKEN); } YY_BREAK case 48: YY_RULE_SETUP -#line 331 "pars0lex.l" +#line 348 "pars0lex.l" { - return(PARS_DELETE_TOKEN); + return(PARS_INTO_TOKEN); } YY_BREAK case 49: YY_RULE_SETUP -#line 335 "pars0lex.l" +#line 352 "pars0lex.l" { - return(PARS_CURRENT_TOKEN); + return(PARS_VALUES_TOKEN); } YY_BREAK case 50: YY_RULE_SETUP -#line 339 "pars0lex.l" +#line 356 "pars0lex.l" { - return(PARS_OF_TOKEN); + return(PARS_UPDATE_TOKEN); } YY_BREAK case 51: YY_RULE_SETUP -#line 343 "pars0lex.l" +#line 360 "pars0lex.l" { - return(PARS_CREATE_TOKEN); + return(PARS_SET_TOKEN); } YY_BREAK case 52: YY_RULE_SETUP -#line 347 "pars0lex.l" +#line 364 "pars0lex.l" { - return(PARS_TABLE_TOKEN); + return(PARS_DELETE_TOKEN); } YY_BREAK case 53: YY_RULE_SETUP -#line 351 "pars0lex.l" +#line 368 "pars0lex.l" { - return(PARS_INDEX_TOKEN); + return(PARS_CURRENT_TOKEN); } YY_BREAK case 54: YY_RULE_SETUP -#line 355 "pars0lex.l" +#line 372 "pars0lex.l" { - return(PARS_UNIQUE_TOKEN); + return(PARS_OF_TOKEN); } YY_BREAK case 55: YY_RULE_SETUP -#line 359 "pars0lex.l" +#line 376 "pars0lex.l" { - return(PARS_CLUSTERED_TOKEN); + return(PARS_CREATE_TOKEN); } YY_BREAK case 56: YY_RULE_SETUP -#line 363 "pars0lex.l" +#line 380 "pars0lex.l" { - return(PARS_DOES_NOT_FIT_IN_MEM_TOKEN); + return(PARS_TABLE_TOKEN); } YY_BREAK case 57: YY_RULE_SETUP -#line 367 "pars0lex.l" +#line 384 "pars0lex.l" { - return(PARS_ON_TOKEN); + return(PARS_INDEX_TOKEN); } YY_BREAK case 58: YY_RULE_SETUP -#line 371 "pars0lex.l" +#line 388 "pars0lex.l" { - return(PARS_DECLARE_TOKEN); + return(PARS_UNIQUE_TOKEN); } YY_BREAK case 59: YY_RULE_SETUP -#line 375 "pars0lex.l" +#line 392 "pars0lex.l" { - return(PARS_CURSOR_TOKEN); + return(PARS_CLUSTERED_TOKEN); } YY_BREAK case 60: YY_RULE_SETUP -#line 379 "pars0lex.l" +#line 396 "pars0lex.l" { - return(PARS_OPEN_TOKEN); + return(PARS_DOES_NOT_FIT_IN_MEM_TOKEN); } YY_BREAK case 61: YY_RULE_SETUP -#line 383 "pars0lex.l" +#line 400 "pars0lex.l" { - return(PARS_FETCH_TOKEN); + return(PARS_ON_TOKEN); } YY_BREAK case 62: YY_RULE_SETUP -#line 387 "pars0lex.l" +#line 404 "pars0lex.l" { - return(PARS_CLOSE_TOKEN); + return(PARS_DECLARE_TOKEN); } YY_BREAK case 63: YY_RULE_SETUP -#line 391 "pars0lex.l" +#line 408 "pars0lex.l" { - return(PARS_NOTFOUND_TOKEN); + return(PARS_CURSOR_TOKEN); } YY_BREAK case 64: YY_RULE_SETUP -#line 395 "pars0lex.l" +#line 412 "pars0lex.l" { - return(PARS_TO_CHAR_TOKEN); + return(PARS_OPEN_TOKEN); } YY_BREAK case 65: YY_RULE_SETUP -#line 399 "pars0lex.l" +#line 416 "pars0lex.l" { - return(PARS_TO_NUMBER_TOKEN); + return(PARS_FETCH_TOKEN); } YY_BREAK case 66: YY_RULE_SETUP -#line 403 "pars0lex.l" +#line 420 "pars0lex.l" { - return(PARS_TO_BINARY_TOKEN); + return(PARS_CLOSE_TOKEN); } YY_BREAK case 67: YY_RULE_SETUP -#line 407 "pars0lex.l" +#line 424 "pars0lex.l" { - return(PARS_BINARY_TO_NUMBER_TOKEN); + return(PARS_NOTFOUND_TOKEN); } YY_BREAK case 68: YY_RULE_SETUP -#line 411 "pars0lex.l" +#line 428 "pars0lex.l" { - return(PARS_SUBSTR_TOKEN); + return(PARS_TO_CHAR_TOKEN); } YY_BREAK case 69: YY_RULE_SETUP -#line 415 "pars0lex.l" +#line 432 "pars0lex.l" { - return(PARS_REPLSTR_TOKEN); + return(PARS_TO_NUMBER_TOKEN); } YY_BREAK case 70: YY_RULE_SETUP -#line 419 "pars0lex.l" +#line 436 "pars0lex.l" { - return(PARS_CONCAT_TOKEN); + return(PARS_TO_BINARY_TOKEN); } YY_BREAK case 71: YY_RULE_SETUP -#line 423 "pars0lex.l" +#line 440 "pars0lex.l" { - return(PARS_INSTR_TOKEN); + return(PARS_BINARY_TO_NUMBER_TOKEN); } YY_BREAK case 72: YY_RULE_SETUP -#line 427 "pars0lex.l" +#line 444 "pars0lex.l" { - return(PARS_LENGTH_TOKEN); + return(PARS_SUBSTR_TOKEN); } YY_BREAK case 73: YY_RULE_SETUP -#line 431 "pars0lex.l" +#line 448 "pars0lex.l" { - return(PARS_SYSDATE_TOKEN); + return(PARS_REPLSTR_TOKEN); } YY_BREAK case 74: YY_RULE_SETUP -#line 435 "pars0lex.l" +#line 452 "pars0lex.l" { - return(PARS_PRINTF_TOKEN); + return(PARS_CONCAT_TOKEN); } YY_BREAK case 75: YY_RULE_SETUP -#line 439 "pars0lex.l" +#line 456 "pars0lex.l" { - return(PARS_ASSERT_TOKEN); + return(PARS_INSTR_TOKEN); } YY_BREAK case 76: YY_RULE_SETUP -#line 443 "pars0lex.l" +#line 460 "pars0lex.l" { - return(PARS_RND_TOKEN); + return(PARS_LENGTH_TOKEN); } YY_BREAK case 77: YY_RULE_SETUP -#line 447 "pars0lex.l" +#line 464 "pars0lex.l" { - return(PARS_RND_STR_TOKEN); + return(PARS_SYSDATE_TOKEN); } YY_BREAK case 78: YY_RULE_SETUP -#line 451 "pars0lex.l" +#line 468 "pars0lex.l" { - return(PARS_ROW_PRINTF_TOKEN); + return(PARS_PRINTF_TOKEN); } YY_BREAK case 79: YY_RULE_SETUP -#line 455 "pars0lex.l" +#line 472 "pars0lex.l" { - return(PARS_COMMIT_TOKEN); + return(PARS_ASSERT_TOKEN); } YY_BREAK case 80: YY_RULE_SETUP -#line 459 "pars0lex.l" +#line 476 "pars0lex.l" { - return(PARS_ROLLBACK_TOKEN); + return(PARS_RND_TOKEN); } YY_BREAK case 81: YY_RULE_SETUP -#line 463 "pars0lex.l" +#line 480 "pars0lex.l" { - return(PARS_WORK_TOKEN); + return(PARS_RND_STR_TOKEN); } YY_BREAK case 82: YY_RULE_SETUP -#line 467 "pars0lex.l" +#line 484 "pars0lex.l" +{ + return(PARS_ROW_PRINTF_TOKEN); +} + YY_BREAK +case 83: +YY_RULE_SETUP +#line 488 "pars0lex.l" +{ + return(PARS_COMMIT_TOKEN); +} + YY_BREAK +case 84: +YY_RULE_SETUP +#line 492 "pars0lex.l" +{ + return(PARS_ROLLBACK_TOKEN); +} + YY_BREAK +case 85: +YY_RULE_SETUP +#line 496 "pars0lex.l" +{ + return(PARS_WORK_TOKEN); +} + YY_BREAK +case 86: +YY_RULE_SETUP +#line 500 "pars0lex.l" +{ + return(PARS_UNSIGNED_TOKEN); +} + YY_BREAK +case 87: +YY_RULE_SETUP +#line 504 "pars0lex.l" +{ + return(PARS_EXIT_TOKEN); +} + YY_BREAK +case 88: +YY_RULE_SETUP +#line 508 "pars0lex.l" +{ + return(PARS_FUNCTION_TOKEN); +} + YY_BREAK +case 89: +YY_RULE_SETUP +#line 512 "pars0lex.l" { yylval = sym_tab_add_id(pars_sym_tab_global, (byte*)yytext, @@ -1597,122 +1689,50 @@ YY_RULE_SETUP return(PARS_ID_TOKEN); } YY_BREAK -case 83: +case 90: YY_RULE_SETUP -#line 474 "pars0lex.l" +#line 519 "pars0lex.l" { return(PARS_DDOT_TOKEN); } YY_BREAK -case 84: +case 91: YY_RULE_SETUP -#line 478 "pars0lex.l" +#line 523 "pars0lex.l" { return(PARS_ASSIGN_TOKEN); } YY_BREAK -case 85: +case 92: YY_RULE_SETUP -#line 482 "pars0lex.l" +#line 527 "pars0lex.l" { return(PARS_LE_TOKEN); } YY_BREAK -case 86: +case 93: YY_RULE_SETUP -#line 486 "pars0lex.l" +#line 531 "pars0lex.l" { return(PARS_GE_TOKEN); } YY_BREAK -case 87: +case 94: YY_RULE_SETUP -#line 490 "pars0lex.l" +#line 535 "pars0lex.l" { return(PARS_NE_TOKEN); } YY_BREAK -case 88: -YY_RULE_SETUP -#line 494 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 89: -YY_RULE_SETUP -#line 499 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 90: -YY_RULE_SETUP -#line 504 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 91: -YY_RULE_SETUP -#line 509 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 92: -YY_RULE_SETUP -#line 514 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 93: -YY_RULE_SETUP -#line 519 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 94: -YY_RULE_SETUP -#line 524 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK case 95: YY_RULE_SETUP -#line 529 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 96: -YY_RULE_SETUP -#line 534 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 97: -YY_RULE_SETUP #line 539 "pars0lex.l" { return((int)(*yytext)); } YY_BREAK -case 98: +case 96: YY_RULE_SETUP #line 544 "pars0lex.l" { @@ -1720,7 +1740,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 99: +case 97: YY_RULE_SETUP #line 549 "pars0lex.l" { @@ -1728,7 +1748,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 100: +case 98: YY_RULE_SETUP #line 554 "pars0lex.l" { @@ -1736,7 +1756,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 101: +case 99: YY_RULE_SETUP #line 559 "pars0lex.l" { @@ -1744,7 +1764,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 102: +case 100: YY_RULE_SETUP #line 564 "pars0lex.l" { @@ -1752,37 +1772,109 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 103: +case 101: YY_RULE_SETUP #line 569 "pars0lex.l" -BEGIN(comment); /* eat up comment */ +{ + + return((int)(*yytext)); +} + YY_BREAK +case 102: +YY_RULE_SETUP +#line 574 "pars0lex.l" +{ + + return((int)(*yytext)); +} + YY_BREAK +case 103: +YY_RULE_SETUP +#line 579 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 104: -/* rule 104 can match eol */ YY_RULE_SETUP -#line 571 "pars0lex.l" +#line 584 "pars0lex.l" +{ + return((int)(*yytext)); +} YY_BREAK case 105: -/* rule 105 can match eol */ YY_RULE_SETUP -#line 572 "pars0lex.l" +#line 589 "pars0lex.l" +{ + return((int)(*yytext)); +} YY_BREAK case 106: YY_RULE_SETUP -#line 573 "pars0lex.l" -BEGIN(INITIAL); +#line 594 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 107: -/* rule 107 can match eol */ YY_RULE_SETUP -#line 575 "pars0lex.l" -/* eat up whitespace */ +#line 599 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 108: YY_RULE_SETUP -#line 578 "pars0lex.l" +#line 604 "pars0lex.l" +{ + + return((int)(*yytext)); +} + YY_BREAK +case 109: +YY_RULE_SETUP +#line 609 "pars0lex.l" +{ + + return((int)(*yytext)); +} + YY_BREAK +case 110: +YY_RULE_SETUP +#line 614 "pars0lex.l" +BEGIN(comment); /* eat up comment */ + YY_BREAK +case 111: +/* rule 111 can match eol */ +YY_RULE_SETUP +#line 616 "pars0lex.l" + + YY_BREAK +case 112: +/* rule 112 can match eol */ +YY_RULE_SETUP +#line 617 "pars0lex.l" + + YY_BREAK +case 113: +YY_RULE_SETUP +#line 618 "pars0lex.l" +BEGIN(INITIAL); + YY_BREAK +case 114: +/* rule 114 can match eol */ +YY_RULE_SETUP +#line 620 "pars0lex.l" +/* eat up whitespace */ + YY_BREAK +case 115: +YY_RULE_SETUP +#line 623 "pars0lex.l" { fprintf(stderr,"Unrecognized character: %02x\n", *yytext); @@ -1792,15 +1884,16 @@ YY_RULE_SETUP return(0); } YY_BREAK -case 109: +case 116: YY_RULE_SETUP -#line 587 "pars0lex.l" +#line 632 "pars0lex.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK -#line 1799 "lex.yy.c" +#line 1892 "_flex_tmp.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(comment): case YY_STATE_EOF(quoted): +case YY_STATE_EOF(id): yyterminate(); case YY_END_OF_BUFFER: @@ -2084,7 +2177,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 370 ) + if ( yy_current_state >= 394 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -2112,11 +2205,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 370 ) + if ( yy_current_state >= 394 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 369); + yy_is_jam = (yy_current_state == 393); return yy_is_jam ? 0 : yy_current_state; } @@ -2145,7 +2238,7 @@ static int yy_get_next_buffer (void) else { /* need more input */ - int offset = (int)(yy_c_buf_p - yytext_ptr); + int offset = (int)((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -2639,7 +2732,7 @@ void yyfree (void * ptr ) #undef YY_DECL_IS_OURS #undef YY_DECL #endif -#line 587 "pars0lex.l" +#line 632 "pars0lex.l" diff --git a/storage/innobase/pars/make_bison.sh b/storage/innobase/pars/make_bison.sh index 43b0322494c..c11456230c4 100755 --- a/storage/innobase/pars/make_bison.sh +++ b/storage/innobase/pars/make_bison.sh @@ -1,7 +1,6 @@ #!/bin/bash # -# regenerate parser from bison input files as documented at the top of -# pars0lex.l. +# generate parser files from bison input files. set -eu diff --git a/storage/innobase/pars/make_flex.sh b/storage/innobase/pars/make_flex.sh new file mode 100755 index 00000000000..c015327bf8c --- /dev/null +++ b/storage/innobase/pars/make_flex.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# generate lexer files from flex input files. + +set -eu + +TMPFILE=_flex_tmp.c +OUTFILE=lexyy.c + +flex -o $TMPFILE pars0lex.l + +# AIX needs its includes done in a certain order, so include "univ.i" first +# to be sure we get it right. +echo '#include "univ.i"' > $OUTFILE + +# flex assigns a pointer to an int in one place without a cast, resulting in +# a warning on Win64. this adds the cast. +sed -e 's/int offset = (yy_c_buf_p) - (yytext_ptr);/int offset = (int)((yy_c_buf_p) - (yytext_ptr));/;' < $TMPFILE >> $OUTFILE + +rm $TMPFILE diff --git a/storage/innobase/pars/pars0grm.c b/storage/innobase/pars/pars0grm.c index 3800cdda88e..2cce7cb1c8b 100644 --- a/storage/innobase/pars/pars0grm.c +++ b/storage/innobase/pars/pars0grm.c @@ -56,177 +56,187 @@ PARS_INT_LIT = 258, PARS_FLOAT_LIT = 259, PARS_STR_LIT = 260, - PARS_NULL_LIT = 261, - PARS_ID_TOKEN = 262, - PARS_AND_TOKEN = 263, - PARS_OR_TOKEN = 264, - PARS_NOT_TOKEN = 265, - PARS_GE_TOKEN = 266, - PARS_LE_TOKEN = 267, - PARS_NE_TOKEN = 268, - PARS_PROCEDURE_TOKEN = 269, - PARS_IN_TOKEN = 270, - PARS_OUT_TOKEN = 271, - PARS_BINARY_TOKEN = 272, - PARS_BLOB_TOKEN = 273, - PARS_INT_TOKEN = 274, - PARS_INTEGER_TOKEN = 275, - PARS_FLOAT_TOKEN = 276, - PARS_CHAR_TOKEN = 277, - PARS_IS_TOKEN = 278, - PARS_BEGIN_TOKEN = 279, - PARS_END_TOKEN = 280, - PARS_IF_TOKEN = 281, - PARS_THEN_TOKEN = 282, - PARS_ELSE_TOKEN = 283, - PARS_ELSIF_TOKEN = 284, - PARS_LOOP_TOKEN = 285, - PARS_WHILE_TOKEN = 286, - PARS_RETURN_TOKEN = 287, - PARS_SELECT_TOKEN = 288, - PARS_SUM_TOKEN = 289, - PARS_COUNT_TOKEN = 290, - PARS_DISTINCT_TOKEN = 291, - PARS_FROM_TOKEN = 292, - PARS_WHERE_TOKEN = 293, - PARS_FOR_TOKEN = 294, - PARS_DDOT_TOKEN = 295, - PARS_CONSISTENT_TOKEN = 296, - PARS_READ_TOKEN = 297, - PARS_ORDER_TOKEN = 298, - PARS_BY_TOKEN = 299, - PARS_ASC_TOKEN = 300, - PARS_DESC_TOKEN = 301, - PARS_INSERT_TOKEN = 302, - PARS_INTO_TOKEN = 303, - PARS_VALUES_TOKEN = 304, - PARS_UPDATE_TOKEN = 305, - PARS_SET_TOKEN = 306, - PARS_DELETE_TOKEN = 307, - PARS_CURRENT_TOKEN = 308, - PARS_OF_TOKEN = 309, - PARS_CREATE_TOKEN = 310, - PARS_TABLE_TOKEN = 311, - PARS_INDEX_TOKEN = 312, - PARS_UNIQUE_TOKEN = 313, - PARS_CLUSTERED_TOKEN = 314, - PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315, - PARS_ON_TOKEN = 316, - PARS_ASSIGN_TOKEN = 317, - PARS_DECLARE_TOKEN = 318, - PARS_CURSOR_TOKEN = 319, - PARS_SQL_TOKEN = 320, - PARS_OPEN_TOKEN = 321, - PARS_FETCH_TOKEN = 322, - PARS_CLOSE_TOKEN = 323, - PARS_NOTFOUND_TOKEN = 324, - PARS_TO_CHAR_TOKEN = 325, - PARS_TO_NUMBER_TOKEN = 326, - PARS_TO_BINARY_TOKEN = 327, - PARS_BINARY_TO_NUMBER_TOKEN = 328, - PARS_SUBSTR_TOKEN = 329, - PARS_REPLSTR_TOKEN = 330, - PARS_CONCAT_TOKEN = 331, - PARS_INSTR_TOKEN = 332, - PARS_LENGTH_TOKEN = 333, - PARS_SYSDATE_TOKEN = 334, - PARS_PRINTF_TOKEN = 335, - PARS_ASSERT_TOKEN = 336, - PARS_RND_TOKEN = 337, - PARS_RND_STR_TOKEN = 338, - PARS_ROW_PRINTF_TOKEN = 339, - PARS_COMMIT_TOKEN = 340, - PARS_ROLLBACK_TOKEN = 341, - PARS_WORK_TOKEN = 342, - NEG = 343 + PARS_FIXBINARY_LIT = 261, + PARS_BLOB_LIT = 262, + PARS_NULL_LIT = 263, + PARS_ID_TOKEN = 264, + PARS_AND_TOKEN = 265, + PARS_OR_TOKEN = 266, + PARS_NOT_TOKEN = 267, + PARS_GE_TOKEN = 268, + PARS_LE_TOKEN = 269, + PARS_NE_TOKEN = 270, + PARS_PROCEDURE_TOKEN = 271, + PARS_IN_TOKEN = 272, + PARS_OUT_TOKEN = 273, + PARS_BINARY_TOKEN = 274, + PARS_BLOB_TOKEN = 275, + PARS_INT_TOKEN = 276, + PARS_INTEGER_TOKEN = 277, + PARS_FLOAT_TOKEN = 278, + PARS_CHAR_TOKEN = 279, + PARS_IS_TOKEN = 280, + PARS_BEGIN_TOKEN = 281, + PARS_END_TOKEN = 282, + PARS_IF_TOKEN = 283, + PARS_THEN_TOKEN = 284, + PARS_ELSE_TOKEN = 285, + PARS_ELSIF_TOKEN = 286, + PARS_LOOP_TOKEN = 287, + PARS_WHILE_TOKEN = 288, + PARS_RETURN_TOKEN = 289, + PARS_SELECT_TOKEN = 290, + PARS_SUM_TOKEN = 291, + PARS_COUNT_TOKEN = 292, + PARS_DISTINCT_TOKEN = 293, + PARS_FROM_TOKEN = 294, + PARS_WHERE_TOKEN = 295, + PARS_FOR_TOKEN = 296, + PARS_DDOT_TOKEN = 297, + PARS_CONSISTENT_TOKEN = 298, + PARS_READ_TOKEN = 299, + PARS_ORDER_TOKEN = 300, + PARS_BY_TOKEN = 301, + PARS_ASC_TOKEN = 302, + PARS_DESC_TOKEN = 303, + PARS_INSERT_TOKEN = 304, + PARS_INTO_TOKEN = 305, + PARS_VALUES_TOKEN = 306, + PARS_UPDATE_TOKEN = 307, + PARS_SET_TOKEN = 308, + PARS_DELETE_TOKEN = 309, + PARS_CURRENT_TOKEN = 310, + PARS_OF_TOKEN = 311, + PARS_CREATE_TOKEN = 312, + PARS_TABLE_TOKEN = 313, + PARS_INDEX_TOKEN = 314, + PARS_UNIQUE_TOKEN = 315, + PARS_CLUSTERED_TOKEN = 316, + PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317, + PARS_ON_TOKEN = 318, + PARS_ASSIGN_TOKEN = 319, + PARS_DECLARE_TOKEN = 320, + PARS_CURSOR_TOKEN = 321, + PARS_SQL_TOKEN = 322, + PARS_OPEN_TOKEN = 323, + PARS_FETCH_TOKEN = 324, + PARS_CLOSE_TOKEN = 325, + PARS_NOTFOUND_TOKEN = 326, + PARS_TO_CHAR_TOKEN = 327, + PARS_TO_NUMBER_TOKEN = 328, + PARS_TO_BINARY_TOKEN = 329, + PARS_BINARY_TO_NUMBER_TOKEN = 330, + PARS_SUBSTR_TOKEN = 331, + PARS_REPLSTR_TOKEN = 332, + PARS_CONCAT_TOKEN = 333, + PARS_INSTR_TOKEN = 334, + PARS_LENGTH_TOKEN = 335, + PARS_SYSDATE_TOKEN = 336, + PARS_PRINTF_TOKEN = 337, + PARS_ASSERT_TOKEN = 338, + PARS_RND_TOKEN = 339, + PARS_RND_STR_TOKEN = 340, + PARS_ROW_PRINTF_TOKEN = 341, + PARS_COMMIT_TOKEN = 342, + PARS_ROLLBACK_TOKEN = 343, + PARS_WORK_TOKEN = 344, + PARS_UNSIGNED_TOKEN = 345, + PARS_EXIT_TOKEN = 346, + PARS_FUNCTION_TOKEN = 347, + NEG = 348 }; #endif #define PARS_INT_LIT 258 #define PARS_FLOAT_LIT 259 #define PARS_STR_LIT 260 -#define PARS_NULL_LIT 261 -#define PARS_ID_TOKEN 262 -#define PARS_AND_TOKEN 263 -#define PARS_OR_TOKEN 264 -#define PARS_NOT_TOKEN 265 -#define PARS_GE_TOKEN 266 -#define PARS_LE_TOKEN 267 -#define PARS_NE_TOKEN 268 -#define PARS_PROCEDURE_TOKEN 269 -#define PARS_IN_TOKEN 270 -#define PARS_OUT_TOKEN 271 -#define PARS_BINARY_TOKEN 272 -#define PARS_BLOB_TOKEN 273 -#define PARS_INT_TOKEN 274 -#define PARS_INTEGER_TOKEN 275 -#define PARS_FLOAT_TOKEN 276 -#define PARS_CHAR_TOKEN 277 -#define PARS_IS_TOKEN 278 -#define PARS_BEGIN_TOKEN 279 -#define PARS_END_TOKEN 280 -#define PARS_IF_TOKEN 281 -#define PARS_THEN_TOKEN 282 -#define PARS_ELSE_TOKEN 283 -#define PARS_ELSIF_TOKEN 284 -#define PARS_LOOP_TOKEN 285 -#define PARS_WHILE_TOKEN 286 -#define PARS_RETURN_TOKEN 287 -#define PARS_SELECT_TOKEN 288 -#define PARS_SUM_TOKEN 289 -#define PARS_COUNT_TOKEN 290 -#define PARS_DISTINCT_TOKEN 291 -#define PARS_FROM_TOKEN 292 -#define PARS_WHERE_TOKEN 293 -#define PARS_FOR_TOKEN 294 -#define PARS_DDOT_TOKEN 295 -#define PARS_CONSISTENT_TOKEN 296 -#define PARS_READ_TOKEN 297 -#define PARS_ORDER_TOKEN 298 -#define PARS_BY_TOKEN 299 -#define PARS_ASC_TOKEN 300 -#define PARS_DESC_TOKEN 301 -#define PARS_INSERT_TOKEN 302 -#define PARS_INTO_TOKEN 303 -#define PARS_VALUES_TOKEN 304 -#define PARS_UPDATE_TOKEN 305 -#define PARS_SET_TOKEN 306 -#define PARS_DELETE_TOKEN 307 -#define PARS_CURRENT_TOKEN 308 -#define PARS_OF_TOKEN 309 -#define PARS_CREATE_TOKEN 310 -#define PARS_TABLE_TOKEN 311 -#define PARS_INDEX_TOKEN 312 -#define PARS_UNIQUE_TOKEN 313 -#define PARS_CLUSTERED_TOKEN 314 -#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315 -#define PARS_ON_TOKEN 316 -#define PARS_ASSIGN_TOKEN 317 -#define PARS_DECLARE_TOKEN 318 -#define PARS_CURSOR_TOKEN 319 -#define PARS_SQL_TOKEN 320 -#define PARS_OPEN_TOKEN 321 -#define PARS_FETCH_TOKEN 322 -#define PARS_CLOSE_TOKEN 323 -#define PARS_NOTFOUND_TOKEN 324 -#define PARS_TO_CHAR_TOKEN 325 -#define PARS_TO_NUMBER_TOKEN 326 -#define PARS_TO_BINARY_TOKEN 327 -#define PARS_BINARY_TO_NUMBER_TOKEN 328 -#define PARS_SUBSTR_TOKEN 329 -#define PARS_REPLSTR_TOKEN 330 -#define PARS_CONCAT_TOKEN 331 -#define PARS_INSTR_TOKEN 332 -#define PARS_LENGTH_TOKEN 333 -#define PARS_SYSDATE_TOKEN 334 -#define PARS_PRINTF_TOKEN 335 -#define PARS_ASSERT_TOKEN 336 -#define PARS_RND_TOKEN 337 -#define PARS_RND_STR_TOKEN 338 -#define PARS_ROW_PRINTF_TOKEN 339 -#define PARS_COMMIT_TOKEN 340 -#define PARS_ROLLBACK_TOKEN 341 -#define PARS_WORK_TOKEN 342 -#define NEG 343 +#define PARS_FIXBINARY_LIT 261 +#define PARS_BLOB_LIT 262 +#define PARS_NULL_LIT 263 +#define PARS_ID_TOKEN 264 +#define PARS_AND_TOKEN 265 +#define PARS_OR_TOKEN 266 +#define PARS_NOT_TOKEN 267 +#define PARS_GE_TOKEN 268 +#define PARS_LE_TOKEN 269 +#define PARS_NE_TOKEN 270 +#define PARS_PROCEDURE_TOKEN 271 +#define PARS_IN_TOKEN 272 +#define PARS_OUT_TOKEN 273 +#define PARS_BINARY_TOKEN 274 +#define PARS_BLOB_TOKEN 275 +#define PARS_INT_TOKEN 276 +#define PARS_INTEGER_TOKEN 277 +#define PARS_FLOAT_TOKEN 278 +#define PARS_CHAR_TOKEN 279 +#define PARS_IS_TOKEN 280 +#define PARS_BEGIN_TOKEN 281 +#define PARS_END_TOKEN 282 +#define PARS_IF_TOKEN 283 +#define PARS_THEN_TOKEN 284 +#define PARS_ELSE_TOKEN 285 +#define PARS_ELSIF_TOKEN 286 +#define PARS_LOOP_TOKEN 287 +#define PARS_WHILE_TOKEN 288 +#define PARS_RETURN_TOKEN 289 +#define PARS_SELECT_TOKEN 290 +#define PARS_SUM_TOKEN 291 +#define PARS_COUNT_TOKEN 292 +#define PARS_DISTINCT_TOKEN 293 +#define PARS_FROM_TOKEN 294 +#define PARS_WHERE_TOKEN 295 +#define PARS_FOR_TOKEN 296 +#define PARS_DDOT_TOKEN 297 +#define PARS_CONSISTENT_TOKEN 298 +#define PARS_READ_TOKEN 299 +#define PARS_ORDER_TOKEN 300 +#define PARS_BY_TOKEN 301 +#define PARS_ASC_TOKEN 302 +#define PARS_DESC_TOKEN 303 +#define PARS_INSERT_TOKEN 304 +#define PARS_INTO_TOKEN 305 +#define PARS_VALUES_TOKEN 306 +#define PARS_UPDATE_TOKEN 307 +#define PARS_SET_TOKEN 308 +#define PARS_DELETE_TOKEN 309 +#define PARS_CURRENT_TOKEN 310 +#define PARS_OF_TOKEN 311 +#define PARS_CREATE_TOKEN 312 +#define PARS_TABLE_TOKEN 313 +#define PARS_INDEX_TOKEN 314 +#define PARS_UNIQUE_TOKEN 315 +#define PARS_CLUSTERED_TOKEN 316 +#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317 +#define PARS_ON_TOKEN 318 +#define PARS_ASSIGN_TOKEN 319 +#define PARS_DECLARE_TOKEN 320 +#define PARS_CURSOR_TOKEN 321 +#define PARS_SQL_TOKEN 322 +#define PARS_OPEN_TOKEN 323 +#define PARS_FETCH_TOKEN 324 +#define PARS_CLOSE_TOKEN 325 +#define PARS_NOTFOUND_TOKEN 326 +#define PARS_TO_CHAR_TOKEN 327 +#define PARS_TO_NUMBER_TOKEN 328 +#define PARS_TO_BINARY_TOKEN 329 +#define PARS_BINARY_TO_NUMBER_TOKEN 330 +#define PARS_SUBSTR_TOKEN 331 +#define PARS_REPLSTR_TOKEN 332 +#define PARS_CONCAT_TOKEN 333 +#define PARS_INSTR_TOKEN 334 +#define PARS_LENGTH_TOKEN 335 +#define PARS_SYSDATE_TOKEN 336 +#define PARS_PRINTF_TOKEN 337 +#define PARS_ASSERT_TOKEN 338 +#define PARS_RND_TOKEN 339 +#define PARS_RND_STR_TOKEN 340 +#define PARS_ROW_PRINTF_TOKEN 341 +#define PARS_COMMIT_TOKEN 342 +#define PARS_ROLLBACK_TOKEN 343 +#define PARS_WORK_TOKEN 344 +#define PARS_UNSIGNED_TOKEN 345 +#define PARS_EXIT_TOKEN 346 +#define PARS_FUNCTION_TOKEN 347 +#define NEG 348 @@ -279,7 +289,7 @@ typedef int YYSTYPE; /* Line 214 of yacc.c. */ -#line 283 "pars0grm.tab.c" +#line 293 "pars0grm.tab.c" #if ! defined (yyoverflow) || YYERROR_VERBOSE @@ -383,22 +393,22 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 95 +#define YYFINAL 99 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 734 +#define YYLAST 756 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 104 +#define YYNTOKENS 109 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 64 +#define YYNNTS 69 /* YYNRULES -- Number of rules. */ -#define YYNRULES 164 +#define YYNRULES 175 /* YYNRULES -- Number of states. */ -#define YYNSTATES 321 +#define YYNSTATES 337 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 343 +#define YYMAXUTOK 348 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -409,16 +419,16 @@ static const unsigned char yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 96, 2, 2, - 98, 99, 93, 92, 101, 91, 2, 94, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, - 89, 88, 90, 100, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, + 103, 104, 98, 97, 106, 96, 2, 99, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, + 94, 93, 95, 105, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 102, 2, 103, 2, 2, 2, 2, + 2, 2, 2, 107, 2, 108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -440,7 +450,7 @@ static const unsigned char yytranslate[] = 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 95 + 85, 86, 87, 88, 89, 90, 91, 92, 100 }; #if YYDEBUG @@ -450,100 +460,105 @@ static const unsigned short int yyprhs[] = { 0, 0, 3, 6, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, - 56, 59, 62, 65, 68, 70, 73, 75, 80, 82, - 84, 86, 88, 90, 94, 98, 102, 106, 109, 113, - 117, 121, 125, 129, 133, 137, 141, 145, 148, 152, - 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, - 176, 178, 179, 181, 185, 192, 197, 199, 201, 203, - 205, 209, 210, 212, 216, 217, 219, 223, 225, 230, - 236, 241, 242, 244, 248, 250, 254, 256, 257, 260, - 261, 264, 265, 268, 269, 271, 273, 274, 279, 288, - 292, 298, 301, 305, 307, 311, 316, 321, 324, 327, - 331, 334, 337, 340, 344, 349, 351, 354, 355, 358, - 360, 368, 375, 386, 388, 391, 394, 399, 404, 406, - 410, 411, 415, 416, 419, 420, 422, 430, 432, 436, - 437, 439, 440, 442, 453, 456, 459, 461, 463, 465, - 467, 469, 473, 477, 478, 480, 484, 488, 489, 491, - 494, 501, 502, 504, 507 + 56, 59, 62, 65, 68, 71, 73, 76, 78, 83, + 85, 87, 89, 91, 93, 95, 97, 101, 105, 109, + 113, 116, 120, 124, 128, 132, 136, 140, 144, 148, + 152, 155, 159, 163, 165, 167, 169, 171, 173, 175, + 177, 179, 181, 183, 185, 186, 188, 192, 199, 204, + 206, 208, 210, 214, 216, 220, 221, 223, 227, 228, + 230, 234, 236, 241, 247, 252, 253, 255, 259, 261, + 265, 267, 268, 271, 272, 275, 276, 279, 280, 282, + 284, 285, 290, 299, 303, 309, 312, 316, 318, 322, + 327, 332, 335, 338, 342, 345, 348, 351, 355, 360, + 362, 365, 366, 369, 371, 379, 386, 397, 399, 401, + 404, 407, 412, 417, 423, 425, 429, 430, 434, 435, + 437, 438, 441, 442, 444, 452, 454, 458, 459, 461, + 462, 464, 475, 478, 481, 483, 485, 487, 489, 491, + 495, 499, 500, 502, 506, 510, 511, 513, 516, 523, + 528, 530, 532, 533, 535, 538 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const short int yyrhs[] = { - 105, 0, -1, 167, 97, -1, 110, -1, 111, 97, - -1, 142, 97, -1, 143, 97, -1, 141, 97, -1, - 144, 97, -1, 137, 97, -1, 124, 97, -1, 126, - 97, -1, 136, 97, -1, 134, 97, -1, 135, 97, - -1, 131, 97, -1, 132, 97, -1, 145, 97, -1, - 147, 97, -1, 146, 97, -1, 158, 97, -1, 159, - 97, -1, 153, 97, -1, 157, 97, -1, 105, -1, - 106, 105, -1, 7, -1, 108, 98, 115, 99, -1, - 3, -1, 4, -1, 5, -1, 6, -1, 65, -1, - 107, 92, 107, -1, 107, 91, 107, -1, 107, 93, - 107, -1, 107, 94, 107, -1, 91, 107, -1, 98, - 107, 99, -1, 107, 88, 107, -1, 107, 89, 107, - -1, 107, 90, 107, -1, 107, 11, 107, -1, 107, - 12, 107, -1, 107, 13, 107, -1, 107, 8, 107, - -1, 107, 9, 107, -1, 10, 107, -1, 7, 96, - 69, -1, 65, 96, 69, -1, 70, -1, 71, -1, - 72, -1, 73, -1, 74, -1, 76, -1, 77, -1, - 78, -1, 79, -1, 82, -1, 83, -1, -1, 100, - -1, 109, 101, 100, -1, 102, 7, 98, 109, 99, - 103, -1, 112, 98, 115, 99, -1, 75, -1, 80, - -1, 81, -1, 7, -1, 113, 101, 7, -1, -1, - 7, -1, 114, 101, 7, -1, -1, 107, -1, 115, - 101, 107, -1, 107, -1, 35, 98, 93, 99, -1, - 35, 98, 36, 7, 99, -1, 34, 98, 107, 99, - -1, -1, 116, -1, 117, 101, 116, -1, 93, -1, - 117, 48, 114, -1, 117, -1, -1, 38, 107, -1, - -1, 39, 50, -1, -1, 41, 42, -1, -1, 45, - -1, 46, -1, -1, 43, 44, 7, 122, -1, 33, - 118, 37, 113, 119, 120, 121, 123, -1, 47, 48, - 7, -1, 125, 49, 98, 115, 99, -1, 125, 124, - -1, 7, 88, 107, -1, 127, -1, 128, 101, 127, - -1, 38, 53, 54, 7, -1, 50, 7, 51, 128, - -1, 130, 119, -1, 130, 129, -1, 52, 37, 7, - -1, 133, 119, -1, 133, 129, -1, 84, 124, -1, - 7, 62, 107, -1, 29, 107, 27, 106, -1, 138, - -1, 139, 138, -1, -1, 28, 106, -1, 139, -1, - 26, 107, 27, 106, 140, 25, 26, -1, 31, 107, - 30, 106, 25, 30, -1, 39, 7, 15, 107, 40, - 107, 30, 106, 25, 30, -1, 32, -1, 66, 7, - -1, 68, 7, -1, 67, 7, 48, 114, -1, 7, - 160, 150, 151, -1, 148, -1, 149, 101, 148, -1, - -1, 98, 3, 99, -1, -1, 10, 6, -1, -1, - 60, -1, 55, 56, 7, 98, 149, 99, 152, -1, - 7, -1, 154, 101, 7, -1, -1, 58, -1, -1, - 59, -1, 55, 155, 156, 57, 7, 61, 7, 98, - 154, 99, -1, 85, 87, -1, 86, 87, -1, 19, - -1, 20, -1, 22, -1, 17, -1, 18, -1, 7, - 15, 160, -1, 7, 16, 160, -1, -1, 161, -1, - 162, 101, 161, -1, 7, 160, 97, -1, -1, 163, - -1, 164, 163, -1, 63, 64, 7, 23, 124, 97, - -1, -1, 165, -1, 166, 165, -1, 14, 7, 98, - 162, 99, 23, 164, 166, 24, 106, 25, -1 + 110, 0, -1, 177, 102, -1, 115, -1, 116, 102, + -1, 148, 102, -1, 149, 102, -1, 150, 102, -1, + 147, 102, -1, 151, 102, -1, 143, 102, -1, 130, + 102, -1, 132, 102, -1, 142, 102, -1, 140, 102, + -1, 141, 102, -1, 137, 102, -1, 138, 102, -1, + 152, 102, -1, 154, 102, -1, 153, 102, -1, 166, + 102, -1, 167, 102, -1, 161, 102, -1, 165, 102, + -1, 110, -1, 111, 110, -1, 9, -1, 113, 103, + 121, 104, -1, 3, -1, 4, -1, 5, -1, 6, + -1, 7, -1, 8, -1, 67, -1, 112, 97, 112, + -1, 112, 96, 112, -1, 112, 98, 112, -1, 112, + 99, 112, -1, 96, 112, -1, 103, 112, 104, -1, + 112, 93, 112, -1, 112, 94, 112, -1, 112, 95, + 112, -1, 112, 13, 112, -1, 112, 14, 112, -1, + 112, 15, 112, -1, 112, 10, 112, -1, 112, 11, + 112, -1, 12, 112, -1, 9, 101, 71, -1, 67, + 101, 71, -1, 72, -1, 73, -1, 74, -1, 75, + -1, 76, -1, 78, -1, 79, -1, 80, -1, 81, + -1, 84, -1, 85, -1, -1, 105, -1, 114, 106, + 105, -1, 107, 9, 103, 114, 104, 108, -1, 117, + 103, 121, 104, -1, 77, -1, 82, -1, 83, -1, + 9, 103, 104, -1, 9, -1, 119, 106, 9, -1, + -1, 9, -1, 120, 106, 9, -1, -1, 112, -1, + 121, 106, 112, -1, 112, -1, 37, 103, 98, 104, + -1, 37, 103, 38, 9, 104, -1, 36, 103, 112, + 104, -1, -1, 122, -1, 123, 106, 122, -1, 98, + -1, 123, 50, 120, -1, 123, -1, -1, 40, 112, + -1, -1, 41, 52, -1, -1, 43, 44, -1, -1, + 47, -1, 48, -1, -1, 45, 46, 9, 128, -1, + 35, 124, 39, 119, 125, 126, 127, 129, -1, 49, + 50, 9, -1, 131, 51, 103, 121, 104, -1, 131, + 130, -1, 9, 93, 112, -1, 133, -1, 134, 106, + 133, -1, 40, 55, 56, 9, -1, 52, 9, 53, + 134, -1, 136, 125, -1, 136, 135, -1, 54, 39, + 9, -1, 139, 125, -1, 139, 135, -1, 86, 130, + -1, 9, 64, 112, -1, 31, 112, 29, 111, -1, + 144, -1, 145, 144, -1, -1, 30, 111, -1, 145, + -1, 28, 112, 29, 111, 146, 27, 28, -1, 33, + 112, 32, 111, 27, 32, -1, 41, 9, 17, 112, + 42, 112, 32, 111, 27, 32, -1, 91, -1, 34, + -1, 68, 9, -1, 70, 9, -1, 69, 9, 50, + 120, -1, 69, 9, 50, 118, -1, 9, 168, 157, + 158, 159, -1, 155, -1, 156, 106, 155, -1, -1, + 103, 3, 104, -1, -1, 90, -1, -1, 12, 8, + -1, -1, 62, -1, 57, 58, 9, 103, 156, 104, + 160, -1, 9, -1, 162, 106, 9, -1, -1, 60, + -1, -1, 61, -1, 57, 163, 164, 59, 9, 63, + 9, 103, 162, 104, -1, 87, 89, -1, 88, 89, + -1, 21, -1, 22, -1, 24, -1, 19, -1, 20, + -1, 9, 17, 168, -1, 9, 18, 168, -1, -1, + 169, -1, 170, 106, 169, -1, 9, 168, 102, -1, + -1, 171, -1, 172, 171, -1, 65, 66, 9, 25, + 130, 102, -1, 65, 92, 9, 102, -1, 173, -1, + 174, -1, -1, 175, -1, 176, 175, -1, 16, 9, + 103, 170, 104, 25, 172, 176, 26, 111, 27, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short int yyrline[] = { - 0, 131, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 156, 157, 162, 163, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 187, - 192, 193, 194, 195, 197, 198, 199, 200, 201, 202, - 203, 206, 208, 209, 213, 218, 223, 224, 225, 229, - 230, 235, 236, 237, 242, 243, 244, 248, 249, 254, - 260, 267, 268, 269, 274, 276, 278, 282, 283, 287, - 288, 293, 294, 299, 300, 301, 305, 306, 311, 321, - 326, 328, 333, 337, 338, 343, 349, 356, 361, 366, - 372, 377, 382, 387, 392, 398, 399, 404, 405, 407, - 411, 418, 424, 432, 436, 442, 448, 453, 458, 459, - 464, 465, 470, 471, 477, 478, 484, 490, 491, 496, - 497, 501, 502, 506, 514, 519, 524, 525, 526, 527, - 528, 532, 535, 541, 542, 543, 548, 552, 554, 555, - 559, 564, 566, 567, 571 + 0, 136, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 162, 163, 168, 169, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 195, 200, 201, 202, 203, 205, 206, 207, + 208, 209, 210, 211, 214, 216, 217, 221, 226, 231, + 232, 233, 237, 241, 242, 247, 248, 249, 254, 255, + 256, 260, 261, 266, 272, 279, 280, 281, 286, 288, + 290, 294, 295, 299, 300, 305, 306, 311, 312, 313, + 317, 318, 323, 333, 338, 340, 345, 349, 350, 355, + 361, 368, 373, 378, 384, 389, 394, 399, 404, 410, + 411, 416, 417, 419, 423, 430, 436, 444, 448, 452, + 458, 464, 466, 471, 476, 477, 482, 483, 488, 489, + 495, 496, 502, 503, 509, 515, 516, 521, 522, 526, + 527, 531, 539, 544, 549, 550, 551, 552, 553, 557, + 560, 566, 567, 568, 573, 577, 579, 580, 584, 590, + 595, 596, 599, 601, 602, 606 }; #endif @@ -553,38 +568,40 @@ static const unsigned short int yyrline[] = static const char *const yytname[] = { "$end", "error", "$undefined", "PARS_INT_LIT", "PARS_FLOAT_LIT", - "PARS_STR_LIT", "PARS_NULL_LIT", "PARS_ID_TOKEN", "PARS_AND_TOKEN", - "PARS_OR_TOKEN", "PARS_NOT_TOKEN", "PARS_GE_TOKEN", "PARS_LE_TOKEN", - "PARS_NE_TOKEN", "PARS_PROCEDURE_TOKEN", "PARS_IN_TOKEN", - "PARS_OUT_TOKEN", "PARS_BINARY_TOKEN", "PARS_BLOB_TOKEN", - "PARS_INT_TOKEN", "PARS_INTEGER_TOKEN", "PARS_FLOAT_TOKEN", - "PARS_CHAR_TOKEN", "PARS_IS_TOKEN", "PARS_BEGIN_TOKEN", "PARS_END_TOKEN", - "PARS_IF_TOKEN", "PARS_THEN_TOKEN", "PARS_ELSE_TOKEN", - "PARS_ELSIF_TOKEN", "PARS_LOOP_TOKEN", "PARS_WHILE_TOKEN", - "PARS_RETURN_TOKEN", "PARS_SELECT_TOKEN", "PARS_SUM_TOKEN", - "PARS_COUNT_TOKEN", "PARS_DISTINCT_TOKEN", "PARS_FROM_TOKEN", - "PARS_WHERE_TOKEN", "PARS_FOR_TOKEN", "PARS_DDOT_TOKEN", - "PARS_CONSISTENT_TOKEN", "PARS_READ_TOKEN", "PARS_ORDER_TOKEN", - "PARS_BY_TOKEN", "PARS_ASC_TOKEN", "PARS_DESC_TOKEN", - "PARS_INSERT_TOKEN", "PARS_INTO_TOKEN", "PARS_VALUES_TOKEN", - "PARS_UPDATE_TOKEN", "PARS_SET_TOKEN", "PARS_DELETE_TOKEN", - "PARS_CURRENT_TOKEN", "PARS_OF_TOKEN", "PARS_CREATE_TOKEN", - "PARS_TABLE_TOKEN", "PARS_INDEX_TOKEN", "PARS_UNIQUE_TOKEN", - "PARS_CLUSTERED_TOKEN", "PARS_DOES_NOT_FIT_IN_MEM_TOKEN", - "PARS_ON_TOKEN", "PARS_ASSIGN_TOKEN", "PARS_DECLARE_TOKEN", - "PARS_CURSOR_TOKEN", "PARS_SQL_TOKEN", "PARS_OPEN_TOKEN", - "PARS_FETCH_TOKEN", "PARS_CLOSE_TOKEN", "PARS_NOTFOUND_TOKEN", - "PARS_TO_CHAR_TOKEN", "PARS_TO_NUMBER_TOKEN", "PARS_TO_BINARY_TOKEN", - "PARS_BINARY_TO_NUMBER_TOKEN", "PARS_SUBSTR_TOKEN", "PARS_REPLSTR_TOKEN", - "PARS_CONCAT_TOKEN", "PARS_INSTR_TOKEN", "PARS_LENGTH_TOKEN", - "PARS_SYSDATE_TOKEN", "PARS_PRINTF_TOKEN", "PARS_ASSERT_TOKEN", - "PARS_RND_TOKEN", "PARS_RND_STR_TOKEN", "PARS_ROW_PRINTF_TOKEN", - "PARS_COMMIT_TOKEN", "PARS_ROLLBACK_TOKEN", "PARS_WORK_TOKEN", "'='", - "'<'", "'>'", "'-'", "'+'", "'*'", "'/'", "NEG", "'%'", "';'", "'('", - "')'", "'?'", "','", "'{'", "'}'", "$accept", "statement", - "statement_list", "exp", "function_name", "question_mark_list", - "stored_procedure_call", "predefined_procedure_call", - "predefined_procedure_name", "table_list", "variable_list", "exp_list", + "PARS_STR_LIT", "PARS_FIXBINARY_LIT", "PARS_BLOB_LIT", "PARS_NULL_LIT", + "PARS_ID_TOKEN", "PARS_AND_TOKEN", "PARS_OR_TOKEN", "PARS_NOT_TOKEN", + "PARS_GE_TOKEN", "PARS_LE_TOKEN", "PARS_NE_TOKEN", + "PARS_PROCEDURE_TOKEN", "PARS_IN_TOKEN", "PARS_OUT_TOKEN", + "PARS_BINARY_TOKEN", "PARS_BLOB_TOKEN", "PARS_INT_TOKEN", + "PARS_INTEGER_TOKEN", "PARS_FLOAT_TOKEN", "PARS_CHAR_TOKEN", + "PARS_IS_TOKEN", "PARS_BEGIN_TOKEN", "PARS_END_TOKEN", "PARS_IF_TOKEN", + "PARS_THEN_TOKEN", "PARS_ELSE_TOKEN", "PARS_ELSIF_TOKEN", + "PARS_LOOP_TOKEN", "PARS_WHILE_TOKEN", "PARS_RETURN_TOKEN", + "PARS_SELECT_TOKEN", "PARS_SUM_TOKEN", "PARS_COUNT_TOKEN", + "PARS_DISTINCT_TOKEN", "PARS_FROM_TOKEN", "PARS_WHERE_TOKEN", + "PARS_FOR_TOKEN", "PARS_DDOT_TOKEN", "PARS_CONSISTENT_TOKEN", + "PARS_READ_TOKEN", "PARS_ORDER_TOKEN", "PARS_BY_TOKEN", "PARS_ASC_TOKEN", + "PARS_DESC_TOKEN", "PARS_INSERT_TOKEN", "PARS_INTO_TOKEN", + "PARS_VALUES_TOKEN", "PARS_UPDATE_TOKEN", "PARS_SET_TOKEN", + "PARS_DELETE_TOKEN", "PARS_CURRENT_TOKEN", "PARS_OF_TOKEN", + "PARS_CREATE_TOKEN", "PARS_TABLE_TOKEN", "PARS_INDEX_TOKEN", + "PARS_UNIQUE_TOKEN", "PARS_CLUSTERED_TOKEN", + "PARS_DOES_NOT_FIT_IN_MEM_TOKEN", "PARS_ON_TOKEN", "PARS_ASSIGN_TOKEN", + "PARS_DECLARE_TOKEN", "PARS_CURSOR_TOKEN", "PARS_SQL_TOKEN", + "PARS_OPEN_TOKEN", "PARS_FETCH_TOKEN", "PARS_CLOSE_TOKEN", + "PARS_NOTFOUND_TOKEN", "PARS_TO_CHAR_TOKEN", "PARS_TO_NUMBER_TOKEN", + "PARS_TO_BINARY_TOKEN", "PARS_BINARY_TO_NUMBER_TOKEN", + "PARS_SUBSTR_TOKEN", "PARS_REPLSTR_TOKEN", "PARS_CONCAT_TOKEN", + "PARS_INSTR_TOKEN", "PARS_LENGTH_TOKEN", "PARS_SYSDATE_TOKEN", + "PARS_PRINTF_TOKEN", "PARS_ASSERT_TOKEN", "PARS_RND_TOKEN", + "PARS_RND_STR_TOKEN", "PARS_ROW_PRINTF_TOKEN", "PARS_COMMIT_TOKEN", + "PARS_ROLLBACK_TOKEN", "PARS_WORK_TOKEN", "PARS_UNSIGNED_TOKEN", + "PARS_EXIT_TOKEN", "PARS_FUNCTION_TOKEN", "'='", "'<'", "'>'", "'-'", + "'+'", "'*'", "'/'", "NEG", "'%'", "';'", "'('", "')'", "'?'", "','", + "'{'", "'}'", "$accept", "statement", "statement_list", "exp", + "function_name", "question_mark_list", "stored_procedure_call", + "predefined_procedure_call", "predefined_procedure_name", + "user_function_call", "table_list", "variable_list", "exp_list", "select_item", "select_item_list", "select_list", "search_condition", "for_update_clause", "consistent_read_clause", "order_direction", "order_by_clause", "select_statement", "insert_statement_start", @@ -594,15 +611,16 @@ static const char *const yytname[] = "delete_statement_start", "delete_statement_searched", "delete_statement_positioned", "row_printf_statement", "assignment_statement", "elsif_element", "elsif_list", "else_part", - "if_statement", "while_statement", "for_statement", "return_statement", - "open_cursor_statement", "close_cursor_statement", "fetch_statement", - "column_def", "column_def_list", "opt_column_len", "opt_not_null", - "not_fit_in_memory", "create_table", "column_list", "unique_def", - "clustered_def", "create_index", "commit_statement", - "rollback_statement", "type_name", "parameter_declaration", - "parameter_declaration_list", "variable_declaration", - "variable_declaration_list", "cursor_declaration", "declaration_list", - "procedure_definition", 0 + "if_statement", "while_statement", "for_statement", "exit_statement", + "return_statement", "open_cursor_statement", "close_cursor_statement", + "fetch_statement", "column_def", "column_def_list", "opt_column_len", + "opt_unsigned", "opt_not_null", "not_fit_in_memory", "create_table", + "column_list", "unique_def", "clustered_def", "create_index", + "commit_statement", "rollback_statement", "type_name", + "parameter_declaration", "parameter_declaration_list", + "variable_declaration", "variable_declaration_list", + "cursor_declaration", "function_declaration", "declaration", + "declaration_list", "procedure_definition", 0 }; #endif @@ -619,32 +637,33 @@ static const unsigned short int yytoknum[] = 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 61, 60, - 62, 45, 43, 42, 47, 343, 37, 59, 40, 41, - 63, 44, 123, 125 + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 61, 60, 62, 45, 43, 42, 47, + 348, 37, 59, 40, 41, 63, 44, 123, 125 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char yyr1[] = { - 0, 104, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 106, 106, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 109, 109, 109, 110, 111, 112, 112, 112, 113, - 113, 114, 114, 114, 115, 115, 115, 116, 116, 116, - 116, 117, 117, 117, 118, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 122, 123, 123, 124, 125, - 126, 126, 127, 128, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 139, 140, 140, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 149, - 150, 150, 151, 151, 152, 152, 153, 154, 154, 155, - 155, 156, 156, 157, 158, 159, 160, 160, 160, 160, - 160, 161, 161, 162, 162, 162, 163, 164, 164, 164, - 165, 166, 166, 166, 167 + 0, 109, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 111, 111, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 114, 114, 114, 115, 116, 117, + 117, 117, 118, 119, 119, 120, 120, 120, 121, 121, + 121, 122, 122, 122, 122, 123, 123, 123, 124, 124, + 124, 125, 125, 126, 126, 127, 127, 128, 128, 128, + 129, 129, 130, 131, 132, 132, 133, 134, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 145, 146, 146, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 154, 155, 156, 156, 157, 157, 158, 158, + 159, 159, 160, 160, 161, 162, 162, 163, 163, 164, + 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, + 169, 170, 170, 170, 171, 172, 172, 172, 173, 174, + 175, 175, 176, 176, 176, 177 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -652,21 +671,22 @@ static const unsigned char yyr2[] = { 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 2, 1, 4, 1, 1, - 1, 1, 1, 3, 3, 3, 3, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 3, 6, 4, 1, 1, 1, 1, - 3, 0, 1, 3, 0, 1, 3, 1, 4, 5, - 4, 0, 1, 3, 1, 3, 1, 0, 2, 0, - 2, 0, 2, 0, 1, 1, 0, 4, 8, 3, - 5, 2, 3, 1, 3, 4, 4, 2, 2, 3, - 2, 2, 2, 3, 4, 1, 2, 0, 2, 1, - 7, 6, 10, 1, 2, 2, 4, 4, 1, 3, - 0, 3, 0, 2, 0, 1, 7, 1, 3, 0, - 1, 0, 1, 10, 2, 2, 1, 1, 1, 1, - 1, 3, 3, 0, 1, 3, 3, 0, 1, 2, - 6, 0, 1, 2, 11 + 2, 2, 2, 2, 2, 1, 2, 1, 4, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 3, 6, 4, 1, + 1, 1, 3, 1, 3, 0, 1, 3, 0, 1, + 3, 1, 4, 5, 4, 0, 1, 3, 1, 3, + 1, 0, 2, 0, 2, 0, 2, 0, 1, 1, + 0, 4, 8, 3, 5, 2, 3, 1, 3, 4, + 4, 2, 2, 3, 2, 2, 2, 3, 4, 1, + 2, 0, 2, 1, 7, 6, 10, 1, 1, 2, + 2, 4, 4, 5, 1, 3, 0, 3, 0, 1, + 0, 2, 0, 1, 7, 1, 3, 0, 1, 0, + 1, 10, 2, 2, 1, 1, 1, 1, 1, 3, + 3, 0, 1, 3, 3, 0, 1, 2, 6, 4, + 1, 1, 0, 1, 2, 11 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -674,103 +694,105 @@ static const unsigned char yyr2[] = means the default is an error. */ static const unsigned char yydefact[] = { - 0, 0, 0, 0, 0, 123, 81, 0, 0, 0, - 0, 139, 0, 0, 0, 66, 67, 68, 0, 0, - 0, 0, 0, 3, 0, 0, 0, 0, 0, 87, - 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 85, 0, 0, 0, + 0, 147, 0, 0, 0, 69, 70, 71, 0, 0, + 0, 127, 0, 0, 3, 0, 0, 0, 0, 0, + 91, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 28, 29, 30, 31, 26, 0, 32, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 0, - 0, 0, 0, 0, 0, 0, 84, 77, 82, 86, - 0, 0, 0, 0, 0, 0, 140, 141, 124, 0, - 125, 112, 144, 145, 0, 1, 4, 74, 10, 0, - 101, 11, 0, 107, 108, 15, 16, 110, 111, 13, - 14, 12, 9, 7, 5, 6, 8, 17, 19, 18, - 22, 23, 20, 21, 2, 113, 153, 0, 47, 0, - 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 74, 0, 0, 0, 71, - 0, 0, 0, 99, 0, 109, 0, 142, 0, 71, - 61, 75, 0, 74, 0, 88, 0, 154, 0, 48, - 49, 38, 45, 46, 42, 43, 44, 24, 117, 39, - 40, 41, 34, 33, 35, 36, 0, 0, 0, 0, - 0, 72, 85, 83, 69, 87, 0, 0, 103, 106, - 0, 0, 126, 62, 0, 65, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 25, 115, 119, 0, 27, - 0, 80, 0, 78, 0, 0, 0, 89, 0, 0, - 0, 0, 128, 0, 0, 0, 0, 76, 100, 105, - 149, 150, 146, 147, 148, 151, 152, 157, 155, 118, - 0, 116, 0, 121, 79, 73, 70, 0, 91, 0, - 102, 104, 130, 134, 0, 0, 64, 63, 0, 158, - 161, 0, 120, 90, 0, 96, 0, 0, 132, 135, - 136, 129, 0, 0, 0, 159, 162, 0, 114, 92, - 0, 98, 0, 0, 0, 127, 0, 156, 0, 0, - 163, 0, 0, 131, 133, 137, 0, 0, 0, 93, - 122, 143, 0, 0, 164, 94, 95, 97, 138, 0, - 160 + 0, 0, 0, 29, 30, 31, 32, 33, 34, 27, + 0, 35, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 0, 0, 0, 0, 0, 0, 0, + 88, 81, 86, 90, 0, 0, 0, 0, 0, 0, + 148, 149, 129, 0, 130, 116, 152, 153, 0, 1, + 4, 78, 11, 0, 105, 12, 0, 111, 112, 16, + 17, 114, 115, 14, 15, 13, 10, 8, 5, 6, + 7, 9, 18, 20, 19, 23, 24, 21, 22, 2, + 117, 161, 0, 50, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 78, 0, 0, 0, 75, 0, 0, 0, 103, 0, + 113, 0, 150, 0, 75, 64, 79, 0, 78, 0, + 92, 0, 162, 0, 51, 52, 41, 48, 49, 45, + 46, 47, 25, 121, 42, 43, 44, 37, 36, 38, + 39, 0, 0, 0, 0, 0, 76, 89, 87, 73, + 91, 0, 0, 107, 110, 0, 0, 76, 132, 131, + 65, 0, 68, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 119, 123, 0, 28, 0, 84, 0, + 82, 0, 0, 0, 93, 0, 0, 0, 0, 134, + 0, 0, 0, 0, 0, 80, 104, 109, 157, 158, + 154, 155, 156, 159, 160, 165, 163, 122, 0, 120, + 0, 125, 83, 77, 74, 0, 95, 0, 106, 108, + 136, 142, 0, 0, 72, 67, 66, 0, 166, 172, + 0, 124, 94, 0, 100, 0, 0, 138, 143, 144, + 135, 0, 0, 0, 167, 170, 171, 173, 0, 118, + 96, 0, 102, 0, 0, 139, 140, 0, 164, 0, + 0, 0, 174, 0, 0, 137, 0, 133, 145, 0, + 0, 0, 0, 97, 126, 141, 151, 0, 0, 169, + 175, 98, 99, 101, 146, 0, 168 }; /* YYDEFGOTO[NTERM-NUM]. */ static const short int yydefgoto[] = { - -1, 177, 178, 161, 72, 204, 23, 24, 25, 195, - 192, 162, 78, 79, 80, 103, 258, 275, 317, 291, - 26, 27, 28, 198, 199, 104, 29, 30, 31, 32, - 33, 34, 35, 36, 216, 217, 218, 37, 38, 39, - 40, 41, 42, 43, 232, 233, 278, 295, 280, 44, - 306, 87, 158, 45, 46, 47, 245, 167, 168, 269, - 270, 286, 287, 48 + -1, 182, 183, 166, 76, 211, 24, 25, 26, 208, + 200, 197, 167, 82, 83, 84, 107, 266, 284, 333, + 302, 27, 28, 29, 203, 204, 108, 30, 31, 32, + 33, 34, 35, 36, 37, 223, 224, 225, 38, 39, + 40, 41, 42, 43, 44, 45, 239, 240, 287, 306, + 317, 289, 46, 319, 91, 163, 47, 48, 49, 253, + 172, 173, 278, 279, 295, 296, 297, 298, 50 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -205 +#define YYPACT_NINF -209 static const short int yypact[] = { - 454, -48, 30, 521, 521, -205, 12, 42, -18, 46, - -4, -33, 67, 69, 71, -205, -205, -205, 47, -8, - -6, 85, 93, -205, 1, -2, 2, -20, 3, 59, - 5, 7, 59, 24, 27, 28, 31, 32, 33, 39, - 50, 51, 55, 56, 57, 58, 60, 62, 63, 521, - 22, -205, -205, -205, -205, 48, 521, 65, -205, -205, - -205, -205, -205, -205, -205, -205, -205, -205, -205, 521, - 521, 252, 64, 576, 66, 68, -205, 640, -205, -40, - 86, 111, 120, 105, 156, 161, -205, 110, -205, 122, - -205, -205, -205, -205, 73, -205, -205, 521, -205, 74, - -205, -205, 492, -205, -205, -205, -205, -205, -205, -205, - -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, - -205, -205, -205, -205, -205, 640, 167, 106, 309, 107, - 168, 23, 521, 521, 521, 521, 521, 454, 521, 521, - 521, 521, 521, 521, 521, 521, 454, 521, -27, 178, - 204, 179, 521, -205, 181, -205, 91, -205, 134, 178, - 92, 640, -75, 521, 139, 640, 29, -205, -59, -205, - -205, -205, 309, 309, 15, 15, 640, -205, 151, 15, - 15, 15, 25, 25, 168, 168, -58, 284, 535, 187, - 96, -205, 95, -205, -205, -31, 568, 109, -205, 98, - 193, 195, 95, -205, -49, -205, 521, -45, 197, 40, - 40, 189, 167, 454, 521, -205, -205, 186, 191, -205, - 190, -205, 123, -205, 214, 521, 216, 194, 521, 521, - 181, 40, -205, -36, 164, 126, 130, 640, -205, -205, - -205, -205, -205, -205, -205, -205, -205, 227, -205, 454, - 605, -205, 215, -205, -205, -205, -205, 192, 199, 633, - 640, -205, 145, 184, 193, 238, -205, -205, 40, -205, - 4, 454, -205, -205, 205, 203, 454, 245, 240, -205, - -205, -205, 153, 155, 198, -205, -205, -12, 454, -205, - 210, -205, 341, 157, 249, -205, 250, -205, 251, 454, - -205, 259, 229, -205, -205, -205, -26, 244, 398, 26, - -205, -205, 261, 47, -205, -205, -205, -205, -205, 173, - -205 + 578, -30, 40, 256, 256, -209, 19, 44, 7, 55, + 26, -16, 62, 69, 73, -209, -209, -209, 48, -5, + -4, -209, 78, 75, -209, -13, -15, -6, -18, 4, + 67, 6, 12, 67, 17, 18, 21, 29, 30, 32, + 33, 39, 47, 50, 51, 64, 65, 70, 82, 83, + 84, 256, 13, -209, -209, -209, -209, -209, -209, 8, + 256, 20, -209, -209, -209, -209, -209, -209, -209, -209, + -209, -209, -209, 256, 256, 295, 15, 421, 77, 86, + -209, 657, -209, -44, 129, 152, 178, 137, 182, 189, + -209, 142, -209, 154, -209, -209, -209, -209, 104, -209, + -209, 256, -209, 105, -209, -209, 170, -209, -209, -209, + -209, -209, -209, -209, -209, -209, -209, -209, -209, -209, + -209, -209, -209, -209, -209, -209, -209, -209, -209, -209, + 657, 200, 139, 582, 140, 198, 66, 256, 256, 256, + 256, 256, 578, 256, 256, 256, 256, 256, 256, 256, + 256, 578, 256, -31, 205, 121, 206, 256, -209, 207, + -209, 115, -209, 160, 212, 117, 657, -63, 256, 167, + 657, -2, -209, -59, -209, -209, -209, 582, 582, 14, + 14, 657, -209, 330, 14, 14, 14, 3, 3, 198, + 198, -58, 392, 279, 217, 123, -209, 122, -209, -209, + -32, 607, 136, -209, 124, 223, 224, 133, -209, 122, + -209, -52, -209, 256, -46, 229, 16, 16, 214, 200, + 578, 256, -209, -209, 209, 220, -209, 221, -209, 148, + -209, 232, 256, 247, 226, 256, 256, 207, 16, -209, + -43, 195, 165, 162, 166, 657, -209, -209, -209, -209, + -209, -209, -209, -209, -209, 263, -209, 578, 483, -209, + 246, -209, -209, -209, -209, 225, 233, 626, 657, -209, + 172, 216, 223, 270, -209, -209, -209, 16, -209, 1, + 578, -209, -209, 236, 237, 578, 278, 193, -209, -209, + -209, 181, 183, -53, -209, -209, -209, -209, -14, 578, + -209, 240, -209, 454, 184, -209, 275, 282, -209, 286, + 287, 578, -209, 288, 266, -209, 292, -209, -209, -36, + 276, 202, 516, -28, -209, -209, -209, 293, 48, -209, + -209, -209, -209, -209, -209, 210, -209 }; /* YYPGOTO[NTERM-NUM]. */ static const short int yypgoto[] = { - -205, 0, -126, -1, -205, -205, -205, -205, -205, -205, - 112, -124, 135, -205, -205, -28, -205, -205, -205, -205, - -17, -205, -205, 43, -205, 257, -205, -205, -205, -205, - -205, -205, -205, -205, 76, -205, -205, -205, -205, -205, - -205, -205, -205, -205, 8, -205, -205, -205, -205, -205, - -205, -205, -205, -205, -205, -205, -204, 72, -205, 20, - -205, 10, -205, -205 + -209, 0, -130, -1, -209, -209, -209, -209, -209, -209, + -209, 143, -136, 158, -209, -209, -29, -209, -209, -209, + -209, -17, -209, -209, 79, -209, 281, -209, -209, -209, + -209, -209, -209, -209, -209, 91, -209, -209, -209, -209, + -209, -209, -209, -209, -209, -209, 45, -209, -209, -209, + -209, -209, -209, -209, -209, -209, -209, -209, -209, -208, + 99, -209, 41, -209, -209, -209, 23, -209, -209 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -780,197 +802,202 @@ static const short int yypgoto[] = #define YYTABLE_NINF -1 static const unsigned short int yytable[] = { - 22, 91, 71, 73, 107, 77, 246, 225, 149, 189, - 100, 268, 299, 6, 49, 51, 52, 53, 54, 55, - 187, 186, 56, 85, 205, 86, 206, 262, 136, 99, - 82, 132, 133, 84, 134, 135, 136, 50, 136, 207, - 211, 219, 212, 206, 209, 210, 74, 75, 125, 81, - 235, 284, 236, 83, 238, 128, 206, 240, 241, 242, - 243, 150, 244, 263, 283, 264, 190, 284, 130, 131, - 226, 315, 316, 311, 88, 312, 89, 57, 90, 92, - 6, 93, 58, 59, 60, 61, 62, 249, 63, 64, - 65, 66, 94, 95, 67, 68, 97, 102, 96, 98, - 101, 165, 105, 69, 106, 76, 141, 142, 143, 144, - 70, 138, 139, 140, 141, 142, 143, 144, 143, 144, - 126, 109, 171, 151, 110, 111, 152, 153, 112, 113, - 114, 172, 173, 174, 175, 176, 115, 179, 180, 181, - 182, 183, 184, 185, 127, 288, 188, 116, 117, 77, - 292, 196, 118, 119, 120, 121, 154, 122, 1, 123, - 124, 129, 145, 155, 147, 2, 148, 227, 156, 157, - 159, 160, 163, 308, 166, 169, 170, 3, 215, 213, - 214, 136, 4, 5, 6, 191, 194, 215, 197, 200, - 7, 201, 203, 208, 222, 223, 224, 229, 8, 230, - 231, 9, 234, 10, 239, 237, 11, 51, 52, 53, - 54, 55, 247, 250, 56, 214, 252, 12, 13, 14, - 253, 255, 254, 256, 165, 265, 15, 259, 260, 266, - 267, 16, 17, 257, 268, 18, 19, 20, 74, 75, - 274, 272, 273, 277, 279, 282, 290, 289, 293, 215, - 294, 296, 297, 21, 301, 304, 303, 305, 307, 310, - 132, 133, 298, 134, 135, 136, 309, 313, 318, 57, - 320, 202, 281, 261, 58, 59, 60, 61, 62, 137, - 63, 64, 65, 66, 248, 193, 67, 68, 215, 108, - 285, 1, 215, 251, 0, 69, 319, 300, 2, 0, - 0, 0, 70, 0, 0, 0, 0, 0, 215, 220, - 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, - 134, 135, 136, 7, 0, 0, 0, 0, 0, 0, + 23, 95, 75, 77, 111, 81, 154, 194, 232, 254, + 277, 104, 311, 309, 191, 216, 217, 6, 141, 331, + 332, 192, 53, 54, 55, 56, 57, 58, 59, 141, + 270, 60, 214, 103, 51, 248, 249, 250, 251, 310, + 252, 212, 89, 213, 90, 218, 226, 219, 213, 52, + 130, 293, 243, 85, 244, 78, 79, 86, 246, 133, + 213, 271, 155, 272, 87, 88, 293, 195, 326, 292, + 327, 92, 135, 136, 233, 99, 137, 138, 93, 139, + 140, 141, 94, 6, 96, 97, 61, 98, 101, 100, + 257, 62, 63, 64, 65, 66, 102, 67, 68, 69, + 70, 148, 149, 71, 72, 170, 105, 106, 109, 132, + 146, 147, 148, 149, 110, 73, 131, 80, 150, 113, + 114, 134, 74, 115, 53, 54, 55, 56, 57, 58, + 59, 116, 117, 60, 118, 119, 177, 178, 179, 180, + 181, 120, 184, 185, 186, 187, 188, 189, 190, 121, + 299, 193, 122, 123, 81, 303, 201, 78, 79, 143, + 144, 145, 146, 147, 148, 149, 124, 125, 156, 157, + 176, 234, 126, 53, 54, 55, 56, 57, 58, 59, + 152, 322, 60, 222, 127, 128, 129, 158, 61, 153, + 159, 160, 222, 62, 63, 64, 65, 66, 161, 67, + 68, 69, 70, 162, 164, 71, 72, 165, 168, 171, + 174, 175, 245, 141, 196, 199, 202, 73, 205, 206, + 258, 207, 210, 215, 74, 169, 229, 230, 231, 236, + 237, 170, 238, 241, 267, 268, 242, 61, 247, 255, + 221, 263, 62, 63, 64, 65, 66, 260, 67, 68, + 69, 70, 262, 261, 71, 72, 264, 222, 273, 53, + 54, 55, 56, 57, 58, 59, 73, 265, 60, 274, + 275, 276, 277, 74, 281, 286, 283, 282, 288, 291, + 300, 304, 301, 305, 307, 308, 313, 316, 315, 137, + 138, 318, 139, 140, 141, 320, 321, 323, 324, 222, + 325, 328, 334, 222, 329, 137, 138, 209, 139, 140, + 141, 335, 336, 198, 112, 259, 269, 290, 256, 0, + 294, 312, 222, 61, 142, 0, 0, 0, 62, 63, + 64, 65, 66, 0, 67, 68, 69, 70, 0, 1, + 71, 72, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 73, 0, 0, 0, 0, 0, 3, 74, + 220, 221, 0, 4, 5, 6, 0, 0, 0, 0, + 0, 7, 143, 144, 145, 146, 147, 148, 149, 8, + 0, 0, 9, 228, 10, 0, 0, 11, 143, 144, + 145, 146, 147, 148, 149, 0, 0, 0, 12, 13, + 14, 1, 0, 0, 0, 0, 0, 15, 2, 0, + 0, 0, 16, 17, 0, 0, 18, 19, 20, 227, + 3, 21, 0, 0, 0, 4, 5, 6, 0, 0, + 0, 137, 138, 7, 139, 140, 141, 22, 0, 0, 0, 8, 0, 0, 9, 0, 10, 0, 0, 11, - 138, 139, 140, 141, 142, 143, 144, 0, 1, 0, - 12, 13, 14, 0, 0, 2, 0, 0, 0, 15, - 0, 0, 0, 0, 16, 17, 302, 3, 18, 19, - 20, 0, 4, 5, 6, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 21, 0, 8, 0, - 0, 9, 0, 10, 0, 0, 11, 138, 139, 140, - 141, 142, 143, 144, 0, 1, 0, 12, 13, 14, - 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, - 0, 16, 17, 314, 3, 18, 19, 20, 0, 4, + 0, 0, 0, 151, 0, 0, 0, 0, 0, 0, + 12, 13, 14, 1, 0, 0, 0, 0, 0, 15, + 2, 0, 0, 0, 16, 17, 0, 0, 18, 19, + 20, 314, 3, 21, 0, 0, 0, 4, 5, 6, + 0, 0, 0, 137, 138, 7, 139, 140, 141, 22, + 0, 0, 0, 8, 0, 0, 9, 0, 10, 0, + 0, 11, 280, 0, 143, 144, 145, 146, 147, 148, + 149, 0, 12, 13, 14, 1, 0, 0, 0, 0, + 0, 15, 2, 0, 0, 0, 16, 17, 0, 0, + 18, 19, 20, 330, 3, 21, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 7, 0, 0, - 0, 0, 0, 21, 0, 8, 0, 0, 9, 0, - 10, 0, 0, 11, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 12, 13, 14, 0, 2, 0, - 0, 0, 0, 15, 0, 0, 0, 0, 16, 17, - 3, 0, 18, 19, 20, 4, 5, 6, 0, 0, - 0, 0, 0, 7, 0, 51, 52, 53, 54, 55, - 21, 8, 56, 0, 9, 0, 10, 0, 0, 11, + 0, 22, 0, 0, 0, 8, 0, 0, 9, 0, + 10, 0, 0, 11, 0, 0, 143, 144, 145, 146, + 147, 148, 149, 0, 12, 13, 14, 1, 0, 0, + 0, 0, 0, 15, 2, 139, 140, 141, 16, 17, + 0, 0, 18, 19, 20, 0, 3, 21, 0, 0, + 0, 4, 5, 6, 0, 0, 0, 137, 138, 7, + 139, 140, 141, 22, 0, 0, 0, 8, 0, 0, + 9, 0, 10, 0, 0, 11, 137, 138, 0, 139, + 140, 141, 0, 0, 0, 0, 12, 13, 14, 235, + 0, 0, 0, 0, 0, 15, 0, 0, 285, 0, + 16, 17, 0, 0, 18, 19, 20, 137, 138, 21, + 139, 140, 141, 0, 0, 143, 144, 145, 146, 147, + 148, 149, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 12, 13, 14, 0, 51, 52, 53, 54, 55, 15, - 0, 56, 0, 0, 16, 17, 0, 0, 18, 19, - 20, 0, 0, 132, 133, 164, 134, 135, 136, 0, - 0, 0, 0, 0, 0, 0, 21, 57, 0, 0, - 0, 0, 58, 59, 60, 61, 62, 0, 63, 64, - 65, 66, 0, 0, 67, 68, 132, 133, 0, 134, - 135, 136, 0, 69, 132, 133, 57, 134, 135, 136, - 70, 58, 59, 60, 61, 62, 0, 63, 64, 65, - 66, 0, 0, 67, 68, 0, 146, 0, 228, 0, - 0, 0, 69, 132, 133, 0, 134, 135, 136, 70, - 0, 0, 0, 138, 139, 140, 141, 142, 143, 144, - 0, 0, 271, 0, 221, 0, 0, 0, 0, 0, - 0, 132, 133, 0, 134, 135, 136, 0, 132, 133, - 0, 134, 135, 136, 0, 0, 138, 139, 140, 141, - 142, 143, 144, 276, 138, 139, 140, 141, 142, 143, - 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 139, 140, 141, 142, 143, 144, + 143, 144, 145, 146, 147, 148, 149, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, + 144, 145, 146, 147, 148, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 138, 139, 140, 141, 142, 143, 144, 138, 139, - 140, 141, 142, 143, 144 + 143, 144, 145, 146, 147, 148, 149 }; static const short int yycheck[] = { - 0, 18, 3, 4, 32, 6, 210, 38, 48, 36, - 27, 7, 24, 33, 62, 3, 4, 5, 6, 7, - 146, 145, 10, 56, 99, 58, 101, 231, 13, 49, - 48, 8, 9, 37, 11, 12, 13, 7, 13, 163, - 99, 99, 101, 101, 15, 16, 34, 35, 49, 7, - 99, 63, 101, 7, 99, 56, 101, 17, 18, 19, - 20, 101, 22, 99, 268, 101, 93, 63, 69, 70, - 101, 45, 46, 99, 7, 101, 7, 65, 7, 87, - 33, 87, 70, 71, 72, 73, 74, 213, 76, 77, - 78, 79, 7, 0, 82, 83, 98, 38, 97, 97, - 97, 102, 97, 91, 97, 93, 91, 92, 93, 94, - 98, 88, 89, 90, 91, 92, 93, 94, 93, 94, - 98, 97, 99, 37, 97, 97, 15, 7, 97, 97, - 97, 132, 133, 134, 135, 136, 97, 138, 139, 140, - 141, 142, 143, 144, 96, 271, 147, 97, 97, 150, - 276, 152, 97, 97, 97, 97, 51, 97, 7, 97, - 97, 96, 98, 7, 98, 14, 98, 195, 7, 59, - 48, 98, 98, 299, 7, 69, 69, 26, 178, 28, - 29, 13, 31, 32, 33, 7, 7, 187, 7, 98, - 39, 57, 100, 54, 7, 99, 101, 88, 47, 101, - 7, 50, 7, 52, 7, 206, 55, 3, 4, 5, - 6, 7, 23, 214, 10, 29, 25, 66, 67, 68, - 30, 7, 99, 7, 225, 61, 75, 228, 229, 103, - 100, 80, 81, 39, 7, 84, 85, 86, 34, 35, - 41, 26, 50, 98, 60, 7, 43, 42, 3, 249, - 10, 98, 97, 102, 44, 6, 99, 7, 7, 30, - 8, 9, 64, 11, 12, 13, 7, 23, 7, 65, - 97, 159, 264, 230, 70, 71, 72, 73, 74, 27, - 76, 77, 78, 79, 212, 150, 82, 83, 288, 32, - 270, 7, 292, 217, -1, 91, 313, 287, 14, -1, - -1, -1, 98, -1, -1, -1, -1, -1, 308, 25, - 26, -1, -1, -1, -1, 31, 32, 33, -1, -1, - 11, 12, 13, 39, -1, -1, -1, -1, -1, -1, - -1, 47, -1, -1, 50, -1, 52, -1, -1, 55, - 88, 89, 90, 91, 92, 93, 94, -1, 7, -1, - 66, 67, 68, -1, -1, 14, -1, -1, -1, 75, - -1, -1, -1, -1, 80, 81, 25, 26, 84, 85, - 86, -1, 31, 32, 33, -1, -1, -1, -1, -1, - 39, -1, -1, -1, -1, -1, 102, -1, 47, -1, - -1, 50, -1, 52, -1, -1, 55, 88, 89, 90, - 91, 92, 93, 94, -1, 7, -1, 66, 67, 68, - -1, -1, 14, -1, -1, -1, 75, -1, -1, -1, - -1, 80, 81, 25, 26, 84, 85, 86, -1, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - -1, -1, -1, 102, -1, 47, -1, -1, 50, -1, - 52, -1, -1, 55, -1, -1, -1, -1, -1, -1, - -1, 7, -1, -1, 66, 67, 68, -1, 14, -1, - -1, -1, -1, 75, -1, -1, -1, -1, 80, 81, - 26, -1, 84, 85, 86, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, 3, 4, 5, 6, 7, - 102, 47, 10, -1, 50, -1, 52, -1, -1, 55, + 0, 18, 3, 4, 33, 6, 50, 38, 40, 217, + 9, 28, 26, 66, 150, 17, 18, 35, 15, 47, + 48, 151, 3, 4, 5, 6, 7, 8, 9, 15, + 238, 12, 168, 51, 64, 19, 20, 21, 22, 92, + 24, 104, 58, 106, 60, 104, 104, 106, 106, 9, + 51, 65, 104, 9, 106, 36, 37, 50, 104, 60, + 106, 104, 106, 106, 9, 39, 65, 98, 104, 277, + 106, 9, 73, 74, 106, 0, 10, 11, 9, 13, + 14, 15, 9, 35, 89, 89, 67, 9, 103, 102, + 220, 72, 73, 74, 75, 76, 102, 78, 79, 80, + 81, 98, 99, 84, 85, 106, 102, 40, 102, 101, + 96, 97, 98, 99, 102, 96, 103, 98, 103, 102, + 102, 101, 103, 102, 3, 4, 5, 6, 7, 8, + 9, 102, 102, 12, 102, 102, 137, 138, 139, 140, + 141, 102, 143, 144, 145, 146, 147, 148, 149, 102, + 280, 152, 102, 102, 155, 285, 157, 36, 37, 93, + 94, 95, 96, 97, 98, 99, 102, 102, 39, 17, + 104, 200, 102, 3, 4, 5, 6, 7, 8, 9, + 103, 311, 12, 183, 102, 102, 102, 9, 67, 103, + 53, 9, 192, 72, 73, 74, 75, 76, 9, 78, + 79, 80, 81, 61, 50, 84, 85, 103, 103, 9, + 71, 71, 213, 15, 9, 9, 9, 96, 103, 59, + 221, 9, 105, 56, 103, 55, 9, 104, 106, 93, + 106, 232, 9, 9, 235, 236, 103, 67, 9, 25, + 31, 9, 72, 73, 74, 75, 76, 27, 78, 79, + 80, 81, 104, 32, 84, 85, 9, 257, 63, 3, + 4, 5, 6, 7, 8, 9, 96, 41, 12, 104, + 108, 105, 9, 103, 28, 103, 43, 52, 62, 9, + 44, 3, 45, 90, 103, 102, 46, 12, 104, 10, + 11, 9, 13, 14, 15, 9, 9, 9, 32, 299, + 8, 25, 9, 303, 102, 10, 11, 164, 13, 14, + 15, 328, 102, 155, 33, 224, 237, 272, 219, -1, + 279, 298, 322, 67, 29, -1, -1, -1, 72, 73, + 74, 75, 76, -1, 78, 79, 80, 81, -1, 9, + 84, 85, -1, -1, -1, -1, 16, -1, -1, -1, + -1, -1, 96, -1, -1, -1, -1, -1, 28, 103, + 30, 31, -1, 33, 34, 35, -1, -1, -1, -1, + -1, 41, 93, 94, 95, 96, 97, 98, 99, 49, + -1, -1, 52, 104, 54, -1, -1, 57, 93, 94, + 95, 96, 97, 98, 99, -1, -1, -1, 68, 69, + 70, 9, -1, -1, -1, -1, -1, 77, 16, -1, + -1, -1, 82, 83, -1, -1, 86, 87, 88, 27, + 28, 91, -1, -1, -1, 33, 34, 35, -1, -1, + -1, 10, 11, 41, 13, 14, 15, 107, -1, -1, + -1, 49, -1, -1, 52, -1, 54, -1, -1, 57, + -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, + 68, 69, 70, 9, -1, -1, -1, -1, -1, 77, + 16, -1, -1, -1, 82, 83, -1, -1, 86, 87, + 88, 27, 28, 91, -1, -1, -1, 33, 34, 35, + -1, -1, -1, 10, 11, 41, 13, 14, 15, 107, + -1, -1, -1, 49, -1, -1, 52, -1, 54, -1, + -1, 57, 29, -1, 93, 94, 95, 96, 97, 98, + 99, -1, 68, 69, 70, 9, -1, -1, -1, -1, + -1, 77, 16, -1, -1, -1, 82, 83, -1, -1, + 86, 87, 88, 27, 28, 91, -1, -1, -1, 33, + 34, 35, -1, -1, -1, -1, -1, 41, -1, -1, + -1, 107, -1, -1, -1, 49, -1, -1, 52, -1, + 54, -1, -1, 57, -1, -1, 93, 94, 95, 96, + 97, 98, 99, -1, 68, 69, 70, 9, -1, -1, + -1, -1, -1, 77, 16, 13, 14, 15, 82, 83, + -1, -1, 86, 87, 88, -1, 28, 91, -1, -1, + -1, 33, 34, 35, -1, -1, -1, 10, 11, 41, + 13, 14, 15, 107, -1, -1, -1, 49, -1, -1, + 52, -1, 54, -1, -1, 57, 10, 11, -1, 13, + 14, 15, -1, -1, -1, -1, 68, 69, 70, 42, + -1, -1, -1, -1, -1, 77, -1, -1, 32, -1, + 82, 83, -1, -1, 86, 87, 88, 10, 11, 91, + 13, 14, 15, -1, -1, 93, 94, 95, 96, 97, + 98, 99, -1, -1, -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 66, 67, 68, -1, 3, 4, 5, 6, 7, 75, - -1, 10, -1, -1, 80, 81, -1, -1, 84, 85, - 86, -1, -1, 8, 9, 53, 11, 12, 13, -1, - -1, -1, -1, -1, -1, -1, 102, 65, -1, -1, - -1, -1, 70, 71, 72, 73, 74, -1, 76, 77, - 78, 79, -1, -1, 82, 83, 8, 9, -1, 11, - 12, 13, -1, 91, 8, 9, 65, 11, 12, 13, - 98, 70, 71, 72, 73, 74, -1, 76, 77, 78, - 79, -1, -1, 82, 83, -1, 30, -1, 40, -1, - -1, -1, 91, 8, 9, -1, 11, 12, 13, 98, - -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, - -1, -1, 27, -1, 99, -1, -1, -1, -1, -1, - -1, 8, 9, -1, 11, 12, 13, -1, 8, 9, - -1, 11, 12, 13, -1, -1, 88, 89, 90, 91, - 92, 93, 94, 30, 88, 89, 90, 91, 92, 93, - 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, + 93, 94, 95, 96, 97, 98, 99, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, + 94, 95, 96, 97, 98, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 88, 89, 90, 91, 92, 93, 94, 88, 89, - 90, 91, 92, 93, 94 + 93, 94, 95, 96, 97, 98, 99 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char yystos[] = { - 0, 7, 14, 26, 31, 32, 33, 39, 47, 50, - 52, 55, 66, 67, 68, 75, 80, 81, 84, 85, - 86, 102, 105, 110, 111, 112, 124, 125, 126, 130, - 131, 132, 133, 134, 135, 136, 137, 141, 142, 143, - 144, 145, 146, 147, 153, 157, 158, 159, 167, 62, - 7, 3, 4, 5, 6, 7, 10, 65, 70, 71, - 72, 73, 74, 76, 77, 78, 79, 82, 83, 91, - 98, 107, 108, 107, 34, 35, 93, 107, 116, 117, - 118, 7, 48, 7, 37, 56, 58, 155, 7, 7, - 7, 124, 87, 87, 7, 0, 97, 98, 97, 49, - 124, 97, 38, 119, 129, 97, 97, 119, 129, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 107, 98, 96, 107, 96, - 107, 107, 8, 9, 11, 12, 13, 27, 88, 89, - 90, 91, 92, 93, 94, 98, 30, 98, 98, 48, - 101, 37, 15, 7, 51, 7, 7, 59, 156, 48, - 98, 107, 115, 98, 53, 107, 7, 161, 162, 69, - 69, 99, 107, 107, 107, 107, 107, 105, 106, 107, - 107, 107, 107, 107, 107, 107, 115, 106, 107, 36, - 93, 7, 114, 116, 7, 113, 107, 7, 127, 128, - 98, 57, 114, 100, 109, 99, 101, 115, 54, 15, - 16, 99, 101, 28, 29, 105, 138, 139, 140, 99, - 25, 99, 7, 99, 101, 38, 101, 119, 40, 88, - 101, 7, 148, 149, 7, 99, 101, 107, 99, 7, - 17, 18, 19, 20, 22, 160, 160, 23, 161, 106, - 107, 138, 25, 30, 99, 7, 7, 39, 120, 107, - 107, 127, 160, 99, 101, 61, 103, 100, 7, 163, - 164, 27, 26, 50, 41, 121, 30, 98, 150, 60, - 152, 148, 7, 160, 63, 163, 165, 166, 106, 42, - 43, 123, 106, 3, 10, 151, 98, 97, 64, 24, - 165, 44, 25, 99, 6, 7, 154, 7, 106, 7, - 30, 99, 101, 23, 25, 45, 46, 122, 7, 124, - 97 + 0, 9, 16, 28, 33, 34, 35, 41, 49, 52, + 54, 57, 68, 69, 70, 77, 82, 83, 86, 87, + 88, 91, 107, 110, 115, 116, 117, 130, 131, 132, + 136, 137, 138, 139, 140, 141, 142, 143, 147, 148, + 149, 150, 151, 152, 153, 154, 161, 165, 166, 167, + 177, 64, 9, 3, 4, 5, 6, 7, 8, 9, + 12, 67, 72, 73, 74, 75, 76, 78, 79, 80, + 81, 84, 85, 96, 103, 112, 113, 112, 36, 37, + 98, 112, 122, 123, 124, 9, 50, 9, 39, 58, + 60, 163, 9, 9, 9, 130, 89, 89, 9, 0, + 102, 103, 102, 51, 130, 102, 40, 125, 135, 102, + 102, 125, 135, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 112, 103, 101, 112, 101, 112, 112, 10, 11, 13, + 14, 15, 29, 93, 94, 95, 96, 97, 98, 99, + 103, 32, 103, 103, 50, 106, 39, 17, 9, 53, + 9, 9, 61, 164, 50, 103, 112, 121, 103, 55, + 112, 9, 169, 170, 71, 71, 104, 112, 112, 112, + 112, 112, 110, 111, 112, 112, 112, 112, 112, 112, + 112, 121, 111, 112, 38, 98, 9, 120, 122, 9, + 119, 112, 9, 133, 134, 103, 59, 9, 118, 120, + 105, 114, 104, 106, 121, 56, 17, 18, 104, 106, + 30, 31, 110, 144, 145, 146, 104, 27, 104, 9, + 104, 106, 40, 106, 125, 42, 93, 106, 9, 155, + 156, 9, 103, 104, 106, 112, 104, 9, 19, 20, + 21, 22, 24, 168, 168, 25, 169, 111, 112, 144, + 27, 32, 104, 9, 9, 41, 126, 112, 112, 133, + 168, 104, 106, 63, 104, 108, 105, 9, 171, 172, + 29, 28, 52, 43, 127, 32, 103, 157, 62, 160, + 155, 9, 168, 65, 171, 173, 174, 175, 176, 111, + 44, 45, 129, 111, 3, 90, 158, 103, 102, 66, + 92, 26, 175, 46, 27, 104, 12, 159, 9, 162, + 9, 9, 111, 9, 32, 8, 104, 106, 25, 102, + 27, 47, 48, 128, 9, 130, 102 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) @@ -1581,271 +1608,286 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 24: -#line 156 "pars0grm.y" + case 25: +#line 162 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; - case 25: -#line 158 "pars0grm.y" + case 26: +#line 164 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); ;} break; - case 26: -#line 162 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - case 27: -#line 164 "pars0grm.y" - { yyval = pars_func(yyvsp[-3], yyvsp[-1]); ;} - break; - - case 28: -#line 165 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - - case 29: -#line 166 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - - case 30: -#line 167 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - - case 31: #line 168 "pars0grm.y" { yyval = yyvsp[0];;} break; + case 28: +#line 170 "pars0grm.y" + { yyval = pars_func(yyvsp[-3], yyvsp[-1]); ;} + break; + + case 29: +#line 171 "pars0grm.y" + { yyval = yyvsp[0];;} + break; + + case 30: +#line 172 "pars0grm.y" + { yyval = yyvsp[0];;} + break; + + case 31: +#line 173 "pars0grm.y" + { yyval = yyvsp[0];;} + break; + case 32: -#line 169 "pars0grm.y" +#line 174 "pars0grm.y" { yyval = yyvsp[0];;} break; case 33: -#line 170 "pars0grm.y" - { yyval = pars_op('+', yyvsp[-2], yyvsp[0]); ;} +#line 175 "pars0grm.y" + { yyval = yyvsp[0];;} break; case 34: -#line 171 "pars0grm.y" - { yyval = pars_op('-', yyvsp[-2], yyvsp[0]); ;} +#line 176 "pars0grm.y" + { yyval = yyvsp[0];;} break; case 35: -#line 172 "pars0grm.y" - { yyval = pars_op('*', yyvsp[-2], yyvsp[0]); ;} +#line 177 "pars0grm.y" + { yyval = yyvsp[0];;} break; case 36: -#line 173 "pars0grm.y" - { yyval = pars_op('/', yyvsp[-2], yyvsp[0]); ;} +#line 178 "pars0grm.y" + { yyval = pars_op('+', yyvsp[-2], yyvsp[0]); ;} break; case 37: -#line 174 "pars0grm.y" - { yyval = pars_op('-', yyvsp[0], NULL); ;} +#line 179 "pars0grm.y" + { yyval = pars_op('-', yyvsp[-2], yyvsp[0]); ;} break; case 38: -#line 175 "pars0grm.y" - { yyval = yyvsp[-1]; ;} +#line 180 "pars0grm.y" + { yyval = pars_op('*', yyvsp[-2], yyvsp[0]); ;} break; case 39: -#line 176 "pars0grm.y" - { yyval = pars_op('=', yyvsp[-2], yyvsp[0]); ;} +#line 181 "pars0grm.y" + { yyval = pars_op('/', yyvsp[-2], yyvsp[0]); ;} break; case 40: -#line 177 "pars0grm.y" - { yyval = pars_op('<', yyvsp[-2], yyvsp[0]); ;} +#line 182 "pars0grm.y" + { yyval = pars_op('-', yyvsp[0], NULL); ;} break; case 41: -#line 178 "pars0grm.y" - { yyval = pars_op('>', yyvsp[-2], yyvsp[0]); ;} +#line 183 "pars0grm.y" + { yyval = yyvsp[-1]; ;} break; case 42: -#line 179 "pars0grm.y" - { yyval = pars_op(PARS_GE_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 184 "pars0grm.y" + { yyval = pars_op('=', yyvsp[-2], yyvsp[0]); ;} break; case 43: -#line 180 "pars0grm.y" - { yyval = pars_op(PARS_LE_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 185 "pars0grm.y" + { yyval = pars_op('<', yyvsp[-2], yyvsp[0]); ;} break; case 44: -#line 181 "pars0grm.y" - { yyval = pars_op(PARS_NE_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 186 "pars0grm.y" + { yyval = pars_op('>', yyvsp[-2], yyvsp[0]); ;} break; case 45: -#line 182 "pars0grm.y" - { yyval = pars_op(PARS_AND_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 187 "pars0grm.y" + { yyval = pars_op(PARS_GE_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 46: -#line 183 "pars0grm.y" - { yyval = pars_op(PARS_OR_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 188 "pars0grm.y" + { yyval = pars_op(PARS_LE_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 47: -#line 184 "pars0grm.y" - { yyval = pars_op(PARS_NOT_TOKEN, yyvsp[0], NULL); ;} +#line 189 "pars0grm.y" + { yyval = pars_op(PARS_NE_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 48: -#line 186 "pars0grm.y" - { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} +#line 190 "pars0grm.y" + { yyval = pars_op(PARS_AND_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 49: -#line 188 "pars0grm.y" - { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} +#line 191 "pars0grm.y" + { yyval = pars_op(PARS_OR_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 50: #line 192 "pars0grm.y" - { yyval = &pars_to_char_token; ;} + { yyval = pars_op(PARS_NOT_TOKEN, yyvsp[0], NULL); ;} break; case 51: -#line 193 "pars0grm.y" - { yyval = &pars_to_number_token; ;} +#line 194 "pars0grm.y" + { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} break; case 52: -#line 194 "pars0grm.y" - { yyval = &pars_to_binary_token; ;} +#line 196 "pars0grm.y" + { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} break; case 53: -#line 196 "pars0grm.y" - { yyval = &pars_binary_to_number_token; ;} +#line 200 "pars0grm.y" + { yyval = &pars_to_char_token; ;} break; case 54: -#line 197 "pars0grm.y" - { yyval = &pars_substr_token; ;} +#line 201 "pars0grm.y" + { yyval = &pars_to_number_token; ;} break; case 55: -#line 198 "pars0grm.y" - { yyval = &pars_concat_token; ;} +#line 202 "pars0grm.y" + { yyval = &pars_to_binary_token; ;} break; case 56: -#line 199 "pars0grm.y" - { yyval = &pars_instr_token; ;} +#line 204 "pars0grm.y" + { yyval = &pars_binary_to_number_token; ;} break; case 57: -#line 200 "pars0grm.y" - { yyval = &pars_length_token; ;} +#line 205 "pars0grm.y" + { yyval = &pars_substr_token; ;} break; case 58: -#line 201 "pars0grm.y" - { yyval = &pars_sysdate_token; ;} +#line 206 "pars0grm.y" + { yyval = &pars_concat_token; ;} break; case 59: -#line 202 "pars0grm.y" - { yyval = &pars_rnd_token; ;} +#line 207 "pars0grm.y" + { yyval = &pars_instr_token; ;} break; case 60: -#line 203 "pars0grm.y" +#line 208 "pars0grm.y" + { yyval = &pars_length_token; ;} + break; + + case 61: +#line 209 "pars0grm.y" + { yyval = &pars_sysdate_token; ;} + break; + + case 62: +#line 210 "pars0grm.y" + { yyval = &pars_rnd_token; ;} + break; + + case 63: +#line 211 "pars0grm.y" { yyval = &pars_rnd_str_token; ;} break; - case 64: -#line 214 "pars0grm.y" + case 67: +#line 222 "pars0grm.y" { yyval = pars_stored_procedure_call(yyvsp[-4]); ;} break; - case 65: -#line 219 "pars0grm.y" + case 68: +#line 227 "pars0grm.y" { yyval = pars_procedure_call(yyvsp[-3], yyvsp[-1]); ;} break; - case 66: -#line 223 "pars0grm.y" + case 69: +#line 231 "pars0grm.y" { yyval = &pars_replstr_token; ;} break; - case 67: -#line 224 "pars0grm.y" + case 70: +#line 232 "pars0grm.y" { yyval = &pars_printf_token; ;} break; - case 68: -#line 225 "pars0grm.y" + case 71: +#line 233 "pars0grm.y" { yyval = &pars_assert_token; ;} break; - case 69: -#line 229 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 70: -#line 231 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 71: -#line 235 "pars0grm.y" - { yyval = NULL; ;} - break; - case 72: -#line 236 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} +#line 237 "pars0grm.y" + { yyval = yyvsp[-2]; ;} break; case 73: -#line 238 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} +#line 241 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 74: -#line 242 "pars0grm.y" - { yyval = NULL; ;} - break; - - case 75: #line 243 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]);;} - break; - - case 76: -#line 244 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; - case 77: + case 75: +#line 247 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 76: #line 248 "pars0grm.y" - { yyval = yyvsp[0]; ;} + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} + break; + + case 77: +#line 250 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; case 78: -#line 250 "pars0grm.y" +#line 254 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 79: +#line 255 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]);;} + break; + + case 80: +#line 256 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + break; + + case 81: +#line 260 "pars0grm.y" + { yyval = yyvsp[0]; ;} + break; + + case 82: +#line 262 "pars0grm.y" { yyval = pars_func(&pars_count_token, que_node_list_add_last(NULL, sym_tab_add_int_lit( pars_sym_tab_global, 1))); ;} break; - case 79: -#line 255 "pars0grm.y" + case 83: +#line 267 "pars0grm.y" { yyval = pars_func(&pars_count_token, que_node_list_add_last(NULL, pars_func(&pars_distinct_token, @@ -1853,410 +1895,436 @@ yyreduce: NULL, yyvsp[-1])))); ;} break; - case 80: -#line 261 "pars0grm.y" + case 84: +#line 273 "pars0grm.y" { yyval = pars_func(&pars_sum_token, que_node_list_add_last(NULL, yyvsp[-1])); ;} break; - case 81: -#line 267 "pars0grm.y" + case 85: +#line 279 "pars0grm.y" { yyval = NULL; ;} break; - case 82: -#line 268 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 83: -#line 270 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 84: -#line 274 "pars0grm.y" - { yyval = pars_select_list(&pars_star_denoter, - NULL); ;} - break; - - case 85: -#line 277 "pars0grm.y" - { yyval = pars_select_list(yyvsp[-2], yyvsp[0]); ;} - break; - case 86: -#line 278 "pars0grm.y" - { yyval = pars_select_list(yyvsp[0], NULL); ;} +#line 280 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 87: #line 282 "pars0grm.y" - { yyval = NULL; ;} + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; case 88: -#line 283 "pars0grm.y" - { yyval = yyvsp[0]; ;} +#line 286 "pars0grm.y" + { yyval = pars_select_list(&pars_star_denoter, + NULL); ;} break; case 89: -#line 287 "pars0grm.y" - { yyval = NULL; ;} +#line 289 "pars0grm.y" + { yyval = pars_select_list(yyvsp[-2], yyvsp[0]); ;} break; case 90: -#line 289 "pars0grm.y" - { yyval = &pars_update_token; ;} +#line 290 "pars0grm.y" + { yyval = pars_select_list(yyvsp[0], NULL); ;} break; case 91: -#line 293 "pars0grm.y" +#line 294 "pars0grm.y" { yyval = NULL; ;} break; case 92: #line 295 "pars0grm.y" - { yyval = &pars_consistent_token; ;} + { yyval = yyvsp[0]; ;} break; case 93: #line 299 "pars0grm.y" - { yyval = &pars_asc_token; ;} + { yyval = NULL; ;} break; case 94: -#line 300 "pars0grm.y" - { yyval = &pars_asc_token; ;} +#line 301 "pars0grm.y" + { yyval = &pars_update_token; ;} break; case 95: -#line 301 "pars0grm.y" - { yyval = &pars_desc_token; ;} - break; - - case 96: #line 305 "pars0grm.y" { yyval = NULL; ;} break; - case 97: + case 96: #line 307 "pars0grm.y" - { yyval = pars_order_by(yyvsp[-1], yyvsp[0]); ;} + { yyval = &pars_consistent_token; ;} + break; + + case 97: +#line 311 "pars0grm.y" + { yyval = &pars_asc_token; ;} break; case 98: -#line 316 "pars0grm.y" +#line 312 "pars0grm.y" + { yyval = &pars_asc_token; ;} + break; + + case 99: +#line 313 "pars0grm.y" + { yyval = &pars_desc_token; ;} + break; + + case 100: +#line 317 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 101: +#line 319 "pars0grm.y" + { yyval = pars_order_by(yyvsp[-1], yyvsp[0]); ;} + break; + + case 102: +#line 328 "pars0grm.y" { yyval = pars_select_statement(yyvsp[-6], yyvsp[-4], yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); ;} break; - case 99: -#line 322 "pars0grm.y" - { yyval = yyvsp[0]; ;} - break; - - case 100: -#line 327 "pars0grm.y" - { yyval = pars_insert_statement(yyvsp[-4], yyvsp[-1], NULL); ;} - break; - - case 101: -#line 329 "pars0grm.y" - { yyval = pars_insert_statement(yyvsp[-1], NULL, yyvsp[0]); ;} - break; - - case 102: -#line 333 "pars0grm.y" - { yyval = pars_column_assignment(yyvsp[-2], yyvsp[0]); ;} - break; - case 103: -#line 337 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} +#line 334 "pars0grm.y" + { yyval = yyvsp[0]; ;} break; case 104: #line 339 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + { yyval = pars_insert_statement(yyvsp[-4], yyvsp[-1], NULL); ;} break; case 105: -#line 345 "pars0grm.y" - { yyval = yyvsp[0]; ;} +#line 341 "pars0grm.y" + { yyval = pars_insert_statement(yyvsp[-1], NULL, yyvsp[0]); ;} break; case 106: +#line 345 "pars0grm.y" + { yyval = pars_column_assignment(yyvsp[-2], yyvsp[0]); ;} + break; + + case 107: +#line 349 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} + break; + + case 108: #line 351 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + break; + + case 109: +#line 357 "pars0grm.y" + { yyval = yyvsp[0]; ;} + break; + + case 110: +#line 363 "pars0grm.y" { yyval = pars_update_statement_start(FALSE, yyvsp[-2], yyvsp[0]); ;} break; - case 107: -#line 357 "pars0grm.y" + case 111: +#line 369 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], NULL, yyvsp[0]); ;} break; - case 108: -#line 362 "pars0grm.y" + case 112: +#line 374 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], yyvsp[0], NULL); ;} break; - case 109: -#line 367 "pars0grm.y" + case 113: +#line 379 "pars0grm.y" { yyval = pars_update_statement_start(TRUE, yyvsp[0], NULL); ;} break; - case 110: -#line 373 "pars0grm.y" + case 114: +#line 385 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], NULL, yyvsp[0]); ;} break; - case 111: -#line 378 "pars0grm.y" + case 115: +#line 390 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], yyvsp[0], NULL); ;} break; - case 112: -#line 383 "pars0grm.y" + case 116: +#line 395 "pars0grm.y" { yyval = pars_row_printf_statement(yyvsp[0]); ;} break; - case 113: -#line 388 "pars0grm.y" - { yyval = pars_assignment_statement(yyvsp[-2], yyvsp[0]); ;} - break; - - case 114: -#line 394 "pars0grm.y" - { yyval = pars_elsif_element(yyvsp[-2], yyvsp[0]); ;} - break; - - case 115: -#line 398 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 116: -#line 400 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); ;} - break; - case 117: -#line 404 "pars0grm.y" - { yyval = NULL; ;} +#line 400 "pars0grm.y" + { yyval = pars_assignment_statement(yyvsp[-2], yyvsp[0]); ;} break; case 118: #line 406 "pars0grm.y" - { yyval = yyvsp[0]; ;} + { yyval = pars_elsif_element(yyvsp[-2], yyvsp[0]); ;} break; case 119: -#line 407 "pars0grm.y" - { yyval = yyvsp[0]; ;} +#line 410 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 120: -#line 414 "pars0grm.y" - { yyval = pars_if_statement(yyvsp[-5], yyvsp[-3], yyvsp[-2]); ;} +#line 412 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); ;} break; case 121: -#line 420 "pars0grm.y" - { yyval = pars_while_statement(yyvsp[-4], yyvsp[-2]); ;} +#line 416 "pars0grm.y" + { yyval = NULL; ;} break; case 122: -#line 428 "pars0grm.y" - { yyval = pars_for_statement(yyvsp[-8], yyvsp[-6], yyvsp[-4], yyvsp[-2]); ;} +#line 418 "pars0grm.y" + { yyval = yyvsp[0]; ;} break; case 123: -#line 432 "pars0grm.y" - { yyval = pars_return_statement(); ;} +#line 419 "pars0grm.y" + { yyval = yyvsp[0]; ;} break; case 124: -#line 437 "pars0grm.y" +#line 426 "pars0grm.y" + { yyval = pars_if_statement(yyvsp[-5], yyvsp[-3], yyvsp[-2]); ;} + break; + + case 125: +#line 432 "pars0grm.y" + { yyval = pars_while_statement(yyvsp[-4], yyvsp[-2]); ;} + break; + + case 126: +#line 440 "pars0grm.y" + { yyval = pars_for_statement(yyvsp[-8], yyvsp[-6], yyvsp[-4], yyvsp[-2]); ;} + break; + + case 127: +#line 444 "pars0grm.y" + { yyval = pars_exit_statement(); ;} + break; + + case 128: +#line 448 "pars0grm.y" + { yyval = pars_return_statement(); ;} + break; + + case 129: +#line 453 "pars0grm.y" { yyval = pars_open_statement( ROW_SEL_OPEN_CURSOR, yyvsp[0]); ;} break; - case 125: -#line 443 "pars0grm.y" + case 130: +#line 459 "pars0grm.y" { yyval = pars_open_statement( ROW_SEL_CLOSE_CURSOR, yyvsp[0]); ;} break; - case 126: -#line 449 "pars0grm.y" - { yyval = pars_fetch_statement(yyvsp[-2], yyvsp[0]); ;} - break; - - case 127: -#line 454 "pars0grm.y" - { yyval = pars_column_def(yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); ;} - break; - - case 128: -#line 458 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 129: -#line 460 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 130: -#line 464 "pars0grm.y" - { yyval = NULL; ;} - break; - case 131: -#line 466 "pars0grm.y" - { yyval = yyvsp[-1]; ;} +#line 465 "pars0grm.y" + { yyval = pars_fetch_statement(yyvsp[-2], yyvsp[0], NULL); ;} break; case 132: -#line 470 "pars0grm.y" - { yyval = NULL; ;} +#line 467 "pars0grm.y" + { yyval = pars_fetch_statement(yyvsp[-2], NULL, yyvsp[0]); ;} break; case 133: #line 472 "pars0grm.y" - { yyval = &pars_int_token; - /* pass any non-NULL pointer */ ;} + { yyval = pars_column_def(yyvsp[-4], yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); ;} break; case 134: -#line 477 "pars0grm.y" - { yyval = NULL; ;} +#line 476 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 135: -#line 479 "pars0grm.y" +#line 478 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + break; + + case 136: +#line 482 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 137: +#line 484 "pars0grm.y" + { yyval = yyvsp[-1]; ;} + break; + + case 138: +#line 488 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 139: +#line 490 "pars0grm.y" { yyval = &pars_int_token; /* pass any non-NULL pointer */ ;} break; - case 136: -#line 486 "pars0grm.y" - { yyval = pars_create_table(yyvsp[-4], yyvsp[-2], yyvsp[0]); ;} - break; - - case 137: -#line 490 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 138: -#line 492 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 139: -#line 496 "pars0grm.y" - { yyval = NULL; ;} - break; - case 140: -#line 497 "pars0grm.y" - { yyval = &pars_unique_token; ;} +#line 495 "pars0grm.y" + { yyval = NULL; ;} break; case 141: -#line 501 "pars0grm.y" - { yyval = NULL; ;} +#line 497 "pars0grm.y" + { yyval = &pars_int_token; + /* pass any non-NULL pointer */ ;} break; case 142: #line 502 "pars0grm.y" - { yyval = &pars_clustered_token; ;} + { yyval = NULL; ;} break; case 143: -#line 510 "pars0grm.y" - { yyval = pars_create_index(yyvsp[-8], yyvsp[-7], yyvsp[-5], yyvsp[-3], yyvsp[-1]); ;} +#line 504 "pars0grm.y" + { yyval = &pars_int_token; + /* pass any non-NULL pointer */ ;} break; case 144: -#line 515 "pars0grm.y" - { yyval = pars_commit_statement(); ;} +#line 511 "pars0grm.y" + { yyval = pars_create_table(yyvsp[-4], yyvsp[-2], yyvsp[0]); ;} break; case 145: -#line 520 "pars0grm.y" - { yyval = pars_rollback_statement(); ;} +#line 515 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 146: -#line 524 "pars0grm.y" - { yyval = &pars_int_token; ;} +#line 517 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; case 147: -#line 525 "pars0grm.y" - { yyval = &pars_int_token; ;} +#line 521 "pars0grm.y" + { yyval = NULL; ;} break; case 148: -#line 526 "pars0grm.y" - { yyval = &pars_char_token; ;} +#line 522 "pars0grm.y" + { yyval = &pars_unique_token; ;} break; case 149: -#line 527 "pars0grm.y" - { yyval = &pars_binary_token; ;} +#line 526 "pars0grm.y" + { yyval = NULL; ;} break; case 150: -#line 528 "pars0grm.y" - { yyval = &pars_blob_token; ;} +#line 527 "pars0grm.y" + { yyval = &pars_clustered_token; ;} break; case 151: -#line 533 "pars0grm.y" +#line 535 "pars0grm.y" + { yyval = pars_create_index(yyvsp[-8], yyvsp[-7], yyvsp[-5], yyvsp[-3], yyvsp[-1]); ;} + break; + + case 152: +#line 540 "pars0grm.y" + { yyval = pars_commit_statement(); ;} + break; + + case 153: +#line 545 "pars0grm.y" + { yyval = pars_rollback_statement(); ;} + break; + + case 154: +#line 549 "pars0grm.y" + { yyval = &pars_int_token; ;} + break; + + case 155: +#line 550 "pars0grm.y" + { yyval = &pars_int_token; ;} + break; + + case 156: +#line 551 "pars0grm.y" + { yyval = &pars_char_token; ;} + break; + + case 157: +#line 552 "pars0grm.y" + { yyval = &pars_binary_token; ;} + break; + + case 158: +#line 553 "pars0grm.y" + { yyval = &pars_blob_token; ;} + break; + + case 159: +#line 558 "pars0grm.y" { yyval = pars_parameter_declaration(yyvsp[-2], PARS_INPUT, yyvsp[0]); ;} break; - case 152: -#line 536 "pars0grm.y" + case 160: +#line 561 "pars0grm.y" { yyval = pars_parameter_declaration(yyvsp[-2], PARS_OUTPUT, yyvsp[0]); ;} break; - case 153: -#line 541 "pars0grm.y" + case 161: +#line 566 "pars0grm.y" { yyval = NULL; ;} break; - case 154: -#line 542 "pars0grm.y" + case 162: +#line 567 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; - case 155: -#line 544 "pars0grm.y" + case 163: +#line 569 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; - case 156: -#line 549 "pars0grm.y" + case 164: +#line 574 "pars0grm.y" { yyval = pars_variable_declaration(yyvsp[-2], yyvsp[-1]); ;} break; - case 160: -#line 561 "pars0grm.y" + case 168: +#line 586 "pars0grm.y" { yyval = pars_cursor_declaration(yyvsp[-3], yyvsp[-1]); ;} break; - case 164: -#line 577 "pars0grm.y" + case 169: +#line 591 "pars0grm.y" + { yyval = pars_function_declaration(yyvsp[-1]); ;} + break; + + case 175: +#line 612 "pars0grm.y" { yyval = pars_procedure_definition(yyvsp[-9], yyvsp[-7], yyvsp[-1]); ;} break; @@ -2265,7 +2333,7 @@ yyreduce: } /* Line 1010 of yacc.c. */ -#line 2269 "pars0grm.tab.c" +#line 2337 "pars0grm.tab.c" yyvsp -= yylen; yyssp -= yylen; @@ -2490,6 +2558,6 @@ yyreturn: } -#line 581 "pars0grm.y" +#line 616 "pars0grm.y" diff --git a/storage/innobase/pars/pars0grm.h b/storage/innobase/pars/pars0grm.h index e35fcf47692..996fc37f13b 100644 --- a/storage/innobase/pars/pars0grm.h +++ b/storage/innobase/pars/pars0grm.h @@ -32,177 +32,187 @@ PARS_INT_LIT = 258, PARS_FLOAT_LIT = 259, PARS_STR_LIT = 260, - PARS_NULL_LIT = 261, - PARS_ID_TOKEN = 262, - PARS_AND_TOKEN = 263, - PARS_OR_TOKEN = 264, - PARS_NOT_TOKEN = 265, - PARS_GE_TOKEN = 266, - PARS_LE_TOKEN = 267, - PARS_NE_TOKEN = 268, - PARS_PROCEDURE_TOKEN = 269, - PARS_IN_TOKEN = 270, - PARS_OUT_TOKEN = 271, - PARS_BINARY_TOKEN = 272, - PARS_BLOB_TOKEN = 273, - PARS_INT_TOKEN = 274, - PARS_INTEGER_TOKEN = 275, - PARS_FLOAT_TOKEN = 276, - PARS_CHAR_TOKEN = 277, - PARS_IS_TOKEN = 278, - PARS_BEGIN_TOKEN = 279, - PARS_END_TOKEN = 280, - PARS_IF_TOKEN = 281, - PARS_THEN_TOKEN = 282, - PARS_ELSE_TOKEN = 283, - PARS_ELSIF_TOKEN = 284, - PARS_LOOP_TOKEN = 285, - PARS_WHILE_TOKEN = 286, - PARS_RETURN_TOKEN = 287, - PARS_SELECT_TOKEN = 288, - PARS_SUM_TOKEN = 289, - PARS_COUNT_TOKEN = 290, - PARS_DISTINCT_TOKEN = 291, - PARS_FROM_TOKEN = 292, - PARS_WHERE_TOKEN = 293, - PARS_FOR_TOKEN = 294, - PARS_DDOT_TOKEN = 295, - PARS_CONSISTENT_TOKEN = 296, - PARS_READ_TOKEN = 297, - PARS_ORDER_TOKEN = 298, - PARS_BY_TOKEN = 299, - PARS_ASC_TOKEN = 300, - PARS_DESC_TOKEN = 301, - PARS_INSERT_TOKEN = 302, - PARS_INTO_TOKEN = 303, - PARS_VALUES_TOKEN = 304, - PARS_UPDATE_TOKEN = 305, - PARS_SET_TOKEN = 306, - PARS_DELETE_TOKEN = 307, - PARS_CURRENT_TOKEN = 308, - PARS_OF_TOKEN = 309, - PARS_CREATE_TOKEN = 310, - PARS_TABLE_TOKEN = 311, - PARS_INDEX_TOKEN = 312, - PARS_UNIQUE_TOKEN = 313, - PARS_CLUSTERED_TOKEN = 314, - PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315, - PARS_ON_TOKEN = 316, - PARS_ASSIGN_TOKEN = 317, - PARS_DECLARE_TOKEN = 318, - PARS_CURSOR_TOKEN = 319, - PARS_SQL_TOKEN = 320, - PARS_OPEN_TOKEN = 321, - PARS_FETCH_TOKEN = 322, - PARS_CLOSE_TOKEN = 323, - PARS_NOTFOUND_TOKEN = 324, - PARS_TO_CHAR_TOKEN = 325, - PARS_TO_NUMBER_TOKEN = 326, - PARS_TO_BINARY_TOKEN = 327, - PARS_BINARY_TO_NUMBER_TOKEN = 328, - PARS_SUBSTR_TOKEN = 329, - PARS_REPLSTR_TOKEN = 330, - PARS_CONCAT_TOKEN = 331, - PARS_INSTR_TOKEN = 332, - PARS_LENGTH_TOKEN = 333, - PARS_SYSDATE_TOKEN = 334, - PARS_PRINTF_TOKEN = 335, - PARS_ASSERT_TOKEN = 336, - PARS_RND_TOKEN = 337, - PARS_RND_STR_TOKEN = 338, - PARS_ROW_PRINTF_TOKEN = 339, - PARS_COMMIT_TOKEN = 340, - PARS_ROLLBACK_TOKEN = 341, - PARS_WORK_TOKEN = 342, - NEG = 343 + PARS_FIXBINARY_LIT = 261, + PARS_BLOB_LIT = 262, + PARS_NULL_LIT = 263, + PARS_ID_TOKEN = 264, + PARS_AND_TOKEN = 265, + PARS_OR_TOKEN = 266, + PARS_NOT_TOKEN = 267, + PARS_GE_TOKEN = 268, + PARS_LE_TOKEN = 269, + PARS_NE_TOKEN = 270, + PARS_PROCEDURE_TOKEN = 271, + PARS_IN_TOKEN = 272, + PARS_OUT_TOKEN = 273, + PARS_BINARY_TOKEN = 274, + PARS_BLOB_TOKEN = 275, + PARS_INT_TOKEN = 276, + PARS_INTEGER_TOKEN = 277, + PARS_FLOAT_TOKEN = 278, + PARS_CHAR_TOKEN = 279, + PARS_IS_TOKEN = 280, + PARS_BEGIN_TOKEN = 281, + PARS_END_TOKEN = 282, + PARS_IF_TOKEN = 283, + PARS_THEN_TOKEN = 284, + PARS_ELSE_TOKEN = 285, + PARS_ELSIF_TOKEN = 286, + PARS_LOOP_TOKEN = 287, + PARS_WHILE_TOKEN = 288, + PARS_RETURN_TOKEN = 289, + PARS_SELECT_TOKEN = 290, + PARS_SUM_TOKEN = 291, + PARS_COUNT_TOKEN = 292, + PARS_DISTINCT_TOKEN = 293, + PARS_FROM_TOKEN = 294, + PARS_WHERE_TOKEN = 295, + PARS_FOR_TOKEN = 296, + PARS_DDOT_TOKEN = 297, + PARS_CONSISTENT_TOKEN = 298, + PARS_READ_TOKEN = 299, + PARS_ORDER_TOKEN = 300, + PARS_BY_TOKEN = 301, + PARS_ASC_TOKEN = 302, + PARS_DESC_TOKEN = 303, + PARS_INSERT_TOKEN = 304, + PARS_INTO_TOKEN = 305, + PARS_VALUES_TOKEN = 306, + PARS_UPDATE_TOKEN = 307, + PARS_SET_TOKEN = 308, + PARS_DELETE_TOKEN = 309, + PARS_CURRENT_TOKEN = 310, + PARS_OF_TOKEN = 311, + PARS_CREATE_TOKEN = 312, + PARS_TABLE_TOKEN = 313, + PARS_INDEX_TOKEN = 314, + PARS_UNIQUE_TOKEN = 315, + PARS_CLUSTERED_TOKEN = 316, + PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317, + PARS_ON_TOKEN = 318, + PARS_ASSIGN_TOKEN = 319, + PARS_DECLARE_TOKEN = 320, + PARS_CURSOR_TOKEN = 321, + PARS_SQL_TOKEN = 322, + PARS_OPEN_TOKEN = 323, + PARS_FETCH_TOKEN = 324, + PARS_CLOSE_TOKEN = 325, + PARS_NOTFOUND_TOKEN = 326, + PARS_TO_CHAR_TOKEN = 327, + PARS_TO_NUMBER_TOKEN = 328, + PARS_TO_BINARY_TOKEN = 329, + PARS_BINARY_TO_NUMBER_TOKEN = 330, + PARS_SUBSTR_TOKEN = 331, + PARS_REPLSTR_TOKEN = 332, + PARS_CONCAT_TOKEN = 333, + PARS_INSTR_TOKEN = 334, + PARS_LENGTH_TOKEN = 335, + PARS_SYSDATE_TOKEN = 336, + PARS_PRINTF_TOKEN = 337, + PARS_ASSERT_TOKEN = 338, + PARS_RND_TOKEN = 339, + PARS_RND_STR_TOKEN = 340, + PARS_ROW_PRINTF_TOKEN = 341, + PARS_COMMIT_TOKEN = 342, + PARS_ROLLBACK_TOKEN = 343, + PARS_WORK_TOKEN = 344, + PARS_UNSIGNED_TOKEN = 345, + PARS_EXIT_TOKEN = 346, + PARS_FUNCTION_TOKEN = 347, + NEG = 348 }; #endif #define PARS_INT_LIT 258 #define PARS_FLOAT_LIT 259 #define PARS_STR_LIT 260 -#define PARS_NULL_LIT 261 -#define PARS_ID_TOKEN 262 -#define PARS_AND_TOKEN 263 -#define PARS_OR_TOKEN 264 -#define PARS_NOT_TOKEN 265 -#define PARS_GE_TOKEN 266 -#define PARS_LE_TOKEN 267 -#define PARS_NE_TOKEN 268 -#define PARS_PROCEDURE_TOKEN 269 -#define PARS_IN_TOKEN 270 -#define PARS_OUT_TOKEN 271 -#define PARS_BINARY_TOKEN 272 -#define PARS_BLOB_TOKEN 273 -#define PARS_INT_TOKEN 274 -#define PARS_INTEGER_TOKEN 275 -#define PARS_FLOAT_TOKEN 276 -#define PARS_CHAR_TOKEN 277 -#define PARS_IS_TOKEN 278 -#define PARS_BEGIN_TOKEN 279 -#define PARS_END_TOKEN 280 -#define PARS_IF_TOKEN 281 -#define PARS_THEN_TOKEN 282 -#define PARS_ELSE_TOKEN 283 -#define PARS_ELSIF_TOKEN 284 -#define PARS_LOOP_TOKEN 285 -#define PARS_WHILE_TOKEN 286 -#define PARS_RETURN_TOKEN 287 -#define PARS_SELECT_TOKEN 288 -#define PARS_SUM_TOKEN 289 -#define PARS_COUNT_TOKEN 290 -#define PARS_DISTINCT_TOKEN 291 -#define PARS_FROM_TOKEN 292 -#define PARS_WHERE_TOKEN 293 -#define PARS_FOR_TOKEN 294 -#define PARS_DDOT_TOKEN 295 -#define PARS_CONSISTENT_TOKEN 296 -#define PARS_READ_TOKEN 297 -#define PARS_ORDER_TOKEN 298 -#define PARS_BY_TOKEN 299 -#define PARS_ASC_TOKEN 300 -#define PARS_DESC_TOKEN 301 -#define PARS_INSERT_TOKEN 302 -#define PARS_INTO_TOKEN 303 -#define PARS_VALUES_TOKEN 304 -#define PARS_UPDATE_TOKEN 305 -#define PARS_SET_TOKEN 306 -#define PARS_DELETE_TOKEN 307 -#define PARS_CURRENT_TOKEN 308 -#define PARS_OF_TOKEN 309 -#define PARS_CREATE_TOKEN 310 -#define PARS_TABLE_TOKEN 311 -#define PARS_INDEX_TOKEN 312 -#define PARS_UNIQUE_TOKEN 313 -#define PARS_CLUSTERED_TOKEN 314 -#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315 -#define PARS_ON_TOKEN 316 -#define PARS_ASSIGN_TOKEN 317 -#define PARS_DECLARE_TOKEN 318 -#define PARS_CURSOR_TOKEN 319 -#define PARS_SQL_TOKEN 320 -#define PARS_OPEN_TOKEN 321 -#define PARS_FETCH_TOKEN 322 -#define PARS_CLOSE_TOKEN 323 -#define PARS_NOTFOUND_TOKEN 324 -#define PARS_TO_CHAR_TOKEN 325 -#define PARS_TO_NUMBER_TOKEN 326 -#define PARS_TO_BINARY_TOKEN 327 -#define PARS_BINARY_TO_NUMBER_TOKEN 328 -#define PARS_SUBSTR_TOKEN 329 -#define PARS_REPLSTR_TOKEN 330 -#define PARS_CONCAT_TOKEN 331 -#define PARS_INSTR_TOKEN 332 -#define PARS_LENGTH_TOKEN 333 -#define PARS_SYSDATE_TOKEN 334 -#define PARS_PRINTF_TOKEN 335 -#define PARS_ASSERT_TOKEN 336 -#define PARS_RND_TOKEN 337 -#define PARS_RND_STR_TOKEN 338 -#define PARS_ROW_PRINTF_TOKEN 339 -#define PARS_COMMIT_TOKEN 340 -#define PARS_ROLLBACK_TOKEN 341 -#define PARS_WORK_TOKEN 342 -#define NEG 343 +#define PARS_FIXBINARY_LIT 261 +#define PARS_BLOB_LIT 262 +#define PARS_NULL_LIT 263 +#define PARS_ID_TOKEN 264 +#define PARS_AND_TOKEN 265 +#define PARS_OR_TOKEN 266 +#define PARS_NOT_TOKEN 267 +#define PARS_GE_TOKEN 268 +#define PARS_LE_TOKEN 269 +#define PARS_NE_TOKEN 270 +#define PARS_PROCEDURE_TOKEN 271 +#define PARS_IN_TOKEN 272 +#define PARS_OUT_TOKEN 273 +#define PARS_BINARY_TOKEN 274 +#define PARS_BLOB_TOKEN 275 +#define PARS_INT_TOKEN 276 +#define PARS_INTEGER_TOKEN 277 +#define PARS_FLOAT_TOKEN 278 +#define PARS_CHAR_TOKEN 279 +#define PARS_IS_TOKEN 280 +#define PARS_BEGIN_TOKEN 281 +#define PARS_END_TOKEN 282 +#define PARS_IF_TOKEN 283 +#define PARS_THEN_TOKEN 284 +#define PARS_ELSE_TOKEN 285 +#define PARS_ELSIF_TOKEN 286 +#define PARS_LOOP_TOKEN 287 +#define PARS_WHILE_TOKEN 288 +#define PARS_RETURN_TOKEN 289 +#define PARS_SELECT_TOKEN 290 +#define PARS_SUM_TOKEN 291 +#define PARS_COUNT_TOKEN 292 +#define PARS_DISTINCT_TOKEN 293 +#define PARS_FROM_TOKEN 294 +#define PARS_WHERE_TOKEN 295 +#define PARS_FOR_TOKEN 296 +#define PARS_DDOT_TOKEN 297 +#define PARS_CONSISTENT_TOKEN 298 +#define PARS_READ_TOKEN 299 +#define PARS_ORDER_TOKEN 300 +#define PARS_BY_TOKEN 301 +#define PARS_ASC_TOKEN 302 +#define PARS_DESC_TOKEN 303 +#define PARS_INSERT_TOKEN 304 +#define PARS_INTO_TOKEN 305 +#define PARS_VALUES_TOKEN 306 +#define PARS_UPDATE_TOKEN 307 +#define PARS_SET_TOKEN 308 +#define PARS_DELETE_TOKEN 309 +#define PARS_CURRENT_TOKEN 310 +#define PARS_OF_TOKEN 311 +#define PARS_CREATE_TOKEN 312 +#define PARS_TABLE_TOKEN 313 +#define PARS_INDEX_TOKEN 314 +#define PARS_UNIQUE_TOKEN 315 +#define PARS_CLUSTERED_TOKEN 316 +#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317 +#define PARS_ON_TOKEN 318 +#define PARS_ASSIGN_TOKEN 319 +#define PARS_DECLARE_TOKEN 320 +#define PARS_CURSOR_TOKEN 321 +#define PARS_SQL_TOKEN 322 +#define PARS_OPEN_TOKEN 323 +#define PARS_FETCH_TOKEN 324 +#define PARS_CLOSE_TOKEN 325 +#define PARS_NOTFOUND_TOKEN 326 +#define PARS_TO_CHAR_TOKEN 327 +#define PARS_TO_NUMBER_TOKEN 328 +#define PARS_TO_BINARY_TOKEN 329 +#define PARS_BINARY_TO_NUMBER_TOKEN 330 +#define PARS_SUBSTR_TOKEN 331 +#define PARS_REPLSTR_TOKEN 332 +#define PARS_CONCAT_TOKEN 333 +#define PARS_INSTR_TOKEN 334 +#define PARS_LENGTH_TOKEN 335 +#define PARS_SYSDATE_TOKEN 336 +#define PARS_PRINTF_TOKEN 337 +#define PARS_ASSERT_TOKEN 338 +#define PARS_RND_TOKEN 339 +#define PARS_RND_STR_TOKEN 340 +#define PARS_ROW_PRINTF_TOKEN 341 +#define PARS_COMMIT_TOKEN 342 +#define PARS_ROLLBACK_TOKEN 343 +#define PARS_WORK_TOKEN 344 +#define PARS_UNSIGNED_TOKEN 345 +#define PARS_EXIT_TOKEN 346 +#define PARS_FUNCTION_TOKEN 347 +#define NEG 348 diff --git a/storage/innobase/pars/pars0grm.y b/storage/innobase/pars/pars0grm.y index 435025d7386..7f13312fc6e 100644 --- a/storage/innobase/pars/pars0grm.y +++ b/storage/innobase/pars/pars0grm.y @@ -29,10 +29,12 @@ que_node_t */ int yylex(void); %} - + %token PARS_INT_LIT %token PARS_FLOAT_LIT %token PARS_STR_LIT +%token PARS_FIXBINARY_LIT +%token PARS_BLOB_LIT %token PARS_NULL_LIT %token PARS_ID_TOKEN %token PARS_AND_TOKEN @@ -115,6 +117,9 @@ yylex(void); %token PARS_COMMIT_TOKEN %token PARS_ROLLBACK_TOKEN %token PARS_WORK_TOKEN +%token PARS_UNSIGNED_TOKEN +%token PARS_EXIT_TOKEN +%token PARS_FUNCTION_TOKEN %left PARS_AND_TOKEN PARS_OR_TOKEN %left PARS_NOT_TOKEN @@ -133,6 +138,7 @@ statement: | predefined_procedure_call ';' | while_statement ';' | for_statement ';' + | exit_statement ';' | if_statement ';' | return_statement ';' | assignment_statement ';' @@ -165,6 +171,8 @@ exp: | PARS_INT_LIT { $$ = $1;} | PARS_FLOAT_LIT { $$ = $1;} | PARS_STR_LIT { $$ = $1;} + | PARS_FIXBINARY_LIT { $$ = $1;} + | PARS_BLOB_LIT { $$ = $1;} | PARS_NULL_LIT { $$ = $1;} | PARS_SQL_TOKEN { $$ = $1;} | exp '+' exp { $$ = pars_op('+', $1, $3); } @@ -225,6 +233,10 @@ predefined_procedure_name: | PARS_ASSERT_TOKEN { $$ = &pars_assert_token; } ; +user_function_call: + PARS_ID_TOKEN '(' ')' { $$ = $1; } +; + table_list: PARS_ID_TOKEN { $$ = que_node_list_add_last(NULL, $1); } | table_list ',' PARS_ID_TOKEN @@ -262,14 +274,14 @@ select_item: que_node_list_add_last(NULL, $3)); } ; - + select_item_list: /* Nothing */ { $$ = NULL; } | select_item { $$ = que_node_list_add_last(NULL, $1); } | select_item_list ',' select_item { $$ = que_node_list_add_last($1, $3); } ; - + select_list: '*' { $$ = pars_select_list(&pars_star_denoter, NULL); } @@ -377,7 +389,7 @@ delete_statement_positioned: delete_statement_start cursor_positioned { $$ = pars_update_statement($1, $2, NULL); } ; - + row_printf_statement: PARS_ROW_PRINTF_TOKEN select_statement { $$ = pars_row_printf_statement($2); } @@ -428,6 +440,10 @@ for_statement: { $$ = pars_for_statement($2, $4, $6, $8); } ; +exit_statement: + PARS_EXIT_TOKEN { $$ = pars_exit_statement(); } +; + return_statement: PARS_RETURN_TOKEN { $$ = pars_return_statement(); } ; @@ -446,12 +462,14 @@ close_cursor_statement: fetch_statement: PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN variable_list - { $$ = pars_fetch_statement($2, $4); } + { $$ = pars_fetch_statement($2, $4, NULL); } + | PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN user_function_call + { $$ = pars_fetch_statement($2, NULL, $4); } ; column_def: - PARS_ID_TOKEN type_name opt_column_len opt_not_null - { $$ = pars_column_def($1, $2, $3, $4); } + PARS_ID_TOKEN type_name opt_column_len opt_unsigned opt_not_null + { $$ = pars_column_def($1, $2, $3, $4, $5); } ; column_def_list: @@ -466,6 +484,13 @@ opt_column_len: { $$ = $2; } ; +opt_unsigned: + /* Nothing */ { $$ = NULL; } + | PARS_UNSIGNED_TOKEN + { $$ = &pars_int_token; + /* pass any non-NULL pointer */ } +; + opt_not_null: /* Nothing */ { $$ = NULL; } | PARS_NOT_TOKEN PARS_NULL_LIT @@ -479,7 +504,7 @@ not_fit_in_memory: { $$ = &pars_int_token; /* pass any non-NULL pointer */ } ; - + create_table: PARS_CREATE_TOKEN PARS_TABLE_TOKEN PARS_ID_TOKEN '(' column_def_list ')' @@ -550,8 +575,8 @@ variable_declaration: ; variable_declaration_list: - /* Nothing */ - | variable_declaration + /* Nothing */ + | variable_declaration | variable_declaration_list variable_declaration ; @@ -561,10 +586,20 @@ cursor_declaration: { $$ = pars_cursor_declaration($3, $5); } ; +function_declaration: + PARS_DECLARE_TOKEN PARS_FUNCTION_TOKEN PARS_ID_TOKEN ';' + { $$ = pars_function_declaration($3); } +; + +declaration: + cursor_declaration + | function_declaration +; + declaration_list: /* Nothing */ - | cursor_declaration - | declaration_list cursor_declaration + | declaration + | declaration_list declaration ; procedure_definition: @@ -577,5 +612,5 @@ procedure_definition: PARS_END_TOKEN { $$ = pars_procedure_definition($2, $4, $10); } ; - + %% diff --git a/storage/innobase/pars/pars0lex.l b/storage/innobase/pars/pars0lex.l index 4224536d49e..ab1fe446924 100644 --- a/storage/innobase/pars/pars0lex.l +++ b/storage/innobase/pars/pars0lex.l @@ -12,27 +12,11 @@ not automatically generate them from pars0grm.y and pars0lex.l. How to make the InnoDB parser and lexer C files: -1. First do - bison -d pars0grm.y - That generates pars0grm.tab.c and pars0grm.tab.h. +1. Run ./make_flex.sh to generate lexer files. -2. Rename pars0grm.tab.c to pars0grm.c and pars0grm.tab.h to pars0grm.h. +2. Run ./make_bison.sh to generate parser files. -3. Copy pars0grm.h also to /innobase/include - -4. Do - flex pars0lex.l - That generates lex.yy.c. - -5. Rename lex.yy.c to lexyy.c. - -6. Add '#include "univ.i"' before #include in lexyy.c - (Needed for AIX) - -7. Add a type cast to int to the assignment below the comment - 'need more input.' (Removes a warning on Win64) - -These instructions seem to work at least with bison-1.28 and flex-2.5.4 on +These instructions seem to work at least with bison-1.875d and flex-2.5.31 on Linux. *******************************************************/ @@ -96,11 +80,14 @@ string_append( } %} - + DIGIT [0-9] ID [a-z_A-Z][a-z_A-Z0-9]* +BOUND_LIT \:[a-z_A-Z0-9]+ + %x comment %x quoted +%x id %% {DIGIT}+ { @@ -115,6 +102,15 @@ ID [a-z_A-Z][a-z_A-Z0-9]* return(PARS_FLOAT_LIT); } +{BOUND_LIT} { + ulint type; + + yylval = sym_tab_add_bound_lit(pars_sym_tab_global, + yytext + 1, &type); + + return(type); +} + "'" { /* Quoted character string literals are handled in an explicit start state 'quoted'. This state is entered and the buffer for @@ -153,6 +149,45 @@ In the state 'quoted', only two actions are possible (defined below). */ } } +\" { +/* Quoted identifiers are handled in an explicit start state 'id'. +This state is entered and the buffer for the scanned string is emptied +upon encountering a starting quote. + +In the state 'id', only two actions are possible (defined below). */ + BEGIN(id); + stringbuf_len = 0; +} +[^\"]+ { + /* Got a sequence of characters other than '"': + append to string buffer */ + string_append(yytext, yyleng); +} +\"+ { + /* Got a sequence of '"' characters: + append half of them to string buffer, + as '""' represents a single '"'. + We apply truncating division, + so that '"""' will result in '"'. */ + + string_append(yytext, yyleng / 2); + + /* If we got an odd number of quotes, then the + last quote we got is the terminating quote. + At the end of the string, we return to the + initial start state and report the scanned + identifier. */ + + if (yyleng % 2) { + BEGIN(INITIAL); + yylval = sym_tab_add_id( + pars_sym_tab_global, + (byte*) stringbuf, stringbuf_len); + + return(PARS_ID_TOKEN); + } +} + "NULL" { yylval = sym_tab_add_null_lit(pars_sym_tab_global); @@ -462,6 +497,18 @@ In the state 'quoted', only two actions are possible (defined below). */ return(PARS_WORK_TOKEN); } +"UNSIGNED" { + return(PARS_UNSIGNED_TOKEN); +} + +"EXIT" { + return(PARS_EXIT_TOKEN); +} + +"FUNCTION" { + return(PARS_FUNCTION_TOKEN); +} + {ID} { yylval = sym_tab_add_id(pars_sym_tab_global, (byte*)yytext, diff --git a/storage/innobase/pars/pars0opt.c b/storage/innobase/pars/pars0opt.c index bb41b5da074..4037f50cb5c 100644 --- a/storage/innobase/pars/pars0opt.c +++ b/storage/innobase/pars/pars0opt.c @@ -313,7 +313,6 @@ opt_calc_index_goodness( ulint goodness; ulint n_fields; ulint col_no; - ulint mix_id_col_no; ulint op; ulint j; @@ -326,8 +325,6 @@ opt_calc_index_goodness( n_fields = dict_index_get_n_unique_in_tree(index); - mix_id_col_no = dict_table_get_sys_col_no(index->table, DATA_MIX_ID); - for (j = 0; j < n_fields; j++) { col_no = dict_index_get_nth_col_no(index, j); @@ -335,13 +332,7 @@ opt_calc_index_goodness( exp = opt_look_for_col_in_cond_before(OPT_EQUAL, col_no, sel_node->search_cond, sel_node, nth_table, &op); - if (col_no == mix_id_col_no) { - ut_ad(exp == NULL); - - index_plan[j] = NULL; - *last_op = '='; - goodness += 4; - } else if (exp) { + if (exp) { /* The value for this column is exactly known already at this stage of the join */ @@ -531,7 +522,6 @@ opt_search_plan_for_table( warning */ ulint best_goodness; ulint best_last_op = 0; /* remove warning */ - ulint mix_id_pos; que_node_t* index_plan[256]; que_node_t* best_index_plan[256]; @@ -601,26 +591,6 @@ opt_search_plan_for_table( plan->unique_search = FALSE; } - if ((table->type != DICT_TABLE_ORDINARY) - && (best_index->type & DICT_CLUSTERED)) { - - plan->mixed_index = TRUE; - - mix_id_pos = table->mix_len; - - if (mix_id_pos < n_fields) { - /* We have to add the mix id as a (string) literal - expression to the tuple_exps */ - - plan->tuple_exps[mix_id_pos] = - sym_tab_add_str_lit(pars_sym_tab_global, - table->mix_id_buf, - table->mix_id_len); - } - } else { - plan->mixed_index = FALSE; - } - plan->old_vers_heap = NULL; btr_pcur_init(&(plan->pcur)); @@ -1055,7 +1025,6 @@ opt_clust_access( dict_table_t* table; dict_index_t* clust_index; dict_index_t* index; - dfield_t* dfield; mem_heap_t* heap; ulint n_fields; ulint pos; @@ -1109,22 +1078,7 @@ opt_clust_access( *(plan->clust_map + i) = pos; - ut_ad((pos != ULINT_UNDEFINED) - || ((table->type == DICT_TABLE_CLUSTER_MEMBER) - && (i == table->mix_len))); - } - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* Preset the mix id field to the mix id constant */ - - dfield = dtuple_get_nth_field(plan->clust_ref, table->mix_len); - - dfield_set_data(dfield, mem_heap_alloc(heap, - table->mix_id_len), - table->mix_id_len); - ut_memcpy(dfield_get_data(dfield), table->mix_id_buf, - table->mix_id_len); + ut_ad(pos != ULINT_UNDEFINED); } } diff --git a/storage/innobase/pars/pars0pars.c b/storage/innobase/pars/pars0pars.c index 1b7a3a653a9..7ef2f65c724 100644 --- a/storage/innobase/pars/pars0pars.c +++ b/storage/innobase/pars/pars0pars.c @@ -373,14 +373,15 @@ pars_resolve_exp_variables_and_types( } /* Not resolved yet: look in the symbol table for a variable - or a cursor with the same name */ + or a cursor or a function with the same name */ node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list); while (node) { if (node->resolved && ((node->token_type == SYM_VAR) - || (node->token_type == SYM_CURSOR)) + || (node->token_type == SYM_CURSOR) + || (node->token_type == SYM_FUNCTION)) && node->name && (sym_node->name_len == node->name_len) && (ut_memcmp(sym_node->name, node->name, @@ -486,7 +487,7 @@ pars_resolve_exp_columns( while (t_node) { table = t_node->table; - n_cols = dict_table_get_n_user_cols(table); + n_cols = dict_table_get_n_cols(table); for (i = 0; i < n_cols; i++) { col = dict_table_get_nth_col(table, i); @@ -786,6 +787,26 @@ pars_cursor_declaration( return(sym_node); } +/************************************************************************* +Parses a function declaration. */ + +que_node_t* +pars_function_declaration( +/*======================*/ + /* out: sym_node */ + sym_node_t* sym_node) /* in: function id node in the symbol + table */ +{ + sym_node->resolved = TRUE; + sym_node->token_type = SYM_FUNCTION; + + /* Check that the function exists. */ + ut_a(pars_info_get_user_func(pars_sym_tab_global->info, + sym_node->name)); + + return(sym_node); +} + /************************************************************************* Parses a delete or update statement start. */ @@ -1085,6 +1106,8 @@ pars_set_dfield_type( pars_res_word_t* type, /* in: pointer to a type token */ ulint len, /* in: length, or 0 */ + ibool is_unsigned, /* in: if TRUE, column is + UNSIGNED. */ ibool is_not_null) /* in: if TRUE, column is NOT NULL. */ { @@ -1094,48 +1117,30 @@ pars_set_dfield_type( flags |= DATA_NOT_NULL; } + if (is_unsigned) { + flags |= DATA_UNSIGNED; + } + if (type == &pars_int_token) { - if (len != 0) { - ut_error; - } + ut_a(len == 0); dtype_set(dfield_get_type(dfield), DATA_INT, flags, 4, 0); } else if (type == &pars_char_token) { - if (len != 0) { - ut_error; - } + ut_a(len == 0); dtype_set(dfield_get_type(dfield), DATA_VARCHAR, DATA_ENGLISH | flags, 0, 0); } else if (type == &pars_binary_token) { - if (len == 0) { - ut_error; - } + ut_a(len != 0); dtype_set(dfield_get_type(dfield), DATA_FIXBINARY, DATA_BINARY_TYPE | flags, len, 0); } else if (type == &pars_blob_token) { - if (len != 0) { - ut_error; - } + ut_a(len == 0); dtype_set(dfield_get_type(dfield), DATA_BLOB, DATA_BINARY_TYPE | flags, 0, 0); - } else if (type == &pars_binary_token) { - if (len == 0) { - ut_error; - } - - dtype_set(dfield_get_type(dfield), DATA_FIXBINARY, - DATA_BINARY_TYPE, len, 0); - } else if (type == &pars_blob_token) { - if (len != 0) { - ut_error; - } - - dtype_set(dfield_get_type(dfield), DATA_BLOB, - DATA_BINARY_TYPE, 0, 0); } else { ut_error; } @@ -1158,7 +1163,7 @@ pars_variable_declaration( node->param_type = PARS_NOT_PARAM; - pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE); + pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE, FALSE); return(node); } @@ -1346,6 +1351,22 @@ pars_for_statement( return(node); } +/************************************************************************* +Parses an exit statement. */ + +exit_node_t* +pars_exit_statement(void) +/*=====================*/ + /* out: exit statement node */ +{ + exit_node_t* node; + + node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(exit_node_t)); + node->common.type = QUE_NODE_EXIT; + + return(node); +} + /************************************************************************* Parses a return-statement. */ @@ -1411,26 +1432,42 @@ pars_procedure_call( } /************************************************************************* -Parses a fetch statement. */ +Parses a fetch statement. into_list or user_func (but not both) must be +non-NULL. */ fetch_node_t* pars_fetch_statement( /*=================*/ /* out: fetch statement node */ sym_node_t* cursor, /* in: cursor node */ - sym_node_t* into_list) /* in: variables to set */ + sym_node_t* into_list, /* in: variables to set, or NULL */ + sym_node_t* user_func) /* in: user function name, or NULL */ { sym_node_t* cursor_decl; fetch_node_t* node; + /* Logical XOR. */ + ut_a(!into_list != !user_func); + node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(fetch_node_t)); node->common.type = QUE_NODE_FETCH; pars_resolve_exp_variables_and_types(NULL, cursor); - pars_resolve_exp_list_variables_and_types(NULL, into_list); - node->into_list = into_list; + if (into_list) { + pars_resolve_exp_list_variables_and_types(NULL, into_list); + node->into_list = into_list; + node->func = NULL; + } else { + pars_resolve_exp_variables_and_types(NULL, user_func); + + node->func = pars_info_get_user_func(pars_sym_tab_global->info, + user_func->name); + ut_a(node->func); + + node->into_list = NULL; + } cursor_decl = cursor->alias; @@ -1438,8 +1475,11 @@ pars_fetch_statement( node->cursor_def = cursor_decl->cursor_def; - ut_a(que_node_list_get_len(into_list) - == que_node_list_get_len(node->cursor_def->select_list)); + if (into_list) { + ut_a(que_node_list_get_len(into_list) + == que_node_list_get_len( + node->cursor_def->select_list)); + } return(node); } @@ -1529,6 +1569,8 @@ pars_column_def( pars_res_word_t* type, /* in: data type */ sym_node_t* len, /* in: length of column, or NULL */ + void* is_unsigned, /* in: if not NULL, column + is of type UNSIGNED. */ void* is_not_null) /* in: if not NULL, column is of type NOT NULL. */ { @@ -1541,7 +1583,7 @@ pars_column_def( } pars_set_dfield_type(que_node_get_val(sym_node), type, len2, - is_not_null != NULL); + is_unsigned != NULL, is_not_null != NULL); return(sym_node); } @@ -1798,6 +1840,7 @@ que_t* pars_sql( /*=====*/ /* out, own: the query graph */ + pars_info_t* info, /* in: extra information, or NULL */ const char* str) /* in: SQL string */ { sym_node_t* sym_node; @@ -1817,6 +1860,7 @@ pars_sql( pars_sym_tab_global->sql_string = mem_heap_strdup(heap, str); pars_sym_tab_global->string_len = strlen(str); pars_sym_tab_global->next_char_pos = 0; + pars_sym_tab_global->info = info; yyparse(); @@ -1831,6 +1875,7 @@ pars_sql( graph = pars_sym_tab_global->query_graph; graph->sym_tab = pars_sym_tab_global; + graph->info = info; /* fprintf(stderr, "SQL graph size %lu\n", mem_heap_get_size(heap)); */ @@ -1867,3 +1912,222 @@ pars_complete_graph_for_exec( return(thr); } + +/******************************************************************** +Create parser info struct.*/ + +pars_info_t* +pars_info_create(void) +/*==================*/ + /* out, own: info struct */ +{ + pars_info_t* info; + mem_heap_t* heap; + + heap = mem_heap_create(512); + + info = mem_heap_alloc(heap, sizeof(*info)); + + info->heap = heap; + info->funcs = NULL; + info->bound_lits = NULL; + info->graph_owns_us = TRUE; + + return(info); +} + +/******************************************************************** +Free info struct and everything it contains.*/ + +void +pars_info_free( +/*===========*/ + pars_info_t* info) /* in: info struct */ +{ + mem_heap_free(info->heap); +} + +/******************************************************************** +Add bound literal. */ + +void +pars_info_add_literal( +/*==================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const void* address, /* in: address */ + ulint length, /* in: length of data */ + ulint type, /* in: type, e.g. DATA_FIXBINARY */ + ulint prtype) /* in: precise type, e.g. + DATA_UNSIGNED */ +{ + pars_bound_lit_t* pbl; + + ut_ad(!pars_info_get_bound_lit(info, name)); + + pbl = mem_heap_alloc(info->heap, sizeof(*pbl)); + + pbl->name = name; + pbl->address = address; + pbl->length = length; + pbl->type = type; + pbl->prtype = prtype; + + if (!info->bound_lits) { + info->bound_lits = ib_vector_create(info->heap, 8); + } + + ib_vector_push(info->bound_lits, pbl); +} + +/******************************************************************** +Equivalent to pars_info_add_literal(info, name, str, strlen(str), +DATA_VARCHAR, DATA_ENGLISH). */ + +void +pars_info_add_str_literal( +/*======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const char* str) /* in: string */ +{ + pars_info_add_literal(info, name, str, strlen(str), + DATA_VARCHAR, DATA_ENGLISH); +} + +/******************************************************************** +Equivalent to: + +char buf[4]; +mach_write_to_4(buf, val); +pars_info_add_literal(info, name, buf, 4, DATA_INT, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_int4_literal( +/*=======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + lint val) /* in: value */ +{ + byte* buf = mem_heap_alloc(info->heap, 4); + + mach_write_to_4(buf, val); + pars_info_add_literal(info, name, buf, 4, DATA_INT, 0); +} + +/******************************************************************** +Equivalent to: + +char buf[8]; +mach_write_to_8(buf, val); +pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_dulint_literal( +/*=========================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + dulint val) /* in: value */ +{ + byte* buf = mem_heap_alloc(info->heap, 8); + + mach_write_to_8(buf, val); + + pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0); +} + +/******************************************************************** +Add user function. */ + +void +pars_info_add_function( +/*===================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: function name */ + pars_user_func_cb_t func, /* in: function address */ + void* arg) /* in: user-supplied argument */ +{ + pars_user_func_t* puf; + + ut_ad(!pars_info_get_user_func(info, name)); + + puf = mem_heap_alloc(info->heap, sizeof(*puf)); + + puf->name = name; + puf->func = func; + puf->arg = arg; + + if (!info->funcs) { + info->funcs = ib_vector_create(info->heap, 8); + } + + ib_vector_push(info->funcs, puf); +} + +/******************************************************************** +Get user function with the given name.*/ + +pars_user_func_t* +pars_info_get_user_func( +/*====================*/ + /* out: user func, or NULL if not + found */ + pars_info_t* info, /* in: info struct */ + const char* name) /* in: function name to find*/ +{ + ulint i; + ib_vector_t* vec; + + if (!info || !info->funcs) { + return(NULL); + } + + vec = info->funcs; + + for (i = 0; i < ib_vector_size(vec); i++) { + pars_user_func_t* puf = ib_vector_get(vec, i); + + if (strcmp(puf->name, name) == 0) { + return(puf); + } + } + + return(NULL); +} + +/******************************************************************** +Get bound literal with the given name.*/ + +pars_bound_lit_t* +pars_info_get_bound_lit( +/*====================*/ + /* out: bound literal, or NULL if + not found */ + pars_info_t* info, /* in: info struct */ + const char* name) /* in: bound literal name to find */ +{ + ulint i; + ib_vector_t* vec; + + if (!info || !info->bound_lits) { + return(NULL); + } + + vec = info->bound_lits; + + for (i = 0; i < ib_vector_size(vec); i++) { + pars_bound_lit_t* pbl = ib_vector_get(vec, i); + + if (strcmp(pbl->name, name) == 0) { + return(pbl); + } + } + + return(NULL); +} diff --git a/storage/innobase/pars/pars0sym.c b/storage/innobase/pars/pars0sym.c index d8025998f9a..79a1e555b06 100644 --- a/storage/innobase/pars/pars0sym.c +++ b/storage/innobase/pars/pars0sym.c @@ -15,6 +15,7 @@ Created 12/15/1997 Heikki Tuuri #include "mem0mem.h" #include "data0type.h" #include "data0data.h" +#include "pars0grm.h" #include "pars0pars.h" #include "que0que.h" #include "eval0eval.h" @@ -165,6 +166,74 @@ sym_tab_add_str_lit( return(node); } +/********************************************************************** +Add a bound literal to a symbol table. */ + +sym_node_t* +sym_tab_add_bound_lit( +/*==================*/ + /* out: symbol table node */ + sym_tab_t* sym_tab, /* in: symbol table */ + const char* name, /* in: name of bound literal */ + ulint* lit_type) /* out: type of literal (PARS_*_LIT) */ +{ + sym_node_t* node; + pars_bound_lit_t* blit; + ulint len = 0; + + blit = pars_info_get_bound_lit(sym_tab->info, name); + ut_a(blit); + + node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t)); + + node->common.type = QUE_NODE_SYMBOL; + + node->resolved = TRUE; + node->token_type = SYM_LIT; + + node->indirection = NULL; + + switch (blit->type) { + case DATA_FIXBINARY: + len = blit->length; + *lit_type = PARS_FIXBINARY_LIT; + break; + + case DATA_BLOB: + *lit_type = PARS_BLOB_LIT; + break; + + case DATA_VARCHAR: + *lit_type = PARS_STR_LIT; + break; + + case DATA_INT: + ut_a(blit->length > 0); + ut_a(blit->length <= 8); + + len = blit->length; + *lit_type = PARS_INT_LIT; + break; + + default: + ut_error; + } + + dtype_set(&(node->common.val.type), blit->type, blit->prtype, len, 0); + + dfield_set_data(&(node->common.val), blit->address, blit->length); + + node->common.val_buf_size = 0; + node->prefetch_buf = NULL; + node->cursor_def = NULL; + + UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); + + node->sym_table = sym_tab; + + return(node); +} + /********************************************************************** Adds an SQL null literal to a symbol table. */ @@ -220,7 +289,7 @@ sym_tab_add_id( node->resolved = FALSE; node->indirection = NULL; - node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len + 1); + node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len); node->name_len = len; UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); diff --git a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c index e048b94cdc5..59d90eb7e29 100644 --- a/storage/innobase/que/que0que.c +++ b/storage/innobase/que/que0que.c @@ -25,6 +25,7 @@ Created 5/27/1996 Heikki Tuuri #include "log0log.h" #include "eval0proc.h" #include "eval0eval.h" +#include "pars0types.h" #define QUE_PARALLELIZE_LIMIT (64 * 256 * 256 * 256) #define QUE_ROUND_ROBIN_LIMIT (64 * 256 * 256 * 256) @@ -36,6 +37,50 @@ ibool que_trace_on = FALSE; ibool que_always_false = FALSE; +/* Short introduction to query graphs + ================================== + +A query graph consists of nodes linked to each other in various ways. The +execution starts at que_run_threads() which takes a que_thr_t parameter. +que_thr_t contains two fields that control query graph execution: run_node +and prev_node. run_node is the next node to execute and prev_node is the +last node executed. + +Each node has a pointer to a 'next' statement, i.e., its brother, and a +pointer to its parent node. The next pointer is NULL in the last statement +of a block. + +Loop nodes contain a link to the first statement of the enclosed statement +list. While the loop runs, que_thr_step() checks if execution to the loop +node came from its parent or from one of the statement nodes in the loop. If +it came from the parent of the loop node it starts executing the first +statement node in the loop. If it came from one of the statement nodes in +the loop, then it checks if the statement node has another statement node +following it, and runs it if so. + +To signify loop ending, the loop statements (see e.g. while_step()) set +que_thr_t->run_node to the loop node's parent node. This is noticed on the +next call of que_thr_step() and execution proceeds to the node pointed to by +the loop node's 'next' pointer. + +For example, the code: + +X := 1; +WHILE X < 5 LOOP + X := X + 1; + X := X + 1; +X := 5 + +will result in the following node hierarchy, with the X-axis indicating +'next' links and the Y-axis indicating parent/child links: + +A - W - A + | + | + A - A + +A = assign_node_t, W = while_node_t. */ + /* How a stored procedure containing COMMIT or ROLLBACK commands is executed? @@ -128,6 +173,7 @@ que_fork_create( UT_LIST_INIT(fork->thrs); fork->sym_tab = NULL; + fork->info = NULL; fork->heap = heap; @@ -583,6 +629,7 @@ que_graph_free_recursive( break; case QUE_NODE_ASSIGNMENT: + case QUE_NODE_EXIT: case QUE_NODE_RETURN: case QUE_NODE_COMMIT: case QUE_NODE_ROLLBACK: @@ -626,6 +673,10 @@ que_graph_free( sym_tab_free_private(graph->sym_tab); } + if (graph->info && graph->info->graph_owns_us) { + pars_info_free(graph->info); + } + que_graph_free_recursive(graph); mem_heap_free(graph->heap); @@ -1040,6 +1091,37 @@ que_thr_stop_for_mysql_no_error( trx->n_active_thrs--; } +/******************************************************************** +Get the first containing loop node (e.g. while_node_t or for_node_t) for the +given node, or NULL if the node is not within a loop. */ + +que_node_t* +que_node_get_containing_loop_node( +/*==============================*/ + /* out: containing loop node, or NULL. */ + que_node_t* node) /* in: node */ +{ + ut_ad(node); + + for (;;) { + ulint type; + + node = que_node_get_parent(node); + + if (!node) { + break; + } + + type = que_node_get_type(node); + + if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) { + break; + } + } + + return(node); +} + /************************************************************************** Prints info of an SQL query graph node. */ @@ -1093,6 +1175,8 @@ que_node_print_info( str = "FOR LOOP"; } else if (type == QUE_NODE_RETURN) { str = "RETURN"; + } else if (type == QUE_NODE_EXIT) { + str = "EXIT"; } else { str = "UNKNOWN NODE TYPE"; } @@ -1120,8 +1204,8 @@ que_thr_step( thr->resource++; - type = que_node_get_type(thr->run_node); node = thr->run_node; + type = que_node_get_type(node); old_thr = thr; @@ -1160,6 +1244,8 @@ que_thr_step( proc_step(thr); } else if (type == QUE_NODE_WHILE) { while_step(thr); + } else { + ut_error; } } else if (type == QUE_NODE_ASSIGNMENT) { assign_step(thr); @@ -1192,6 +1278,8 @@ que_thr_step( thr = row_purge_step(thr); } else if (type == QUE_NODE_RETURN) { thr = return_step(thr); + } else if (type == QUE_NODE_EXIT) { + thr = exit_step(thr); } else if (type == QUE_NODE_ROLLBACK) { thr = trx_rollback_step(thr); } else if (type == QUE_NODE_CREATE_TABLE) { @@ -1204,7 +1292,11 @@ que_thr_step( ut_error; } - old_thr->prev_node = node; + if (type == QUE_NODE_EXIT) { + old_thr->prev_node = que_node_get_containing_loop_node(node); + } else { + old_thr->prev_node = node; + } return(thr); } @@ -1274,3 +1366,33 @@ loop: goto loop; } + +/************************************************************************* +Evaluate the given SQL */ + +ulint +que_eval_sql( +/*=========*/ + pars_info_t* info, /* out: error code or DB_SUCCESS */ + const char* sql, /* in: info struct, or NULL */ + trx_t* trx) /* in: trx */ +{ + que_thr_t* thr; + que_t* graph; + + graph = pars_sql(info, sql); + ut_a(graph); + + graph->trx = trx; + trx->graph = NULL; + + graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + + ut_a(thr = que_fork_start_command(graph)); + + que_run_threads(thr); + + que_graph_free(graph); + + return(trx->error_state); +} diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index c80a61cc729..e47d6a621a7 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -28,6 +28,7 @@ Created 4/20/1996 Heikki Tuuri #include "eval0eval.h" #include "data0data.h" #include "usr0sess.h" +#include "buf0lru.h" #define ROW_INS_PREV 1 #define ROW_INS_NEXT 2 @@ -139,7 +140,6 @@ row_ins_alloc_sys_fields( mem_heap_t* heap; dict_col_t* col; dfield_t* dfield; - ulint len; byte* ptr; row = node->row; @@ -161,21 +161,6 @@ row_ins_alloc_sys_fields( node->row_id_buf = ptr; - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* 2. Fill in the dfield for mix id */ - - col = dict_table_get_sys_col(table, DATA_MIX_ID); - - dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); - - len = mach_dulint_get_compressed_size(table->mix_id); - ptr = mem_heap_alloc(heap, DATA_MIX_ID_LEN); - - mach_dulint_write_compressed(ptr, table->mix_id); - dfield_set_data(dfield, ptr, len); - } - /* 3. Allocate buffer for trx id */ col = dict_table_get_sys_col(table, DATA_TRX_ID); @@ -279,10 +264,17 @@ row_ins_sec_index_entry_by_modify( } } else { ut_a(mode == BTR_MODIFY_TREE); + if (buf_LRU_buf_pool_running_out()) { + + err = DB_LOCK_TABLE_FULL; + + goto func_exit; + } + err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, &dummy_big_rec, update, 0, thr, mtr); } - +func_exit: mem_heap_free(heap); return(err); @@ -344,10 +336,16 @@ row_ins_clust_index_entry_by_modify( } } else { ut_a(mode == BTR_MODIFY_TREE); + if (buf_LRU_buf_pool_running_out()) { + + err = DB_LOCK_TABLE_FULL; + + goto func_exit; + } err = btr_cur_pessimistic_update(0, cursor, big_rec, update, 0, thr, mtr); } - +func_exit: mem_heap_free(heap); return(err); @@ -1882,7 +1880,6 @@ row_ins_duplicate_error_in_clust( err = DB_DUPLICATE_KEY; goto func_exit; } - mem_heap_free(heap); } ut_a(!(cursor->index->type & DICT_CLUSTERED)); @@ -1891,6 +1888,9 @@ row_ins_duplicate_error_in_clust( err = DB_SUCCESS; func_exit: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } return(err); #else /* UNIV_HOTBACKUP */ /* This function depends on MySQL code that is not included in @@ -2091,6 +2091,12 @@ row_ins_index_entry_low( &insert_rec, &big_rec, thr, &mtr); } else { ut_a(mode == BTR_MODIFY_TREE); + if (buf_LRU_buf_pool_running_out()) { + + err = DB_LOCK_TABLE_FULL; + + goto function_exit; + } err = btr_cur_pessimistic_insert(0, &cursor, entry, &insert_rec, &big_rec, thr, &mtr); } @@ -2429,7 +2435,15 @@ row_ins_step( /* If this is the first time this node is executed (or when execution resumes after wait for the table IX lock), set an - IX lock on the table and reset the possible select node. */ + IX lock on the table and reset the possible select node. MySQL's + partitioned table code may also call an insert within the same + SQL statement AFTER it has used this table handle to do a search. + This happens, for example, when a row update moves it to another + partition. In that case, we have already set the IX lock on the + table during the search operation, and there is no need to set + it again here. But we must write trx->id to node->trx_id_buf. */ + + trx_write_trx_id(node->trx_id_buf, trx->id); if (node->state == INS_NODE_SET_IX_LOCK) { @@ -2437,13 +2451,11 @@ row_ins_step( its transaction, or it has been committed: */ if (UT_DULINT_EQ(trx->id, node->trx_id)) { - /* No need to do IX-locking or write trx id to buf */ + /* No need to do IX-locking */ goto same_trx; } - trx_write_trx_id(node->trx_id_buf, trx->id); - err = lock_table(0, node->table, LOCK_IX, thr); if (err != DB_SUCCESS) { diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 4dbe5128974..56574618f9a 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -85,9 +85,11 @@ row_mysql_is_system_table( system table name */ const char* name) { - if (memcmp(name, "mysql/", 6)) { + if (strncmp(name, "mysql/", 6) != 0) { + return(FALSE); } + return(0 == strcmp(name + 6, "host") || 0 == strcmp(name + 6, "user") || 0 == strcmp(name + 6, "db")); @@ -1435,7 +1437,8 @@ run_again: } /************************************************************************* -This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +This can only be used when srv_locks_unsafe_for_binlog is TRUE or +this session is using a READ COMMITTED isolation level. Before calling this function we must use trx_reset_new_rec_lock_info() and trx_register_new_rec_lock() to store the information which new record locks really were set. This function removes a newly set lock under prebuilt->pcur, @@ -1466,11 +1469,13 @@ row_unlock_for_mysql( ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - if (!srv_locks_unsafe_for_binlog) { + if (!(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED)) { fprintf(stderr, "InnoDB: Error: calling row_unlock_for_mysql though\n" -"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n"); +"InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n" +"InnoDB: this session is not using READ COMMITTED isolation level.\n"); return(DB_SUCCESS); } @@ -1670,7 +1675,9 @@ row_mysql_recover_tmp_table( if (!ptr) { /* table name does not begin with "/rsql" */ + dict_mem_table_free(table); trx_commit_for_mysql(trx); + return(DB_ERROR); } else { @@ -1782,6 +1789,7 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; + ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1799,6 +1807,7 @@ row_create_table_for_mysql( "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); + dict_mem_table_free(table); trx_commit_for_mysql(trx); return(DB_ERROR); @@ -1813,11 +1822,25 @@ row_create_table_for_mysql( "InnoDB: MySQL system tables must be of the MyISAM type!\n", table->name); + dict_mem_table_free(table); trx_commit_for_mysql(trx); return(DB_ERROR); } + /* Check that no reserved column names are used. */ + for (i = 0; i < dict_table_get_n_user_cols(table); i++) { + dict_col_t* col = dict_table_get_nth_col(table, i); + + if (dict_col_name_is_reserved(col->name)) { + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + return(DB_ERROR); + } + } + trx_start_if_not_started(trx); if (row_mysql_is_recovered_tmp_table(table->name)) { @@ -2361,11 +2384,9 @@ row_discard_tablespace_for_mysql( dict_foreign_t* foreign; dulint new_id; dict_table_t* table; - que_thr_t* thr; - que_t* graph = NULL; ibool success; ulint err; - char* buf; + pars_info_t* info = NULL; /* How do we prevent crashes caused by ongoing operations on the table? Old operations could try to access non-existent pages. @@ -2387,36 +2408,6 @@ discard ongoing operations. 5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we do not allow the discard. We also reserve the data dictionary latch. */ - static const char discard_tablespace_proc1[] = - "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" - "old_id CHAR;\n" - "new_id CHAR;\n" - "new_id_low INT;\n" - "new_id_high INT;\n" - "table_name CHAR;\n" - "BEGIN\n" - "table_name := '"; - static const char discard_tablespace_proc2[] = - "';\n" - "new_id_high := %lu;\n" - "new_id_low := %lu;\n" - "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n" - "SELECT ID INTO old_id\n" - "FROM SYS_TABLES\n" - "WHERE NAME = table_name;\n" - "IF (SQL %% NOTFOUND) THEN\n" - " COMMIT WORK;\n" - " RETURN;\n" - "END IF;\n" - "UPDATE SYS_TABLES SET ID = new_id\n" - "WHERE ID = old_id;\n" - "UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "UPDATE SYS_INDEXES SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "COMMIT WORK;\n" - "END;\n"; - ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); trx->op_info = "discarding tablespace"; @@ -2496,35 +2487,34 @@ do not allow the discard. We also reserve the data dictionary latch. */ new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - buf = mem_alloc((sizeof discard_tablespace_proc1) + - (sizeof discard_tablespace_proc2) + - 20 + ut_strlenq(name, '\'')); - - memcpy(buf, discard_tablespace_proc1, sizeof discard_tablespace_proc1); - sprintf(ut_strcpyq(buf + (sizeof discard_tablespace_proc1 - 1), - '\'', name), - discard_tablespace_proc2, - (ulong) ut_dulint_get_high(new_id), - (ulong) ut_dulint_get_low(new_id)); - - graph = pars_sql(buf); - - ut_a(graph); - /* Remove any locks there are on the table or its records */ - lock_reset_all_on_table(table); - graph->trx = trx; - trx->graph = NULL; + info = pars_info_create(); - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + pars_info_add_str_literal(info, "table_name", name); + pars_info_add_dulint_literal(info, "new_id", new_id); - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - err = trx->error_state; + err = que_eval_sql(info, + "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" + "old_id CHAR;\n" + "BEGIN\n" + "SELECT ID INTO old_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = :table_name;\n" + "IF (SQL % NOTFOUND) THEN\n" + " COMMIT WORK;\n" + " RETURN;\n" + "END IF;\n" + "UPDATE SYS_TABLES SET ID = :new_id\n" + " WHERE ID = old_id;\n" + "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = old_id;\n" + "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = old_id;\n" + "COMMIT WORK;\n" + "END;\n" + , trx); if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; @@ -2548,13 +2538,10 @@ do not allow the discard. We also reserve the data dictionary latch. */ table->ibd_file_missing = TRUE; } } + funct_exit: row_mysql_unlock_data_dictionary(trx); - if (graph) { - que_graph_free(graph); - } - trx_commit_for_mysql(trx); trx->op_info = ""; @@ -2715,9 +2702,7 @@ row_truncate_table_for_mysql( btr_pcur_t pcur; mtr_t mtr; dulint new_id; - char* sql; - que_thr_t* thr; - que_t* graph = NULL; + pars_info_t* info = NULL; /* How do we prevent crashes caused by ongoing operations on the table? Old operations could try to access non-existent pages. @@ -2745,30 +2730,6 @@ by DISCARD TABLESPACE.) 5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we do not allow the TRUNCATE. We also reserve the data dictionary latch. */ - static const char renumber_tablespace_proc[] = - "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n" - "old_id CHAR;\n" - "new_id CHAR;\n" - "old_id_low INT;\n" - "old_id_high INT;\n" - "new_id_low INT;\n" - "new_id_high INT;\n" - "BEGIN\n" - "old_id_high := %lu;\n" - "old_id_low := %lu;\n" - "new_id_high := %lu;\n" - "new_id_low := %lu;\n" - "old_id := CONCAT(TO_BINARY(old_id_high, 4), TO_BINARY(old_id_low, 4));\n" - "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n" - "UPDATE SYS_TABLES SET ID = new_id\n" - "WHERE ID = old_id;\n" - "UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "UPDATE SYS_INDEXES SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "COMMIT WORK;\n" - "END;\n"; - ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(table); @@ -2929,35 +2890,27 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ btr_pcur_close(&pcur); mtr_commit(&mtr); - new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - - mem_heap_empty(heap); - sql = mem_heap_alloc(heap, (sizeof renumber_tablespace_proc) + 40); - sprintf(sql, renumber_tablespace_proc, - (ulong) ut_dulint_get_high(table->id), - (ulong) ut_dulint_get_low(table->id), - (ulong) ut_dulint_get_high(new_id), - (ulong) ut_dulint_get_low(new_id)); - - graph = pars_sql(sql); - - ut_a(graph); - mem_heap_free(heap); - graph->trx = trx; - trx->graph = NULL; + new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + info = pars_info_create(); - thr = que_fork_start_command(graph); - ut_a(thr); + pars_info_add_dulint_literal(info, "old_id", table->id); + pars_info_add_dulint_literal(info, "new_id", new_id); - que_run_threads(thr); - - que_graph_free(graph); - - err = trx->error_state; + err = que_eval_sql(info, + "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n" + "BEGIN\n" + "UPDATE SYS_TABLES SET ID = :new_id\n" + " WHERE ID = :old_id;\n" + "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = :old_id;\n" + "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = :old_id;\n" + "COMMIT WORK;\n" + "END;\n" + , trx); if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; @@ -3007,83 +2960,13 @@ row_drop_table_for_mysql( dict_foreign_t* foreign; dict_table_t* table; ulint space_id; - que_thr_t* thr; - que_t* graph; ulint err; const char* table_name; ulint namelen; char* dir_path_of_temp_table = NULL; ibool success; ibool locked_dictionary = FALSE; - char* quoted_name; - char* sql; - - /* We use the private SQL parser of Innobase to generate the - query graphs needed in deleting the dictionary data from system - tables in Innobase. Deleting a row from SYS_INDEXES table also - frees the file segments of the B-tree associated with the index. */ - - static const char str1[] = - "PROCEDURE DROP_TABLE_PROC () IS\n" - "table_name CHAR;\n" - "sys_foreign_id CHAR;\n" - "table_id CHAR;\n" - "index_id CHAR;\n" - "foreign_id CHAR;\n" - "found INT;\n" - "BEGIN\n" - "table_name := "; - static const char str2[] = - ";\n" - "SELECT ID INTO table_id\n" - "FROM SYS_TABLES\n" - "WHERE NAME = table_name;\n" - "IF (SQL % NOTFOUND) THEN\n" - " COMMIT WORK;\n" - " RETURN;\n" - "END IF;\n" - "found := 1;\n" - "SELECT ID INTO sys_foreign_id\n" - "FROM SYS_TABLES\n" - "WHERE NAME = 'SYS_FOREIGN';\n" - "IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - "END IF;\n" - "IF (table_name = 'SYS_FOREIGN') THEN\n" - " found := 0;\n" - "END IF;\n" - "IF (table_name = 'SYS_FOREIGN_COLS') THEN\n" - " found := 0;\n" - "END IF;\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = table_name\n" - " AND TO_BINARY(FOR_NAME) = TO_BINARY(table_name);\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE" - " DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n" - " DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n" - " END IF;\n" - "END LOOP;\n" - "found := 1;\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO index_id\n" - " FROM SYS_INDEXES\n" - " WHERE TABLE_ID = table_id;\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE" - " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n" - " DELETE FROM SYS_INDEXES WHERE ID = index_id\n" - " AND TABLE_ID = table_id;\n" - " END IF;\n" - "END LOOP;\n" - "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n" - "DELETE FROM SYS_TABLES WHERE ID = table_id;\n" - "COMMIT WORK;\n" - "END;\n"; + pars_info_t* info = NULL; ut_a(name != NULL); @@ -3138,14 +3021,6 @@ row_drop_table_for_mysql( srv_print_innodb_table_monitor = FALSE; } - quoted_name = mem_strdupq(name, '\''); - namelen = strlen(quoted_name); - sql = mem_alloc((sizeof str1) + (sizeof str2) - 2 + 1 + namelen); - memcpy(sql, str1, (sizeof str1) - 1); - memcpy(sql + (sizeof str1) - 1, quoted_name, namelen); - memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2); - mem_free(quoted_name); - /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations */ @@ -3163,16 +3038,6 @@ row_drop_table_for_mysql( ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - graph = pars_sql(sql); - - ut_a(graph); - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - table = dict_table_get_low(name); if (!table) { @@ -3296,18 +3161,80 @@ fputs(" InnoDB: You are trying to drop table ", stderr); trx->dict_operation = TRUE; trx->table_id = table->id; - ut_a(thr = que_fork_start_command(graph)); + /* We use the private SQL parser of Innobase to generate the + query graphs needed in deleting the dictionary data from system + tables in Innobase. Deleting a row from SYS_INDEXES table also + frees the file segments of the B-tree associated with the index. */ - que_run_threads(thr); + info = pars_info_create(); - err = trx->error_state; + pars_info_add_str_literal(info, "table_name", name); + + err = que_eval_sql(info, + "PROCEDURE DROP_TABLE_PROC () IS\n" + "sys_foreign_id CHAR;\n" + "table_id CHAR;\n" + "index_id CHAR;\n" + "foreign_id CHAR;\n" + "found INT;\n" + "BEGIN\n" + "SELECT ID INTO table_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = :table_name;\n" + "IF (SQL % NOTFOUND) THEN\n" + " COMMIT WORK;\n" + " RETURN;\n" + "END IF;\n" + "found := 1;\n" + "SELECT ID INTO sys_foreign_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = 'SYS_FOREIGN';\n" + "IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + "END IF;\n" + "IF (:table_name = 'SYS_FOREIGN') THEN\n" + " found := 0;\n" + "END IF;\n" + "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n" + " found := 0;\n" + "END IF;\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = :table_name\n" + " AND TO_BINARY(FOR_NAME) = TO_BINARY(:table_name);\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE" + " DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n" + " DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n" + " END IF;\n" + "END LOOP;\n" + "found := 1;\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO index_id\n" + " FROM SYS_INDEXES\n" + " WHERE TABLE_ID = table_id;\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE" + " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n" + " DELETE FROM SYS_INDEXES WHERE ID = index_id\n" + " AND TABLE_ID = table_id;\n" + " END IF;\n" + "END LOOP;\n" + "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n" + "DELETE FROM SYS_TABLES WHERE ID = table_id;\n" + "COMMIT WORK;\n" + "END;\n" + , trx); if (err != DB_SUCCESS) { ut_a(err == DB_OUT_OF_FILE_SPACE); err = DB_MUST_GET_MORE_FILE_SPACE; - row_mysql_handle_errors(&err, trx, thr, NULL); + row_mysql_handle_errors(&err, trx, NULL, NULL); ut_error; } else { @@ -3385,8 +3312,6 @@ funct_exit: mem_free(dir_path_of_temp_table); } - que_graph_free(graph); - trx_commit_for_mysql(trx); trx->op_info = ""; @@ -3491,6 +3416,62 @@ row_is_mysql_tmp_table_name( return(strstr(name, "/@0023sql") != NULL); } +/******************************************************************** +Delete a single constraint. */ +static +int +row_delete_constraint_low( +/*======================*/ + /* out: error code or DB_SUCCESS */ + const char* id, /* in: constraint id */ + trx_t* trx) /* in: transaction handle */ +{ + pars_info_t* info = pars_info_create(); + + pars_info_add_str_literal(info, "id", id); + + return(que_eval_sql(info, + "PROCEDURE DELETE_CONSTRAINT () IS\n" + "BEGIN\n" + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n" + "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n" + "END;\n" + , trx)); +} + +/******************************************************************** +Delete a single constraint. */ +static +int +row_delete_constraint( +/*==================*/ + /* out: error code or DB_SUCCESS */ + const char* id, /* in: constraint id */ + const char* database_name, /* in: database name, with the + trailing '/' */ + mem_heap_t* heap, /* in: memory heap */ + trx_t* trx) /* in: transaction handle */ +{ + ulint err; + + /* New format constraints have ids /. */ + err = row_delete_constraint_low( + mem_heap_strcat(heap, database_name, id), trx); + + if ((err == DB_SUCCESS) && !strchr(id, '/')) { + /* Old format < 4.0.18 constraints have constraint ids + _. We only try deleting them if the + constraint name does not contain a '/' character, otherwise + deleting a new format constraint named 'foo/bar' from + database 'baz' would remove constraint 'bar' from database + 'foo', if it existed. */ + + err = row_delete_constraint_low(id, trx); + } + + return(err); +} + /************************************************************************* Renames a table for MySQL. */ @@ -3503,100 +3484,13 @@ row_rename_table_for_mysql( trx_t* trx) /* in: transaction handle */ { dict_table_t* table; - que_thr_t* thr; - que_t* graph = NULL; ulint err; - /* We use the private SQL parser of Innobase to generate the - query graphs needed in deleting the dictionary data from system - tables in Innobase. Deleting a row from SYS_INDEXES table also - frees the file segments of the B-tree associated with the index. */ - static const char str1[] = - "PROCEDURE RENAME_TABLE_PROC () IS\n" - "new_table_name CHAR;\n" - "old_table_name CHAR;\n" - "gen_constr_prefix CHAR;\n" - "new_db_name CHAR;\n" - "foreign_id CHAR;\n" - "new_foreign_id CHAR;\n" - "old_db_name_len INT;\n" - "old_t_name_len INT;\n" - "new_db_name_len INT;\n" - "id_len INT;\n" - "found INT;\n" - "BEGIN\n" - "new_table_name := '"; - static const char str2[] = - "';\nold_table_name := '"; - static const char str3[] = - "';\n" - "UPDATE SYS_TABLES SET NAME = new_table_name\n" - "WHERE NAME = old_table_name;\n"; - static const char str4a1[] = /* drop some constraints of tmp tables */ - "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '"; - static const char str4a2[] = "';\n" - "DELETE FROM SYS_FOREIGN WHERE ID = '"; - static const char str4a3[] = "';\n"; - static const char str4b[] = /* rename all constraints */ - "found := 1;\n" - "old_db_name_len := INSTR(old_table_name, '/') - 1;\n" - "new_db_name_len := INSTR(new_table_name, '/') - 1;\n" - "new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n" - "old_t_name_len := LENGTH(old_table_name);\n" - "gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = old_table_name\n" - " AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE\n" - " UPDATE SYS_FOREIGN\n" - " SET FOR_NAME = new_table_name\n" - " WHERE ID = foreign_id;\n" - " id_len := LENGTH(foreign_id);\n" - " IF (INSTR(foreign_id, '/') > 0) THEN\n" - " IF (INSTR(foreign_id,\n" - " gen_constr_prefix) > 0)\n" - " THEN\n" - " new_foreign_id :=\n" - " CONCAT(new_table_name,\n" - " SUBSTR(foreign_id, old_t_name_len,\n" - " id_len - old_t_name_len));\n" - " ELSE\n" - " new_foreign_id :=\n" - " CONCAT(new_db_name,\n" - " SUBSTR(foreign_id,\n" - " old_db_name_len,\n" - " id_len - old_db_name_len));\n" - " END IF;\n" - " UPDATE SYS_FOREIGN\n" - " SET ID = new_foreign_id\n" - " WHERE ID = foreign_id;\n" - " UPDATE SYS_FOREIGN_COLS\n" - " SET ID = new_foreign_id\n" - " WHERE ID = foreign_id;\n" - " END IF;\n" - " END IF;\n" - "END LOOP;\n" - "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" - "WHERE REF_NAME = old_table_name\n" - " AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);\n"; - static const char str5[] = - "END;\n"; - mem_heap_t* heap = NULL; const char** constraints_to_drop = NULL; ulint n_constraints_to_drop = 0; ibool recovering_temp_table = FALSE; ibool old_is_tmp, new_is_tmp; - ulint len; - ulint i; - ibool success; - /* length of database name; 0 if not renaming to a temporary table */ - ulint db_name_len; - char* sql; - char* sqlend; + pars_info_t* info = NULL; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_a(old_name != NULL); @@ -3674,13 +3568,7 @@ row_rename_table_for_mysql( goto funct_exit; } - /* calculate the length of the SQL string */ - len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4 - + ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\''); - if (new_is_tmp) { - db_name_len = dict_get_db_name_len(old_name) + 1; - /* MySQL is doing an ALTER TABLE command and it renames the original table to a temporary table name. We want to preserve the original foreign key constraint definitions despite the @@ -3690,110 +3578,124 @@ row_rename_table_for_mysql( heap = mem_heap_create(100); err = dict_foreign_parse_drop_constraints(heap, trx, - table, - &n_constraints_to_drop, - &constraints_to_drop); + table, &n_constraints_to_drop, &constraints_to_drop); + if (err != DB_SUCCESS) { goto funct_exit; } - - /* reserve space for all database names */ - len += 2 * n_constraints_to_drop - * (ut_strlenq(old_name, '\'') - - ut_strlenq(old_name + db_name_len, '\'')); - - for (i = 0; i < n_constraints_to_drop; i++) { - ulint addlen - = 2 * ut_strlenq(constraints_to_drop[i], '\'') - + ((sizeof str4a1) + (sizeof str4a2) - + (sizeof str4a3) - 3); - if (!strchr(constraints_to_drop[i], '/')) { - addlen *= 2; - } - len += addlen; - } - } else { - db_name_len = 0; - len += (sizeof str4b) - 1; } - sql = sqlend = mem_alloc(len + 1); - memcpy(sql, str1, (sizeof str1) - 1); - sqlend += (sizeof str1) - 1; - sqlend = ut_strcpyq(sqlend, '\'', new_name); - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - sqlend = ut_strcpyq(sqlend, '\'', old_name); - memcpy(sqlend, str3, (sizeof str3) - 1); - sqlend += (sizeof str3) - 1; + /* We use the private SQL parser of Innobase to generate the query + graphs needed in deleting the dictionary data from system tables in + Innobase. Deleting a row from SYS_INDEXES table also frees the file + segments of the B-tree associated with the index. */ - if (db_name_len) { - /* Internally, old format < 4.0.18 constraints have as the - constraint id _, while new format constraints - have /. */ + info = pars_info_create(); + + pars_info_add_str_literal(info, "new_table_name", new_name); + pars_info_add_str_literal(info, "old_table_name", old_name); + + err = que_eval_sql(info, + "PROCEDURE RENAME_TABLE () IS\n" + "BEGIN\n" + "UPDATE SYS_TABLES SET NAME = :new_table_name\n" + " WHERE NAME = :old_table_name;\n" + "END;\n" + , trx); + + if (err != DB_SUCCESS) { + + goto end; + } + + if (!new_is_tmp) { + /* Rename all constraints. */ + + info = pars_info_create(); + + pars_info_add_str_literal(info, "new_table_name", new_name); + pars_info_add_str_literal(info, "old_table_name", old_name); + + err = que_eval_sql(info, + "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" + "gen_constr_prefix CHAR;\n" + "new_db_name CHAR;\n" + "foreign_id CHAR;\n" + "new_foreign_id CHAR;\n" + "old_db_name_len INT;\n" + "old_t_name_len INT;\n" + "new_db_name_len INT;\n" + "id_len INT;\n" + "found INT;\n" + "BEGIN\n" + "found := 1;\n" + "old_db_name_len := INSTR(:old_table_name, '/') - 1;\n" + "new_db_name_len := INSTR(:new_table_name, '/') - 1;\n" + "new_db_name := SUBSTR(:new_table_name, 0, new_db_name_len);\n" + "old_t_name_len := LENGTH(:old_table_name);\n" + "gen_constr_prefix := CONCAT(:old_table_name, '_ibfk_');\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = :old_table_name\n" + " AND TO_BINARY(FOR_NAME) = TO_BINARY(:old_table_name);\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE\n" + " UPDATE SYS_FOREIGN\n" + " SET FOR_NAME = :new_table_name\n" + " WHERE ID = foreign_id;\n" + " id_len := LENGTH(foreign_id);\n" + " IF (INSTR(foreign_id, '/') > 0) THEN\n" + " IF (INSTR(foreign_id,\n" + " gen_constr_prefix) > 0)\n" + " THEN\n" + " new_foreign_id :=\n" + " CONCAT(:new_table_name,\n" + " SUBSTR(foreign_id, old_t_name_len,\n" + " id_len - old_t_name_len));\n" + " ELSE\n" + " new_foreign_id :=\n" + " CONCAT(new_db_name,\n" + " SUBSTR(foreign_id,\n" + " old_db_name_len,\n" + " id_len - old_db_name_len));\n" + " END IF;\n" + " UPDATE SYS_FOREIGN\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " UPDATE SYS_FOREIGN_COLS\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " END IF;\n" + " END IF;\n" + "END LOOP;\n" + "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n" + "WHERE REF_NAME = :old_table_name\n" + " AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n" + "END;\n" + , trx); + + } else if (n_constraints_to_drop > 0) { + /* Drop some constraints of tmp tables. */ + + ulint db_name_len = dict_get_db_name_len(old_name) + 1; + char* db_name = mem_heap_strdupl(heap, old_name, + db_name_len); + ulint i; for (i = 0; i < n_constraints_to_drop; i++) { - memcpy(sqlend, str4a1, (sizeof str4a1) - 1); - sqlend += (sizeof str4a1) - 1; - sqlend = ut_memcpyq(sqlend, '\'', - old_name, db_name_len); - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a2, (sizeof str4a2) - 1); - sqlend += (sizeof str4a2) - 1; - sqlend = ut_memcpyq(sqlend, '\'', - old_name, db_name_len); - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a3, (sizeof str4a3) - 1); - sqlend += (sizeof str4a3) - 1; + err = row_delete_constraint(constraints_to_drop[i], + db_name, heap, trx); - if (!strchr(constraints_to_drop[i], '/')) { - /* If this happens to be an old format - constraint, let us delete it. Since all new - format constraints contain '/', it does no - harm to run these DELETEs anyway. */ - - memcpy(sqlend, str4a1, (sizeof str4a1) - 1); - sqlend += (sizeof str4a1) - 1; - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a2, (sizeof str4a2) - 1); - sqlend += (sizeof str4a2) - 1; - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a3, (sizeof str4a3) - 1); - sqlend += (sizeof str4a3) - 1; + if (err != DB_SUCCESS) { + break; } } } - else { - memcpy(sqlend, str4b, (sizeof str4b) - 1); - sqlend += (sizeof str4b) - 1; - } - - memcpy(sqlend, str5, sizeof str5); - sqlend += sizeof str5; - - ut_a(sqlend == sql + len + 1); - - graph = pars_sql(sql); - - ut_a(graph); - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - err = trx->error_state; +end: if (err != DB_SUCCESS) { if (err == DB_DUPLICATE_KEY) { ut_print_timestamp(stderr); @@ -3830,8 +3732,9 @@ row_rename_table_for_mysql( /* The following call will also rename the .ibd data file if the table is stored in a single-table tablespace */ - success = dict_table_rename_in_cache(table, new_name, + ibool success = dict_table_rename_in_cache(table, new_name, !new_is_tmp); + if (!success) { trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, FALSE, NULL); @@ -3879,20 +3782,16 @@ row_rename_table_for_mysql( ut_a(dict_table_rename_in_cache(table, old_name, FALSE)); trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, - NULL); + trx_general_rollback_for_mysql(trx, FALSE, NULL); trx->error_state = DB_SUCCESS; } } + funct_exit: if (!recovering_temp_table) { row_mysql_unlock_data_dictionary(trx); } - if (graph) { - que_graph_free(graph); - } - if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 0809d2872a5..c0f906f4ed7 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -710,12 +710,17 @@ row_sel_get_clust_rec( if (!node->read_view) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using READ COMMITTED isolation level we lock only the record, i.e., next-key locking is not used. */ ulint lock_type; + trx_t* trx; - if (srv_locks_unsafe_for_binlog) { + trx = thr_get_trx(thr); + + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -1307,16 +1312,22 @@ rec_loop: if (!consistent_read) { - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e., next-key locking is - not used. */ + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using READ COMMITTED isolation + level, we lock only the record, i.e., next-key + locking is not used. */ rec_t* next_rec = page_rec_get_next(rec); ulint lock_type; + trx_t* trx; + + trx = thr_get_trx(thr); + offsets = rec_get_offsets(next_rec, index, offsets, ULINT_UNDEFINED, &heap); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -1350,15 +1361,21 @@ rec_loop: if (!consistent_read) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using READ COMMITTED isolation level, we lock only the record, i.e., next-key locking is not used. */ ulint lock_type; + trx_t* trx; + offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); - if (srv_locks_unsafe_for_binlog) { + trx = thr_get_trx(thr); + + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -1413,14 +1430,6 @@ rec_loop: /* Ok, no need to test end_conds or mix id */ - } else if (plan->mixed_index) { - /* We have to check if the record in a mixed cluster belongs - to this table */ - - if (!dict_is_mixed_table_rec(plan->table, rec)) { - - goto next_rec; - } } /* We are ready to look at a possible new index entry in the result @@ -1958,7 +1967,18 @@ fetch_step( if (sel_node->state != SEL_NODE_NO_MORE_ROWS) { - sel_assign_into_var_values(node->into_list, sel_node); + if (node->into_list) { + sel_assign_into_var_values(node->into_list, + sel_node); + } else { + void* ret = (*node->func->func)(sel_node, + node->func->arg); + + if (!ret) { + sel_node->state = + SEL_NODE_NO_MORE_ROWS; + } + } } thr->run_node = que_node_get_parent(node); @@ -1974,8 +1994,8 @@ fetch_step( sel_node->common.parent = node; if (sel_node->state == SEL_NODE_CLOSED) { - /* SQL error detected */ - fprintf(stderr, "SQL error %lu\n", (ulong)DB_ERROR); + fprintf(stderr, + "InnoDB: Error: fetch called on a closed cursor\n"); que_thr_handle_error(thr, DB_ERROR, NULL, 0); @@ -1987,6 +2007,76 @@ fetch_step( return(thr); } +/******************************************************************** +Sample callback function for fetch that prints each row.*/ + +void* +row_fetch_print( +/*============*/ + /* out: always returns non-NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg) /* in: not used */ +{ + sel_node_t* node = row; + que_node_t* exp; + ulint i = 0; + + UT_NOT_USED(user_arg); + + fprintf(stderr, "row_fetch_print: row %p\n", row); + + exp = node->select_list; + + while (exp) { + dfield_t* dfield = que_node_get_val(exp); + dtype_t* type = dfield_get_type(dfield); + + fprintf(stderr, " column %lu:\n", (ulong)i); + + dtype_print(type); + fprintf(stderr, "\n"); + + ut_print_buf(stderr, dfield_get_data(dfield), + dfield_get_len(dfield)); + fprintf(stderr, "\n"); + + exp = que_node_get_next(exp); + i++; + } + + return((void*)42); +} + +/******************************************************************** +Callback function for fetch that stores an unsigned 4 byte integer to the +location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length += 4. */ + +void* +row_fetch_store_uint4( +/*==================*/ + /* out: always returns NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg) /* in: data pointer */ +{ + sel_node_t* node = row; + ib_uint32_t* val = user_arg; + ulint tmp; + + dfield_t* dfield = que_node_get_val(node->select_list); + dtype_t* type = dfield_get_type(dfield); + ulint len = dfield_get_len(dfield); + + ut_a(dtype_get_mtype(type) == DATA_INT); + ut_a(dtype_get_prtype(type) & DATA_UNSIGNED); + ut_a(len == 4); + + tmp = mach_read_from_4(dfield_get_data(dfield)); + *val = tmp; + + return(NULL); +} + /*************************************************************** Prints a row in a select result. */ @@ -2397,18 +2487,16 @@ row_sel_field_store_in_mysql_format( } else if (templ->type == DATA_MYSQL) { memcpy(dest, data, len); -#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG) - ut_a(templ->mysql_col_len >= len); - ut_a(templ->mbmaxlen >= templ->mbminlen); + ut_ad(templ->mysql_col_len >= len); + ut_ad(templ->mbmaxlen >= templ->mbminlen); - ut_a(templ->mbmaxlen > templ->mbminlen + ut_ad(templ->mbmaxlen > templ->mbminlen || templ->mysql_col_len == len); - ut_a(len * templ->mbmaxlen >= templ->mysql_col_len); -#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */ /* The following assertion would fail for old tables containing UTF-8 ENUM columns due to Bug #9526. */ ut_ad(!templ->mbmaxlen || !(templ->mysql_col_len % templ->mbmaxlen)); + ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len); if (templ->mbminlen != templ->mbmaxlen) { /* Pad with spaces. This undoes the stripping @@ -2418,15 +2506,13 @@ row_sel_field_store_in_mysql_format( memset(dest + len, 0x20, templ->mysql_col_len - len); } } else { -#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG) - ut_a(templ->type == DATA_CHAR + ut_ad(templ->type == DATA_CHAR || templ->type == DATA_FIXBINARY /*|| templ->type == DATA_SYS_CHILD || templ->type == DATA_SYS*/ || templ->type == DATA_FLOAT || templ->type == DATA_DOUBLE || templ->type == DATA_DECIMAL); -#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */ ut_ad(templ->mysql_col_len == len); memcpy(dest, data, len); @@ -3210,11 +3296,13 @@ stderr); } /* Reset the new record lock info if srv_locks_unsafe_for_binlog - is set. Then we are able to remove the record locks set here on an - individual row. */ + is set or session is using a READ COMMITED isolation level. Then + we are able to remove the record locks set here on an individual + row. */ - if (srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { trx_reset_new_rec_lock_info(trx); } @@ -3582,13 +3670,15 @@ rec_loop: if (page_rec_is_supremum(rec)) { if (set_also_gap_locks - && !srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + && !(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, - we do not lock gaps. Supremum record is really + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using a READ COMMITTED isolation + level we do not lock gaps. Supremum record is really a gap and therefore we do not set locks there. */ offsets = rec_get_offsets(rec, index, offsets, @@ -3708,12 +3798,14 @@ wrong_offs: if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) { if (set_also_gap_locks - && !srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + && !(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the index record only if innodb_locks_unsafe_for_binlog - option is not set */ + option is not set or this session is not + using a READ COMMITTED isolation level. */ err = sel_set_rec_lock(rec, index, offsets, prebuilt->select_lock_type, @@ -3739,12 +3831,14 @@ wrong_offs: if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) { if (set_also_gap_locks - && !srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + && !(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the index record only if innodb_locks_unsafe_for_binlog - option is not set */ + option is not set or this session is not + using a READ COMMITTED isolation level. */ err = sel_set_rec_lock(rec, index, offsets, prebuilt->select_lock_type, @@ -3775,16 +3869,18 @@ wrong_offs: is a non-delete marked record, then it is enough to lock its existence with LOCK_REC_NOT_GAP. */ - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e., next-key locking is + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using a READ COMMITED isolation + level we lock only the record, i.e., next-key locking is not used. */ ulint lock_type; if (!set_also_gap_locks - || srv_locks_unsafe_for_binlog - || (unique_search && !UNIV_UNLIKELY( - rec_get_deleted_flag(rec, comp)))) { + || srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED + || (unique_search + && !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) { goto no_gap_lock; } else { @@ -3943,9 +4039,10 @@ no_gap_lock: /* The record is delete-marked: we can skip it */ - if (srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE - && !did_semi_consistent_read) { + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE + && !did_semi_consistent_read) { /* No need to keep a lock on a delete-marked record if we do not want to use next-key locking. */ @@ -3996,8 +4093,9 @@ requires_clust_rec: /* The record is delete marked: we can skip it */ - if (srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* No need to keep a lock on a delete-marked record if we do not want to use next-key @@ -4117,8 +4215,9 @@ next_rec: } did_semi_consistent_read = FALSE; - if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog) - && prebuilt->select_lock_type != LOCK_NONE) { + if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { trx_reset_new_rec_lock_info(trx); } @@ -4206,7 +4305,11 @@ lock_wait_or_error: sel_restore_position_for_mysql(&same_user_rec, BTR_SEARCH_LEAF, pcur, moves_up, &mtr); - if (srv_locks_unsafe_for_binlog && !same_user_rec) { + + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && !same_user_rec) { + /* Since we were not able to restore the cursor on the same user record, we cannot use row_unlock_for_mysql() to unlock any records, and diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 23be601a17b..4023283a60c 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -28,6 +28,7 @@ Created 12/27/1996 Heikki Tuuri #include "log0log.h" #include "pars0sym.h" #include "eval0eval.h" +#include "buf0lru.h" /* What kind of latch and lock can we assume when the control comes to @@ -869,6 +870,10 @@ row_upd_index_replace_new_col_vals_index_pos( upd_t* update, /* in: an update vector built for the index so that the field number in an upd_field is the index position */ + ibool order_only, + /* in: if TRUE, limit the replacement to + ordering fields of index; note that this + does not work for non-clustered indexes. */ mem_heap_t* heap) /* in: memory heap to which we allocate and copy the new values, set this as NULL if you do not want allocation */ @@ -879,13 +884,20 @@ row_upd_index_replace_new_col_vals_index_pos( dfield_t* new_val; ulint j; ulint i; + ulint n_fields; dtype_t* cur_type; ut_ad(index); dtuple_set_info_bits(entry, update->info_bits); - for (j = 0; j < dict_index_get_n_fields(index); j++) { + if (order_only) { + n_fields = dict_index_get_n_unique(index); + } else { + n_fields = dict_index_get_n_fields(index); + } + + for (j = 0; j < n_fields; j++) { field = dict_index_get_nth_field(index, j); @@ -1530,6 +1542,10 @@ row_upd_clust_rec( return(err); } + if (buf_LRU_buf_pool_running_out()) { + + return(DB_LOCK_TABLE_FULL); + } /* We may have to modify the tree structure: do a pessimistic descent down the index tree */ diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 1256dd21c87..fe1eeab9c3f 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -1713,6 +1713,8 @@ srv_printf_innodb_monitor( "; in additional pool allocated " ULINTPF "\n", ut_total_allocated_memory, mem_pool_get_reserved(mem_comm_pool)); + fprintf(file, "Dictionary memory allocated " ULINTPF "\n", + dict_sys->size); if (srv_use_awe) { fprintf(file, diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 1f3d6df0403..fb7ec4cc78b 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -524,7 +524,7 @@ sync_array_cell_print( "Last time reserved in file %s line %lu, " #endif /* UNIV_SYNC_DEBUG */ "waiters flag %lu\n", - mutex, mutex->cfile_name, (ulong) mutex->cline, + (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) mutex->lock_word, #ifdef UNIV_SYNC_DEBUG mutex->file_name, (ulong) mutex->line, @@ -539,7 +539,7 @@ sync_array_cell_print( fprintf(file, " RW-latch at %p created in file %s line %lu\n", - rwlock, rwlock->cfile_name, + (void*) rwlock, rwlock->cfile_name, (ulong) rwlock->cline); if (rwlock->writer != RW_LOCK_NOT_LOCKED) { fprintf(file, @@ -670,7 +670,6 @@ sync_array_detect_deadlock( rw_lock_debug_t*debug; ut_a(arr && start && cell); - ut_ad(cell->state == SC_RESERVED); ut_ad(cell->wait_object); ut_ad(os_thread_get_curr_id() == start->thread); ut_ad(depth < 100); @@ -703,7 +702,7 @@ sync_array_detect_deadlock( if (ret) { fprintf(stderr, "Mutex %p owned by thread %lu file %s line %lu\n", - mutex, + (void*) mutex, (ulong) os_thread_pf(mutex->thread_id), mutex->file_name, (ulong) mutex->line); sync_array_cell_print(stderr, cell); @@ -740,7 +739,8 @@ sync_array_detect_deadlock( thread, debug->pass, depth); if (ret) { print: - fprintf(stderr, "rw-lock %p ", lock); + fprintf(stderr, "rw-lock %p ", + (void*) lock); sync_array_cell_print(stderr, cell); rw_lock_debug_print(debug); return(TRUE); diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index b33c1553bae..673e1080d89 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -246,7 +246,7 @@ lock_loop: if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-s-lock at %p cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), lock, + (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock, lock->cfile_name, (ulong) lock->cline, (ulong) i); } @@ -277,7 +277,8 @@ lock_loop: fprintf(stderr, "Thread %lu OS wait rw-s-lock at %p cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), - lock, lock->cfile_name, (ulong) lock->cline); + (void*) lock, lock->cfile_name, + (ulong) lock->cline); } rw_s_system_call_count++; @@ -495,8 +496,8 @@ lock_loop: if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-x-lock at %p cfile %s cline %lu rnds %lu\n", - os_thread_pf(os_thread_get_curr_id()), lock, - lock->cfile_name, (ulong) lock->cline, (ulong) i); + os_thread_pf(os_thread_get_curr_id()), (void*) lock, + lock->cfile_name, (ulong) lock->cline, (ulong) i); } rw_x_spin_wait_count++; @@ -528,8 +529,8 @@ lock_loop: if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu OS wait for rw-x-lock at %p cfile %s cline %lu\n", - os_thread_pf(os_thread_get_curr_id()), lock, - lock->cfile_name, (ulong) lock->cline); + os_thread_pf(os_thread_get_curr_id()), (void*) lock, + lock->cfile_name, (ulong) lock->cline); } rw_x_system_call_count++; @@ -787,7 +788,7 @@ rw_lock_list_print_info(void) || (rw_lock_get_reader_count(lock) != 0) || (rw_lock_get_waiters(lock) != 0)) { - fprintf(stderr, "RW-LOCK: %p ", lock); + fprintf(stderr, "RW-LOCK: %p ", (void*) lock); if (rw_lock_get_waiters(lock)) { fputs(" Waiters for the lock exist\n", stderr); @@ -823,7 +824,7 @@ rw_lock_print( fprintf(stderr, "-------------\n" "RW-LATCH INFO\n" - "RW-LATCH: %p ", lock); + "RW-LATCH: %p ", (void*) lock); if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) || (rw_lock_get_reader_count(lock) != 0) diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 86fa66d5112..6354830df70 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -423,7 +423,7 @@ spin_loop: #ifdef UNIV_SRV_PRINT_LATCH_WAITS fprintf(stderr, "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, + (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i); #endif @@ -485,7 +485,7 @@ spin_loop: fprintf(stderr, "Thread %lu spin wait succeeds at 2:" " mutex at %p\n", (ulong) os_thread_pf(os_thread_get_curr_id()), - mutex); + (void*) mutex); #endif goto finish_timing; @@ -503,7 +503,7 @@ spin_loop: #ifdef UNIV_SRV_PRINT_LATCH_WAITS fprintf(stderr, "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, + (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i); #endif @@ -666,7 +666,7 @@ mutex_list_print_info(void) &thread_id); fprintf(stderr, "Locked mutex: addr %p thread %ld file %s line %ld\n", - mutex, os_thread_pf(thread_id), + (void*) mutex, os_thread_pf(thread_id), file_name, line); } @@ -852,10 +852,10 @@ sync_thread_levels_g( fprintf(stderr, "InnoDB: Locked mutex: addr %p thread %ld file %s line %ld\n", - mutex, os_thread_pf(thread_id), file_name, (ulong) line); + (void*) mutex, os_thread_pf(thread_id), file_name, (ulong) line); #else /* UNIV_SYNC_DEBUG */ fprintf(stderr, - "InnoDB: Locked mutex: addr %p\n", mutex); + "InnoDB: Locked mutex: addr %p\n", (void*) mutex); #endif /* UNIV_SYNC_DEBUG */ } else { fputs("Not locked\n", stderr); diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 90d6d92c09e..a3115e332cd 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -366,8 +366,6 @@ trx_free_for_mysql( /*===============*/ trx_t* trx) /* in, own: trx object */ { - thr_local_free(trx->mysql_thread_id); - mutex_enter(&kernel_mutex); UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx); @@ -1770,6 +1768,9 @@ trx_print( fprintf(f, "%lu lock struct(s), heap size %lu", (ulong) UT_LIST_GET_LEN(trx->trx_locks), (ulong) mem_heap_get_size(trx->lock_heap)); + + fprintf(f, "%lu row lock(s)", + (ulong) lock_number_of_rows_locked(trx)); } if (trx->has_search_latch) { diff --git a/storage/innobase/ut/Makefile.am b/storage/innobase/ut/Makefile.am index 2fdbb99e0f3..c833a6d5a4c 100644 --- a/storage/innobase/ut/Makefile.am +++ b/storage/innobase/ut/Makefile.am @@ -19,6 +19,6 @@ include ../include/Makefile.i noinst_LIBRARIES = libut.a -libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c +libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c ut0vec.c EXTRA_PROGRAMS = diff --git a/storage/innobase/ut/ut0mem.c b/storage/innobase/ut/ut0mem.c index 345c14e00f9..4358edba8c0 100644 --- a/storage/innobase/ut/ut0mem.c +++ b/storage/innobase/ut/ut0mem.c @@ -437,3 +437,96 @@ ut_memcpyq( return(dest); } + +/************************************************************************** +Return the number of times s2 occurs in s1. Overlapping instances of s2 +are only counted once. */ + +ulint +ut_strcount( +/*========*/ + /* out: the number of times s2 occurs in s1 */ + const char* s1, /* in: string to search in */ + const char* s2) /* in: string to search for */ +{ + ulint count = 0; + ulint len = strlen(s2); + + if (len == 0) { + + return(0); + } + + for (;;) { + s1 = strstr(s1, s2); + + if (!s1) { + + break; + } + + count++; + s1 += len; + } + + return(count); +} + +/************************************************************************** +Replace every occurrence of s1 in str with s2. Overlapping instances of s1 +are only replaced once. */ + +char * +ut_strreplace( +/*==========*/ + /* out, own: modified string, must be + freed with mem_free() */ + const char* str, /* in: string to operate on */ + const char* s1, /* in: string to replace */ + const char* s2) /* in: string to replace s1 with */ +{ + char* new_str; + char* ptr; + const char* str_end; + ulint str_len = strlen(str); + ulint s1_len = strlen(s1); + ulint s2_len = strlen(s2); + ulint count = 0; + int len_delta = (int)s2_len - (int)s1_len; + + str_end = str + str_len; + + if (len_delta <= 0) { + len_delta = 0; + } else { + count = ut_strcount(str, s1); + } + + new_str = mem_alloc(str_len + count * len_delta + 1); + ptr = new_str; + + while (str) { + const char* next = strstr(str, s1); + + if (!next) { + next = str_end; + } + + memcpy(ptr, str, next - str); + ptr += next - str; + + if (next == str_end) { + + break; + } + + memcpy(ptr, s2, s2_len); + ptr += s2_len; + + str = next + s1_len; + } + + *ptr = '\0'; + + return(new_str); +} diff --git a/storage/innobase/ut/ut0vec.c b/storage/innobase/ut/ut0vec.c new file mode 100644 index 00000000000..3f61c8c8386 --- /dev/null +++ b/storage/innobase/ut/ut0vec.c @@ -0,0 +1,54 @@ +#include "ut0vec.h" +#ifdef UNIV_NONINL +#include "ut0vec.ic" +#endif +#include + +/******************************************************************** +Create a new vector with the given initial size. */ + +ib_vector_t* +ib_vector_create( +/*=============*/ + /* out: vector */ + mem_heap_t* heap, /* in: heap */ + ulint size) /* in: initial size */ +{ + ib_vector_t* vec; + + ut_a(size > 0); + + vec = mem_heap_alloc(heap, sizeof(*vec)); + + vec->heap = heap; + vec->data = mem_heap_alloc(heap, sizeof(void*) * size); + vec->used = 0; + vec->total = size; + + return(vec); +} + +/******************************************************************** +Push a new element to the vector, increasing its size if necessary. */ + +void +ib_vector_push( +/*===========*/ + ib_vector_t* vec, /* in: vector */ + void* elem) /* in: data element */ +{ + if (vec->used >= vec->total) { + void** new_data; + ulint new_total = vec->total * 2; + + new_data = mem_heap_alloc(vec->heap, + sizeof(void*) * new_total); + memcpy(new_data, vec->data, sizeof(void*) * vec->total); + + vec->data = new_data; + vec->total = new_total; + } + + vec->data[vec->used] = elem; + vec->used++; +} From 9935dcc7bd14a30733768d782f729701f3e4ab16 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 23 Apr 2006 16:05:11 +0400 Subject: [PATCH 096/101] Corrected merge mistake. --- mysql-test/t/innodb.test | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 55316988bdb..bcd80c18326 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2112,18 +2112,6 @@ connection default; disconnect a; disconnect b; -# -# Bug #14360: problem with intervals -# - -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 - where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -drop table t1, t2; - # # Test that cascading updates leading to duplicate keys give the correct # error message (bug #9680) @@ -2176,6 +2164,7 @@ alter table t1 drop foreign key c2_fk; show create table t1; # drop table t1, t2; + # # Bug #14360: problem with intervals # From c7a5f503420c56522ccc63fdcac80177e00dabb1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 23 Apr 2006 18:15:41 +0200 Subject: [PATCH 097/101] Fix cmakelists.txt removed by innodb snapshot. --- storage/innobase/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am index dfc3a511d52..0cceac97688 100644 --- a/storage/innobase/Makefile.am +++ b/storage/innobase/Makefile.am @@ -76,7 +76,8 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \ include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \ include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \ - include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic + include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic \ + cmakelists.txt # Don't update the files from bitkeeper %::SCCS/s.% From f9606d258466eebcf17e6de7413c7b1563b8210c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Apr 2006 15:39:49 +0200 Subject: [PATCH 098/101] Fix for Bug #17840 mysqldump should not dump tables in database cluster, skip cluster internal database client/mysqldump.c: Fix for Bug #17840 mysqldump should not dump tables in database , skip cluster internal database --- client/mysqldump.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index f268ca5b468..a0da4a1d13b 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -134,7 +134,7 @@ static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; /* do we met VIEWs during tables scaning */ my_bool was_views= 0; - +const char * cluster_db="cluster"; const char *compatible_mode_names[]= { "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", @@ -2937,6 +2937,8 @@ static int dump_all_tables_in_db(char *database) afterdot= strmov(hash_key, database); *afterdot++= '.'; + if (!strcmp(database, cluster_db)) /* Skip cluster internal database */ + return 0; if (init_dumping(database)) return 1; if (opt_xml) From 883710979d384624f64659e4abbd84dcb2b501d2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Apr 2006 15:50:05 +0200 Subject: [PATCH 099/101] Fix for Bug #17840 mysqldump should not dump tables in database cluster, reuse existing define --- client/mysqldump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index a0da4a1d13b..23d78a588a7 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -50,6 +50,7 @@ #include "mysql.h" #include "mysql_version.h" #include "mysqld_error.h" +#include "sql/ha_ndbcluster_tables.h" /* Exit codes */ @@ -134,7 +135,6 @@ static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; /* do we met VIEWs during tables scaning */ my_bool was_views= 0; -const char * cluster_db="cluster"; const char *compatible_mode_names[]= { "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", @@ -2937,7 +2937,7 @@ static int dump_all_tables_in_db(char *database) afterdot= strmov(hash_key, database); *afterdot++= '.'; - if (!strcmp(database, cluster_db)) /* Skip cluster internal database */ + if (!strcmp(database, NDB_REP_DB)) /* Skip cluster internal database */ return 0; if (init_dumping(database)) return 1; From 3f63edb362e89df761e575842ac39ef4c86a664c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Apr 2006 20:19:32 +0500 Subject: [PATCH 100/101] after merge fix --- storage/myisam/mi_dynrec.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/storage/myisam/mi_dynrec.c b/storage/myisam/mi_dynrec.c index 36d88bd362a..9d76a1fb9a5 100644 --- a/storage/myisam/mi_dynrec.c +++ b/storage/myisam/mi_dynrec.c @@ -67,6 +67,11 @@ static int _mi_cmp_buffer(File file, const byte *buff, my_off_t filepos, my_bool mi_dynmap_file(MI_INFO *info, my_off_t size) { DBUG_ENTER("mi_dynmap_file"); + if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN) + { + DBUG_PRINT("warning", ("File is too large for mmap")); + DBUG_RETURN(1); + } info->s->file_map= (byte*) my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN), info->s->mode==O_RDONLY ? PROT_READ : From aa19a8f2b4a98f580bd03d7126e5b130d419dcf9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Apr 2006 16:05:57 -0400 Subject: [PATCH 101/101] Manual merge fix. mysql-test/r/innodb.result: Corrected from manual merge. I know the numbers are right (it's a 7,7-seeded fibbonaci sequence), but I don't know how I missed the latter line. --- mysql-test/r/innodb.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index a7e425cfa4d..f32d7ee264a 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1305,14 +1305,14 @@ insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; select count(*) from t1; count(*) -623 +29267 explain select * from t1 where c between 1 and 2500; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range c c 5 NULL # Using where update t1 set c=a; explain select * from t1 where c between 1 and 2500; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL c NULL NULL NULL # Using where +1 SIMPLE t1 range c c 5 NULL # Using where drop table t1,t2; create table t1 (id int primary key auto_increment, fk int, index index_fk (fk)) engine=innodb; insert into t1 (id) values (null),(null),(null),(null),(null);