diff options
Diffstat (limited to 'sql')
244 files changed, 10378 insertions, 5918 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 4cdc4c01c4e..002aabb91b0 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -1,3 +1,18 @@ +# Copyright (C) 2006 MySQL AB +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR") SET(CMAKE_C_FLAGS_DEBUG @@ -22,8 +37,7 @@ SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/sql/message.rc ${PROJECT_SOURCE_DIR}/include/sql_state.h PROPERTIES GENERATED 1) -ADD_DEFINITIONS(-DHAVE_ROW_BASED_REPLICATION -DMYSQL_SERVER - -D_CONSOLE -DHAVE_DLOPEN) +ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN) ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc discover.cc ../libmysql/errmsg.c field.cc field_conv.cc @@ -33,7 +47,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc item_create.cc item_func.cc item_geofunc.cc item_row.cc item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc - item_uniq.cc key.cc log.cc lock.cc log_event.cc message.rc + key.cc log.cc lock.cc log_event.cc message.rc message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c mysqld.cc net_serv.cc nt_servc.cc nt_servc.h opt_range.cc opt_range.h opt_sum.cc @@ -54,7 +68,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc event_queue.cc event_db_repository.cc sql_tablespace.cc events.cc ../sql-common/my_user.c partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc - rpl_rli.cc rpl_mi.cc + rpl_rli.cc rpl_mi.cc sql_servers.cc + sql_connect.cc scheduler.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h diff --git a/sql/Makefile.am b/sql/Makefile.am index 91fe875c73d..c3a692615dd 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -1,9 +1,8 @@ -# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# Copyright (C) 2000-2006 MySQL AB # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -41,9 +40,10 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ @pstack_libs@ \ @mysql_plugin_libs@ \ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \ - @yassl_libs@ @openssl_libs@ + $(yassl_libs) $(openssl_libs) + noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ - item_strfunc.h item_timefunc.h item_uniq.h \ + item_strfunc.h item_timefunc.h \ item_xmlfunc.h \ item_create.h item_subselect.h item_row.h \ mysql_priv.h item_geofunc.h sql_bitmap.h \ @@ -64,11 +64,12 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ tztime.h my_decimal.h\ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ parse_file.h sql_view.h sql_trigger.h \ - sql_array.h sql_cursor.h events.h \ + sql_array.h sql_cursor.h events.h scheduler.h \ event_db_repository.h event_queue.h \ - sql_plugin.h authors.h sql_partition.h event_data_objects.h \ - partition_info.h partition_element.h event_scheduler.h \ - contributors.h + sql_plugin.h authors.h \ + event_data_objects.h event_scheduler.h \ + sql_partition.h partition_info.h partition_element.h \ + contributors.h sql_servers.h mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ @@ -79,11 +80,12 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ - set_var.cc sql_parse.cc sql_yacc.yy \ + sql_connect.cc scheduler.cc sql_parse.cc \ + set_var.cc sql_yacc.yy \ sql_base.cc table.cc sql_select.cc sql_insert.cc \ sql_prepare.cc sql_error.cc sql_locale.cc \ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \ - procedure.cc item_uniq.cc sql_test.cc \ + procedure.cc sql_test.cc \ log.cc log_event.cc init.cc derror.cc sql_acl.cc \ unireg.cc des_key_file.cc \ discover.cc time.cc opt_range.cc opt_sum.cc \ @@ -106,7 +108,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ event_scheduler.cc event_data_objects.cc \ event_queue.cc event_db_repository.cc events.cc \ sql_plugin.cc sql_binlog.cc \ - sql_builtin.cc sql_tablespace.cc partition_info.cc + sql_builtin.cc sql_tablespace.cc partition_info.cc \ + sql_servers.cc gen_lex_hash_SOURCES = gen_lex_hash.cc @@ -121,13 +124,14 @@ DEFS = -DMYSQL_SERVER \ -DLIBDIR="\"$(MYSQLLIBdir)\"" \ @DEFS@ -BUILT_DIST_SRC = sql_yacc.cc sql_yacc.h -BUILT_SOURCES = $(BUILT_DIST_SRC) lex_hash.h -EXTRA_DIST = udf_example.c udf_example.def $(BUILT_DIST_SRC) \ +BUILT_MAINT_SRC = sql_yacc.cc sql_yacc.h +BUILT_SOURCES = $(BUILT_MAINT_SRC) lex_hash.h +EXTRA_DIST = udf_example.c udf_example.def $(BUILT_MAINT_SRC) \ nt_servc.cc nt_servc.h message.mc CMakeLists.txt \ udf_example.c udf_example.def -CLEANFILES = lex_hash.h sql_yacc.cc sql_yacc.h sql_yacc.output -AM_YFLAGS = -d --debug --verbose +CLEANFILES = lex_hash.h sql_yacc.output +MAINTAINERCLEANFILES = $(BUILT_MAINT_SRC) +AM_YFLAGS = -d --verbose mysql_tzinfo_to_sql.cc: rm -f mysql_tzinfo_to_sql.cc @@ -148,23 +152,6 @@ link_sources: mysql_tzinfo_to_sql.cc mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES) $(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $< -# Try to get better dependencies for the grammar. Othervise really bad -# things like different grammars for different pars of MySQL can -# happen if you are unlucky. -sql_yacc.cc: sql_yacc.yy - -sql_yacc.h: sql_yacc.yy - -# Be careful here, note that we use VPATH and might or might not have -# a pregenerated "sql_yacc.cc" in $(srcdir) or one we just built in -# $(builddir). And it has to work if $(srcdir) == $(builddir). -sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS) - @SED@ -e 's/__attribute__ ((__unused__))//' $< > sql_yacc.cc-new - @MV@ sql_yacc.cc-new sql_yacc.cc - @echo "Note: The following compile may take a long time." - @echo "If it fails, re-run configure with --with-low-memory" - $(CXXCOMPILE) $(LM_CFLAGS) -c sql_yacc.cc - # FIXME seems like now "lex_hash.h" differs depending on configure # flags, so can't pregenerate and include in source TAR. Revert to # dist pregenerated if this changes, so the file doesn't differ. diff --git a/sql/authors.h b/sql/authors.h index 980ec7670de..48b807c7884 100644 --- a/sql/authors.h +++ b/sql/authors.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Structure of the name list */ diff --git a/sql/client_settings.h b/sql/client_settings.h index a8cd36af102..f0742cd8046 100644 --- a/sql/client_settings.h +++ b/sql/client_settings.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/contributors.h b/sql/contributors.h index dca232b9b69..87001e29d88 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Structure of the name list */ diff --git a/sql/custom_conf.h b/sql/custom_conf.h index 19ced12bfbb..137b7e9eef2 100644 --- a/sql/custom_conf.h +++ b/sql/custom_conf.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/derror.cc b/sql/derror.cc index bee818a14c1..0e74d411b1f 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc index 77cb0c8de0f..d99d712b45a 100644 --- a/sql/des_key_file.cc +++ b/sql/des_key_file.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2001-2003, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/discover.cc b/sql/discover.cc index 938a05ff4a7..395bfbfff45 100644 --- a/sql/discover.cc +++ b/sql/discover.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index ad7f0ab4e41..07575a6d33a 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -395,7 +394,14 @@ Event_parse_data::init_starts(THD *thd) if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE))) goto wrong_value; - /* Let's check whether time is in the past */ + /* + Let's check whether time is in the past. + Note: This call is not post year 2038 safe. That's because + thd->query_start() is of time_t, while gmt_sec_to_TIME() + wants my_time_t. In the case time_t is larger than my_time_t + an overflow might happen and events subsystem will not work as + expected. + */ thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t) thd->query_start()); @@ -407,12 +413,12 @@ Event_parse_data::init_starts(THD *thd) goto wrong_value; /* - This may result in a 1970-01-01 date if ltime is > 2037-xx-xx. - CONVERT_TZ has similar problem. - mysql_priv.h currently lists + Again, after 2038 this code won't work. As + mysql_priv.h currently lists #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp()) */ - my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime, ¬_used)); + my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime, + ¬_used)); if (!t) goto wrong_value; @@ -465,13 +471,13 @@ Event_parse_data::init_ends(THD *thd) goto error_bad_params; /* - This may result in a 1970-01-01 date if ltime is > 2037-xx-xx. - CONVERT_TZ has similar problem. - mysql_priv.h currently lists + Again, after 2038 this code won't work. As + mysql_priv.h currently lists #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp()) */ DBUG_PRINT("info", ("get the UTC time")); - my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime, ¬_used)); + my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime, + ¬_used)); if (!t) goto error_bad_params; @@ -1554,7 +1560,6 @@ done: int Event_timed::get_create_event(THD *thd, String *buf) { - int multipl= 0; char tmp_buf[2 * STRING_BUFFER_USUAL_SIZE]; String expr_buf(tmp_buf, sizeof(tmp_buf), system_charset_info); expr_buf.length(0); diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h index 2da39c2158b..e00b0b94eaf 100644 --- a/sql/event_data_objects.h +++ b/sql/event_data_objects.h @@ -4,8 +4,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 367c5bae579..940930ec4c6 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -519,7 +518,6 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not) { int ret= 0; - CHARSET_INFO *scs= system_charset_info; TABLE *table= NULL; char old_db_buf[NAME_LEN+1]; LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; diff --git a/sql/event_db_repository.h b/sql/event_db_repository.h index ed74edd7e19..1457fb64e2e 100644 --- a/sql/event_db_repository.h +++ b/sql/event_db_repository.h @@ -4,8 +4,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 7ec665fcd5f..068abbe3408 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -140,8 +139,6 @@ bool Event_queue::init_queue(THD *thd, Event_db_repository *db_repo) { bool res; - struct event_queue_param *event_queue_param_value= NULL; - DBUG_ENTER("Event_queue::init_queue"); DBUG_PRINT("enter", ("this: 0x%lx", (long) this)); @@ -160,7 +157,6 @@ Event_queue::init_queue(THD *thd, Event_db_repository *db_repo) { sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ." "The scheduler may not work correctly. Stopping"); - DBUG_ASSERT(0); goto err; } @@ -693,16 +689,11 @@ static const char *queue_wait_msg= "Waiting for next activation"; SYNOPSIS Event_queue::get_top_for_execution_if_time() thd [in] Thread - now [in] Current timestamp job_data [out] The object to execute - abstime [out] Time to sleep RETURN VALUE FALSE No error. If *job_data==NULL then top not elligible for execution. - Could be that there is no top. If abstime->tv_sec is set to value - greater than zero then use abstime with pthread_cond_timedwait(). - If abstime->tv_sec is zero then sleep with pthread_cond_wait(). - abstime->tv_nsec is always zero. + Could be that there is no top. TRUE Error */ @@ -712,56 +703,51 @@ Event_queue::get_top_for_execution_if_time(THD *thd, Event_job_data **job_data) { bool ret= FALSE; struct timespec top_time; - struct timespec *abstime; Event_queue_element *top= NULL; bool to_free= FALSE; bool to_drop= FALSE; *job_data= NULL; DBUG_ENTER("Event_queue::get_top_for_execution_if_time"); - top_time.tv_nsec= 0; LOCK_QUEUE_DATA(); for (;;) { int res; - thd->end_time(); - time_t now= thd->query_start(); - abstime= NULL; + /* Break loop if thd has been killed */ + if (thd->killed) + { + DBUG_PRINT("info", ("thd->killed=%d", thd->killed)); + goto end; + } - if (queue.elements) + if (!queue.elements) { - top= ((Event_queue_element*) queue_element(&queue, 0)); - top_time.tv_sec= sec_since_epoch_TIME(&top->execute_at); + /* There are no events in the queue */ + set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME); - abstime= &top_time; + /* Wait on condition until signaled. Release LOCK_queue while waiting. */ + cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__); + + continue; } - if (!abstime || abstime->tv_sec > now) - { - const char *msg; - if (abstime) - { - next_activation_at= top->execute_at; - msg= queue_wait_msg; - } - else - { - set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME); - msg= queue_wait_msg; - } + top= ((Event_queue_element*) queue_element(&queue, 0)); - cond_wait(thd, abstime, msg, SCHED_FUNC, __LINE__); - if (thd->killed) - { - DBUG_PRINT("info", ("thd->killed=%d", thd->killed)); - goto end; - } + thd->end_time(); /* Get current time */ + + time_t seconds_to_next_event= + sec_since_epoch_TIME(&top->execute_at) - thd->query_start(); + next_activation_at= top->execute_at; + if (seconds_to_next_event > 0) + { /* - The queue could have been emptied. Therefore it's safe to start from - the beginning. Moreover, this way we will get also the new top, if - the element at the top has been changed. + Not yet time for top event, wait on condition with + time or until signaled. Release LOCK_queue while waiting. */ + set_timespec(top_time, seconds_to_next_event); + cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__); + continue; } @@ -803,7 +789,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd, Event_job_data **job_data) else queue_replaced(&queue); - dbug_dump_queue(now); + dbug_dump_queue(thd->query_start()); break; } end: @@ -816,8 +802,7 @@ end: if (to_free) delete top; - DBUG_PRINT("info", ("returning %d et_new: 0x%lx abstime.tv_sec: %ld ", - ret, (long) *job_data, abstime ? abstime->tv_sec : 0)); + DBUG_PRINT("info", ("returning %d et_new: 0x%lx ", ret, (long) *job_data)); if (*job_data) DBUG_PRINT("info", ("db: %s name: %s definer=%s", (*job_data)->dbname.str, diff --git a/sql/event_queue.h b/sql/event_queue.h index 5b70506d388..9f48da4914f 100644 --- a/sql/event_queue.h +++ b/sql/event_queue.h @@ -4,8 +4,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 1e9526b3364..aeacaef0b6d 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -105,25 +104,22 @@ evex_print_warnings(THD *thd, Event_job_data *et) SYNOPSIS post_init_event_thread() thd Thread + + NOTES + Before this is called, one should not do any DBUG_XXX() calls. + */ bool post_init_event_thread(THD *thd) { - my_thread_init(); - pthread_detach_this_thread(); - thd->real_id= pthread_self(); + (void) init_new_connection_handler_thread(); if (init_thr_lock() || thd->store_globals()) { thd->cleanup(); return TRUE; } -#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); thread_count++; @@ -188,7 +184,7 @@ pre_init_event_thread(THD* thd) thd->options|= OPTION_AUTO_IS_NULL; thd->client_capabilities|= CLIENT_MULTI_RESULTS; pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id= thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; pthread_mutex_unlock(&LOCK_thread_count); /* @@ -219,20 +215,20 @@ pthread_handler_t event_scheduler_thread(void *arg) { /* needs to be first for thread_stack */ - THD *thd= (THD *)((struct scheduler_param *) arg)->thd; + THD *thd= (THD *) ((struct scheduler_param *) arg)->thd; Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler; + bool res; - my_free((char*)arg, MYF(0)); - - thd->thread_stack= (char *)&thd; // remember where our stack is + thd->thread_stack= (char*) &thd; // remember where our stack is + res= post_init_event_thread(thd); DBUG_ENTER("event_scheduler_thread"); - - if (!post_init_event_thread(thd)) + my_free((char*)arg, MYF(0)); + if (!res) scheduler->run(thd); deinit_event_thread(thd); - + pthread_exit(0); DBUG_RETURN(0); // Against gcc warnings } @@ -256,13 +252,14 @@ event_worker_thread(void *arg) THD *thd; Event_job_data *event= (Event_job_data *)arg; int ret; + bool res; thd= event->thd; - thd->thread_stack= (char *) &thd; // remember where our stack is + res= post_init_event_thread(thd); DBUG_ENTER("event_worker_thread"); - if (!post_init_event_thread(thd)) + if (!res) { DBUG_PRINT("info", ("Baikonur, time is %ld, BURAN reporting and operational." "THD: 0x%lx", @@ -296,6 +293,7 @@ event_worker_thread(void *arg) deinit_event_thread(thd); + pthread_exit(0); DBUG_RETURN(0); // Can't return anything here } diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h index dffaf8c056c..18625ef35f3 100644 --- a/sql/event_scheduler.h +++ b/sql/event_scheduler.h @@ -4,8 +4,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/events.cc b/sql/events.cc index 3dbc6fd27e1..e6224915d6b 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/events.h b/sql/events.h index 79c4a419388..621ab0ffca5 100644 --- a/sql/events.h +++ b/sql/events.h @@ -4,8 +4,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/examples/CMakeLists.txt b/sql/examples/CMakeLists.txt index d3cc430ef40..1a22e9a3efd 100755 --- a/sql/examples/CMakeLists.txt +++ b/sql/examples/CMakeLists.txt @@ -1,3 +1,18 @@ +# Copyright (C) 2006 MySQL AB +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") diff --git a/sql/field.cc b/sql/field.cc index fa6a433a09e..5d4dbe9a416 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -1416,12 +1415,12 @@ my_decimal* Field_num::val_decimal(my_decimal *decimal_value) Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg, CHARSET_INFO *charset) + const char *field_name_arg, CHARSET_INFO *charset_arg) :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { - field_charset=charset; - if (charset->state & MY_CS_BINSORT) + field_charset= charset_arg; + if (charset_arg->state & MY_CS_BINSORT) flags|=BINARY_FLAG; field_derivation= DERIVATION_IMPLICIT; } @@ -1528,7 +1527,7 @@ bool Field::get_time(TIME *ltime) Needs to be changed if/when we want to support different time formats */ -int Field::store_time(TIME *ltime, timestamp_type type) +int Field::store_time(TIME *ltime, timestamp_type type_arg) { ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[MAX_DATE_STRING_REP_LENGTH]; @@ -2243,12 +2242,12 @@ Field_new_decimal::Field_new_decimal(char *ptr_arg, Field_new_decimal::Field_new_decimal(uint32 len_arg, - bool maybe_null, + bool maybe_null_arg, const char *name, uint8 dec_arg, bool unsigned_arg) :Field_num((char*) 0, len_arg, - maybe_null ? (uchar*) "": 0, 0, + maybe_null_arg ? (uchar*) "": 0, 0, NONE, name, dec_arg, 0, unsigned_arg) { precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg); @@ -2352,7 +2351,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) int Field_new_decimal::store(const char *from, uint length, - CHARSET_INFO *charset) + CHARSET_INFO *charset_arg) { ASSERT_COLUMN_MARKED_FOR_WRITE; int err; @@ -2361,7 +2360,7 @@ int Field_new_decimal::store(const char *from, uint length, if ((err= str2my_decimal(E_DEC_FATAL_ERROR & ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM), - from, length, charset, &decimal_value)) && + from, length, charset_arg, &decimal_value)) && table->in_use->abort_on_warning) { /* Because "from" is not NUL-terminated and we use %s in the ER() */ @@ -2557,7 +2556,7 @@ uint Field_new_decimal::is_equal(create_field *new_field) (uint) (flags & UNSIGNED_FLAG)) && ((new_field->flags & AUTO_INCREMENT_FLAG) == (uint) (flags & AUTO_INCREMENT_FLAG)) && - (new_field->length == max_length()) && + (new_field->length == max_display_length()) && (new_field->decimals == dec)); } @@ -3283,25 +3282,6 @@ void Field_medium::sql_type(String &res) const ** long int ****************************************************************************/ -/* - A helper function to check whether the next character - in the string "s" is MINUS SIGN. -*/ -#ifdef HAVE_CHARSET_ucs2 -static bool test_if_minus(CHARSET_INFO *cs, - const char *s, const char *e) -{ - my_wc_t wc; - return cs->cset->mb_wc(cs, &wc, (uchar*) s, (uchar*) e) > 0 && wc == '-'; -} -#else -/* - If not UCS2 support is compiled then it is easier -*/ -#define test_if_minus(cs, s, e) (*s == '-') -#endif - - int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE; @@ -4164,7 +4144,7 @@ int Field_double::store(double nr) else { double max_value; - if (dec >= NOT_FIXED_DEC) + if (not_fixed) { max_value= DBL_MAX; } @@ -4913,7 +4893,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) } -int Field_time::store_time(TIME *ltime, timestamp_type type) +int Field_time::store_time(TIME *ltime, timestamp_type time_type) { long tmp= ((ltime->month ? 0 : ltime->day * 24L) + ltime->hour) * 10000L + (ltime->minute * 100 + ltime->second); @@ -5524,12 +5504,13 @@ int Field_newdate::store(longlong nr, bool unsigned_val) } -int Field_newdate::store_time(TIME *ltime,timestamp_type type) +int Field_newdate::store_time(TIME *ltime,timestamp_type time_type) { ASSERT_COLUMN_MARKED_FOR_WRITE; long tmp; int error= 0; - if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME) + if (time_type == MYSQL_TIMESTAMP_DATE || + time_type == MYSQL_TIMESTAMP_DATETIME) { tmp=ltime->year*16*32+ltime->month*32+ltime->day; if (check_date(ltime, tmp != 0, @@ -5749,7 +5730,7 @@ int Field_datetime::store(longlong nr, bool unsigned_val) } -int Field_datetime::store_time(TIME *ltime,timestamp_type type) +int Field_datetime::store_time(TIME *ltime,timestamp_type time_type) { ASSERT_COLUMN_MARKED_FOR_WRITE; longlong tmp; @@ -5758,7 +5739,8 @@ int Field_datetime::store_time(TIME *ltime,timestamp_type type) We don't perform range checking here since values stored in TIME structure always fit into DATETIME range. */ - if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME) + if (time_type == MYSQL_TIMESTAMP_DATE || + time_type == MYSQL_TIMESTAMP_DATETIME) { tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+ (ltime->hour*10000L+ltime->minute*100+ltime->second)); @@ -6137,32 +6119,32 @@ int Field_str::store(double nr) char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; uint length; bool use_scientific_notation= TRUE; - uint char_length= field_length / charset()->mbmaxlen; + uint local_char_length= field_length / charset()->mbmaxlen; /* Check fabs(nr) against longest value that can be stored in field, which depends on whether the value is < 1 or not, and negative or not */ double anr= fabs(nr); int neg= (nr < 0.0) ? 1 : 0; - if (char_length > 4 && char_length < 32 && - (anr < 1.0 ? anr > 1/(log_10[max(0,(int) char_length-neg-2)]) /* -2 for "0." */ - : anr < log_10[char_length-neg]-1)) + if (local_char_length > 4 && local_char_length < 32 && + (anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */ + : anr < log_10[local_char_length-neg]-1)) use_scientific_notation= FALSE; length= (uint) my_sprintf(buff, (buff, "%-.*g", (use_scientific_notation ? - max(0, (int)char_length-neg-5) : - char_length), + max(0, (int)local_char_length-neg-5) : + local_char_length), nr)); /* +1 below is because "precision" in %g above means the max. number of significant digits, not the output width. Thus the width can be larger than number of significant digits by 1 (for decimal point) - the test for char_length < 5 is for extreme cases, + the test for local_char_length < 5 is for extreme cases, like inserting 500.0 in char(1) */ - DBUG_ASSERT(char_length < 5 || length <= char_length+1); + DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1); return store((const char *) buff, length, charset()); } @@ -6183,7 +6165,7 @@ uint Field_str::is_equal(create_field *new_field) return ((new_field->sql_type == real_type()) && new_field->charset == field_charset && - new_field->length == max_length()); + new_field->length == max_display_length()); } @@ -6315,9 +6297,9 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr) void Field_string::sort_string(char *to,uint length) { - uint tmp= my_strnxfrm(field_charset, - (uchar*) to, length, - (uchar*) ptr, field_length); + IF_DBUG(uint tmp=) my_strnxfrm(field_charset, + (uchar*) to, length, + (uchar*) ptr, field_length); DBUG_ASSERT(tmp == length); } @@ -6345,10 +6327,11 @@ void Field_string::sql_type(String &res) const char *Field_string::pack(char *to, const char *from, uint max_length) { uint length= min(field_length,max_length); - uint char_length= max_length/field_charset->mbmaxlen; - if (length > char_length) - char_length= my_charpos(field_charset, from, from+length, char_length); - set_if_smaller(length, char_length); + uint local_char_length= max_length/field_charset->mbmaxlen; + if (length > local_char_length) + local_char_length= my_charpos(field_charset, from, from+length, + local_char_length); + set_if_smaller(length, local_char_length); while (length && from[length-1] == ' ') length--; *to++= (char) (uchar) length; @@ -6432,15 +6415,15 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length, int Field_string::pack_cmp(const char *key, uint length, my_bool insert_or_update) { - uint row_length, key_length; + uint row_length, local_key_length; char *end; if (length > 255) { - key_length= uint2korr(key); + local_key_length= uint2korr(key); key+= 2; } else - key_length= (uint) (uchar) *key++; + local_key_length= (uint) (uchar) *key++; /* Only use 'length' of key, not field_length */ end= ptr + length; @@ -6450,7 +6433,7 @@ int Field_string::pack_cmp(const char *key, uint length, return field_charset->coll->strnncollsp(field_charset, (const uchar*) ptr, row_length, - (const uchar*) key, key_length, + (const uchar*) key, local_key_length, insert_or_update); } @@ -6642,11 +6625,11 @@ int Field_varstring::cmp_max(const char *a_ptr, const char *b_ptr, int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length) { uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); - uint char_length= max_key_length / field_charset->mbmaxlen; + uint local_char_length= max_key_length / field_charset->mbmaxlen; - char_length= my_charpos(field_charset, ptr + length_bytes, - ptr + length_bytes + length, char_length); - set_if_smaller(length, char_length); + local_char_length= my_charpos(field_charset, ptr + length_bytes, + ptr + length_bytes + length, local_char_length); + set_if_smaller(length, local_char_length); return field_charset->coll->strnncollsp(field_charset, (const uchar*) ptr + length_bytes, length, @@ -6756,13 +6739,14 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length) char *Field_varstring::pack_key(char *to, const char *key, uint max_length) { uint length= length_bytes == 1 ? (uint) (uchar) *key : uint2korr(key); - uint char_length= ((field_charset->mbmaxlen > 1) ? + uint local_char_length= ((field_charset->mbmaxlen > 1) ? max_length/field_charset->mbmaxlen : max_length); key+= length_bytes; - if (length > char_length) + if (length > local_char_length) { - char_length= my_charpos(field_charset, key, key+length, char_length); - set_if_smaller(length, char_length); + local_char_length= my_charpos(field_charset, key, key+length, + local_char_length); + set_if_smaller(length, local_char_length); } *to++= (char) (length & 255); if (max_length > 255) @@ -6858,11 +6842,12 @@ const char *Field_varstring::unpack(char *to, const char *from) } -int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length, +int Field_varstring::pack_cmp(const char *a, const char *b, + uint key_length_arg, my_bool insert_or_update) { uint a_length, b_length; - if (key_length > 255) + if (key_length_arg > 255) { a_length=uint2korr(a); a+= 2; b_length=uint2korr(b); b+= 2; @@ -6879,26 +6864,28 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length, } -int Field_varstring::pack_cmp(const char *b, uint key_length, +int Field_varstring::pack_cmp(const char *b, uint key_length_arg, my_bool insert_or_update) { char *a= ptr+ length_bytes; uint a_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); uint b_length; - uint char_length= ((field_charset->mbmaxlen > 1) ? - key_length / field_charset->mbmaxlen : key_length); + uint local_char_length= ((field_charset->mbmaxlen > 1) ? + key_length_arg / field_charset->mbmaxlen : + key_length_arg); - if (key_length > 255) + if (key_length_arg > 255) { b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH; } else b_length= (uint) (uchar) *b++; - if (a_length > char_length) + if (a_length > local_char_length) { - char_length= my_charpos(field_charset, a, a+a_length, char_length); - set_if_smaller(a_length, char_length); + local_char_length= my_charpos(field_charset, a, a+a_length, + local_char_length); + set_if_smaller(a_length, local_char_length); } return field_charset->coll->strnncollsp(field_charset, @@ -6923,13 +6910,15 @@ uint Field_varstring::max_packed_col_length(uint max_length) } -void Field_varstring::get_key_image(char *buff, uint length, imagetype type) +void Field_varstring::get_key_image(char *buff, uint length, + imagetype type_arg) { uint f_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); - uint char_length= length / field_charset->mbmaxlen; + uint local_char_length= length / field_charset->mbmaxlen; char *pos= ptr+length_bytes; - char_length= my_charpos(field_charset, pos, pos + f_length, char_length); - set_if_smaller(f_length, char_length); + local_char_length= my_charpos(field_charset, pos, pos + f_length, + local_char_length); + set_if_smaller(f_length, local_char_length); /* Key is always stored with 2 bytes */ int2store(buff,f_length); memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length); @@ -7010,11 +6999,11 @@ uint Field_varstring::is_equal(create_field *new_field) if (new_field->sql_type == real_type() && new_field->charset == field_charset) { - if (new_field->length == max_length()) + if (new_field->length == max_display_length()) return IS_EQUAL_YES; - if (new_field->length > max_length() && - ((new_field->length <= 255 && max_length() <= 255) || - (new_field->length > 255 && max_length() > 255))) + if (new_field->length > max_display_length() && + ((new_field->length <= 255 && max_display_length() <= 255) || + (new_field->length > 255 && max_display_length() > 255))) return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length } return IS_EQUAL_NO; @@ -7345,13 +7334,13 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr, /* The following is used only when comparing a key */ -void Field_blob::get_key_image(char *buff, uint length, imagetype type) +void Field_blob::get_key_image(char *buff, uint length, imagetype type_arg) { uint32 blob_length= get_length(ptr); char *blob; #ifdef HAVE_SPATIAL - if (type == itMBR) + if (type_arg == itMBR) { const char *dummy; MBR mbr; @@ -7379,10 +7368,10 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type) #endif /*HAVE_SPATIAL*/ get_ptr(&blob); - uint char_length= length / field_charset->mbmaxlen; - char_length= my_charpos(field_charset, blob, blob + blob_length, - char_length); - set_if_smaller(blob_length, char_length); + uint local_char_length= length / field_charset->mbmaxlen; + local_char_length= my_charpos(field_charset, blob, blob + blob_length, + local_char_length); + set_if_smaller(blob_length, local_char_length); if ((uint32) length > blob_length) { @@ -7411,9 +7400,10 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length) uint blob_length=get_length(ptr); memcpy_fixed(&blob1,ptr+packlength,sizeof(char*)); CHARSET_INFO *cs= charset(); - uint char_length= max_key_length / cs->mbmaxlen; - char_length= my_charpos(cs, blob1, blob1+blob_length, char_length); - set_if_smaller(blob_length, char_length); + uint local_char_length= max_key_length / cs->mbmaxlen; + local_char_length= my_charpos(cs, blob1, blob1+blob_length, + local_char_length); + set_if_smaller(blob_length, local_char_length); return Field_blob::cmp(blob1, blob_length, (char*) key_ptr+HA_KEY_BLOB_LENGTH, uint2korr(key_ptr)); @@ -7535,11 +7525,11 @@ const char *Field_blob::unpack(char *to, const char *from) /* Keys for blobs are like keys on varchars */ -int Field_blob::pack_cmp(const char *a, const char *b, uint key_length, +int Field_blob::pack_cmp(const char *a, const char *b, uint key_length_arg, my_bool insert_or_update) { uint a_length, b_length; - if (key_length > 255) + if (key_length_arg > 255) { a_length=uint2korr(a); a+=2; b_length=uint2korr(b); b+=2; @@ -7556,19 +7546,19 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length, } -int Field_blob::pack_cmp(const char *b, uint key_length, +int Field_blob::pack_cmp(const char *b, uint key_length_arg, my_bool insert_or_update) { char *a; + uint a_length, b_length; memcpy_fixed(&a,ptr+packlength,sizeof(char*)); if (!a) - return key_length > 0 ? -1 : 0; - uint a_length=get_length(ptr); - uint b_length; + return key_length_arg > 0 ? -1 : 0; - if (key_length > 255) + a_length= get_length(ptr); + if (key_length_arg > 255) { - b_length=uint2korr(b); b+=2; + b_length= uint2korr(b); b+=2; } else b_length= (uint) (uchar) *b++; @@ -7585,13 +7575,14 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length) char *save=ptr; ptr=(char*) from; uint32 length=get_length(); // Length of from string - uint char_length= ((field_charset->mbmaxlen > 1) ? + uint local_char_length= ((field_charset->mbmaxlen > 1) ? max_length/field_charset->mbmaxlen : max_length); if (length) get_ptr((char**) &from); - if (length > char_length) - char_length= my_charpos(field_charset, from, from+length, char_length); - set_if_smaller(length, char_length); + if (length > local_char_length) + local_char_length= my_charpos(field_charset, from, from+length, + local_char_length); + set_if_smaller(length, local_char_length); *to++= (uchar) length; if (max_length > 255) // 2 byte length *to++= (uchar) (length >> 8); @@ -7678,7 +7669,7 @@ uint Field_blob::max_packed_col_length(uint max_length) #ifdef HAVE_SPATIAL -void Field_geom::get_key_image(char *buff, uint length, imagetype type) +void Field_geom::get_key_image(char *buff, uint length, imagetype type_arg) { char *blob; const char *dummy; @@ -7776,7 +7767,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) goto err; wkb_type= uint4korr(from + SRID_SIZE + 1); if (wkb_type < (uint32) Geometry::wkb_point || - wkb_type > (uint32) Geometry::wkb_end) + wkb_type > (uint32) Geometry::wkb_last) goto err; Field_blob::store_length(length); if (table->copy_blobs || length <= MAX_FIELD_WIDTH) @@ -8031,6 +8022,16 @@ void Field_enum::sql_type(String &res) const } +Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table, + bool keep_type) +{ + Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type); + if (res) + res->typelib= copy_typelib(root, typelib); + return res; +} + + /* set type. This is a string which can have a collection of different values. @@ -8195,7 +8196,7 @@ uint Field_num::is_equal(create_field *new_field) UNSIGNED_FLAG)) && ((new_field->flags & AUTO_INCREMENT_FLAG) == (uint) (flags & AUTO_INCREMENT_FLAG)) && - (new_field->length <= max_length())); + (new_field->length <= max_display_length())); } @@ -8236,6 +8237,7 @@ Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7), bytes_in_rec(len_arg / 8) { + flags|= UNSIGNED_FLAG; /* Ensure that Field::eq() can distinguish between two different bit fields. (two bit fields that are not null, may have same ptr and null_ptr) @@ -8475,7 +8477,7 @@ int Field_bit::cmp_offset(uint row_offset) } -void Field_bit::get_key_image(char *buff, uint length, imagetype type) +void Field_bit::get_key_image(char *buff, uint length, imagetype type_arg) { if (bit_len) { @@ -8525,10 +8527,12 @@ const char *Field_bit::unpack(char *to, const char *from) void Field_bit::set_default() { - my_ptrdiff_t const offset= (my_ptrdiff_t) (table->s->default_values - - table->record[0]); - uchar bits= (uchar) get_rec_bits(bit_ptr + offset, bit_ofs, bit_len); - set_rec_bits(bits, bit_ptr, bit_ofs, bit_len); + if (bit_len > 0) + { + my_ptrdiff_t const offset= table->s->default_values - table->record[0]; + uchar bits= get_rec_bits(bit_ptr + offset, bit_ofs, bit_len); + set_rec_bits(bits, bit_ptr, bit_ofs, bit_len); + } Field::set_default(); } @@ -8543,6 +8547,7 @@ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg, :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, 0, unireg_check_arg, field_name_arg) { + flags|= UNSIGNED_FLAG; bit_len= 0; bytes_in_rec= (len_arg + 7) / 8; } @@ -8646,7 +8651,7 @@ void create_field::create_length_to_internal_length(void) void create_field::init_for_tmp_table(enum_field_types sql_type_arg, - uint32 length_arg, uint32 decimals, + uint32 length_arg, uint32 decimals_arg, bool maybe_null, bool is_unsigned) { field_name= ""; @@ -8657,7 +8662,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg, charset= &my_charset_bin; geom_type= Field::GEOM_GEOMETRY; pack_flag= (FIELDFLAG_NUMBER | - ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) | + ((decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) | (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) | (is_unsigned ? 0 : FIELDFLAG_DECIMAL)); } @@ -8727,7 +8732,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP. */ if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) && - (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP) + (fld_type_modifier & NOT_NULL_FLAG) && fld_type != MYSQL_TYPE_TIMESTAMP) flags|= NO_DEFAULT_VALUE_FLAG; if (fld_length && !(length= (uint) atoi(fld_length))) @@ -8735,34 +8740,34 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; switch (fld_type) { - case FIELD_TYPE_TINY: + case MYSQL_TYPE_TINY: if (!fld_length) length= MAX_TINYINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; - case FIELD_TYPE_SHORT: + case MYSQL_TYPE_SHORT: if (!fld_length) length= MAX_SMALLINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; - case FIELD_TYPE_INT24: + case MYSQL_TYPE_INT24: if (!fld_length) length= MAX_MEDIUMINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; - case FIELD_TYPE_LONG: + case MYSQL_TYPE_LONG: if (!fld_length) length= MAX_INT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; - case FIELD_TYPE_LONGLONG: + case MYSQL_TYPE_LONGLONG: if (!fld_length) length= MAX_BIGINT_WIDTH; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; - case FIELD_TYPE_NULL: + case MYSQL_TYPE_NULL: break; - case FIELD_TYPE_NEWDECIMAL: + case MYSQL_TYPE_NEWDECIMAL: if (!fld_length && !decimals) length= 10; if (length > DECIMAL_MAX_PRECISION) @@ -8791,11 +8796,11 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, break; case MYSQL_TYPE_STRING: break; - case FIELD_TYPE_BLOB: - case FIELD_TYPE_TINY_BLOB: - case FIELD_TYPE_LONG_BLOB: - case FIELD_TYPE_MEDIUM_BLOB: - case FIELD_TYPE_GEOMETRY: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_GEOMETRY: if (fld_default_value) { /* Allow empty as default value. */ @@ -8827,12 +8832,12 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } flags|= BLOB_FLAG; break; - case FIELD_TYPE_YEAR: + case MYSQL_TYPE_YEAR: if (!fld_length || length != 2) length= 4; /* Default length */ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; break; - case FIELD_TYPE_FLOAT: + case MYSQL_TYPE_FLOAT: /* change FLOAT(precision) to FLOAT or DOUBLE */ allowed_type_modifier= AUTO_INCREMENT_FLAG; if (fld_length && !fld_decimals) @@ -8845,7 +8850,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } else if (tmp_length > PRECISION_FOR_FLOAT) { - sql_type= FIELD_TYPE_DOUBLE; + sql_type= MYSQL_TYPE_DOUBLE; length= DBL_DIG+7; /* -[digits].E+### */ } else @@ -8865,7 +8870,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, DBUG_RETURN(TRUE); } break; - case FIELD_TYPE_DOUBLE: + case MYSQL_TYPE_DOUBLE: allowed_type_modifier= AUTO_INCREMENT_FLAG; if (!fld_length && !fld_decimals) { @@ -8879,7 +8884,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, DBUG_RETURN(TRUE); } break; - case FIELD_TYPE_TIMESTAMP: + case MYSQL_TYPE_TIMESTAMP: if (!fld_length) length= 14; /* Full date YYYYMMDDHHMMSS */ else if (length != 19) @@ -8930,21 +8935,21 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, Field::NONE)); } break; - case FIELD_TYPE_DATE: + case MYSQL_TYPE_DATE: /* Old date type. */ if (protocol_version != PROTOCOL_VERSION-1) - sql_type= FIELD_TYPE_NEWDATE; + sql_type= MYSQL_TYPE_NEWDATE; /* fall trough */ - case FIELD_TYPE_NEWDATE: + case MYSQL_TYPE_NEWDATE: length= 10; break; - case FIELD_TYPE_TIME: + case MYSQL_TYPE_TIME: length= 10; break; - case FIELD_TYPE_DATETIME: + case MYSQL_TYPE_DATETIME: length= 19; break; - case FIELD_TYPE_SET: + case MYSQL_TYPE_SET: { if (fld_interval_list->elements > sizeof(longlong)*8) { @@ -8965,7 +8970,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, length= 1; break; } - case FIELD_TYPE_ENUM: + case MYSQL_TYPE_ENUM: { /* Should be safe. */ pack_length= get_enum_pack_length(fld_interval_list->elements); @@ -8974,7 +8979,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, String *tmp; while ((tmp= it++)) interval_list.push_back(tmp); - length= 1; /* See comment for FIELD_TYPE_SET above. */ + length= 1; /* See comment for MYSQL_TYPE_SET above. */ break; } case MYSQL_TYPE_VAR_STRING: @@ -8993,19 +8998,19 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, pack_length= (length + 7) / 8; break; } - case FIELD_TYPE_DECIMAL: + case MYSQL_TYPE_DECIMAL: DBUG_ASSERT(0); /* Was obsolete */ } /* Remember the value of length */ char_length= length; if (!(flags & BLOB_FLAG) && - ((length > max_field_charlength && fld_type != FIELD_TYPE_SET && - fld_type != FIELD_TYPE_ENUM && + ((length > max_field_charlength && fld_type != MYSQL_TYPE_SET && + fld_type != MYSQL_TYPE_ENUM && (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) || (!length && fld_type != MYSQL_TYPE_STRING && - fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY))) + fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY))) { my_error((fld_type == MYSQL_TYPE_VAR_STRING || fld_type == MYSQL_TYPE_VARCHAR || @@ -9030,13 +9035,13 @@ enum_field_types get_blob_type_from_length(ulong length) { enum_field_types type; if (length < 256) - type= FIELD_TYPE_TINY_BLOB; + type= MYSQL_TYPE_TINY_BLOB; else if (length < 65536) - type= FIELD_TYPE_BLOB; + type= MYSQL_TYPE_BLOB; else if (length < 256L*256L*256L) - type= FIELD_TYPE_MEDIUM_BLOB; + type= MYSQL_TYPE_MEDIUM_BLOB; else - type= FIELD_TYPE_LONG_BLOB; + type= MYSQL_TYPE_LONG_BLOB; return type; } @@ -9050,32 +9055,32 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) switch (type) { case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: - case FIELD_TYPE_DECIMAL: return (length); + case MYSQL_TYPE_DECIMAL: return (length); case MYSQL_TYPE_VARCHAR: return (length + (length < 256 ? 1: 2)); - case FIELD_TYPE_YEAR: - case FIELD_TYPE_TINY : return 1; - case FIELD_TYPE_SHORT : return 2; - case FIELD_TYPE_INT24: - case FIELD_TYPE_NEWDATE: - case FIELD_TYPE_TIME: return 3; - case FIELD_TYPE_TIMESTAMP: - case FIELD_TYPE_DATE: - case FIELD_TYPE_LONG : return 4; - case FIELD_TYPE_FLOAT : return sizeof(float); - case FIELD_TYPE_DOUBLE: return sizeof(double); - case FIELD_TYPE_DATETIME: - case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */ - case FIELD_TYPE_NULL : return 0; - case FIELD_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr; - case FIELD_TYPE_BLOB: return 2+portable_sizeof_char_ptr; - case FIELD_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr; - case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr; - case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr; - case FIELD_TYPE_SET: - case FIELD_TYPE_ENUM: - case FIELD_TYPE_NEWDECIMAL: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_TINY : return 1; + case MYSQL_TYPE_SHORT : return 2; + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: return 3; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_LONG : return 4; + case MYSQL_TYPE_FLOAT : return sizeof(float); + case MYSQL_TYPE_DOUBLE: return sizeof(double); + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */ + case MYSQL_TYPE_NULL : return 0; + case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr; + case MYSQL_TYPE_BLOB: return 2+portable_sizeof_char_ptr; + case MYSQL_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr; + case MYSQL_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr; + case MYSQL_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr; + case MYSQL_TYPE_SET: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_NEWDECIMAL: abort(); return 0; // This shouldn't happen - case FIELD_TYPE_BIT: return length / 8; + case MYSQL_TYPE_BIT: return length / 8; default: return 0; } @@ -9085,11 +9090,11 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) uint pack_length_to_packflag(uint type) { switch (type) { - case 1: return f_settype((uint) FIELD_TYPE_TINY); - case 2: return f_settype((uint) FIELD_TYPE_SHORT); - case 3: return f_settype((uint) FIELD_TYPE_INT24); - case 4: return f_settype((uint) FIELD_TYPE_LONG); - case 8: return f_settype((uint) FIELD_TYPE_LONGLONG); + case 1: return f_settype((uint) MYSQL_TYPE_TINY); + case 2: return f_settype((uint) MYSQL_TYPE_SHORT); + case 3: return f_settype((uint) MYSQL_TYPE_INT24); + case 4: return f_settype((uint) MYSQL_TYPE_LONG); + case 8: return f_settype((uint) MYSQL_TYPE_LONGLONG); } return 0; // This shouldn't happen } @@ -9109,7 +9114,7 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length, uchar bit_offset; LINT_INIT(bit_ptr); LINT_INIT(bit_offset); - if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) + if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) { bit_ptr= null_pos; bit_offset= null_bit; @@ -9131,11 +9136,11 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length, } switch (field_type) { - case FIELD_TYPE_DATE: - case FIELD_TYPE_NEWDATE: - case FIELD_TYPE_TIME: - case FIELD_TYPE_DATETIME: - case FIELD_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: field_charset= &my_charset_bin; default: break; } @@ -9145,7 +9150,7 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length, if (!f_is_packed(pack_flag)) { if (field_type == MYSQL_TYPE_STRING || - field_type == FIELD_TYPE_DECIMAL || // 3.23 or 4.0 string + field_type == MYSQL_TYPE_DECIMAL || // 3.23 or 4.0 string field_type == MYSQL_TYPE_VAR_STRING) return new Field_string(ptr,field_length,null_pos,null_bit, unireg_check, field_name, @@ -9188,78 +9193,78 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length, } switch (field_type) { - case FIELD_TYPE_DECIMAL: + case MYSQL_TYPE_DECIMAL: return new Field_decimal(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_decimals(pack_flag), f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_NEWDECIMAL: + case MYSQL_TYPE_NEWDECIMAL: return new Field_new_decimal(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_decimals(pack_flag), f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_FLOAT: + case MYSQL_TYPE_FLOAT: return new Field_float(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_decimals(pack_flag), f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag)== 0); - case FIELD_TYPE_DOUBLE: + case MYSQL_TYPE_DOUBLE: return new Field_double(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_decimals(pack_flag), f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag)== 0); - case FIELD_TYPE_TINY: + case MYSQL_TYPE_TINY: return new Field_tiny(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_SHORT: + case MYSQL_TYPE_SHORT: return new Field_short(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_INT24: + case MYSQL_TYPE_INT24: return new Field_medium(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_LONG: + case MYSQL_TYPE_LONG: return new Field_long(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_LONGLONG: + case MYSQL_TYPE_LONGLONG: return new Field_longlong(ptr,field_length,null_pos,null_bit, unireg_check, field_name, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); - case FIELD_TYPE_TIMESTAMP: + case MYSQL_TYPE_TIMESTAMP: return new Field_timestamp(ptr,field_length, null_pos, null_bit, unireg_check, field_name, share, field_charset); - case FIELD_TYPE_YEAR: + case MYSQL_TYPE_YEAR: return new Field_year(ptr,field_length,null_pos,null_bit, unireg_check, field_name); - case FIELD_TYPE_DATE: + case MYSQL_TYPE_DATE: return new Field_date(ptr,null_pos,null_bit, unireg_check, field_name, field_charset); - case FIELD_TYPE_NEWDATE: + case MYSQL_TYPE_NEWDATE: return new Field_newdate(ptr,null_pos,null_bit, unireg_check, field_name, field_charset); - case FIELD_TYPE_TIME: + case MYSQL_TYPE_TIME: return new Field_time(ptr,null_pos,null_bit, unireg_check, field_name, field_charset); - case FIELD_TYPE_DATETIME: + case MYSQL_TYPE_DATETIME: return new Field_datetime(ptr,null_pos,null_bit, unireg_check, field_name, field_charset); - case FIELD_TYPE_NULL: + case MYSQL_TYPE_NULL: return new Field_null(ptr, field_length, unireg_check, field_name, field_charset); - case FIELD_TYPE_BIT: + case MYSQL_TYPE_BIT: return f_bit_as_char(pack_flag) ? new Field_bit_as_char(ptr, field_length, null_pos, null_bit, unireg_check, field_name) : @@ -9295,12 +9300,12 @@ create_field::create_field(Field *old_field,Field *orig_field) portable_sizeof_char_ptr); switch (sql_type) { - case FIELD_TYPE_BLOB: + case MYSQL_TYPE_BLOB: switch (pack_length - portable_sizeof_char_ptr) { - case 1: sql_type= FIELD_TYPE_TINY_BLOB; break; - case 2: sql_type= FIELD_TYPE_BLOB; break; - case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break; - default: sql_type= FIELD_TYPE_LONG_BLOB; break; + case 1: sql_type= MYSQL_TYPE_TINY_BLOB; break; + case 2: sql_type= MYSQL_TYPE_BLOB; break; + case 3: sql_type= MYSQL_TYPE_MEDIUM_BLOB; break; + default: sql_type= MYSQL_TYPE_LONG_BLOB; break; } length/= charset->mbmaxlen; key_length/= charset->mbmaxlen; @@ -9319,7 +9324,7 @@ create_field::create_field(Field *old_field,Field *orig_field) length= (length+charset->mbmaxlen-1) / charset->mbmaxlen; break; #ifdef HAVE_SPATIAL - case FIELD_TYPE_GEOMETRY: + case MYSQL_TYPE_GEOMETRY: geom_type= ((Field_geom*)old_field)->geom_type; break; #endif @@ -9336,7 +9341,7 @@ create_field::create_field(Field *old_field,Field *orig_field) if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && old_field->ptr && orig_field && - (sql_type != FIELD_TYPE_TIMESTAMP || /* set def only if */ + (sql_type != MYSQL_TYPE_TIMESTAMP || /* set def only if */ old_field->table->timestamp_field != old_field || /* timestamp field */ unireg_check == Field::TIMESTAMP_UN_FIELD)) /* has default val */ { @@ -9365,12 +9370,13 @@ create_field::create_field(Field *old_field,Field *orig_field) maximum possible display length for blob SYNOPSIS - Field_blob::max_length() + Field_blob::max_display_length() RETURN length */ -uint32 Field_blob::max_length() + +uint32 Field_blob::max_display_length() { switch (packlength) { diff --git a/sql/field.h b/sql/field.h index e71936c4805..f27ed8b9394 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,7 +30,7 @@ class Send_field; class Protocol; class create_field; struct st_cache_field; -void field_conv(Field *to,Field *from); +int field_conv(Field *to,Field *from); inline uint get_enum_pack_length(int elements) { @@ -159,12 +158,12 @@ public: virtual void reset_fields() {} virtual void set_default() { - my_ptrdiff_t offset = (my_ptrdiff_t) (table->s->default_values - + my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values - table->record[0]); - memcpy(ptr, ptr + offset, pack_length()); + memcpy(ptr, ptr + l_offset, pack_length()); if (null_ptr) *null_ptr= ((*null_ptr & (uchar) ~null_bit) | - null_ptr[offset] & null_bit); + null_ptr[l_offset] & null_bit); } virtual bool binary() const { return 1; } virtual bool zero_pack() const { return 1; } @@ -277,7 +276,7 @@ public: { memcpy(buff,ptr,length); } inline void set_image(char *buff,uint length, CHARSET_INFO *cs) { memcpy(ptr,buff,length); } - virtual void get_key_image(char *buff, uint length, imagetype type) + virtual void get_key_image(char *buff, uint length, imagetype type_arg) { get_image(buff,length, &my_charset_bin); } virtual void set_key_image(char *buff,uint length) { set_image(buff,length, &my_charset_bin); } @@ -353,10 +352,10 @@ public: virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual CHARSET_INFO *sort_charset(void) const { return charset(); } virtual bool has_charset(void) const { return FALSE; } - virtual void set_charset(CHARSET_INFO *charset) { } + virtual void set_charset(CHARSET_INFO *charset_arg) { } virtual enum Derivation derivation(void) const { return DERIVATION_IMPLICIT; } - virtual void set_derivation(enum Derivation derivation) { } + virtual void set_derivation(enum Derivation derivation_arg) { } bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code, int cuted_increment); bool check_int(const char *str, int length, const char *int_end, @@ -381,7 +380,7 @@ public: } /* maximum possible display length */ - virtual uint32 max_length()= 0; + virtual uint32 max_display_length()= 0; virtual uint is_equal(create_field *new_field); /* convert decimal to longlong with overflow check */ @@ -465,12 +464,12 @@ public: int store(const char *to,uint length,CHARSET_INFO *cs)=0; uint size_of() const { return sizeof(*this); } CHARSET_INFO *charset(void) const { return field_charset; } - void set_charset(CHARSET_INFO *charset) { field_charset=charset; } + void set_charset(CHARSET_INFO *charset_arg) { field_charset= charset_arg; } enum Derivation derivation(void) const { return field_derivation; } virtual void set_derivation(enum Derivation derivation_arg) { field_derivation= derivation_arg; } bool binary() const { return field_charset == &my_charset_bin; } - uint32 max_length() { return field_length; } + uint32 max_display_length() { return field_length; } friend class create_field; my_decimal *val_decimal(my_decimal *); virtual bool str_needs_quotes() { return TRUE; } @@ -485,9 +484,9 @@ class Field_longstr :public Field_str public: Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg, CHARSET_INFO *charset) + const char *field_name_arg, CHARSET_INFO *charset_arg) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg, charset) + field_name_arg, charset_arg) {} int store_decimal(const my_decimal *d); @@ -518,7 +517,7 @@ public: unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg) {} - enum_field_types type() const { return FIELD_TYPE_DECIMAL;} + enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} enum ha_base_keytype key_type() const { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } int reset(void); @@ -533,7 +532,7 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; - uint32 max_length() { return field_length; } + uint32 max_display_length() { return field_length; } }; @@ -556,7 +555,7 @@ public: Field_new_decimal(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, uint8 dec_arg, bool unsigned_arg); - enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;} + enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } Item_result result_type () const { return DECIMAL_RESULT; } int reset(void); @@ -575,7 +574,7 @@ public: void sort_string(char *buff, uint length); bool zero_pack() const { return 0; } void sql_type(String &str) const; - uint32 max_length() { return field_length; } + uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } uint32 pack_length() const { return (uint32) bin_size; } uint is_equal(create_field *new_field); @@ -593,7 +592,7 @@ public: 0, zero_arg,unsigned_arg) {} enum Item_result result_type () const { return INT_RESULT; } - enum_field_types type() const { return FIELD_TYPE_TINY;} + enum_field_types type() const { return MYSQL_TYPE_TINY;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -608,7 +607,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 1; } void sql_type(String &str) const; - uint32 max_length() { return 4; } + uint32 max_display_length() { return 4; } }; @@ -628,7 +627,7 @@ public: NONE, field_name_arg, 0, 0, unsigned_arg) {} enum Item_result result_type () const { return INT_RESULT; } - enum_field_types type() const { return FIELD_TYPE_SHORT;} + enum_field_types type() const { return MYSQL_TYPE_SHORT;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} int store(const char *to,uint length,CHARSET_INFO *charset); @@ -643,7 +642,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 2; } void sql_type(String &str) const; - uint32 max_length() { return 6; } + uint32 max_display_length() { return 6; } }; @@ -658,7 +657,7 @@ public: 0, zero_arg,unsigned_arg) {} enum Item_result result_type () const { return INT_RESULT; } - enum_field_types type() const { return FIELD_TYPE_INT24;} + enum_field_types type() const { return MYSQL_TYPE_INT24;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -673,7 +672,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 3; } void sql_type(String &str) const; - uint32 max_length() { return 8; } + uint32 max_display_length() { return 8; } }; @@ -693,7 +692,7 @@ public: NONE, field_name_arg,0,0,unsigned_arg) {} enum Item_result result_type () const { return INT_RESULT; } - enum_field_types type() const { return FIELD_TYPE_LONG;} + enum_field_types type() const { return MYSQL_TYPE_LONG;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -708,7 +707,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 4; } void sql_type(String &str) const; - uint32 max_length() { return 11; } + uint32 max_display_length() { return 11; } }; @@ -730,7 +729,7 @@ public: NONE, field_name_arg,0,0,unsigned_arg) {} enum Item_result result_type () const { return INT_RESULT; } - enum_field_types type() const { return FIELD_TYPE_LONGLONG;} + enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -750,7 +749,7 @@ public: uint32 pack_length() const { return 8; } void sql_type(String &str) const; bool can_be_compared_as_longlong() const { return TRUE; } - uint32 max_length() { return 20; } + uint32 max_display_length() { return 20; } }; #endif @@ -770,7 +769,7 @@ public: :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, NONE, field_name_arg, dec_arg, 0, 0) {} - enum_field_types type() const { return FIELD_TYPE_FLOAT;} + enum_field_types type() const { return MYSQL_TYPE_FLOAT;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -784,26 +783,35 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(float); } void sql_type(String &str) const; - uint32 max_length() { return 24; } + uint32 max_display_length() { return 24; } }; class Field_double :public Field_real { public: + my_bool not_fixed; Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, uint8 dec_arg,bool zero_arg,bool unsigned_arg) :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, - dec_arg, zero_arg, unsigned_arg) + dec_arg, zero_arg, unsigned_arg), + not_fixed(dec_arg >= NOT_FIXED_DEC) {} Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, uint8 dec_arg) - :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) + :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0), + not_fixed(dec_arg >= NOT_FIXED_DEC) + {} + Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg, my_bool not_fixed_srg) + :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0), + not_fixed(not_fixed_srg) {} - enum_field_types type() const { return FIELD_TYPE_DOUBLE;} + enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -817,7 +825,8 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(double); } void sql_type(String &str) const; - uint32 max_length() { return 53; } + uint32 max_display_length() { return 53; } + uint size_of() const { return sizeof(*this); } }; @@ -832,7 +841,7 @@ public: :Field_str(ptr_arg, len_arg, null, 1, unireg_check_arg, field_name_arg, cs) {} - enum_field_types type() const { return FIELD_TYPE_NULL;} + enum_field_types type() const { return MYSQL_TYPE_NULL;} int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; } int store(double nr) { null[0]=1; return 0; } @@ -849,7 +858,7 @@ public: uint32 pack_length() const { return 0; } void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } - uint32 max_length() { return 4; } + uint32 max_display_length() { return 4; } }; @@ -861,7 +870,7 @@ public: TABLE_SHARE *share, CHARSET_INFO *cs); Field_timestamp(bool maybe_null_arg, const char *field_name_arg, CHARSET_INFO *cs); - enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;} + enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -914,7 +923,7 @@ public: :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, 1, 1) {} - enum_field_types type() const { return FIELD_TYPE_YEAR;} + enum_field_types type() const { return MYSQL_TYPE_YEAR;} int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); int store(longlong nr, bool unsigned_val); @@ -939,7 +948,7 @@ public: CHARSET_INFO *cs) :Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} - enum_field_types type() const { return FIELD_TYPE_DATE;} + enum_field_types type() const { return MYSQL_TYPE_DATE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -967,8 +976,8 @@ public: :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, cs) {} - enum_field_types type() const { return FIELD_TYPE_DATE;} - enum_field_types real_type() const { return FIELD_TYPE_NEWDATE; } + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -1003,7 +1012,7 @@ public: CHARSET_INFO *cs) :Field_str((char*) 0,8, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} - enum_field_types type() const { return FIELD_TYPE_TIME;} + enum_field_types type() const { return MYSQL_TYPE_TIME;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } enum Item_result cmp_type () const { return INT_RESULT; } int store_time(TIME *ltime, timestamp_type type); @@ -1038,7 +1047,7 @@ public: CHARSET_INFO *cs) :Field_str((char*) 0,19, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} - enum_field_types type() const { return FIELD_TYPE_DATETIME;} + enum_field_types type() const { return MYSQL_TYPE_DATETIME;} #ifdef HAVE_LONG_LONG enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } #endif @@ -1097,7 +1106,8 @@ public: bool zero_pack() const { return 0; } int reset(void) { - charset()->cset->fill(charset(),ptr,field_length,' '); + charset()->cset->fill(charset(),ptr,field_length, + (has_charset() ? ' ' : 0)); return 0; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -1118,7 +1128,7 @@ public: uint packed_col_length(const char *to, uint length); uint max_packed_col_length(uint max_length); uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return FIELD_TYPE_STRING; } + enum_field_types real_type() const { return MYSQL_TYPE_STRING; } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type); @@ -1229,13 +1239,13 @@ public: packlength= 4; if (set_packlength) { - uint32 char_length= len_arg/cs->mbmaxlen; - packlength= char_length <= 255 ? 1 : - char_length <= 65535 ? 2 : - char_length <= 16777215 ? 3 : 4; + uint32 l_char_length= len_arg/cs->mbmaxlen; + packlength= l_char_length <= 255 ? 1 : + l_char_length <= 65535 ? 2 : + l_char_length <= 16777215 ? 3 : 4; } } - enum_field_types type() const { return FIELD_TYPE_BLOB;} + enum_field_types type() const { return MYSQL_TYPE_BLOB;} enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -1312,11 +1322,11 @@ public: uint max_packed_col_length(uint max_length); void free() { value.free(); } inline void clear_temporary() { bzero((char*) &value,sizeof(value)); } - friend void field_conv(Field *to,Field *from); + friend int field_conv(Field *to,Field *from); uint size_of() const { return sizeof(*this); } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } - uint32 max_length(); + uint32 max_display_length(); }; @@ -1337,7 +1347,7 @@ public: :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) { geom_type= geom_type_arg; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } - enum_field_types type() const { return FIELD_TYPE_GEOMETRY; } + enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } void sql_type(String &str) const; int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); @@ -1367,7 +1377,8 @@ public: { flags|=ENUM_FLAG; } - enum_field_types type() const { return FIELD_TYPE_STRING; } + Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type); + enum_field_types type() const { return MYSQL_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } enum Item_result cast_to_int_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; @@ -1383,7 +1394,7 @@ public: void store_type(ulonglong value); void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return FIELD_TYPE_ENUM; } + enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } virtual bool zero_pack() const { return 0; } bool optimize_range(uint idx, uint part) { return 0; } bool eq_def(Field *field); @@ -1413,7 +1424,7 @@ public: virtual bool zero_pack() const { return 1; } String *val_str(String*,String *); void sql_type(String &str) const; - enum_field_types real_type() const { return FIELD_TYPE_SET; } + enum_field_types real_type() const { return MYSQL_TYPE_SET; } bool has_charset(void) const { return TRUE; } }; @@ -1441,10 +1452,10 @@ public: Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, enum utype unireg_check_arg, const char *field_name_arg); - enum_field_types type() const { return FIELD_TYPE_BIT; } + enum_field_types type() const { return MYSQL_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) (field_length + 7) / 8; } - uint32 max_length() { return field_length; } + uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } int reset(void) { bzero(ptr, bytes_in_rec); return 0; } @@ -1504,6 +1515,13 @@ private: }; +/** + BIT field represented as chars for non-MyISAM tables. + + @todo The inheritance relationship is backwards since Field_bit is + an extended version of Field_bit_as_char and not the other way + around. Hence, we should refactor it to fix the hierarchy order. + */ class Field_bit_as_char: public Field_bit { public: Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 5fde5ecb2e8..805aba01754 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -165,7 +164,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) when set to NULL (TIMESTAMP fields which allow setting to NULL are handled by first check). */ - if (field->type() == FIELD_TYPE_TIMESTAMP) + if (field->type() == MYSQL_TYPE_TIMESTAMP) { ((Field_timestamp*) field)->set_time(); return 0; // Ok to set time to NULL @@ -500,7 +499,7 @@ void Copy_field::set(char *to,Field *from) void Copy_field::set(Field *to,Field *from,bool save) { - if (to->type() == FIELD_TYPE_NULL) + if (to->type() == MYSQL_TYPE_NULL) { to_null_ptr=0; // For easy debugging to_ptr=0; @@ -534,7 +533,7 @@ void Copy_field::set(Field *to,Field *from,bool save) } else { - if (to_field->type() == FIELD_TYPE_TIMESTAMP) + if (to_field->type() == MYSQL_TYPE_TIMESTAMP) do_copy= do_copy_timestamp; // Automatic timestamp else if (to_field == to_field->table->next_number_field) do_copy= do_copy_next_number; @@ -578,8 +577,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) } else { - if (to->real_type() == FIELD_TYPE_BIT || - from->real_type() == FIELD_TYPE_BIT) + if (to->real_type() == MYSQL_TYPE_BIT || + from->real_type() == MYSQL_TYPE_BIT) return do_field_int; // Check if identical fields if (from->result_type() == STRING_RESULT) @@ -601,17 +600,17 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) !compatible_db_low_byte_first || ((to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) && - to->type() == FIELD_TYPE_DATE || - to->type() == FIELD_TYPE_DATETIME)) + to->type() == MYSQL_TYPE_DATE || + to->type() == MYSQL_TYPE_DATETIME)) { - if (from->real_type() == FIELD_TYPE_ENUM || - from->real_type() == FIELD_TYPE_SET) + if (from->real_type() == MYSQL_TYPE_ENUM || + from->real_type() == MYSQL_TYPE_SET) if (to->result_type() != STRING_RESULT) return do_field_int; // Convert SET to number return do_field_string; } - if (to->real_type() == FIELD_TYPE_ENUM || - to->real_type() == FIELD_TYPE_SET) + if (to->real_type() == MYSQL_TYPE_ENUM || + to->real_type() == MYSQL_TYPE_SET) { if (!to->eq_def(from)) return do_field_string; @@ -644,7 +643,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) to_length != from_length || !compatible_db_low_byte_first) { - if (to->real_type() == FIELD_TYPE_DECIMAL || + if (to->real_type() == MYSQL_TYPE_DECIMAL || to->result_type() == STRING_RESULT) return do_field_string; if (to->result_type() == INT_RESULT) @@ -655,7 +654,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) { if (!to->eq_def(from) || !compatible_db_low_byte_first) { - if (to->real_type() == FIELD_TYPE_DECIMAL) + if (to->real_type() == MYSQL_TYPE_DECIMAL) return do_field_string; if (to->result_type() == INT_RESULT) return do_field_int; @@ -679,25 +678,25 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) /* Simple quick field convert that is called on insert */ -void field_conv(Field *to,Field *from) +int field_conv(Field *to,Field *from) { if (to->real_type() == from->real_type() && - !(to->type() == FIELD_TYPE_BLOB && to->table->copy_blobs)) + !(to->type() == MYSQL_TYPE_BLOB && to->table->copy_blobs)) { if (to->pack_length() == from->pack_length() && !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && - to->real_type() != FIELD_TYPE_ENUM && - to->real_type() != FIELD_TYPE_SET && - to->real_type() != FIELD_TYPE_BIT && - (to->real_type() != FIELD_TYPE_NEWDECIMAL || + to->real_type() != MYSQL_TYPE_ENUM && + to->real_type() != MYSQL_TYPE_SET && + to->real_type() != MYSQL_TYPE_BIT && + (to->real_type() != MYSQL_TYPE_NEWDECIMAL || (to->field_length == from->field_length && (((Field_num*)to)->dec == ((Field_num*)from)->dec))) && from->charset() == to->charset() && to->table->s->db_low_byte_first == from->table->s->db_low_byte_first && (!(to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) || - to->type() != FIELD_TYPE_DATE && - to->type() != FIELD_TYPE_DATETIME) && + to->type() != MYSQL_TYPE_DATE && + to->type() != MYSQL_TYPE_DATETIME) && (from->real_type() != MYSQL_TYPE_VARCHAR || ((Field_varstring*)from)->length_bytes == ((Field_varstring*)to)->length_bytes)) @@ -707,10 +706,10 @@ void field_conv(Field *to,Field *from) if (to->ptr != from->ptr) #endif memcpy(to->ptr,from->ptr,to->pack_length()); - return; + return 0; } } - if (to->type() == FIELD_TYPE_BLOB) + if (to->type() == MYSQL_TYPE_BLOB) { // Be sure the value is stored Field_blob *blob=(Field_blob*) to; from->val_str(&blob->value); @@ -723,14 +722,13 @@ void field_conv(Field *to,Field *from) from->real_type() != MYSQL_TYPE_STRING && from->real_type() != MYSQL_TYPE_VARCHAR)) blob->value.copy(); - blob->store(blob->value.ptr(),blob->value.length(),from->charset()); - return; + return blob->store(blob->value.ptr(),blob->value.length(),from->charset()); } if ((from->result_type() == STRING_RESULT && (to->result_type() == STRING_RESULT || - (from->real_type() != FIELD_TYPE_ENUM && - from->real_type() != FIELD_TYPE_SET))) || - to->type() == FIELD_TYPE_DECIMAL) + (from->real_type() != MYSQL_TYPE_ENUM && + from->real_type() != MYSQL_TYPE_SET))) || + to->type() == MYSQL_TYPE_DECIMAL) { char buff[MAX_FIELD_WIDTH]; String result(buff,sizeof(buff),from->charset()); @@ -741,15 +739,15 @@ void field_conv(Field *to,Field *from) end with \0. Can be replaced with .ptr() when we have our own string->double conversion. */ - to->store(result.c_ptr_quick(),result.length(),from->charset()); + return to->store(result.c_ptr_quick(),result.length(),from->charset()); } else if (from->result_type() == REAL_RESULT) - to->store(from->val_real()); + return to->store(from->val_real()); else if (from->result_type() == DECIMAL_RESULT) { my_decimal buff; - to->store_decimal(from->val_decimal(&buff)); + return to->store_decimal(from->val_decimal(&buff)); } else - to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG)); + return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG)); } diff --git a/sql/filesort.cc b/sql/filesort.cc index 77365499da0..4b0170a0db0 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -105,7 +104,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, uint maxbuffer; BUFFPEK *buffpek; ha_rows records= HA_POS_ERROR; - uchar **sort_keys; + uchar **sort_keys= 0; IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; SORTPARAM param; bool multi_byte_charset; @@ -435,7 +434,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH]; my_off_t record; TABLE *sort_form; - volatile THD::killed_state *killed= ¤t_thd->killed; + THD *thd= current_thd; + volatile THD::killed_state *killed= &thd->killed; handler *file; MY_BITMAP *save_read_set, *save_write_set; DBUG_ENTER("find_all_keys"); @@ -548,6 +548,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, } else file->unlock_row(); + /* It does not make sense to read more keys in case of a fatal error */ + if (thd->net.report_error) + DBUG_RETURN(HA_POS_ERROR); } if (quick_select) { @@ -887,12 +890,14 @@ static void make_sortkey(register SORTPARAM *param, } else { - uchar *end= (uchar*) field->pack((char *) to, field->ptr); #ifdef HAVE_purify + uchar *end= (uchar*) field->pack((char *) to, field->ptr); uint length= (uint) ((to + addonf->length) - end); DBUG_ASSERT((int) length >= 0); if (length) bzero(end, length); +#else + (void) field->pack((char *) to, field->ptr); #endif } to+= addonf->length; diff --git a/sql/frm_crypt.cc b/sql/frm_crypt.cc index 8dd70900648..590205e83ab 100644 --- a/sql/frm_crypt.cc +++ b/sql/frm_crypt.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index ab0dd500f64..7a78bcf591e 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -446,10 +445,24 @@ int main(int argc,char **argv) /* Broken up to indicate that it's not advice to you, gentle reader. */ printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n"); - printf("/* Copyright (C) 2001-2004 MySQL AB\n\ - This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ - and you are welcome to modify and redistribute it under the GPL license\n\ - \n*/\n\n"); + printf("\ +/* Copyright (C) 2001-2004 MySQL AB\n\ +\n\ + This program is free software; you can redistribute it and/or modify\n\ + it under the terms of the GNU General Public License as published by\n\ + the Free Software Foundation; version 2 of the License.\n\ +\n\ + This program is distributed in the hope that it will be useful,\n\ + but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ + GNU General Public License for more details.\n\ +\n\ + You should have received a copy of the GNU General Public License\n\ + along with this program; see the file COPYING. If not, write to the\n\ + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston\n\ + MA 02110-1301 USA. */\n\ +\n\ +"); /* Broken up to indicate that it's not advice to you, gentle reader. */ printf("/* Do " "not " "edit " "this " "file! This is generated by " diff --git a/sql/gstream.cc b/sql/gstream.cc index 4083cb2fe71..46e12b6ef3b 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/gstream.h b/sql/gstream.h index bfbf28851ce..10274635413 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0c3a79baacc..9c3959f3feb 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -134,7 +133,7 @@ static uint ndbcluster_alter_table_flags(uint flags) } static int ndbcluster_inited= 0; -int ndbcluster_util_inited= 0; +static int ndbcluster_terminating= 0; static Ndb* g_ndb= NULL; Ndb_cluster_connection* g_ndb_cluster_connection= NULL; @@ -151,15 +150,16 @@ static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length, #ifdef HAVE_NDB_BINLOG static int rename_share(NDB_SHARE *share, const char *new_key); #endif -static void ndb_set_fragmentation(NDBTAB &tab, TABLE *table, uint pk_len); static int ndb_get_table_statistics(ha_ndbcluster*, bool, Ndb*, const NDBTAB *, struct Ndb_statistics *); // Util thread variables pthread_t ndb_util_thread; +int ndb_util_thread_running= 0; pthread_mutex_t LOCK_ndb_util_thread; pthread_cond_t COND_ndb_util_thread; +pthread_cond_t COND_ndb_util_ready; pthread_handler_t ndb_util_thread_func(void *arg); ulong ndb_cache_check_time; @@ -259,16 +259,16 @@ static int ndb_to_mysql_error(const NdbError *ndberr) int execute_no_commit_ignore_no_key(ha_ndbcluster *h, NdbTransaction *trans) { - int res= trans->execute(NdbTransaction::NoCommit, - NdbTransaction::AO_IgnoreError, - h->m_force_send); - if (res == 0) - return 0; + if (trans->execute(NdbTransaction::NoCommit, + NdbOperation::AO_IgnoreError, + h->m_force_send) == -1) + return -1; const NdbError &err= trans->getNdbError(); - if (err.classification != NdbError::ConstraintViolation && + if (err.classification != NdbError::NoError && + err.classification != NdbError::ConstraintViolation && err.classification != NdbError::NoDataFound) - return res; + return -1; return 0; } @@ -286,7 +286,7 @@ int execute_no_commit(ha_ndbcluster *h, NdbTransaction *trans, return h->m_ignore_no_key ? execute_no_commit_ignore_no_key(h,trans) : trans->execute(NdbTransaction::NoCommit, - NdbTransaction::AbortOnError, + NdbOperation::AbortOnError, h->m_force_send); } @@ -299,7 +299,7 @@ int execute_commit(ha_ndbcluster *h, NdbTransaction *trans) return 0; #endif return trans->execute(NdbTransaction::Commit, - NdbTransaction::AbortOnError, + NdbOperation::AbortOnError, h->m_force_send); } @@ -312,7 +312,7 @@ int execute_commit(THD *thd, NdbTransaction *trans) return 0; #endif return trans->execute(NdbTransaction::Commit, - NdbTransaction::AbortOnError, + NdbOperation::AbortOnError, thd->variables.ndb_force_send); } @@ -327,7 +327,7 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans, #endif h->release_completed_operations(trans, force_release); return trans->execute(NdbTransaction::NoCommit, - NdbTransaction::AO_IgnoreError, + NdbOperation::AO_IgnoreError, h->m_force_send); } @@ -442,15 +442,15 @@ ha_rows ha_ndbcluster::records() { ha_rows retval; DBUG_ENTER("ha_ndbcluster::records"); - struct Ndb_local_table_statistics *info= m_table_info; + struct Ndb_local_table_statistics *local_info= m_table_info; DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d", ((const NDBTAB *)m_table)->getTableId(), - info->no_uncommitted_rows_count)); + local_info->no_uncommitted_rows_count)); Ndb *ndb= get_ndb(); ndb->setDatabaseName(m_dbname); struct Ndb_statistics stat; - if (ndb_get_table_statistics(this, true, ndb, m_table, &stat) == 0) + if (ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat) == 0) { retval= stat.row_count; } @@ -461,9 +461,9 @@ ha_rows ha_ndbcluster::records() THD *thd= current_thd; if (get_thd_ndb(thd)->error) - info->no_uncommitted_rows_count= 0; + local_info->no_uncommitted_rows_count= 0; - DBUG_RETURN(retval + info->no_uncommitted_rows_count); + DBUG_RETURN(retval + local_info->no_uncommitted_rows_count); } int ha_ndbcluster::records_update() @@ -473,30 +473,29 @@ int ha_ndbcluster::records_update() DBUG_ENTER("ha_ndbcluster::records_update"); int result= 0; - struct Ndb_local_table_statistics *info= m_table_info; + struct Ndb_local_table_statistics *local_info= m_table_info; DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d", ((const NDBTAB *)m_table)->getTableId(), - info->no_uncommitted_rows_count)); - // if (info->records == ~(ha_rows)0) + local_info->no_uncommitted_rows_count)); { Ndb *ndb= get_ndb(); struct Ndb_statistics stat; ndb->setDatabaseName(m_dbname); - result= ndb_get_table_statistics(this, true, ndb, m_table, &stat); + result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat); if (result == 0) { stats.mean_rec_length= stat.row_size; stats.data_file_length= stat.fragment_memory; - info->records= stat.row_count; + local_info->records= stat.row_count; } } { THD *thd= current_thd; if (get_thd_ndb(thd)->error) - info->no_uncommitted_rows_count= 0; + local_info->no_uncommitted_rows_count= 0; } - if(result==0) - stats.records= info->records+ info->no_uncommitted_rows_count; + if (result == 0) + stats.records= local_info->records+ local_info->no_uncommitted_rows_count; DBUG_RETURN(result); } @@ -514,11 +513,11 @@ void ha_ndbcluster::no_uncommitted_rows_update(int c) if (m_ha_not_exact_count) return; DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_update"); - struct Ndb_local_table_statistics *info= m_table_info; - info->no_uncommitted_rows_count+= c; + struct Ndb_local_table_statistics *local_info= m_table_info; + local_info->no_uncommitted_rows_count+= c; DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d", ((const NDBTAB *)m_table)->getTableId(), - info->no_uncommitted_rows_count)); + local_info->no_uncommitted_rows_count)); DBUG_VOID_RETURN; } @@ -955,7 +954,6 @@ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) bool ha_ndbcluster::uses_blob_value() { - uint blob_fields; MY_BITMAP *bitmap; uint *blob_index, *blob_index_end; if (table_share->blob_fields == 0) @@ -1105,7 +1103,6 @@ int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab) const char *index_name; KEY* key_info= tab->key_info; const char **key_name= tab->s->keynames.type_names; - NDBDICT *dict= ndb->getDictionary(); DBUG_ENTER("ha_ndbcluster::create_indexes"); for (i= 0; i < tab->s->keys; i++, key_info++, key_name++) @@ -1243,7 +1240,6 @@ int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error) int error= 0; THD *thd=current_thd; NDBDICT *dict= ndb->getDictionary(); - const char *index_name; KEY* key_info= tab->key_info; const char **key_name= tab->s->keynames.type_names; DBUG_ENTER("ha_ndbcluster::open_indexes"); @@ -1255,9 +1251,9 @@ int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error) m_index[i].index= m_index[i].unique_index= NULL; else break; - m_index[i].null_in_unique_index= false; + m_index[i].null_in_unique_index= FALSE; if (check_index_fields_not_null(key_info)) - m_index[i].null_in_unique_index= true; + m_index[i].null_in_unique_index= TRUE; } if (error && !ignore_error) @@ -1293,7 +1289,6 @@ void ha_ndbcluster::renumber_indexes(Ndb *ndb, TABLE *tab) const char *index_name; KEY* key_info= tab->key_info; const char **key_name= tab->s->keynames.type_names; - NDBDICT *dict= ndb->getDictionary(); DBUG_ENTER("ha_ndbcluster::renumber_indexes"); for (i= 0; i < tab->s->keys; i++, key_info++, key_name++) @@ -1410,10 +1405,10 @@ bool ha_ndbcluster::check_index_fields_not_null(KEY* key_info) { Field* field= key_part->field; if (field->maybe_null()) - DBUG_RETURN(true); + DBUG_RETURN(TRUE); } - DBUG_RETURN(false); + DBUG_RETURN(FALSE); } void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb) @@ -1731,7 +1726,8 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf, ERR_RETURN(trans->getNdbError()); } - if (execute_no_commit_ie(this,trans,false) != 0) + if ((res = execute_no_commit_ie(this,trans,FALSE)) != 0 || + op->getNdbError().code) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(ndb_err(trans)); @@ -1796,7 +1792,7 @@ int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data, } } - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(ndb_err(trans)); @@ -1842,7 +1838,7 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans, if (err.status != NdbError::Success) { if (ndb_to_mysql_error(&err) != (int) errcode) - DBUG_RETURN(false); + DBUG_RETURN(FALSE); if (op == last) break; op= trans->getNextCompletedOperation(op); } @@ -1873,10 +1869,10 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans, if (errcode == HA_ERR_KEY_NOT_FOUND) m_dupkey= table->s->primary_key; } - DBUG_RETURN(false); + DBUG_RETURN(FALSE); } } - DBUG_RETURN(true); + DBUG_RETURN(TRUE); } @@ -1954,7 +1950,7 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record, } last= trans->getLastDefinedOperation(); if (first) - res= execute_no_commit_ie(this,trans,false); + res= execute_no_commit_ie(this,trans,FALSE); else { // Table has no keys @@ -2003,7 +1999,8 @@ int ha_ndbcluster::unique_index_read(const byte *key, if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); - if (execute_no_commit_ie(this,trans,false) != 0) + if (execute_no_commit_ie(this,trans,FALSE) != 0 || + op->getNdbError().code) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(ndb_err(trans)); @@ -2017,7 +2014,7 @@ int ha_ndbcluster::unique_index_read(const byte *key, inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { DBUG_ENTER("fetch_next"); - int check; + int local_check; NdbTransaction *trans= m_active_trans; if (m_lock_tuple) @@ -2028,19 +2025,21 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) LOCK WITH SHARE MODE) and row was not explictly unlocked with unlock_row() call */ - NdbConnection *trans= m_active_trans; + NdbConnection *con_trans= m_active_trans; NdbOperation *op; // Lock row DBUG_PRINT("info", ("Keeping lock on scanned row")); if (!(op= m_active_cursor->lockCurrentTuple())) { - m_lock_tuple= false; - ERR_RETURN(trans->getNdbError()); + /* purecov: begin inspected */ + m_lock_tuple= FALSE; + ERR_RETURN(con_trans->getNdbError()); + /* purecov: end */ } m_ops_pending++; } - m_lock_tuple= false; + m_lock_tuple= FALSE; bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE && m_lock.type != TL_READ_WITH_SHARED_LOCKS;; @@ -2051,13 +2050,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) */ if (m_ops_pending && m_blobs_pending) { - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) DBUG_RETURN(ndb_err(trans)); m_ops_pending= 0; m_blobs_pending= FALSE; } - if ((check= cursor->nextResult(contact_ndb, m_force_send)) == 0) + if ((local_check= cursor->nextResult(contact_ndb, m_force_send)) == 0) { /* Explicitly lock tuple if "select for update" or @@ -2068,7 +2067,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) m_lock.type == TL_READ_WITH_SHARED_LOCKS); DBUG_RETURN(0); } - else if (check == 1 || check == 2) + else if (local_check == 1 || local_check == 2) { // 1: No more records // 2: No more cached records @@ -2083,7 +2082,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { if (m_transaction_on) { - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) DBUG_RETURN(-1); } else @@ -2098,13 +2097,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) } m_ops_pending= 0; } - contact_ndb= (check == 2); + contact_ndb= (local_check == 2); } else { DBUG_RETURN(-1); } - } while (check == 2); + } while (local_check == 2); DBUG_RETURN(1); } @@ -2281,8 +2280,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, DBUG_PRINT("error", ("key %d unknown flag %d", j, p.key->flag)); DBUG_ASSERT(FALSE); // Stop setting bounds but continue with what we have - op->end_of_bound(range_no); - DBUG_RETURN(0); + DBUG_RETURN(op->end_of_bound(range_no)); } } } @@ -2329,8 +2327,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, tot_len+= part_store_len; } - op->end_of_bound(range_no); - DBUG_RETURN(0); + DBUG_RETURN(op->end_of_bound(range_no)); } /* @@ -2364,7 +2361,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, bool need_pk = (lm == NdbOperation::LM_Read); if (!(op= trans->getNdbIndexScanOperation(m_index[active_index].index, m_table)) || - op->readTuples(lm, 0, parallelism, sorted, descending, false, need_pk)) + op->readTuples(lm, 0, parallelism, sorted, descending, FALSE, need_pk)) ERR_RETURN(trans->getNdbError()); if (m_use_partition_function && part_spec != NULL && part_spec->start_part == part_spec->end_part) @@ -2386,7 +2383,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, { const key_range *keys[2]= { start_key, end_key }; - res= set_bounds(op, active_index, false, keys); + res= set_bounds(op, active_index, FALSE, keys); if (res) DBUG_RETURN(res); } @@ -2410,7 +2407,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, ERR_RETURN(trans->getNdbError()); } - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) DBUG_RETURN(ndb_err(trans)); DBUG_RETURN(next_result(buf)); @@ -2505,7 +2502,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info, if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) DBUG_RETURN(ndb_err(trans)); DBUG_PRINT("exit", ("Scan started successfully")); DBUG_RETURN(next_result(buf)); @@ -2574,7 +2571,7 @@ int ha_ndbcluster::full_table_scan(byte *buf) if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) DBUG_RETURN(ndb_err(trans)); DBUG_PRINT("exit", ("Scan started successfully")); DBUG_RETURN(next_result(buf)); @@ -2590,7 +2587,7 @@ int ha_ndbcluster::write_row(byte *record) NdbTransaction *trans= m_active_trans; NdbOperation *op; int res; - THD *thd= current_thd; + THD *thd= table->in_use; longlong func_value= 0; DBUG_ENTER("ha_ndbcluster::write_row"); @@ -2603,7 +2600,6 @@ int ha_ndbcluster::write_row(byte *record) */ if (has_auto_increment) { - THD *thd= table->in_use; int error; m_skip_auto_increment= FALSE; @@ -2623,7 +2619,7 @@ int ha_ndbcluster::write_row(byte *record) start_bulk_insert will set parameters to ensure that each write_row is committed individually */ - int peek_res= peek_indexed_rows(record, true); + int peek_res= peek_indexed_rows(record, TRUE); if (!peek_res) { @@ -2742,7 +2738,7 @@ int ha_ndbcluster::write_row(byte *record) m_bulk_insert_not_flushed= FALSE; if (m_transaction_on) { - if (execute_no_commit(this,trans,false) != 0) + if (execute_no_commit(this,trans,FALSE) != 0) { m_skip_auto_increment= TRUE; no_uncommitted_rows_execute_failure(); @@ -2768,10 +2764,12 @@ int ha_ndbcluster::write_row(byte *record) { Ndb *ndb= get_ndb(); Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1; +#ifndef DBUG_OFF char buff[22]; DBUG_PRINT("info", ("Trying to set next auto increment value to %s", llstr(next_val, buff))); +#endif Ndb_tuple_id_range_guard g(m_share); if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) == -1) @@ -2824,7 +2822,7 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row, int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) { - THD *thd= current_thd; + THD *thd= table->in_use; NdbTransaction *trans= m_active_trans; NdbScanOperation* cursor= m_active_cursor; NdbOperation *op; @@ -2933,7 +2931,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) DBUG_PRINT("info", ("Calling updateTuple on cursor")); if (!(op= cursor->updateCurrentTuple())) ERR_RETURN(trans->getNdbError()); - m_lock_tuple= false; + m_lock_tuple= FALSE; m_ops_pending++; if (uses_blob_value()) m_blobs_pending= TRUE; @@ -2996,7 +2994,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) op->setValue(no_fields, part_func_value); } // Execute update operation - if (!cursor && execute_no_commit(this,trans,false) != 0) { + if (!cursor && execute_no_commit(this,trans,FALSE) != 0) { no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } @@ -3011,7 +3009,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) int ha_ndbcluster::delete_row(const byte *record) { - THD *thd= current_thd; + THD *thd= table->in_use; NdbTransaction *trans= m_active_trans; NdbScanOperation* cursor= m_active_cursor; NdbOperation *op; @@ -3042,7 +3040,7 @@ int ha_ndbcluster::delete_row(const byte *record) DBUG_PRINT("info", ("Calling deleteTuple on cursor")); if (cursor->deleteCurrentTuple() != 0) ERR_RETURN(trans->getNdbError()); - m_lock_tuple= false; + m_lock_tuple= FALSE; m_ops_pending++; if (m_use_partition_function) @@ -3082,7 +3080,7 @@ int ha_ndbcluster::delete_row(const byte *record) } // Execute delete operation - if (execute_no_commit(this,trans,false) != 0) { + if (execute_no_commit(this,trans,FALSE) != 0) { no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } @@ -3310,8 +3308,7 @@ int ha_ndbcluster::index_init(uint index, bool sorted) unless m_lock.type == TL_READ_HIGH_PRIORITY and no sub-sequent call to unlock_row() */ - m_lock_tuple= false; - m_lock_tuple= false; + m_lock_tuple= FALSE; DBUG_RETURN(0); } @@ -3333,7 +3330,6 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len) const byte* end_ptr= key + key_len; curr_part= key_info->key_part; end_part= curr_part + key_info->key_parts; - for (; curr_part != end_part && key < end_ptr; curr_part++) { @@ -3478,8 +3474,9 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, { if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); - DBUG_RETURN(pk_read(start_key->key, start_key->length, buf, - part_spec.start_part)); + error= pk_read(start_key->key, start_key->length, buf, + part_spec.start_part); + DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); } break; case UNIQUE_ORDERED_INDEX: @@ -3490,7 +3487,9 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, { if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); - DBUG_RETURN(unique_index_read(start_key->key, start_key->length, buf)); + + error= unique_index_read(start_key->key, start_key->length, buf); + DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); } else if (type == UNIQUE_INDEX) DBUG_RETURN(unique_index_scan(key_info, @@ -3568,12 +3567,12 @@ int ha_ndbcluster::close_scan() if (!(op= cursor->lockCurrentTuple())) { - m_lock_tuple= false; + m_lock_tuple= FALSE; ERR_RETURN(trans->getNdbError()); } m_ops_pending++; } - m_lock_tuple= false; + m_lock_tuple= FALSE; if (m_ops_pending) { /* @@ -3581,7 +3580,7 @@ int ha_ndbcluster::close_scan() deleteing/updating transaction before closing the scan */ DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending)); - if (execute_no_commit(this,trans,false) != 0) { + if (execute_no_commit(this,trans,FALSE) != 0) { no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } @@ -3699,20 +3698,26 @@ void ha_ndbcluster::position(const byte *record) size_t len = key_part->length; const byte * ptr = record + key_part->offset; Field *field = key_part->field; - if ((field->type() == MYSQL_TYPE_VARCHAR) && - ((Field_varstring*)field)->length_bytes == 1) + if (field->type() == MYSQL_TYPE_VARCHAR) { - /** - * Keys always use 2 bytes length - */ - buff[0] = ptr[0]; - buff[1] = 0; - memcpy(buff+2, ptr + 1, len); - len += 2; + if (((Field_varstring*)field)->length_bytes == 1) + { + /** + * Keys always use 2 bytes length + */ + buff[0] = ptr[0]; + buff[1] = 0; + memcpy(buff+2, ptr + 1, len); + } + else + { + memcpy(buff, ptr, len + 2); + } + len += 2; } else { - memcpy(buff, ptr, len); + memcpy(buff, ptr, len); } buff += len; } @@ -3780,7 +3785,7 @@ int ha_ndbcluster::info(uint flag) struct Ndb_statistics stat; ndb->setDatabaseName(m_dbname); if (current_thd->variables.ndb_use_exact_count && - (result= ndb_get_table_statistics(this, true, ndb, m_table, &stat)) + (result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat)) == 0) { stats.mean_rec_length= stat.row_size; @@ -3807,7 +3812,7 @@ int ha_ndbcluster::info(uint flag) if (flag & HA_STATUS_AUTO) { DBUG_PRINT("info", ("HA_STATUS_AUTO")); - if (m_table) + if (m_table && table->found_next_number_field) { Ndb *ndb= get_ndb(); Ndb_tuple_id_range_guard g(m_share); @@ -3981,7 +3986,7 @@ int ha_ndbcluster::end_bulk_insert() m_bulk_insert_not_flushed= FALSE; if (m_transaction_on) { - if (execute_no_commit(this, trans,false) != 0) + if (execute_no_commit(this, trans,FALSE) != 0) { no_uncommitted_rows_execute_failure(); my_errno= error= ndb_err(trans); @@ -3996,7 +4001,7 @@ int ha_ndbcluster::end_bulk_insert() } else { - int res= trans->restart(); + IF_DBUG(int res=) trans->restart(); DBUG_ASSERT(res == 0); } } @@ -4306,7 +4311,7 @@ void ha_ndbcluster::unlock_row() DBUG_ENTER("unlock_row"); DBUG_PRINT("info", ("Unlocking row")); - m_lock_tuple= false; + m_lock_tuple= FALSE; DBUG_VOID_RETURN; } @@ -4334,11 +4339,10 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) ERR_RETURN(ndb->getNdbError()); no_uncommitted_rows_reset(thd); thd_ndb->stmt= trans; + thd_ndb->query_state&= NDB_QUERY_NORMAL; trans_register_ha(thd, FALSE, ndbcluster_hton); } - thd_ndb->query_state&= NDB_QUERY_NORMAL; m_active_trans= trans; - // Start of statement m_ops_pending= 0; thd->set_current_stmt_binlog_row_based_if_mixed(); @@ -4636,19 +4640,29 @@ static int create_ndb_column(NDBCOL &col, col.setType(NDBCOL::Text); col.setCharset(cs); } - // Use "<=" even if "<" is the exact condition - if (field->max_length() <= (1 << 8)) - goto mysql_type_tiny_blob; - else if (field->max_length() <= (1 << 16)) { - col.setInlineSize(256); - col.setPartSize(2000); - col.setStripeSize(16); + Field_blob *field_blob= (Field_blob *)field; + /* + * max_data_length is 2^8-1, 2^16-1, 2^24-1 for tiny, blob, medium. + * Tinyblob gets no blob parts. The other cases are just a crude + * way to control part size and striping. + * + * In mysql blob(256) is promoted to blob(65535) so it does not + * in fact fit "inline" in NDB. + */ + if (field_blob->max_data_length() < (1 << 8)) + goto mysql_type_tiny_blob; + else if (field_blob->max_data_length() < (1 << 16)) + { + col.setInlineSize(256); + col.setPartSize(2000); + col.setStripeSize(16); + } + else if (field_blob->max_data_length() < (1 << 24)) + goto mysql_type_medium_blob; + else + goto mysql_type_long_blob; } - else if (field->max_length() <= (1 << 24)) - goto mysql_type_medium_blob; - else - goto mysql_type_long_blob; break; mysql_type_medium_blob: case MYSQL_TYPE_MEDIUM_BLOB: @@ -4705,7 +4719,9 @@ static int create_ndb_column(NDBCOL &col, // Set autoincrement if (field->flags & AUTO_INCREMENT_FLAG) { +#ifndef DBUG_OFF char buff[22]; +#endif col.setAutoIncrement(TRUE); ulonglong value= info->auto_increment_value ? info->auto_increment_value : (ulonglong) 1; @@ -4723,15 +4739,16 @@ static int create_ndb_column(NDBCOL &col, int ha_ndbcluster::create(const char *name, TABLE *form, - HA_CREATE_INFO *info) + HA_CREATE_INFO *create_info) { THD *thd= current_thd; NDBTAB tab; NDBCOL col; uint pack_length, length, i, pk_length= 0; const void *data, *pack_data; - bool create_from_engine= (info->table_options & HA_OPTION_CREATE_FROM_ENGINE); + bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE); bool is_truncate= (thd->lex->sql_command == SQLCOM_TRUNCATE); + char tablespace[FN_LEN]; DBUG_ENTER("ha_ndbcluster::create"); DBUG_PRINT("enter", ("name: %s", name)); @@ -4740,8 +4757,22 @@ int ha_ndbcluster::create(const char *name, set_dbname(name); set_tabname(name); + if ((my_errno= check_ndb_connection())) + DBUG_RETURN(my_errno); + + Ndb *ndb= get_ndb(); + NDBDICT *dict= ndb->getDictionary(); + if (is_truncate) { + { + Ndb_table_guard ndbtab_g(dict, m_tabname); + if (!(m_table= ndbtab_g.get_table())) + ERR_RETURN(dict->getNdbError()); + if ((get_tablespace_name(thd, tablespace, FN_LEN))) + create_info->tablespace= tablespace; + m_table= NULL; + } DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE")); if ((my_errno= delete_table(name))) DBUG_RETURN(my_errno); @@ -4780,7 +4811,7 @@ int ha_ndbcluster::create(const char *name, DBUG_PRINT("table", ("name: %s", m_tabname)); tab.setName(m_tabname); - tab.setLogging(!(info->options & HA_LEX_CREATE_TMP_TABLE)); + tab.setLogging(!(create_info->options & HA_LEX_CREATE_TMP_TABLE)); // Save frm data for this table if (readfrm(name, &data, &length)) @@ -4801,10 +4832,10 @@ int ha_ndbcluster::create(const char *name, DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d", field->field_name, field->real_type(), field->pack_length())); - if ((my_errno= create_ndb_column(col, field, info))) + if ((my_errno= create_ndb_column(col, field, create_info))) DBUG_RETURN(my_errno); - if (info->store_on_disk || getenv("NDB_DEFAULT_DISK")) + if (create_info->storage_media == HA_SM_DISK) col.setStorageType(NdbDictionary::Column::StorageTypeDisk); else col.setStorageType(NdbDictionary::Column::StorageTypeMemory); @@ -4824,17 +4855,27 @@ int ha_ndbcluster::create(const char *name, NdbDictionary::Column::StorageTypeMemory); } - if (info->store_on_disk) + if (create_info->storage_media == HA_SM_DISK) { - if (info->tablespace) - tab.setTablespace(info->tablespace); + if (create_info->tablespace) + tab.setTablespaceName(create_info->tablespace); else - tab.setTablespace("DEFAULT-TS"); + tab.setTablespaceName("DEFAULT-TS"); } - else if (info->tablespace) + else if (create_info->tablespace) { - tab.setTablespace(info->tablespace); - info->store_on_disk = true; //if use tablespace, that also means store on disk + if (create_info->storage_media == HA_SM_MEMORY) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_ILLEGAL_HA_CREATE_OPTION, + ER(ER_ILLEGAL_HA_CREATE_OPTION), + ndbcluster_hton_name, + "TABLESPACE currently only supported for " + "STORAGE DISK"); + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } + tab.setTablespaceName(create_info->tablespace); + create_info->storage_media = HA_SM_DISK; //if use tablespace, that also means store on disk } // No primary key, create shadow key as 64 bit, auto increment @@ -4865,13 +4906,13 @@ int ha_ndbcluster::create(const char *name, case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: { - NdbDictionary::Column * col= tab.getColumn(i); - int size= pk_length + (col->getPartSize()+3)/4 + 7; + NdbDictionary::Column * column= tab.getColumn(i); + int size= pk_length + (column->getPartSize()+3)/4 + 7; if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS && (pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS) { size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7; - col->setPartSize(4*size); + column->setPartSize(4*size); } /** * If size > NDB_MAX and pk_length+7 >= NDB_MAX @@ -4891,12 +4932,7 @@ int ha_ndbcluster::create(const char *name, DBUG_RETURN(my_errno); } - if ((my_errno= check_ndb_connection())) - DBUG_RETURN(my_errno); - // Create the table in NDB - Ndb *ndb= get_ndb(); - NDBDICT *dict= ndb->getDictionary(); if (dict->createTable(tab) != 0) { const NdbError err= dict->getNdbError(); @@ -4969,11 +5005,17 @@ int ha_ndbcluster::create(const char *name, get a new share */ - if (!(share= get_share(name, form, true, true))) + /* ndb_share reference create */ + if (!(share= get_share(name, form, TRUE, TRUE))) { sql_print_error("NDB: allocating table share for %s failed", name); /* my_errno is set */ } + else + { + DBUG_PRINT("NDB_SHARE", ("%s binlog create use_count: %u", + share->key, share->use_count)); + } pthread_mutex_unlock(&ndbcluster_mutex); while (!IS_TMP_PREFIX(m_tabname)) @@ -4997,7 +5039,7 @@ int ha_ndbcluster::create(const char *name, if (ndb_extra_logging) sql_print_information("NDB Binlog: CREATE TABLE Event: %s", event_name.c_ptr()); - if (share && do_event_op && + if (share && ndbcluster_create_event_ops(share, m_table, event_name.c_ptr())) { sql_print_error("NDB Binlog: FAILED CREATE TABLE event operations." @@ -5031,10 +5073,8 @@ int ha_ndbcluster::create(const char *name, int ha_ndbcluster::create_handler_files(const char *file, const char *old_name, int action_flag, - HA_CREATE_INFO *info) + HA_CREATE_INFO *create_info) { - char path[FN_REFLEN]; - const char *name; Ndb* ndb; const NDBTAB *tab; const void *data, *pack_data; @@ -5052,7 +5092,7 @@ int ha_ndbcluster::create_handler_files(const char *file, DBUG_RETURN(HA_ERR_NO_CONNECTION); NDBDICT *dict= ndb->getDictionary(); - if (!info->frm_only) + if (!create_info->frm_only) DBUG_RETURN(0); // Must be a create, ignore since frm is saved in create // TODO handle this @@ -5089,6 +5129,9 @@ int ha_ndbcluster::create_handler_files(const char *file, } set_ndb_share_state(m_share, NSS_INITIAL); + /* ndb_share reference schema(?) free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog schema(?) free use_count: %u", + m_share->key, m_share->use_count)); free_share(&m_share); // Decrease ref_count DBUG_RETURN(error); @@ -5131,6 +5174,17 @@ int ha_ndbcluster::create_index(const char *name, KEY *key_info, error= create_unique_index(unique_name, key_info); break; case ORDERED_INDEX: + if (key_info->algorithm == HA_KEY_ALG_HASH) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_ILLEGAL_HA_CREATE_OPTION, + ER(ER_ILLEGAL_HA_CREATE_OPTION), + ndbcluster_hton_name, + "Ndb does not support non-unique " + "hash based indexes"); + error= HA_ERR_UNSUPPORTED; + break; + } error= create_ordered_index(name, key_info); break; default: @@ -5204,7 +5258,10 @@ int ha_ndbcluster::create_ndb_index(const char *name, */ void ha_ndbcluster::prepare_for_alter() { + /* ndb_share reference schema */ ndbcluster_get_share(m_share); // Increase ref_count + DBUG_PRINT("NDB_SHARE", ("%s binlog schema use_count: %u", + m_share->key, m_share->use_count)); set_ndb_share_state(m_share, NSS_ALTERED); } @@ -5225,7 +5282,7 @@ int ha_ndbcluster::add_index(TABLE *table_arg, KEY *key= key_info + idx; KEY_PART_INFO *key_part= key->key_part; KEY_PART_INFO *end= key_part + key->key_parts; - NDB_INDEX_TYPE idx_type= get_index_type_from_key(idx, key, false); + NDB_INDEX_TYPE idx_type= get_index_type_from_key(idx, key_info, false); DBUG_PRINT("info", ("Adding index: '%s'", key_info[idx].name)); // Add fields to key_part struct for (; key_part != end; key_part++) @@ -5238,6 +5295,9 @@ int ha_ndbcluster::add_index(TABLE *table_arg, if (error) { set_ndb_share_state(m_share, NSS_INITIAL); + /* ndb_share reference schema free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u", + m_share->key, m_share->use_count)); free_share(&m_share); // Decrease ref_count } DBUG_RETURN(error); @@ -5282,6 +5342,9 @@ int ha_ndbcluster::final_drop_index(TABLE *table_arg) if((error= drop_indexes(ndb, table_arg))) { m_share->state= NSS_INITIAL; + /* ndb_share reference schema free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u", + m_share->key, m_share->use_count)); free_share(&m_share); // Decrease ref_count } DBUG_RETURN(error); @@ -5323,10 +5386,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) int ndb_table_id= orig_tab->getObjectId(); int ndb_table_version= orig_tab->getObjectVersion(); - NDB_SHARE *share= get_share(from, 0, false); + /* ndb_share reference temporary */ + NDB_SHARE *share= get_share(from, 0, FALSE); if (share) { - int r= rename_share(share, to); + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); + IF_DBUG(int r=) rename_share(share, to); DBUG_ASSERT(r == 0); } #endif @@ -5347,8 +5413,11 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) #ifdef HAVE_NDB_BINLOG if (share) { - int r= rename_share(share, from); - DBUG_ASSERT(r == 0); + IF_DBUG(int ret=) rename_share(share, from); + DBUG_ASSERT(ret == 0); + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); } #endif @@ -5361,7 +5430,12 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) // ToDo in 4.1 should rollback alter table... #ifdef HAVE_NDB_BINLOG if (share) + { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); free_share(&share); + } #endif DBUG_RETURN(result); } @@ -5395,7 +5469,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) if (ndb_extra_logging) sql_print_information("NDB Binlog: RENAME Event: %s", event_name.c_ptr()); - if (share && ndb_binlog_running && + if (share && ndbcluster_create_event_ops(share, ndbtab, event_name.c_ptr())) { sql_print_error("NDB Binlog: FAILED create event operations " @@ -5442,7 +5516,12 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) } } if (share) + { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); + } #endif DBUG_RETURN(result); @@ -5477,7 +5556,13 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb, DBUG_PRINT("info", ("Schema distribution table not setup")); DBUG_RETURN(HA_ERR_NO_CONNECTION); } - NDB_SHARE *share= get_share(path, 0, false); + /* ndb_share reference temporary */ + NDB_SHARE *share= get_share(path, 0, FALSE); + if (share) + { + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); + } #endif /* Drop the table from NDB */ @@ -5557,9 +5642,14 @@ retry_temporary_error1: The share kept by the server has not been freed, free it */ share->state= NSS_DROPPED; + /* ndb_share reference create free */ + DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u", + share->key, share->use_count)); free_share(&share, TRUE); } - /* free the share taken above */ + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share, TRUE); pthread_mutex_unlock(&ndbcluster_mutex); } @@ -5609,9 +5699,14 @@ retry_temporary_error1: The share kept by the server has not been freed, free it */ share->state= NSS_DROPPED; + /* ndb_share reference create free */ + DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u", + share->key, share->use_count)); free_share(&share, TRUE); } - /* free the share taken above */ + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share, TRUE); pthread_mutex_unlock(&ndbcluster_mutex); } @@ -5787,6 +5882,9 @@ ha_ndbcluster::~ha_ndbcluster() if (m_share) { + /* ndb_share reference handler free */ + DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u", + m_share->key, m_share->use_count)); free_share(&m_share); } release_metadata(thd, ndb); @@ -5849,14 +5947,21 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked) DBUG_PRINT("info", ("ref_length: %d", ref_length)); // Init table lock structure + /* ndb_share reference handler */ if (!(m_share=get_share(name, table))) DBUG_RETURN(1); + DBUG_PRINT("NDB_SHARE", ("%s handler use_count: %u", + m_share->key, m_share->use_count)); thr_lock_data_init(&m_share->lock,&m_lock,(void*) 0); set_dbname(name); set_tabname(name); - if (check_ndb_connection()) { + if (check_ndb_connection()) + { + /* ndb_share reference handler free */ + DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u", + m_share->key, m_share->use_count)); free_share(&m_share); m_share= 0; DBUG_RETURN(HA_ERR_NO_CONNECTION); @@ -5868,7 +5973,7 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked) Ndb *ndb= get_ndb(); ndb->setDatabaseName(m_dbname); struct Ndb_statistics stat; - res= ndb_get_table_statistics(NULL, false, ndb, m_table, &stat); + res= ndb_get_table_statistics(NULL, FALSE, ndb, m_table, &stat); stats.mean_rec_length= stat.row_size; stats.data_file_length= stat.fragment_memory; stats.records= stat.row_count; @@ -5915,8 +6020,11 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) int ha_ndbcluster::close(void) { DBUG_ENTER("close"); - THD *thd= current_thd; + THD *thd= table->in_use; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; + /* ndb_share reference handler free */ + DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u", + m_share->key, m_share->use_count)); free_share(&m_share); m_share= 0; release_metadata(thd, ndb); @@ -6023,7 +6131,13 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db, ndb->setDatabaseName(db); NDBDICT* dict= ndb->getDictionary(); build_table_filename(key, sizeof(key), db, name, "", 0); - NDB_SHARE *share= get_share(key, 0, false); + /* ndb_share reference temporary */ + NDB_SHARE *share= get_share(key, 0, FALSE); + if (share) + { + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); + } if (share && get_ndb_share_state(share) == NSS_ALTERED) { // Frm has been altered on disk, but not yet written to ndb @@ -6069,12 +6183,22 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db, *frmblob= data; if (share) + { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); + } DBUG_RETURN(0); err: if (share) + { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); + } if (ndb_error.code) { ERR_RETURN(ndb_error); @@ -6190,7 +6314,6 @@ int ndbcluster_drop_database_impl(const char *path) static void ndbcluster_drop_database(handlerton *hton, char *path) { - THD *thd= current_thd; DBUG_ENTER("ndbcluster_drop_database"); #ifdef HAVE_NDB_BINLOG /* @@ -6207,6 +6330,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path) ndbcluster_drop_database_impl(path); #ifdef HAVE_NDB_BINLOG char db[FN_REFLEN]; + THD *thd= current_thd; ha_ndbcluster::set_dbname(path, db); ndbcluster_log_schema_op(thd, 0, thd->query, thd->query_length, @@ -6232,16 +6356,17 @@ int ndb_create_table_from_engine(THD *thd, const char *db, */ int ndbcluster_find_all_files(THD *thd) { - DBUG_ENTER("ndbcluster_find_all_files"); Ndb* ndb; char key[FN_REFLEN]; + NDBDICT *dict; + int unhandled, retries= 5, skipped; + DBUG_ENTER("ndbcluster_find_all_files"); if (!(ndb= check_ndb_in_thd(thd))) DBUG_RETURN(HA_ERR_NO_CONNECTION); - NDBDICT *dict= ndb->getDictionary(); + dict= ndb->getDictionary(); - int unhandled, retries= 5, skipped; LINT_INIT(unhandled); LINT_INIT(skipped); do @@ -6311,7 +6436,13 @@ int ndbcluster_find_all_files(THD *thd) } else if (cmp_frm(ndbtab, pack_data, pack_length)) { - NDB_SHARE *share= get_share(key, 0, false); + /* ndb_share reference temporary */ + NDB_SHARE *share= get_share(key, 0, FALSE); + if (share) + { + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); + } if (!share || get_ndb_share_state(share) != NSS_ALTERED) { discover= 1; @@ -6319,7 +6450,12 @@ int ndbcluster_find_all_files(THD *thd) elmt.database, elmt.name); } if (share) + { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); + } } my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR)); @@ -6425,12 +6561,12 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, List<char> delete_list; while ((file_name=it++)) { - bool file_on_disk= false; + bool file_on_disk= FALSE; DBUG_PRINT("info", ("%s", file_name)); if (hash_search(&ndb_tables, file_name, strlen(file_name))) { DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name)); - file_on_disk= true; + file_on_disk= TRUE; } // Check for .ndb file with this name @@ -6576,6 +6712,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, /* Call back after cluster connect */ static int connect_callback() { + pthread_mutex_lock(&LOCK_ndb_util_thread); update_status_variables(g_ndb_cluster_connection); uint node_id, i= 0; @@ -6585,6 +6722,7 @@ static int connect_callback() g_node_id_map[node_id]= i++; pthread_cond_signal(&COND_ndb_util_thread); + pthread_mutex_unlock(&LOCK_ndb_util_thread); return 0; } @@ -6595,6 +6733,15 @@ static int ndbcluster_init(void *p) int res; DBUG_ENTER("ndbcluster_init"); + if (ndbcluster_inited) + DBUG_RETURN(FALSE); + + pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST); + pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_ndb_util_thread, NULL); + pthread_cond_init(&COND_ndb_util_ready, NULL); + ndb_util_thread_running= -1; + ndbcluster_terminating= 0; ndb_dictionary_is_mysqld= 1; ndbcluster_hton= (handlerton *)p; @@ -6693,17 +6840,12 @@ static int ndbcluster_init(void *p) (void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0, (hash_get_key) ndbcluster_get_key,0,0); - pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST); #ifdef HAVE_NDB_BINLOG /* start the ndb injector thread */ if (ndbcluster_binlog_start()) goto ndbcluster_init_error; #endif /* HAVE_NDB_BINLOG */ - pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST); - pthread_cond_init(&COND_ndb_util_thread, NULL); - - ndb_cache_check_time = opt_ndb_cache_check_time; // Create utility thread pthread_t tmp; @@ -6714,6 +6856,24 @@ static int ndbcluster_init(void *p) pthread_mutex_destroy(&ndbcluster_mutex); pthread_mutex_destroy(&LOCK_ndb_util_thread); pthread_cond_destroy(&COND_ndb_util_thread); + pthread_cond_destroy(&COND_ndb_util_ready); + goto ndbcluster_init_error; + } + + /* Wait for the util thread to start */ + pthread_mutex_lock(&LOCK_ndb_util_thread); + while (ndb_util_thread_running < 0) + pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread); + pthread_mutex_unlock(&LOCK_ndb_util_thread); + + if (!ndb_util_thread_running) + { + DBUG_PRINT("error", ("ndb utility thread exited prematurely")); + hash_free(&ndbcluster_open_tables); + pthread_mutex_destroy(&ndbcluster_mutex); + pthread_mutex_destroy(&LOCK_ndb_util_thread); + pthread_cond_destroy(&COND_ndb_util_thread); + pthread_cond_destroy(&COND_ndb_util_ready); goto ndbcluster_init_error; } @@ -6739,6 +6899,17 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type) if (!ndbcluster_inited) DBUG_RETURN(0); + ndbcluster_inited= 0; + + /* wait for util thread to finish */ + sql_print_information("Stopping Cluster Utility thread"); + pthread_mutex_lock(&LOCK_ndb_util_thread); + ndbcluster_terminating= 1; + pthread_cond_signal(&COND_ndb_util_thread); + while (ndb_util_thread_running > 0) + pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread); + pthread_mutex_unlock(&LOCK_ndb_util_thread); + #ifdef HAVE_NDB_BINLOG { @@ -6751,7 +6922,7 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type) fprintf(stderr, "NDB: table share %s with use_count %d not freed\n", share->key, share->use_count); #endif - real_free_share(&share); + ndbcluster_real_free_share(&share); } pthread_mutex_unlock(&ndbcluster_mutex); } @@ -6785,7 +6956,7 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type) pthread_mutex_destroy(&ndbcluster_mutex); pthread_mutex_destroy(&LOCK_ndb_util_thread); pthread_cond_destroy(&COND_ndb_util_thread); - ndbcluster_inited= 0; + pthread_cond_destroy(&COND_ndb_util_ready); DBUG_RETURN(0); } @@ -6948,19 +7119,19 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, { // We must provide approx table rows Uint64 table_rows=0; - Ndb_local_table_statistics *info= m_table_info; - if (info->records != ~(ha_rows)0 && info->records != 0) + Ndb_local_table_statistics *ndb_info= m_table_info; + if (ndb_info->records != ~(ha_rows)0 && ndb_info->records != 0) { - table_rows = info->records; - DBUG_PRINT("info", ("use info->records: %llu", table_rows)); + table_rows = ndb_info->records; + DBUG_PRINT("info", ("use info->records: %lu", (ulong) table_rows)); } else { Ndb_statistics stat; - if ((res=ndb_get_table_statistics(this, true, ndb, m_table, &stat)) != 0) + if ((res=ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat))) break; table_rows=stat.row_count; - DBUG_PRINT("info", ("use db row_count: %llu", table_rows)); + DBUG_PRINT("info", ("use db row_count: %lu", (ulong) table_rows)); if (table_rows == 0) { // Problem if autocommit=0 #ifdef ndb_get_table_statistics_uses_active_trans @@ -6983,7 +7154,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, if ((op->readTuples(NdbOperation::LM_CommittedRead)) == -1) ERR_BREAK(op->getNdbError(), res); const key_range *keys[2]={ min_key, max_key }; - if ((res=set_bounds(op, inx, true, keys)) != 0) + if ((res=set_bounds(op, inx, TRUE, keys)) != 0) break; // Decide if db should be contacted @@ -7089,7 +7260,10 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables", name)); DBUG_RETURN(1); } + /* ndb_share reference temporary, free below */ share->use_count++; + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); pthread_mutex_unlock(&ndbcluster_mutex); pthread_mutex_lock(&share->mutex); @@ -7098,10 +7272,15 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, if (share->commit_count != 0) { *commit_count= share->commit_count; +#ifndef DBUG_OFF char buff[22]; +#endif DBUG_PRINT("info", ("Getting commit_count: %s from share", llstr(share->commit_count, buff))); pthread_mutex_unlock(&share->mutex); + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); DBUG_RETURN(0); } @@ -7118,8 +7297,11 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, { Ndb_table_guard ndbtab_g(ndb->getDictionary(), tabname); if (ndbtab_g.get_table() == 0 - || ndb_get_table_statistics(NULL, false, ndb, ndbtab_g.get_table(), &stat)) + || ndb_get_table_statistics(NULL, FALSE, ndb, ndbtab_g.get_table(), &stat)) { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); DBUG_RETURN(1); } @@ -7128,7 +7310,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, pthread_mutex_lock(&share->mutex); if (share->commit_count_lock == lock) { +#ifndef DBUG_OFF char buff[22]; +#endif DBUG_PRINT("info", ("Setting commit_count to %s", llstr(stat.commit_count, buff))); share->commit_count= stat.commit_count; @@ -7140,6 +7324,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, *commit_count= 0; } pthread_mutex_unlock(&share->mutex); + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); DBUG_RETURN(0); } @@ -7184,7 +7371,9 @@ ndbcluster_cache_retrieval_allowed(THD *thd, bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); char *dbname= full_name; char *tabname= dbname+strlen(dbname)+1; +#ifndef DBUG_OFF char buff[22], buff2[22]; +#endif DBUG_ENTER("ndbcluster_cache_retrieval_allowed"); DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d", dbname, tabname, is_autocommit)); @@ -7251,7 +7440,9 @@ ha_ndbcluster::register_query_cache_table(THD *thd, ulonglong *engine_data) { Uint64 commit_count; +#ifndef DBUG_OFF char buff[22]; +#endif bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); DBUG_ENTER("ha_ndbcluster::register_query_cache_table"); DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d", @@ -7356,21 +7547,34 @@ int handle_trailing_share(NDB_SHARE *share) static ulong trailing_share_id= 0; DBUG_ENTER("handle_trailing_share"); + /* ndb_share reference temporary, free below */ ++share->use_count; + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); pthread_mutex_unlock(&ndbcluster_mutex); TABLE_LIST table_list; bzero((char*) &table_list,sizeof(table_list)); table_list.db= share->db; table_list.alias= table_list.table_name= share->table_name; + safe_mutex_assert_owner(&LOCK_open); close_cached_tables(thd, 0, &table_list, TRUE); pthread_mutex_lock(&ndbcluster_mutex); + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); if (!--share->use_count) { - DBUG_PRINT("info", ("NDB_SHARE: close_cashed_tables %s freed share.", - share->key)); - real_free_share(&share); + if (ndb_extra_logging) + sql_print_information("NDB_SHARE: trailing share " + "%s(connect_count: %u) " + "released by close_cached_tables at " + "connect_count: %u", + share->key, + share->connect_count, + g_ndb_cluster_connection->get_connect_count()); + ndbcluster_real_free_share(&share); DBUG_RETURN(0); } @@ -7378,16 +7582,28 @@ int handle_trailing_share(NDB_SHARE *share) share still exists, if share has not been dropped by server release that share */ - if (share->state != NSS_DROPPED && !--share->use_count) + if (share->state != NSS_DROPPED) { - DBUG_PRINT("info", ("NDB_SHARE: %s already exists, " - "use_count=%d state != NSS_DROPPED.", - share->key, share->use_count)); - real_free_share(&share); - DBUG_RETURN(0); + share->state= NSS_DROPPED; + /* ndb_share reference create free */ + DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u", + share->key, share->use_count)); + --share->use_count; + + if (share->use_count == 0) + { + if (ndb_extra_logging) + sql_print_information("NDB_SHARE: trailing share " + "%s(connect_count: %u) " + "released after NSS_DROPPED check " + "at connect_count: %u", + share->key, + share->connect_count, + g_ndb_cluster_connection->get_connect_count()); + ndbcluster_real_free_share(&share); + DBUG_RETURN(0); + } } - DBUG_PRINT("error", ("NDB_SHARE: %s already exists use_count=%d.", - share->key, share->use_count)); sql_print_error("NDB_SHARE: %s already exists use_count=%d." " Moving away for safety, but possible memleak.", @@ -7536,7 +7752,6 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table, bool create_if_not_exists, bool have_lock) { - THD *thd= current_thd; NDB_SHARE *share; uint length= (uint) strlen(key); DBUG_ENTER("ndbcluster_get_share"); @@ -7650,7 +7865,7 @@ void ndbcluster_free_share(NDB_SHARE **share, bool have_lock) (*share)->util_lock= 0; if (!--(*share)->use_count) { - real_free_share(share); + ndbcluster_real_free_share(share); } else { @@ -7672,7 +7887,9 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const int retries= 10; int reterr= 0; int retry_sleep= 30 * 1000; /* 30 milliseconds */ +#ifndef DBUG_OFF char buff[22], buff2[22], buff3[22], buff4[22]; +#endif DBUG_ENTER("ndb_get_table_statistics"); DBUG_PRINT("enter", ("table: %s", ndbtab->getName())); @@ -7688,7 +7905,6 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const Uint64 sum_row_size= 0; Uint64 sum_mem= 0; NdbScanOperation*pOp; - NdbResultSet *rs; int check; if ((pTrans= ndb->startTransaction()) == NULL) @@ -7724,7 +7940,7 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const (char*)&var_mem); if (pTrans->execute(NdbTransaction::NoCommit, - NdbTransaction::AbortOnError, + NdbOperation::AbortOnError, TRUE) == -1) { error= pTrans->getNdbError(); @@ -7768,7 +7984,7 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const retry: if(report_error) { - if (file) + if (file && pTrans) { reterr= file->ndb_err(pTrans); } @@ -7867,10 +8083,10 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges, const byte *key= range->start_key.key; uint key_len= range->start_key.length; if (check_null_in_key(key_info, key, key_len)) - DBUG_RETURN(true); + DBUG_RETURN(TRUE); curr += reclength; } - DBUG_RETURN(false); + DBUG_RETURN(FALSE); } int @@ -7880,21 +8096,20 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, bool sorted, HANDLER_BUFFER *buffer) { - DBUG_ENTER("ha_ndbcluster::read_multi_range_first"); m_write_op= FALSE; - int res; KEY* key_info= table->key_info + active_index; - NDB_INDEX_TYPE index_type= get_index_type(active_index); + NDB_INDEX_TYPE cur_index_type= get_index_type(active_index); ulong reclength= table_share->reclength; NdbOperation* op; Thd_ndb *thd_ndb= get_thd_ndb(current_thd); + DBUG_ENTER("ha_ndbcluster::read_multi_range_first"); /** * blobs and unique hash index with NULL can't be batched currently */ if (uses_blob_value() || - (index_type == UNIQUE_INDEX && + (cur_index_type == UNIQUE_INDEX && has_null_in_unique_index(active_index) && null_value_index_search(ranges, ranges+range_count, buffer))) { @@ -7969,7 +8184,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, continue; } } - switch(index_type){ + switch (cur_index_type) { case PRIMARY_KEY_ORDERED_INDEX: if (!(multi_range_curr->start_key.length == key_info->key_length && multi_range_curr->start_key.flag == HA_READ_KEY_EXACT)) @@ -7982,9 +8197,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, !op->readTuple(lm) && !set_primary_key(op, multi_range_curr->start_key.key) && !define_read_attrs(curr, op) && - (op->setAbortOption(AO_IgnoreError), TRUE) && (!m_use_partition_function || - (op->setPartitionId(part_spec.start_part), true))) + (op->setPartitionId(part_spec.start_part), TRUE))) curr += reclength; else ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError()); @@ -8004,8 +8218,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) && !op->readTuple(lm) && !set_index_key(op, key_info, multi_range_curr->start_key.key) && - !define_read_attrs(curr, op) && - (op->setAbortOption(AO_IgnoreError), TRUE)) + !define_read_attrs(curr, op)) curr += reclength; else ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError()); @@ -8029,7 +8242,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, } else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab)) &&!scanOp->readTuples(lm, 0, parallelism, sorted, - FALSE, TRUE, need_pk) + FALSE, TRUE, need_pk, TRUE) &&!generate_scan_filter(m_cond_stack, scanOp) &&!define_read_attrs(end_of_buffer-reclength, scanOp)) { @@ -8045,7 +8258,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, const key_range *keys[2]= { &multi_range_curr->start_key, &multi_range_curr->end_key }; - if ((res= set_bounds(scanOp, active_index, false, keys, + if ((res= set_bounds(scanOp, active_index, FALSE, keys, multi_range_curr-ranges))) DBUG_RETURN(res); break; @@ -8167,7 +8380,7 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p) DBUG_MULTI_RANGE(6); // First fetch from cursor DBUG_ASSERT(range_no == -1); - if ((res= m_multi_cursor->nextResult(true))) + if ((res= m_multi_cursor->nextResult(TRUE))) { DBUG_MULTI_RANGE(15); goto close_scan; @@ -8205,6 +8418,8 @@ close_scan: if (multi_range_curr == multi_range_end) { DBUG_MULTI_RANGE(16); + Thd_ndb *thd_ndb= get_thd_ndb(current_thd); + thd_ndb->query_state&= NDB_QUERY_NORMAL; DBUG_RETURN(HA_ERR_END_OF_FILE); } @@ -8289,7 +8504,6 @@ ha_ndbcluster::update_table_comment( } ndb->setDatabaseName(m_dbname); - NDBDICT* dict= ndb->getDictionary(); const NDBTAB* tab= m_table; DBUG_ASSERT(tab != NULL); @@ -8319,6 +8533,8 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) my_thread_init(); DBUG_ENTER("ndb_util_thread"); DBUG_PRINT("enter", ("ndb_cache_check_time: %lu", ndb_cache_check_time)); + + pthread_mutex_lock(&LOCK_ndb_util_thread); thd= new THD; /* note that contructor of THD uses DBUG_ */ THD_CHECK_SENTRY(thd); @@ -8328,11 +8544,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) thd->thread_stack= (char*)&thd; /* remember where our stack is */ if (thd->store_globals()) - { - thd->cleanup(); - delete thd; - DBUG_RETURN(NULL); - } + goto ndb_util_thread_fail; thd->init_for_queries(); thd->version=refresh_version; thd->set_time(); @@ -8343,16 +8555,29 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) thd->main_security_ctx.priv_user = 0; thd->current_stmt_binlog_row_based= TRUE; // If in mixed mode + /* Signal successful initialization */ + ndb_util_thread_running= 1; + pthread_cond_signal(&COND_ndb_util_ready); + pthread_mutex_unlock(&LOCK_ndb_util_thread); + /* wait for mysql server to start */ pthread_mutex_lock(&LOCK_server_started); while (!mysqld_server_started) - pthread_cond_wait(&COND_server_started, &LOCK_server_started); + { + set_timespec(abstime, 1); + pthread_cond_timedwait(&COND_server_started, &LOCK_server_started, + &abstime); + if (ndbcluster_terminating) + { + pthread_mutex_unlock(&LOCK_server_started); + pthread_mutex_lock(&LOCK_ndb_util_thread); + goto ndb_util_thread_end; + } + } pthread_mutex_unlock(&LOCK_server_started); - ndbcluster_util_inited= 1; - /* Wait for cluster to start */ @@ -8360,15 +8585,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) while (!ndb_cluster_node_id && (ndbcluster_hton->slot != ~(uint)0)) { /* ndb not connected yet */ - set_timespec(abstime, 1); - pthread_cond_timedwait(&COND_ndb_util_thread, - &LOCK_ndb_util_thread, - &abstime); - if (abort_loop) - { - pthread_mutex_unlock(&LOCK_ndb_util_thread); + pthread_cond_wait(&COND_ndb_util_thread, &LOCK_ndb_util_thread); + if (ndbcluster_terminating) goto ndb_util_thread_end; - } } pthread_mutex_unlock(&LOCK_ndb_util_thread); @@ -8376,6 +8595,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb())) { sql_print_error("Could not allocate Thd_ndb object"); + pthread_mutex_lock(&LOCK_ndb_util_thread); goto ndb_util_thread_end; } set_thd_ndb(thd, thd_ndb); @@ -8394,19 +8614,20 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) #endif set_timespec(abstime, 0); - for (;!abort_loop;) + for (;;) { pthread_mutex_lock(&LOCK_ndb_util_thread); - pthread_cond_timedwait(&COND_ndb_util_thread, - &LOCK_ndb_util_thread, - &abstime); + if (!ndbcluster_terminating) + pthread_cond_timedwait(&COND_ndb_util_thread, + &LOCK_ndb_util_thread, + &abstime); + if (ndbcluster_terminating) /* Shutting down server */ + goto ndb_util_thread_end; pthread_mutex_unlock(&LOCK_ndb_util_thread); #ifdef NDB_EXTRA_DEBUG_UTIL_THREAD DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %lu", ndb_cache_check_time)); #endif - if (abort_loop) - break; /* Shutting down server */ #ifdef HAVE_NDB_BINLOG /* @@ -8437,7 +8658,10 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) continue; // injector thread is the only user, skip statistics share->util_lock= current_thd; // Mark that util thread has lock #endif /* HAVE_NDB_BINLOG */ + /* ndb_share reference temporary, free below */ share->use_count++; /* Make sure the table can't be closed */ + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); DBUG_PRINT("ndb_util_thread", ("Found open table[%d]: %s, use_count: %d", i, share->table_name, share->use_count)); @@ -8458,6 +8682,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) /* Util thread and injector thread is the only user, skip statistics */ + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); continue; } @@ -8477,10 +8704,12 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) ndb->setDatabaseName(share->db); Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name); if (ndbtab_g.get_table() && - ndb_get_table_statistics(NULL, false, ndb, + ndb_get_table_statistics(NULL, FALSE, ndb, ndbtab_g.get_table(), &stat) == 0) { +#ifndef DBUG_OFF char buff[22], buff2[22]; +#endif DBUG_PRINT("info", ("Table: %s commit_count: %s rows: %s", share->key, @@ -8501,7 +8730,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) share->commit_count= stat.commit_count; pthread_mutex_unlock(&share->mutex); - /* Decrease the use count and possibly free share */ + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); } @@ -8529,11 +8760,19 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) abstime.tv_nsec-= 1000000000; } } + + pthread_mutex_lock(&LOCK_ndb_util_thread); + ndb_util_thread_end: - sql_print_information("Stopping Cluster Utility thread"); net_end(&thd->net); +ndb_util_thread_fail: thd->cleanup(); delete thd; + + /* signal termination */ + ndb_util_thread_running= 0; + pthread_cond_signal(&COND_ndb_util_ready); + pthread_mutex_unlock(&LOCK_ndb_util_thread); DBUG_PRINT("exit", ("ndb_util_thread")); my_thread_end(); pthread_exit(0); @@ -8650,14 +8889,14 @@ void ndb_serialize_cond(const Item *item, void *arg) if (context->supported) { - Ndb_rewrite_context *rewrite_context= context->rewrite_stack; - const Item_func *func_item; + Ndb_rewrite_context *rewrite_context2= context->rewrite_stack; + const Item_func *rewrite_func_item; // Check if we are rewriting some unsupported function call - if (rewrite_context && - (func_item= rewrite_context->func_item) && - rewrite_context->count++ == 0) + if (rewrite_context2 && + (rewrite_func_item= rewrite_context2->func_item) && + rewrite_context2->count++ == 0) { - switch (func_item->functype()) { + switch (rewrite_func_item->functype()) { case Item_func::BETWEEN: /* Rewrite @@ -8684,7 +8923,7 @@ void ndb_serialize_cond(const Item *item, void *arg) if (context->expecting(item->type())) { // This is the <field>|<const> item, save it in the rewrite context - rewrite_context->left_hand_item= item; + rewrite_context2->left_hand_item= item; if (item->type() == Item::FUNC_ITEM) { Item_func *func_item= (Item_func *) item; @@ -8828,7 +9067,7 @@ void ndb_serialize_cond(const Item *item, void *arg) Check that the field is part of the table of the handler instance and that we expect a field with of this result type. */ - if (context->table == field->table) + if (context->table->s == field->table->s) { const NDBTAB *tab= (const NDBTAB *) context->ndb_table; DBUG_PRINT("info", ("FIELD_ITEM")); @@ -8849,7 +9088,7 @@ void ndb_serialize_cond(const Item *item, void *arg) type == MYSQL_TYPE_DATETIME) ? (context->expecting_field_result(STRING_RESULT) || context->expecting_field_result(INT_RESULT)) - : true)) && + : TRUE)) && // Bit fields no yet supported in scan filter type != MYSQL_TYPE_BIT && // No BLOB support in scan filter @@ -9322,8 +9561,8 @@ void ndb_serialize_cond(const Item *item, void *arg) DBUG_PRINT("info", ("INT_ITEM")); if (context->expecting(Item::INT_ITEM)) { - Item_int *int_item= (Item_int *) item; - DBUG_PRINT("info", ("value %ld", (long) int_item->value)); + DBUG_PRINT("info", ("value %ld", + (long) ((Item_int*) item)->value)); NDB_ITEM_QUALIFICATION q; q.value_type= Item::INT_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -9349,8 +9588,7 @@ void ndb_serialize_cond(const Item *item, void *arg) DBUG_PRINT("info", ("REAL_ITEM")); if (context->expecting(Item::REAL_ITEM)) { - Item_float *float_item= (Item_float *) item; - DBUG_PRINT("info", ("value %f", float_item->value)); + DBUG_PRINT("info", ("value %f", ((Item_float*) item)->value)); NDB_ITEM_QUALIFICATION q; q.value_type= Item::REAL_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -9397,8 +9635,8 @@ void ndb_serialize_cond(const Item *item, void *arg) DBUG_PRINT("info", ("DECIMAL_ITEM")); if (context->expecting(Item::DECIMAL_ITEM)) { - Item_decimal *decimal_item= (Item_decimal *) item; - DBUG_PRINT("info", ("value %f", decimal_item->val_real())); + DBUG_PRINT("info", ("value %f", + ((Item_decimal*) item)->val_real())); NDB_ITEM_QUALIFICATION q; q.value_type= Item::DECIMAL_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -9509,25 +9747,24 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, break; Ndb_item *a= cond->next->ndb_item; Ndb_item *b, *field, *value= NULL; - LINT_INIT(field); switch (cond->ndb_item->argument_count()) { case 1: - field= - (a->type == NDB_FIELD)? a : NULL; + field= (a->type == NDB_FIELD)? a : NULL; break; case 2: if (!cond->next->next) + { + field= NULL; break; + } b= cond->next->next->ndb_item; - value= - (a->type == NDB_VALUE)? a - : (b->type == NDB_VALUE)? b - : NULL; - field= - (a->type == NDB_FIELD)? a - : (b->type == NDB_FIELD)? b - : NULL; + value= ((a->type == NDB_VALUE) ? a : + (b->type == NDB_VALUE) ? b : + NULL); + field= ((a->type == NDB_FIELD) ? a : + (b->type == NDB_FIELD) ? b : + NULL); break; default: field= NULL; //Keep compiler happy @@ -9737,6 +9974,7 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, DBUG_RETURN(1); } + int ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) { @@ -9810,6 +10048,7 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) DBUG_RETURN(0); } + int ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter) { @@ -9860,14 +10099,14 @@ ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack, DBUG_RETURN(0); } + int ha_ndbcluster::generate_scan_filter_from_cond(Ndb_cond_stack *ndb_cond_stack, NdbScanFilter& filter) { - DBUG_ENTER("generate_scan_filter_from_cond"); bool multiple_cond= FALSE; - - DBUG_PRINT("info", ("Generating scan filter")); + DBUG_ENTER("generate_scan_filter_from_cond"); + // Wrap an AND group around multiple conditions if (ndb_cond_stack->next) { @@ -9893,6 +10132,7 @@ ha_ndbcluster::generate_scan_filter_from_cond(Ndb_cond_stack *ndb_cond_stack, DBUG_RETURN(0); } + int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op, const KEY* key_info, const byte *key, @@ -9903,15 +10143,14 @@ int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op, KEY_PART_INFO* end= key_part+key_info->key_parts; NdbScanFilter filter(op); int res; - DBUG_ENTER("generate_scan_filter_from_key"); + filter.begin(NdbScanFilter::AND); for (; key_part != end; key_part++) { Field* field= key_part->field; uint32 pack_len= field->pack_length(); const byte* ptr= key; - char buf[256]; DBUG_PRINT("info", ("Filtering value for %s", field->field_name)); DBUG_DUMP("key", (char*)ptr, pack_len); if (key_part->null_bit) @@ -9946,7 +10185,7 @@ int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op, /* get table space info for SHOW CREATE TABLE */ -char* ha_ndbcluster::get_tablespace_name(THD *thd) +char* ha_ndbcluster::get_tablespace_name(THD *thd, char* name, uint name_len) { Ndb *ndb= check_ndb_in_thd(thd); NDBDICT *ndbdict= ndb->getDictionary(); @@ -9964,7 +10203,14 @@ char* ha_ndbcluster::get_tablespace_name(THD *thd) ndberr= ndbdict->getNdbError(); if(ndberr.classification != NdbError::NoError) goto err; - return (my_strdup(ts.getName(), MYF(0))); + DBUG_PRINT("info", ("Found tablespace '%s'", ts.getName())); + if (name) + { + strxnmov(name, name_len, ts.getName(), NullS); + return name; + } + else + return (my_strdup(ts.getName(), MYF(0))); } err: if (ndberr.status == NdbError::TemporaryError) @@ -10082,13 +10328,13 @@ static bool adjusted_frag_count(uint no_fragments, uint no_nodes, return (reported_frags < no_fragments); } -int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *info) +int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *create_info) { ha_rows max_rows, min_rows; - if (info) + if (create_info) { - max_rows= info->max_rows; - min_rows= info->min_rows; + max_rows= create_info->max_rows; + min_rows= create_info->min_rows; } else { @@ -10239,15 +10485,14 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info, { uint16 frag_data[MAX_PARTITIONS]; char *ts_names[MAX_PARTITIONS]; - ulong ts_index= 0, fd_index= 0, i, j; + ulong fd_index= 0, i, j; NDBTAB *tab= (NDBTAB*)tab_par; NDBTAB::FragmentType ftype= NDBTAB::UserDefined; partition_element *part_elem; bool first= TRUE; - uint ts_id, ts_version, part_count= 0, tot_ts_name_len; + uint tot_ts_name_len; List_iterator<partition_element> part_it(part_info->partitions); int error; - char *name_ptr; DBUG_ENTER("ha_ndbcluster::set_up_partition_info"); if (part_info->part_type == HASH_PARTITION && @@ -10361,7 +10606,7 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info, } -bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info, +bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info, uint table_changes) { DBUG_ENTER("ha_ndbcluster::check_if_incompatible_data"); @@ -10419,76 +10664,78 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info, } /* Check that auto_increment value was not changed */ - if ((info->used_fields & HA_CREATE_USED_AUTO) && - info->auto_increment_value != 0) + if ((create_info->used_fields & HA_CREATE_USED_AUTO) && + create_info->auto_increment_value != 0) DBUG_RETURN(COMPATIBLE_DATA_NO); /* Check that row format didn't change */ - if ((info->used_fields & HA_CREATE_USED_AUTO) && - get_row_type() != info->row_type) + if ((create_info->used_fields & HA_CREATE_USED_AUTO) && + get_row_type() != create_info->row_type) DBUG_RETURN(COMPATIBLE_DATA_NO); DBUG_RETURN(COMPATIBLE_DATA_YES); } -bool set_up_tablespace(st_alter_tablespace *info, +bool set_up_tablespace(st_alter_tablespace *alter_info, NdbDictionary::Tablespace *ndb_ts) { - ndb_ts->setName(info->tablespace_name); - ndb_ts->setExtentSize(info->extent_size); - ndb_ts->setDefaultLogfileGroup(info->logfile_group_name); - return false; + ndb_ts->setName(alter_info->tablespace_name); + ndb_ts->setExtentSize(alter_info->extent_size); + ndb_ts->setDefaultLogfileGroup(alter_info->logfile_group_name); + return FALSE; } -bool set_up_datafile(st_alter_tablespace *info, +bool set_up_datafile(st_alter_tablespace *alter_info, NdbDictionary::Datafile *ndb_df) { - if (info->max_size > 0) + if (alter_info->max_size > 0) { my_error(ER_TABLESPACE_AUTO_EXTEND_ERROR, MYF(0)); - return true; + return TRUE; } - ndb_df->setPath(info->data_file_name); - ndb_df->setSize(info->initial_size); - ndb_df->setTablespace(info->tablespace_name); - return false; + ndb_df->setPath(alter_info->data_file_name); + ndb_df->setSize(alter_info->initial_size); + ndb_df->setTablespace(alter_info->tablespace_name); + return FALSE; } -bool set_up_logfile_group(st_alter_tablespace *info, +bool set_up_logfile_group(st_alter_tablespace *alter_info, NdbDictionary::LogfileGroup *ndb_lg) { - ndb_lg->setName(info->logfile_group_name); - ndb_lg->setUndoBufferSize(info->undo_buffer_size); - return false; + ndb_lg->setName(alter_info->logfile_group_name); + ndb_lg->setUndoBufferSize(alter_info->undo_buffer_size); + return FALSE; } -bool set_up_undofile(st_alter_tablespace *info, +bool set_up_undofile(st_alter_tablespace *alter_info, NdbDictionary::Undofile *ndb_uf) { - ndb_uf->setPath(info->undo_file_name); - ndb_uf->setSize(info->initial_size); - ndb_uf->setLogfileGroup(info->logfile_group_name); - return false; + ndb_uf->setPath(alter_info->undo_file_name); + ndb_uf->setSize(alter_info->initial_size); + ndb_uf->setLogfileGroup(alter_info->logfile_group_name); + return FALSE; } -int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace *info) +int ndbcluster_alter_tablespace(handlerton *hton, + THD* thd, st_alter_tablespace *alter_info) { + int is_tablespace= 0; + NdbError err; + NDBDICT *dict; + int error; + const char *errmsg; + Ndb *ndb; DBUG_ENTER("ha_ndbcluster::alter_tablespace"); + LINT_INIT(errmsg); - int is_tablespace= 0; - Ndb *ndb= check_ndb_in_thd(thd); + ndb= check_ndb_in_thd(thd); if (ndb == NULL) { DBUG_RETURN(HA_ERR_NO_CONNECTION); } + dict= ndb->getDictionary(); - NdbError err; - NDBDICT *dict= ndb->getDictionary(); - int error; - const char * errmsg; - LINT_INIT(errmsg); - - switch (info->ts_cmd_type){ + switch (alter_info->ts_cmd_type){ case (CREATE_TABLESPACE): { error= ER_CREATE_FILEGROUP_FAILED; @@ -10496,11 +10743,11 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace NdbDictionary::Tablespace ndb_ts; NdbDictionary::Datafile ndb_df; NdbDictionary::ObjectId objid; - if (set_up_tablespace(info, &ndb_ts)) + if (set_up_tablespace(alter_info, &ndb_ts)) { DBUG_RETURN(1); } - if (set_up_datafile(info, &ndb_df)) + if (set_up_datafile(alter_info, &ndb_df)) { DBUG_RETURN(1); } @@ -10510,7 +10757,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace DBUG_PRINT("error", ("createTablespace returned %d", error)); goto ndberror; } - DBUG_PRINT("info", ("Successfully created Tablespace")); + DBUG_PRINT("alter_info", ("Successfully created Tablespace")); errmsg= "DATAFILE"; if (dict->createDatafile(ndb_df)) { @@ -10532,10 +10779,10 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace case (ALTER_TABLESPACE): { error= ER_ALTER_FILEGROUP_FAILED; - if (info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE) + if (alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE) { NdbDictionary::Datafile ndb_df; - if (set_up_datafile(info, &ndb_df)) + if (set_up_datafile(alter_info, &ndb_df)) { DBUG_RETURN(1); } @@ -10545,14 +10792,14 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace goto ndberror; } } - else if(info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE) + else if(alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE) { - NdbDictionary::Tablespace ts= dict->getTablespace(info->tablespace_name); - NdbDictionary::Datafile df= dict->getDatafile(0, info->data_file_name); + NdbDictionary::Tablespace ts= dict->getTablespace(alter_info->tablespace_name); + NdbDictionary::Datafile df= dict->getDatafile(0, alter_info->data_file_name); NdbDictionary::ObjectId objid; df.getTablespaceId(&objid); if (ts.getObjectId() == objid.getObjectId() && - strcmp(df.getPath(), info->data_file_name) == 0) + strcmp(df.getPath(), alter_info->data_file_name) == 0) { errmsg= " DROP DATAFILE"; if (dict->dropDatafile(df)) @@ -10570,7 +10817,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace else { DBUG_PRINT("error", ("Unsupported alter tablespace: %d", - info->ts_alter_tablespace_type)); + alter_info->ts_alter_tablespace_type)); DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); } is_tablespace= 1; @@ -10582,14 +10829,14 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace NdbDictionary::LogfileGroup ndb_lg; NdbDictionary::Undofile ndb_uf; NdbDictionary::ObjectId objid; - if (info->undo_file_name == NULL) + if (alter_info->undo_file_name == NULL) { /* REDO files in LOGFILE GROUP not supported yet */ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); } - if (set_up_logfile_group(info, &ndb_lg)) + if (set_up_logfile_group(alter_info, &ndb_lg)) { DBUG_RETURN(1); } @@ -10598,8 +10845,8 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace { goto ndberror; } - DBUG_PRINT("info", ("Successfully created Logfile Group")); - if (set_up_undofile(info, &ndb_uf)) + DBUG_PRINT("alter_info", ("Successfully created Logfile Group")); + if (set_up_undofile(alter_info, &ndb_uf)) { DBUG_RETURN(1); } @@ -10621,7 +10868,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace case (ALTER_LOGFILE_GROUP): { error= ER_ALTER_FILEGROUP_FAILED; - if (info->undo_file_name == NULL) + if (alter_info->undo_file_name == NULL) { /* REDO files in LOGFILE GROUP not supported yet @@ -10629,7 +10876,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); } NdbDictionary::Undofile ndb_uf; - if (set_up_undofile(info, &ndb_uf)) + if (set_up_undofile(alter_info, &ndb_uf)) { DBUG_RETURN(1); } @@ -10644,7 +10891,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace { error= ER_DROP_FILEGROUP_FAILED; errmsg= "TABLESPACE"; - if (dict->dropTablespace(dict->getTablespace(info->tablespace_name))) + if (dict->dropTablespace(dict->getTablespace(alter_info->tablespace_name))) { goto ndberror; } @@ -10655,7 +10902,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace { error= ER_DROP_FILEGROUP_FAILED; errmsg= "LOGFILE GROUP"; - if (dict->dropLogfileGroup(dict->getLogfileGroup(info->logfile_group_name))) + if (dict->dropLogfileGroup(dict->getLogfileGroup(alter_info->logfile_group_name))) { goto ndberror; } @@ -10678,13 +10925,13 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace if (is_tablespace) ndbcluster_log_schema_op(thd, 0, thd->query, thd->query_length, - "", info->tablespace_name, + "", alter_info->tablespace_name, 0, 0, SOT_TABLESPACE, 0, 0, 0); else ndbcluster_log_schema_op(thd, 0, thd->query, thd->query_length, - "", info->logfile_group_name, + "", alter_info->logfile_group_name, 0, 0, SOT_LOGFILE_GROUP, 0, 0, 0); #endif @@ -10705,7 +10952,6 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts) { Ndb *ndb; NDBDICT *dict; - const NDBTAB *tab; int err; DBUG_ENTER("ha_ndbcluster::get_no_parts"); LINT_INIT(err); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index ed9e5ea41cc..63665fde0f8 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -109,6 +108,7 @@ typedef struct st_ndbcluster_share { char *table_name; Ndb::TupleIdRange tuple_id_range; #ifdef HAVE_NDB_BINLOG + uint32 connect_count; uint32 flags; NdbEventOperation *op; NdbEventOperation *op_old; // for rename table @@ -677,6 +677,8 @@ class ha_ndbcluster: public handler bool get_error_message(int error, String *buf); ha_rows records(); + ha_rows estimate_rows_upper_bound() + { return HA_POS_ERROR; } int info(uint); void get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id); int extra(enum ha_extra_function operation); @@ -824,7 +826,7 @@ private: uint set_up_partition_info(partition_info *part_info, TABLE *table, void *tab); - char* get_tablespace_name(THD *thd); + char* get_tablespace_name(THD *thd, char *name, uint name_len); int set_range_data(void *tab, partition_info* part_info); int set_list_data(void *tab, partition_info* part_info); int complemented_read(const byte *old_data, byte *new_data, diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 490114bf4a9..73363328078 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -81,6 +80,9 @@ THD *injector_thd= 0; static Ndb *injector_ndb= 0; static Ndb *schema_ndb= 0; +static int ndbcluster_binlog_inited= 0; +static int ndbcluster_binlog_terminating= 0; + /* Mutex and condition used for interacting between client sql thread and injector thread @@ -96,6 +98,7 @@ static ulonglong ndb_latest_received_binlog_epoch= 0; NDB_SHARE *ndb_apply_status_share= 0; NDB_SHARE *ndb_schema_share= 0; +pthread_mutex_t ndb_schema_share_mutex; /* Schema object distribution handling */ HASH ndb_schema_objects; @@ -360,6 +363,8 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table) int do_event_op= ndb_binlog_running; DBUG_ENTER("ndbcluster_binlog_init_share"); + share->connect_count= g_ndb_cluster_connection->get_connect_count(); + share->op= 0; share->table= 0; @@ -367,6 +372,10 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table) strcmp(share->db, NDB_REP_DB) == 0 && strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0) do_event_op= 1; + else if (!ndb_apply_status_share && + strcmp(share->db, NDB_REP_DB) == 0 && + strcmp(share->table_name, NDB_APPLY_TABLE) == 0) + do_event_op= 1; { int i, no_nodes= g_ndb_cluster_connection->no_db_nodes(); @@ -558,67 +567,34 @@ ndbcluster_binlog_log_query(handlerton *hton, THD *thd, enum_binlog_command binl DBUG_VOID_RETURN; } + /* - End use of the NDB Cluster table handler - - free all global variables allocated by - ndbcluster_init() + End use of the NDB Cluster binlog + - wait for binlog thread to shutdown */ static int ndbcluster_binlog_end(THD *thd) { - DBUG_ENTER("ndb_binlog_end"); + DBUG_ENTER("ndbcluster_binlog_end"); - if (!ndbcluster_util_inited) + if (!ndbcluster_binlog_inited) DBUG_RETURN(0); - - // Kill ndb utility thread - (void) pthread_mutex_lock(&LOCK_ndb_util_thread); - DBUG_PRINT("exit",("killing ndb util thread: %lx", ndb_util_thread)); - (void) pthread_cond_signal(&COND_ndb_util_thread); - (void) pthread_mutex_unlock(&LOCK_ndb_util_thread); + ndbcluster_binlog_inited= 0; #ifdef HAVE_NDB_BINLOG /* wait for injector thread to finish */ - if (ndb_binlog_thread_running > 0) - { - pthread_mutex_lock(&injector_mutex); - while (ndb_binlog_thread_running > 0) - { - struct timespec abstime; - set_timespec(abstime, 1); - pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime); - } - pthread_mutex_unlock(&injector_mutex); - } + ndbcluster_binlog_terminating= 1; + pthread_cond_signal(&injector_cond); + pthread_mutex_lock(&injector_mutex); + while (ndb_binlog_thread_running > 0) + pthread_cond_wait(&injector_cond, &injector_mutex); + pthread_mutex_unlock(&injector_mutex); - /* remove all shares */ - { - pthread_mutex_lock(&ndbcluster_mutex); - for (uint i= 0; i < ndbcluster_open_tables.records; i++) - { - NDB_SHARE *share= - (NDB_SHARE*) hash_element(&ndbcluster_open_tables, i); - if (share->table) - DBUG_PRINT("share", - ("table->s->db.table_name: %s.%s", - share->table->s->db.str, share->table->s->table_name.str)); - if (share->state != NSS_DROPPED && !--share->use_count) - real_free_share(&share); - else - { - DBUG_PRINT("share", - ("[%d] 0x%lx key: %s key_length: %d", - i, (long) share, share->key, share->key_length)); - DBUG_PRINT("share", - ("db.tablename: %s.%s use_count: %d commit_count: %lu", - share->db, share->table_name, - share->use_count, (long) share->commit_count)); - } - } - pthread_mutex_unlock(&ndbcluster_mutex); - } + pthread_mutex_destroy(&injector_mutex); + pthread_cond_destroy(&injector_cond); + pthread_mutex_destroy(&ndb_schema_share_mutex); #endif - ndbcluster_util_inited= 0; + DBUG_RETURN(0); } @@ -1128,7 +1104,7 @@ ndbcluster_update_slock(THD *thd, ndb_error= this_error; break; } -end: + if (ndb_error) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), @@ -1268,6 +1244,16 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, int no_storage_nodes= g_ndb_cluster_connection->no_db_nodes(); bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, FALSE); bitmap_set_all(&schema_subscribers); + + /* begin protect ndb_schema_share */ + pthread_mutex_lock(&ndb_schema_share_mutex); + if (ndb_schema_share == 0) + { + pthread_mutex_unlock(&ndb_schema_share_mutex); + if (ndb_schema_object) + ndb_free_schema_object(&ndb_schema_object, FALSE); + DBUG_RETURN(0); + } (void) pthread_mutex_lock(&ndb_schema_share->mutex); for (i= 0; i < no_storage_nodes; i++) { @@ -1280,6 +1266,9 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, } } (void) pthread_mutex_unlock(&ndb_schema_share->mutex); + pthread_mutex_unlock(&ndb_schema_share_mutex); + /* end protect ndb_schema_share */ + if (updated) { bitmap_clear_bit(&schema_subscribers, node_id); @@ -1475,6 +1464,14 @@ end: &abstime); if (thd->killed) break; + + /* begin protect ndb_schema_share */ + pthread_mutex_lock(&ndb_schema_share_mutex); + if (ndb_schema_share == 0) + { + pthread_mutex_unlock(&ndb_schema_share_mutex); + break; + } (void) pthread_mutex_lock(&ndb_schema_share->mutex); for (i= 0; i < no_storage_nodes; i++) { @@ -1484,6 +1481,8 @@ end: bitmap_intersect(&schema_subscribers, tmp); } (void) pthread_mutex_unlock(&ndb_schema_share->mutex); + pthread_mutex_unlock(&ndb_schema_share_mutex); + /* end protect ndb_schema_share */ /* remove any unsubscribed from ndb_schema_object->slock */ bitmap_intersect(&ndb_schema_object->slock_bitmap, &schema_subscribers); @@ -1686,15 +1685,25 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, (void) pthread_cond_signal(&injector_cond); pthread_mutex_lock(&ndbcluster_mutex); + /* ndb_share reference binlog free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u", + share->key, share->use_count)); free_share(&share, TRUE); if (is_remote_change && share && share->state != NSS_DROPPED) { DBUG_PRINT("info", ("remote change")); share->state= NSS_DROPPED; if (share->use_count != 1) + { + /* open handler holding reference */ + /* wait with freeing create ndb_share to below */ do_close_cached_tables= TRUE; + } else { + /* ndb_share reference create free */ + DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u", + share->key, share->use_count)); free_share(&share, TRUE); share= 0; } @@ -1717,6 +1726,9 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, table_list.db= (char *)dbname; table_list.alias= table_list.table_name= (char *)tabname; close_cached_tables(thd, 0, &table_list); + /* ndb_share reference create free */ + DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u", + share->key, share->use_count)); free_share(&share); } DBUG_RETURN(0); @@ -1784,7 +1796,13 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, char key[FN_REFLEN]; build_table_filename(key, sizeof(key), schema->db, schema->name, "", 0); + /* ndb_share reference temporary, free below */ NDB_SHARE *share= get_share(key, 0, FALSE, FALSE); + if (share) + { + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); + } // invalidation already handled by binlog thread if (!share || !share->op) { @@ -1800,21 +1818,26 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, table_list.alias= table_list.table_name= schema->name; close_cached_tables(thd, 0, &table_list, FALSE); } + /* ndb_share reference temporary free */ if (share) + { + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); + } } // fall through case SOT_CREATE_TABLE: pthread_mutex_lock(&LOCK_open); - if (ndbcluster_check_if_local_table(schema->db, schema->name)) - { - DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'", - schema->db, schema->name)); + if (ndbcluster_check_if_local_table(schema->db, schema->name)) + { + DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'", + schema->db, schema->name)); sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from " "binlog schema event '%s' from node %d. ", schema->db, schema->name, schema->query, schema->node_id); - } + } else if (ndb_create_table_from_engine(thd, schema->db, schema->name)) { sql_print_error("NDB binlog: Could not discover table '%s.%s' from " @@ -1831,27 +1854,27 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, log_query= 1; break; case SOT_DROP_DB: - /* Drop the database locally if it only contains ndb tables */ - if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db)) - { - run_query(thd, schema->query, - schema->query + schema->query_length, - TRUE, /* print error */ - TRUE); /* don't binlog the query */ - /* binlog dropping database after any table operations */ - post_epoch_log_list->push_back(schema, mem_root); - /* acknowledge this query _after_ epoch completion */ - post_epoch_unlock= 1; - } - else - { - /* Database contained local tables, leave it */ - sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables " + /* Drop the database locally if it only contains ndb tables */ + if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db)) + { + run_query(thd, schema->query, + schema->query + schema->query_length, + TRUE, /* print error */ + TRUE); /* don't binlog the query */ + /* binlog dropping database after any table operations */ + post_epoch_log_list->push_back(schema, mem_root); + /* acknowledge this query _after_ epoch completion */ + post_epoch_unlock= 1; + } + else + { + /* Database contained local tables, leave it */ + sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables " "binlog schema event '%s' from node %d. ", schema->db, schema->query, schema->node_id); - log_query= 1; - } + log_query= 1; + } break; case SOT_CREATE_DB: /* fall through */ @@ -1907,8 +1930,18 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, ndb_binlog_tables_inited && ndb_binlog_running) sql_print_information("NDB Binlog: ndb tables initially " "read only on reconnect."); + + /* begin protect ndb_schema_share */ + pthread_mutex_lock(&ndb_schema_share_mutex); + /* ndb_share reference binlog extra free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u", + ndb_schema_share->key, + ndb_schema_share->use_count)); free_share(&ndb_schema_share); ndb_schema_share= 0; + pthread_mutex_unlock(&ndb_schema_share_mutex); + /* end protect ndb_schema_share */ + close_cached_tables((THD*) 0, 0, (TABLE_LIST*) 0, FALSE); // fall through case NDBEVENT::TE_ALTER: @@ -2030,7 +2063,13 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, pthread_mutex_unlock(&ndbcluster_mutex); continue; } + /* ndb_share reference temporary, free below */ NDB_SHARE *share= get_share(key, 0, FALSE, FALSE); + if (share) + { + DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u", + share->key, share->use_count)); + } switch (schema_type) { case SOT_DROP_DB: @@ -2075,22 +2114,25 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, */ if (share) { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); share= 0; } pthread_mutex_lock(&LOCK_open); - if (ndbcluster_check_if_local_table(schema->db, schema->name)) - { - DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'", - schema->db, schema->name)); + if (ndbcluster_check_if_local_table(schema->db, schema->name)) + { + DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'", + schema->db, schema->name)); sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from " "binlog schema event '%s' from node %d. ", schema->db, schema->name, schema->query, schema->node_id); - } + } else if (ndb_create_table_from_engine(thd, schema->db, schema->name)) - { - sql_print_error("NDB binlog: Could not discover table '%s.%s' from " + { + sql_print_error("NDB binlog: Could not discover table '%s.%s' from " "binlog schema event '%s' from node %d. my_errno: %d", schema->db, schema->name, schema->query, schema->node_id, my_errno); @@ -2107,6 +2149,9 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, } if (share) { + /* ndb_share reference temporary free */ + DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u", + share->key, share->use_count)); free_share(&share); share= 0; } @@ -2215,7 +2260,7 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row) { TABLE_LIST *p_binlog_tables= &binlog_tables; close_tables_for_reopen(thd, &p_binlog_tables); - ndb_binlog_index= 0; + ndb_binlog_index= 0; continue; } sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index"); @@ -2275,6 +2320,7 @@ int ndbcluster_binlog_start() pthread_mutex_init(&injector_mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&injector_cond, NULL); + pthread_mutex_init(&ndb_schema_share_mutex, MY_MUTEX_INIT_FAST); /* Create injector thread */ if (pthread_create(&ndb_binlog_thread, &connection_attrib, @@ -2286,31 +2332,20 @@ int ndbcluster_binlog_start() DBUG_RETURN(-1); } - /* - Wait for the ndb injector thread to finish starting up. - */ + ndbcluster_binlog_inited= 1; + + /* Wait for the injector thread to start */ pthread_mutex_lock(&injector_mutex); while (!ndb_binlog_thread_running) pthread_cond_wait(&injector_cond, &injector_mutex); pthread_mutex_unlock(&injector_mutex); - + if (ndb_binlog_thread_running < 0) DBUG_RETURN(-1); DBUG_RETURN(0); } -static void ndbcluster_binlog_close_connection(THD *thd) -{ - DBUG_ENTER("ndbcluster_binlog_close_connection"); - const char *save_info= thd->proc_info; - thd->proc_info= "ndbcluster_binlog_close_connection"; - do_ndbcluster_binlog_close_connection= BCCC_exit; - while (ndb_binlog_thread_running > 0) - sleep(1); - thd->proc_info= save_info; - DBUG_VOID_RETURN; -} /************************************************************** Internal helper functions for creating/dropping ndb events @@ -2418,20 +2453,42 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key, pthread_mutex_unlock(&ndbcluster_mutex); DBUG_RETURN(1); } - handle_trailing_share(share); + if (!share_may_exist || share->connect_count != + g_ndb_cluster_connection->get_connect_count()) + { + handle_trailing_share(share); + share= NULL; + } } /* Create share which is needed to hold replication information */ - if (!(share= get_share(key, 0, TRUE, TRUE))) + if (share) + { + /* ndb_share reference create */ + ++share->use_count; + DBUG_PRINT("NDB_SHARE", ("%s create use_count: %u", + share->key, share->use_count)); + } + /* ndb_share reference create */ + else if (!(share= get_share(key, 0, TRUE, TRUE))) { sql_print_error("NDB Binlog: " "allocating table share for %s failed", key); } + else + { + DBUG_PRINT("NDB_SHARE", ("%s create use_count: %u", + share->key, share->use_count)); + } if (!ndb_schema_share && strcmp(share->db, NDB_REP_DB) == 0 && strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0) do_event_op= 1; + else if (!ndb_apply_status_share && + strcmp(share->db, NDB_REP_DB) == 0 && + strcmp(share->table_name, NDB_APPLY_TABLE) == 0) + do_event_op= 1; if (!do_event_op) { @@ -2703,7 +2760,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, else if (!ndb_apply_status_share && strcmp(share->db, NDB_REP_DB) == 0 && strcmp(share->table_name, NDB_APPLY_TABLE) == 0) do_ndb_apply_status_share= 1; - else if (!binlog_filter->db_ok(share->db)) + else if (!binlog_filter->db_ok(share->db) || !ndb_binlog_running) { share->flags|= NSF_NO_BINLOG; DBUG_RETURN(0); @@ -2715,6 +2772,9 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, DBUG_ASSERT(share->use_count > 1); sql_print_error("NDB Binlog: discover reusing old ev op"); + /* ndb_share reference ToDo free */ + DBUG_PRINT("NDB_SHARE", ("%s ToDo free use_count: %u", + share->key, share->use_count)); free_share(&share); // old event op already has reference DBUG_RETURN(0); } @@ -2857,15 +2917,24 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, break; } + /* ndb_share reference binlog */ get_share(share); + DBUG_PRINT("NDB_SHARE", ("%s binlog use_count: %u", + share->key, share->use_count)); if (do_ndb_apply_status_share) { + /* ndb_share reference binlog extra */ ndb_apply_status_share= get_share(share); + DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u", + share->key, share->use_count)); (void) pthread_cond_signal(&injector_cond); } else if (do_ndb_schema_share) { + /* ndb_share reference binlog extra */ ndb_schema_share= get_share(share); + DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u", + share->key, share->use_count)); (void) pthread_cond_signal(&injector_cond); } @@ -3052,6 +3121,9 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb, ndb_binlog_tables_inited && ndb_binlog_running) sql_print_information("NDB Binlog: ndb tables initially " "read only on reconnect."); + /* ndb_share reference binlog extra free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u", + share->key, share->use_count)); free_share(&ndb_apply_status_share); ndb_apply_status_share= 0; } @@ -3068,6 +3140,9 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb, ndb_binlog_tables_inited && ndb_binlog_running) sql_print_information("NDB Binlog: ndb tables initially " "read only on reconnect."); + /* ndb_share reference binlog extra free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u", + share->key, share->use_count)); free_share(&ndb_apply_status_share); ndb_apply_status_share= 0; } @@ -3150,15 +3225,17 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, if (share->flags & NSF_BLOB_FLAG) { my_ptrdiff_t ptrdiff= 0; - int ret= get_ndb_blobs_value(table, share->ndb_value[0], - blobs_buffer[0], blobs_buffer_size[0], - ptrdiff); + IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0], + blobs_buffer[0], + blobs_buffer_size[0], + ptrdiff); DBUG_ASSERT(ret == 0); } ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]); - int ret= trans.write_row(::server_id, - injector::transaction::table(table, TRUE), - &b, n_fields, table->record[0]); + IF_DBUG(int ret=) trans.write_row(::server_id, + injector::transaction::table(table, + TRUE), + &b, n_fields, table->record[0]); DBUG_ASSERT(ret == 0); } break; @@ -3176,27 +3253,29 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, n= 0; /* use the primary key only as it save time and space and it is the only thing needed to log the delete - */ + */ else n= 1; /* we use the before values since we don't have a primary key since the mysql server does not handle the hidden primary key - */ + */ if (share->flags & NSF_BLOB_FLAG) { my_ptrdiff_t ptrdiff= table->record[n] - table->record[0]; - int ret= get_ndb_blobs_value(table, share->ndb_value[n], - blobs_buffer[n], blobs_buffer_size[n], - ptrdiff); + IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[n], + blobs_buffer[n], + blobs_buffer_size[n], + ptrdiff); DBUG_ASSERT(ret == 0); } ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]); DBUG_EXECUTE("info", print_records(table, table->record[n]);); - int ret= trans.delete_row(::server_id, - injector::transaction::table(table, TRUE), - &b, n_fields, table->record[n]); + IF_DBUG(int ret =) trans.delete_row(::server_id, + injector::transaction::table(table, + TRUE), + &b, n_fields, table->record[n]); DBUG_ASSERT(ret == 0); } break; @@ -3208,9 +3287,10 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, if (share->flags & NSF_BLOB_FLAG) { my_ptrdiff_t ptrdiff= 0; - int ret= get_ndb_blobs_value(table, share->ndb_value[0], - blobs_buffer[0], blobs_buffer_size[0], - ptrdiff); + IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0], + blobs_buffer[0], + blobs_buffer_size[0], + ptrdiff); DBUG_ASSERT(ret == 0); } ndb_unpack_record(table, share->ndb_value[0], @@ -3221,7 +3301,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, /* since table has a primary key, we can do a write using only after values - */ + */ trans.write_row(::server_id, injector::transaction::table(table, TRUE), &b, n_fields, table->record[0]);// after values } @@ -3230,22 +3310,24 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, /* mysql server cannot handle the ndb hidden key and therefore needs the before image as well - */ + */ if (share->flags & NSF_BLOB_FLAG) { my_ptrdiff_t ptrdiff= table->record[1] - table->record[0]; - int ret= get_ndb_blobs_value(table, share->ndb_value[1], - blobs_buffer[1], blobs_buffer_size[1], - ptrdiff); + IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[1], + blobs_buffer[1], + blobs_buffer_size[1], + ptrdiff); DBUG_ASSERT(ret == 0); } ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]); DBUG_EXECUTE("info", print_records(table, table->record[1]);); - int ret= trans.update_row(::server_id, - injector::transaction::table(table, TRUE), - &b, n_fields, - table->record[1], // before values - table->record[0]);// after values + IF_DBUG(int ret =) trans.update_row(::server_id, + injector::transaction::table(table, + TRUE), + &b, n_fields, + table->record[1], // before values + table->record[0]);// after values DBUG_ASSERT(ret == 0); } } @@ -3444,6 +3526,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) s_ndb->init()) { sql_print_error("NDB Binlog: Getting Schema Ndb object failed"); + ndb_binlog_thread_running= -1; + pthread_mutex_unlock(&injector_mutex); + pthread_cond_signal(&injector_cond); goto err; } @@ -3474,7 +3559,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) p_latest_trans_gci= injector_ndb->get_ndb_cluster_connection().get_latest_trans_gci(); schema_ndb= s_ndb; - ndb_binlog_thread_running= 1; + if (opt_bin_log) { if (global_system_variables.binlog_format == BINLOG_FORMAT_ROW || @@ -3487,10 +3572,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) sql_print_error("NDB: only row based binary logging is supported"); } } - /* - We signal the thread that started us that we've finished - starting up. - */ + + /* Thread start up completed */ + ndb_binlog_thread_running= 1; pthread_mutex_unlock(&injector_mutex); pthread_cond_signal(&injector_cond); @@ -3509,7 +3593,7 @@ restart: struct timespec abstime; set_timespec(abstime, 1); pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime); - if (abort_loop) + if (ndbcluster_binlog_terminating) { pthread_mutex_unlock(&injector_mutex); goto err; @@ -3534,21 +3618,23 @@ restart: { // wait for the first event thd->proc_info= "Waiting for first event from ndbcluster"; - DBUG_PRINT("info", ("Waiting for the first event")); int schema_res, res; Uint64 schema_gci; do { - if (abort_loop) + DBUG_PRINT("info", ("Waiting for the first event")); + + if (ndbcluster_binlog_terminating) goto err; + schema_res= s_ndb->pollEvents(100, &schema_gci); - } while (ndb_latest_received_binlog_epoch == schema_gci); + } while (schema_gci == 0 || ndb_latest_received_binlog_epoch == schema_gci); if (ndb_binlog_running) { Uint64 gci= i_ndb->getLatestGCI(); while (gci < schema_gci || gci == ndb_latest_received_binlog_epoch) { - if (abort_loop) + if (ndbcluster_binlog_terminating) goto err; res= i_ndb->pollEvents(10, &gci); } @@ -3595,7 +3681,8 @@ restart: thd->db= db; } do_ndbcluster_binlog_close_connection= BCCC_running; - for ( ; !((abort_loop || do_ndbcluster_binlog_close_connection) && + for ( ; !((ndbcluster_binlog_terminating || + do_ndbcluster_binlog_close_connection) && ndb_latest_handled_binlog_epoch >= *p_latest_trans_gci) && do_ndbcluster_binlog_close_connection != BCCC_restart; ) { @@ -3642,7 +3729,8 @@ restart: schema_res= s_ndb->pollEvents(10, &schema_gci); } - if ((abort_loop || do_ndbcluster_binlog_close_connection) && + if ((ndbcluster_binlog_terminating || + do_ndbcluster_binlog_close_connection) && (ndb_latest_handled_binlog_epoch >= *p_latest_trans_gci || !ndb_binlog_running)) break; /* Shutting down server */ @@ -3769,7 +3857,9 @@ restart: continue; } TABLE *table= share->table; +#ifndef DBUG_OFF const LEX_STRING &name= table->s->table_name; +#endif if ((event_types & (NdbDictionary::Event::TE_INSERT | NdbDictionary::Event::TE_UPDATE | NdbDictionary::Event::TE_DELETE)) == 0) @@ -3786,7 +3876,7 @@ restart: } DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str)); injector::transaction::table tbl(table, TRUE); - int ret= trans.use_table(::server_id, tbl); + IF_DBUG(int ret=) trans.use_table(::server_id, tbl); DBUG_ASSERT(ret == 0); } } @@ -3796,10 +3886,12 @@ restart: { TABLE *table= ndb_apply_status_share->table; - const LEX_STRING& name=table->s->table_name; +#ifndef DBUG_OFF + const LEX_STRING& name= table->s->table_name; DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str)); +#endif injector::transaction::table tbl(table, TRUE); - int ret= trans.use_table(::server_id, tbl); + IF_DBUG(int ret=) trans.use_table(::server_id, tbl); DBUG_ASSERT(ret == 0); // Set all fields non-null. @@ -3864,7 +3956,7 @@ restart: else { // set injector_ndb database/schema from table internal name - int ret= + IF_DBUG(int ret=) i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable()); DBUG_ASSERT(ret == 0); ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, row); @@ -3898,7 +3990,7 @@ restart: /* note! pOp is not referring to an event in the next epoch or is == 0 - */ + */ #ifdef RUN_NDB_BINLOG_TIMER write_timer.stop(); #endif @@ -3931,9 +4023,9 @@ restart: "%ld(%d e/s), total time %ld(%d e/s)", (ulong)gci, event_count, write_timer.elapsed_ms(), - event_count / write_timer.elapsed_ms(), + (1000*event_count) / write_timer.elapsed_ms(), gci_timer.elapsed_ms(), - event_count / gci_timer.elapsed_ms()); + (1000*event_count) / gci_timer.elapsed_ms()); #endif } } @@ -3953,15 +4045,12 @@ restart: goto restart; } err: + sql_print_information("Stopping Cluster Binlog"); DBUG_PRINT("info",("Shutting down cluster binlog thread")); thd->proc_info= "Shutting down"; close_thread_tables(thd); pthread_mutex_lock(&injector_mutex); /* don't mess with the injector_ndb anymore from other threads */ - uint ndb_obj_cnt= 1; // g_ndb - ndb_obj_cnt+= injector_ndb == 0 ? 0 : 1; - ndb_obj_cnt+= schema_ndb == 0 ? 0 : 1; - ndb_obj_cnt+= ndbcluster_util_inited ? 1 : 0; injector_thd= 0; injector_ndb= 0; p_latest_trans_gci= 0; @@ -3969,38 +4058,27 @@ err: pthread_mutex_unlock(&injector_mutex); thd->db= 0; // as not to try to free memory - if (!ndb_extra_logging) - sql_print_information("Stopping Cluster Binlog"); - else - sql_print_information("Stopping Cluster Binlog: %u(%u)", - g_ndb_cluster_connection->get_active_ndb_objects(), - ndb_obj_cnt); - - /** - * Add extra wait loop to make user "user" ndb-object go away... - * otherwise user thread can have ongoing SUB_DATA - */ - int sleep_cnt= 0; - while (sleep_cnt < 300 && - g_ndb_cluster_connection->get_active_ndb_objects() > ndb_obj_cnt) - { - my_sleep(10000); // 10ms - sleep_cnt++; - } - if (ndb_extra_logging) - sql_print_information("Stopping Cluster Binlog: waited %ums %u(%u)", - 10*sleep_cnt, g_ndb_cluster_connection->get_active_ndb_objects(), - ndb_obj_cnt); - if (ndb_apply_status_share) { + /* ndb_share reference binlog extra free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u", + ndb_apply_status_share->key, + ndb_apply_status_share->use_count)); free_share(&ndb_apply_status_share); ndb_apply_status_share= 0; } if (ndb_schema_share) { + /* begin protect ndb_schema_share */ + pthread_mutex_lock(&ndb_schema_share_mutex); + /* ndb_share reference binlog extra free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u", + ndb_schema_share->key, + ndb_schema_share->use_count)); free_share(&ndb_schema_share); ndb_schema_share= 0; + pthread_mutex_unlock(&ndb_schema_share_mutex); + /* end protect ndb_schema_share */ } /* remove all event operations */ @@ -4018,6 +4096,9 @@ err: DBUG_ASSERT(share->op == op || share->op_old == op); share->op= share->op_old= 0; + /* ndb_share reference binlog free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u", + share->key, share->use_count)); free_share(&share); s_ndb->dropEventOperation(op); } @@ -4038,6 +4119,9 @@ err: DBUG_ASSERT(share->op == op || share->op_old == op); share->op= share->op_old= 0; + /* ndb_share reference binlog free */ + DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u", + share->key, share->use_count)); free_share(&share); i_ndb->dropEventOperation(op); } @@ -4047,8 +4131,8 @@ err: hash_free(&ndb_schema_objects); - // Placed here to avoid a memory leak; TODO: check if needed net_end(&thd->net); + thd->cleanup(); delete thd; ndb_binlog_thread_running= -1; diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h index 18b94bb8f2a..00fc689f061 100644 --- a/sql/ha_ndbcluster_binlog.h +++ b/sql/ha_ndbcluster_binlog.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -209,11 +208,6 @@ inline void free_share(NDB_SHARE **share, bool have_lock= FALSE) ndbcluster_free_share(share, have_lock); } -inline void real_free_share(NDB_SHARE **share) -{ - ndbcluster_real_free_share(share); -} - inline Thd_ndb * get_thd_ndb(THD *thd) { return (Thd_ndb *) thd->ha_data[ndbcluster_hton->slot]; } diff --git a/sql/ha_ndbcluster_tables.h b/sql/ha_ndbcluster_tables.h index 2b1bdbc2b89..9f7b9146d91 100644 --- a/sql/ha_ndbcluster_tables.h +++ b/sql/ha_ndbcluster_tables.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 7cd33dd5726..87d24207dcd 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -585,7 +584,6 @@ int ha_partition::drop_partitions(const char *path) List_iterator<partition_element> part_it(m_part_info->partitions); char part_name_buff[FN_REFLEN]; uint no_parts= m_part_info->partitions.elements; - uint part_count= 0; uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; @@ -1076,7 +1074,6 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint no_parts= m_part_info->no_parts; uint no_subparts= m_part_info->no_subparts; uint i= 0; - LEX *lex= thd->lex; int error; DBUG_ENTER("ha_partition::handle_opt_partitions"); DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag)); @@ -1088,11 +1085,9 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, { if (m_is_sub_partitioned) { - List_iterator<partition_element> sub_it(part_elem->subpartitions); uint j= 0, part; do { - partition_element *sub_elem= sub_it++; part= i * no_subparts + j; DBUG_PRINT("info", ("Optimize subpartition %u", part)); @@ -1137,7 +1132,6 @@ int ha_partition::prepare_new_partition(TABLE *table, { int error; bool create_flag= FALSE; - bool open_flag= FALSE; DBUG_ENTER("prepare_new_partition"); if ((error= set_up_table_before_create(table, part_name, create_info, @@ -1246,7 +1240,6 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, handler **new_file_array; int error= 1; bool first; - bool copy_parts= FALSE; uint temp_partitions= m_part_info->temp_partitions.elements; THD *thd= current_thd; DBUG_ENTER("ha_partition::change_partitions"); @@ -2062,7 +2055,6 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) partition_element *part_elem; uint alloc_len= (m_tot_parts + 1) * sizeof(handler*); List_iterator_fast <partition_element> part_it(m_part_info->partitions); - THD *thd= current_thd; DBUG_ENTER("ha_partition::new_handlers_from_part_info"); if (!(m_file= (handler **) alloc_root(mem_root, alloc_len))) @@ -4016,6 +4008,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order) m_queue.elements= j; queue_fix(&m_queue); return_top_record(buf); + table->status= 0; DBUG_PRINT("info", ("Record returned from partition %d", m_top_entry)); DBUG_RETURN(0); } @@ -4084,6 +4077,7 @@ int ha_partition::handle_ordered_next(byte *buf, bool is_next_same) DBUG_PRINT("info", ("Record returned from partition %u (2)", m_top_entry)); return_top_record(buf); + table->status= 0; error= 0; } } @@ -4127,6 +4121,7 @@ int ha_partition::handle_ordered_prev(byte *buf) DBUG_PRINT("info", ("Record returned from partition %d (2)", m_top_entry)); error= 0; + table->status= 0; } } DBUG_RETURN(error); diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 40af30bf08c..4fdf325fa06 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/handler.cc b/sql/handler.cc index ce9dc342713..2244aaa5311 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,8 +13,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/** @file handler.cc -/* Handler-calling-functions */ + @brief + Handler-calling-functions +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -45,12 +47,6 @@ static handlerton *installed_htons[128]; KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} }; -/* static functions defined in this file */ - -static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root); - -static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; - /* number of entries in handlertons[] */ ulong total_ha= 0; /* number of storage engines (from handlertons[]) that support 2pc */ @@ -81,17 +77,16 @@ static TYPELIB known_extensions= {0,"known_exts", NULL, NULL}; uint known_extensions_id= 0; -/* +/** @brief Return the default storage engine handlerton for thread - + SYNOPSIS ha_default_handlerton(thd) thd current thread - + RETURN pointer to handlerton */ - handlerton *ha_default_handlerton(THD *thd) { return (thd->variables.table_type != NULL) ? @@ -101,7 +96,7 @@ handlerton *ha_default_handlerton(THD *thd) } -/* +/** @brief Return the storage engine handlerton for the supplied name SYNOPSIS @@ -112,7 +107,6 @@ handlerton *ha_default_handlerton(THD *thd) RETURN pointer to handlerton */ - handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name) { const LEX_STRING *table_alias; @@ -167,11 +161,13 @@ const char *ha_get_storage_engine(enum legacy_db_type db_type) } +#ifdef NOT_USED static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root) { handlerton *hton= ha_default_handlerton(current_thd); return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL; } +#endif handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) @@ -189,8 +185,9 @@ handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) } -/* Use other database handler if databasehandler is not compiled in */ - +/** @brief + Use other database handler if databasehandler is not compiled in +*/ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, bool no_substitute, bool report_error) { @@ -270,7 +267,7 @@ handler *get_ha_partition(partition_info *part_info) #endif -/* +/** @brief Register handler error messages for use with my_error(). SYNOPSIS @@ -280,7 +277,6 @@ handler *get_ha_partition(partition_info *part_info) 0 OK != 0 Error */ - static int ha_init_errors(void) { #define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg) @@ -340,7 +336,7 @@ static int ha_init_errors(void) } -/* +/** @brief Unregister handler error messages. SYNOPSIS @@ -350,7 +346,6 @@ static int ha_init_errors(void) 0 OK != 0 Error */ - static int ha_finish_errors(void) { const char **errmsgs; @@ -558,7 +553,9 @@ static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin, } -/* don't bother to rollback here, it's done already */ +/** @brief + don't bother to rollback here, it's done already +*/ void ha_close_connection(THD* thd) { plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0); @@ -567,7 +564,7 @@ void ha_close_connection(THD* thd) /* ======================================================================== ======================= TRANSACTIONS ===================================*/ -/* +/** @brief Register a storage engine for a transaction DESCRIPTION @@ -609,7 +606,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) DBUG_VOID_RETURN; } -/* +/** @brief RETURN 0 - ok 1 - error, transaction was rolled back @@ -649,7 +646,7 @@ int ha_prepare(THD *thd) DBUG_RETURN(error); } -/* +/** @brief RETURN 0 - ok 1 - transaction was rolled back @@ -692,6 +689,19 @@ int ha_commit_trans(THD *thd, bool all) ha_rollback_trans(thd, all); DBUG_RETURN(1); } + + if ( is_real_trans + && opt_readonly + && ! (thd->security_ctx->master_access & SUPER_ACL) + && ! thd->slave_thread + ) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + ha_rollback_trans(thd, all); + error= 1; + goto end; + } + DBUG_EXECUTE_IF("crash_commit_before", abort();); /* Close all cursors that can not survive COMMIT */ @@ -712,7 +722,7 @@ int ha_commit_trans(THD *thd, bool all) } DBUG_EXECUTE_IF("crash_commit_after_prepare", abort();); if (error || (is_real_trans && xid && - (error= !(cookie= tc_log->log(thd, xid))))) + (error= !(cookie= tc_log->log_xid(thd, xid))))) { ha_rollback_trans(thd, all); error= 1; @@ -720,7 +730,7 @@ int ha_commit_trans(THD *thd, bool all) } DBUG_EXECUTE_IF("crash_commit_after_log", abort();); } - error=ha_commit_one_phase(thd, all) ? cookie ? 2 : 1 : 0; + error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0; DBUG_EXECUTE_IF("crash_commit_before_unlog", abort();); if (cookie) tc_log->unlog(cookie, xid); @@ -733,7 +743,7 @@ end: DBUG_RETURN(error); } -/* +/** @brief NOTE - this function does not care about global read lock. A caller should. */ @@ -835,14 +845,14 @@ int ha_rollback_trans(THD *thd, bool all) message in the error log, so we don't send it. */ if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && - !thd->slave_thread) + !thd->slave_thread && thd->killed != THD::KILL_CONNECTION) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); DBUG_RETURN(error); } -/* +/** @brief This is used to commit or rollback a single statement depending on the value of error. Note that if the autocommit is on, then the following call inside InnoDB will commit or rollback the whole transaction (= the statement). The @@ -850,7 +860,6 @@ int ha_rollback_trans(THD *thd, bool all) the user has used LOCK TABLES then that mechanism does not know to do the commit. */ - int ha_autocommit_or_rollback(THD *thd, int error) { DBUG_ENTER("ha_autocommit_or_rollback"); @@ -968,7 +977,7 @@ static char* xid_to_str(char *buf, XID *xid) } #endif -/* +/** @brief recover() step of xa NOTE @@ -987,7 +996,6 @@ static char* xid_to_str(char *buf, XID *xid) in this case commit_list==0, tc_heuristic_recover == 0 there should be no prepared transactions in this case. */ - struct xarecover_st { int len, found_foreign_xids, found_my_xids; @@ -1119,7 +1127,7 @@ int ha_recover(HASH *commit_list) DBUG_RETURN(0); } -/* +/** @brief return the list of XID's to a client, the same way SHOW commands do NOTE @@ -1168,7 +1176,7 @@ bool mysql_xa_recover(THD *thd) DBUG_RETURN(0); } -/* +/** @brief This function should be called when MySQL sends rows of a SELECT result set or the EOF mark to the client. It releases a possible adaptive hash index S-latch held by thd in InnoDB and also releases a possible InnoDB query @@ -1184,7 +1192,6 @@ bool mysql_xa_recover(THD *thd) thd: the thread handle of the current connection return value: always 0 */ - static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin, void *unused) { @@ -1251,12 +1258,11 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) DBUG_RETURN(error); } -/* +/** @brief note, that according to the sql standard (ISO/IEC 9075-2:2003) section "4.33.4 SQL-statements and transaction states", SAVEPOINT is *not* transaction-initiating SQL-statement */ - int ha_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; @@ -1371,11 +1377,10 @@ bool ha_flush_logs(handlerton *db_type) return FALSE; } -/* +/** @brief This should return ENOENT if the file doesn't exists. The .frm file will be deleted only if we return 0 or ENOENT */ - int ha_delete_table(THD *thd, handlerton *table_type, const char *path, const char *db, const char *alias, bool generate_warning) { @@ -1498,14 +1503,13 @@ bool handler::check_if_log_table_locking_is_allowed(uint sql_command, return TRUE; } -/* +/** @brief Open database-handler. IMPLEMENTATION Try O_RDONLY if cannot open as O_RDWR Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set */ - int handler::ha_open(TABLE *table_arg, const char *name, int mode, int test_if_locked) { @@ -1553,12 +1557,11 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, } -/* +/** @brief Read first row (only) from a table This is never called for InnoDB tables, as these table types has the HA_STATS_RECORDS_IS_EXACT set. */ - int handler::read_first_row(byte * buf, uint primary_key) { register int error; @@ -1589,7 +1592,7 @@ int handler::read_first_row(byte * buf, uint primary_key) DBUG_RETURN(error); } -/* +/** @brief Generate the next auto-increment number based on increment and offset: computes the lowest number - strictly greater than "nr" @@ -1600,7 +1603,6 @@ int handler::read_first_row(byte * buf, uint primary_key) If increment=10 and offset=5 and previous number is 1, we get: 1,5,15,25,35,... */ - inline ulonglong compute_next_insert_id(ulonglong nr,struct system_variables *variables) { @@ -1626,7 +1628,7 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) } -/* +/** @brief Computes the largest number X: - smaller than or equal to "nr" - of the form: auto_increment_offset + N * auto_increment_increment @@ -1641,7 +1643,6 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) RETURN The number X if it exists, "nr" otherwise. */ - inline ulonglong prev_insert_id(ulonglong nr, struct system_variables *variables) { @@ -1910,7 +1911,7 @@ int handler::update_auto_increment() } -/* +/** @brief MySQL signal that it changed the column bitmap USAGE @@ -1923,7 +1924,6 @@ int handler::update_auto_increment() rnd_init() call is made as after this, MySQL will not use the bitmap for any program logic checking. */ - void handler::column_bitmaps_signal() { DBUG_ENTER("column_bitmaps_signal"); @@ -1933,7 +1933,7 @@ void handler::column_bitmaps_signal() } -/* +/** @brief Reserves an interval of auto_increment values from the handler. SYNOPSIS @@ -1950,7 +1950,6 @@ void handler::column_bitmaps_signal() If the function sets *nb_reserved_values to ULONGLONG_MAX it means it has reserved to "positive infinite". */ - void handler::get_auto_increment(ulonglong offset, ulonglong increment, ulonglong nb_desired_values, ulonglong *first_value, @@ -2029,7 +2028,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) { /* Key is unknown */ str.copy("", 0, system_charset_info); - my_printf_error(ER_DUP_ENTRY, msg, + my_printf_error(ER_DUP_ENTRY_WITH_KEY_NAME, msg, MYF(0), str.c_ptr(), "*UNKNOWN*"); } else @@ -2042,13 +2041,13 @@ void handler::print_keydup_error(uint key_nr, const char *msg) str.length(max_length-4); str.append(STRING_WITH_LEN("...")); } - my_printf_error(ER_DUP_ENTRY, msg, + my_printf_error(ER_DUP_ENTRY_WITH_KEY_NAME, msg, MYF(0), str.c_ptr(), table->key_info[key_nr].name); } } -/* +/** @brief Print error that we got from handler function NOTE @@ -2057,7 +2056,6 @@ void handler::print_keydup_error(uint key_nr, const char *msg) table->s->path table->alias */ - void handler::print_error(int error, myf errflag) { DBUG_ENTER("handler::print_error"); @@ -2087,7 +2085,7 @@ void handler::print_error(int error, myf errflag) uint key_nr=get_dup_key(error); if ((int) key_nr >= 0) { - print_keydup_error(key_nr, ER(ER_DUP_ENTRY)); + print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME)); DBUG_VOID_RETURN; } textno=ER_DUP_KEY; @@ -2243,7 +2241,7 @@ void handler::print_error(int error, myf errflag) } -/* +/** @brief Return an error message specific to this handler SYNOPSIS @@ -2251,8 +2249,7 @@ void handler::print_error(int error, myf errflag) buf Pointer to String where to add error message Returns true if this is a temporary error - */ - +*/ bool handler::get_error_message(int error, String* buf) { return FALSE; @@ -2278,7 +2275,7 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) if (!keypart->fieldnr) continue; Field *field= table->field[keypart->fieldnr-1]; - if (field->type() == FIELD_TYPE_BLOB) + if (field->type() == MYSQL_TYPE_BLOB) { if (check_opt->sql_flags & TT_FOR_UPGRADE) check_opt->flags= T_MEDIUM; @@ -2300,7 +2297,7 @@ int handler::check_old_types() /* check for bad DECIMAL field */ for (field= table->field; (*field); field++) { - if ((*field)->type() == FIELD_TYPE_NEWDECIMAL) + if ((*field)->type() == MYSQL_TYPE_NEWDECIMAL) { return HA_ADMIN_NEEDS_ALTER; } @@ -2357,8 +2354,8 @@ err: -/* Return key if error because of duplicated keys */ - +/** @brief + Return key if error because of duplicated keys */ uint handler::get_dup_key(int error) { DBUG_ENTER("handler::get_dup_key"); @@ -2371,7 +2368,7 @@ uint handler::get_dup_key(int error) } -/* +/** @brief Delete all files with extension from bas_ext() SYNOPSIS @@ -2387,7 +2384,6 @@ uint handler::get_dup_key(int error) didn't get any other errors than ENOENT # Error */ - int handler::delete_table(const char *name) { int error= 0; @@ -2433,7 +2429,7 @@ void handler::drop_table(const char *name) } -/* +/** @brief Performs checks upon the table. SYNOPSIS @@ -2449,7 +2445,6 @@ void handler::drop_table(const char *name) HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE HA_ADMIN_NOT_IMPLEMENTED */ - int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) { int error; @@ -2483,7 +2478,7 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) } -/* +/** @brief Tell the storage engine that it is allowed to "disable transaction" in the handler. It is a hint that ACID is not required - it is used in NDB for ALTER TABLE, for example, when data are copied to temporary table. @@ -2491,7 +2486,6 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) starts to commit every now and then automatically. This hint can be safely ignored. */ - int ha_enable_transaction(THD *thd, bool on) { int error=0; @@ -2552,7 +2546,7 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, ** Some general functions that isn't in the handler class ****************************************************************************/ -/* +/** @brief Initiates table-file and calls appropriate database-creator NOTES @@ -2563,7 +2557,6 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, 0 ok 1 error */ - int ha_create_table(THD *thd, const char *path, const char *db, const char *table_name, HA_CREATE_INFO *create_info, @@ -2607,7 +2600,7 @@ err: DBUG_RETURN(error != 0); } -/* +/** @brief Try to discover table from engine NOTES @@ -2619,7 +2612,6 @@ err: > 0 Error, table existed but could not be created */ - int ha_create_table_from_engine(THD* thd, const char *db, const char *name) { int error; @@ -2694,9 +2686,9 @@ void st_ha_check_opt::init() call to ha_init_key_cache() (probably out of memory) *****************************************************************************/ -/* Init a key cache if it has not been initied before */ - - +/** @brief + Init a key cache if it has not been initied before +*/ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache) { DBUG_ENTER("ha_init_key_cache"); @@ -2718,8 +2710,9 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache) } -/* Resize key cache */ - +/** @brief + Resize key cache +*/ int ha_resize_key_cache(KEY_CACHE *key_cache) { DBUG_ENTER("ha_resize_key_cache"); @@ -2740,8 +2733,9 @@ int ha_resize_key_cache(KEY_CACHE *key_cache) } -/* Change parameters for key cache (like size) */ - +/** @brief + Change parameters for key cache (like size) +*/ int ha_change_key_cache_param(KEY_CACHE *key_cache) { if (key_cache->key_cache_inited) @@ -2755,16 +2749,18 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache) return 0; } -/* Free memory allocated by a key cache */ - +/** @brief + Free memory allocated by a key cache +*/ int ha_end_key_cache(KEY_CACHE *key_cache) { end_key_cache(key_cache, 1); // Can never fail return 0; } -/* Move all tables from one key cache to another one */ - +/** @brief + Move all tables from one key cache to another one +*/ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache) { @@ -2773,7 +2769,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, } -/* +/** @brief Try to discover one table from handler(s) RETURN @@ -2781,7 +2777,6 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, 0 : OK. In this case *frmblob and *frmlen are set >0 : error. frmblob and frmlen may not be set */ - struct st_discover_args { const char *db; @@ -2825,7 +2820,7 @@ int ha_discover(THD *thd, const char *db, const char *name, } -/* +/** @brief Call this function in order to give the handler the possibility 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 @@ -2860,8 +2855,8 @@ 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", - db, path, wild, dir)); + DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d", + db, path, wild ? wild : "NULL", dir)); st_find_files_args args= {db, path, wild, dir, files}; plugin_foreach(thd, find_files_handlerton, @@ -2871,7 +2866,7 @@ ha_find_files(THD *thd,const char *db,const char *path, } -/* +/** @brief Ask handler if the table exists in engine RETURN @@ -2879,8 +2874,7 @@ ha_find_files(THD *thd,const char *db,const char *path, 1 Table exists # Error code - */ - +*/ struct st_table_exists_in_engine_args { const char *db; @@ -2932,7 +2926,7 @@ struct binlog_func_st void *arg; }; -/* +/** @brief Listing handlertons first to avoid recursive calls and deadlock */ static my_bool binlog_func_list(THD *thd, st_plugin_int *plugin, void *arg) @@ -3050,7 +3044,7 @@ void ha_binlog_log_query(THD *thd, handlerton *hton, } #endif -/* +/** @brief Read the first row of a multi-range set. SYNOPSIS @@ -3074,7 +3068,6 @@ void ha_binlog_log_query(THD *thd, handlerton *hton, HA_ERR_END_OF_FILE No rows in range # Error code */ - int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer) @@ -3107,7 +3100,7 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, } -/* +/** @brief Read the next row of a multi-range set. SYNOPSIS @@ -3125,7 +3118,6 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, HA_ERR_END_OF_FILE No (more) rows in range # Error code */ - int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) { int result; @@ -3178,7 +3170,7 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) } -/* +/** @brief Read first row between two ranges. Store ranges for future calls to read_range_next @@ -3197,7 +3189,6 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) HA_ERR_END_OF_FILE No rows in range # Error code */ - int handler::read_range_first(const key_range *start_key, const key_range *end_key, bool eq_range_arg, bool sorted) @@ -3232,7 +3223,7 @@ int handler::read_range_first(const key_range *start_key, } -/* +/** @brief Read next row between two ranges. SYNOPSIS @@ -3246,7 +3237,6 @@ int handler::read_range_first(const key_range *start_key, HA_ERR_END_OF_FILE No rows in range # Error code */ - int handler::read_range_next() { int result; @@ -3266,7 +3256,7 @@ int handler::read_range_next() } -/* +/** @brief Compare if found key (in row) is over max-value SYNOPSIS @@ -3283,7 +3273,6 @@ int handler::read_range_next() -1 Key is less than range 1 Key is larger than range */ - int handler::compare_key(key_range *range) { int cmp; @@ -3307,7 +3296,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key, } -/* +/** @brief Returns a list of all known extensions. SYNOPSIS @@ -3321,7 +3310,6 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key, RETURN VALUE pointer pointer to TYPELIB structure */ - static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin, void *arg) { @@ -3353,7 +3341,6 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin, TYPELIB *ha_known_exts(void) { - MEM_ROOT *mem_root= current_thd->mem_root; if (!known_extensions.type_names || mysys_usage_id != known_extensions_id) { List<char> found_exts; @@ -3459,7 +3446,6 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) - table is not mysql.event */ -#ifdef HAVE_ROW_BASED_REPLICATION /* The Sun compiler cannot instantiate the template below if this is declared static, but it works by putting it into an anonymous namespace. */ @@ -3484,7 +3470,7 @@ namespace { } } -/* +/** @brief Write table maps for all (manually or automatically) locked tables to the binary log. @@ -3505,7 +3491,7 @@ namespace { SEE ALSO THD::lock THD::locked_tables - */ +*/ namespace { int write_locked_table_maps(THD *thd) @@ -3614,7 +3600,6 @@ namespace binlog_log_row<Update_rows_log_event>(TABLE *, const byte *, const byte *); } -#endif /* HAVE_ROW_BASED_REPLICATION */ int handler::ha_external_lock(THD *thd, int lock_type) { @@ -3629,10 +3614,9 @@ int handler::ha_external_lock(THD *thd, int lock_type) } -/* +/** @brief Check handler usage and reset state of file to after 'open' */ - int handler::ha_reset() { DBUG_ENTER("ha_reset"); @@ -3655,10 +3639,8 @@ int handler::ha_write_row(byte *buf) int error; if (unlikely(error= write_row(buf))) return error; -#ifdef HAVE_ROW_BASED_REPLICATION if (unlikely(error= binlog_log_row<Write_rows_log_event>(table, 0, buf))) return error; -#endif return 0; } @@ -3674,10 +3656,8 @@ int handler::ha_update_row(const byte *old_data, byte *new_data) if (unlikely(error= update_row(old_data, new_data))) return error; -#ifdef HAVE_ROW_BASED_REPLICATION if (unlikely(error= binlog_log_row<Update_rows_log_event>(table, old_data, new_data))) return error; -#endif return 0; } @@ -3686,21 +3666,18 @@ int handler::ha_delete_row(const byte *buf) int error; if (unlikely(error= delete_row(buf))) return error; -#ifdef HAVE_ROW_BASED_REPLICATION if (unlikely(error= binlog_log_row<Delete_rows_log_event>(table, buf, 0))) return error; -#endif return 0; } -/* +/** @brief use_hidden_primary_key() is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key */ - void handler::use_hidden_primary_key() { /* fallback to use all columns in the table to identify row */ @@ -3708,11 +3685,10 @@ void handler::use_hidden_primary_key() } -/* +/** @brief Dummy function which accept information about log files which is not need by handlers */ - void signal_log_not_needed(struct handlerton, char *log_file) { DBUG_ENTER("signal_log_not_needed"); @@ -3768,12 +3744,11 @@ err: #define fl_dir FN_ROOTDIR -/* +/** @brief Dummy function to return log status should be replaced by function which really detect the log status and check that the file is a log of this handler. */ - enum log_status fl_get_log_status(char *log) { MY_STAT stat_buff; @@ -3813,7 +3788,7 @@ void fl_log_iterator_destroy(struct handler_iterator *iterator) } -/* +/** @brief returns buffer, to be assigned in handler_iterator struct */ enum handler_create_iterator_result diff --git a/sql/handler.h b/sql/handler.h index 17e98803209..b6fd807194e 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000,2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -766,7 +765,7 @@ typedef struct st_ha_create_information bool table_existed; /* 1 in create if table existed */ bool frm_only; /* 1 if no ha_create_table() */ bool varchar; /* 1 if table has a VARCHAR */ - bool store_on_disk; /* 1 if table stored on disk */ + enum ha_storage_media storage_media; /* DEFAULT, DISK or MEMORY */ } HA_CREATE_INFO; @@ -1412,7 +1411,7 @@ public: { return FALSE; } virtual char* get_foreign_key_create_info() { return(NULL);} /* gets foreign key create string from InnoDB */ - virtual char* get_tablespace_name(THD *thd) + virtual char* get_tablespace_name(THD *thd, char *name, uint name_len) { return(NULL);} /* gets tablespace name from handler */ /* used in ALTER TABLE; 1 if changing storage engine is allowed */ virtual bool can_switch_engines() { return 1; } diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc index ec200768222..9303120e18a 100644 --- a/sql/hash_filo.cc +++ b/sql/hash_filo.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/hash_filo.h b/sql/hash_filo.h index fc48c3b1540..c25af67b572 100644 --- a/sql/hash_filo.h +++ b/sql/hash_filo.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/hostname.cc b/sql/hostname.cc index 52c4107372f..049220c6b6f 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/init.cc b/sql/init.cc index 9f975296cb6..ff236c03204 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -46,5 +45,11 @@ void unireg_init(ulong options) { /* It's used by filesort... */ log_10[i]= nr ; nr*= 10.0; } + /* Make a tab of powers of 0.1 */ + for (i= 0, nr= 0.1; i < array_elements(log_01); i++) + { + log_01[i]= nr; + nr*= 0.1; + } DBUG_VOID_RETURN; } diff --git a/sql/item.cc b/sql/item.cc index e2ab28dd452..d0691979c66 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,10 +25,6 @@ #include "sql_trigger.h" #include "sql_select.h" -static void mark_as_dependent(THD *thd, - SELECT_LEX *last, SELECT_LEX *current, - Item_ident *item); - const String my_null_string("NULL", 4, default_charset_info); /****************************************************************************/ @@ -1271,7 +1266,10 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, if (type() == SUM_FUNC_ITEM && skip_registered && ((Item_sum *) this)->ref_by) return; - if (type() != SUM_FUNC_ITEM && with_sum_func) + if ((type() != SUM_FUNC_ITEM && with_sum_func) || + (type() == FUNC_ITEM && + (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC || + ((Item_func *) this)->functype() == Item_func::TRIG_COND_FUNC))) { /* Will split complicated items and ignore simple ones */ split_sum_func(thd, ref_pointer_array, fields); @@ -1555,6 +1553,8 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, doesn't display each argument's characteristics. - if nargs is 1, then this error cannot happen. */ + LINT_INIT(safe_args[0]); + LINT_INIT(safe_args[1]); if (nargs >=2 && nargs <= 3) { safe_args[0]= args[0]; @@ -1716,7 +1716,7 @@ void Item_field::set_field(Field *field_par) field=result_field=field_par; // for easy coding with fields maybe_null=field->maybe_null(); decimals= field->decimals(); - max_length= field_par->max_length(); + max_length= field_par->max_display_length(); table_name= *field_par->table_name; field_name= field_par->field_name; db_name= field_par->table->s->db.str; @@ -2425,21 +2425,22 @@ void Item_param::set_decimal(const char *str, ulong length) the fact that even wrong value sent over binary protocol fits into MAX_DATE_STRING_REP_LENGTH buffer. */ -void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg) +void Item_param::set_time(TIME *tm, timestamp_type time_type, + uint32 max_length_arg) { DBUG_ENTER("Item_param::set_time"); value.time= *tm; - value.time.time_type= type; + value.time.time_type= time_type; if (value.time.year > 9999 || value.time.month > 12 || value.time.day > 31 || - type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 || + time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 || value.time.minute > 59 || value.time.second > 59) { char buff[MAX_DATE_STRING_REP_LENGTH]; uint length= my_TIME_to_str(&value.time, buff); - make_truncated_value_warning(current_thd, buff, length, type, 0); + make_truncated_value_warning(current_thd, buff, length, time_type, 0); set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR); } @@ -2905,7 +2906,7 @@ bool Item_param::basic_const_item() const Item * -Item_param::new_item() +Item_param::clone_item() { /* see comments in the header file */ switch (state) { @@ -3504,6 +3505,16 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) { if (*from_field) { + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && + select->cur_pos_in_select_list != UNDEF_POS) + { + /* + As this is an outer field it should be added to the list of + non aggregated fields of the outer select. + */ + marker= select->cur_pos_in_select_list; + select->non_agg_fields.push_back(this); + } if (*from_field != view_ref_found) { prev_subselect_item->used_tables_cache|= (*from_field)->table->map; @@ -3512,28 +3523,29 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) thd->lex->in_sum_func->nest_level == thd->lex->current_select->nest_level) { - Item::Type type= (*reference)->type(); + Item::Type ref_type= (*reference)->type(); set_if_bigger(thd->lex->in_sum_func->max_arg_level, select->nest_level); set_field(*from_field); fixed= 1; mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? + ((ref_type == REF_ITEM || + ref_type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); return 0; } } else { - Item::Type type= (*reference)->type(); + Item::Type ref_type= (*reference)->type(); prev_subselect_item->used_tables_cache|= (*reference)->used_tables(); prev_subselect_item->const_item_cache&= (*reference)->const_item(); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? + ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); /* @@ -3706,10 +3718,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) bool Item_field::fix_fields(THD *thd, Item **reference) { DBUG_ASSERT(fixed == 0); + Field *from_field= (Field *)not_found_field; + bool outer_fixed= false; + if (!field) // If field is not checked { - Field *from_field= (Field *)not_found_field; - bool outer_fixed= false; /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead @@ -3733,6 +3746,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); + if (!res) + return 1; if (res != (Item **)not_found_item) { if ((*res)->type() == Item::FIELD_ITEM) @@ -3799,6 +3814,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) goto error; if (!ret) return FALSE; + outer_fixed= 1; } set_field(from_field); @@ -3858,6 +3874,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference) } #endif fixed= 1; + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && + !outer_fixed && !thd->lex->in_sum_func && + thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS) + { + thd->lex->current_select->non_agg_fields.push_back(this); + marker= thd->lex->current_select->cur_pos_in_select_list; + } return FALSE; error: @@ -4065,7 +4088,7 @@ Item *Item_field::replace_equal_field(byte *arg) void Item::init_make_field(Send_field *tmp_field, - enum enum_field_types field_type) + enum enum_field_types field_type_arg) { char *empty_name= (char*) ""; tmp_field->db_name= empty_name; @@ -4077,7 +4100,7 @@ void Item::init_make_field(Send_field *tmp_field, tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) | (my_binary_compare(collation.collation) ? BINARY_FLAG : 0); - tmp_field->type=field_type; + tmp_field->type= field_type_arg; tmp_field->length=max_length; tmp_field->decimals=decimals; if (unsigned_flag) @@ -4092,12 +4115,12 @@ void Item::make_field(Send_field *tmp_field) enum_field_types Item::string_field_type() const { - enum_field_types type= FIELD_TYPE_VAR_STRING; + enum_field_types f_type= MYSQL_TYPE_VAR_STRING; if (max_length >= 16777216) - type= FIELD_TYPE_LONG_BLOB; + f_type= MYSQL_TYPE_LONG_BLOB; else if (max_length >= 65536) - type= FIELD_TYPE_MEDIUM_BLOB; - return type; + f_type= MYSQL_TYPE_MEDIUM_BLOB; + return f_type; } @@ -4111,9 +4134,9 @@ enum_field_types Item::field_type() const { switch (result_type()) { case STRING_RESULT: return string_field_type(); - case INT_RESULT: return FIELD_TYPE_LONGLONG; - case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL; - case REAL_RESULT: return FIELD_TYPE_DOUBLE; + case INT_RESULT: return MYSQL_TYPE_LONGLONG; + case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL; + case REAL_RESULT: return MYSQL_TYPE_DOUBLE; case ROW_RESULT: default: DBUG_ASSERT(0); @@ -4308,18 +4331,19 @@ void Item_field::save_org_in_field(Field *to) int Item_field::save_in_field(Field *to, bool no_conversions) { + int res; if (result_field->is_null()) { null_value=1; - return set_field_to_null_with_conversions(to, no_conversions); + res= set_field_to_null_with_conversions(to, no_conversions); } else { to->set_notnull(); - field_conv(to,result_field); + res= field_conv(to,result_field); null_value=0; } - return 0; + return res; } @@ -4467,7 +4491,7 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const } -Item *Item_int_with_ref::new_item() +Item *Item_int_with_ref::clone_item() { DBUG_ASSERT(ref->const_item()); /* @@ -4638,18 +4662,31 @@ my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value) int Item_hex_string::save_in_field(Field *field, bool no_conversions) { - int error; field->set_notnull(); if (field->result_type() == STRING_RESULT) + return field->store(str_value.ptr(), str_value.length(), + collation.collation); + + ulonglong nr; + uint32 length= str_value.length(); + if (length > 8) { - error=field->store(str_value.ptr(),str_value.length(),collation.collation); + nr= field->flags & UNSIGNED_FLAG ? ULONGLONG_MAX : LONGLONG_MAX; + goto warn; } - else + nr= (ulonglong) val_int(); + if ((length == 8) && !(field->flags & UNSIGNED_FLAG) && (nr > LONGLONG_MAX)) { - longlong nr=val_int(); - error=field->store(nr, TRUE); // Assume hex numbers are unsigned + nr= LONGLONG_MAX; + goto warn; } - return error; + return field->store((longlong) nr, TRUE); // Assume hex numbers are unsigned + +warn: + if (!field->store((longlong) nr, TRUE)) + field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, + 1); + return 1; } @@ -4732,10 +4769,10 @@ bool Item_null::send(Protocol *protocol, String *packet) bool Item::send(Protocol *protocol, String *buffer) { bool result; - enum_field_types type; + enum_field_types f_type; LINT_INIT(result); // Will be set if null_value == 0 - switch ((type=field_type())) { + switch ((f_type=field_type())) { default: case MYSQL_TYPE_NULL: case MYSQL_TYPE_DECIMAL: @@ -4814,7 +4851,7 @@ bool Item::send(Protocol *protocol, String *buffer) get_date(&tm, TIME_FUZZY_DATE); if (!null_value) { - if (type == MYSQL_TYPE_DATE) + if (f_type == MYSQL_TYPE_DATE) return protocol->store_date(&tm); else result= protocol->store(&tm); @@ -5027,7 +5064,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; if (from_field == view_ref_found) { - Item::Type type= (*reference)->type(); + Item::Type refer_type= (*reference)->type(); prev_subselect_item->used_tables_cache|= (*reference)->used_tables(); prev_subselect_item->const_item_cache&= @@ -5035,7 +5072,8 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) DBUG_ASSERT((*reference)->type() == REF_ITEM); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? + ((refer_type == REF_ITEM || + refer_type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); /* @@ -5326,18 +5364,7 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) int Item_ref::save_in_field(Field *to, bool no_conversions) { int res; - if (result_field) - { - if (result_field->is_null()) - { - null_value= 1; - return set_field_to_null_with_conversions(to, no_conversions); - } - to->set_notnull(); - field_conv(to, result_field); - null_value= 0; - return 0; - } + DBUG_ASSERT(!result_field); res= (*ref)->save_in_field(to, no_conversions); null_value= (*ref)->null_value; return res; @@ -5556,6 +5583,13 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (field_arg->flags & NO_DEFAULT_VALUE_FLAG) { + if (field_arg->reset()) + { + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; + } + if (context->error_processor == &view_error_processor) { TABLE_LIST *view= cached_table->top_table(); @@ -5574,7 +5608,6 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) ER(ER_NO_DEFAULT_FOR_FIELD), field_arg->field_name); } - field_arg->set_default(); return 1; } field_arg->set_default(); @@ -5781,8 +5814,8 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) { table_grants->want_privilege= want_privilege; - if (check_grant_column(thd, table_grants, triggers->table->s->db.str, - triggers->table->s->table_name.str, field_name, + if (check_grant_column(thd, table_grants, triggers->trigger_table->s->db.str, + triggers->trigger_table->s->table_name.str, field_name, strlen(field_name), thd->security_ctx)) return TRUE; } @@ -5895,7 +5928,8 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) DBUG_ASSERT(item_row->cols() == comp_item_row->cols()); col= item_row->cols(); while (col-- > 0) - resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col)); + resolve_const_item(thd, item_row->addr(col), + comp_item_row->element_index(col)); break; } /* Fallthrough */ @@ -6163,7 +6197,7 @@ bool Item_cache_row::setup(Item * item) return 1; for (uint i= 0; i < item_count; i++) { - Item *el= item->el(i); + Item *el= item->element_index(i); Item_cache *tmp; if (!(tmp= values[i]= Item_cache::get_cache(el->result_type()))) return 1; @@ -6179,7 +6213,7 @@ void Item_cache_row::store(Item * item) item->bring_value(); for (uint i= 0; i < item_count; i++) { - values[i]->store(item->el(i)); + values[i]->store(item->element_index(i)); null_value|= values[i]->null_value; } } diff --git a/sql/item.h b/sql/item.h index bda57020cf2..09c118a2e14 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -337,23 +336,18 @@ public: { save_table_list= context->table_list; save_first_name_resolution_table= context->first_name_resolution_table; - save_next_name_resolution_table= (context->first_name_resolution_table) ? - context->first_name_resolution_table-> - next_name_resolution_table : - NULL; save_resolve_in_select_list= context->resolve_in_select_list; save_next_local= table_list->next_local; + save_next_name_resolution_table= table_list->next_name_resolution_table; } /* Restore a name resolution context from saved state. */ void restore_state(Name_resolution_context *context, TABLE_LIST *table_list) { table_list->next_local= save_next_local; + table_list->next_name_resolution_table= save_next_name_resolution_table; context->table_list= save_table_list; context->first_name_resolution_table= save_first_name_resolution_table; - if (context->first_name_resolution_table) - context->first_name_resolution_table-> - next_name_resolution_table= save_next_name_resolution_table; context->resolve_in_select_list= save_resolve_in_select_list; } }; @@ -483,7 +477,8 @@ public: Item *next; uint32 max_length; uint name_length; /* Length of name */ - uint8 marker, decimals; + int8 marker; + uint8 decimals; my_bool maybe_null; /* If item may be null */ my_bool null_value; /* if item is null */ my_bool unsigned_flag; @@ -692,7 +687,7 @@ public: */ virtual bool basic_const_item() const { return 0; } /* cloning of constant items (0 if it is not const) */ - virtual Item *new_item() { return 0; } + virtual Item *clone_item() { return 0; } virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} @@ -823,6 +818,7 @@ public: virtual bool collect_item_field_processor(byte * arg) { return 0; } virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } + virtual bool reset_query_id_processor(byte *query_id_arg) { return 0; } virtual bool is_expensive_processor(byte *arg) { return 0; } virtual bool register_field_in_read_map(byte *arg) { return 0; } /* @@ -900,11 +896,11 @@ public: For SP local variable returns address of pointer to Item representing its current value and pointer passed via parameter otherwise. */ - virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; } + virtual Item **this_item_addr(THD *thd, Item **addr_arg) { return addr_arg; } // Row emulation virtual uint cols() { return 1; } - virtual Item* el(uint i) { return this; } + virtual Item* element_index(uint i) { return this; } virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); // It is not row => null inside is impossible @@ -1170,7 +1166,8 @@ class Item_name_const : public Item Item *value_item; Item *name_item; public: - Item_name_const(Item *name, Item *val): value_item(val), name_item(name) + Item_name_const(Item *name_arg, Item *val): + value_item(val), name_item(name_arg) { Item::maybe_null= TRUE; } @@ -1390,7 +1387,7 @@ public: Item *equal_fields_propagator(byte *arg); bool set_no_const_sub(byte *arg); Item *replace_equal_field(byte *arg); - inline uint32 max_disp_length() { return field->max_length(); } + inline uint32 max_disp_length() { return field->max_display_length(); } Item_field *filed_for_view_update() { return this; } Item *safe_charset_converter(CHARSET_INFO *tocs); int fix_outer_field(THD *thd, Field **field, Item **reference); @@ -1424,7 +1421,7 @@ public: /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() {} bool basic_const_item() const { return 1; } - Item *new_item() { return new Item_null(name); } + Item *clone_item() { return new Item_null(name); } bool is_null() { return 1; } void print(String *str) { str->append(STRING_WITH_LEN("NULL")); } Item *safe_charset_converter(CHARSET_INFO *tocs); @@ -1573,7 +1570,7 @@ public: basic_const_item returned TRUE. */ Item *safe_charset_converter(CHARSET_INFO *tocs); - Item *new_item(); + Item *clone_item(); /* Implement by-value equality evaluation if parameter value is set and is a basic constant (integer, real or string). @@ -1605,7 +1602,7 @@ public: String *val_str(String*); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } - Item *new_item() { return new Item_int(name,value,max_length); } + Item *clone_item() { return new Item_int(name,value,max_length); } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} void print(String *str); @@ -1625,7 +1622,7 @@ public: double val_real() { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } String *val_str(String*); - Item *new_item() { return new Item_uint(name,max_length); } + Item *clone_item() { return new Item_uint(name,max_length); } int save_in_field(Field *field, bool no_conversions); void print(String *str); Item_num *neg (); @@ -1656,7 +1653,7 @@ public: my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } - Item *new_item() + Item *clone_item() { return new Item_decimal(name, &decimal_value, decimals, max_length); } @@ -1714,7 +1711,7 @@ public: bool basic_const_item() const { return 1; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - Item *new_item() + Item *clone_item() { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } void print(String *str); @@ -1800,7 +1797,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; - Item *new_item() + Item *clone_item() { return new Item_string(name, str_value.ptr(), str_value.length(), collation.collation); @@ -1854,9 +1851,9 @@ class Item_return_int :public Item_int { enum_field_types int_field_type; public: - Item_return_int(const char *name, uint length, + Item_return_int(const char *name_arg, uint length, enum_field_types field_type_arg) - :Item_int(name, 0, length), int_field_type(field_type_arg) + :Item_int(name_arg, 0, length), int_field_type(field_type_arg) { unsigned_flag=1; } @@ -2120,7 +2117,7 @@ public: { return ref->save_in_field(field, no_conversions); } - Item *new_item(); + Item *clone_item(); virtual Item *real_item() { return ref; } bool check_partition_func_processor(byte *int_arg) {return TRUE;} }; @@ -2135,7 +2132,6 @@ public: #include "item_strfunc.h" #include "item_geofunc.h" #include "item_timefunc.h" -#include "item_uniq.h" #include "item_subselect.h" #include "item_xmlfunc.h" #endif @@ -2374,6 +2370,9 @@ public: bool fix_fields(THD *, Item **); void print(String *str); table_map used_tables() const { return (table_map)0L; } + Field *get_tmp_table_field() { return 0; } + Item *copy_or_same(THD *thd) { return this; } + Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } void cleanup(); private: @@ -2556,8 +2555,8 @@ public: enum Item_result result_type() const { return ROW_RESULT; } uint cols() { return item_count; } - Item* el(uint i) { return values[i]; } - Item** addr(uint i) { return (Item **) (values + i); } + Item *element_index(uint i) { return values[i]; } + Item **addr(uint i) { return (Item **) (values + i); } bool check_cols(uint c); bool null_inside(); void bring_value(); diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 37f9ca7ce6c..c162b84f457 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 639017872a0..17da1174e37 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,13 +26,17 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item); -static Item_result item_store_type(Item_result a,Item_result b) +static Item_result item_store_type(Item_result a, Item *item, + my_bool unsigned_flag) { + Item_result b= item->result_type(); + if (a == STRING_RESULT || b == STRING_RESULT) return STRING_RESULT; else if (a == REAL_RESULT || b == REAL_RESULT) return REAL_RESULT; - else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT) + else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT || + unsigned_flag != item->unsigned_flag) return DECIMAL_RESULT; else return INT_RESULT; @@ -42,6 +45,7 @@ static Item_result item_store_type(Item_result a,Item_result b) static void agg_result_type(Item_result *type, Item **items, uint nitems) { Item **item, **item_end; + my_bool unsigned_flag= 0; *type= STRING_RESULT; /* Skip beginning NULL items */ @@ -50,6 +54,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) if ((*item)->type() != Item::NULL_ITEM) { *type= (*item)->result_type(); + unsigned_flag= (*item)->unsigned_flag; item++; break; } @@ -58,7 +63,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) for (; item < item_end; item++) { if ((*item)->type() != Item::NULL_ITEM) - *type= item_store_type(type[0], (*item)->result_type()); + *type= item_store_type(*type, *item, unsigned_flag); } } @@ -177,6 +182,22 @@ longlong Item_func_not::val_int() } /* + We put any NOT expression into parenthesis to avoid + possible problems with internal view representations where + any '!' is converted to NOT. It may cause a problem if + '!' is used in an expression together with other operators + whose precedence is lower than the precedence of '!' yet + higher than the precedence of NOT. +*/ + +void Item_func_not::print(String *str) +{ + str->append('('); + Item_func::print(str); + str->append(')'); +} + +/* special NOT for ALL subquery */ @@ -307,7 +328,7 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item) void Item_bool_func2::fix_length_and_dec() { max_length= 1; // Function returns 0 or 1 - THD *thd= current_thd; + THD *thd; /* As some compare functions are generated after sql_yacc, @@ -345,12 +366,13 @@ void Item_bool_func2::fix_length_and_dec() return; } + thd= current_thd; if (!thd->is_context_analysis_only()) { - Item *real_item= args[0]->real_item(); - if (real_item->type() == FIELD_ITEM) + Item *arg_real_item= args[0]->real_item(); + if (arg_real_item->type() == FIELD_ITEM) { - Field *field=((Item_field*) real_item)->field; + Field *field=((Item_field*) arg_real_item)->field; if (field->can_be_compared_as_longlong()) { if (convert_constant_item(thd, field,&args[1])) @@ -362,10 +384,10 @@ void Item_bool_func2::fix_length_and_dec() } } } - real_item= args[1]->real_item(); - if (real_item->type() == FIELD_ITEM /* && !real_item->const_item() */) + arg_real_item= args[1]->real_item(); + if (arg_real_item->type() == FIELD_ITEM) { - Field *field=((Item_field*) real_item)->field; + Field *field=((Item_field*) arg_real_item)->field; if (field->can_be_compared_as_longlong()) { if (convert_constant_item(thd, field,&args[0])) @@ -401,9 +423,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) return 1; for (uint i=0; i < n; i++) { - if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) + if ((*a)->element_index(i)->cols() != (*b)->element_index(i)->cols()) { - my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->el(i)->cols()); + my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); return 1; } comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); @@ -465,8 +487,19 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) break; } case DECIMAL_RESULT: + break; case REAL_RESULT: + { + if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC) + { + precision= 5 * log_01[max((*a)->decimals, (*b)->decimals)]; + if (func == &Arg_comparator::compare_real) + func= &Arg_comparator::compare_real_fixed; + else if (func == &Arg_comparator::compare_e_real) + func= &Arg_comparator::compare_e_real_fixed; + } break; + } default: DBUG_ASSERT(0); } @@ -605,6 +638,44 @@ int Arg_comparator::compare_e_decimal() return test(my_decimal_cmp(val1, val2) == 0); } + +int Arg_comparator::compare_real_fixed() +{ + /* + Fix yet another manifestation of Bug#2338. 'Volatile' will instruct + gcc to flush double values out of 80-bit Intel FPU registers before + performing the comparison. + */ + volatile double val1, val2; + val1= (*a)->val_real(); + if (!(*a)->null_value) + { + val2= (*b)->val_real(); + if (!(*b)->null_value) + { + owner->null_value= 0; + if (val1 == val2 || fabs(val1 - val2) < precision) + return 0; + if (val1 < val2) + return -1; + return 1; + } + } + owner->null_value= 1; + return -1; +} + + +int Arg_comparator::compare_e_real_fixed() +{ + double val1= (*a)->val_real(); + double val2= (*b)->val_real(); + if ((*a)->null_value || (*b)->null_value) + return test((*a)->null_value && (*b)->null_value); + return test(val1 == val2 || fabs(val1 - val2) < precision); +} + + int Arg_comparator::compare_int_signed() { longlong val1= (*a)->val_int(); @@ -788,10 +859,10 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref) uint n= cache->cols(); for (uint i= 0; i < n; i++) { - if (args[0]->el(i)->used_tables()) - ((Item_cache *)cache->el(i))->set_used_tables(OUTER_REF_TABLE_BIT); + if (args[0]->element_index(i)->used_tables()) + ((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT); else - ((Item_cache *)cache->el(i))->set_used_tables(0); + ((Item_cache *)cache->element_index(i))->set_used_tables(0); } used_tables_cache= args[0]->used_tables(); } @@ -832,6 +903,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) longlong Item_in_optimizer::val_int() { + bool tmp; DBUG_ASSERT(fixed == 1); cache->store(args[0]); @@ -862,16 +934,40 @@ longlong Item_in_optimizer::val_int() We disable the predicates we've pushed down into subselect, run the subselect and see if it has produced any rows. */ - ((Item_in_subselect*)args[1])->enable_pushed_conds= FALSE; - longlong tmp= args[1]->val_bool_result(); - result_for_null_param= null_value= - !((Item_in_subselect*)args[1])->engine->no_rows(); - ((Item_in_subselect*)args[1])->enable_pushed_conds= TRUE; + Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; + if (cache->cols() == 1) + { + item_subs->set_cond_guard_var(0, FALSE); + (void) args[1]->val_bool_result(); + result_for_null_param= null_value= !item_subs->engine->no_rows(); + item_subs->set_cond_guard_var(0, TRUE); + } + else + { + uint i; + uint ncols= cache->cols(); + /* + Turn off the predicates that are based on column compares for + which the left part is currently NULL + */ + for (i= 0; i < ncols; i++) + { + if (cache->element_index(i)->null_value) + item_subs->set_cond_guard_var(i, FALSE); + } + + (void) args[1]->val_bool_result(); + result_for_null_param= null_value= !item_subs->engine->no_rows(); + + /* Turn all predicates back on */ + for (i= 0; i < ncols; i++) + item_subs->set_cond_guard_var(i, TRUE); + } } } return 0; } - bool tmp= args[1]->val_bool_result(); + tmp= args[1]->val_bool_result(); null_value= args[1]->null_value; return tmp; } @@ -980,15 +1076,17 @@ longlong Item_func_strcmp::val_int() void Item_func_interval::fix_length_and_dec() { - use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) || - (row->el(0)->result_type() == INT_RESULT); + use_decimal_comparison= ((row->element_index(0)->result_type() == + DECIMAL_RESULT) || + (row->element_index(0)->result_type() == + INT_RESULT)); if (row->cols() > 8) { bool consts=1; for (uint i=1 ; consts && i < row->cols() ; i++) { - consts&= row->el(i)->const_item(); + consts&= row->element_index(i)->const_item(); } if (consts && @@ -999,7 +1097,7 @@ void Item_func_interval::fix_length_and_dec() { for (uint i=1 ; i < row->cols(); i++) { - Item *el= row->el(i); + Item *el= row->element_index(i); interval_range *range= intervals + (i-1); if ((el->result_type() == DECIMAL_RESULT) || (el->result_type() == INT_RESULT)) @@ -1024,7 +1122,7 @@ void Item_func_interval::fix_length_and_dec() { for (uint i=1 ; i < row->cols(); i++) { - intervals[i-1].dbl= row->el(i)->val_real(); + intervals[i-1].dbl= row->element_index(i)->val_real(); } } } @@ -1064,15 +1162,15 @@ longlong Item_func_interval::val_int() if (use_decimal_comparison) { - dec= row->el(0)->val_decimal(&dec_buf); - if (row->el(0)->null_value) + dec= row->element_index(0)->val_decimal(&dec_buf); + if (row->element_index(0)->null_value) return -1; my_decimal2double(E_DEC_FATAL_ERROR, dec, &value); } else { - value= row->el(0)->val_real(); - if (row->el(0)->null_value) + value= row->element_index(0)->val_real(); + if (row->element_index(0)->null_value) return -1; } @@ -1108,16 +1206,16 @@ longlong Item_func_interval::val_int() for (i=1 ; i < row->cols() ; i++) { - Item *el= row->el(i); + Item *el= row->element_index(i); if (use_decimal_comparison && ((el->result_type() == DECIMAL_RESULT) || (el->result_type() == INT_RESULT))) { - my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf); + my_decimal e_dec_buf, *e_dec= row->element_index(i)->val_decimal(&e_dec_buf); if (my_decimal_cmp(e_dec, dec) > 0) return i-1; } - else if (row->el(i)->val_real() > value) + else if (row->element_index(i)->val_real() > value) return i-1; } return i-1; @@ -1194,11 +1292,11 @@ void Item_func_between::fix_length_and_dec() They are compared as integers, so for const item this time-consuming conversion can be done only once, not for every single comparison */ - if (args[0]->type() == FIELD_ITEM && + if (args[0]->real_item()->type() == FIELD_ITEM && thd->lex->sql_command != SQLCOM_CREATE_VIEW && thd->lex->sql_command != SQLCOM_SHOW_CREATE) { - Field *field=((Item_field*) args[0])->field; + Field *field=((Item_field*) (args[0]->real_item()))->field; if (field->can_be_compared_as_longlong()) { /* @@ -1811,7 +1909,9 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref) buff should match stack usage from Item_func_case::val_int() -> Item_func_case::find_item() */ +#ifndef EMBEDDED_LIBRARY char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2]; +#endif bool res= Item_func::fix_fields(thd, ref); /* Call check_stack_overrun after fix_fields to be sure that stack variable @@ -1828,7 +1928,6 @@ void Item_func_case::fix_length_and_dec() { Item **agg; uint nagg; - THD *thd= current_thd; uint found_types= 0; if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; @@ -2289,11 +2388,11 @@ void cmp_item_row::store_value(Item *item) { if (!comparators[i]) if (!(comparators[i]= - cmp_item::get_comparator(item->el(i)->result_type(), - item->el(i)->collation.collation))) + cmp_item::get_comparator(item->element_index(i)->result_type(), + item->element_index(i)->collation.collation))) break; // new failed - comparators[i]->store_value(item->el(i)); - item->null_value|= item->el(i)->null_value; + comparators[i]->store_value(item->element_index(i)); + item->null_value|= item->element_index(i)->null_value; } } DBUG_VOID_RETURN; @@ -2318,8 +2417,8 @@ void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) if (!(comparators[i]= tmpl->comparators[i]->make_same())) break; // new failed comparators[i]->store_value_by_template(tmpl->comparators[i], - item->el(i)); - item->null_value|= item->el(i)->null_value; + item->element_index(i)); + item->null_value|= item->element_index(i)->null_value; } } } @@ -2337,9 +2436,9 @@ int cmp_item_row::cmp(Item *arg) arg->bring_value(); for (uint i=0; i < n; i++) { - if (comparators[i]->cmp(arg->el(i))) + if (comparators[i]->cmp(arg->element_index(i))) { - if (!arg->el(i)->null_value) + if (!arg->element_index(i)->null_value) return 1; was_null= 1; } @@ -2350,11 +2449,11 @@ int cmp_item_row::cmp(Item *arg) int cmp_item_row::compare(cmp_item *c) { - cmp_item_row *cmp= (cmp_item_row *) c; + cmp_item_row *l_cmp= (cmp_item_row *) c; for (uint i=0; i < n; i++) { int res; - if ((res= comparators[i]->compare(cmp->comparators[i]))) + if ((res= comparators[i]->compare(l_cmp->comparators[i]))) return res; } return 0; @@ -2381,8 +2480,8 @@ int cmp_item_decimal::cmp(Item *arg) int cmp_item_decimal::compare(cmp_item *arg) { - cmp_item_decimal *cmp= (cmp_item_decimal*) arg; - return my_decimal_cmp(&value, &cmp->value); + cmp_item_decimal *l_cmp= (cmp_item_decimal*) arg; + return my_decimal_cmp(&value, &l_cmp->value); } @@ -3081,7 +3180,7 @@ longlong Item_func_isnull::val_int() Handle optimization if the argument can't be null This has to be here because of the test in update_used_tables(). */ - if (!used_tables_cache) + if (!used_tables_cache && !with_subselect) return cached_value; return args[0]->is_null() ? 1: 0; } @@ -3090,7 +3189,7 @@ longlong Item_is_not_null_test::val_int() { DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_is_not_null_test::val_int"); - if (!used_tables_cache) + if (!used_tables_cache && !with_subselect) { owner->was_null|= (!cached_value); DBUG_PRINT("info", ("cached: %ld", (long) cached_value)); @@ -3117,7 +3216,7 @@ void Item_is_not_null_test::update_used_tables() else { args[0]->update_used_tables(); - if (!(used_tables_cache=args[0]->used_tables())) + if (!(used_tables_cache=args[0]->used_tables()) && !with_subselect) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) !args[0]->is_null(); @@ -4086,11 +4185,9 @@ longlong Item_equal::val_int() void Item_equal::fix_length_and_dec() { - Item *item= const_item ? const_item : get_first(); + Item *item= get_first(); eval_item= cmp_item::get_comparator(item->result_type(), item->collation.collation); - if (item->result_type() == STRING_RESULT) - eval_item->cmp_charset= cmp_collation.collation; } bool Item_equal::walk(Item_processor processor, bool walk_subquery, byte *arg) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 51cf5667c95..6186d4a78f8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -35,6 +34,7 @@ class Arg_comparator: public Sql_alloc arg_cmp_func func; Item_bool_func2 *owner; Arg_comparator *comparators; // used only for compare_row() + double precision; public: DTCollation cmp_collation; @@ -81,6 +81,8 @@ public: int compare_e_int(); // compare args[0] & args[1] int compare_e_int_diff_signedness(); int compare_e_row(); // compare args[0] & args[1] + int compare_real_fixed(); + int compare_e_real_fixed(); static arg_cmp_func comparator_matrix [5][2]; @@ -272,6 +274,7 @@ public: const char *func_name() const { return "not"; } Item *neg_transformer(THD *thd); bool check_partition_func_processor(byte *int_arg) {return FALSE;} + void print(String *str); }; class Item_maxmin_subselect; @@ -314,6 +317,7 @@ public: enum Functype functype() const { return TRIG_COND_FUNC; }; const char *func_name() const { return "trigcond"; }; bool const_item() const { return FALSE; } + bool *get_trig_var() { return trig_var; } }; class Item_func_not_all :public Item_func_not @@ -814,10 +818,10 @@ public: return (value_res ? (res ? sortcmp(value_res, res, cmp_charset) : 1) : (res ? -1 : 0)); } - int compare(cmp_item *c) + int compare(cmp_item *ci) { - cmp_item_string *cmp= (cmp_item_string *)c; - return sortcmp(value_res, cmp->value_res, cmp_charset); + cmp_item_string *l_cmp= (cmp_item_string *) ci; + return sortcmp(value_res, l_cmp->value_res, cmp_charset); } cmp_item *make_same(); void set_charset(CHARSET_INFO *cs) @@ -840,10 +844,10 @@ public: { return value != arg->val_int(); } - int compare(cmp_item *c) + int compare(cmp_item *ci) { - cmp_item_int *cmp= (cmp_item_int *)c; - return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1); + cmp_item_int *l_cmp= (cmp_item_int *)ci; + return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1); } cmp_item *make_same(); }; @@ -861,10 +865,10 @@ public: { return value != arg->val_real(); } - int compare(cmp_item *c) + int compare(cmp_item *ci) { - cmp_item_real *cmp= (cmp_item_real *)c; - return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1); + cmp_item_real *l_cmp= (cmp_item_real *) ci; + return (value < l_cmp->value)? -1 : ((value == l_cmp->value) ? 0 : 1); } cmp_item *make_same(); }; @@ -930,10 +934,10 @@ public: DBUG_ASSERT(0); return 1; } - int compare(cmp_item *c) + int compare(cmp_item *ci) { - cmp_item_string *cmp= (cmp_item_string *)c; - return sortcmp(value_res, cmp->value_res, cmp_charset); + cmp_item_string *l_cmp= (cmp_item_string *) ci; + return sortcmp(value_res, l_cmp->value_res, cmp_charset); } cmp_item *make_same() { @@ -1034,6 +1038,11 @@ public: class Item_func_in :public Item_func_opt_neg { public: + Item_result cmp_type; + /* + an array of values when the right hand arguments of IN + are all SQL constant and there are no nulls + */ in_vector *array; bool have_null; Item_result left_result_type; @@ -1065,7 +1074,7 @@ public: DBUG_VOID_RETURN; } optimize_type select_optimize() const - { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; } + { return OPTIMIZE_KEY; } void print(String *str); enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } @@ -1103,7 +1112,8 @@ public: else { args[0]->update_used_tables(); - if ((const_item_cache= !(used_tables_cache= args[0]->used_tables()))) + if ((const_item_cache= !(used_tables_cache= args[0]->used_tables())) && + !with_subselect) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) args[0]->is_null(); @@ -1371,7 +1381,6 @@ class Item_equal: public Item_bool_func Item *const_item; /* optional constant item equal to fields items */ cmp_item *eval_item; bool cond_false; - DTCollation cmp_collation; public: inline Item_equal() : Item_bool_func(), const_item(0), eval_item(0), cond_false(0) @@ -1445,7 +1454,7 @@ public: Item_cond_and() :Item_cond() {} Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {} Item_cond_and(THD *thd, Item_cond_and *item) :Item_cond(thd, item) {} - Item_cond_and(List<Item> &list): Item_cond(list) {} + Item_cond_and(List<Item> &list_arg): Item_cond(list_arg) {} enum Functype functype() const { return COND_AND_FUNC; } longlong val_int(); const char *func_name() const { return "and"; } @@ -1467,7 +1476,7 @@ public: Item_cond_or() :Item_cond() {} Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {} Item_cond_or(THD *thd, Item_cond_or *item) :Item_cond(thd, item) {} - Item_cond_or(List<Item> &list): Item_cond(list) {} + Item_cond_or(List<Item> &list_arg): Item_cond(list_arg) {} enum Functype functype() const { return COND_OR_FUNC; } longlong val_int(); const char *func_name() const { return "or"; } diff --git a/sql/item_create.cc b/sql/item_create.cc index 80b5e946ae7..ff5825ef389 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -2342,9 +2341,7 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list) if (item_list != NULL) arg_count= item_list->elements; -#ifdef HAVE_ROW_BASED_REPLICATION thd->lex->binlog_row_based_if_mixed= TRUE; -#endif DBUG_ASSERT( (udf->type == UDFTYPE_FUNCTION) || (udf->type == UDFTYPE_AGGREGATE)); @@ -4533,9 +4530,7 @@ Create_func_uuid Create_func_uuid::s_singleton; Item* Create_func_uuid::create(THD *thd) { -#ifdef HAVE_ROW_BASED_REPLICATION thd->lex->binlog_row_based_if_mixed= TRUE; -#endif return new (thd->mem_root) Item_func_uuid(); } diff --git a/sql/item_create.h b/sql/item_create.h index c20e36af04f..985c4428d8f 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/item_func.cc b/sql/item_func.cc index 3141af3a8b3..8f3ffd00e34 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -234,6 +233,8 @@ void Item_func::traverse_cond(Cond_traverser traverser, (*traverser)(this, argument); } } + else + (*traverser)(this, argument); } @@ -999,7 +1000,7 @@ String *Item_decimal_typecast::val_str(String *str) my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); if (null_value) return NULL; - my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str); + my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str); return str; } @@ -2044,6 +2045,18 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) } +void Item_func_rand::seed_random(Item *arg) +{ + /* + TODO: do not do reinit 'rand' for every execute of PS/SP if + args[0] is a constant. + */ + uint32 tmp= (uint32) arg->val_int(); + randominit(rand, (uint32) (tmp*0x10001L+55555555L), + (uint32) (tmp*0x10000001L)); +} + + bool Item_func_rand::fix_fields(THD *thd,Item **ref) { if (Item_real_func::fix_fields(thd, ref)) @@ -2051,11 +2064,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) used_tables_cache|= RAND_TABLE_BIT; if (arg_count) { // Only use argument once in query - if (!args[0]->const_during_execution()) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND"); - return TRUE; - } /* Allocate rand structure once: we must use thd->stmt_arena to create rand in proper mem_root if it's a prepared statement or @@ -2067,20 +2075,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) if (!rand && !(rand= (struct rand_struct*) thd->stmt_arena->alloc(sizeof(*rand)))) return TRUE; - /* - PARAM_ITEM is returned if we're in statement prepare and consequently - no placeholder value is set yet. - */ - if (args[0]->type() != PARAM_ITEM) - { - /* - TODO: do not do reinit 'rand' for every execute of PS/SP if - args[0] is a constant. - */ - uint32 tmp= (uint32) args[0]->val_int(); - randominit(rand, (uint32) (tmp*0x10001L+55555555L), - (uint32) (tmp*0x10000001L)); - } + + if (args[0]->const_item()) + seed_random (args[0]); } else { @@ -2110,6 +2107,8 @@ void Item_func_rand::update_used_tables() double Item_func_rand::val_real() { DBUG_ASSERT(fixed == 1); + if (arg_count && !args[0]->const_item()) + seed_random (args[0]); return my_rnd(rand); } @@ -2379,7 +2378,7 @@ longlong Item_func_locate::val_int() b->ptr(), b->length(), &match, 1)) return 0; - return (longlong) match.mblen + start0 + 1; + return (longlong) match.mb_len + start0 + 1; } @@ -2514,7 +2513,7 @@ void Item_func_find_in_set::fix_length_and_dec() if (args[0]->const_item() && args[1]->type() == FIELD_ITEM) { Field *field= ((Item_field*) args[1])->field; - if (field->real_type() == FIELD_TYPE_SET) + if (field->real_type() == MYSQL_TYPE_SET) { String *find=args[0]->val_str(&value); if (find) @@ -2748,25 +2747,28 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, if (arguments[i]->const_item()) { - if (arguments[i]->null_value) - continue; - switch (arguments[i]->result_type()) { case STRING_RESULT: case DECIMAL_RESULT: { String *res= arguments[i]->val_str(&buffers[i]); + if (arguments[i]->null_value) + continue; f_args.args[i]= (char*) res->ptr(); break; } case INT_RESULT: *((longlong*) to)= arguments[i]->val_int(); + if (arguments[i]->null_value) + continue; f_args.args[i]= to; to+= ALIGN_SIZE(sizeof(longlong)); break; case REAL_RESULT: *((double*) to)= arguments[i]->val_real(); + if (arguments[i]->null_value) + continue; f_args.args[i]= to; to+= ALIGN_SIZE(sizeof(double)); break; @@ -3086,8 +3088,8 @@ public: int count; bool locked; pthread_cond_t cond; - pthread_t thread; - ulong thread_id; + my_thread_id thread_id; + void set_thread(THD *thd) { thread_id= thd->thread_id; } User_level_lock(const char *key_arg,uint length, ulong id) :key_length(length),count(1),locked(1), thread_id(id) @@ -3174,9 +3176,9 @@ longlong Item_master_pos_wait::val_int() null_value = 1; return 0; } +#ifdef HAVE_REPLICATION longlong pos = (ulong)args[1]->val_int(); longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ; -#ifdef HAVE_REPLICATION if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) { null_value = 1; @@ -3240,7 +3242,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) else { ull->locked=1; - ull->thread=thd->real_id; + ull->set_thread(thd); thd->ull=ull; } pthread_mutex_unlock(&LOCK_user_locks); @@ -3315,7 +3317,7 @@ longlong Item_func_get_lock::val_int() null_value=1; // Probably out of memory return 0; } - ull->thread=thd->real_id; + ull->set_thread(thd); thd->ull=ull; pthread_mutex_unlock(&LOCK_user_locks); return 1; // Got new lock @@ -3356,7 +3358,7 @@ longlong Item_func_get_lock::val_int() else // We got the lock { ull->locked=1; - ull->thread=thd->real_id; + ull->set_thread(thd); ull->thread_id= thd->thread_id; thd->ull=ull; error=0; @@ -3404,7 +3406,7 @@ longlong Item_func_release_lock::val_int() } else { - if (ull->locked && pthread_equal(pthread_self(),ull->thread)) + if (ull->locked && current_thd->thread_id == ull->thread_id) { result=1; // Release is ok item_user_lock_release(ull); @@ -3449,7 +3451,7 @@ longlong Item_func_benchmark::val_int() THD *thd=current_thd; ulong loop_count; - loop_count= args[0]->val_int(); + loop_count= (ulong) args[0]->val_int(); if (args[0]->null_value) { @@ -3684,8 +3686,9 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); if (entry->value == pos) entry->value=0; - if (!(entry->value=(char*) my_realloc(entry->value, length, - MYF(MY_ALLOW_ZERO_PTR)))) + entry->value= (char*) my_realloc(entry->value, length, + MYF(MY_ALLOW_ZERO_PTR | MY_WME)); + if (!entry->value) return 1; } } @@ -3707,7 +3710,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, bool -Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, +Item_func_set_user_var::update_hash(void *ptr, uint length, + Item_result res_type, CHARSET_INFO *cs, Derivation dv, bool unsigned_arg) { @@ -3716,9 +3720,9 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, result type of the variable */ if ((null_value= args[0]->null_value) && null_item) - type= entry->type; // Don't change type of item + res_type= entry->type; // Don't change type of item if (::update_hash(entry, (null_value= args[0]->null_value), - ptr, length, type, cs, dv, unsigned_arg)) + ptr, length, res_type, cs, dv, unsigned_arg)) { current_thd->fatal_error(); // Probably end of memory null_value= 1; @@ -4051,6 +4055,105 @@ void Item_func_set_user_var::make_field(Send_field *tmp_field) Item::make_field(tmp_field); } + +/* + Save the value of a user variable into a field + + SYNOPSIS + save_in_field() + field target field to save the value to + no_conversion flag indicating whether conversions are allowed + + DESCRIPTION + Save the function value into a field and update the user variable + accordingly. If a result field is defined and the target field doesn't + coincide with it then the value from the result field will be used as + the new value of the user variable. + + The reason to have this method rather than simply using the result + field in the val_xxx() methods is that the value from the result field + not always can be used when the result field is defined. + Let's consider the following cases: + 1) when filling a tmp table the result field is defined but the value of it + is undefined because it has to be produced yet. Thus we can't use it. + 2) on execution of an INSERT ... SELECT statement the save_in_field() + function will be called to fill the data in the new record. If the SELECT + part uses a tmp table then the result field is defined and should be + used in order to get the correct result. + + The difference between the SET_USER_VAR function and regular functions + like CONCAT is that the Item_func objects for the regular functions are + replaced by Item_field objects after the values of these functions have + been stored in a tmp table. Yet an object of the Item_field class cannot + be used to update a user variable. + Due to this we have to handle the result field in a special way here and + in the Item_func_set_user_var::send() function. + + RETURN VALUES + FALSE Ok + TRUE Error +*/ + +int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions) +{ + bool use_result_field= (result_field && result_field != field); + int error; + + /* Update the value of the user variable */ + check(use_result_field); + update(); + + if (result_type() == STRING_RESULT || + result_type() == REAL_RESULT && + field->result_type() == STRING_RESULT) + { + String *result; + CHARSET_INFO *cs= collation.collation; + char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns + str_value.set_quick(buff, sizeof(buff), cs); + result= entry->val_str(&null_value, &str_value, decimals); + + if (null_value) + { + str_value.set_quick(0, 0, cs); + return set_field_to_null_with_conversions(field, no_conversions); + } + + /* NOTE: If null_value == FALSE, "result" must be not NULL. */ + + field->set_notnull(); + error=field->store(result->ptr(),result->length(),cs); + str_value.set_quick(0, 0, cs); + } + else if (result_type() == REAL_RESULT) + { + double nr= entry->val_real(&null_value); + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + error=field->store(nr); + } + else if (result_type() == DECIMAL_RESULT) + { + my_decimal decimal_value; + my_decimal *value= entry->val_decimal(&null_value, &decimal_value); + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + error=field->store_decimal(value); + } + else + { + longlong nr= entry->val_int(&null_value); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + error=field->store(nr, unsigned_flag); + } + return error; +} + + String * Item_func_get_user_var::val_str(String *str) { @@ -4757,7 +4860,7 @@ longlong Item_func_bit_xor::val_int() thd Thread handler var_type global / session name Name of base or system variable - component Component. + component Component NOTES If component.str = 0 then the variable name is in 'name' @@ -4869,8 +4972,9 @@ longlong Item_func_row_count::val_int() } -Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name) - :Item_func(), context(context_arg), m_name(name), m_sp(NULL), +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, + sp_name *name_arg) + :Item_func(), context(context_arg), m_name(name_arg), m_sp(NULL), result_field(NULL) { maybe_null= 1; @@ -4881,8 +4985,8 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name) Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, - sp_name *name, List<Item> &list) - :Item_func(list), context(context_arg), m_name(name), m_sp(NULL), + sp_name *name_arg, List<Item> &list) + :Item_func(list), context(context_arg), m_name(name_arg), m_sp(NULL), result_field(NULL) { maybe_null= 1; diff --git a/sql/item_func.h b/sql/item_func.h index 4b0da6d5a58..29dd524d849 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -680,6 +679,8 @@ public: bool const_item() const { return 0; } void update_used_tables(); bool fix_fields(THD *thd, Item **ref); +private: + void seed_random (Item * val); }; @@ -1215,6 +1216,7 @@ public: void print(String *str); void print_as_stmt(String *str); const char *func_name() const { return "set_user_var"; } + int save_in_field(Field *field, bool no_conversions); }; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index ef71dc9b8b5..35a9f026b1d 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2003-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -702,8 +701,9 @@ double Item_func_glength::val_real() null_value= (!swkb || !(geom= Geometry::construct(&buffer, - swkb->ptr(), swkb->length())) || - geom->length(&res)); + swkb->ptr(), + swkb->length())) || + geom->geom_length(&res)); return res; } diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 42f11820869..5361a02aa83 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/item_row.cc b/sql/item_row.cc index 6e71ae0d4db..956556ca783 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/item_row.h b/sql/item_row.h index 39913086e8d..d55d3ae223f 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -72,7 +71,7 @@ public: Item *transform(Item_transformer transformer, byte *arg); uint cols() { return arg_count; } - Item* el(uint i) { return items[i]; } + Item* element_index(uint i) { return items[i]; } Item** addr(uint i) { return items + i; } bool check_cols(uint c); bool null_inside() { return with_null; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e8c87893471..acc522b1b46 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,9 +25,6 @@ #include "mysql_priv.h" #include <m_ctype.h> -#ifdef HAVE_OPENSSL -#include <openssl/des.h> -#endif /* HAVE_OPENSSL */ #include "md5.h" #include "sha1.h" #include "my_aes.h" @@ -38,15 +34,6 @@ C_MODE_END String my_empty_string("",default_charset_info); -static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), - c1.collation->name, c1.derivation_name(), - c2.collation->name, c2.derivation_name(), - fname); -} - String *Item_str_func::check_well_formed_result(String *str) { @@ -1166,7 +1153,8 @@ String *Item_func_substr::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ /* Assumes that the maximum length of a String is < INT_MAX32. */ - if ((args[1]->unsigned_flag) || (start < INT_MIN32) || (start > INT_MAX32)) + if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || + (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32))) return &my_empty_string; start= ((start < 0) ? res->numchars() + start : start - 1); @@ -1811,8 +1799,13 @@ bool Item_func_current_user::fix_fields(THD *thd, Item **ref) if (Item_func_sysconst::fix_fields(thd, ref)) return TRUE; - Security_context *ctx= (context->security_ctx + Security_context *ctx= +#ifndef NO_EMBEDDED_ACCESS_CHECKS + (context->security_ctx ? context->security_ctx : thd->security_ctx); +#else + thd->security_ctx; +#endif /*NO_EMBEDDED_ACCESS_CHECKS*/ return init(ctx->priv_user, ctx->priv_host); } @@ -1930,7 +1923,7 @@ String *Item_func_format::val_str(String *str) int diff; DBUG_ASSERT(fixed == 1); - dec= args[1]->val_int(); + dec= (int) args[1]->val_int(); if (args[1]->null_value) { null_value=1; @@ -2272,25 +2265,23 @@ String *Item_func_repeat::val_str(String *str) uint length,tot_length; char *to; /* must be longlong to avoid truncation */ - longlong tmp_count= args[1]->val_int(); - long count= (long) tmp_count; + longlong count= args[1]->val_int(); String *res= args[0]->val_str(str); - /* Assumes that the maximum length of a String is < INT_MAX32. */ - /* Bounds check on count: If this is triggered, we will error. */ - if ((tmp_count > INT_MAX32) || args[1]->unsigned_flag) - count= INT_MAX32; - if (args[0]->null_value || args[1]->null_value) goto err; // string and/or delim are null null_value= 0; - if ((tmp_count <= 0) && !args[1]->unsigned_flag) // For nicer SQL code + if ((count <= 0) && !args[1]->unsigned_flag) // For nicer SQL code return &my_empty_string; + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Bounds check on count: If this is triggered, we will error. */ + if ((ulonglong) count > INT_MAX32) + count= INT_MAX32; if (count == 1) // To avoid reallocs return res; length=res->length(); // Safe length check - if (length > current_thd->variables.max_allowed_packet/count) + if (length > current_thd->variables.max_allowed_packet / (uint) count) { push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_ALLOWED_PACKET_OVERFLOWED, @@ -2364,15 +2355,14 @@ String *Item_func_rpad::val_str(String *str) String *res= args[0]->val_str(str); String *rpad= args[2]->val_str(&rpad_str); + if (!res || args[1]->null_value || !rpad || + ((count < 0) && !args[1]->unsigned_flag)) + goto err; + null_value=0; /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ - if ((count > INT_MAX32) || args[1]->unsigned_flag) + if ((ulonglong) count > INT_MAX32) count= INT_MAX32; - - if (!res || args[1]->null_value || !rpad || count < 0) - goto err; - null_value=0; - if (count <= (res_char_length= res->numchars())) { // String to pad is big enough res->length(res->charpos((int) count)); // Shorten result if longer @@ -2466,14 +2456,15 @@ String *Item_func_lpad::val_str(String *str) String *res= args[0]->val_str(&tmp_value); String *pad= args[2]->val_str(&lpad_str); + if (!res || args[1]->null_value || !pad || + ((count < 0) && !args[1]->unsigned_flag)) + goto err; + null_value=0; /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ - if ((count > INT_MAX32) || args[1]->unsigned_flag) + if ((ulonglong) count > INT_MAX32) count= INT_MAX32; - if (!res || args[1]->null_value || !pad || count < 0) - goto err; - null_value=0; res_char_length= res->numchars(); if (count <= res_char_length) @@ -3270,15 +3261,17 @@ String *Item_func_uuid::val_str(String *str) int i; if (my_gethwaddr(mac)) { + /* purecov: begin inspected */ /* generating random "hardware addr" and because specs explicitly specify that it should NOT correlate with a clock_seq value (initialized random below), we use a separate randominit() here */ - randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)query_id); + randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)global_query_id); for (i=0; i < (int)sizeof(mac); i++) mac[i]=(uchar)(my_rnd(&uuid_rand)*255); + /* purecov: end */ } s=clock_seq_and_node_str+sizeof(clock_seq_and_node_str)-1; for (i=sizeof(mac)-1 ; i>=0 ; i--) @@ -3286,7 +3279,7 @@ String *Item_func_uuid::val_str(String *str) *--s=_dig_vec_lower[mac[i] & 15]; *--s=_dig_vec_lower[mac[i] >> 4]; } - randominit(&uuid_rand, tmp + (ulong)start_time, + randominit(&uuid_rand, tmp + (ulong) server_start_time, tmp + thd->status_var.bytes_sent); set_clock_seq_str(); } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 3b171b5d50f..ae11e001551 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index da491b91143..de67a314631 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -235,16 +234,20 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, } -bool Item_subselect::exec(bool full_scan) +bool Item_subselect::exec() { int res; - res= engine->exec(full_scan); + if (thd->net.report_error) + /* Do not execute subselect in case of a fatal error */ + return 1; + + res= engine->exec(); if (engine_changed) { engine_changed= 0; - return exec(full_scan); + return exec(); } return (res); } @@ -272,11 +275,11 @@ bool Item_subselect::const_item() const return const_item_cache; } -Item *Item_subselect::get_tmp_table_item(THD *thd) +Item *Item_subselect::get_tmp_table_item(THD *thd_arg) { if (!with_sum_func && !const_item()) return new Item_field(result_field); - return copy_or_same(thd); + return copy_or_same(thd_arg); } void Item_subselect::update_used_tables() @@ -392,6 +395,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) */ !(select_lex->item_list.head()->type() == FIELD_ITEM || select_lex->item_list.head()->type() == REF_ITEM) && + !join->conds && !join->having && /* switch off this optimization for prepare statement, because we do not rollback this changes @@ -416,8 +420,6 @@ Item_singlerow_subselect::select_transformer(JOIN *join) */ substitution->walk(&Item::remove_dependence_processor, 0, (byte *) select_lex->outer_select()); - /* SELECT without FROM clause can't have WHERE or HAVING clause */ - DBUG_ASSERT(join->conds == 0 && join->having == 0); return RES_REDUCE; } return RES_OK; @@ -493,13 +495,13 @@ bool Item_singlerow_subselect::null_inside() void Item_singlerow_subselect::bring_value() { - exec(FALSE); + exec(); } double Item_singlerow_subselect::val_real() { DBUG_ASSERT(fixed == 1); - if (!exec(FALSE) && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_real(); @@ -514,7 +516,7 @@ double Item_singlerow_subselect::val_real() longlong Item_singlerow_subselect::val_int() { DBUG_ASSERT(fixed == 1); - if (!exec(FALSE) && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_int(); @@ -528,7 +530,7 @@ longlong Item_singlerow_subselect::val_int() String *Item_singlerow_subselect::val_str(String *str) { - if (!exec(FALSE) && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_str(str); @@ -543,7 +545,7 @@ String *Item_singlerow_subselect::val_str(String *str) my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value) { - if (!exec(FALSE) && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_decimal(decimal_value); @@ -558,7 +560,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value) bool Item_singlerow_subselect::val_bool() { - if (!exec(FALSE) && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_bool(); @@ -592,13 +594,13 @@ void Item_exists_subselect::print(String *str) } -bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) +bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit_arg) { - if (unit->fake_select_lex && - unit->fake_select_lex->test_limit()) + if (unit_arg->fake_select_lex && + unit_arg->fake_select_lex->test_limit()) return(1); - SELECT_LEX *sl= unit->first_select(); + SELECT_LEX *sl= unit_arg->first_select(); for (; sl; sl= sl->next_select()) { if (sl->test_limit()) @@ -610,7 +612,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) Item_in_subselect::Item_in_subselect(Item * left_exp, st_select_lex *select_lex): Item_exists_subselect(), optimizer(0), transformed(0), - enable_pushed_conds(TRUE), upper_item(0) + pushed_cond_guards(NULL), upper_item(0) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; @@ -655,7 +657,7 @@ void Item_exists_subselect::fix_length_and_dec() double Item_exists_subselect::val_real() { DBUG_ASSERT(fixed == 1); - if (exec(FALSE)) + if (exec()) { reset(); return 0; @@ -666,7 +668,7 @@ double Item_exists_subselect::val_real() longlong Item_exists_subselect::val_int() { DBUG_ASSERT(fixed == 1); - if (exec(FALSE)) + if (exec()) { reset(); return 0; @@ -677,7 +679,7 @@ longlong Item_exists_subselect::val_int() String *Item_exists_subselect::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (exec(FALSE)) + if (exec()) { reset(); return 0; @@ -690,7 +692,7 @@ String *Item_exists_subselect::val_str(String *str) my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); - if (exec(FALSE)) + if (exec()) { reset(); return 0; @@ -703,7 +705,7 @@ my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value) bool Item_exists_subselect::val_bool() { DBUG_ASSERT(fixed == 1); - if (exec(FALSE)) + if (exec()) { reset(); return 0; @@ -721,7 +723,7 @@ double Item_in_subselect::val_real() DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); null_value= 0; - if (exec(!enable_pushed_conds)) + if (exec()) { reset(); null_value= 1; @@ -742,7 +744,7 @@ longlong Item_in_subselect::val_int() DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); null_value= 0; - if (exec(!enable_pushed_conds)) + if (exec()) { reset(); null_value= 1; @@ -763,7 +765,7 @@ String *Item_in_subselect::val_str(String *str) DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); null_value= 0; - if (exec(!enable_pushed_conds)) + if (exec()) { reset(); null_value= 1; @@ -783,7 +785,7 @@ bool Item_in_subselect::val_bool() { DBUG_ASSERT(fixed == 1); null_value= 0; - if (exec(!enable_pushed_conds)) + if (exec()) { reset(); null_value= 1; @@ -803,7 +805,7 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) DBUG_ASSERT(0); null_value= 0; DBUG_ASSERT(fixed == 1); - if (exec(!enable_pushed_conds)) + if (exec()) { reset(); null_value= 1; @@ -870,7 +872,6 @@ Item_subselect::trans_res Item_in_subselect::single_value_transformer(JOIN *join, Comp_creator *func) { - Item_subselect::trans_res result= RES_ERROR; SELECT_LEX *select_lex= join->select_lex; DBUG_ENTER("Item_in_subselect::single_value_transformer"); @@ -967,8 +968,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (!substitution) { - //first call for this unit - SELECT_LEX_UNIT *unit= select_lex->master_unit(); + /* We're invoked for the 1st (or the only) SELECT in the subquery UNION */ + SELECT_LEX_UNIT *master_unit= select_lex->master_unit(); substitution= optimizer; SELECT_LEX *current= thd->lex->current_select, *up; @@ -991,21 +992,16 @@ Item_in_subselect::single_value_transformer(JOIN *join, (char *)"<no matter>", (char *)in_left_expr_name); - unit->uncacheable|= UNCACHEABLE_DEPENDENT; + master_unit->uncacheable|= UNCACHEABLE_DEPENDENT; + } + if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards) + { + if (!(pushed_cond_guards= (bool*)join->thd->alloc(sizeof(bool)))) + DBUG_RETURN(RES_ERROR); + pushed_cond_guards[0]= TRUE; } select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; - /* - Add the left part of a subselect to a WHERE or HAVING clause of - the right part, e.g. - - SELECT 1 IN (SELECT a FROM t1) => - - SELECT Item_in_optimizer(1, SELECT a FROM t1 WHERE a=1) - - HAVING is used only if the right part contains a SUM function, a GROUP - BY or a HAVING clause. - */ if (join->having || select_lex->with_sum_func || select_lex->group_list.elements) { @@ -1017,13 +1013,13 @@ Item_in_subselect::single_value_transformer(JOIN *join, ref_pointer_array, (char *)"<ref>", this->full_name())); - if (!abort_on_null && ((Item*)select_lex->item_list.head())->maybe_null) + if (!abort_on_null && left_expr->maybe_null) { /* We can encounter "NULL IN (SELECT ...)". Wrap the added condition - within a trigger. + within a trig_cond. */ - item= new Item_func_trig_cond(item, &enable_pushed_conds); + item= new Item_func_trig_cond(item, get_cond_guard(0)); } /* @@ -1032,6 +1028,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, argument (reference) to fix_fields() */ select_lex->having= join->having= and_items(join->having, item); + if (join->having == item) + item->name= (char*)in_having_cond; select_lex->having_fix_field= 1; /* we do not check join->having->fixed, because Item_and (from and_items) @@ -1058,14 +1056,19 @@ Item_in_subselect::single_value_transformer(JOIN *join, item= func->create(expr, item); if (!abort_on_null && orig_item->maybe_null) { - having= - new Item_func_trig_cond(new Item_is_not_null_test(this, having), - &enable_pushed_conds); + having= new Item_is_not_null_test(this, having); + if (left_expr->maybe_null) + { + if (!(having= new Item_func_trig_cond(having, + get_cond_guard(0)))) + DBUG_RETURN(RES_ERROR); + } /* Item_is_not_null_test can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() */ + having->name= (char*)in_having_cond; select_lex->having= join->having= having; select_lex->having_fix_field= 1; /* @@ -1077,17 +1080,25 @@ Item_in_subselect::single_value_transformer(JOIN *join, select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); - /* - NOTE: It is important that we add this "IS NULL" here, even when - orig_item can't be NULL. This is needed so that this predicate is - only used by ref[_or_null] analyzer (and, e.g. is not used by const - propagation). - */ item= new Item_cond_or(item, new Item_func_isnull(orig_item)); - item= new Item_func_trig_cond(item, &enable_pushed_conds); } + /* + If we may encounter NULL IN (SELECT ...) and care whether subquery + result is NULL or FALSE, wrap condition in a trig_cond. + */ + if (!abort_on_null && left_expr->maybe_null) + { + if (!(item= new Item_func_trig_cond(item, get_cond_guard(0)))) + DBUG_RETURN(RES_ERROR); + } + /* + TODO: figure out why the following is done here in + single_value_transformer but there is no corresponding action in + row_value_transformer? + */ item->name= (char *)in_additional_cond; + /* AND can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last @@ -1118,10 +1129,16 @@ Item_in_subselect::single_value_transformer(JOIN *join, select_lex->ref_pointer_array, (char *)"<no matter>", (char *)"<result>")); - new_having= new Item_func_trig_cond(new_having, &enable_pushed_conds); + if (!abort_on_null && left_expr->maybe_null) + { + if (!(new_having= new Item_func_trig_cond(new_having, + get_cond_guard(0)))) + DBUG_RETURN(RES_ERROR); + } + new_having->name= (char*)in_having_cond; select_lex->having= join->having= new_having; - select_lex->having_fix_field= 1; + /* we do not check join->having->fixed, because comparison function (from func->create) can't be fixed after creation @@ -1174,7 +1191,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) if (!substitution) { //first call for this unit - SELECT_LEX_UNIT *unit= select_lex->master_unit(); + SELECT_LEX_UNIT *master_unit= select_lex->master_unit(); substitution= optimizer; SELECT_LEX *current= thd->lex->current_select, *up; @@ -1190,7 +1207,16 @@ Item_in_subselect::row_value_transformer(JOIN *join) optimizer->keep_top_level_cache(); thd->lex->current_select= current; - unit->uncacheable|= UNCACHEABLE_DEPENDENT; + master_unit->uncacheable|= UNCACHEABLE_DEPENDENT; + + if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards) + { + if (!(pushed_cond_guards= (bool*)join->thd->alloc(sizeof(bool) * + left_expr->cols()))) + DBUG_RETURN(RES_ERROR); + for (uint i= 0; i < cols_num; i++) + pushed_cond_guards[i]= TRUE; + } } select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; @@ -1207,13 +1233,14 @@ Item_in_subselect::row_value_transformer(JOIN *join) is_not_null_test(v3)) where is_not_null_test used to register nulls in case if we have not found matching to return correct NULL value + TODO: say here explicitly if the order of AND parts matters or not. */ Item *item_having_part2= 0; for (uint i= 0; i < cols_num; i++) { DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); if (select_lex->ref_pointer_array[i]-> - check_cols(left_expr->el(i)->cols())) + check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); Item *item_eq= new Item_func_eq(new @@ -1235,21 +1262,28 @@ Item_in_subselect::row_value_transformer(JOIN *join) (char *)"<no matter>", (char *)"<list ref>") ); - having_item= - and_items(having_item, - new Item_cond_or(item_eq, item_isnull)); - item_having_part2= - and_items(item_having_part2, - new - Item_is_not_null_test(this, - new - Item_ref(&select_lex->context, - select_lex-> - ref_pointer_array + i, - (char *)"<no matter>", - (char *)"<list ref>") - ) - ); + Item *col_item= new Item_cond_or(item_eq, item_isnull); + if (!abort_on_null && left_expr->element_index(i)->maybe_null) + { + if (!(col_item= new Item_func_trig_cond(col_item, get_cond_guard(i)))) + DBUG_RETURN(RES_ERROR); + } + having_item= and_items(having_item, col_item); + + Item *item_nnull_test= + new Item_is_not_null_test(this, + new Item_ref(&select_lex->context, + select_lex-> + ref_pointer_array + i, + (char *)"<no matter>", + (char *)"<list ref>")); + if (!abort_on_null && left_expr->element_index(i)->maybe_null) + { + if (!(item_nnull_test= + new Item_func_trig_cond(item_nnull_test, get_cond_guard(i)))) + DBUG_RETURN(RES_ERROR); + } + item_having_part2= and_items(item_having_part2, item_nnull_test); item_having_part2->top_level_item(); } having_item= and_items(having_item, item_having_part2); @@ -1280,7 +1314,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) Item *item, *item_isnull; DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); if (select_lex->ref_pointer_array[i]-> - check_cols(left_expr->el(i)->cols())) + check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); item= new Item_func_eq(new @@ -1298,18 +1332,15 @@ Item_in_subselect::row_value_transformer(JOIN *join) ); if (!abort_on_null) { - having_item= - and_items(having_item, - new - Item_is_not_null_test(this, - new - Item_ref(&select_lex->context, - select_lex-> - ref_pointer_array + i, - (char *)"<no matter>", - (char *)"<list ref>") - ) - ); + Item *having_col_item= + new Item_is_not_null_test(this, + new + Item_ref(&select_lex->context, + select_lex->ref_pointer_array + i, + (char *)"<no matter>", + (char *)"<list ref>")); + + item_isnull= new Item_func_isnull(new Item_direct_ref(&select_lex->context, @@ -1318,14 +1349,23 @@ Item_in_subselect::row_value_transformer(JOIN *join) (char *)"<no matter>", (char *)"<list ref>") ); - item= new Item_cond_or(item, item_isnull); + /* + TODO: why we create the above for cases where the right part + cant be NULL? + */ + if (left_expr->element_index(i)->maybe_null) + { + if (!(item= new Item_func_trig_cond(item, get_cond_guard(i)))) + DBUG_RETURN(RES_ERROR); + if (!(having_col_item= + new Item_func_trig_cond(having_col_item, get_cond_guard(i)))) + DBUG_RETURN(RES_ERROR); + } + having_item= and_items(having_item, having_col_item); } - where_item= and_items(where_item, item); } - if (where_item) - where_item= new Item_func_trig_cond(where_item, &enable_pushed_conds); /* AND can't be changed during fix_fields() we can assign select_lex->where here, and pass 0 as last @@ -1339,9 +1379,9 @@ Item_in_subselect::row_value_transformer(JOIN *join) if (having_item) { bool res; - having_item= new Item_func_trig_cond(having_item, &enable_pushed_conds); - select_lex->having= join->having= and_items(join->having, having_item); + if (having_item == select_lex->having) + having_item->name= (char*)in_having_cond; select_lex->having->top_level_item(); /* AND can't be changed during fix_fields() @@ -1476,14 +1516,14 @@ void Item_in_subselect::print(String *str) } -bool Item_in_subselect::fix_fields(THD *thd, Item **ref) +bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { bool result = 0; - if(thd->lex->view_prepare_mode && left_expr && !left_expr->fixed) - result = left_expr->fix_fields(thd, &left_expr); + if (thd_arg->lex->view_prepare_mode && left_expr && !left_expr->fixed) + result = left_expr->fix_fields(thd_arg, &left_expr); - return result || Item_subselect::fix_fields(thd, ref); + return result || Item_subselect::fix_fields(thd_arg, ref); } @@ -1522,13 +1562,13 @@ void subselect_engine::set_thd(THD *thd_arg) subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, - select_subselect *result, - Item_subselect *item) - :subselect_engine(item, result), + select_subselect *result_arg, + Item_subselect *item_arg) + :subselect_engine(item_arg, result_arg), prepared(0), optimized(0), executed(0), select_lex(select), join(0) { - select_lex->master_unit()->item= item; + select_lex->master_unit()->item= item_arg; } @@ -1674,7 +1714,7 @@ void subselect_engine::set_row(List<Item> &item_list, Item_cache **row) Item *sel_item; List_iterator_fast<Item> li(item_list); res_type= STRING_RESULT; - res_field_type= FIELD_TYPE_VAR_STRING; + res_field_type= MYSQL_TYPE_VAR_STRING; for (uint i= 0; (sel_item= li++); i++) { item->max_length= sel_item->max_length; @@ -1727,7 +1767,7 @@ int init_read_record_seq(JOIN_TAB *tab); int join_read_always_key_or_null(JOIN_TAB *tab); int join_read_next_same_or_null(READ_RECORD *info); -int subselect_single_select_engine::exec(bool full_scan) +int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); char const *save_where= thd->where; @@ -1765,9 +1805,12 @@ int subselect_single_select_engine::exec(bool full_scan) if (!executed) { item->reset_value_registration(); - if (full_scan) + JOIN_TAB *changed_tabs[MAX_TABLES]; + JOIN_TAB **last_changed_tab= changed_tabs; + if (item->have_guarded_conds()) { /* + For at least one of the pushed predicates the following is true: We should not apply optimizations based on the condition that was pushed down into the subquery. Those optimizations are ref[_or_null] acceses. Change them to be full table scans. @@ -1775,32 +1818,36 @@ int subselect_single_select_engine::exec(bool full_scan) for (uint i=join->const_tables ; i < join->tables ; i++) { JOIN_TAB *tab=join->join_tab+i; - if (tab->keyuse && tab->keyuse->outer_ref) + if (tab && tab->keyuse) { - tab->read_first_record= init_read_record_seq; - tab->read_record.record= tab->table->record[0]; - tab->read_record.thd= join->thd; - tab->read_record.ref_length= tab->table->file->ref_length; + for (uint i= 0; i < tab->ref.key_parts; i++) + { + bool *cond_guard= tab->ref.cond_guards[i]; + if (cond_guard && !*cond_guard) + { + /* Change the access method to full table scan */ + tab->read_first_record= init_read_record_seq; + tab->read_record.record= tab->table->record[0]; + tab->read_record.thd= join->thd; + tab->read_record.ref_length= tab->table->file->ref_length; + *(last_changed_tab++)= tab; + break; + } + } } } } join->exec(); - if (full_scan) + /* Enable the optimizations back */ + for (JOIN_TAB **ptab= changed_tabs; ptab != last_changed_tab; ptab++) { - /* Enable the optimizations back */ - for (uint i=join->const_tables ; i < join->tables ; i++) - { - JOIN_TAB *tab=join->join_tab+i; - if (tab->keyuse && tab->keyuse->outer_ref) - { - tab->read_record.record= 0; - tab->read_record.ref_length= 0; - tab->read_first_record= join_read_always_key_or_null; - tab->read_record.read_record= join_read_next_same_or_null; - } - } + JOIN_TAB *tab= *ptab; + tab->read_record.record= 0; + tab->read_record.ref_length= 0; + tab->read_first_record= join_read_always_key_or_null; + tab->read_record.read_record= join_read_next_same_or_null; } executed= 1; thd->where= save_where; @@ -1812,13 +1859,9 @@ int subselect_single_select_engine::exec(bool full_scan) DBUG_RETURN(0); } -int subselect_union_engine::exec(bool full_scan) +int subselect_union_engine::exec() { char const *save_where= thd->where; - /* - Ignore the full_scan parameter: the pushed down predicates are only used - for filtering, and the caller has disabled them if necessary. - */ int res= unit->exec(); thd->where= save_where; return res; @@ -1826,7 +1869,7 @@ int subselect_union_engine::exec(bool full_scan) /* - Search for at least on row satisfying select condition + Search for at least one row satisfying select condition SYNOPSIS subselect_uniquesubquery_engine::scan_table() @@ -1835,8 +1878,8 @@ int subselect_union_engine::exec(bool full_scan) Scan the table using sequential access until we find at least one row satisfying select condition. - The result of this function (info about whether a row was found) is - stored in this->empty_result_set. + The caller must set this->empty_result_set=FALSE before calling this + function. This function will set it to TRUE if it finds a matching row. RETURN FALSE - OK @@ -1848,7 +1891,6 @@ int subselect_uniquesubquery_engine::scan_table() int error; TABLE *table= tab->table; DBUG_ENTER("subselect_uniquesubquery_engine::scan_table"); - empty_result_set= TRUE; if (table->file->inited) table->file->ha_index_end(); @@ -1941,10 +1983,13 @@ bool subselect_uniquesubquery_engine::copy_ref_key() - FALSE otherwise. In some cases (IN subselect is a top level item, i.e. abort_on_null==TRUE) - the caller doesn't distinguish between NULL and FALSE result and we just + the caller doesn't distinguish between NULL and FALSE result and we just return FALSE. - Otherwise we make a full table scan to see if there is at least one matching row. - + Otherwise we make a full table scan to see if there is at least one + matching row. + + The result of this function (info about whether a row was found) is + stored in this->empty_result_set. NOTE RETURN @@ -1952,11 +1997,12 @@ bool subselect_uniquesubquery_engine::copy_ref_key() TRUE - an error occured while scanning */ -int subselect_uniquesubquery_engine::exec(bool full_scan) +int subselect_uniquesubquery_engine::exec() { DBUG_ENTER("subselect_uniquesubquery_engine::exec"); int error; TABLE *table= tab->table; + empty_result_set= TRUE; /* TODO: change to use of 'full_scan' here? */ if (copy_ref_key()) @@ -1977,9 +2023,13 @@ int subselect_uniquesubquery_engine::exec(bool full_scan) { error= 0; table->null_row= 0; - ((Item_in_subselect *) item)->value= (!table->status && - (!cond || cond->val_int()) ? 1 : - 0); + if (!table->status && (!cond || cond->val_int())) + { + ((Item_in_subselect *) item)->value= 1; + empty_result_set= FALSE; + } + else + ((Item_in_subselect *) item)->value= 0; } DBUG_RETURN(error != 0); @@ -2045,7 +2095,7 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine() 1 */ -int subselect_indexsubquery_engine::exec(bool full_scan) +int subselect_indexsubquery_engine::exec() { DBUG_ENTER("subselect_indexsubquery_engine::exec"); int error; @@ -2086,8 +2136,9 @@ int subselect_indexsubquery_engine::exec(bool full_scan) table->null_row= 0; if (!table->status) { - if (!cond || cond->val_int()) + if ((!cond || cond->val_int()) && (!having || having->val_int())) { + empty_result_set= FALSE; if (null_finding) ((Item_in_subselect *) item)->was_null= 1; else @@ -2230,11 +2281,16 @@ void subselect_indexsubquery_engine::print(String *str) str->append(key_info->name); if (check_null) str->append(STRING_WITH_LEN(" checking NULL")); - if (cond) + if (cond) { str->append(STRING_WITH_LEN(" where ")); cond->print(str); } + if (having) + { + str->append(STRING_WITH_LEN(" having ")); + having->print(str); + } str->append(')'); } @@ -2321,6 +2377,22 @@ bool subselect_single_select_engine::no_tables() /* + Check statically whether the subquery can return NULL + + SINOPSYS + subselect_single_select_engine::may_be_null() + + RETURN + FALSE can guarantee that the subquery never return NULL + TRUE otherwise +*/ +bool subselect_single_select_engine::may_be_null() +{ + return ((no_tables() && !join->conds && !join->having) ? maybe_null : 1); +} + + +/* Report about presence of tables in subquery SYNOPSIS diff --git a/sql/item_subselect.h b/sql/item_subselect.h index c274b5ca31b..fdf3708cabb 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -95,7 +94,7 @@ public: return null_value; } bool fix_fields(THD *thd, Item **ref); - virtual bool exec(bool full_scan); + virtual bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; table_map not_null_tables() const { return 0; } @@ -105,6 +104,7 @@ public: Item *get_tmp_table_item(THD *thd); void update_used_tables(); void print(String *str); + virtual bool have_guarded_conds() { return FALSE; } bool change_engine(subselect_engine *eng) { old_engine= engine; @@ -164,7 +164,7 @@ public: void fix_length_and_dec(); uint cols(); - Item* el(uint i) { return my_reinterpret_cast(Item*)(row[i]); } + Item* element_index(uint i) { return my_reinterpret_cast(Item*)(row[i]); } Item** addr(uint i) { return (Item**)row + i; } bool check_cols(uint c); bool null_inside(); @@ -251,13 +251,21 @@ protected: bool transformed; public: /* Used to trigger on/off conditions that were pushed down to subselect */ - bool enable_pushed_conds; + bool *pushed_cond_guards; + + bool *get_cond_guard(int i) + { + return pushed_cond_guards ? pushed_cond_guards + i : NULL; + } + void set_cond_guard_var(int i, bool v) { pushed_cond_guards[i]= v; } + bool have_guarded_conds() { return test(pushed_cond_guards); } + Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery Item_in_subselect(Item * left_expr, st_select_lex *select_lex); Item_in_subselect() :Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0), - enable_pushed_conds(TRUE), upper_item(0) + pushed_cond_guards(NULL), upper_item(0) {} subs_type substype() { return IN_SUBS; } @@ -323,7 +331,7 @@ public: result= res; item= si; res_type= STRING_RESULT; - res_field_type= FIELD_TYPE_VAR_STRING; + res_field_type= MYSQL_TYPE_VAR_STRING; maybe_null= 0; } virtual ~subselect_engine() {}; // to satisfy compiler @@ -342,29 +350,28 @@ public: SYNOPSIS exec() - full_scan TRUE - Pushed-down predicates are disabled, the engine - must disable made based on those predicates. - FALSE - Pushed-down predicates are in effect. + DESCRIPTION Execute the engine. The result of execution is subquery value that is either captured by previously set up select_result-based 'sink' or stored somewhere by the exec() method itself. - A required side effect: if full_scan==TRUE, subselect_engine->no_rows() - should return correct result. + A required side effect: If at least one pushed-down predicate is + disabled, subselect_engine->no_rows() must return correct result after + the exec() call. RETURN 0 - OK - 1 - Either an execution error, or the engine was be "changed", and + 1 - Either an execution error, or the engine was "changed", and the caller should call exec() again for the new engine. */ - virtual int exec(bool full_scan)= 0; + virtual int exec()= 0; virtual uint cols()= 0; /* return number of columns in select */ virtual uint8 uncacheable()= 0; /* query is uncacheable */ enum Item_result type() { return res_type; } enum_field_types field_type() { return res_field_type; } virtual void exclude()= 0; - bool may_be_null() { return maybe_null; }; + virtual bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; static table_map calc_const_tables(TABLE_LIST *); virtual void print(String *str)= 0; @@ -393,7 +400,7 @@ public: void cleanup(); int prepare(); void fix_length_and_dec(Item_cache** row); - int exec(bool full_scan); + int exec(); uint cols(); uint8 uncacheable(); void exclude(); @@ -401,6 +408,7 @@ public: void print (String *str); bool change_result(Item_subselect *si, select_subselect *result); bool no_tables(); + bool may_be_null(); bool is_executed() const { return executed; } bool no_rows(); }; @@ -416,7 +424,7 @@ public: void cleanup(); int prepare(); void fix_length_and_dec(Item_cache** row); - int exec(bool full_scan); + int exec(); uint cols(); uint8 uncacheable(); void exclude(); @@ -430,11 +438,30 @@ public: struct st_join_table; + + +/* + A subquery execution engine that evaluates the subquery by doing one index + lookup in a unique index. + + This engine is used to resolve subqueries in forms + + outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where) + + or, tuple-based: + + (oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK + FROM tbl WHERE subqwhere) + + i.e. the subquery is a single table SELECT without GROUP BY, aggregate + functions, etc. +*/ + class subselect_uniquesubquery_engine: public subselect_engine { protected: st_join_table *tab; - Item *cond; + Item *cond; /* The WHERE condition of subselect */ /* TRUE<=> last execution produced empty set. Valid only when left expression is NULL. @@ -454,7 +481,7 @@ public: void cleanup(); int prepare(); void fix_length_and_dec(Item_cache** row); - int exec(bool full_scan); + int exec(); uint cols() { return 1; } uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } void exclude(); @@ -472,16 +499,47 @@ class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine { /* FALSE for 'ref', TRUE for 'ref-or-null'. */ bool check_null; + /* + The "having" clause. This clause (further reffered to as "artificial + having") was inserted by subquery transformation code. It contains + Item(s) that have a side-effect: they record whether the subquery has + produced a row with NULL certain components. We need to use it for cases + like + (oe1, oe2) IN (SELECT t.key, t.no_key FROM t1) + where we do index lookup on t.key=oe1 but need also to check if there + was a row such that t.no_key IS NULL. + + NOTE: This is currently here and not in the uniquesubquery_engine. Ideally + it should have been in uniquesubquery_engine in order to allow execution of + subqueries like + + (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl) + + We could use uniquesubquery_engine for the first component and let + Item_is_not_null_test( non_key_maybe_null_field) to handle the second. + + However, subqueries like the above are currently not handled by index + lookup-based subquery engines, the engine applicability check misses + them: it doesn't switch the engine for case of artificial having and + [eq_]ref access (only for artifical having + ref_or_null or no having). + The above example subquery is handled as a full-blown SELECT with eq_ref + access to one table. + + Due to this limitation, the "artificial having" currently needs to be + checked by only in indexsubquery_engine. + */ + Item *having; public: // constructor can assign THD because it will be called after JOIN::prepare - subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg, + subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg, Item_subselect *subs, Item *where, - bool chk_null) - :subselect_uniquesubquery_engine(thd, tab_arg, subs, where), - check_null(chk_null) + Item *having_arg, bool chk_null) + :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where), + check_null(chk_null), + having(having_arg) {} - int exec(bool full_scan); + int exec(); void print (String *str); }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 7ea13e61c23..f34fc008186 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -401,7 +400,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, Field *field; switch (result_type()) { case REAL_RESULT: - field= new Field_double(max_length, maybe_null, name, decimals); + field= new Field_double(max_length, maybe_null, name, decimals, TRUE); break; case INT_RESULT: field= new Field_longlong(max_length, maybe_null, name, unsigned_flag); @@ -1125,7 +1124,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, { /* We must store both value and counter in the temporary table in one field. - The easyest way is to do this is to store both value in a string + The easiest way is to do this is to store both value in a string and unpack on access. */ field= new Field_string(((hybrid_type == DECIMAL_RESULT) ? @@ -1136,7 +1135,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, field= new Field_new_decimal(max_length, maybe_null, name, decimals, unsigned_flag); else - field= new Field_double(max_length, maybe_null, name, decimals); + field= new Field_double(max_length, maybe_null, name, decimals, TRUE); if (field) field->init(table); return field; @@ -1173,7 +1172,7 @@ double Item_sum_avg::val_real() my_decimal *Item_sum_avg::val_decimal(my_decimal *val) { - my_decimal sum, cnt; + my_decimal sum_buff, cnt; const my_decimal *sum_dec; DBUG_ASSERT(fixed == 1); if (!count) @@ -1181,7 +1180,7 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) null_value=1; return NULL; } - sum_dec= Item_sum_sum::val_decimal(&sum); + sum_dec= Item_sum_sum::val_decimal(&sum_buff); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment); return val; @@ -1203,8 +1202,9 @@ String *Item_sum_avg::val_str(String *str) double Item_sum_std::val_real() { DBUG_ASSERT(fixed == 1); - double tmp= Item_sum_variance::val_real(); - return tmp <= 0.0 ? 0.0 : sqrt(tmp); + double nr= Item_sum_variance::val_real(); + DBUG_ASSERT(nr >= 0.0); + return sqrt(nr); } Item *Item_sum_std::copy_or_same(THD* thd) @@ -1218,40 +1218,77 @@ Item *Item_sum_std::copy_or_same(THD* thd) */ -Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), hybrid_type(item->hybrid_type), - cur_dec(item->cur_dec), count(item->count), sample(item->sample), - prec_increment(item->prec_increment) +/** + Variance implementation for floating-point implementations, without + catastrophic cancellation, from Knuth's _TAoCP_, 3rd ed, volume 2, pg232. + This alters the value at m, s, and increments count. +*/ + +/* + These two functions are used by the Item_sum_variance and the + Item_variance_field classes, which are unrelated, and each need to calculate + variance. The difference between the two classes is that the first is used + for a mundane SELECT, while the latter is used in a GROUPing SELECT. +*/ +static void variance_fp_recurrence_next(double *m, double *s, ulonglong *count, double nr) { - if (hybrid_type == DECIMAL_RESULT) + *count += 1; + + if (*count == 1) { - memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum)); - memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr)); - for (int i=0; i<2; i++) - { - dec_sum[i].fix_buffer_pointer(); - dec_sqr[i].fix_buffer_pointer(); - } + *m= nr; + *s= 0; } else { - sum= item->sum; - sum_sqr= item->sum_sqr; + double m_kminusone= *m; + *m= m_kminusone + (nr - m_kminusone) / (double) *count; + *s= *s + (nr - m_kminusone) * (nr - *m); } } +static double variance_fp_recurrence_result(double s, ulonglong count, bool is_sample_variance) +{ + if (count == 1) + return 0.0; + + if (is_sample_variance) + return s / (count - 1); + + /* else, is a population variance */ + return s / count; +} + + +Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): + Item_sum_num(thd, item), hybrid_type(item->hybrid_type), + count(item->count), sample(item->sample), + prec_increment(item->prec_increment) +{ + recurrence_m= item->recurrence_m; + recurrence_s= item->recurrence_s; +} + + void Item_sum_variance::fix_length_and_dec() { DBUG_ENTER("Item_sum_variance::fix_length_and_dec"); maybe_null= null_value= 1; prec_increment= current_thd->variables.div_precincrement; + + /* + According to the SQL2003 standard (Part 2, Foundations; sec 10.9, + aggregate function; paragraph 7h of Syntax Rules), "the declared + type of the result is an implementation-defined aproximate numeric + type. + */ + hybrid_type= REAL_RESULT; + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC); - hybrid_type= REAL_RESULT; - sum= 0.0; break; case INT_RESULT: case DECIMAL_RESULT: @@ -1260,37 +1297,14 @@ void Item_sum_variance::fix_length_and_dec() decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE); max_length= my_decimal_precision_to_length(precision, decimals, unsigned_flag); - cur_dec= 0; - hybrid_type= DECIMAL_RESULT; - my_decimal_set_zero(dec_sum); - my_decimal_set_zero(dec_sqr); - /* - The maxium value to usable for variance is DECIMAL_MAX_LENGTH/2 - becasue we need to be able to calculate in dec_bin_size1 - column_value * column_value - */ - f_scale0= args[0]->decimals; - f_precision0= min(args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS, - DECIMAL_MAX_PRECISION); - f_scale1= min(args[0]->decimals * 2, DECIMAL_MAX_SCALE); - f_precision1= min(args[0]->decimal_precision()*2 + DECIMAL_LONGLONG_DIGITS, - DECIMAL_MAX_PRECISION); - dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0); - dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1); break; } case ROW_RESULT: default: DBUG_ASSERT(0); } - DBUG_PRINT("info", ("Type: %s (%d, %d)", - (hybrid_type == REAL_RESULT ? "REAL_RESULT" : - hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : - hybrid_type == INT_RESULT ? "INT_RESULT" : - "--ILLEGAL!!!--"), - max_length, - (int)decimals)); + DBUG_PRINT("info", ("Type: REAL_RESULT (%d, %d)", max_length, (int)decimals)); DBUG_VOID_RETURN; } @@ -1301,6 +1315,11 @@ Item *Item_sum_variance::copy_or_same(THD* thd) } +/** + Create a new field to match the type of value we're expected to yield. + If we're grouping, then we need some space to serialize variables into, to + pass around. +*/ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { @@ -1309,110 +1328,68 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, { /* We must store both value and counter in the temporary table in one field. - The easyest way is to do this is to store both value in a string + The easiest way is to do this is to store both value in a string and unpack on access. */ - field= new Field_string(((hybrid_type == DECIMAL_RESULT) ? - dec_bin_size0 + dec_bin_size1 : - sizeof(double)*2) + sizeof(longlong), - 0, name, &my_charset_bin); + field= new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, &my_charset_bin); } else - { - field= new Field_double(max_length, maybe_null,name, decimals); - } - if (field) + field= new Field_double(max_length, maybe_null, name, decimals, TRUE); + + if (field != NULL) field->init(table); + return field; } void Item_sum_variance::clear() { - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal_set_zero(dec_sum); - my_decimal_set_zero(dec_sqr); - cur_dec= 0; - } - else - sum=sum_sqr=0.0; - count=0; + count= 0; } bool Item_sum_variance::add() { - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf); - my_decimal sqr_buf; - if (!args[0]->null_value) - { - count++; - int next_dec= cur_dec ^ 1; - my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec); - my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec, - dec_sqr+cur_dec, &sqr_buf); - my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec, - dec_sum+cur_dec, dec); - cur_dec= next_dec; - } - } - else - { - double nr= args[0]->val_real(); - if (!args[0]->null_value) - { - sum+=nr; - sum_sqr+=nr*nr; - count++; - } - } + /* + Why use a temporary variable? We don't know if it is null until we + evaluate it, which has the side-effect of setting null_value . + */ + double nr= args[0]->val_real(); + + if (!args[0]->null_value) + variance_fp_recurrence_next(&recurrence_m, &recurrence_s, &count, nr); return 0; } double Item_sum_variance::val_real() { DBUG_ASSERT(fixed == 1); - if (hybrid_type == DECIMAL_RESULT) - return val_real_from_decimal(); + /* + 'sample' is a 1/0 boolean value. If it is 1/true, id est this is a sample + variance call, then we should set nullness when the count of the items + is one or zero. If it's zero, i.e. a population variance, then we only + set nullness when the count is zero. + + Another way to read it is that 'sample' is the numerical threshhold, at and + below which a 'count' number of items is called NULL. + */ + DBUG_ASSERT((sample == 0) || (sample == 1)); if (count <= sample) { null_value=1; return 0.0; } + null_value=0; - /* Avoid problems when the precision isn't good enough */ - double tmp=ulonglong2double(count); - double tmp2= (sum_sqr - sum*sum/tmp)/(tmp - (double)sample); - return tmp2 <= 0.0 ? 0.0 : tmp2; + return variance_fp_recurrence_result(recurrence_s, count, sample); } my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) { - my_decimal count_buf, count1_buf, sum_sqr_buf; - DBUG_ASSERT(fixed ==1 ); - if (hybrid_type == REAL_RESULT) - return val_decimal_from_real(dec_buf); - - if (count <= sample) - { - null_value= 1; - return 0; - } - null_value= 0; - int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf); - int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &count1_buf); - my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf, - dec_sum+cur_dec, dec_sum+cur_dec); - my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, - &sum_sqr_buf, &count_buf, prec_increment); - my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf); - my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, - &sum_sqr_buf, &count1_buf, prec_increment); - return dec_buf; + DBUG_ASSERT(fixed == 1); + return val_decimal_from_real(dec_buf); } @@ -1421,89 +1398,44 @@ void Item_sum_variance::reset_field() double nr; char *res= result_field->ptr; - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *arg_dec, *arg2_dec; - longlong tmp; - - arg_dec= args[0]->val_decimal(&value); - if (args[0]->null_value) - { - arg_dec= arg2_dec= &decimal_zero; - tmp= 0; - } - else - { - my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec); - arg2_dec= dec_sum; - tmp= 1; - } - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, - res, f_precision0, f_scale0); - my_decimal2binary(E_DEC_FATAL_ERROR, arg2_dec, - res+dec_bin_size0, f_precision1, f_scale1); - res+= dec_bin_size0 + dec_bin_size1; - int8store(res,tmp); - return; - } - nr= args[0]->val_real(); + nr= args[0]->val_real(); /* sets null_value as side-effect */ if (args[0]->null_value) bzero(res,sizeof(double)*2+sizeof(longlong)); else { - longlong tmp; - float8store(res,nr); - nr*=nr; - float8store(res+sizeof(double),nr); - tmp= 1; - int8store(res+sizeof(double)*2,tmp); + /* Serialize format is (double)m, (double)s, (longlong)count */ + ulonglong tmp_count; + double tmp_s; + float8store(res, nr); /* recurrence variable m */ + tmp_s= 0.0; + float8store(res + sizeof(double), tmp_s); + tmp_count= 1; + int8store(res + sizeof(double)*2, tmp_count); } } void Item_sum_variance::update_field() { - longlong field_count; + ulonglong field_count; char *res=result_field->ptr; - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *arg_val= args[0]->val_decimal(&value); - if (!args[0]->null_value) - { - binary2my_decimal(E_DEC_FATAL_ERROR, res, - dec_sum+1, f_precision0, f_scale0); - binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0, - dec_sqr+1, f_precision1, f_scale1); - field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1)); - my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1); - my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val); - my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1); - field_count++; - my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, - res, f_precision0, f_scale0); - my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr, - res+dec_bin_size0, f_precision1, f_scale1); - res+= dec_bin_size0 + dec_bin_size1; - int8store(res, field_count); - } + + double nr= args[0]->val_real(); /* sets null_value as side-effect */ + + if (args[0]->null_value) return; - } - double nr,old_nr,old_sqr; - float8get(old_nr, res); - float8get(old_sqr, res+sizeof(double)); + /* Serialize format is (double)m, (double)s, (longlong)count */ + double field_recurrence_m, field_recurrence_s; + float8get(field_recurrence_m, res); + float8get(field_recurrence_s, res + sizeof(double)); field_count=sint8korr(res+sizeof(double)*2); - nr= args[0]->val_real(); - if (!args[0]->null_value) - { - old_nr+=nr; - old_sqr+=nr*nr; - field_count++; - } - float8store(res,old_nr); - float8store(res+sizeof(double),old_sqr); + variance_fp_recurrence_next(&field_recurrence_m, &field_recurrence_s, &field_count, nr); + + float8store(res, field_recurrence_m); + float8store(res + sizeof(double), field_recurrence_s); res+= sizeof(double)*2; int8store(res,field_count); } @@ -1695,7 +1627,7 @@ bool Item_sum_min::add() break; case DECIMAL_RESULT: { - my_decimal value, *val= args[0]->val_decimal(&value); + my_decimal value_buff, *val= args[0]->val_decimal(&value_buff); if (!args[0]->null_value && (null_value || (my_decimal_cmp(&sum_dec, val) > 0))) { @@ -1759,7 +1691,7 @@ bool Item_sum_max::add() break; case DECIMAL_RESULT: { - my_decimal value, *val= args[0]->val_decimal(&value); + my_decimal value_buff, *val= args[0]->val_decimal(&value_buff); if (!args[0]->null_value && (null_value || (my_decimal_cmp(val, &sum_dec) > 0))) { @@ -1924,7 +1856,7 @@ void Item_sum_hybrid::reset_field() } case DECIMAL_RESULT: { - my_decimal value, *arg_dec= args[0]->val_decimal(&value); + my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff); if (maybe_null) { @@ -2330,25 +2262,9 @@ double Item_std_field::val_real() { double nr; // fix_fields() never calls for this Item - if (hybrid_type == REAL_RESULT) - { - /* - We can't call Item_variance_field::val_real() on a DECIMAL_RESULT - as this would call Item_std_field::val_decimal() and we would - calculate sqrt() twice - */ - nr= Item_variance_field::val_real(); - } - else - { - my_decimal dec_buf,*dec; - dec= Item_variance_field::val_decimal(&dec_buf); - if (!dec) - nr= 0.0; // NULL; Return 0.0 - else - my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr); - } - return nr <= 0.0 ? 0.0 : sqrt(nr); + nr= Item_variance_field::val_real(); + DBUG_ASSERT(nr >= 0.0); + return sqrt(nr); } @@ -2362,11 +2278,13 @@ my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf) double nr; if (hybrid_type == REAL_RESULT) return val_decimal_from_real(dec_buf); + dec= Item_variance_field::val_decimal(dec_buf); if (!dec) return 0; my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr); - nr= nr <= 0.0 ? 0.0 : sqrt(nr); + DBUG_ASSERT(nr >= 0.0); + nr= sqrt(nr); double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec); my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf); return dec_buf; @@ -2401,52 +2319,15 @@ double Item_variance_field::val_real() if (hybrid_type == DECIMAL_RESULT) return val_real_from_decimal(); - double sum,sum_sqr; - longlong count; - float8get(sum,field->ptr); - float8get(sum_sqr,(field->ptr+sizeof(double))); + double recurrence_s; + ulonglong count; + float8get(recurrence_s, (field->ptr + sizeof(double))); count=sint8korr(field->ptr+sizeof(double)*2); if ((null_value= (count <= sample))) return 0.0; - double tmp= (double) count; - double tmp2= (sum_sqr - sum*sum/tmp)/(tmp - (double)sample); - return tmp2 <= 0.0 ? 0.0 : tmp2; -} - - -String *Item_variance_field::val_str(String *str) -{ - if (hybrid_type == DECIMAL_RESULT) - return val_string_from_decimal(str); - return val_string_from_real(str); -} - - -my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf) -{ - // fix_fields() never calls for this Item - if (hybrid_type == REAL_RESULT) - return val_decimal_from_real(dec_buf); - - longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1); - if ((null_value= (count <= sample))) - return 0; - - my_decimal dec_count, dec1_count, dec_sum, dec_sqr, tmp; - int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); - int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &dec1_count); - binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr, - &dec_sum, f_precision0, f_scale0); - binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0, - &dec_sqr, f_precision1, f_scale1); - my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum); - my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, prec_increment); - my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf); - my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, - &dec_sum, &dec1_count, prec_increment); - return dec_buf; + return variance_fp_recurrence_result(recurrence_s, count, sample); } @@ -2603,11 +2484,11 @@ bool Item_sum_count_distinct::setup(THD *thd) for (tree_key_length= 0; field < field_end; ++field) { Field *f= *field; - enum enum_field_types type= f->type(); + enum enum_field_types f_type= f->type(); tree_key_length+= f->pack_length(); - if ((type == MYSQL_TYPE_VARCHAR) || - !f->binary() && (type == MYSQL_TYPE_STRING || - type == MYSQL_TYPE_VAR_STRING)) + if ((f_type == MYSQL_TYPE_VARCHAR) || + !f->binary() && (f_type == MYSQL_TYPE_STRING || + f_type == MYSQL_TYPE_VAR_STRING)) { all_binary= FALSE; break; @@ -3192,8 +3073,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, void Item_func_group_concat::cleanup() { - THD *thd= current_thd; - DBUG_ENTER("Item_func_group_concat::cleanup"); Item_sum::cleanup(); @@ -3202,7 +3081,7 @@ void Item_func_group_concat::cleanup() { char warn_buff[MYSQL_ERRMSG_SIZE]; sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); - warning->set_msg(thd, warn_buff); + warning->set_msg(current_thd, warn_buff); warning= 0; } @@ -3232,8 +3111,7 @@ void Item_func_group_concat::cleanup() warning= 0; } } - DBUG_ASSERT(tree == 0); - DBUG_ASSERT(warning == 0); + DBUG_ASSERT(tree == 0 && warning == 0); } DBUG_VOID_RETURN; } diff --git a/sql/item_sum.h b/sql/item_sum.h index acd23d1ff4c..4cf16fc79af 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -223,7 +222,7 @@ class Item_sum :public Item_result_field public: enum Sumfunctype { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, - AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, + AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC, VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; @@ -683,8 +682,10 @@ public: double val_real(); longlong val_int() { /* can't be fix_fields()ed */ return (longlong) rint(val_real()); } - String *val_str(String*); - my_decimal *val_decimal(my_decimal *); + String *val_str(String *str) + { return val_string_from_real(str); } + my_decimal *val_decimal(my_decimal *dec_buf) + { return val_decimal_from_real(dec_buf); } bool is_null() { update_null_value(); return null_value; } enum_field_types field_type() const { @@ -706,6 +707,14 @@ public: = (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) = = (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) = = (sum(ai^2) - sum(a)^2/count(a))/count(a) + +But, this falls prey to catastrophic cancellation. Instead, use the recurrence formulas + + M_{1} = x_{1}, ~ M_{k} = M_{k-1} + (x_{k} - M_{k-1}) / k newline + S_{1} = 0, ~ S_{k} = S_{k-1} + (x_{k} - M_{k-1}) times (x_{k} - M_{k}) newline + for 2 <= k <= n newline + ital variance = S_{n} / (n-1) + */ class Item_sum_variance : public Item_sum_num @@ -714,9 +723,8 @@ class Item_sum_variance : public Item_sum_num public: Item_result hybrid_type; - double sum, sum_sqr; - my_decimal dec_sum[2], dec_sqr[2]; int cur_dec; + double recurrence_m, recurrence_s; /* Used in recurrence relation. */ ulonglong count; uint f_precision0, f_scale0; uint f_precision1, f_scale1; @@ -725,7 +733,7 @@ public: uint prec_increment; Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par), - hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg) + hybrid_type(REAL_RESULT), count(0), sample(sample_arg) {} Item_sum_variance(THD *thd, Item_sum_variance *item); enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } @@ -745,7 +753,6 @@ public: enum Item_result result_type () const { return REAL_RESULT; } void cleanup() { - cur_dec= 0; count= 0; Item_sum_num::cleanup(); } @@ -804,7 +811,7 @@ protected: public: Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par), sum(0.0), sum_int(0), - hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG), + hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG), cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) { collation.set(&my_charset_bin); } @@ -1187,7 +1194,7 @@ public: enum_field_types field_type() const { if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB ) - return FIELD_TYPE_BLOB; + return MYSQL_TYPE_BLOB; else return MYSQL_TYPE_VARCHAR; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ff688e15307..1bf1fec5cfb 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -609,16 +608,10 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, uint weekday; ulong length; const char *ptr, *end; - MY_LOCALE *locale; THD *thd= current_thd; - char buf[STRING_BUFFER_USUAL_SIZE]; - String tmp(buf, sizeof(buf), thd->variables.character_set_results); - uint errors= 0; + MY_LOCALE *locale= thd->variables.lc_time_names; - tmp.length(0); str->length(0); - str->set_charset(&my_charset_bin); - locale = thd->variables.lc_time_names; if (l_time->neg) str->append('-'); @@ -632,41 +625,37 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, { switch (*++ptr) { case 'M': - if (!l_time->month) - return 1; - tmp.copy(locale->month_names->type_names[l_time->month-1], - strlen(locale->month_names->type_names[l_time->month-1]), - system_charset_info, tmp.charset(), &errors); - str->append(tmp.ptr(), tmp.length()); - break; + if (!l_time->month) + return 1; + str->append(locale->month_names->type_names[l_time->month-1], + strlen(locale->month_names->type_names[l_time->month-1]), + system_charset_info); + break; case 'b': - if (!l_time->month) - return 1; - tmp.copy(locale->ab_month_names->type_names[l_time->month-1], - strlen(locale->ab_month_names->type_names[l_time->month-1]), - system_charset_info, tmp.charset(), &errors); - str->append(tmp.ptr(), tmp.length()); - break; + if (!l_time->month) + return 1; + str->append(locale->ab_month_names->type_names[l_time->month-1], + strlen(locale->ab_month_names->type_names[l_time->month-1]), + system_charset_info); + break; case 'W': - if (type == MYSQL_TIMESTAMP_TIME) - return 1; - weekday= calc_weekday(calc_daynr(l_time->year,l_time->month, - l_time->day),0); - tmp.copy(locale->day_names->type_names[weekday], - strlen(locale->day_names->type_names[weekday]), - system_charset_info, tmp.charset(), &errors); - str->append(tmp.ptr(), tmp.length()); - break; + if (type == MYSQL_TIMESTAMP_TIME) + return 1; + weekday= calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),0); + str->append(locale->day_names->type_names[weekday], + strlen(locale->day_names->type_names[weekday]), + system_charset_info); + break; case 'a': - if (type == MYSQL_TIMESTAMP_TIME) - return 1; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, - l_time->day),0); - tmp.copy(locale->ab_day_names->type_names[weekday], - strlen(locale->ab_day_names->type_names[weekday]), - system_charset_info, tmp.charset(), &errors); - str->append(tmp.ptr(), tmp.length()); - break; + if (type == MYSQL_TIMESTAMP_TIME) + return 1; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),0); + str->append(locale->ab_day_names->type_names[weekday], + strlen(locale->ab_day_names->type_names[weekday]), + system_charset_info); + break; case 'D': if (type == MYSQL_TIMESTAMP_TIME) return 1; @@ -1018,7 +1007,8 @@ longlong Item_func_quarter::val_int() { DBUG_ASSERT(fixed == 1); TIME ltime; - (void) get_arg0_date(<ime, TIME_FUZZY_DATE); + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) + return 0; return (longlong) ((ltime.month+2)/3); } @@ -1130,14 +1120,14 @@ String* Item_func_dayname::val_str(String* str) { DBUG_ASSERT(fixed == 1); uint weekday=(uint) val_int(); // Always Item_func_daynr() - const char *name; + const char *day_name; THD *thd= current_thd; if (null_value) return (String*) 0; - name= thd->variables.lc_time_names->day_names->type_names[weekday]; - str->set(name, strlen(name), system_charset_info); + day_name= thd->variables.lc_time_names->day_names->type_names[weekday]; + str->set(day_name, strlen(day_name), system_charset_info); return str; } @@ -1185,7 +1175,7 @@ longlong Item_func_unix_timestamp::val_int() if (args[0]->type() == FIELD_ITEM) { // Optimize timestamp field Field *field=((Item_field*) args[0])->field; - if (field->type() == FIELD_TYPE_TIMESTAMP) + if (field->type() == MYSQL_TYPE_TIMESTAMP) return ((Field_timestamp*) field)->get_timestamp(&null_value); } @@ -1597,7 +1587,7 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time) { THD *thd= current_thd; - thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL)); + thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) time(NULL)); thd->time_zone_used= 1; } @@ -1658,6 +1648,7 @@ String *Item_func_sec_to_time::val_str(String *str) { DBUG_ASSERT(fixed == 1); TIME ltime; + longlong arg_val= args[0]->val_int(); if ((null_value=args[0]->null_value) || str->alloc(19)) { @@ -1665,7 +1656,7 @@ String *Item_func_sec_to_time::val_str(String *str) return (String*) 0; } - sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + sec_to_time(arg_val, args[0]->unsigned_flag, <ime); make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; @@ -1676,11 +1667,12 @@ longlong Item_func_sec_to_time::val_int() { DBUG_ASSERT(fixed == 1); TIME ltime; + longlong arg_val= args[0]->val_int(); if ((null_value=args[0]->null_value)) return 0; - sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + sec_to_time(arg_val, args[0]->unsigned_flag, <ime); return (ltime.neg ? -1 : 1) * ((ltime.hour)*10000 + ltime.minute*100 + ltime.second); @@ -1689,6 +1681,7 @@ longlong Item_func_sec_to_time::val_int() void Item_func_date_format::fix_length_and_dec() { + THD* thd= current_thd; /* Must use this_item() in case it's a local SP variable (for ->max_length and ->str_value) @@ -1696,22 +1689,18 @@ void Item_func_date_format::fix_length_and_dec() Item *arg1= args[1]->this_item(); decimals=0; - collation.set(&my_charset_bin); + collation.set(thd->variables.collation_connection); if (arg1->type() == STRING_ITEM) { // Optimize the normal case fixed_length=1; - - /* - The result is a binary string (no reason to use collation->mbmaxlen - This is becasue make_date_time() only returns binary strings - */ - max_length= format_length(&arg1->str_value); + max_length= format_length(&arg1->str_value) * + collation.collation->mbmaxlen; } else { fixed_length=0; - /* The result is a binary string (no reason to use collation->mbmaxlen */ - max_length=min(arg1->max_length, MAX_BLOB_WIDTH) * 10; + max_length=min(arg1->max_length, MAX_BLOB_WIDTH) * 10 * + collation.collation->mbmaxlen; set_if_smaller(max_length,MAX_BLOB_WIDTH); } maybe_null=1; // If wrong date @@ -1856,6 +1845,7 @@ String *Item_func_date_format::val_str(String *str) date_time_format.format.length= format->length(); /* Create the result string */ + str->set_charset(collation.collation); if (!make_date_time(&date_time_format, &l_time, is_time_format ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATE, @@ -2541,7 +2531,10 @@ longlong Item_date_typecast::val_int() DBUG_ASSERT(fixed == 1); TIME ltime; if (args[0]->get_date(<ime, TIME_FUZZY_DATE)) + { + null_value= 1; return 0; + } return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day); } @@ -3181,10 +3174,10 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) { DATE_TIME_FORMAT date_time_format; char val_buff[64], format_buff[64]; - String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val; + String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val; String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; - val= args[0]->val_str(&val_str); + val= args[0]->val_str(&val_string); format= args[1]->val_str(&format_str); if (args[0]->null_value || args[1]->null_value) goto null_date; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 360307a677f..e53826ce3df 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc deleted file mode 100644 index 9db8228b345..00000000000 --- a/sql/item_uniq.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Compability file */ - -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - -#include "mysql_priv.h" - -Field *Item_sum_unique_users::create_tmp_field(bool group, TABLE *table, - uint convert_blob_length) -{ - Field *field= new Field_long(9, maybe_null, name, 1); - if (field) - field->init(table); - return field; -} diff --git a/sql/item_uniq.h b/sql/item_uniq.h deleted file mode 100644 index a0aa0b96cc6..00000000000 --- a/sql/item_uniq.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Compability file ; This file only contains dummy functions */ - -#ifdef USE_PRAGMA_INTERFACE -#pragma interface -#endif - -#include <queues.h> - -class Item_func_unique_users :public Item_real_func -{ -public: - Item_func_unique_users(Item *name_arg,int start,int end,List<Item> &list) - :Item_real_func(list) {} - double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } - void fix_length_and_dec() { decimals=0; max_length=6; } - void print(String *str) { str->append(STRING_WITH_LEN("0.0")); } - const char *func_name() const { return "unique_users"; } -}; - - -class Item_sum_unique_users :public Item_sum_num -{ -public: - Item_sum_unique_users(Item *name_arg,int start,int end,Item *item_arg) - :Item_sum_num(item_arg) {} - Item_sum_unique_users(THD *thd, Item_sum_unique_users *item) - :Item_sum_num(thd, item) {} - double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } - enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;} - void clear() {} - bool add() { return 0; } - void reset_field() {} - void update_field() {} - bool fix_fields(THD *thd, Item **ref) - { - DBUG_ASSERT(fixed == 0); - fixed= 1; - return FALSE; - } - Item *copy_or_same(THD* thd) - { - return new Item_sum_unique_users(thd, this); - } - void print(String *str) { str->append(STRING_WITH_LEN("0.0")); } - Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); - const char *func_name() const { return "sum_unique_users"; } -}; diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 966bae43984..9321992e566 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,8 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __GNUC__ #pragma implementation @@ -579,7 +577,6 @@ String * Item_nodeset_func_union::val_nodeset(String *nodeset) both_str.alloc(numnodes); char *both= (char*) both_str.ptr(); bzero((void*)both, numnodes); - uint pos= 0; MY_XPATH_FLT *flt; fltbeg= (MY_XPATH_FLT*) s0->ptr(); @@ -1486,7 +1483,6 @@ static int my_xpath_parse_AxisName(MY_XPATH *xpath) static int my_xpath_parse_LocationPath(MY_XPATH *xpath); static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath); static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath); -static int my_xpath_parse_AbbreviatedAbsoluteLocationPath(MY_XPATH *xpath); static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath); static int my_xpath_parse_Step(MY_XPATH *xpath); static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath); @@ -1505,7 +1501,6 @@ static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath); static int my_xpath_parse_AndExpr(MY_XPATH *xpath); static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath); static int my_xpath_parse_VariableReference(MY_XPATH *xpath); -static int my_xpath_parse_slash_opt_slash(MY_XPATH *xpath); /* @@ -2701,7 +2696,6 @@ String *Item_func_xml_update::val_str(String *str) } MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml.ptr(); - MY_XML_NODE *nodeend= (MY_XML_NODE*) pxml.ptr() + pxml.length(); MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr(); MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length()); diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h index 6fa33081373..9f2860ef403 100644 --- a/sql/item_xmlfunc.h +++ b/sql/item_xmlfunc.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/key.cc b/sql/key.cc index dceeab1c011..bd614b10a70 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/lex.h b/sql/lex.h index 254d7f10fb7..45155da7692 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -223,12 +222,13 @@ static SYMBOL symbols[] = { { "GLOBAL", SYM(GLOBAL_SYM)}, { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, - { "GROUP", SYM(GROUP)}, + { "GROUP", SYM(GROUP_SYM)}, { "HANDLER", SYM(HANDLER_SYM)}, { "HASH", SYM(HASH_SYM)}, { "HAVING", SYM(HAVING)}, { "HELP", SYM(HELP_SYM)}, { "HIGH_PRIORITY", SYM(HIGH_PRIORITY)}, + { "HOST", SYM(HOST_SYM)}, { "HOSTS", SYM(HOSTS_SYM)}, { "HOUR", SYM(HOUR_SYM)}, { "HOUR_MICROSECOND", SYM(HOUR_MICROSECOND_SYM)}, @@ -368,6 +368,7 @@ static SYMBOL symbols[] = { { "ONE_SHOT", SYM(ONE_SHOT_SYM)}, { "OPEN", SYM(OPEN_SYM)}, { "OPTIMIZE", SYM(OPTIMIZE)}, + { "OPTIONS", SYM(OPTIONS_SYM)}, { "OPTION", SYM(OPTION)}, { "OPTIONALLY", SYM(OPTIONALLY)}, { "OR", SYM(OR_SYM)}, @@ -375,6 +376,7 @@ static SYMBOL symbols[] = { { "OUT", SYM(OUT_SYM)}, { "OUTER", SYM(OUTER)}, { "OUTFILE", SYM(OUTFILE)}, + { "OWNER", SYM(OWNER_SYM)}, { "PACK_KEYS", SYM(PACK_KEYS_SYM)}, { "PARSER", SYM(PARSER_SYM)}, { "PARTIAL", SYM(PARTIAL)}, @@ -387,6 +389,7 @@ static SYMBOL symbols[] = { { "PLUGINS", SYM(PLUGINS_SYM)}, { "POINT", SYM(POINT_SYM)}, { "POLYGON", SYM(POLYGON)}, + { "PORT", SYM(PORT_SYM)}, { "PRECISION", SYM(PRECISION)}, { "PREPARE", SYM(PREPARE_SYM)}, { "PRESERVE", SYM(PRESERVE_SYM)}, @@ -456,6 +459,7 @@ static SYMBOL symbols[] = { { "SERIAL", SYM(SERIAL_SYM)}, { "SERIALIZABLE", SYM(SERIALIZABLE_SYM)}, { "SESSION", SYM(SESSION_SYM)}, + { "SERVER", SYM(SERVER_SYM)}, { "SET", SYM(SET)}, { "SHARE", SYM(SHARE_SYM)}, { "SHOW", SYM(SHOW)}, @@ -465,6 +469,7 @@ static SYMBOL symbols[] = { { "SLAVE", SYM(SLAVE)}, { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, { "SMALLINT", SYM(SMALLINT)}, + { "SOCKET", SYM(SOCKET_SYM)}, { "SOME", SYM(ANY_SYM)}, { "SONAME", SYM(SONAME_SYM)}, { "SOUNDS", SYM(SOUNDS_SYM)}, @@ -569,6 +574,7 @@ static SYMBOL symbols[] = { { "VIEW", SYM(VIEW_SYM)}, { "WITH", SYM(WITH)}, { "WORK", SYM(WORK_SYM)}, + { "WRAPPER", SYM(WRAPPER_SYM)}, { "WRITE", SYM(WRITE_SYM)}, { "X509", SYM(X509_SYM)}, { "XOR", SYM(XOR)}, @@ -593,7 +599,6 @@ static SYMBOL sql_functions[] = { { "DATE_SUB", SYM(DATE_SUB_INTERVAL)}, { "EXTRACT", SYM(EXTRACT_SYM)}, { "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM)}, - { "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS)}, { "MAX", SYM(MAX_SYM)}, { "MID", SYM(SUBSTRING)}, /* unireg function */ { "MIN", SYM(MIN_SYM)}, @@ -611,7 +616,6 @@ static SYMBOL sql_functions[] = { { "SYSDATE", SYM(SYSDATE)}, { "SYSTEM_USER", SYM(USER)}, { "TRIM", SYM(TRIM)}, - { "UNIQUE_USERS", SYM(UNIQUE_USERS)}, { "VARIANCE", SYM(VARIANCE_SYM)}, { "VAR_POP", SYM(VARIANCE_SYM)}, { "VAR_SAMP", SYM(VAR_SAMP_SYM)}, diff --git a/sql/lex_symbol.h b/sql/lex_symbol.h index 5ba785d16f3..000c0709071 100644 --- a/sql/lex_symbol.h +++ b/sql/lex_symbol.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/lock.cc b/sql/lock.cc index f36ecf58620..edef3b3b67f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -151,6 +150,23 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } } + if ( write_lock_used + && opt_readonly + && ! (thd->security_ctx->master_access & SUPER_ACL) + && ! thd->slave_thread + ) + { + /* + Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock. + We do not wait for READ_ONLY=0, and fail. + */ + reset_lock_data(sql_lock); + my_free((gptr) sql_lock, MYF(0)); + sql_lock=0; + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + break; + } + thd->proc_info="System lock"; DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info)); if (lock_external(thd, tables, count)) @@ -469,7 +485,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) for (uint i=0; i < locked->lock_count; i++) { if (thr_abort_locks_for_thread(locked->locks[i]->lock, - table->in_use->real_id)) + table->in_use->thread_id)) result= TRUE; } my_free((gptr) locked,MYF(0)); diff --git a/sql/log.cc b/sql/log.cc index 3a2a344e514..8de6e8d7d22 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -82,23 +81,54 @@ char *make_default_log_name(char *buff,const char* log_ext) } /* + Helper class to hold a mutex for the duration of the + block. + + Eliminates the need for explicit unlocking of mutexes on, e.g., + error returns. On passing a null pointer, the sentry will not do + anything. + */ +class Mutex_sentry +{ +public: + Mutex_sentry(pthread_mutex_t *mutex) + : m_mutex(mutex) + { + if (m_mutex) + pthread_mutex_lock(mutex); + } + + ~Mutex_sentry() + { + if (m_mutex) + pthread_mutex_unlock(m_mutex); +#ifndef DBUG_OFF + m_mutex= 0; +#endif + } + +private: + pthread_mutex_t *m_mutex; + + // It's not allowed to copy this object in any way + Mutex_sentry(Mutex_sentry const&); + void operator=(Mutex_sentry const&); +}; + +/* Helper class to store binary log transaction data. */ class binlog_trx_data { public: binlog_trx_data() -#ifdef HAVE_ROW_BASED_REPLICATION : m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF) -#endif { trans_log.end_of_file= max_binlog_cache_size; } ~binlog_trx_data() { -#ifdef HAVE_ROW_BASED_REPLICATION DBUG_ASSERT(pending() == NULL); -#endif close_cached_file(&trans_log); } @@ -108,11 +138,7 @@ public: bool empty() const { -#ifdef HAVE_ROW_BASED_REPLICATION return pending() == NULL && my_b_tell(&trans_log) == 0; -#else - return my_b_tell(&trans_log) == 0; -#endif } /* @@ -121,11 +147,12 @@ public: */ void truncate(my_off_t pos) { -#ifdef HAVE_ROW_BASED_REPLICATION + DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos)); delete pending(); set_pending(0); -#endif reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); + if (pos < before_stmt_pos) + before_stmt_pos= MY_OFF_T_UNDEF; } /* @@ -135,13 +162,10 @@ public: void reset() { if (!empty()) truncate(0); -#ifdef HAVE_ROW_BASED_REPLICATION before_stmt_pos= MY_OFF_T_UNDEF; -#endif trans_log.end_of_file= max_binlog_cache_size; } -#ifdef HAVE_ROW_BASED_REPLICATION Rows_log_event *pending() const { return m_pending; @@ -151,12 +175,10 @@ public: { m_pending= pending; } -#endif IO_CACHE trans_log; // The transaction cache private: -#ifdef HAVE_ROW_BASED_REPLICATION /* Pending binrows event. This event is the event where the rows are currently written. @@ -168,7 +190,6 @@ public: Binlog position before the start of the current statement. */ my_off_t before_stmt_pos; -#endif }; handlerton *binlog_hton; @@ -246,7 +267,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type) table->table_name_length= 8; break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } /* @@ -887,7 +908,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, my_time_t current_time; Security_context *sctx= thd->security_ctx; - uint message_buff_len= 0, user_host_len= 0; + uint user_host_len= 0; longlong query_time= 0, lock_time= 0; /* @@ -1140,7 +1161,7 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type) log_thd= table_log_handler->general_log_thd; break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } if (!(*tmp_opt)) @@ -1289,7 +1310,7 @@ void Log_to_csv_event_handler:: table= &slow_log; break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } /* @@ -1468,9 +1489,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, were, we would have to ensure that we're not ending a statement inside a stored function. */ -#ifdef HAVE_ROW_BASED_REPLICATION thd->binlog_flush_pending_rows_event(TRUE); -#endif /* We write the transaction cache to the binary log if either we're committing the entire transaction, or if we are doing an @@ -1480,13 +1499,11 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, { error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev); trx_data->reset(); -#ifdef HAVE_ROW_BASED_REPLICATION /* We need to step the table map version after writing the transaction cache to disk. */ mysql_bin_log.update_table_map_version(); -#endif statistic_increment(binlog_cache_use, &LOCK_status); if (trans_log->disk_writes != 0) { @@ -1495,7 +1512,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, } } } -#ifdef HAVE_ROW_BASED_REPLICATION else { /* @@ -1504,12 +1520,11 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, If rolling back a statement in a transaction, we truncate the transaction cache to remove the statement. - */ if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) trx_data->reset(); - else - trx_data->truncate(trx_data->before_stmt_pos); // ...statement + else // ...statement + trx_data->truncate(trx_data->before_stmt_pos); /* We need to step the table map version on a rollback to ensure @@ -1518,7 +1533,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, */ mysql_bin_log.update_table_map_version(); } -#endif DBUG_RETURN(error); } @@ -1529,23 +1543,21 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) do nothing. just pretend we can do 2pc, so that MySQL won't switch to 1pc. - real work will be done in MYSQL_BIN_LOG::log() + real work will be done in MYSQL_BIN_LOG::log_xid() */ return 0; } static int binlog_commit(handlerton *hton, THD *thd, bool all) { - int error= 0; DBUG_ENTER("binlog_commit"); binlog_trx_data *const trx_data= (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; - IO_CACHE *trans_log= &trx_data->trans_log; DBUG_ASSERT(mysql_bin_log.is_open()); if (all && trx_data->empty()) { - // we're here because trans_log was flushed in MYSQL_BIN_LOG::log() + // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid() trx_data->reset(); DBUG_RETURN(0); } @@ -1569,7 +1581,6 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) int error=0; binlog_trx_data *const trx_data= (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; - IO_CACHE *trans_log= &trx_data->trans_log; DBUG_ASSERT(mysql_bin_log.is_open()); if (trx_data->empty()) { @@ -1632,9 +1643,6 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) { DBUG_ENTER("binlog_savepoint_rollback"); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; - IO_CACHE *trans_log= &trx_data->trans_log; DBUG_ASSERT(mysql_bin_log.is_open()); /* @@ -1645,7 +1653,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) if (unlikely(thd->options & (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG))) { - int const error= + int error= thd->binlog_query(THD::STMT_QUERY_TYPE, thd->query, thd->query_length, TRUE, FALSE); DBUG_RETURN(error); @@ -1654,6 +1662,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) DBUG_RETURN(0); } + int check_binlog_magic(IO_CACHE* log, const char** errmsg) { char magic[4]; @@ -1674,6 +1683,7 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg) return 0; } + File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg) { File file; @@ -1732,7 +1742,7 @@ void setup_windows_event_source() /* Register EventMessageFile */ dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ, - (PBYTE) szPath, strlen(szPath)+1); + (PBYTE) szPath, (DWORD) (strlen(szPath) + 1)); /* Register supported event types */ dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | @@ -2097,7 +2107,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host, if (my_b_write(&log_file, (byte*) "\t\t" ,2) < 0) goto err; - /* command_type, thread_id */ + /* command_type, thread_id */ length= my_snprintf(buff, 32, "%5ld ", (long) thread_id); if (my_b_write(&log_file, (byte*) buff, length)) @@ -2180,7 +2190,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT)) { - Security_context *sctx= thd->security_ctx; if (current_time != last_time) { last_time= current_time; @@ -2424,7 +2433,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name, bool null_created_arg) { File file= -1; - int open_flags = O_CREAT | O_BINARY; DBUG_ENTER("MYSQL_BIN_LOG::open"); DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg)); @@ -2586,6 +2594,8 @@ int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo) 0 ok */ +#ifdef HAVE_REPLICATION + static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset) { int bytes_read; @@ -2619,6 +2629,7 @@ err: DBUG_RETURN(1); } +#endif /* HAVE_REPLICATION */ /* Find the position in the log-index-file for the given log name @@ -3111,8 +3122,6 @@ err: pthread_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } - - #endif /* HAVE_REPLICATION */ @@ -3234,7 +3243,6 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) We log the whole file name for log file as the user may decide to change base names at some point. */ - THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */ Rotate_log_event r(new_name+dirname_length(new_name), 0, LOG_EVENT_OFFSET, 0); r.write(&log_file); @@ -3401,7 +3409,6 @@ int THD::binlog_setup_trx_data() DBUG_RETURN(0); } -#ifdef HAVE_ROW_BASED_REPLICATION /* Function to start a statement and optionally a transaction for the binary log. @@ -3443,18 +3450,7 @@ THD::binlog_start_trans_and_stmt() if (trx_data == NULL || trx_data->before_stmt_pos == MY_OFF_T_UNDEF) { - /* - The call to binlog_trans_log_savepos() might create the trx_data - structure, if it didn't exist before, so we save the position - into an auto variable and then write it into the transaction - data for the binary log (i.e., trx_data). - */ - my_off_t pos= 0; - binlog_trans_log_savepos(this, &pos); - trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; - - trx_data->before_stmt_pos= pos; - + this->binlog_set_stmt_begin(); if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); @@ -3462,6 +3458,51 @@ THD::binlog_start_trans_and_stmt() DBUG_VOID_RETURN; } +void THD::binlog_set_stmt_begin() { + binlog_trx_data *trx_data= + (binlog_trx_data*) ha_data[binlog_hton->slot]; + + /* + The call to binlog_trans_log_savepos() might create the trx_data + structure, if it didn't exist before, so we save the position + into an auto variable and then write it into the transaction + data for the binary log (i.e., trx_data). + */ + my_off_t pos= 0; + binlog_trans_log_savepos(this, &pos); + trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; + trx_data->before_stmt_pos= pos; +} + +int THD::binlog_flush_transaction_cache() +{ + DBUG_ENTER("binlog_flush_transaction_cache"); + binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; + DBUG_PRINT("enter", ("trx_data: 0x%lx", (ulong) trx_data)); + if (trx_data) + DBUG_PRINT("enter", ("trx_data->before_stmt_pos: %lu", + (ulong) trx_data->before_stmt_pos)); + + /* + Write the transaction cache to the binary log. We don't flush and + sync the log file since we don't know if more will be written to + it. If the caller want the log file sync:ed, the caller has to do + it. + + The transaction data is only reset upon a successful write of the + cache to the binary log. + */ + + if (trx_data && likely(mysql_bin_log.is_open())) { + if (int error= mysql_bin_log.write_cache(&trx_data->trans_log, true, true)) + DBUG_RETURN(error); + trx_data->reset(); + } + + DBUG_RETURN(0); +} + + /* Write a table map to the binary log. */ @@ -3610,7 +3651,6 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, DBUG_RETURN(error); } -#endif /*HAVE_ROW_BASED_REPLICATION*/ /* Write an event to the binary log @@ -3643,11 +3683,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) we are inside a stored function, we do not end the statement since this will close all tables on the slave. */ -#ifdef HAVE_ROW_BASED_REPLICATION bool const end_stmt= thd->prelocked_mode && thd->lex->requires_prelocking(); thd->binlog_flush_pending_rows_event(end_stmt); -#endif /*HAVE_ROW_BASED_REPLICATION*/ pthread_mutex_lock(&LOCK_log); @@ -3658,14 +3696,14 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) */ if (likely(is_open())) { - const char *local_db= event_info->get_db(); IO_CACHE *file= &log_file; #ifdef HAVE_REPLICATION /* - In the future we need to add to the following if tests like - "do the involved tables match (to be implemented) - binlog_[wild_]{do|ignore}_table?" (WL#1049)" + In the future we need to add to the following if tests like + "do the involved tables match (to be implemented) + binlog_[wild_]{do|ignore}_table?" (WL#1049)" */ + const char *local_db= event_info->get_db(); if ((thd && !(thd->options & OPTION_BIN_LOG)) || (!binlog_filter->db_ok(local_db))) { @@ -3677,7 +3715,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) } #endif /* HAVE_REPLICATION */ -#if defined(USING_TRANSACTIONS) && defined(HAVE_ROW_BASED_REPLICATION) +#if defined(USING_TRANSACTIONS) /* Should we write to the binlog cache or to the binlog on disk? Write to the binlog cache if: @@ -3712,7 +3750,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) LOCK_log. */ } -#endif /* USING_TRANSACTIONS && HAVE_ROW_BASED_REPLICATION */ +#endif /* USING_TRANSACTIONS */ DBUG_PRINT("info",("event type: %d",event_info->get_type_code())); /* @@ -3854,7 +3892,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) #ifdef HAVE_REPLICATION if (expire_logs_days) { - long purge_time= time(0) - expire_logs_days*24*60*60; + long purge_time= (long) (time(0) - expire_logs_days*24*60*60); if (purge_time >= 0) purge_logs_before_date(purge_time); } @@ -3875,12 +3913,48 @@ uint MYSQL_BIN_LOG::next_file_id() /* + Write the contents of a cache to the binary log. + + SYNOPSIS + write_cache() + cache Cache to write to the binary log + lock_log True if the LOCK_log mutex should be aquired, false otherwise + sync_log True if the log should be flushed and sync:ed + + DESCRIPTION + Write the contents of the cache to the binary log. The cache will + be reset as a READ_CACHE to be able to read the contents from it. + */ + +int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) +{ + Mutex_sentry sentry(lock_log ? &LOCK_log : NULL); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + return ER_ERROR_ON_WRITE; + uint bytes= my_b_bytes_in_cache(cache); + do + { + if (my_b_write(&log_file, cache->read_pos, bytes)) + return ER_ERROR_ON_WRITE; + cache->read_pos= cache->read_end; + } while ((bytes= my_b_fill(cache))); + + if (sync_log) + flush_and_sync(); + + return 0; // All OK +} + +/* Write a cached log entry to the binary log SYNOPSIS write() thd cache The cache to copy to the binlog + commit_event The commit event to print after writing the + contents of the cache. NOTE - We only come here if there is something in the cache. @@ -3905,8 +3979,6 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) if (likely(is_open())) // Should always be true { - uint length; - /* We only bother to write to the binary log if there is anything to write. @@ -3940,25 +4012,12 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) if (qinfo.write(&log_file)) goto err; } - /* Read from the file used to cache the queries .*/ - if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) - goto err; - length=my_b_bytes_in_cache(cache); - DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;); - do - { - /* Write data to the binary log file */ - if (my_b_write(&log_file, cache->read_pos, length)) - goto err; - cache->read_pos=cache->read_end; // Mark buffer used up - DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;); - } while ((length=my_b_fill(cache))); + if ((write_error= write_cache(cache, false, false))) + goto err; + if (commit_event && commit_event->write(&log_file)) goto err; -#ifndef DBUG_OFF - DBUG_skip_commit: -#endif if (flush_and_sync()) goto err; DBUG_EXECUTE_IF("half_binlogged_transaction", abort();); @@ -4618,21 +4677,34 @@ int TC_LOG_MMAP::overflow() } /* - all access to active page is serialized but it's not a problem, as - we're assuming that fsync() will be a main bottleneck. - That is, parallelizing writes to log pages we'll decrease number of - threads waiting for a page, but then all these threads will be waiting - for a fsync() anyway + Record that transaction XID is committed on the persistent storage + + NOTES + This function is called in the middle of two-phase commit: + First all resources prepare the transaction, then tc_log->log() is called, + then all resources commit the transaction, then tc_log->unlog() is called. + + All access to active page is serialized but it's not a problem, as + we're assuming that fsync() will be a main bottleneck. + That is, parallelizing writes to log pages we'll decrease number of + threads waiting for a page, but then all these threads will be waiting + for a fsync() anyway + + IMPLEMENTATION + If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and + records XID in a special Xid_log_event. + If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped + log. RETURN - 0 - error - otherwise - "cookie", a number that will be passed as an argument - to unlog() call. tc_log can define it any way it wants, - and use for whatever purposes. TC_LOG_MMAP sets it - to the position in memory where xid was logged to. + 0 Error + # "cookie", a number that will be passed as an argument + to unlog() call. tc_log can define it any way it wants, + and use for whatever purposes. TC_LOG_MMAP sets it + to the position in memory where xid was logged to. */ -int TC_LOG_MMAP::log(THD *thd, my_xid xid) +int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) { int err; PAGE *p; @@ -4741,6 +4813,7 @@ int TC_LOG_MMAP::sync() erase xid from the page, update page free space counters/pointers. cookie points directly to the memory where xid was logged */ + void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) { PAGE *p=pages+(cookie/tc_log_page_size); @@ -4983,7 +5056,7 @@ void TC_LOG_BINLOG::close() 0 - error 1 - success */ -int TC_LOG_BINLOG::log(THD *thd, my_xid xid) +int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid) { DBUG_ENTER("TC_LOG_BINLOG::log"); Xid_log_event xle(thd, xid); diff --git a/sql/log.h b/sql/log.h index f481d3448e0..80aa4b20ee6 100644 --- a/sql/log.h +++ b/sql/log.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -34,7 +33,7 @@ class TC_LOG virtual int open(const char *opt_name)=0; virtual void close()=0; - virtual int log(THD *thd, my_xid xid)=0; + virtual int log_xid(THD *thd, my_xid xid)=0; virtual void unlog(ulong cookie, my_xid xid)=0; }; @@ -44,7 +43,7 @@ public: TC_LOG_DUMMY() {} int open(const char *opt_name) { return 0; } void close() { } - int log(THD *thd, my_xid xid) { return 1; } + int log_xid(THD *thd, my_xid xid) { return 1; } void unlog(ulong cookie, my_xid xid) { } }; @@ -89,7 +88,7 @@ class TC_LOG_MMAP: public TC_LOG TC_LOG_MMAP(): inited(0) {} int open(const char *opt_name); void close(); - int log(THD *thd, my_xid xid); + int log_xid(THD *thd, my_xid xid); void unlog(ulong cookie, my_xid xid); int recover(); @@ -288,7 +287,7 @@ public: int open(const char *opt_name); void close(); - int log(THD *thd, my_xid xid); + int log_xid(THD *thd, my_xid xid); void unlog(ulong cookie, my_xid xid); int recover(IO_CACHE *log, Format_description_log_event *fdle); #if !defined(MYSQL_CLIENT) @@ -340,6 +339,8 @@ public: bool write(Log_event* event_info); // binary log write bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event); + int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync); + void start_union_events(THD *thd); void stop_union_events(THD *thd); bool is_query_in_union(THD *thd, query_id_t query_id_param); @@ -603,14 +604,12 @@ public: enum enum_binlog_format { BINLOG_FORMAT_STMT= 0, // statement-based -#ifdef HAVE_ROW_BASED_REPLICATION BINLOG_FORMAT_ROW= 1, // row_based /* statement-based except for cases where only row-based can work (UUID() etc): */ BINLOG_FORMAT_MIXED= 2, -#endif /* This value is last, after the end of binlog_format_typelib: it has no corresponding cell in this typelib. We use this value to be able to know if diff --git a/sql/log_event.cc b/sql/log_event.cc index 44cba324a02..951cf72d653 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -140,22 +139,6 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len) } #endif /* MYSQL_CLIENT */ -#ifdef HAVE_purify -static void -valgrind_check_mem(void *ptr, size_t len) -{ - static volatile uchar dummy; - for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p) - { - int const c = *p; - if (c < 128) - dummy= c + 1; - else - dummy = c - 1; - } -} -#endif - #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) static void clear_all_errors(THD *thd, struct st_relay_log_info *rli) @@ -373,7 +356,7 @@ append_query_string(CHARSET_INFO *csinfo, else { *ptr++= '\''; - ptr+= escape_string_for_mysql(from->charset(), ptr, 0, + ptr+= escape_string_for_mysql(csinfo, ptr, 0, from->ptr(), from->length()); *ptr++='\''; } @@ -382,12 +365,14 @@ append_query_string(CHARSET_INFO *csinfo, } #endif + /* Prints a "session_var=value" string. Used by mysqlbinlog to print some SET commands just before it prints a query. */ #ifdef MYSQL_CLIENT + static void print_set_option(IO_CACHE* file, uint32 bits_changed, uint32 option, uint32 flags, const char* name, bool* need_comma) @@ -994,7 +979,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, case FORMAT_DESCRIPTION_EVENT: ev = new Format_description_log_event(buf, event_len, description_event); break; -#if defined(HAVE_REPLICATION) && defined(HAVE_ROW_BASED_REPLICATION) +#if defined(HAVE_REPLICATION) case WRITE_ROWS_EVENT: ev = new Write_rows_log_event(buf, event_len, description_event); break; @@ -1163,7 +1148,6 @@ void Log_event::print_base64(IO_CACHE* file, { const uchar *ptr= (const uchar *)temp_buf; uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET); - DBUG_ENTER("Log_event::print_base64"); size_t const tmp_str_sz= base64_needed_encoded_length((int) size); @@ -1174,8 +1158,10 @@ void Log_event::print_base64(IO_CACHE* file, DBUG_VOID_RETURN; } - int const res= base64_encode(ptr, (size_t) size, tmp_str); - DBUG_ASSERT(res == 0); + if (base64_encode(ptr, (size_t) size, tmp_str)) + { + DBUG_ASSERT(0); + } if (my_b_tell(file) == 0) my_b_printf(file, "\nBINLOG '\n"); @@ -1183,7 +1169,7 @@ void Log_event::print_base64(IO_CACHE* file, my_b_printf(file, "%s\n", tmp_str); if (!more) - my_b_printf(file, "';\n"); + my_b_printf(file, "'%s\n", print_event_info->delimiter); my_free(tmp_str, MYF(0)); DBUG_VOID_RETURN; @@ -1289,7 +1275,8 @@ bool Query_log_event::write(IO_CACHE* file) 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog 1+4+ // code of autoinc and the 2 autoinc variables 1+6+ // code of charset and charset - 1+1+MAX_TIME_ZONE_NAME_LENGTH // code of tz and tz length and tz name + 1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name + 1+2 // code of lc_time_names and lc_time_names_number ], *start, *start_of_status; ulong event_length; @@ -1401,6 +1388,13 @@ bool Query_log_event::write(IO_CACHE* file) memcpy(start, time_zone_str, time_zone_len); start+= time_zone_len; } + if (lc_time_names_number) + { + DBUG_ASSERT(lc_time_names_number <= 0xFFFF); + *start++= Q_LC_TIME_NAMES_CODE; + int2store(start, lc_time_names_number); + start+= 2; + } /* Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) @@ -1465,7 +1459,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, flags2_inited(1), sql_mode_inited(1), charset_inited(1), sql_mode(thd_arg->variables.sql_mode), auto_increment_increment(thd_arg->variables.auto_increment_increment), - auto_increment_offset(thd_arg->variables.auto_increment_offset) + auto_increment_offset(thd_arg->variables.auto_increment_offset), + lc_time_names_number(thd_arg->variables.lc_time_names->number) { time_t end_time; time(&end_time); @@ -1507,23 +1502,30 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* 2 utility functions for the next method */ -static void get_str_len_and_pointer(const char **dst, const char **src, uint *len) +/* + Get the pointer for a string (src) that contains the length in + the first byte. Set the output string (dst) to the string value + and place the length of the string in the byte after the string. +*/ +static void get_str_len_and_pointer(const Log_event::Byte **src, + const char **dst, + uint *len) { if ((*len= **src)) - *dst= *src + 1; // Will be copied later - (*src)+= *len+1; + *dst= (char *)*src + 1; // Will be copied later + (*src)+= *len + 1; } - -static void copy_str_and_move(char **dst, const char **src, uint len) +static void copy_str_and_move(const char **src, + Log_event::Byte **dst, + uint len) { memcpy(*dst, *src, len); - *src= *dst; + *src= (const char *)*dst; (*dst)+= len; *(*dst)++= 0; } - /* Query_log_event::Query_log_event() This is used by the SQL slave thread to prepare the event before execution. @@ -1536,13 +1538,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db(NullS), catalog_len(0), status_vars_len(0), flags2_inited(0), sql_mode_inited(0), charset_inited(0), auto_increment_increment(1), auto_increment_offset(1), - time_zone_len(0) + time_zone_len(0), lc_time_names_number(0) { ulong data_len; uint32 tmp; uint8 common_header_len, post_header_len; - char *start; - const char *end; + Log_event::Byte *start; + const Log_event::Byte *end; bool catalog_nz= 1; DBUG_ENTER("Query_log_event::Query_log_event(char*,...)"); @@ -1588,9 +1590,9 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, /* variable-part: the status vars; only in MySQL 5.0 */ - start= (char*) (buf+post_header_len); - end= (const char*) (start+status_vars_len); - for (const uchar* pos= (const uchar*) start; pos < (const uchar*) end;) + start= (Log_event::Byte*) (buf+post_header_len); + end= (const Log_event::Byte*) (start+status_vars_len); + for (const Log_event::Byte* pos= start; pos < end;) { switch (*pos++) { case Q_FLAGS2_CODE: @@ -1612,7 +1614,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, break; } case Q_CATALOG_NZ_CODE: - get_str_len_and_pointer(&catalog, (const char **)(&pos), &catalog_len); + get_str_len_and_pointer(&pos, &catalog, &catalog_len); break; case Q_AUTO_INCREMENT: auto_increment_increment= uint2korr(pos); @@ -1628,7 +1630,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } case Q_TIME_ZONE_CODE: { - get_str_len_and_pointer(&time_zone_str, (const char **)(&pos), &time_zone_len); + get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len); break; } case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */ @@ -1637,6 +1639,10 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, pos+= catalog_len+2; // leap over end 0 catalog_nz= 0; // catalog has end 0 in event break; + case Q_LC_TIME_NAMES_CODE: + lc_time_names_number= uint2korr(pos); + pos+= 2; + break; default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -1646,38 +1652,38 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } #if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + - time_zone_len + 1 + - data_len + 1 + - QUERY_CACHE_FLAGS_SIZE + - db_len + 1, - MYF(MY_WME)))) + if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + data_len + 1 + + QUERY_CACHE_FLAGS_SIZE + + db_len + 1, + MYF(MY_WME)))) #else - if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + - time_zone_len + 1 + - data_len + 1, - MYF(MY_WME)))) + if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + data_len + 1, + MYF(MY_WME)))) #endif DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3. - copy_str_and_move(&start, &catalog, catalog_len); + copy_str_and_move(&catalog, &start, catalog_len); else { memcpy(start, catalog, catalog_len+1); // copy end 0 - catalog= start; + catalog= (const char *)start; start+= catalog_len+1; } } if (time_zone_len) - copy_str_and_move(&start, &time_zone_str, time_zone_len); + copy_str_and_move(&time_zone_str, &start, time_zone_len); /* A 2nd variable part; this is common to all versions */ memcpy((char*) start, end, data_len); // Copy db and query start[data_len]= '\0'; // End query with \0 (For safetly) - db= start; - query= start + db_len + 1; + db= (char *)start; + query= (char *)(start + db_len + 1); q_len= data_len - db_len -1; DBUG_VOID_RETURN; } @@ -1709,15 +1715,16 @@ void Query_log_event::print_query_header(IO_CACHE* file, if (different_db= memcmp(print_event_info->db, db, db_len + 1)) memcpy(print_event_info->db, db, db_len + 1); if (db[0] && different_db) - my_b_printf(file, "use %s;\n", db); + my_b_printf(file, "use %s%s\n", db, print_event_info->delimiter); } end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10); - *end++=';'; + end= strmov(end, print_event_info->delimiter); *end++='\n'; my_b_write(file, (byte*) buff, (uint) (end-buff)); if (flags & LOG_EVENT_THREAD_SPECIFIC_F) - my_b_printf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id); + my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n", + (ulong)thread_id, print_event_info->delimiter); /* If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to @@ -1746,7 +1753,7 @@ void Query_log_event::print_query_header(IO_CACHE* file, "@@session.sql_auto_is_null", &need_comma); print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2, "@@session.unique_checks", &need_comma); - my_b_printf(file,";\n"); + my_b_printf(file,"%s\n", print_event_info->delimiter); print_event_info->flags2= flags2; } } @@ -1774,15 +1781,17 @@ void Query_log_event::print_query_header(IO_CACHE* file, } if (unlikely(print_event_info->sql_mode != sql_mode)) { - my_b_printf(file,"SET @@session.sql_mode=%lu;\n",(ulong)sql_mode); + my_b_printf(file,"SET @@session.sql_mode=%lu%s\n", + (ulong)sql_mode, print_event_info->delimiter); print_event_info->sql_mode= sql_mode; } } if (print_event_info->auto_increment_increment != auto_increment_increment || print_event_info->auto_increment_offset != auto_increment_offset) { - my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu;\n", - auto_increment_increment,auto_increment_offset); + my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n", + auto_increment_increment,auto_increment_offset, + print_event_info->delimiter); print_event_info->auto_increment_increment= auto_increment_increment; print_event_info->auto_increment_offset= auto_increment_offset; } @@ -1802,16 +1811,18 @@ void Query_log_event::print_query_header(IO_CACHE* file, if (cs_info) { /* for mysql client */ - my_b_printf(file, "/*!\\C %s */;\n", cs_info->csname); + my_b_printf(file, "/*!\\C %s */%s\n", + cs_info->csname, print_event_info->delimiter); } my_b_printf(file,"SET " "@@session.character_set_client=%d," "@@session.collation_connection=%d," "@@session.collation_server=%d" - ";\n", + "%s\n", uint2korr(charset), uint2korr(charset+2), - uint2korr(charset+4)); + uint2korr(charset+4), + print_event_info->delimiter); memcpy(print_event_info->charset, charset, 6); } } @@ -1819,10 +1830,17 @@ void Query_log_event::print_query_header(IO_CACHE* file, { if (bcmp(print_event_info->time_zone_str, time_zone_str, time_zone_len+1)) { - my_b_printf(file,"SET @@session.time_zone='%s';\n", time_zone_str); + my_b_printf(file,"SET @@session.time_zone='%s'%s\n", + time_zone_str, print_event_info->delimiter); memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1); } } + if (lc_time_names_number != print_event_info->lc_time_names_number) + { + my_b_printf(file, "SET @@session.lc_time_names=%d%s\n", + lc_time_names_number, print_event_info->delimiter); + print_event_info->lc_time_names_number= lc_time_names_number; + } } @@ -1832,7 +1850,7 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) print_query_header(&cache, print_event_info); my_b_write(&cache, (byte*) query, q_len); - my_b_printf(&cache, ";\n"); + my_b_printf(&cache, "%s\n", print_event_info->delimiter); } #endif /* MYSQL_CLIENT */ @@ -1965,6 +1983,19 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, goto compare_errors; } } + if (lc_time_names_number) + { + if (!(thd->variables.lc_time_names= + my_locale_by_number(lc_time_names_number))) + { + my_printf_error(ER_UNKNOWN_ERROR, + "Unknown locale: '%d'", MYF(0), lc_time_names_number); + thd->variables.lc_time_names= &my_locale_en_US; + goto compare_errors; + } + } + else + thd->variables.lc_time_names= &my_locale_en_US; /* Execute the query (note that we bypass dispatch_command()) */ mysql_parse(thd, thd->query, thd->query_length); @@ -2189,9 +2220,9 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) and rollback unfinished transaction. Probably this can be done with RESET CONNECTION (syntax to be defined). */ - my_b_printf(&cache,"RESET CONNECTION;\n"); + my_b_printf(&cache,"RESET CONNECTION%s\n", print_event_info->delimiter); #else - my_b_printf(&cache,"ROLLBACK;\n"); + my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter); #endif } DBUG_VOID_RETURN; @@ -2946,15 +2977,16 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info, } if (db && db[0] && different_db) - my_b_printf(&cache, "%suse %s;\n", + my_b_printf(&cache, "%suse %s%s\n", commented ? "# " : "", - db); + db, print_event_info->delimiter); if (flags & LOG_EVENT_THREAD_SPECIFIC_F) - my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu;\n", - commented ? "# " : "", (ulong)thread_id); + my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n", + commented ? "# " : "", (ulong)thread_id, + print_event_info->delimiter); my_b_printf(&cache, "%sLOAD DATA ", - commented ? "# " : ""); + commented ? "# " : ""); if (check_fname_outside_temp_buf()) my_b_printf(&cache, "LOCAL "); my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname); @@ -3004,7 +3036,7 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info, my_b_printf(&cache, ")"); } - my_b_printf(&cache, ";\n"); + my_b_printf(&cache, "%s\n", print_event_info->delimiter); DBUG_VOID_RETURN; } #endif /* MYSQL_CLIENT */ @@ -3224,7 +3256,6 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables); set_fields(tables.db, field_list, &thd->main_lex.select_lex.context); thd->variables.pseudo_thread_id= thread_id; - List<Item> set_fields; if (net) { // mysql_load will use thd->net to read the file @@ -3235,10 +3266,11 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, thd->net.pkt_nr = net->pkt_nr; } /* - It is safe to use set_fields twice because we are not going to + It is safe to use tmp_list twice because we are not going to update it inside mysql_load(). */ - if (mysql_load(thd, &ex, &tables, field_list, set_fields, set_fields, + List<Item> tmp_list; + if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list, handle_dup, ignore, net != 0)) thd->query_error= 1; if (thd->cuted_fields) @@ -3583,7 +3615,8 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) msg="INVALID_INT"; break; } - my_b_printf(&cache, "%s=%s;\n", msg, llstr(val,llbuff)); + my_b_printf(&cache, "%s=%s%s\n", + msg, llstr(val,llbuff), print_event_info->delimiter); } #endif @@ -3661,8 +3694,9 @@ void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) print_header(&cache, print_event_info, FALSE); my_b_printf(&cache, "\tRand\n"); } - my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n", - llstr(seed1, llbuff),llstr(seed2, llbuff2)); + my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n", + llstr(seed1, llbuff),llstr(seed2, llbuff2), + print_event_info->delimiter); } #endif /* MYSQL_CLIENT */ @@ -3735,7 +3769,7 @@ void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) print_header(&cache, print_event_info, FALSE); my_b_printf(&cache, "\tXid = %s\n", buf); } - my_b_printf(&cache, "COMMIT;\n"); + my_b_printf(&cache, "COMMIT%s\n", print_event_info->delimiter); } #endif /* MYSQL_CLIENT */ @@ -3940,7 +3974,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) if (is_null) { - my_b_printf(&cache, ":=NULL;\n"); + my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter); } else { @@ -3948,12 +3982,12 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) case REAL_RESULT: double real_val; float8get(real_val, val); - my_b_printf(&cache, ":=%.14g;\n", real_val); + my_b_printf(&cache, ":=%.14g%s\n", real_val, print_event_info->delimiter); break; case INT_RESULT: char int_buf[22]; longlong10_to_str(uint8korr(val), int_buf, -10); - my_b_printf(&cache, ":=%s;\n", int_buf); + my_b_printf(&cache, ":=%s%s\n", int_buf, print_event_info->delimiter); break; case DECIMAL_RESULT: { @@ -3969,7 +4003,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) bin2decimal(val+2, &dec, precision, scale); decimal2string(&dec, str_buf, &str_len, 0, 0, 0); str_buf[str_len]= 0; - my_b_printf(&cache, ":=%s;\n",str_buf); + my_b_printf(&cache, ":=%s%s\n", str_buf, print_event_info->delimiter); break; } case STRING_RESULT: @@ -4005,9 +4039,11 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) Generate an unusable command (=> syntax error) is probably the best thing we can do here. */ - my_b_printf(&cache, ":=???;\n"); + my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter); else - my_b_printf(&cache, ":=_%s %s COLLATE `%s`;\n", cs->csname, hex_str, cs->name); + my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n", + cs->csname, hex_str, cs->name, + print_event_info->delimiter); my_afree(hex_str); } break; @@ -5109,12 +5145,12 @@ void Execute_load_query_log_event::print(FILE* file, my_b_printf(&cache, " REPLACE"); my_b_printf(&cache, " INTO"); my_b_write(&cache, (byte*) query + fn_pos_end, q_len-fn_pos_end); - my_b_printf(&cache, ";\n"); + my_b_printf(&cache, "%s\n", print_event_info->delimiter); } else { my_b_write(&cache, (byte*) query, q_len); - my_b_printf(&cache, ";\n"); + my_b_printf(&cache, "%s\n", print_event_info->delimiter); } if (!print_event_info->short_form) @@ -5288,8 +5324,6 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) } -#ifdef HAVE_ROW_BASED_REPLICATION - /************************************************************************** Rows_log_event member functions **************************************************************************/ @@ -5434,12 +5468,11 @@ int Rows_log_event::do_add_row_data(byte *const row_data, if (static_cast<my_size_t>(m_rows_end - m_rows_cur) < length) { my_size_t const block_size= 1024; - my_ptrdiff_t const old_alloc= m_rows_end - m_rows_buf; my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf; my_ptrdiff_t const new_alloc= block_size * ((cur_size + length) / block_size + block_size - 1); - byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, new_alloc, + byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, (uint) new_alloc, MYF(MY_ALLOW_ZERO_PTR|MY_WME)); if (unlikely(!new_buf)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -5558,9 +5591,9 @@ unpack_row(RELAY_LOG_INFO *rli, if (bitmap_is_set(cols, field_ptr - begin_ptr)) { - DBUG_ASSERT(table->record[0] <= f->ptr); - DBUG_ASSERT(f->ptr < (table->record[0] + table->s->reclength + - (f->pack_length_in_rec() == 0))); + DBUG_ASSERT((const char *)table->record[0] <= f->ptr); + DBUG_ASSERT(f->ptr < (char*)(table->record[0] + table->s->reclength + + (f->pack_length_in_rec() == 0))); DBUG_PRINT("info", ("unpacking column '%s' to 0x%lx", f->field_name, (long) f->ptr)); @@ -5670,9 +5703,26 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) { if (!need_reopen) { - slave_print_msg(ERROR_LEVEL, rli, error, - "Error in %s event: when locking tables", - get_type_str()); + if (thd->query_error || thd->is_fatal_error) + { + /* + Error reporting borrowed from Query_log_event with many excessive + simplifications (we don't honour --slave-skip-errors) + */ + uint actual_error= thd->net.last_errno; + slave_print_msg(ERROR_LEVEL, rli, actual_error, + "Error '%s' in %s event: when locking tables", + (actual_error ? thd->net.last_error : + "unexpected success or fatal error"), + get_type_str()); + thd->is_fatal_error= 1; + } + else + { + slave_print_msg(ERROR_LEVEL, rli, error, + "Error in %s event: when locking tables", + get_type_str()); + } rli->clear_tables_to_lock(); DBUG_RETURN(error); } @@ -5965,7 +6015,7 @@ bool Rows_log_event::write_data_body(IO_CACHE*file) sbuf_end - sbuf) || my_b_safe_write(file, reinterpret_cast<byte*>(m_cols.bitmap), no_bytes_in_map(&m_cols)) || - my_b_safe_write(file, m_rows_buf, data_size)); + my_b_safe_write(file, m_rows_buf, (uint) data_size)); } #endif @@ -6318,8 +6368,8 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file) DBUG_ASSERT(m_dblen < 128); DBUG_ASSERT(m_tbllen < 128); - byte const dbuf[]= { m_dblen }; - byte const tbuf[]= { m_tbllen }; + byte const dbuf[]= { (byte) m_dblen }; + byte const tbuf[]= { (byte) m_tbllen }; char cbuf[sizeof(m_colcnt)]; char *const cbuf_end= net_store_length((char*) cbuf, (uint) m_colcnt); @@ -6581,12 +6631,15 @@ copy_extra_record_fields(TABLE *table, /* Nothing to do */ break; - case FIELD_TYPE_BIT: + case MYSQL_TYPE_BIT: Field_bit *f= static_cast<Field_bit*>(*field_ptr); - my_ptrdiff_t const offset= table->record[1] - table->record[0]; - uchar const bits= - get_rec_bits(f->bit_ptr + offset, f->bit_ofs, f->bit_len); - set_rec_bits(bits, f->bit_ptr, f->bit_ofs, f->bit_len); + if (f->bit_len > 0) + { + my_ptrdiff_t const offset= table->record[1] - table->record[0]; + uchar const bits= + get_rec_bits(f->bit_ptr + offset, f->bit_ofs, f->bit_len); + set_rec_bits(bits, f->bit_ptr, f->bit_ofs, f->bit_len); + } break; } } @@ -6843,8 +6896,8 @@ static int find_and_fetch_row(TABLE *table, byte *key) trigger false warnings. */ #ifndef HAVE_purify - DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength); - DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength); + DBUG_DUMP("table->record[0]", (const char *)table->record[0], table->s->reclength); + DBUG_DUMP("table->record[1]", (const char *)table->record[1], table->s->reclength); #endif /* @@ -6870,8 +6923,8 @@ static int find_and_fetch_row(TABLE *table, byte *key) trigger false warnings. */ #ifndef HAVE_purify - DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength); - DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength); + DBUG_DUMP("table->record[0]", (const char *)table->record[0], table->s->reclength); + DBUG_DUMP("table->record[1]", (const char *)table->record[1], table->s->reclength); #endif /* Below is a minor "optimization". If the key (i.e., key number @@ -7287,4 +7340,3 @@ void Update_rows_log_event::print(FILE *file, } #endif -#endif /* defined(HAVE_ROW_BASED_REPLICATION) */ diff --git a/sql/log_event.h b/sql/log_event.h index 4b74bf7c7ee..5994beb0df3 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -271,6 +270,8 @@ struct sql_ex_info */ #define Q_CATALOG_NZ_CODE 6 +#define Q_LC_TIME_NAMES_CODE 7 + /* Intvar event post-header */ #define I_TYPE_OFFSET 0 @@ -423,12 +424,18 @@ struct sql_ex_info either, as the manual says (because a too big in-memory temp table is automatically written to disk). */ -#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \ -OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS) +#define OPTIONS_WRITTEN_TO_BIN_LOG \ + (OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \ + OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT) + +/* Shouldn't be defined before */ +#define EXPECTED_OPTIONS \ + ((ULL(1) << 14) | (ULL(1) << 26) | (ULL(1) << 27) | (ULL(1) << 19)) -#if OPTIONS_WRITTEN_TO_BIN_LOG != ((1L << 14) | (1L << 26) | (1L << 27)) +#if OPTIONS_WRITTEN_TO_BIN_LOG != EXPECTED_OPTIONS #error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values! #endif +#undef EXPECTED_OPTIONS /* You shouldn't use this one */ enum Log_event_type { @@ -525,9 +532,11 @@ typedef struct st_print_event_info bool charset_inited; char charset[6]; // 3 variables, each of them storable in 2 bytes char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH]; + uint lc_time_names_number; st_print_event_info() :flags2_inited(0), sql_mode_inited(0), - auto_increment_increment(1),auto_increment_offset(1), charset_inited(0) + auto_increment_increment(1),auto_increment_offset(1), charset_inited(0), + lc_time_names_number(0) { /* Currently we only use static PRINT_EVENT_INFO objects, so zeroed at @@ -537,6 +546,7 @@ typedef struct st_print_event_info bzero(db, sizeof(db)); bzero(charset, sizeof(charset)); bzero(time_zone_str, sizeof(time_zone_str)); + strcpy(delimiter, ";"); uint const flags = MYF(MY_WME | MY_NABP); init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags); init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags); @@ -553,6 +563,7 @@ typedef struct st_print_event_info bool base64_output; my_off_t hexdump_from; uint8 common_header_len; + char delimiter[16]; /* These two caches are used by the row-based replication events to @@ -576,6 +587,13 @@ class Log_event { public: /* + The following type definition is to be used whenever data is placed + and manipulated in a common buffer. Use this typedef for buffers + that contain data containing binary and character data. + */ + typedef unsigned char Byte; + + /* The offset in the log where this event originally appeared (it is preserved in relay logs, making SHOW SLAVE STATUS able to print coordinates of the event in the master's binlog). Note: when a @@ -756,7 +774,7 @@ public: class Query_log_event: public Log_event { protected: - char* data_buf; + Log_event::Byte* data_buf; public: const char* query; const char* catalog; @@ -827,6 +845,7 @@ public: char charset[6]; uint time_zone_len; /* 0 means uninited */ const char *time_zone_str; + uint lc_time_names_number; /* 0 means en_US */ #ifndef MYSQL_CLIENT @@ -1691,8 +1710,6 @@ public: #endif char *str_to_hex(char *to, const char *from, uint len); -#ifdef HAVE_ROW_BASED_REPLICATION - /***************************************************************************** Table map log event class @@ -2021,7 +2038,7 @@ public: Write_rows_log_event(const char *buf, uint event_len, const Format_description_log_event *description_event); #endif -#if !defined(MYSQL_CLIENT) && defined(HAVE_ROW_BASED_REPLICATION) +#if !defined(MYSQL_CLIENT) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, MY_BITMAP *cols, @@ -2086,7 +2103,7 @@ public: const Format_description_log_event *description_event); #endif -#if !defined(MYSQL_CLIENT) && defined(HAVE_ROW_BASED_REPLICATION) +#if !defined(MYSQL_CLIENT) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, MY_BITMAP *cols, @@ -2156,7 +2173,7 @@ public: Delete_rows_log_event(const char *buf, uint event_len, const Format_description_log_event *description_event); #endif -#if !defined(MYSQL_CLIENT) && defined(HAVE_ROW_BASED_REPLICATION) +#if !defined(MYSQL_CLIENT) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, MY_BITMAP *cols, @@ -2190,6 +2207,4 @@ private: #endif }; -#endif /* HAVE_ROW_BASED_REPLICATION */ - #endif /* _log_event_h */ diff --git a/sql/matherr.c b/sql/matherr.c index ea0c15d2feb..4998d8b4961 100644 --- a/sql/matherr.c +++ b/sql/matherr.c @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index 71c8d588de7..f237f15dbc9 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 30a271df064..511942e9a5d 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 9e2dea26700..cefc5ee00fd 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/my_lock.c b/sql/my_lock.c index 69884df22f8..f66d7282f72 100644 --- a/sql/my_lock.c +++ b/sql/my_lock.c @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 82e71f59b2c..755f7c80fc2 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -36,8 +35,10 @@ #include <signal.h> #include <thr_lock.h> #include <my_base.h> /* Needed by field.h */ +#include <queues.h> #include "sql_bitmap.h" #include "sql_array.h" +#include "scheduler.h" /* TODO convert all these three maps to Bitmap classes */ typedef ulonglong table_map; /* Used for table bits in join */ @@ -57,10 +58,10 @@ typedef ulonglong nested_join_map; /* query_id */ typedef ulonglong query_id_t; -extern query_id_t query_id; +extern query_id_t global_query_id; /* increment query_id and return it. */ -inline query_id_t next_query_id() { return query_id++; } +inline query_id_t next_query_id() { return global_query_id++; } /* useful constants */ extern const key_map key_map_empty; @@ -87,6 +88,9 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); +void net_set_write_timeout(NET *net, uint timeout); +void net_set_read_timeout(NET *net, uint timeout); + #define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); } #define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } } #define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1)) @@ -118,6 +122,7 @@ enum Derivation typedef struct my_locale_st { + uint number; const char *name; const char *description; const bool is_ascii; @@ -126,9 +131,11 @@ typedef struct my_locale_st TYPELIB *day_names; TYPELIB *ab_day_names; #ifdef __cplusplus - my_locale_st(const char *name_par, const char *descr_par, bool is_ascii_par, + my_locale_st(uint number_par, + const char *name_par, const char *descr_par, bool is_ascii_par, TYPELIB *month_names_par, TYPELIB *ab_month_names_par, TYPELIB *day_names_par, TYPELIB *ab_day_names_par) : + number(number_par), name(name_par), description(descr_par), is_ascii(is_ascii_par), month_names(month_names_par), ab_month_names(ab_month_names_par), day_names(day_names_par), ab_day_names(ab_day_names_par) @@ -140,6 +147,7 @@ extern MY_LOCALE my_locale_en_US; extern MY_LOCALE *my_locales[]; MY_LOCALE *my_locale_by_name(const char *name); +MY_LOCALE *my_locale_by_number(uint number); /*************************************************************************** Configuration parameters @@ -163,7 +171,7 @@ MY_LOCALE *my_locale_by_name(const char *name); Feel free to raise this by the smallest amount you can to get the "execution_constants" test to pass. */ -#define STACK_MIN_SIZE 10788 // Abort if less stack during eval. +#define STACK_MIN_SIZE 12000 // Abort if less stack during eval. #define STACK_MIN_SIZE_FOR_OPEN 1024*80 #define STACK_BUFF_ALLOC 256 // For stack overrun checks @@ -275,7 +283,6 @@ MY_LOCALE *my_locale_by_name(const char *name); #define TEST_MIT_THREAD 4 #define TEST_BLOCKING 8 #define TEST_KEEP_TMP_TABLES 16 -#define TEST_NO_THREADS 32 /* For debugging under Linux */ #define TEST_READCHECK 64 /* Force use of readcheck */ #define TEST_NO_EXTRA 128 #define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */ @@ -303,54 +310,55 @@ MY_LOCALE *my_locale_by_name(const char *name); TODO: separate three contexts above, move them to separate bitfields. */ -#define SELECT_DISTINCT (LL(1) << 0) // SELECT, user -#define SELECT_STRAIGHT_JOIN (LL(1) << 1) // SELECT, user -#define SELECT_DESCRIBE (LL(1) << 2) // SELECT, user -#define SELECT_SMALL_RESULT (LL(1) << 3) // SELECT, user -#define SELECT_BIG_RESULT (LL(1) << 4) // SELECT, user -#define OPTION_FOUND_ROWS (LL(1) << 5) // SELECT, user -#define OPTION_TO_QUERY_CACHE (LL(1) << 6) // SELECT, user -#define SELECT_NO_JOIN_CACHE (LL(1) << 7) // intern -#define OPTION_BIG_TABLES (LL(1) << 8) // THD, user -#define OPTION_BIG_SELECTS (LL(1) << 9) // THD, user -#define OPTION_LOG_OFF (LL(1) << 10) // THD, user -#define OPTION_QUOTE_SHOW_CREATE (LL(1) << 11) // THD, user -#define TMP_TABLE_ALL_COLUMNS (LL(1) << 12) // SELECT, intern -#define OPTION_WARNINGS (LL(1) << 13) // THD, user -#define OPTION_AUTO_IS_NULL (LL(1) << 14) // THD, user, binlog -#define OPTION_FOUND_COMMENT (LL(1) << 15) // SELECT, intern, parser -#define OPTION_SAFE_UPDATES (LL(1) << 16) // THD, user -#define OPTION_BUFFER_RESULT (LL(1) << 17) // SELECT, user -#define OPTION_BIN_LOG (LL(1) << 18) // THD, user -#define OPTION_NOT_AUTOCOMMIT (LL(1) << 19) // THD, user -#define OPTION_BEGIN (LL(1) << 20) // THD, intern -#define OPTION_TABLE_LOCK (LL(1) << 21) // THD, intern -#define OPTION_QUICK (LL(1) << 22) // SELECT (for DELETE) -#define OPTION_KEEP_LOG (LL(1) << 23) // Keep binlog on rollback +#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user +#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user +#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user +#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user +#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user +#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user +#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user +#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern +#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user +#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user +#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user +#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 11) // THD, user, unused +#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern +#define OPTION_WARNINGS (ULL(1) << 13) // THD, user +#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog +#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser +#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user +#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user +#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user +#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user +#define OPTION_BEGIN (ULL(1) << 20) // THD, intern +#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern +#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE) +#define OPTION_KEEP_LOG (ULL(1) << 23) // THD, user /* The following is used to detect a conflict with DISTINCT */ -#define SELECT_ALL (LL(1) << 24) // SELECT, user, parser +#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser /* Set if we are updating a non-transaction safe table */ -#define OPTION_STATUS_NO_TRANS_UPDATE (LL(1) << 25) // THD, intern +#define OPTION_STATUS_NO_TRANS_UPDATE (ULL(1) << 25) // THD, intern /* The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ -#define OPTION_NO_FOREIGN_KEY_CHECKS (LL(1) << 26) // THD, user, binlog +#define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog /* The following speeds up inserts to InnoDB tables by suppressing unique key checks in some cases */ -#define OPTION_RELAXED_UNIQUE_CHECKS (LL(1) << 27) // THD, user, binlog -#define SELECT_NO_UNLOCK (LL(1) << 28) // SELECT, intern -#define OPTION_SCHEMA_TABLE (LL(1) << 29) // SELECT, intern +#define OPTION_RELAXED_UNIQUE_CHECKS (ULL(1) << 27) // THD, user, binlog +#define SELECT_NO_UNLOCK (ULL(1) << 28) // SELECT, intern +#define OPTION_SCHEMA_TABLE (ULL(1) << 29) // SELECT, intern /* Flag set if setup_tables already done */ -#define OPTION_SETUP_TABLES_DONE (LL(1) << 30) // intern +#define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ -#define OPTION_SQL_NOTES (LL(1) << 31) // THD, user -/* +#define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user +/* Force the used temporary table to be a MyISAM table (because we will use fulltext functions when reading from it. */ -#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32) +#define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32) + /* Maximum length of time zone name that we support @@ -416,7 +424,11 @@ MY_LOCALE *my_locale_by_name(const char *name); #define UNCACHEABLE_EXPLAIN 8 /* Don't evaluate subqueries in prepare even if they're not correlated */ #define UNCACHEABLE_PREPARE 16 +/* For uncorrelated SELECT in an UNION with some correlated SELECTs */ +#define UNCACHEABLE_UNITED 32 +/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ +#define UNDEF_POS (-1) #ifdef EXTRA_DEBUG /* Sync points allow us to force the server to reach a certain line of code @@ -624,6 +636,7 @@ Item *negate_expression(THD *thd, Item *expr); #include "sql_acl.h" #include "tztime.h" #ifdef MYSQL_SERVER +#include "sql_servers.h" #include "opt_range.h" #ifdef HAVE_QUERY_CACHE @@ -774,6 +787,23 @@ uint build_table_path(char *buff, size_t bufflen, const char *db, void write_bin_log(THD *thd, bool clear_error, char const *query, ulong query_length); +/* sql_connect.cc */ +int check_user(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count); +pthread_handler_t handle_one_connection(void *arg); +bool init_new_connection_handler_thread(); +void reset_mqh(LEX_USER *lu, bool get_them); +bool check_mqh(THD *thd, uint check_command); +void time_out_user_resource_limits(THD *thd, USER_CONN *uc); +int check_for_max_user_connections(THD *thd, USER_CONN *uc); +void decrease_user_connections(USER_CONN *uc); +void thd_init_client_charset(THD *thd, uint cs_number); +bool setup_connection_thread_globals(THD *thd); +bool login_connection(THD *thd); +void prepare_new_connection_state(THD* thd); +void end_connection(THD *thd); + bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); @@ -809,16 +839,14 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); void free_max_user_conn(void); -pthread_handler_t handle_one_connection(void *arg); pthread_handler_t handle_bootstrap(void *arg); -void end_thread(THD *thd,bool put_in_cache); -void flush_thread_cache(); bool mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); bool check_dup(const char *db, const char *name, TABLE_LIST *tables); +bool compare_record(TABLE *table); bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); @@ -1088,7 +1116,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); -bool get_schema_tables_result(JOIN *join); +bool get_schema_tables_result(JOIN *join, + enum enum_schema_table_state executed_place); #define is_schema_db(X) \ !my_strcasecmp(system_charset_info, information_schema_name.str, (X)) @@ -1142,7 +1171,8 @@ bool push_new_name_resolution_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op); void add_join_on(TABLE_LIST *b,Item *expr); -void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields); +void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields, + SELECT_LEX *lex); bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); void update_non_unique_table_error(TABLE_LIST *update, @@ -1478,6 +1508,12 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, /* mysqld.cc */ extern void MYSQLerror(const char*); void refresh_status(THD *thd); +my_bool mysql_rm_tmp_tables(void); +void handle_connection_in_main_thread(THD *thd); +void create_thread_to_handle_connection(THD *thd); +void unlink_thd(THD *thd); +bool one_thread_per_connection_end(THD *thd, bool put_in_cache); +void flush_thread_cache(); /* item_func.cc */ extern bool check_reserved_words(LEX_STRING *name); @@ -1512,7 +1548,7 @@ extern int creating_table; // How many mysql_create_table() are running External variables */ -extern time_t start_time; +extern time_t server_start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[], def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; @@ -1522,7 +1558,7 @@ extern const LEX_STRING command_name[]; extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword; extern const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; -extern const char *in_left_expr_name, *in_additional_cond; +extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond; extern const char * const triggers_file_ext; extern const char * const trigname_file_ext; extern Eq_creator eq_creator; @@ -1537,6 +1573,7 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; extern char log_error_file[FN_REFLEN], *opt_tc_log_file; extern double log_10[32]; +extern double log_01[32]; extern ulonglong log_10_int[20]; extern ulonglong keybuff_size; extern ulonglong thd_startup_options; @@ -1559,10 +1596,8 @@ extern ulong query_buff_size; extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; -#ifdef HAVE_ROW_BASED_REPLICATION extern ulong opt_binlog_rows_event_max_size; -#endif -extern ulong rpl_recovery_rank, thread_cache_size; +extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size; extern ulong back_log; extern ulong specialflag, current_pid; extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter; @@ -1647,6 +1682,9 @@ extern TABLE *unused_tables; extern const char* any_db; extern struct my_option my_long_options[]; extern const LEX_STRING view_type; +extern scheduler_functions thread_scheduler; +extern TYPELIB thread_handling_typelib; +extern uint8 uc_update_queries[SQLCOM_END+1]; extern uint sql_command_flags[]; extern TYPELIB log_output_typelib; @@ -1661,7 +1699,6 @@ extern handlerton *partition_hton; extern handlerton *myisam_hton; extern handlerton *heap_hton; -extern SHOW_COMP_OPTION have_row_based_replication; extern SHOW_COMP_OPTION have_openssl, have_symlink, have_dlopen; extern SHOW_COMP_OPTION have_query_cache; extern SHOW_COMP_OPTION have_geometry, have_rtree_keys; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d3cada2405f..4b722479516 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,9 +31,7 @@ #include "../storage/maria/ha_maria.h" #endif -#ifdef HAVE_ROW_BASED_REPLICATION #include "rpl_injector.h" -#endif #ifdef WITH_INNOBASE_STORAGE_ENGINE #define OPT_INNODB_DEFAULT 1 @@ -54,6 +51,10 @@ #define OPT_NDBCLUSTER_DEFAULT 0 #endif +#ifndef DEFAULT_SKIP_THREAD_PRIORITY +#define DEFAULT_SKIP_THREAD_PRIORITY 0 +#endif + #include <thr_alarm.h> #include <ft_global.h> #include <errmsg.h> @@ -62,10 +63,6 @@ #define mysqld_charset &my_charset_latin1 -#ifndef DBUG_OFF -#define ONE_THREAD -#endif - #ifdef HAVE_purify #define IF_PURIFY(A,B) (A) #else @@ -285,6 +282,16 @@ static TYPELIB tc_heuristic_recover_typelib= array_elements(tc_heuristic_recover_names)-1,"", tc_heuristic_recover_names, NULL }; + +static const char *thread_handling_names[]= +{ "one-thread-per-connection", "no-threads", "pool-of-threads", NullS}; + +TYPELIB thread_handling_typelib= +{ + array_elements(thread_handling_names) - 1, "", + thread_handling_names, NULL +}; + const char *first_keyword= "first", *binary_keyword= "BINARY"; const char *my_localhost= "localhost", *delayed_user= "DELAYED"; #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) @@ -395,6 +402,7 @@ extern my_bool innobase_log_archive, innobase_use_large_pages, innobase_use_native_aio, innobase_file_per_table, innobase_locks_unsafe_for_binlog, + innobase_rollback_on_timeout, innobase_create_status_file; extern "C" { extern ulong srv_max_buf_pool_modified_pct; @@ -447,12 +455,8 @@ volatile bool mqh_used = 0; my_bool opt_noacl; my_bool sp_automatic_privileges= 1; -#ifdef HAVE_ROW_BASED_REPLICATION ulong opt_binlog_rows_event_max_size; const char *binlog_format_names[]= {"STATEMENT", "ROW", "MIXED", NullS}; -#else -const char *binlog_format_names[]= {"STATEMENT", NullS}; -#endif TYPELIB binlog_format_typelib= { array_elements(binlog_format_names)-1,"", binlog_format_names, NULL }; @@ -473,10 +477,11 @@ ulong what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout, slave_trans_retries; -ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; +ulong thread_cache_size=0, thread_pool_size= 0; +ulong binlog_cache_size=0, max_binlog_cache_size=0; ulong query_cache_size=0; ulong refresh_version, flush_version; /* Increments on each reload */ -query_id_t query_id; +query_id_t global_query_id; 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; @@ -508,7 +513,8 @@ ulong rpl_recovery_rank=0; const char *log_output_str= "TABLE"; double log_10[32]; /* 10 potences */ -time_t start_time; +double log_01[32]; +time_t server_start_time; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30]; char *default_tz_name; @@ -524,17 +530,19 @@ key_map key_map_full(0); // Will be initialized later const char *opt_date_time_formats[3]; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; -struct passwd *user_info; char server_version[SERVER_VERSION_LENGTH]; char *mysqld_unix_port, *opt_mysql_tmpdir; const char **errmesg; /* Error messages */ const char *myisam_recover_options_str="OFF"; const char *myisam_stats_method_str="nulls_unequal"; const char *maria_stats_method_str="nulls_unequal"; + /* name of reference on left espression in rewritten IN subquery */ const char *in_left_expr_name= "<left expr>"; /* name of additional condition */ const char *in_additional_cond= "<IN COND>"; +const char *in_having_cond= "<IN HAVING>"; + my_decimal decimal_zero; /* classes for comparation parsing/processing */ Eq_creator eq_creator; @@ -544,7 +552,6 @@ Lt_creator lt_creator; Ge_creator ge_creator; Le_creator le_creator; - FILE *bootstrap_file; int bootstrap_error; FILE *stderror_file=0; @@ -565,7 +572,6 @@ CHARSET_INFO *system_charset_info, *files_charset_info ; CHARSET_INFO *national_charset_info, *table_alias_charset; CHARSET_INFO *character_set_filesystem; -SHOW_COMP_OPTION have_row_based_replication; SHOW_COMP_OPTION have_openssl, have_symlink, have_dlopen, have_query_cache; SHOW_COMP_OPTION have_geometry, have_rtree_keys; SHOW_COMP_OPTION have_crypt, have_compress; @@ -628,9 +634,13 @@ static char **defaults_argv; static char *opt_bin_logname; static my_socket unix_sock,ip_sock; -static pthread_t select_thread; struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() +#ifndef EMBEDDED_LIBRARY +struct passwd *user_info; +static pthread_t select_thread; +#endif + /* OS specific variables */ #ifdef __WIN__ @@ -683,6 +693,8 @@ my_bool opt_enable_shared_memory; HANDLE smem_event_connect_request= 0; #endif +scheduler_functions thread_scheduler; + #define SSL_VARS_NOT_STATIC #include "sslopt-vars.h" #ifdef HAVE_OPENSSL @@ -707,7 +719,6 @@ struct st_VioSSLFd *ssl_acceptor_fd; /* Function declarations */ -static void start_signal_handler(void); pthread_handler_t signal_hand(void *arg); static void mysql_init_variables(void); static void get_options(int argc,char **argv); @@ -718,7 +729,6 @@ static void fix_paths(void); pthread_handler_t handle_connections_sockets(void *arg); pthread_handler_t kill_server_thread(void *arg); static void bootstrap(FILE *file); -static void close_server_sock(); static bool read_init_file(char *file_name); #ifdef __NT__ pthread_handler_t handle_connections_namedpipes(void *arg); @@ -729,11 +739,17 @@ pthread_handler_t handle_connections_shared_memory(void *arg); pthread_handler_t handle_slave(void *arg); static ulong find_bit_type(const char *x, TYPELIB *bit_lib); static void clean_up(bool print_message); +static int test_if_case_insensitive(const char *dir_name); + +#ifndef EMBEDDED_LIBRARY +static void start_signal_handler(void); +static void close_server_sock(); static void clean_up_mutexes(void); static void wait_for_signal_thread_to_end(void); -static int test_if_case_insensitive(const char *dir_name); static void create_pid_file(); static void end_ssl(); +#endif + #ifndef EMBEDDED_LIBRARY /**************************************************************************** @@ -859,6 +875,7 @@ static void close_connections(void) continue; tmp->killed= THD::KILL_CONNECTION; + thread_scheduler.post_kill_notification(tmp); if (tmp->mysys_var) { tmp->mysys_var->abort=1; @@ -923,7 +940,6 @@ static void close_connections(void) DBUG_PRINT("quit",("close_connections thread")); DBUG_VOID_RETURN; } -#endif /*EMBEDDED_LIBRARY*/ static void close_server_sock() @@ -966,12 +982,14 @@ static void close_server_sock() #endif } +#endif /*EMBEDDED_LIBRARY*/ + void kill_mysql(void) { DBUG_ENTER("kill_mysql"); -#ifdef SIGNALS_DONT_BREAK_READ +#if defined(SIGNALS_DONT_BREAK_READ) && !defined(EMBEDDED_LIBRARY) abort_loop=1; // Break connection loops close_server_sock(); // Force accept to wake up #endif @@ -1049,7 +1067,7 @@ static void __cdecl kill_server(int sig_ptr) kill_in_progress=TRUE; abort_loop=1; // This should be set if (sig != 0) // 0 is not a valid signal number - my_sigset(sig,SIG_IGN); + my_sigset(sig, SIG_IGN); /* purify inspected */ if (sig == MYSQL_KILL_SIGNAL || sig == 0) sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname); else @@ -1173,9 +1191,7 @@ void clean_up(bool print_message) what they have that is dependent on the binlog */ ha_binlog_end(current_thd); -#ifdef HAVE_ROW_BASED_REPLICATION injector::free_instance(); -#endif mysql_bin_log.cleanup(); #ifdef HAVE_REPLICATION @@ -1185,6 +1201,7 @@ void clean_up(bool print_message) my_tz_free(); my_database_names_free(); #ifndef NO_EMBEDDED_ACCESS_CHECKS + servers_free(1); acl_free(1); grant_free(); #endif @@ -1238,7 +1255,9 @@ void clean_up(bool print_message) #endif delete binlog_filter; delete rpl_filter; +#ifndef EMBEDDED_LIBRARY end_ssl(); +#endif vio_end(); #ifdef USE_REGEX my_regex_end(); @@ -1250,6 +1269,7 @@ void clean_up(bool print_message) if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist #endif + thread_scheduler.end(); finish_client_errs(); my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST), MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); @@ -1271,6 +1291,8 @@ void clean_up(bool print_message) } /* clean_up */ +#ifndef EMBEDDED_LIBRARY + /* This is mainly needed when running with purify, but it's still nice to know that all child threads have died when mysqld exits @@ -1341,6 +1363,9 @@ static void clean_up_mutexes() (void) pthread_cond_destroy(&COND_manager); } +#endif /*EMBEDDED_LIBRARY*/ + + /**************************************************************************** ** Init IP and UNIX socket ****************************************************************************/ @@ -1375,7 +1400,7 @@ static void set_ports() static struct passwd *check_user(const char *user) { #if !defined(__WIN__) && !defined(__NETWARE__) - struct passwd *user_info; + struct passwd *tmp_user_info; uid_t user_id= geteuid(); // Don't bother if we aren't superuser @@ -1383,12 +1408,14 @@ static struct passwd *check_user(const char *user) { if (user) { - // Don't give a warning, if real user is same as given with --user - user_info= getpwnam(user); - if ((!user_info || user_id != user_info->pw_uid) && + /* Don't give a warning, if real user is same as given with --user */ + /* purecov: begin tested */ + tmp_user_info= getpwnam(user); + if ((!tmp_user_info || user_id != tmp_user_info->pw_uid) && global_system_variables.log_warnings) sql_print_warning( "One can only use the --user switch if running as root\n"); + /* purecov: end */ } return NULL; } @@ -1401,23 +1428,22 @@ static struct passwd *check_user(const char *user) } return NULL; } + /* purecov: begin tested */ if (!strcmp(user,"root")) return NULL; // Avoid problem with dynamic libraries - if (!(user_info= getpwnam(user))) + if (!(tmp_user_info= getpwnam(user))) { // Allow a numeric uid to be used const char *pos; for (pos= user; my_isdigit(mysqld_charset,*pos); pos++) ; if (*pos) // Not numeric id goto err; - if (!(user_info= getpwuid(atoi(user)))) + if (!(tmp_user_info= getpwuid(atoi(user)))) goto err; - else - return user_info; } - else - return user_info; + return tmp_user_info; + /* purecov: end */ err: sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user); @@ -1426,10 +1452,11 @@ err: return NULL; } -static void set_user(const char *user, struct passwd *user_info) +static void set_user(const char *user, struct passwd *user_info_arg) { + /* purecov: begin tested */ #if !defined(__WIN__) && !defined(__NETWARE__) - DBUG_ASSERT(user_info != 0); + DBUG_ASSERT(user_info_arg != 0); #ifdef HAVE_INITGROUPS /* We can get a SIGSEGV when calling initgroups() on some systems when NSS @@ -1438,33 +1465,34 @@ static void set_user(const char *user, struct passwd *user_info) output a specific message to help the user resolve this problem. */ calling_initgroups= TRUE; - initgroups((char*) user, user_info->pw_gid); + initgroups((char*) user, user_info_arg->pw_gid); calling_initgroups= FALSE; #endif - if (setgid(user_info->pw_gid) == -1) + if (setgid(user_info_arg->pw_gid) == -1) { sql_perror("setgid"); unireg_abort(1); } - if (setuid(user_info->pw_uid) == -1) + if (setuid(user_info_arg->pw_uid) == -1) { sql_perror("setuid"); unireg_abort(1); } #endif + /* purecov: end */ } -static void set_effective_user(struct passwd *user_info) +static void set_effective_user(struct passwd *user_info_arg) { #if !defined(__WIN__) && !defined(__NETWARE__) - DBUG_ASSERT(user_info != 0); - if (setregid((gid_t)-1, user_info->pw_gid) == -1) + DBUG_ASSERT(user_info_arg != 0); + if (setregid((gid_t)-1, user_info_arg->pw_gid) == -1) { sql_perror("setregid"); unireg_abort(1); } - if (setreuid((uid_t)-1, user_info->pw_uid) == -1) + if (setreuid((uid_t)-1, user_info_arg->pw_uid) == -1) { sql_perror("setreuid"); unireg_abort(1); @@ -1501,6 +1529,9 @@ static void network_init(void) DBUG_ENTER("network_init"); LINT_INIT(ret); + if (thread_scheduler.init()) + unireg_abort(1); /* purecov: inspected */ + set_ports(); if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap) @@ -1719,21 +1750,55 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused))) if (thd && ! thd->bootstrap) { statistic_increment(killed_threads, &LOCK_status); - end_thread(thd,0); + thread_scheduler.end_thread(thd,0); /* purecov: inspected */ } DBUG_VOID_RETURN; /* purecov: deadcode */ } -void end_thread(THD *thd, bool put_in_cache) +/* + Unlink thd from global list of available connections and free thd + + SYNOPSIS + unlink_thd() + thd Thread handler + + NOTES + LOCK_thread_count is locked and left locked +*/ + +void unlink_thd(THD *thd) { - DBUG_ENTER("end_thread"); + DBUG_ENTER("unlink_thd"); + DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); thd->cleanup(); (void) pthread_mutex_lock(&LOCK_thread_count); thread_count--; delete thd; + DBUG_VOID_RETURN; +} - if (put_in_cache && cached_thread_count < thread_cache_size && + +/* + Store thread in cache for reuse by new connections + + SYNOPSIS + cache_thread() + + NOTES + LOCK_thread_count has to be locked + + RETURN + 0 Thread was not put in cache + 1 Thread is to be reused by new connection. + (ie, caller should return, not abort with pthread_exit()) +*/ + + +static bool cache_thread() +{ + safe_mutex_assert_owner(&LOCK_thread_count); + if (cached_thread_count < thread_cache_size && ! abort_loop && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ @@ -1746,31 +1811,56 @@ void end_thread(THD *thd, bool put_in_cache) pthread_cond_signal(&COND_flush_thread_cache); if (wake_thread) { + THD *thd; wake_thread--; - thd=thread_cache.get(); - thd->real_id=pthread_self(); + thd= thread_cache.get(); thd->thread_stack= (char*) &thd; // For store_globals (void) thd->store_globals(); thd->thr_create_time= time(NULL); threads.append(thd); - pthread_mutex_unlock(&LOCK_thread_count); - DBUG_VOID_RETURN; + return(1); } } + return(0); +} + + +/* + End thread for the current connection + + SYNOPSIS + one_thread_per_connection_end() + thd Thread handler + put_in_cache Store thread in cache, if there is room in it + Normally this is true in all cases except when we got + out of resources initializing the current thread + + NOTES + If thread is cached, we will wait until thread is scheduled to be + reused and then we will return. + If thread is not cached, we end the thread. + + RETURN + 0 Signal to handle_one_connection to reuse connection +*/ + +bool one_thread_per_connection_end(THD *thd, bool put_in_cache) +{ + DBUG_ENTER("one_thread_per_connection_end"); + unlink_thd(thd); + if (put_in_cache) + put_in_cache= cache_thread(); + pthread_mutex_unlock(&LOCK_thread_count); + if (put_in_cache) + DBUG_RETURN(0); // Thread is reused - /* Tell main we are ready */ - (void) pthread_mutex_unlock(&LOCK_thread_count); /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); (void) pthread_cond_broadcast(&COND_thread_count); -#ifdef ONE_THREAD - if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux -#endif - { - my_thread_end(); - pthread_exit(0); - } - DBUG_VOID_RETURN; + + my_thread_end(); + pthread_exit(0); + DBUG_RETURN(0); // Impossible } @@ -1805,6 +1895,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused))) } #endif + /****************************************************************************** Setup a signal thread with handles all signals. Because Linux doesn't support schemas use a mutex to check that @@ -1824,6 +1915,7 @@ static void init_signals(void) #endif } + static void start_signal_handler(void) { // Save vm id of this process @@ -1831,6 +1923,7 @@ static void start_signal_handler(void) create_pid_file(); } + static void check_data_home(const char *path) {} @@ -2051,6 +2144,7 @@ static void init_signals(void) } + static void start_signal_handler(void) { // Save vm id of this process @@ -2107,14 +2201,15 @@ and this may fail.\n\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); - fprintf(stderr, "max_connections=%lu\n", max_connections); + fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads); fprintf(stderr, "threads_connected=%u\n", thread_count); fprintf(stderr, "It is possible that mysqld could use up to \n\ -key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %lu K\n\ +key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\ bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size + (global_system_variables.read_buff_size + global_system_variables.sortbuff_size) * - max_connections)/ 1024); + thread_scheduler.max_threads + + max_connections * sizeof(THD)) / 1024); fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); #if defined(HAVE_LINUXTHREADS) @@ -2187,6 +2282,8 @@ bugs.\n"); #define SA_NODEFER 0 #endif +#ifndef EMBEDDED_LIBRARY + static void init_signals(void) { sigset_t set; @@ -2259,7 +2356,6 @@ static void init_signals(void) } -#ifndef EMBEDDED_LIBRARY static void start_signal_handler(void) { int error; @@ -2314,7 +2410,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) This should actually be '+ max_number_of_slaves' instead of +10, but the +10 should be quite safe. */ - init_thr_alarm(max_connections + + init_thr_alarm(thread_scheduler.max_threads + global_system_variables.max_insert_delayed_threads + 10); #if SIGINT != THR_KILL_SIGNAL if (test_flags & TEST_SIGINT) @@ -2433,11 +2529,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) } return(0); /* purecov: deadcode */ } -#endif /*!EMBEDDED_LIBRARY*/ static void check_data_home(const char *path) {} +#endif /*!EMBEDDED_LIBRARY*/ #endif /* __WIN__*/ @@ -2502,6 +2598,7 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) } +#ifndef EMBEDDED_LIBRARY static void *my_str_malloc_mysqld(size_t size) { return my_malloc(size, MYF(MY_FAE)); @@ -2512,22 +2609,11 @@ static void my_str_free_mysqld(void *ptr) { my_free((gptr)ptr, MYF(MY_FAE)); } +#endif /* EMBEDDED_LIBRARY */ #ifdef __WIN__ -struct utsname -{ - char nodename[FN_REFLEN]; -}; - - -int uname(struct utsname *a) -{ - return -1; -} - - pthread_handler_t handle_shutdown(void *arg) { MSG msg; @@ -2618,7 +2704,15 @@ static int init_common_variables(const char *conf_file_name, int argc, tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; - start_time=time((time_t*) 0); + server_start_time= time((time_t*) 0); + rpl_filter= new Rpl_filter; + binlog_filter= new Rpl_filter; + if (!rpl_filter || !binlog_filter) + { + sql_perror("Could not allocate replication and binlog filters"); + exit(1); + } + if (init_thread_environment()) return 1; mysql_init_variables(); @@ -2626,7 +2720,7 @@ static int init_common_variables(const char *conf_file_name, int argc, #ifdef HAVE_TZNAME { struct tm tm_tmp; - localtime_r(&start_time,&tm_tmp); + localtime_r(&server_start_time,&tm_tmp); strmake(system_time_zone, tzname[tm_tmp.tm_isdst != 0 ? 1 : 0], sizeof(system_time_zone)-1); @@ -3016,6 +3110,8 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, #endif /* HAVE_OPENSSL */ +#ifndef EMBEDDED_LIBRARY + static void init_ssl() { #ifdef HAVE_OPENSSL @@ -3053,6 +3149,8 @@ static void end_ssl() #endif /* HAVE_OPENSSL */ } +#endif /* EMBEDDED_LIBRARY */ + static int init_server_components() { @@ -3068,7 +3166,7 @@ static int init_server_components() query_cache_set_min_res_unit(query_cache_min_res_unit); query_cache_init(); query_cache_resize(query_cache_size); - randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); + randominit(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2); reset_floating_point_exceptions(); init_thr_lock(); #ifdef HAVE_REPLICATION @@ -3171,11 +3269,7 @@ with --log-bin instead."); } if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC) { -#if defined(HAVE_ROW_BASED_REPLICATION) global_system_variables.binlog_format= BINLOG_FORMAT_MIXED; -#else - global_system_variables.binlog_format= BINLOG_FORMAT_STMT; -#endif } /* Check that we have not let the format to unspecified at this point */ @@ -3330,7 +3424,7 @@ server."); #ifdef HAVE_REPLICATION if (opt_bin_log && expire_logs_days) { - long purge_time= time(0) - expire_logs_days*24*60*60; + long purge_time= (long) (time(0) - expire_logs_days*24*60*60); if (purge_time >= 0) mysql_bin_log.purge_logs_before_date(purge_time); } @@ -3375,6 +3469,8 @@ server."); } +#ifndef EMBEDDED_LIBRARY + static void create_maintenance_thread() { if (flush_time && flush_time != ~(ulong) 0L) @@ -3388,7 +3484,6 @@ static void create_maintenance_thread() static void create_shutdown_thread() { -#if !defined(EMBEDDED_LIBRARY) #ifdef __WIN__ hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name); pthread_t hThread; @@ -3397,10 +3492,11 @@ static void create_shutdown_thread() // On "Stop Service" we have to do regular shutdown Service.SetShutdownEvent(hEventShutdown); -#endif -#endif // EMBEDDED_LIBRARY +#endif /* __WIN__ */ } +#endif /* EMBEDDED_LIBRARY */ + #if (defined(__NT__) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) static void handle_connections_methods() @@ -3480,15 +3576,8 @@ int win_main(int argc, char **argv) int main(int argc, char **argv) #endif { - rpl_filter= new Rpl_filter; - binlog_filter= new Rpl_filter; - if (!rpl_filter || !binlog_filter) - { - sql_perror("Could not allocate replication and binlog filters"); - exit(1); - } - MY_INIT(argv[0]); // init my_sys library & pthreads + /* nothing should come before this line ^^^ */ /* Perform basic logger initialization logger. Should be called after @@ -3641,7 +3730,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); error_handler_hook= my_message_sql; start_signal_handler(); // Creates pidfile - if (acl_init(opt_noacl) || + if (mysql_rm_tmp_tables() || acl_init(opt_noacl) || my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) { abort_loop=1; @@ -3660,6 +3749,9 @@ we force server id to 2, but this MySQL server will not act as a slave."); if (!opt_noacl) (void) grant_init(); + if (!opt_bootstrap) + servers_init(0); + if (!opt_noacl) { #ifdef HAVE_DLOPEN @@ -3707,15 +3799,18 @@ we force server id to 2, but this MySQL server will not act as a slave."); mysqld_port, MYSQL_COMPILATION_COMMENT); - // Signal threads waiting for server to be started - mysqld_server_started= 1; - pthread_cond_signal(&COND_server_started); - if (!opt_noacl) { if (Events::get_instance()->init()) unireg_abort(1); } + + /* Signal threads waiting for server to be started */ + pthread_mutex_lock(&LOCK_server_started); + mysqld_server_started= 1; + pthread_cond_signal(&COND_server_started); + pthread_mutex_unlock(&LOCK_server_started); + #if defined(__NT__) || defined(HAVE_SMEM) handle_connections_methods(); #else @@ -3981,7 +4076,7 @@ static void bootstrap(FILE *file) my_net_init(&thd->net,(st_vio*) 0); thd->max_client_packet_length= thd->net.max_packet; thd->security_ctx->master_access= ~(ulong)0; - thd->thread_id=thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; thread_count++; bootstrap_file=file; @@ -4024,6 +4119,74 @@ static bool read_init_file(char *file_name) #ifndef EMBEDDED_LIBRARY + +/* + Simple scheduler that use the main thread to handle the request + + NOTES + This is only used for debugging, when starting mysqld with + --thread-handling=no-threads or --one-thread + + When we enter this function, LOCK_thread_count is hold! +*/ + +void handle_connection_in_main_thread(THD *thd) +{ + safe_mutex_assert_owner(&LOCK_thread_count); + thread_cache_size=0; // Safety + threads.append(thd); + (void) pthread_mutex_unlock(&LOCK_thread_count); + handle_one_connection((void*) thd); +} + + +/* + Scheduler that uses one thread per connection +*/ + +void create_thread_to_handle_connection(THD *thd) +{ + if (cached_thread_count > wake_thread) + { + /* Get thread from cache */ + thread_cache.append(thd); + wake_thread++; + pthread_cond_signal(&COND_thread_cache); + } + else + { + /* Create new thread to handle connection */ + int error; + thread_created++; + threads.append(thd); + DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); + thd->connect_time = time(NULL); + if ((error=pthread_create(&thd->real_id,&connection_attrib, + handle_one_connection, + (void*) thd))) + { + /* purify: begin inspected */ + DBUG_PRINT("error", + ("Can't create thread to handle request (error %d)", + error)); + thread_count--; + thd->killed= THD::KILL_CONNECTION; // Safety + (void) pthread_mutex_unlock(&LOCK_thread_count); + statistic_increment(aborted_connects,&LOCK_status); + net_printf_error(thd, ER_CANT_CREATE_THREAD, error); + (void) pthread_mutex_lock(&LOCK_thread_count); + close_connection(thd,0,0); + delete thd; + (void) pthread_mutex_unlock(&LOCK_thread_count); + return; + /* purecov: end */ + } + } + (void) pthread_mutex_unlock(&LOCK_thread_count); + DBUG_PRINT("info",("Thread created")); +} + + /* Create new thread to handle incoming connection. @@ -4045,10 +4208,9 @@ static bool read_init_file(char *file_name) static void create_new_thread(THD *thd) { + NET *net=&thd->net; DBUG_ENTER("create_new_thread"); - NET *net=&thd->net; // For easy ref - net->read_timeout = (uint) connect_timeout; if (protocol_version > 9) net->return_errno=1; @@ -4061,64 +4223,15 @@ static void create_new_thread(THD *thd) DBUG_VOID_RETURN; } pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id=thread_id++; - - thd->real_id=pthread_self(); // Keep purify happy + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; /* 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 - threads.append(thd); - thd->real_id=pthread_self(); - (void) pthread_mutex_unlock(&LOCK_thread_count); - handle_one_connection((void*) 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) - { - thread_cache.append(thd); - wake_thread++; - pthread_cond_signal(&COND_thread_cache); - } - else - { - int error; - thread_created++; - threads.append(thd); - DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->connect_time = time(NULL); - if ((error=pthread_create(&thd->real_id,&connection_attrib, - handle_one_connection, - (void*) thd))) - { - DBUG_PRINT("error", - ("Can't create thread to handle request (error %d)", - error)); - thread_count--; - thd->killed= THD::KILL_CONNECTION; // Safety - (void) pthread_mutex_unlock(&LOCK_thread_count); - statistic_increment(aborted_connects,&LOCK_status); - net_printf_error(thd, ER_CANT_CREATE_THREAD, error); - (void) pthread_mutex_lock(&LOCK_thread_count); - close_connection(thd,0,0); - delete thd; - (void) pthread_mutex_unlock(&LOCK_thread_count); - DBUG_VOID_RETURN; - } - } - (void) pthread_mutex_unlock(&LOCK_thread_count); + if (thread_count - delayed_insert_threads > max_used_connections) + max_used_connections= thread_count - delayed_insert_threads; - } - DBUG_PRINT("info",("Thread created")); + thread_scheduler.add_connection(thd); DBUG_VOID_RETURN; } #endif /* EMBEDDED_LIBRARY */ @@ -4342,12 +4455,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) } if (sock == unix_sock) thd->security_ctx->host=(char*) my_localhost; -#ifdef __WIN__ - /* Set default wait_timeout */ - ulong wait_timeout= global_system_variables.net_wait_timeout * 1000; - (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout, - sizeof(wait_timeout)); -#endif + create_new_thread(thd); } @@ -4713,9 +4821,7 @@ enum options_mysqld #ifndef DBUG_OFF OPT_BINLOG_SHOW_XID, #endif -#ifdef HAVE_ROW_BASED_REPLICATION OPT_BINLOG_ROWS_EVENT_MAX_SIZE, -#endif OPT_WANT_CORE, OPT_CONCURRENT_INSERT, OPT_MEMLOCK, OPT_MYISAM_RECOVER, OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID, @@ -4740,8 +4846,8 @@ enum options_mysqld OPT_LOG_BIN_TRUST_FUNCTION_CREATORS, OPT_SAFE_SHOW_DB, OPT_INNODB_SAFE_BINLOG, OPT_INNODB, OPT_ISAM, - OPT_ENGINE_CONDITION_PUSHDOWN, - OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT, + OPT_ENGINE_CONDITION_PUSHDOWN, OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, + OPT_NDB_USE_EXACT_COUNT, OPT_NDB_USE_TRANSACTIONS, OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME, OPT_NDB_MGMD, OPT_NDB_NODEID, @@ -4881,7 +4987,9 @@ enum options_mysqld OPT_PORT_OPEN_TIMEOUT, OPT_GENERAL_LOG, OPT_SLOW_LOG, - OPT_MERGE + OPT_MERGE, + OPT_THREAD_HANDLING, + OPT_INNODB_ROLLBACK_ON_TIMEOUT }; @@ -4932,7 +5040,6 @@ struct my_option my_long_options[] = (gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog_format", OPT_BINLOG_FORMAT, -#ifdef HAVE_ROW_BASED_REPLICATION "Tell the master the form of binary logging to use: either 'row' for " "row-based binary logging, or 'statement' for statement-based binary " "logging, or 'mixed'. 'mixed' is statement-based binary logging except " @@ -4942,17 +5049,8 @@ struct my_option my_long_options[] = #ifdef HAVE_NDB_BINLOG "If ndbcluster is enabled, the default is 'row'." #endif -#else - "Tell the master the form of binary logging to use: this build " - "supports only statement-based binary logging, so only 'statement' is " - "a legal value." -#endif , 0, 0, 0, GET_STR, REQUIRED_ARG, -#ifdef HAVE_ROW_BASED_REPLICATION BINLOG_FORMAT_MIXED -#else - BINLOG_FORMAT_STMT -#endif , 0, 0, 0, 0, 0 }, {"binlog-do-db", OPT_BINLOG_DO_DB, "Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.", @@ -4960,7 +5058,6 @@ struct my_option my_long_options[] = {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, "Tells the master that updates to the given database should not be logged tothe binary log.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_ROW_BASED_REPLICATION {"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE, "The maximum size of a row-based binary log event in bytes. Rows will be " "grouped into events smaller than this size if possible. " @@ -4972,9 +5069,10 @@ struct my_option my_long_options[] = /* sub_size */ 0, /* block_size */ 256, /* app_type */ 0 }, -#endif +#ifndef DISABLE_GRANT_OPTIONS {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, "Don't ignore client side character set value sent during handshake.", (gptr*) &opt_character_set_client_handshake, @@ -5068,7 +5166,7 @@ struct my_option my_long_options[] = "Push supported query conditions to the storage engine.", (gptr*) &global_system_variables.engine_condition_pushdown, (gptr*) &global_system_variables.engine_condition_pushdown, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, /* See how it's handled in get_one_option() */ {"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.", NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -5097,9 +5195,11 @@ Disable with --skip-large-pages.", {"init-connect", OPT_INIT_CONNECT, "Command(s) that are executed for each new connection", (gptr*) &opt_init_connect, (gptr*) &opt_init_connect, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DISABLE_GRANT_OPTIONS {"init-file", OPT_INIT_FILE, "Read SQL commands from this file at startup.", (gptr*) &opt_init_file, (gptr*) &opt_init_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed when a slave connects to this master", @@ -5174,6 +5274,10 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, (gptr*) &srv_max_purge_lag, (gptr*) &srv_max_purge_lag, 0, GET_LONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1L, 0}, + {"innodb_rollback_on_timeout", OPT_INNODB_ROLLBACK_ON_TIMEOUT, + "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)", + (gptr*) &innobase_rollback_on_timeout, (gptr*) &innobase_rollback_on_timeout, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_status_file", OPT_INNODB_STATUS_FILE, "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file", (gptr*) &innobase_create_status_file, (gptr*) &innobase_create_status_file, @@ -5230,11 +5334,9 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, "If equal to 0 (the default), then when --log-bin is used, creation of " "a stored function (or trigger) is allowed only to users having the SUPER privilege " "and only if this stored function (trigger) may not break binary logging." -#ifdef HAVE_ROW_BASED_REPLICATION "Note that if ALL connections to this server ALWAYS use row-based binary " "logging, the security issues do not exist and the binary logging cannot " "break, so you can safely set this to 1." -#endif ,(gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-error", OPT_ERROR_LOG_FILE, "Error log file.", @@ -5439,6 +5541,17 @@ Disable with --skip-ndbcluster (will save memory).", (gptr*) &global_system_variables.ndb_use_exact_count, (gptr*) &global_system_variables.ndb_use_exact_count, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"ndb-use-transactions", OPT_NDB_USE_TRANSACTIONS, + "Use transactions for large inserts, if enabled then large " + "inserts will be split into several smaller transactions", + (gptr*) &global_system_variables.ndb_use_transactions, + (gptr*) &global_system_variables.ndb_use_transactions, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"ndb_use_transactions", OPT_NDB_USE_TRANSACTIONS, + "same as --ndb-use-transactions.", + (gptr*) &global_system_variables.ndb_use_transactions, + (gptr*) &global_system_variables.ndb_use_transactions, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"ndb-shm", OPT_NDB_SHM, "Use shared memory connections when available.", (gptr*) &opt_ndb_shm, @@ -5483,11 +5596,9 @@ Disable with --skip-ndbcluster (will save memory).", (gptr*) &global_system_variables.old_passwords, (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef ONE_THREAD {"one-thread", OPT_ONE_THREAD, - "Only use one thread (for debugging under Linux).", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif + "(deprecated): Only use one thread (for debugging under Linux). Use thread-handling=no-threads instead", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS, "Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)", (gptr*) &opt_old_style_user_limits, (gptr*) &opt_old_style_user_limits, @@ -5600,10 +5711,12 @@ Can't be set to 1 if --log-slave-updates is used.", "Show user and password in SHOW SLAVE HOSTS on this master", (gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DISABLE_GRANT_OPTIONS {"skip-grant-tables", OPT_SKIP_GRANT, "Start without grant tables. This gives all users FULL ACCESS to all tables!", (gptr*) &opt_noacl, (gptr*) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"skip-host-cache", OPT_SKIP_HOST_CACHE, "Don't cache host names.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-locking", OPT_SKIP_LOCK, @@ -5636,8 +5749,8 @@ Can't be set to 1 if --log-slave-updates is used.", {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Deprecated option. Use --skip-symbolic-links instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-thread-priority", OPT_SKIP_PRIOR, - "Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, - 0, 0, 0, 0, 0}, + "Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, + DEFAULT_SKIP_THREAD_PRIORITY, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION {"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR, "The location where the slave should put its temporary files when \ @@ -5711,6 +5824,11 @@ log and this option does nothing anymore.", 0, 0, 0, 0, 0}, {"use-symbolic-links", 's', "Enable symbolic link support. Deprecated option; use --symbolic-links instead.", (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, + /* + The system call realpath() produces warnings under valgrind and + purify. These are not suppressed: instead we disable symlinks + option if compiled with valgrind support. + */ IF_PURIFY(0,1), 0, 0, 0, 0, 0}, {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -6002,7 +6120,7 @@ The minimum value for this variable is 4096.", // children, to avoid "too many connections" error in a common setup {"max_connections", OPT_MAX_CONNECTIONS, "The number of simultaneous clients allowed.", (gptr*) &max_connections, - (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 16384, 0, 1, + (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 100000, 0, 1, 0}, {"max_delayed_threads", OPT_MAX_DELAYED_THREADS, "Don't start more than this number of threads to handle INSERT DELAYED statements. If set to zero, which means INSERT DELAYED is not used.", @@ -6287,6 +6405,12 @@ The minimum value for this variable is 4096.", "Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.", (gptr*) &concurrency, (gptr*) &concurrency, 0, GET_ULONG, REQUIRED_ARG, DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0}, +#if HAVE_POOL_OF_THREADS == 1 + {"thread_pool_size", OPT_THREAD_CACHE_SIZE, + "How many threads we should create to handle query requests in case of 'thread_handling=pool-of-threads'", + (gptr*) &thread_pool_size, (gptr*) &thread_pool_size, 0, GET_ULONG, + REQUIRED_ARG, 20, 1, 16384, 0, 1, 0}, +#endif {"thread_stack", OPT_THREAD_STACK, "The stack size for each thread.", (gptr*) &my_thread_stack_size, (gptr*) &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, @@ -6311,6 +6435,10 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.trans_prealloc_size, (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, + {"thread_handling", OPT_THREAD_HANDLING, + "Define threads usage for handling queries: " + "one-thread-per-connection or no-threads", 0, 0, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT, "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).", (gptr*) &global_system_variables.updatable_views_with_limit, @@ -6343,7 +6471,7 @@ static int show_starttime(THD *thd, SHOW_VAR *var, char *buff) { var->type= SHOW_LONG; var->value= buff; - *((long *)buff)= (long) (thd->query_start() - start_time); + *((long *)buff)= (long) (thd->query_start() - server_start_time); return 0; } @@ -7027,7 +7155,7 @@ static void mysql_init_variables(void) protocol_version= PROTOCOL_VERSION; what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= flush_version= 1L; /* Increments on each reload */ - query_id= thread_id= 1L; + global_query_id= thread_id= 1L; strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; myisam_stats_method_str= maria_stats_method_str= "nulls_unequal"; @@ -7122,11 +7250,6 @@ static void mysql_init_variables(void) #else have_partition_db= SHOW_OPTION_NO; #endif -#ifdef HAVE_ROW_BASED_REPLICATION - have_row_based_replication= SHOW_OPTION_YES; -#else - have_row_based_replication= SHOW_OPTION_NO; -#endif #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE have_ndbcluster=SHOW_OPTION_DISABLED; global_system_variables.ndb_index_stat_enable=FALSE; @@ -7272,7 +7395,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'T': test_flags= argument ? (uint) atoi(argument) : 0; - test_flags&= ~TEST_NO_THREADS; opt_endinfo=1; break; case (int) OPT_BIG_TABLES: @@ -7356,7 +7478,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int id; if ((id= find_type(argument, &binlog_format_typelib, 2)) <= 0) { -#ifdef HAVE_ROW_BASED_REPLICATION fprintf(stderr, "Unknown binary log format: '%s' " "(should be one of '%s', '%s', '%s')\n", @@ -7364,11 +7485,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), binlog_format_names[BINLOG_FORMAT_STMT], binlog_format_names[BINLOG_FORMAT_ROW], binlog_format_names[BINLOG_FORMAT_MIXED]); -#else - fprintf(stderr, - "Unknown binary log format: '%s' (only legal value is '%s')\n", - argument, binlog_format_names[BINLOG_FORMAT_STMT]); -#endif exit(1); } global_system_variables.binlog_format= id-1; @@ -7510,11 +7626,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_skip_show_db=1; opt_specialflag|=SPECIAL_SKIP_SHOW_DB; break; -#ifdef ONE_THREAD - case (int) OPT_ONE_THREAD: - test_flags |= TEST_NO_THREADS; -#endif - break; case (int) OPT_WANT_CORE: test_flags |= TEST_CORE_ON_SIGNAL; break; @@ -7759,6 +7870,23 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), sql_mode); break; } + case OPT_ONE_THREAD: + global_system_variables.thread_handling= 2; + break; + case OPT_THREAD_HANDLING: + { + if ((global_system_variables.thread_handling= + find_type(argument, &thread_handling_typelib, 2)) <= 0 || + (global_system_variables.thread_handling == SCHEDULER_POOL_OF_THREADS + && !HAVE_POOL_OF_THREADS)) + { + /* purecov: begin tested */ + fprintf(stderr,"Unknown/unsupported thread-handling: %s\n",argument); + exit(1); + /* purecov: end */ + } + break; + } case OPT_FT_BOOLEAN_SYNTAX: if (ft_boolean_check_syntax_string((byte*) argument)) { @@ -7879,6 +8007,7 @@ static void get_options(int argc,char **argv) if (mysqld_chroot) set_root(mysqld_chroot); #else + global_system_variables.thread_handling = SCHEDULER_NO_THREADS; max_allowed_packet= global_system_variables.max_allowed_packet; net_buffer_length= global_system_variables.net_buffer_length; #endif @@ -7909,6 +8038,17 @@ static void get_options(int argc,char **argv) &global_system_variables.datetime_format)) exit(1); +#ifdef EMBEDDED_LIBRARY + one_thread_scheduler(&thread_scheduler); +#else + if (global_system_variables.thread_handling <= + SCHEDULER_ONE_THREAD_PER_CONNECTION) + one_thread_per_connection_scheduler(&thread_scheduler); + else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS) + one_thread_scheduler(&thread_scheduler); + else + pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */ +#endif } @@ -8126,6 +8266,8 @@ static int test_if_case_insensitive(const char *dir_name) /* Create file to store pid number */ +#ifndef EMBEDDED_LIBRARY + static void create_pid_file() { File file; @@ -8145,7 +8287,7 @@ static void create_pid_file() sql_perror("Can't start server: can't create PID file"); exit(1); } - +#endif /* EMBEDDED_LIBRARY */ /* Clear most status variables */ void refresh_status(THD *thd) @@ -8214,7 +8356,8 @@ my_bool innobase_log_archive, innobase_use_doublewrite, innobase_use_checksums, innobase_file_per_table, - innobase_locks_unsafe_for_binlog; + innobase_locks_unsafe_for_binlog, + innobase_rollback_on_timeout; extern "C" { ulong srv_max_buf_pool_modified_pct; @@ -8248,5 +8391,3 @@ template class I_List<NAMED_LIST>; template class I_List<Statement>; template class I_List_iterator<Statement>; #endif - - diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej deleted file mode 100644 index 62f0357622d..00000000000 --- a/sql/mysqld.cc.rej +++ /dev/null @@ -1,17 +0,0 @@ -*************** -*** 5316,5322 **** - (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ - --skip-merge.", -! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0}, - {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, ---- 5336,5342 ---- - (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ - --skip-merge.", -! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, diff --git a/sql/mysqld_suffix.h b/sql/mysqld_suffix.h index 405c5d855b7..b348f272db1 100644 --- a/sql/mysqld_suffix.h +++ b/sql/mysqld_suffix.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 6f8993f584d..2156888b8cf 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -48,9 +47,6 @@ #include <violite.h> #include <signal.h> #include <errno.h> -#ifdef __WIN__ -#include <winsock.h> -#endif #ifdef __NETWARE__ #include <sys/select.h> #endif @@ -221,6 +217,8 @@ my_bool net_realloc(NET *net, ulong length) -1 Don't know if data is ready or not */ +#if !defined(EMBEDDED_LIBRARY) + static int net_data_is_ready(my_socket sd) { #ifdef HAVE_POLL @@ -255,9 +253,10 @@ static int net_data_is_ready(my_socket sd) return 0; else return test(res ? FD_ISSET(sd, &sfds) : 0); -#endif +#endif /* HAVE_POLL */ } +#endif /* EMBEDDED_LIBRARY */ /* Remove unwanted characters from connection @@ -283,8 +282,11 @@ static int net_data_is_ready(my_socket sd) void net_clear(NET *net, my_bool clear_buffer) { +#if !defined(EMBEDDED_LIBRARY) int count, ready; +#endif DBUG_ENTER("net_clear"); + #if !defined(EMBEDDED_LIBRARY) if (clear_buffer) { @@ -296,7 +298,7 @@ void net_clear(NET *net, my_bool clear_buffer) { DBUG_PRINT("info",("skipped %d bytes from file: %s", count, vio_description(net->vio))); -#ifdef EXTRA_DEBUG +#if defined(EXTRA_DEBUG) && (MYSQL_VERSION_ID < 51000) fprintf(stderr,"Error: net_clear() skipped %d bytes from file: %s\n", count, vio_description(net->vio)); #endif @@ -600,14 +602,17 @@ net_real_write(NET *net,const char *packet,ulong len) } #endif /* HAVE_COMPRESS */ - /* DBUG_DUMP("net",packet,len); */ +#ifdef DEBUG_DATA_PACKETS + DBUG_DUMP("data",packet,len); +#endif + #ifndef NO_ALARM thr_alarm_init(&alarmed); if (net_blocking) thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff); #else alarmed=0; - vio_timeout(net->vio, 1, net->write_timeout); + /* Write timeout is set in net_set_write_timeout */ #endif /* NO_ALARM */ pos=(char*) packet; end=pos+len; @@ -800,7 +805,7 @@ my_real_read(NET *net, ulong *complen) if (net_blocking) thr_alarm(&alarmed,net->read_timeout,&alarm_buff); #else - vio_timeout(net->vio, 0, net->read_timeout); + /* Read timeout is set in net_set_read_timeout */ #endif /* NO_ALARM */ pos = net->buff + net->where_b; /* net->packet -4 */ @@ -1111,3 +1116,26 @@ my_net_read(NET *net) return len; } + +void net_set_read_timeout(NET *net, uint timeout) +{ + DBUG_ENTER("net_set_read_timeout"); + DBUG_PRINT("enter", ("timeout: %d", timeout)); + net->read_timeout= timeout; +#ifdef NO_ALARM + vio_timeout(net->vio, 0, timeout); +#endif + DBUG_VOID_RETURN; +} + + +void net_set_write_timeout(NET *net, uint timeout) +{ + DBUG_ENTER("net_set_write_timeout"); + DBUG_PRINT("enter", ("timeout: %d", timeout)); + net->write_timeout= timeout; +#ifdef NO_ALARM + vio_timeout(net->vio, 1, timeout); +#endif + DBUG_VOID_RETURN; +} diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fa575e73c39..5789c1a4ae3 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -220,6 +219,8 @@ public: } inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; } inline void maybe_smaller() { maybe_flag=1; } + /* Return true iff it's a single-point null interval */ + inline bool is_null_interval() { return maybe_null && max_value[0] == 1; } inline int cmp_min_to_min(SEL_ARG* arg) { return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag); @@ -561,6 +562,7 @@ public: bool is_ror_scan; /* Number of ranges in the last checked tree->key */ uint n_ranges; + uint8 first_null_comp; /* first null component if any, 0 - otherwise */ }; class TABLE_READ_PLAN; @@ -607,9 +609,6 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, double read_time); static TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree); -static int get_index_merge_params(PARAM *param, key_map& needed_reg, - SEL_IMERGE *imerge, double *read_time, - ha_rows* imerge_rows); static double get_index_only_read_time(const PARAM* param, ha_rows records, int keynr); @@ -619,7 +618,6 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, static void print_ror_scans_arr(TABLE *table, const char *msg, struct st_ror_scan_info **start, struct st_ror_scan_info **end); -static void print_rowid(byte* val, int len); static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg); #endif @@ -931,7 +929,7 @@ QUICK_SELECT_I::QUICK_SELECT_I() QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc, MEM_ROOT *parent_alloc) - :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),range(0) + :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),last_range(0) { my_bitmap_map *bitmap; DBUG_ENTER("QUICK_RANGE_SELECT::QUICK_RANGE_SELECT"); @@ -1002,6 +1000,11 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() if (file) { range_end(); + if (head->key_read) + { + head->key_read= 0; + file->extra(HA_EXTRA_NO_KEYREAD); + } if (free_file) { DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, @@ -1010,10 +1013,6 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() file->close(); delete file; } - else - { - file->extra(HA_EXTRA_NO_KEYREAD); - } } delete_dynamic(&ranges); /* ranges are allocated in alloc */ free_root(&alloc,MYF(0)); @@ -1195,7 +1194,11 @@ end: org_file= head->file; head->file= file; /* We don't have to set 'head->keyread' here as the 'file' is unique */ - head->mark_columns_used_by_index(index); + if (!head->no_keyread) + { + head->key_read= 1; + head->mark_columns_used_by_index(index); + } head->prepare_for_position(); head->file= org_file; bitmap_copy(&column_bitmap, head->read_set); @@ -1386,13 +1389,12 @@ int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, byte *val1, byte *val2) int QUICK_ROR_UNION_SELECT::reset() { - QUICK_SELECT_I* quick; + QUICK_SELECT_I *quick; int error; DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset"); have_prev_rowid= FALSE; if (!scans_inited) { - QUICK_SELECT_I *quick; List_iterator_fast<QUICK_SELECT_I> it(quick_selects); while ((quick= it++)) { @@ -2421,8 +2423,6 @@ static int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar, List<SEL_IMERGE> &merges); static void mark_all_partitions_as_used(partition_info *part_info); -static uint32 part_num_to_part_id_range(PART_PRUNE_PARAM* prune_par, - uint32 num); #ifndef DBUG_OFF static void print_partitioning_index(KEY_PART *parts, KEY_PART *parts_end); @@ -3132,7 +3132,7 @@ static bool fields_ok_for_partition_index(Field **pfield) for (; (*pfield); pfield++) { enum_field_types ftype= (*pfield)->real_type(); - if (ftype == FIELD_TYPE_ENUM || ftype == FIELD_TYPE_GEOMETRY) + if (ftype == MYSQL_TYPE_ENUM || ftype == MYSQL_TYPE_GEOMETRY) return FALSE; } return TRUE; @@ -3231,7 +3231,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) key_part->store_length= (uint16) (*field)->pack_length(); if ((*field)->real_maybe_null()) key_part->store_length+= HA_KEY_NULL_LENGTH; - if ((*field)->type() == FIELD_TYPE_BLOB || + if ((*field)->type() == MYSQL_TYPE_BLOB || (*field)->real_type() == MYSQL_TYPE_VARCHAR) key_part->store_length+= HA_KEY_BLOB_LENGTH; @@ -4683,8 +4683,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, param->table->key_info[keynr].name, found_read_time, read_time)); - if (read_time > found_read_time && found_records != HA_POS_ERROR - /*|| read_time == DBL_MAX*/ ) + if (read_time > found_read_time && found_records != HA_POS_ERROR) { read_time= found_read_time; best_records= found_records; @@ -5012,7 +5011,8 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, for (uint idx= 0; idx < param->keys; idx++) { SEL_ARG *new_interval, *last_val; - if (((new_interval= tree2->keys[idx])) && + if (((new_interval= tree2->keys[idx])) && + (tree->keys[idx]) && ((last_val= tree->keys[idx]->last()))) { new_interval->min_value= last_val->max_value; @@ -5589,13 +5589,28 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, /* For comparison purposes allow invalid dates like 2000-01-32 */ orig_sql_mode= field->table->in_use->variables.sql_mode; if (value->real_item()->type() == Item::STRING_ITEM && - (field->type() == FIELD_TYPE_DATE || - field->type() == FIELD_TYPE_DATETIME)) + (field->type() == MYSQL_TYPE_DATE || + field->type() == MYSQL_TYPE_DATETIME)) field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; err= value->save_in_field_no_warnings(field, 1); if (err > 0 && field->cmp_type() != value->result_type()) { - tree= 0; + if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && + value->result_type() == item_cmp_type(field->result_type(), + value->result_type())) + + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + } + else + { + /* + TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE + for the cases like int_field > 999999999999999999999999 as well. + */ + tree= 0; + } goto end; } if (err < 0) @@ -7011,6 +7026,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats) DBUG_ENTER("check_quick_select"); param->is_ror_scan= FALSE; + param->first_null_comp= 0; if (!tree) DBUG_RETURN(HA_POS_ERROR); // Can't use it @@ -7111,6 +7127,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, ha_rows records=0, tmp; uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length; char *tmp_min_key, *tmp_max_key; + uint8 save_first_null_comp= param->first_null_comp; param->max_key_part=max(param->max_key_part,key_tree->part); if (key_tree->left != &null_element) @@ -7148,6 +7165,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, param->is_ror_scan= FALSE; } + if (!param->first_null_comp && key_tree->is_null_interval()) + param->first_null_comp= key_tree->part+1; + if (key_tree->next_key_part && key_tree->next_key_part->part == key_tree->part+1 && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) @@ -7191,7 +7211,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME && min_key_length == max_key_length && - !memcmp(param->min_key,param->max_key,min_key_length)) + !memcmp(param->min_key,param->max_key,min_key_length) && + !param->first_null_comp) { tmp=1; // Max one record param->n_ranges++; @@ -7266,6 +7287,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, return tmp; records+=tmp; } + param->first_null_comp= save_first_null_comp; return records; } @@ -7983,7 +8005,7 @@ int QUICK_RANGE_SELECT::reset() byte *mrange_buff; DBUG_ENTER("QUICK_RANGE_SELECT::reset"); next=0; - range= NULL; + last_range= NULL; in_range= FALSE; cur_range= (QUICK_RANGE**) ranges.buffer; @@ -8117,23 +8139,23 @@ int QUICK_RANGE_SELECT::get_next() { start_key= &mrange_slot->start_key; end_key= &mrange_slot->end_key; - range= *(cur_range++); + last_range= *(cur_range++); - start_key->key= (const byte*) range->min_key; - start_key->length= range->min_length; - start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : - (range->flag & EQ_RANGE) ? + start_key->key= (const byte*) last_range->min_key; + start_key->length= last_range->min_length; + start_key->flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : + (last_range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); - end_key->key= (const byte*) range->max_key; - end_key->length= range->max_length; + end_key->key= (const byte*) last_range->max_key; + end_key->length= last_range->max_length; /* We use HA_READ_AFTER_KEY here because if we are reading on a key prefix. We want to find all keys with this prefix. */ - end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : + end_key->flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); - mrange_slot->range_flag= range->flag; + mrange_slot->range_flag= last_range->flag; } result= file->read_multi_range_first(&mrange, multi_range, count, @@ -8189,7 +8211,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) { int result; key_range start_key, end_key; - if (range) + if (last_range) { /* Read the next record in the same range with prefix after cur_prefix. */ DBUG_ASSERT(cur_prefix != 0); @@ -8203,35 +8225,35 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) if (count == 0) { /* Ranges have already been used up before. None is left for read. */ - range= 0; + last_range= 0; DBUG_RETURN(HA_ERR_END_OF_FILE); } - range= *(cur_range++); + last_range= *(cur_range++); - start_key.key= (const byte*) range->min_key; - start_key.length= min(range->min_length, prefix_length); - start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : - (range->flag & EQ_RANGE) ? + start_key.key= (const byte*) last_range->min_key; + start_key.length= min(last_range->min_length, prefix_length); + start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : + (last_range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); - end_key.key= (const byte*) range->max_key; - end_key.length= min(range->max_length, prefix_length); + end_key.key= (const byte*) last_range->max_key; + end_key.length= min(last_range->max_length, prefix_length); /* We use READ_AFTER_KEY here because if we are reading on a key prefix we want to find all keys with this prefix */ - end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : + end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); - result= file->read_range_first(range->min_length ? &start_key : 0, - range->max_length ? &end_key : 0, - test(range->flag & EQ_RANGE), + result= file->read_range_first(last_range->min_length ? &start_key : 0, + last_range->max_length ? &end_key : 0, + test(last_range->flag & EQ_RANGE), sorted); - if (range->flag == (UNIQUE_RANGE | EQ_RANGE)) - range=0; // Stop searching + if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) + last_range= 0; // Stop searching if (result != HA_ERR_END_OF_FILE) DBUG_RETURN(result); - range=0; // No matching rows; go to next range + last_range= 0; // No matching rows; go to next range } } @@ -8245,11 +8267,11 @@ int QUICK_RANGE_SELECT_GEOM::get_next() for (;;) { int result; - if (range) + if (last_range) { // Already read through key - result= file->index_next_same(record, (byte*) range->min_key, - range->min_length); + result= file->index_next_same(record, (byte*) last_range->min_key, + last_range->min_length); if (result != HA_ERR_END_OF_FILE) DBUG_RETURN(result); } @@ -8258,18 +8280,18 @@ int QUICK_RANGE_SELECT_GEOM::get_next() if (count == 0) { /* Ranges have already been used up before. None is left for read. */ - range= 0; + last_range= 0; DBUG_RETURN(HA_ERR_END_OF_FILE); } - range= *(cur_range++); + last_range= *(cur_range++); result= file->index_read(record, - (byte*) range->min_key, - range->min_length, - (ha_rkey_function)(range->flag ^ GEOM_FLAG)); + (byte*) last_range->min_key, + last_range->min_length, + (ha_rkey_function)(last_range->flag ^ GEOM_FLAG)); if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE) DBUG_RETURN(result); - range=0; // Not found, to next range + last_range= 0; // Not found, to next range } } @@ -8294,7 +8316,7 @@ int QUICK_RANGE_SELECT_GEOM::get_next() bool QUICK_RANGE_SELECT::row_in_ranges() { - QUICK_RANGE *range; + QUICK_RANGE *res; uint min= 0; uint max= ranges.elements - 1; uint mid= (max + min)/2; @@ -8310,8 +8332,8 @@ bool QUICK_RANGE_SELECT::row_in_ranges() max= mid; mid= (min + max) / 2; } - range= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid); - return (!cmp_next(range) && !cmp_prev(range)); + res= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid); + return (!cmp_next(res) && !cmp_prev(res)); } /* @@ -8325,14 +8347,14 @@ bool QUICK_RANGE_SELECT::row_in_ranges() */ QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, - uint used_key_parts) + uint used_key_parts_arg) :QUICK_RANGE_SELECT(*q), rev_it(rev_ranges) { QUICK_RANGE *r; QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer; - QUICK_RANGE **last_range= pr + ranges.elements; - for (; pr!=last_range; pr++) + QUICK_RANGE **end_range= pr + ranges.elements; + for (; pr!=end_range; pr++) rev_ranges.push_front(*pr); /* Remove EQ_RANGE flag for keys that are not using the full key */ @@ -8366,11 +8388,11 @@ int QUICK_SELECT_DESC::get_next() for (;;) { int result; - if (range) + if (last_range) { // Already read through key - result = ((range->flag & EQ_RANGE) - ? file->index_next_same(record, (byte*) range->min_key, - range->min_length) : + result = ((last_range->flag & EQ_RANGE) + ? file->index_next_same(record, (byte*) last_range->min_key, + last_range->min_length) : file->index_prev(record)); if (!result) { @@ -8381,47 +8403,49 @@ int QUICK_SELECT_DESC::get_next() DBUG_RETURN(result); } - if (!(range=rev_it++)) + if (!(last_range= rev_it++)) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used - if (range->flag & NO_MAX_RANGE) // Read last record + if (last_range->flag & NO_MAX_RANGE) // Read last record { int local_error; if ((local_error=file->index_last(record))) DBUG_RETURN(local_error); // Empty table - if (cmp_prev(range) == 0) + if (cmp_prev(last_range) == 0) DBUG_RETURN(0); - range=0; // No matching records; go to next range + last_range= 0; // No match; go to next range continue; } - if (range->flag & EQ_RANGE) + if (last_range->flag & EQ_RANGE) { - result = file->index_read(record, (byte*) range->max_key, - range->max_length, HA_READ_KEY_EXACT); + result= file->index_read(record, (byte*) last_range->max_key, + last_range->max_length, HA_READ_KEY_EXACT); } else { - DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); - result=file->index_read(record, (byte*) range->max_key, - range->max_length, - ((range->flag & NEAR_MAX) ? - HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV)); + DBUG_ASSERT(last_range->flag & NEAR_MAX || + range_reads_after_key(last_range)); + result=file->index_read(record, (byte*) last_range->max_key, + last_range->max_length, + ((last_range->flag & NEAR_MAX) ? + HA_READ_BEFORE_KEY : + HA_READ_PREFIX_LAST_OR_PREV)); } if (result) { if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE) DBUG_RETURN(result); - range=0; // Not found, to next range + last_range= 0; // Not found, to next range continue; } - if (cmp_prev(range) == 0) + if (cmp_prev(last_range) == 0) { - if (range->flag == (UNIQUE_RANGE | EQ_RANGE)) - range = 0; // Stop searching + if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) + last_range= 0; // Stop searching DBUG_RETURN(0); // Found key is in range } - range = 0; // To next range + last_range= 0; // To next range } } @@ -10149,14 +10173,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void) DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset"); file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ - result= file->ha_index_init(index, 1); - result= file->index_last(record); - if (result == HA_ERR_END_OF_FILE) - DBUG_RETURN(0); - if (result) + if ((result= file->ha_index_init(index,1))) DBUG_RETURN(result); if (quick_prefix_select && quick_prefix_select->reset()) DBUG_RETURN(1); + result= file->index_last(record); + if (result == HA_ERR_END_OF_FILE) + DBUG_RETURN(0); /* Save the prefix of the last group. */ key_copy(last_prefix, record, index_info, group_prefix_len); @@ -10205,7 +10228,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() #else int result; #endif - int is_last_prefix; + int is_last_prefix= 0; DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::get_next"); @@ -10220,13 +10243,18 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() Check if this is the last group prefix. Notice that at this point this->record contains the current prefix in record format. */ - is_last_prefix= key_cmp(index_info->key_part, last_prefix, - group_prefix_len); - DBUG_ASSERT(is_last_prefix <= 0); - if (result == HA_ERR_KEY_NOT_FOUND) - continue; - if (result) + if (!result) + { + is_last_prefix= key_cmp(index_info->key_part, last_prefix, + group_prefix_len); + DBUG_ASSERT(is_last_prefix <= 0); + } + else + { + if (result == HA_ERR_KEY_NOT_FOUND) + continue; break; + } if (have_min) { @@ -10913,23 +10941,9 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg) } -static void print_rowid(byte* val, int len) -{ - byte *pb; - DBUG_LOCK_FILE; - fputc('\"', DBUG_FILE); - for (pb= val; pb!= val + len; ++pb) - fprintf(DBUG_FILE, "%c", *pb); - fprintf(DBUG_FILE, "\", hex: "); - - for (pb= val; pb!= val + len; ++pb) - fprintf(DBUG_FILE, "%x ", *pb); - fputc('\n', DBUG_FILE); - DBUG_UNLOCK_FILE; -} - void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose) { + /* purecov: begin inspected */ fprintf(DBUG_FILE, "%*squick range select, key %s, length: %d\n", indent, "", head->key_info[index].name, max_used_key_length); @@ -10937,8 +10951,8 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose) { QUICK_RANGE *range; QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer; - QUICK_RANGE **last_range= pr + ranges.elements; - for (; pr!=last_range; ++pr) + QUICK_RANGE **end_range= pr + ranges.elements; + for (; pr != end_range; ++pr) { fprintf(DBUG_FILE, "%*s", indent + 2, ""); range= *pr; @@ -10963,6 +10977,7 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose) fputs("\n",DBUG_FILE); } } + /* purecov: end */ } void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose) diff --git a/sql/opt_range.h b/sql/opt_range.h index 170766c7c10..d82e1dc459e 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -302,7 +301,7 @@ protected: DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */ QUICK_RANGE **cur_range; /* current element in ranges */ - QUICK_RANGE *range; + QUICK_RANGE *last_range; KEY_PART *key_parts; KEY_PART_INFO *key_part_info; int cmp_next(QUICK_RANGE *range); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index cb8b53ac6a7..5bd5ec4b42d 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -98,9 +97,9 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) GROUP BY part. RETURN VALUES - 0 No errors - 1 if all items were resolved - -1 on impossible conditions + 0 no errors + 1 if all items were resolved + HA_ERR_KEY_NOT_FOUND on impossible conditions OR an error number from my_base.h HA_ERR_... if a deadlock or a lock wait timeout happens, for example */ @@ -268,7 +267,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (error) { if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) - return -1; // No rows matching WHERE + return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE /* HA_ERR_LOCK_DEADLOCK or some other error */ table->file->print_error(error, MYF(0)); return(error); @@ -355,7 +354,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (error) { if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) - return -1; // No rows matching WHERE + return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE /* HA_ERR_LOCK_DEADLOCK or some other error */ table->file->print_error(error, MYF(0)); return(error); diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 0a2d4012af4..f5b62e3afe2 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -229,7 +228,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, if (dir) { - fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME); + fn_format(path, file_name->str, dir->str, "", MY_UNPACK_FILENAME); path_end= strlen(path); } else diff --git a/sql/parse_file.h b/sql/parse_file.h index 0a02bf7eb75..21873b32904 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/partition_element.h b/sql/partition_element.h index 1e2769bc21a..c056d40b85b 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000,200666666 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * An enum and a struct to handle partitioning and subpartitioning. diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 9d5b6d0494a..a7f9bd413c6 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -921,7 +920,6 @@ bool partition_info::set_up_charset_field_preps() if (field_is_partition_charset(field)) { char *field_buf; - CHARSET_INFO *cs= ((Field_str*)field)->charset(); size= field->pack_length(); if (!(field_buf= sql_calloc(size))) goto error; diff --git a/sql/partition_info.h b/sql/partition_info.h index 09d827d44c4..8bcc769054f 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000,2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ diff --git a/sql/password.c b/sql/password.c index c6d904bc45b..1ff67888ea4 100644 --- a/sql/password.c +++ b/sql/password.c @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -473,7 +472,7 @@ scramble(char *to, const char *message, const char *password) */ my_bool -check_scramble(const char *scramble, const char *message, +check_scramble(const char *scramble_arg, const char *message, const uint8 *hash_stage2) { SHA1_CONTEXT sha1_context; @@ -486,7 +485,7 @@ check_scramble(const char *scramble, const char *message, mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); mysql_sha1_result(&sha1_context, buf); /* encrypt scramble */ - my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH); + my_crypt((char *) buf, buf, (const uchar *) scramble_arg, SCRAMBLE_LENGTH); /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */ mysql_sha1_reset(&sha1_context); mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE); @@ -496,7 +495,8 @@ check_scramble(const char *scramble, const char *message, /* - Convert scrambled password from asciiz hex string to binary form. + Convert scrambled password from asciiz hex string to binary form. + SYNOPSIS get_salt_from_password() res OUT buf to hold password. Must be at least SHA1_HASH_SIZE diff --git a/sql/procedure.cc b/sql/procedure.cc index 554e2cd0565..bbfabc46608 100644 --- a/sql/procedure.cc +++ b/sql/procedure.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2002, 2004-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/procedure.h b/sql/procedure.h index 5c8a3387eec..6a731766046 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/protocol.cc b/sql/protocol.cc index 6fe4e34d5a9..05e98c68e4e 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -28,8 +27,10 @@ #include <stdarg.h> static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; -static void write_eof_packet(THD *thd, NET *net); void net_send_error_packet(THD *thd, uint sql_errno, const char *err); +#ifndef EMBEDDED_LIBRARY +static void write_eof_packet(THD *thd, NET *net); +#endif #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const char *from, uint length) @@ -936,15 +937,15 @@ bool Protocol_simple::store(Field *field) char buff[MAX_FIELD_WIDTH]; String str(buff,sizeof(buff), &my_charset_bin); CHARSET_INFO *tocs= this->thd->variables.character_set_results; +#ifndef DBUG_OFF TABLE *table= field->table; -#ifdef DBUG_OFF my_bitmap_map *old_map= 0; if (table->file) old_map= dbug_tmp_use_all_columns(table, table->read_set); #endif field->val_str(&str); -#ifdef DBUG_OFF +#ifndef DBUG_OFF if (old_map) dbug_tmp_restore_column_map(table->read_set, old_map); #endif diff --git a/sql/protocol.h b/sql/protocol.h index 7e2bc1516ec..6c4c7414ea5 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2002-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -59,6 +58,8 @@ public: String *storage_packet() { return packet; } inline void free() { packet->free(); } virtual bool write(); + inline bool store(int from) + { return store_long((longlong) from); } inline bool store(uint32 from) { return store_long((longlong) from); } inline bool store(longlong from) diff --git a/sql/records.cc b/sql/records.cc index f8b6a7d1df9..0923ab1d75e 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 762fcfb7a6a..934a6821514 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha +/* Copyright (C) 2001-2006 MySQL AB & Sasha This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -58,6 +57,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, functions like register_slave()) are working. */ +#if NOT_USED static int init_failsafe_rpl_thread(THD* thd) { DBUG_ENTER("init_failsafe_rpl_thread"); @@ -73,23 +73,19 @@ static int init_failsafe_rpl_thread(THD* thd) thd->net.read_timeout = slave_net_timeout; thd->max_client_packet_length=thd->net.max_packet; pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id = thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; pthread_mutex_unlock(&LOCK_thread_count); if (init_thr_lock() || thd->store_globals()) { + /* purecov: begin inspected */ close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed? statistic_increment(aborted_connects,&LOCK_status); - end_thread(thd,0); + one_thread_per_connection_end(thd,0); DBUG_RETURN(-1); + /* purecov: end */ } -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif - thd->mem_root->free= thd->mem_root->used= 0; if (thd->variables.max_join_size == HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; @@ -99,7 +95,7 @@ static int init_failsafe_rpl_thread(THD* thd) thd->set_time(); DBUG_RETURN(0); } - +#endif void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status) { @@ -530,11 +526,11 @@ HOSTS"; while ((row= mysql_fetch_row(res))) { - uint32 server_id; + uint32 log_server_id; SLAVE_INFO* si, *old_si; - server_id = atoi(row[0]); + log_server_id = atoi(row[0]); if ((old_si= (SLAVE_INFO*)hash_search(&slave_list, - (byte*)&server_id,4))) + (byte*)&log_server_id,4))) si = old_si; else { @@ -544,7 +540,7 @@ HOSTS"; pthread_mutex_unlock(&LOCK_slave_list); goto err; } - si->server_id = server_id; + si->server_id = log_server_id; my_hash_insert(&slave_list, (byte*)si); } strmake(si->host, row[1], sizeof(si->host)-1); @@ -573,12 +569,14 @@ err: } +#if NOT_USED int find_recovery_captain(THD* thd, MYSQL* mysql) { return 0; } +#endif - +#if NOT_USED pthread_handler_t handle_failsafe_rpl(void *arg) { DBUG_ENTER("handle_failsafe_rpl"); @@ -626,7 +624,7 @@ err: pthread_exit(0); DBUG_RETURN(0); } - +#endif bool show_slave_hosts(THD* thd) { @@ -916,14 +914,14 @@ bool load_master_data(THD* thd) setting active_mi, because init_master_info() sets active_mi with defaults. */ - int error; + int error_2; if (init_master_info(active_mi, master_info_file, relay_log_info_file, 0, (SLAVE_IO | SLAVE_SQL))) my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0)); strmake(active_mi->master_log_name, row[0], sizeof(active_mi->master_log_name)); - active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error); + active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error_2); /* at least in recent versions, the condition below should be false */ if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE) active_mi->master_log_pos = BIN_LOG_HEADER_SIZE; diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h index 19849e63af9..561db00d841 100644 --- a/sql/repl_failsafe.h +++ b/sql/repl_failsafe.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha +/* Copyright (C) 2001-2005 MySQL AB & Sasha This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index c01b5189887..f76f798f6a6 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_filter.h b/sql/rpl_filter.h index 718fd401c56..396207d3a28 100644 --- a/sql/rpl_filter.h +++ b/sql/rpl_filter.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index 3a0fca4dfa5..95b5ecba895 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -1,10 +1,8 @@ -/* - Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,11 +11,10 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mysql_priv.h" #include "rpl_injector.h" -#ifdef HAVE_ROW_BASED_REPLICATION /* injector::transaction - member definitions @@ -191,5 +188,3 @@ void injector::new_trans(THD *thd, injector::transaction *ptr) DBUG_VOID_RETURN; } - -#endif diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h index 17251f54746..61c2e0ecebc 100644 --- a/sql/rpl_injector.h +++ b/sql/rpl_injector.h @@ -1,10 +1,8 @@ -/* - Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef INJECTOR_H #define INJECTOR_H @@ -21,7 +19,6 @@ /* Pull in 'byte', 'my_off_t', and 'uint32' */ #include <my_global.h> -#ifdef HAVE_ROW_BASED_REPLICATION #include <my_bitmap.h> /* Forward declarations */ @@ -287,12 +284,14 @@ public: */ int check_state(enum_state const target_state) { +#ifndef DBUG_OFF static char const *state_name[] = { "START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT" }; DBUG_ASSERT(0 <= target_state && target_state <= STATE_COUNT); DBUG_PRINT("info", ("In state %s", state_name[m_state])); +#endif if (m_state <= target_state && target_state <= m_state + 1 && m_state < STATE_COUNT) @@ -331,5 +330,4 @@ private: */ }; -#endif /* HAVE_ROW_BASED_REPLICATION */ #endif /* INJECTOR_H */ diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index c89c8aa131e..1c426eff768 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index f0a7d6681fe..ae77e64d93a 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index a2edb9dc8a8..6a7b22bf23d 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index d737055baf2..cb9894a2125 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index 97f0066233c..7df4bcbdde7 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_tblmap.h b/sql/rpl_tblmap.h index 23864bd329e..dbc968d0f67 100644 --- a/sql/rpl_tblmap.h +++ b/sql/rpl_tblmap.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 4bed1343e55..65a44a4947b 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -1,9 +1,8 @@ -/* Copyright 2006 MySQL AB. All rights reserved. +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "rpl_utility.h" diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index df0b0cd2ee1..34cebf93ddb 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -1,9 +1,8 @@ -/* Copyright 2006 MySQL AB. All rights reserved. +/* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef RPL_UTILITY_H #define RPL_UTILITY_H diff --git a/sql/scheduler.cc b/sql/scheduler.cc new file mode 100644 index 00000000000..b05bdf4756f --- /dev/null +++ b/sql/scheduler.cc @@ -0,0 +1,88 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Implementation for the thread scheduler +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma implementation +#endif + +#include <mysql_priv.h> + +/* + 'Dummy' functions to be used when we don't need any handling for a scheduler + event + */ + +static bool init_dummy(void) {return 0;} +static void post_kill_dummy(THD* thd) {} +static void end_dummy(void) {} +static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; } + +/* + Initialize default scheduler with dummy functions so that setup functions + only need to declare those that are relvant for their usage +*/ + +scheduler_functions::scheduler_functions() + :init(init_dummy), + init_new_connection_thread(init_new_connection_handler_thread), + add_connection(0), // Must be defined + post_kill_notification(post_kill_dummy), + end_thread(end_thread_dummy), end(end_dummy) +{} + + +/* + End connection, in case when we are using 'no-threads' +*/ + +static bool no_threads_end(THD *thd, bool put_in_cache) +{ + unlink_thd(thd); + pthread_mutex_unlock(&LOCK_thread_count); + return 1; // Abort handle_one_connection +} + + +/* + Initailize scheduler for --thread-handling=no-threads +*/ + +void one_thread_scheduler(scheduler_functions* func) +{ + func->max_threads= 1; +#ifndef EMBEDDED_LIBRARY + func->add_connection= handle_connection_in_main_thread; +#endif + func->init_new_connection_thread= init_dummy; + func->end_thread= no_threads_end; +} + + +/* + Initialize scheduler for --thread-handling=one-thread-per-connection +*/ + +#ifndef EMBEDDED_LIBRARY +void one_thread_per_connection_scheduler(scheduler_functions* func) +{ + func->max_threads= max_connections; + func->add_connection= create_thread_to_handle_connection; + func->end_thread= one_thread_per_connection_end; +} +#endif /* EMBEDDED_LIBRARY */ diff --git a/sql/scheduler.h b/sql/scheduler.h new file mode 100644 index 00000000000..8351cefda4c --- /dev/null +++ b/sql/scheduler.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Classes for the thread scheduler +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface +#endif + +class THD; + +/* Functions used when manipulating threads */ + +class scheduler_functions +{ +public: + uint max_threads; + bool (*init)(void); + bool (*init_new_connection_thread)(void); + void (*add_connection)(THD *thd); + void (*post_kill_notification)(THD *thd); + bool (*end_thread)(THD *thd, bool cache_thread); + void (*end)(void); + scheduler_functions(); +}; + +enum scheduler_types +{ + SCHEDULER_ONE_THREAD_PER_CONNECTION=1, + SCHEDULER_NO_THREADS, + SCHEDULER_POOL_OF_THREADS +}; + +void one_thread_per_connection_scheduler(scheduler_functions* func); +void one_thread_scheduler(scheduler_functions* func); + +enum pool_command_op +{ + NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP +}; + +#define HAVE_POOL_OF_THREADS 0 /* For easyer tests */ +#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A) + +class thd_scheduler +{}; diff --git a/sql/set_var.cc b/sql/set_var.cc index bd68863ff97..2d40cb67bab 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -81,7 +80,8 @@ extern my_bool innobase_log_archive, innobase_use_doublewrite, innobase_use_checksums, innobase_file_per_table, - innobase_locks_unsafe_for_binlog; + innobase_locks_unsafe_for_binlog, + innobase_rollback_on_timeout; extern "C" { extern ulong srv_max_buf_pool_modified_pct; @@ -119,9 +119,6 @@ TYPELIB delay_key_write_typelib= delay_key_write_type_names, NULL }; -static int sys_check_charset(THD *thd, set_var *var); -static bool sys_update_charset(THD *thd, set_var *var); -static void sys_set_default_charset(THD *thd, enum_var_type type); static int sys_check_ftb_syntax(THD *thd, set_var *var); static bool sys_update_ftb_syntax(THD *thd, set_var * var); static void sys_default_ftb_syntax(THD *thd, enum_var_type type); @@ -381,7 +378,7 @@ sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size", &SV::preload_buff_size); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", &SV::read_buff_size); -sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); +sys_var_opt_readonly sys_readonly("read_only", &opt_readonly); sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size", &SV::read_rnd_buff_size); sys_var_thd_ulong sys_div_precincrement("div_precision_increment", @@ -411,6 +408,10 @@ sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size", sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size", &SV::trans_prealloc_size, 0, fix_trans_mem_root); +sys_var_thd_enum sys_thread_handling("thread_handling", + &SV::thread_handling, + &thread_handling_typelib, + NULL); #ifdef HAVE_QUERY_CACHE sys_var_long_ptr sys_query_cache_limit("query_cache_limit", @@ -479,6 +480,10 @@ sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout", &table_lock_wait_timeout); sys_var_long_ptr sys_thread_cache_size("thread_cache_size", &thread_cache_size); +#if HAVE_POOL_OF_THREADS == 1 +sys_var_long_ptr sys_thread_pool_size("thread_pool_size", + &thread_pool_size); +#endif sys_var_thd_enum sys_tx_isolation("tx_isolation", &SV::tx_isolation, &tx_isolation_typelib, @@ -683,7 +688,6 @@ sys_var_have_variable sys_have_query_cache("have_query_cache", &have_query_cache); sys_var_have_variable sys_have_rtree_keys("have_rtree_keys", &have_rtree_keys); sys_var_have_variable sys_have_symlink("have_symlink", &have_symlink); -sys_var_have_variable sys_have_row_based_replication("have_row_based_replication",&have_row_based_replication); /* Global read-only variable describing server license */ sys_var_const_str sys_license("license", STRINGIFY_ARG(LICENSE)); @@ -806,7 +810,6 @@ SHOW_VAR init_vars[]= { {sys_have_openssl.name, (char*) &have_openssl, SHOW_HAVE}, {sys_have_partition_db.name,(char*) &have_partition_db, SHOW_HAVE}, {sys_have_query_cache.name, (char*) &have_query_cache, SHOW_HAVE}, - {sys_have_row_based_replication.name, (char*) &have_row_based_replication, SHOW_HAVE}, {sys_have_rtree_keys.name, (char*) &have_rtree_keys, SHOW_HAVE}, {sys_have_symlink.name, (char*) &have_symlink, SHOW_HAVE}, {"init_connect", (char*) &sys_init_connect, SHOW_SYS}, @@ -839,6 +842,7 @@ SHOW_VAR init_vars[]= { {sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG }, + {"innodb_rollback_on_timeout", (char*) &innobase_rollback_on_timeout, SHOW_MY_BOOL}, {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS}, {sys_innodb_sync_spin_loops.name, (char*) &sys_innodb_sync_spin_loops, SHOW_SYS}, {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, @@ -1034,6 +1038,10 @@ SHOW_VAR init_vars[]= { #ifdef HAVE_THR_SETCONCURRENCY {"thread_concurrency", (char*) &concurrency, SHOW_LONG}, #endif + {sys_thread_handling.name, (char*) &sys_thread_handling, SHOW_SYS}, +#if HAVE_POOL_OF_THREADS == 1 + {sys_thread_pool_size.name, (char*) &sys_thread_pool_size, SHOW_SYS}, +#endif {"thread_stack", (char*) &my_thread_stack_size, SHOW_LONG}, {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS}, {"time_zone", (char*) &sys_time_zone, SHOW_SYS}, @@ -1255,14 +1263,14 @@ static int check_completion_type(THD *thd, set_var *var) static void fix_net_read_timeout(THD *thd, enum_var_type type) { if (type != OPT_GLOBAL) - thd->net.read_timeout=thd->variables.net_read_timeout; + net_set_read_timeout(&thd->net, thd->variables.net_read_timeout); } static void fix_net_write_timeout(THD *thd, enum_var_type type) { if (type != OPT_GLOBAL) - thd->net.write_timeout=thd->variables.net_write_timeout; + net_set_write_timeout(&thd->net, thd->variables.net_write_timeout); } static void fix_net_retry_count(THD *thd, enum_var_type type) @@ -1339,10 +1347,6 @@ bool sys_var_thd_binlog_format::is_readonly() const If we don't have row-based replication compiled in, the variable is always read-only. */ -#ifndef HAVE_ROW_BASED_REPLICATION - my_error(ER_RBR_NOT_AVAILABLE, MYF(0)); - return 1; -#else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW) && thd->temporary_tables) { @@ -1367,16 +1371,13 @@ bool sys_var_thd_binlog_format::is_readonly() const return 1; } #endif /* HAVE_NDB_BINLOG */ -#endif /* HAVE_ROW_BASED_REPLICATION */ return sys_var_thd_enum::is_readonly(); } void fix_binlog_format_after_update(THD *thd, enum_var_type type) { -#ifdef HAVE_ROW_BASED_REPLICATION thd->reset_current_stmt_binlog_row_based(); -#endif /*HAVE_ROW_BASED_REPLICATION*/ } @@ -1455,9 +1456,9 @@ static void fix_server_id(THD *thd, enum_var_type type) sys_var_long_ptr:: -sys_var_long_ptr(const char *name_arg, ulong *value_ptr, +sys_var_long_ptr(const char *name_arg, ulong *value_ptr_arg, sys_after_update_func after_update_arg) - :sys_var_long_ptr_global(name_arg, value_ptr, + :sys_var_long_ptr_global(name_arg, value_ptr_arg, &LOCK_global_system_variables, after_update_arg) {} @@ -1807,7 +1808,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) /* As there was no local variable, return the global value */ var_type= OPT_GLOBAL; } - switch (type()) { + switch (show_type()) { case SHOW_INT: { uint value; @@ -2632,7 +2633,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str, file_log= logger.get_log_file_handler(); break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } if (!old_value) @@ -3019,17 +3020,39 @@ byte *sys_var_max_user_conn::value_ptr(THD *thd, enum_var_type type, return (byte*) &(max_user_connections); } + bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var) { - char *locale_str =var->value->str_value.c_ptr(); - MY_LOCALE *locale_match= my_locale_by_name(locale_str); + MY_LOCALE *locale_match; - if (locale_match == NULL) + if (var->value->result_type() == INT_RESULT) { - my_printf_error(ER_UNKNOWN_ERROR, - "Unknown locale: '%s'", MYF(0), locale_str); - return 1; + if (!(locale_match= my_locale_by_number((uint) var->value->val_int()))) + { + char buf[20]; + int10_to_str((int) var->value->val_int(), buf, -10); + my_printf_error(ER_UNKNOWN_ERROR, "Unknown locale: '%s'", MYF(0), buf); + return 1; + } } + else // STRING_RESULT + { + char buff[6]; + String str(buff, sizeof(buff), &my_charset_latin1), *res; + if (!(res=var->value->val_str(&str))) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL"); + return 1; + } + const char *locale_str= res->c_ptr(); + if (!(locale_match= my_locale_by_name(locale_str))) + { + my_printf_error(ER_UNKNOWN_ERROR, + "Unknown locale: '%s'", MYF(0), locale_str); + return 1; + } + } + var->save_result.locale_value= locale_match; return 0; } @@ -3649,7 +3672,7 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var) */ byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd, - ulong val, + ulonglong val, ulong *len) { char buff[256]; @@ -3890,6 +3913,70 @@ bool sys_var_trust_routine_creators::update(THD *thd, set_var *var) return sys_var_bool_ptr::update(thd, var); } +bool sys_var_opt_readonly::update(THD *thd, set_var *var) +{ + bool result; + + DBUG_ENTER("sys_var_opt_readonly::update"); + + /* Prevent self dead-lock */ + if (thd->locked_tables || thd->active_transaction()) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + DBUG_RETURN(true); + } + + if (thd->global_read_lock) + { + /* + This connection already holds the global read lock. + This can be the case with: + - FLUSH TABLES WITH READ LOCK + - SET GLOBAL READ_ONLY = 1 + */ + result= sys_var_bool_ptr::update(thd, var); + DBUG_RETURN(result); + } + + /* + Perform a 'FLUSH TABLES WITH READ LOCK'. + This is a 3 step process: + - [1] lock_global_read_lock() + - [2] close_cached_tables() + - [3] make_global_read_lock_block_commit() + [1] prevents new connections from obtaining tables locked for write. + [2] waits until all existing connections close their tables. + [3] prevents transactions from being committed. + */ + + if (lock_global_read_lock(thd)) + DBUG_RETURN(true); + + /* + This call will be blocked by any connection holding a READ or WRITE lock. + Ideally, we want to wait only for pending WRITE locks, but since: + con 1> LOCK TABLE T FOR READ; + con 2> LOCK TABLE T FOR WRITE; (blocked by con 1) + con 3> SET GLOBAL READ ONLY=1; (blocked by con 2) + can cause to wait on a read lock, it's required for the client application + to unlock everything, and acceptable for the server to wait on all locks. + */ + if (result= close_cached_tables(thd, true, NULL, false)) + goto end_with_read_lock; + + if (result= make_global_read_lock_block_commit(thd)) + goto end_with_read_lock; + + /* Change the opt_readonly system variable, safe because the lock is held */ + result= sys_var_bool_ptr::update(thd, var); + +end_with_read_lock: + /* Release the lock */ + unlock_global_read_lock(thd); + DBUG_RETURN(result); +} + + /* even session variable here requires SUPER, because of -#o,file */ bool sys_var_thd_dbug::check(THD *thd, set_var *var) { @@ -3955,15 +4042,13 @@ sys_var_event_scheduler::update(THD *thd, set_var *var) DBUG_PRINT("info", ("new_value: %d", (int) var->save_result.ulong_value)); - Item_result var_type= var->value->result_type(); - if (var->save_result.ulong_value == Events::EVENTS_ON) res= Events::get_instance()->start_execution_of_events(); else if (var->save_result.ulong_value == Events::EVENTS_OFF) res= Events::get_instance()->stop_execution_of_events(); else { - DBUG_ASSERT(0); + assert(0); // Impossible } if (res) my_error(ER_EVENT_SET_VAR_ERROR, MYF(0)); diff --git a/sql/set_var.h b/sql/set_var.h index 17f9b248c07..0540f9964e0 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2002-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -65,8 +64,8 @@ public: bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names); bool check_set(THD *thd, set_var *var, TYPELIB *enum_names); virtual bool update(THD *thd, set_var *var)=0; - virtual void set_default(THD *thd, enum_var_type type) {} - virtual SHOW_TYPE type() { return SHOW_UNDEF; } + virtual void set_default(THD *thd_arg, enum_var_type type) {} + virtual SHOW_TYPE show_type() { return SHOW_UNDEF; } virtual byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return 0; } virtual bool check_type(enum_var_type type) @@ -106,14 +105,16 @@ class sys_var_long_ptr_global: public sys_var_global { public: ulong *value; - sys_var_long_ptr_global(const char *name_arg, ulong *value_ptr, + sys_var_long_ptr_global(const char *name_arg, ulong *value_ptr_arg, pthread_mutex_t *guard_arg, sys_after_update_func after_update_arg= NULL) - :sys_var_global(name_arg, after_update_arg, guard_arg), value(value_ptr) {} + :sys_var_global(name_arg, after_update_arg, guard_arg), + value(value_ptr_arg) + {} bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_LONG; } + SHOW_TYPE show_type() { return SHOW_LONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) value; } }; @@ -135,14 +136,14 @@ class sys_var_ulonglong_ptr :public sys_var { public: ulonglong *value; - sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr) - :sys_var(name_arg),value(value_ptr) {} - sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr, + sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr_arg) + :sys_var(name_arg),value(value_ptr_arg) {} + sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr_arg, sys_after_update_func func) - :sys_var(name_arg,func), value(value_ptr) {} + :sys_var(name_arg,func), value(value_ptr_arg) {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_LONGLONG; } + SHOW_TYPE show_type() { return SHOW_LONGLONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) value; } }; @@ -161,7 +162,7 @@ public: } bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_MY_BOOL; } + SHOW_TYPE show_type() { return SHOW_MY_BOOL; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) value; } bool check_update_type(Item_result type) { return 0; } @@ -193,7 +194,7 @@ public: { (*set_default_func)(thd, type); } - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) value; } bool check_update_type(Item_result type) @@ -219,7 +220,7 @@ public: { return 1; } - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) value; @@ -248,7 +249,7 @@ public: { return 1; } - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) *value; @@ -276,7 +277,7 @@ public: return check_enum(thd, var, enum_names); } bool update(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_update_type(Item_result type) { return 0; } }; @@ -311,7 +312,7 @@ public: bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_LONG; } + SHOW_TYPE show_type() { return SHOW_LONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -329,7 +330,7 @@ public: {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_HA_ROWS; } + SHOW_TYPE show_type() { return SHOW_HA_ROWS; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -349,7 +350,7 @@ public: {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_LONGLONG; } + SHOW_TYPE show_type() { return SHOW_LONGLONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_default(enum_var_type type) { @@ -375,7 +376,7 @@ public: {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_MY_BOOL; } + SHOW_TYPE show_type() { return SHOW_MY_BOOL; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check(THD *thd, set_var *var) { @@ -418,7 +419,7 @@ public: } bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_update_type(Item_result type) { return 0; } }; @@ -439,7 +440,7 @@ public: } void set_default(THD *thd, enum_var_type type); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); - static byte *symbolic_mode_representation(THD *thd, ulong sql_mode, + static byte *symbolic_mode_representation(THD *thd, ulonglong sql_mode, ulong *length); }; @@ -453,7 +454,7 @@ public: :sys_var_thd(name_arg), offset(offset_arg) {} bool check(THD *thd, set_var *var); -SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return type != STRING_RESULT; /* Only accept strings */ @@ -479,11 +480,11 @@ class sys_var_thd_bit :public sys_var_thd sys_check_func check_func; sys_update_func update_func; public: - ulong bit_flag; + ulonglong bit_flag; bool reverse; sys_var_thd_bit(const char *name_arg, sys_check_func c_func, sys_update_func u_func, - ulong bit, bool reverse_arg=0) + ulonglong bit, bool reverse_arg=0) :sys_var_thd(name_arg), check_func(c_func), update_func(u_func), bit_flag(bit), reverse(reverse_arg) {} @@ -491,7 +492,7 @@ public: bool update(THD *thd, set_var *var); bool check_update_type(Item_result type) { return 0; } bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } - SHOW_TYPE type() { return SHOW_MY_BOOL; } + SHOW_TYPE show_type() { return SHOW_MY_BOOL; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -501,7 +502,7 @@ public: sys_var_thd_dbug(const char *name_arg) :sys_var_thd(name_arg) {} bool check_update_type(Item_result type) { return type != STRING_RESULT; } bool check(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type) { DBUG_POP(); } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b); @@ -519,7 +520,7 @@ public: void set_default(THD *thd, enum_var_type type); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } bool check_default(enum_var_type type) { return 0; } - SHOW_TYPE type() { return SHOW_LONG; } + SHOW_TYPE show_type() { return SHOW_LONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -530,7 +531,7 @@ public: sys_var_last_insert_id(const char *name_arg) :sys_var(name_arg) {} bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } - SHOW_TYPE type() { return SHOW_LONGLONG; } + SHOW_TYPE show_type() { return SHOW_LONGLONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -541,7 +542,7 @@ public: sys_var_insert_id(const char *name_arg) :sys_var(name_arg) {} bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } - SHOW_TYPE type() { return SHOW_LONGLONG; } + SHOW_TYPE show_type() { return SHOW_LONGLONG; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -556,15 +557,15 @@ public: bool check_type(enum_var_type type) { return type != OPT_GLOBAL; } /* We can't retrieve the value of this, so we don't have to define - type() or value_ptr() + show_type() or value_ptr() */ }; class sys_var_sync_binlog_period :public sys_var_long_ptr { public: - sys_var_sync_binlog_period(const char *name_arg, ulong *value_ptr) - :sys_var_long_ptr(name_arg,value_ptr) {} + sys_var_sync_binlog_period(const char *name_arg, ulong *value_ptr_arg) + :sys_var_long_ptr(name_arg,value_ptr_arg) {} bool update(THD *thd, set_var *var); }; #endif @@ -594,7 +595,7 @@ public: no_support_one_shot= 0; } bool check(THD *thd, set_var *var); -SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return ((type != STRING_RESULT) && (type != INT_RESULT)); @@ -618,7 +619,7 @@ public: no_support_one_shot= 0; } bool check(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return ((type != STRING_RESULT) && (type != INT_RESULT)); @@ -734,7 +735,7 @@ public: :sys_var_key_cache_param(name_arg, offsetof(KEY_CACHE, param_buff_size)) {} bool update(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_LONGLONG; } + SHOW_TYPE show_type() { return SHOW_LONGLONG; } }; @@ -745,7 +746,7 @@ public: :sys_var_key_cache_param(name_arg, offset_arg) {} bool update(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_LONG; } + SHOW_TYPE show_type() { return SHOW_LONG; } }; @@ -760,7 +761,7 @@ public: :sys_var_thd(name_arg), offset(offset_arg), date_time_type(date_time_type_arg) {} - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return type != STRING_RESULT; /* Only accept strings */ @@ -802,7 +803,7 @@ public: byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_update_type(Item_result type) { return 0; } void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } }; @@ -812,13 +813,13 @@ class sys_var_readonly: public sys_var { public: enum_var_type var_type; - SHOW_TYPE show_type; + SHOW_TYPE show_type_value; sys_value_ptr_func value_ptr_func; sys_var_readonly(const char *name_arg, enum_var_type type, SHOW_TYPE show_type_arg, sys_value_ptr_func value_ptr_func_arg) :sys_var(name_arg), var_type(type), - show_type(show_type_arg), value_ptr_func(value_ptr_func_arg) + show_type_value(show_type_arg), value_ptr_func(value_ptr_func_arg) {} bool update(THD *thd, set_var *var) { return 1; } bool check_default(enum_var_type type) { return 1; } @@ -828,7 +829,7 @@ public: { return (*value_ptr_func)(thd); } - SHOW_TYPE type() { return show_type; } + SHOW_TYPE show_type() { return show_type_value; } bool is_readonly() const { return 1; } }; @@ -851,7 +852,7 @@ public: bool check_default(enum_var_type type) { return 1; } bool check_type(enum_var_type type) { return type != OPT_GLOBAL; } bool check_update_type(Item_result type) { return 1; } - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool is_readonly() const { return 1; } }; @@ -865,7 +866,7 @@ public: no_support_one_shot= 0; } bool check(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return type != STRING_RESULT; /* Only accept strings */ @@ -889,7 +890,7 @@ public: return type != OPT_GLOBAL || !option_limits; } void set_default(THD *thd, enum_var_type type); - SHOW_TYPE type() { return SHOW_INT; } + SHOW_TYPE show_type() { return SHOW_INT; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -905,17 +906,35 @@ public: }; +/** + Handler for setting the system variable --read-only. +*/ + +class sys_var_opt_readonly :public sys_var_bool_ptr +{ +public: + sys_var_opt_readonly(const char *name_arg, my_bool *value_arg) : + sys_var_bool_ptr(name_arg, value_arg) {}; + ~sys_var_opt_readonly() {}; + bool update(THD *thd, set_var *var); +}; + + class sys_var_thd_lc_time_names :public sys_var_thd { public: sys_var_thd_lc_time_names(const char *name_arg): - sys_var_thd(name_arg) - {} + sys_var_thd(name_arg) + { +#if MYSQL_VERSION_ID < 50000 + no_support_one_shot= 0; +#endif + } bool check(THD *thd, set_var *var); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { - return type != STRING_RESULT; /* Only accept strings */ + return ((type != STRING_RESULT) && (type != INT_RESULT)); } bool check_default(enum_var_type type) { return 0; } bool update(THD *thd, set_var *var); @@ -932,7 +951,7 @@ public: sys_var_long_ptr(name_arg, NULL, NULL) {}; bool update(THD *thd, set_var *var); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); - SHOW_TYPE type() { return SHOW_CHAR; } + SHOW_TYPE show_type() { return SHOW_CHAR; } bool check(THD *thd, set_var *var); bool check_update_type(Item_result type) { @@ -940,9 +959,7 @@ public: } }; -#ifdef HAVE_ROW_BASED_REPLICATION extern void fix_binlog_format_after_update(THD *thd, enum_var_type type); -#endif class sys_var_thd_binlog_format :public sys_var_thd_enum { @@ -950,9 +967,7 @@ public: sys_var_thd_binlog_format(const char *name_arg, ulong SV::*offset_arg) :sys_var_thd_enum(name_arg, offset_arg, &binlog_format_typelib -#ifdef HAVE_ROW_BASED_REPLICATION , fix_binlog_format_after_update -#endif ) {}; bool is_readonly() const; @@ -995,8 +1010,8 @@ public: } save_result; LEX_STRING base; /* for structs */ - set_var(enum_var_type type_arg, sys_var *var_arg, const LEX_STRING *base_name_arg, - Item *value_arg) + set_var(enum_var_type type_arg, sys_var *var_arg, + const LEX_STRING *base_name_arg, Item *value_arg) :var(var_arg), type(type_arg), base(*base_name_arg) { /* diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index 6d905ba35dc..68b393e619f 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -2,8 +2,7 @@ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml index 3f1a25072b7..80b844e2f19 100644 --- a/sql/share/charsets/Index.xml +++ b/sql/share/charsets/Index.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/armscii8.xml b/sql/share/charsets/armscii8.xml index d0ab428345f..714e57bb12e 100644 --- a/sql/share/charsets/armscii8.xml +++ b/sql/share/charsets/armscii8.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/ascii.xml b/sql/share/charsets/ascii.xml index 3813bd42601..97006c53680 100644 --- a/sql/share/charsets/ascii.xml +++ b/sql/share/charsets/ascii.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp1250.xml b/sql/share/charsets/cp1250.xml index b83d0faeca8..bd0d7d3f3c0 100644 --- a/sql/share/charsets/cp1250.xml +++ b/sql/share/charsets/cp1250.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp1251.xml b/sql/share/charsets/cp1251.xml index 7f94788c0d0..b80db9f8ec0 100644 --- a/sql/share/charsets/cp1251.xml +++ b/sql/share/charsets/cp1251.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp1256.xml b/sql/share/charsets/cp1256.xml index 69eb6a68238..64cb253145c 100644 --- a/sql/share/charsets/cp1256.xml +++ b/sql/share/charsets/cp1256.xml @@ -9,8 +9,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp1257.xml b/sql/share/charsets/cp1257.xml index 93a1bd47a77..0c2688c264e 100644 --- a/sql/share/charsets/cp1257.xml +++ b/sql/share/charsets/cp1257.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp850.xml b/sql/share/charsets/cp850.xml index 79497aa17f1..4076a5f6a56 100644 --- a/sql/share/charsets/cp850.xml +++ b/sql/share/charsets/cp850.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp852.xml b/sql/share/charsets/cp852.xml index 73a81e54b02..25b622d2a4b 100644 --- a/sql/share/charsets/cp852.xml +++ b/sql/share/charsets/cp852.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/cp866.xml b/sql/share/charsets/cp866.xml index 1a72b396c7c..fa2e1865de6 100644 --- a/sql/share/charsets/cp866.xml +++ b/sql/share/charsets/cp866.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/dec8.xml b/sql/share/charsets/dec8.xml index 2cb28cb0f4f..2cd52de464a 100644 --- a/sql/share/charsets/dec8.xml +++ b/sql/share/charsets/dec8.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/geostd8.xml b/sql/share/charsets/geostd8.xml index c09aa078fb7..5e3816975d6 100644 --- a/sql/share/charsets/geostd8.xml +++ b/sql/share/charsets/geostd8.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/greek.xml b/sql/share/charsets/greek.xml index 1cfe6b49610..000019a8ce0 100644 --- a/sql/share/charsets/greek.xml +++ b/sql/share/charsets/greek.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/hebrew.xml b/sql/share/charsets/hebrew.xml index 5bcf222a728..20d68487301 100644 --- a/sql/share/charsets/hebrew.xml +++ b/sql/share/charsets/hebrew.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -40,7 +39,7 @@ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 - 02 02 02 02 02 02 02 02 02 02 02 00 00 00 00 00 + 02 02 02 02 02 02 02 02 02 02 02 00 00 20 20 00 </map> </ctype> @@ -106,7 +105,7 @@ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2017 05D0 05D1 05D2 05D3 05D4 05D5 05D6 05D7 05D8 05D9 05DA 05DB 05DC 05DD 05DE 05DF -05E0 05E1 05E2 05E3 05E4 05E5 05E6 05E7 05E8 05E9 05EA 0000 0000 0000 0000 0000 +05E0 05E1 05E2 05E3 05E4 05E5 05E6 05E7 05E8 05E9 05EA 0000 0000 200E 200F 0000 </map> </unicode> diff --git a/sql/share/charsets/hp8.xml b/sql/share/charsets/hp8.xml index 35224f8c544..3ab383ef386 100644 --- a/sql/share/charsets/hp8.xml +++ b/sql/share/charsets/hp8.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/keybcs2.xml b/sql/share/charsets/keybcs2.xml index 6332891ef23..7335a0f428d 100644 --- a/sql/share/charsets/keybcs2.xml +++ b/sql/share/charsets/keybcs2.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/koi8r.xml b/sql/share/charsets/koi8r.xml index 033597e9bfc..2d8473f6440 100644 --- a/sql/share/charsets/koi8r.xml +++ b/sql/share/charsets/koi8r.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/koi8u.xml b/sql/share/charsets/koi8u.xml index 4f5fa35af3d..16177627ffe 100644 --- a/sql/share/charsets/koi8u.xml +++ b/sql/share/charsets/koi8u.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/latin1.xml b/sql/share/charsets/latin1.xml index 5814a17b0e1..88ceff440d5 100644 --- a/sql/share/charsets/latin1.xml +++ b/sql/share/charsets/latin1.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/latin2.xml b/sql/share/charsets/latin2.xml index 7f00148a1df..6b887b927a4 100644 --- a/sql/share/charsets/latin2.xml +++ b/sql/share/charsets/latin2.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml index 5004f045889..9c23200a46d 100644 --- a/sql/share/charsets/latin5.xml +++ b/sql/share/charsets/latin5.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml index dd87a1a2d89..02d3ff8b17e 100644 --- a/sql/share/charsets/latin7.xml +++ b/sql/share/charsets/latin7.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/macce.xml b/sql/share/charsets/macce.xml index 61f6d79b34f..21e303609cf 100644 --- a/sql/share/charsets/macce.xml +++ b/sql/share/charsets/macce.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/macroman.xml b/sql/share/charsets/macroman.xml index 36c8e8cf13a..2b43fe73b07 100644 --- a/sql/share/charsets/macroman.xml +++ b/sql/share/charsets/macroman.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/charsets/swe7.xml b/sql/share/charsets/swe7.xml index 2b8ff4edcce..17fa6b7d9bc 100644 --- a/sql/share/charsets/swe7.xml +++ b/sql/share/charsets/swe7.xml @@ -7,8 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index c64f4da045e..29fde49bbd6 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -78,7 +78,7 @@ ER_CANT_CREATE_TABLE cze "Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)" dan "Kan ikke oprette tabellen '%-.64s' (Fejlkode: %d)" nla "Kan tabel '%-.64s' niet aanmaken (Errcode: %d)" - eng "Can't create table '%-.64s' (errno: %d)" + eng "Can't create table '%-.200s' (errno: %d)" jps "'%-.64s' ƒe[ƒuƒ‹‚ªì‚ê‚Ü‚¹‚ñ.(errno: %d)", est "Ei suuda luua tabelit '%-.64s' (veakood: %d)" fre "Ne peut créer la table '%-.64s' (Errcode: %d)" @@ -574,7 +574,7 @@ ER_ERROR_ON_RENAME cze "Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)" dan "Fejl ved omdøbning af '%-.64s' til '%-.64s' (Fejlkode: %d)" nla "Fout bij het hernoemen van '%-.64s' naar '%-.64s' (Errcode: %d)" - eng "Error on rename of '%-.64s' to '%-.64s' (errno: %d)" + eng "Error on rename of '%-.150s' to '%-.150s' (errno: %d)" jps "'%-.64s' ‚ð '%-.64s' ‚É rename ‚Å‚«‚Ü‚¹‚ñ (errno: %d)", est "Viga faili '%-.64s' ümbernimetamisel '%-.64s'-ks (veakood: %d)" fre "Erreur en renommant '%-.64s' en '%-.64s' (Errcode: %d)" @@ -950,7 +950,7 @@ ER_CON_COUNT_ERROR 08004 eng "Too many connections" jps "Ú‘±‚ª‘½‚·‚¬‚Ü‚·", est "Liiga palju samaaegseid ühendusi" - fre "Trop de connections" + fre "Trop de connexions" ger "Zu viele Verbindungen" greek "ÕðÜñ÷ïõí ðïëëÝò óõíäÝóåéò..." hun "Tul sok kapcsolat" @@ -1479,30 +1479,30 @@ ER_DUP_KEYNAME 42000 S1009 swe "Nyckelnamn '%-.64s' finns flera gånger" ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.64s'" ER_DUP_ENTRY 23000 S1009 - cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe '%-.64s')" - dan "Ens værdier '%-.64s' for indeks '%-.64s'" - nla "Dubbele ingang '%-.64s' voor zoeksleutel '%-.64s'" - eng "Duplicate entry '%-.64s' for key '%-.64s'" - jps "'%-.64s' ‚Í key '%-.64s' ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·", - est "Kattuv väärtus '%-.64s' võtmele '%-.64s'" - fre "Duplicata du champ '%-.64s' pour la clef '%-.64s'" - ger "Doppelter Eintrag '%-.64s' für Schlüssel '%-.64s'" - greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß '%-.64s'" - hun "Duplikalt bejegyzes '%-.64s' a '%-.64s' kulcs szerint." - ita "Valore duplicato '%-.64s' per la chiave '%-.64s'" - jpn "'%-.64s' ¤Ï key '%-.64s' ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹" - kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key '%-.64s'" - nor "Like verdier '%-.64s' for nøkkel '%-.64s'" - norwegian-ny "Like verdiar '%-.64s' for nykkel '%-.64s'" - pol "Powtórzone wyst?pienie '%-.64s' dla klucza '%-.64s'" - por "Entrada '%-.64s' duplicada para a chave '%-.64s'" - rum "Cimpul '%-.64s' e duplicat pentru cheia '%-.64s'" - rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ '%-.64s'" - serbian "Dupliran unos '%-.64s' za kljuè '%-.64s'" - slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa '%-.64s')" - spa "Entrada duplicada '%-.64s' para la clave '%-.64s'" - swe "Dubbel nyckel '%-.64s' för nyckel '%-.64s'" - ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ '%-.64s'" + cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe %d)" + dan "Ens værdier '%-.64s' for indeks %d" + nla "Dubbele ingang '%-.64s' voor zoeksleutel %d" + eng "Duplicate entry '%-.64s' for key %d" + jps "'%-.64s' ‚Í key %d ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·", + est "Kattuv väärtus '%-.64s' võtmele %d" + fre "Duplicata du champ '%-.64s' pour la clef %d" + ger "Doppelter Eintrag '%-.64s' für Schlüssel %d" + greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß %d" + hun "Duplikalt bejegyzes '%-.64s' a %d kulcs szerint." + ita "Valore duplicato '%-.64s' per la chiave %d" + jpn "'%-.64s' ¤Ï key %d ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹" + kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key %d" + nor "Like verdier '%-.64s' for nøkkel %d" + norwegian-ny "Like verdiar '%-.64s' for nykkel %d" + pol "Powtórzone wyst?pienie '%-.64s' dla klucza %d" + por "Entrada '%-.64s' duplicada para a chave %d" + rum "Cimpul '%-.64s' e duplicat pentru cheia %d" + rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ %d" + serbian "Dupliran unos '%-.64s' za kljuè '%d'" + slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa %d)" + spa "Entrada duplicada '%-.64s' para la clave %d" + swe "Dubbel nyckel '%-.64s' för nyckel %d" + ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ %d" ER_WRONG_FIELD_SPEC 42000 S1009 cze "Chybn-Bá specifikace sloupce '%-.64s'" dan "Forkert kolonnespecifikaton for felt '%-.64s'" @@ -1827,7 +1827,7 @@ ER_READY eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d" jps "%s: €”õŠ®—¹", est "%s: ootab ühendusi" - fre "%s: Prêt pour des connections" + fre "%s: Prêt pour des connexions" ger "%-.64s: Bereit für Verbindungen.\nVersion: '%2' Socket: '%s' Port: %d" greek "%s: óå áíáìïíÞ óõíäÝóåùí" hun "%s: kapcsolatra kesz" @@ -1950,7 +1950,7 @@ ER_IPSOCK_ERROR 08S01 eng "Can't create IP socket" jps "IP socket ‚ªì‚ê‚Ü‚¹‚ñ", est "Ei suuda luua IP socketit" - fre "Ne peut créer la connection IP (socket)" + fre "Ne peut créer la connexion IP (socket)" ger "Kann IP-Socket nicht erzeugen" greek "Äåí åßíáé äõíáôÞ ç äçìéïõñãßá IP socket" hun "Az IP socket nem hozhato letre" @@ -3031,7 +3031,7 @@ ER_HOST_IS_BLOCKED eng "Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'" jps "Host '%-.64s' ‚Í many connection error ‚Ì‚½‚ßA‹‘”Û‚³‚ê‚Ü‚µ‚½. 'mysqladmin flush-hosts' ‚ʼn𜂵‚Ä‚‚¾‚³‚¢", est "Masin '%-.64s' on blokeeritud hulgaliste ühendusvigade tõttu. Blokeeringu saab tühistada 'mysqladmin flush-hosts' käsuga" - fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connection. Débloquer le par 'mysqladmin flush-hosts'" + fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connexion. Débloquer le par 'mysqladmin flush-hosts'" ger "Host '%-.64s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'" greek "Ï õðïëïãéóôÞò Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'" hun "A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot" @@ -3533,7 +3533,7 @@ ER_NET_READ_ERROR_FROM_PIPE 08S01 nla "Kreeg leesfout van de verbindings pipe" eng "Got a read error from the connection pipe" est "Viga ühendustoru lugemisel" - fre "Erreur de lecture reçue du pipe de connection" + fre "Erreur de lecture reçue du pipe de connexion" ger "Lese-Fehler bei einer Verbindungs-Pipe" hun "Olvasasi hiba a kapcsolat soran" ita "Rilevato un errore di lettura dalla pipe di connessione" @@ -4331,7 +4331,7 @@ ER_TOO_MANY_USER_CONNECTIONS 42000 nla "Gebruiker %-.64s heeft reeds meer dan 'max_user_connections' actieve verbindingen" eng "User %-.64s already has more than 'max_user_connections' active connections" est "Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga" - fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connections actives" + fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connexions actives" ger "Benutzer '%-.64s' hat mehr als 'max_user_connections' aktive Verbindungen" ita "L'utente %-.64s ha gia' piu' di 'max_user_connections' connessioni attive" por "Usuário '%-.64s' já possui mais que o valor máximo de conexões (max_user_connections) ativas" @@ -5607,6 +5607,8 @@ ER_SP_RECURSION_LIMIT ER_SP_PROC_TABLE_CORRUPT eng "Failed to load routine %-.64s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)" ger "Routine %-64s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)" +ER_FOREIGN_SERVER_EXISTS + eng "The foreign server, %s, you are trying to create already exists." ER_SP_WRONG_NAME 42000 eng "Incorrect routine name '%-.64s'" ger "Ungültiger Routinenname '%-.64s'" @@ -5847,6 +5849,9 @@ ER_BINLOG_ROW_WRONG_TABLE_DEF ER_BINLOG_ROW_RBR_TO_SBR eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events" ger "Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können" +ER_FOREIGN_SERVER_DOESNT_EXIST + eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s" + ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s" ER_EVENT_ALREADY_EXISTS eng "Event '%-.64s' already exists" ger "Event '%-.64s' existiert bereits" @@ -6004,15 +6009,47 @@ ER_BAD_LOG_STATEMENT ger "Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist" ER_NON_INSERTABLE_TABLE eng "The target table %-.100s of the %s is not insertable-into" + ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar" ER_CANT_RENAME_LOG_TABLE eng "Cannot rename '%s'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to '%s'" + ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen beim Umbenennen zu/von einer Logtabelle zwei Tabellen angegeben werden: die Logtabelle zu einer Archivtabelle und eine weitere Tabelle zurück zu '%s'" ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000 eng "Incorrect parameter count in the call to native function '%-.64s'" + ger "Falsche Anzahl von Parametern beim Aufruf der nativen Funktion '%-.64s'" ER_WRONG_PARAMETERS_TO_NATIVE_FCT 42000 eng "Incorrect parameters in the call to native function '%-.64s'" + ger "Falscher Parameter beim Aufruf der nativen Funktion '%-.64s'" ER_WRONG_PARAMETERS_TO_STORED_FCT 42000 eng "Incorrect parameters in the call to stored function '%-.64s'" + ger "Falsche Parameter beim Aufruf der gespeicherten Funktion '%-.64s'" ER_NATIVE_FCT_NAME_COLLISION - eng "This function '%-.64s' has the same name as a native function." + eng "This function '%-.64s' has the same name as a native function" + ger "Die Funktion '%-.64s' hat denselben Namen wie eine native Funktion" +ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009 + cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe '%-.64s')" + dan "Ens værdier '%-.64s' for indeks '%-.64s'" + nla "Dubbele ingang '%-.64s' voor zoeksleutel '%-.64s'" + eng "Duplicate entry '%-.64s' for key '%-.64s'" + jps "'%-.64s' ‚Í key '%-.64s' ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·", + est "Kattuv väärtus '%-.64s' võtmele '%-.64s'" + fre "Duplicata du champ '%-.64s' pour la clef '%-.64s'" + ger "Doppelter Eintrag '%-.64s' für Schlüssel '%-.64s'" + greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß '%-.64s'" + hun "Duplikalt bejegyzes '%-.64s' a '%-.64s' kulcs szerint." + ita "Valore duplicato '%-.64s' per la chiave '%-.64s'" + jpn "'%-.64s' ¤Ï key '%-.64s' ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹" + kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key '%-.64s'" + nor "Like verdier '%-.64s' for nøkkel '%-.64s'" + norwegian-ny "Like verdiar '%-.64s' for nykkel '%-.64s'" + pol "Powtórzone wyst?pienie '%-.64s' dla klucza '%-.64s'" + por "Entrada '%-.64s' duplicada para a chave '%-.64s'" + rum "Cimpul '%-.64s' e duplicat pentru cheia '%-.64s'" + rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ '%-.64s'" + serbian "Dupliran unos '%-.64s' za kljuè '%-.64s'" + slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa '%-.64s')" + spa "Entrada duplicada '%-.64s' para la clave '%-.64s'" + swe "Dubbel nyckel '%-.64s' för nyckel '%-.64s'" + ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ '%-.64s'" ER_BINLOG_PURGE_EMFILE eng "Too many files opened, please execute the command again" + ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus" diff --git a/sql/slave.cc b/sql/slave.cc index 67e8ba20c4f..12418915ad7 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -33,6 +32,7 @@ int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); +#define FLAGSTR(V,F) ((V)&(F)?#F" ":"") #define MAX_SLAVE_RETRY_PAUSE 5 bool use_slave_mask = 0; @@ -73,6 +73,7 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table); static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, const char* table_name, bool overwrite); static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi); +static Log_event* next_event(RELAY_LOG_INFO* rli); /* Find out which replications threads are running @@ -1295,7 +1296,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) rpl_filter->get_wild_ignore_table(&tmp); protocol->store(&tmp); - protocol->store((uint32) mi->rli.last_slave_errno); + protocol->store(mi->rli.last_slave_errno); protocol->store(mi->rli.last_slave_error, &my_charset_bin); protocol->store((uint32) mi->rli.slave_skip_counter); protocol->store((ulonglong) mi->rli.group_master_log_pos); @@ -1326,12 +1327,12 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) && mi->rli.slave_running) { - long tmp= (long)((time_t)time((time_t*) 0) - - mi->rli.last_master_timestamp) - - mi->clock_diff_with_master; + long time_diff= ((long)((time_t)time((time_t*) 0) + - mi->rli.last_master_timestamp) + - mi->clock_diff_with_master); /* - Apparently on some systems tmp can be <0. Here are possible reasons - related to MySQL: + Apparently on some systems time_diff can be <0. Here are possible + reasons related to MySQL: - the master is itself a slave of another master whose time is ahead. - somebody used an explicit SET TIMESTAMP on the master. Possible reason related to granularity-to-second of time functions @@ -1349,8 +1350,8 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) last_master_timestamp == 0 (an "impossible" timestamp 1970) is a special marker to say "consider we have caught up". */ - protocol->store((longlong)(mi->rli.last_master_timestamp ? max(0, tmp) - : 0)); + protocol->store((longlong)(mi->rli.last_master_timestamp ? + max(0, time_diff) : 0)); } else protocol->store_null(); @@ -1421,13 +1422,11 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) */ thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ - thd->net.read_timeout = slave_net_timeout; thd->slave_thread = 1; set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; - thd->real_id=pthread_self(); pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id = thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; pthread_mutex_unlock(&LOCK_thread_count); if (init_thr_lock() || thd->store_globals()) @@ -1437,12 +1436,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) DBUG_RETURN(-1); } -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif - if (thd_type == SLAVE_THD_SQL) thd->proc_info= "Waiting for the next event in relay log"; else @@ -1799,6 +1792,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) if (!ev->when) ev->when = time(NULL); ev->thd = thd; // because up to this point, ev->thd == 0 + DBUG_PRINT("info", ("thd->options={ %s%s}", + FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), + FLAGSTR(thd->options, OPTION_BEGIN))); + exec_res = ev->exec_event(rli); DBUG_PRINT("info", ("exec_event result: %d", exec_res)); DBUG_ASSERT(rli->sql_thd==thd); @@ -2048,15 +2045,16 @@ after reconnect"); while (!io_slave_killed(thd,mi)) { - bool suppress_warnings= 0; + ulong event_len; + suppress_warnings= 0; /* We say "waiting" because read_event() will wait if there's nothing to read. But if there's something to read, it will not wait. The important thing is to not confuse users by saying "reading" whereas we're in fact receiving nothing. */ - thd->proc_info = "Waiting for master to send event"; - ulong event_len = read_event(mysql, mi, &suppress_warnings); + thd->proc_info= "Waiting for master to send event"; + event_len= read_event(mysql, mi, &suppress_warnings); if (io_slave_killed(thd,mi)) { if (global_system_variables.log_warnings) @@ -2857,6 +2855,8 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) pthread_mutex_t *log_lock= rli->relay_log.get_log_lock(); DBUG_ENTER("queue_event"); + LINT_INIT(inc_pos); + if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 && buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */) DBUG_RETURN(queue_old_event(mi,buf,event_len)); @@ -2998,7 +2998,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) err: pthread_mutex_unlock(&mi->data_lock); - DBUG_PRINT("info", ("error=%d", error)); + DBUG_PRINT("info", ("error: %d", error)); DBUG_RETURN(error); } @@ -3318,7 +3318,13 @@ static Log_event* next_event(RELAY_LOG_INFO* rli) hot_log=0; // Using old binary log } } - + /* + As there is no guarantee that the relay is open (for example, an I/O + error during a write by the slave I/O thread may have closed it), we + have to test it. + */ + if (!my_b_inited(cur_log)) + goto err; #ifndef DBUG_OFF { /* This is an assertion which sometimes fails, let's try to track it */ diff --git a/sql/slave.h b/sql/slave.h index 24ba09d78d3..bc039f6eb75 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -112,8 +111,6 @@ extern ulonglong relay_log_space_limit; #define MYSQL_SLAVE_RUN_NOT_CONNECT 1 #define MYSQL_SLAVE_RUN_CONNECT 2 -static Log_event* next_event(RELAY_LOG_INFO* rli); - #define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\ "FIRST") #define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\ diff --git a/sql/sp.cc b/sql/sp.cc index 9e53aff742e..3a7bea6a4b1 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -48,7 +47,7 @@ enum { MYSQL_PROC_FIELD_DB = 0, MYSQL_PROC_FIELD_NAME, - MYSQL_PROC_FIELD_TYPE, + MYSQL_PROC_MYSQL_TYPE, MYSQL_PROC_FIELD_SPECIFIC_NAME, MYSQL_PROC_FIELD_LANGUAGE, MYSQL_PROC_FIELD_ACCESS, @@ -495,8 +494,6 @@ db_create_routine(THD *thd, int type, sp_head *sp) int ret; TABLE *table; char definer[USER_HOST_BUFF_SIZE]; - char old_db_buf[NAME_LEN+1]; - LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; DBUG_ENTER("db_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length, sp->m_name.str)); @@ -534,7 +531,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) store(sp->m_db.str, sp->m_db.length, system_charset_info); table->field[MYSQL_PROC_FIELD_NAME]-> store(sp->m_name.str, sp->m_name.length, system_charset_info); - table->field[MYSQL_PROC_FIELD_TYPE]-> + table->field[MYSQL_PROC_MYSQL_TYPE]-> store((longlong)type, TRUE); table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]-> store(sp->m_name.str, sp->m_name.length, system_charset_info); @@ -734,7 +731,7 @@ print_field_values(THD *thd, TABLE *table, { Protocol *protocol= thd->protocol; - if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type) + if (table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == type) { String db_string; String name_string; @@ -991,7 +988,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); if (sp->m_first_free_instance) { - DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x", + DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x", (ulong)sp->m_first_free_instance, sp->m_first_free_instance->m_recursion_level, sp->m_first_free_instance->m_flags)); @@ -1840,9 +1837,7 @@ create_string(THD *thd, String *buf, SYNOPSIS sp_use_new_db() thd thread handle - new_db new database name (a string and its length) - old_db [IN] str points to a buffer where to store the old database, length contains the size of the buffer [OUT] if old db was not NULL, its name is copied @@ -1850,7 +1845,6 @@ create_string(THD *thd, String *buf, accordingly. Otherwise str[0] is set to '\0' and length is set to 0. The out parameter should be used only if the database name has been changed (see dbchangedp). - dbchangedp [OUT] is set to TRUE if the current database is changed, FALSE otherwise. A database is not changed if the old name is the same as the new one, both names are empty, @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index f5912caddaf..de4e1efd496 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 1021d17b9e2..9d34c9a2fb5 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c0c778c0e8d..b77d0cc9a0c 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -93,10 +92,8 @@ sp_map_item_type(enum enum_field_types type) */ static String * -sp_get_item_value(Item *item, String *str) +sp_get_item_value(THD *thd, Item *item, String *str) { - Item_result result_type= item->result_type(); - switch (item->result_type()) { case REAL_RESULT: case INT_RESULT: @@ -113,15 +110,16 @@ sp_get_item_value(Item *item, String *str) { char buf_holder[STRING_BUFFER_USUAL_SIZE]; String buf(buf_holder, sizeof(buf_holder), result->charset()); + CHARSET_INFO *cs= thd->variables.character_set_client; /* We must reset length of the buffer, because of String specificity. */ buf.length(0); buf.append('_'); buf.append(result->charset()->csname); - if (result->charset()->escape_with_backslash_is_dangerous) + if (cs->escape_with_backslash_is_dangerous) buf.append(' '); - append_query_string(result->charset(), result, &buf); + append_query_string(cs, result, &buf); str->copy(buf); return str; @@ -629,27 +627,6 @@ sp_head::create(THD *thd) DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s", m_type, m_name.str, m_params.str, m_body.str)); -#ifndef DBUG_OFF - optimize(); - { - String s; - sp_instr *i; - uint ip= 0; - while ((i = get_instr(ip))) - { - char buf[8]; - - sprintf(buf, "%4u: ", ip); - s.append(buf); - i->print(&s); - s.append('\n'); - ip+= 1; - } - s.append('\0'); - DBUG_PRINT("info", ("Code %s\n%s", m_qname.str, s.ptr())); - } -#endif - if (m_type == TYPE_ENUM_FUNCTION) ret= sp_create_function(thd, this); else @@ -904,7 +881,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) val= (*splocal)->this_item(); DBUG_PRINT("info", ("print 0x%lx", (long) val)); - str_value= sp_get_item_value(val, &str_value_holder); + str_value= sp_get_item_value(thd, val, &str_value_holder); if (str_value) res|= qbuf.append(*str_value); else @@ -1390,7 +1367,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, MEM_ROOT call_mem_root; Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); Query_arena backup_arena; - DBUG_ENTER("sp_head::execute_function"); DBUG_PRINT("info", ("function %s", m_name.str)); @@ -1471,6 +1447,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, { binlog_buf.length(0); binlog_buf.append(STRING_WITH_LEN("SELECT ")); + append_identifier(thd, &binlog_buf, m_db.str, m_db.length); + binlog_buf.append('.'); append_identifier(thd, &binlog_buf, m_name.str, m_name.length); binlog_buf.append('('); for (arg_no= 0; arg_no < argcount; arg_no++) @@ -1481,7 +1459,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, if (arg_no) binlog_buf.append(','); - str_value= sp_get_item_value(nctx->get_item(arg_no), + str_value= sp_get_item_value(thd, nctx->get_item(arg_no), &str_value_holder); if (str_value) @@ -1796,7 +1774,7 @@ sp_head::reset_lex(THD *thd) DBUG_ENTER("sp_head::reset_lex"); LEX *sublex; LEX *oldlex= thd->lex; - my_lex_states state= oldlex->next_state; // Keep original next_state + my_lex_states org_next_state= oldlex->next_state; (void)m_lex.push_front(oldlex); thd->lex= sublex= new st_lex; @@ -1805,10 +1783,10 @@ sp_head::reset_lex(THD *thd) lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr)); /* - * next_state is normally the same (0), but it happens that we swap lex in - * "mid-sentence", so we must restore it. + next_state is normally the same (0), but it happens that we swap lex in + "mid-sentence", so we must restore it. */ - sublex->next_state= state; + sublex->next_state= org_next_state; /* We must reset ptr and end_of_query again */ sublex->ptr= oldlex->ptr; sublex->end_of_query= oldlex->end_of_query; @@ -1853,7 +1831,6 @@ sp_head::restore_lex(THD *thd) oldlex->next_state= sublex->next_state; oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); -#ifdef HAVE_ROW_BASED_REPLICATION /* If this substatement needs row-based, the entire routine does too (we cannot switch from statement-based to row-based only for this @@ -1861,7 +1838,6 @@ sp_head::restore_lex(THD *thd) */ if (sublex->binlog_row_based_if_mixed) m_flags|= BINLOG_ROW_BASED_IF_MIXED; -#endif /* Add routines which are used by statement to respective set for @@ -2230,7 +2206,7 @@ sp_head::show_create_function(THD *thd) This is the main mark and move loop; it relies on the following methods in sp_instr and its subclasses: - opt_mark() Mark instruction as reachable (will recurse for jumps) + opt_mark() Mark instruction as reachable opt_shortcut_jump() Shortcut jumps to the final destination; used by opt_mark(). opt_move() Update moved instruction @@ -2243,7 +2219,7 @@ void sp_head::optimize() sp_instr *i; uint src, dst; - opt_mark(0); + opt_mark(); bp.empty(); src= dst= 0; @@ -2277,13 +2253,50 @@ void sp_head::optimize() bp.empty(); } +void sp_head::add_mark_lead(uint ip, List<sp_instr> *leads) +{ + sp_instr *i= get_instr(ip); + + if (i && ! i->marked) + leads->push_front(i); +} + void -sp_head::opt_mark(uint ip) +sp_head::opt_mark() { + uint ip; sp_instr *i; + List<sp_instr> leads; + + /* + Forward flow analysis algorithm in the instruction graph: + - first, add the entry point in the graph (the first instruction) to the + 'leads' list of paths to explore. + - while there are still leads to explore: + - pick one lead, and follow the path forward. Mark instruction reached. + Stop only if the end of the routine is reached, or the path converge + to code already explored (marked). + - while following a path, collect in the 'leads' list any fork to + another path (caused by conditional jumps instructions), so that these + paths can be explored as well. + */ - while ((i= get_instr(ip)) && !i->marked) - ip= i->opt_mark(this); + /* Add the entry point */ + i= get_instr(0); + leads.push_front(i); + + /* For each path of code ... */ + while (leads.elements != 0) + { + i= leads.pop(); + + /* Mark the entire path, collecting new leads. */ + while (i && ! i->marked) + { + ip= i->opt_mark(this, & leads); + i= get_instr(ip); + } + } } @@ -2685,7 +2698,7 @@ sp_instr_jump::print(String *str) } uint -sp_instr_jump::opt_mark(sp_head *sp) +sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads) { m_dest= opt_shortcut_jump(sp, this); if (m_dest != m_ip+1) /* Jumping to following instruction? */ @@ -2779,7 +2792,7 @@ sp_instr_jump_if_not::print(String *str) uint -sp_instr_jump_if_not::opt_mark(sp_head *sp) +sp_instr_jump_if_not::opt_mark(sp_head *sp, List<sp_instr> *leads) { sp_instr *i; @@ -2789,13 +2802,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) m_dest= i->opt_shortcut_jump(sp, this); m_optdest= sp->get_instr(m_dest); } - sp->opt_mark(m_dest); + sp->add_mark_lead(m_dest, leads); if ((i= sp->get_instr(m_cont_dest))) { m_cont_dest= i->opt_shortcut_jump(sp, this); m_cont_optdest= sp->get_instr(m_cont_dest); } - sp->opt_mark(m_cont_dest); + sp->add_mark_lead(m_cont_dest, leads); return m_ip+1; } @@ -2916,7 +2929,7 @@ sp_instr_hpush_jump::print(String *str) uint -sp_instr_hpush_jump::opt_mark(sp_head *sp) +sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads) { sp_instr *i; @@ -2926,7 +2939,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp) m_dest= i->opt_shortcut_jump(sp, this); m_optdest= sp->get_instr(m_dest); } - sp->opt_mark(m_dest); + sp->add_mark_lead(m_dest, leads); return m_ip+1; } @@ -2991,15 +3004,13 @@ sp_instr_hreturn::print(String *str) uint -sp_instr_hreturn::opt_mark(sp_head *sp) +sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) { if (m_dest) - return sp_instr_jump::opt_mark(sp); - else - { - marked= 1; - return UINT_MAX; - } + return sp_instr_jump::opt_mark(sp, leads); + + marked= 1; + return UINT_MAX; } @@ -3342,7 +3353,7 @@ sp_instr_set_case_expr::print(String *str) } uint -sp_instr_set_case_expr::opt_mark(sp_head *sp) +sp_instr_set_case_expr::opt_mark(sp_head *sp, List<sp_instr> *leads) { sp_instr *i; @@ -3352,7 +3363,7 @@ sp_instr_set_case_expr::opt_mark(sp_head *sp) m_cont_dest= i->opt_shortcut_jump(sp, this); m_cont_optdest= sp->get_instr(m_cont_dest); } - sp->opt_mark(m_cont_dest); + sp->add_mark_lead(m_cont_dest, leads); return m_ip+1; } diff --git a/sql/sp_head.h b/sql/sp_head.h index 41ed5256840..be6eefa2ea4 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -304,8 +303,19 @@ public: void restore_thd_mem_root(THD *thd); + /** + Optimize the code. + */ void optimize(); - void opt_mark(uint ip); + + /** + Helper used during flow analysis during code optimization. + See the implementation of <code>opt_mark()</code>. + @param ip the instruction to add to the leads list + @param leads the list of remaining paths to explore in the graph that + represents the code, during flow analysis. + */ + void add_mark_lead(uint ip, List<sp_instr> *leads); void recursion_level_error(THD *thd); @@ -362,7 +372,6 @@ public: */ void propagate_attributes(LEX *lex) { -#ifdef HAVE_ROW_BASED_REPLICATION /* If this routine needs row-based binary logging, the entire top statement too (we cannot switch from statement-based to row-based only for this @@ -371,7 +380,6 @@ public: */ if (m_flags & BINLOG_ROW_BASED_IF_MIXED) lex->binlog_row_based_if_mixed= TRUE; -#endif } @@ -414,6 +422,12 @@ private: bool execute(THD *thd); + /** + Perform a forward flow analysis in the generated code. + Mark reachable instructions, for the optimizer. + */ + void opt_mark(); + /* Merge the list of tables used by query into the multi-set of tables used by routine. @@ -481,10 +495,10 @@ public: /* Mark this instruction as reachable during optimization and return the - index to the next instruction. Jump instruction will mark their - destination too recursively. + index to the next instruction. Jump instruction will add their + destination to the leads list. */ - virtual uint opt_mark(sp_head *sp) + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) { marked= 1; return m_ip+1; @@ -639,9 +653,9 @@ class sp_instr_set : public sp_instr public: sp_instr_set(uint ip, sp_pcontext *ctx, - uint offset, Item *val, enum enum_field_types type, + uint offset, Item *val, enum enum_field_types type_arg, LEX *lex, bool lex_resp) - : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type), + : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type_arg), m_lex_keeper(lex, lex_resp) {} @@ -756,7 +770,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start); @@ -806,7 +820,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); /* Override sp_instr_jump's shortcut; we stop here */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) @@ -839,8 +853,9 @@ class sp_instr_freturn : public sp_instr public: sp_instr_freturn(uint ip, sp_pcontext *ctx, - Item *val, enum enum_field_types type, LEX *lex) - : sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE) + Item *val, enum enum_field_types type_arg, LEX *lex) + : sp_instr(ip, ctx), m_value(val), m_type(type_arg), + m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_freturn() @@ -852,7 +867,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp) + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) { marked= 1; return UINT_MAX; @@ -889,7 +904,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); /* Override sp_instr_jump's shortcut; we stop here. */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) @@ -954,7 +969,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); private: @@ -1124,7 +1139,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp) + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) { marked= 1; return UINT_MAX; @@ -1157,7 +1172,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); virtual void opt_move(uint dst, List<sp_instr> *ibp); diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index b0b65d5313b..6229cf14604 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 2ee77696efb..b2cdd5e689c 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 67ee5459bb4..e49c4eb1240 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 5e03aa60d23..fbf479f52aa 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/spatial.cc b/sql/spatial.cc index 02f1525f2ad..6cadb0f3aad 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,13 +23,13 @@ String Geometry::bad_geometry_data("Bad object", &my_charset_bin); -Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]= +Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]= { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static Geometry::Class_info **ci_collection_end= - Geometry::ci_collection+Geometry::wkb_end + 1; + Geometry::ci_collection+Geometry::wkb_last + 1; Geometry::Class_info::Class_info(const char *name, int type_id, void(*create_func)(void *)): @@ -553,7 +552,7 @@ bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const } -int Gis_line_string::length(double *len) const +int Gis_line_string::geom_length(double *len) const { uint32 n_points; double prev_x, prev_y; @@ -929,6 +928,8 @@ int Gis_polygon::centroid_xy(double *x, double *y) const n_linear_rings= uint4korr(data); data+= 4; + DBUG_ASSERT(n_linear_rings > 0); + while (n_linear_rings--) { uint32 n_points, org_n_points; @@ -948,14 +949,14 @@ int Gis_polygon::centroid_xy(double *x, double *y) const while (--n_points) // One point is already read { - double x, y; - get_point(&x, &y, data); + double tmp_x, tmp_y; + get_point(&tmp_x, &tmp_y, data); data+= (SIZEOF_STORED_DOUBLE*2); - cur_area+= (prev_x + x) * (prev_y - y); - cur_cx+= x; - cur_cy+= y; - prev_x= x; - prev_y= y; + cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y); + cur_cx+= tmp_x; + cur_cy+= tmp_y; + prev_x= tmp_x; + prev_y= tmp_y; } cur_area= fabs(cur_area) / 2; cur_cx= cur_cx / (org_n_points - 1); @@ -1299,7 +1300,7 @@ int Gis_multi_line_string::geometry_n(uint32 num, String *result) const } -int Gis_multi_line_string::length(double *len) const +int Gis_multi_line_string::geom_length(double *len) const { uint32 n_line_strings; const char *data= m_data; @@ -1316,7 +1317,7 @@ int Gis_multi_line_string::length(double *len) const Gis_line_string ls; data+= WKB_HEADER_SIZE; ls.set_data_ptr(data, (uint32) (m_data_end - data)); - if (ls.length(&ls_len)) + if (ls.geom_length(&ls_len)) return 1; *len+= ls_len; /* diff --git a/sql/spatial.h b/sql/spatial.h index 36949ff5014..f0c8b7bba28 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2002-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -189,7 +188,7 @@ public: wkb_multilinestring= 5, wkb_multipolygon= 6, wkb_geometrycollection= 7, - wkb_end=7 + wkb_last=7 }; enum wkbByteOrder { @@ -218,7 +217,7 @@ public: virtual bool dimension(uint32 *dim, const char **end) const=0; virtual int get_x(double *x) const { return -1; } virtual int get_y(double *y) const { return -1; } - virtual int length(double *len) const { return -1; } + virtual int geom_length(double *len) const { return -1; } virtual int area(double *ar, const char **end) const { return -1;} virtual int is_closed(int *closed) const { return -1; } virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; } @@ -274,12 +273,12 @@ public: } bool envelope(String *result) const; - static Class_info *ci_collection[wkb_end+1]; + static Class_info *ci_collection[wkb_last+1]; protected: static Class_info *find_class(int type_id) { - return ((type_id < wkb_point) || (type_id > wkb_end)) ? + return ((type_id < wkb_point) || (type_id > wkb_last)) ? NULL : ci_collection[type_id]; } static Class_info *find_class(const char *name, uint32 len); @@ -360,7 +359,7 @@ public: uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; - int length(double *len) const; + int geom_length(double *len) const; int is_closed(int *closed) const; int num_points(uint32 *n_points) const; int start_point(String *point) const; @@ -442,7 +441,7 @@ public: bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; int geometry_n(uint32 num, String *result) const; - int length(double *len) const; + int geom_length(double *len) const; int is_closed(int *closed) const; bool dimension(uint32 *dim, const char **end) const { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 721b6b5a003..3d3b51bab42 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -761,7 +760,7 @@ static ulong get_access(TABLE *form, uint fieldnr, uint *next_field) Field **pos; for (pos=form->field+fieldnr, bit=1; - *pos && (*pos)->real_type() == FIELD_TYPE_ENUM && + *pos && (*pos)->real_type() == MYSQL_TYPE_ENUM && ((Field_enum*) (*pos))->typelib->count == 2 ; pos++, fieldnr++, bit<<=1) { @@ -1630,7 +1629,7 @@ bool change_password(THD *thd, const char *host, const char *user, { query_length= my_sprintf(buff, - (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", + (buff,"SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", acl_user->user ? acl_user->user : "", acl_user->host.hostname ? acl_user->host.hostname : "", new_password)); @@ -1969,7 +1968,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, ulong priv; uint next_field; for (tmp_field= table->field+3, priv = SELECT_ACL; - *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM && + *tmp_field && (*tmp_field)->real_type() == MYSQL_TYPE_ENUM && ((Field_enum*) (*tmp_field))->typelib->count == 2 ; tmp_field++, priv <<= 1) { @@ -5170,6 +5169,8 @@ static int handle_grant_struct(uint struct_no, bool drop, user= grant_name->user; host= grant_name->host.hostname; break; + default: + assert(0); } if (! user) user= ""; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index e1153522ed5..86d2cabc703 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 264e3e2b988..e7decf4a8fc 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -87,6 +86,11 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if (param->next) { // first parameter + if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) + { + DBUG_PRINT("info", ("fix_fields() for the first parameter failed")); + goto err; + } if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val_real() < 0) { @@ -101,6 +105,11 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, goto err; } // second parameter + if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) + { + DBUG_PRINT("info", ("fix_fields() for the second parameter failed")); + goto err; + } if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val_real() < 0) { @@ -140,7 +149,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, case INT_RESULT: // Check if fieldtype is ulonglong if (item->type() == Item::FIELD_ITEM && - ((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG && + ((Item_field*) item)->field->type() == MYSQL_TYPE_LONGLONG && ((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag) new_field= new field_ulonglong(item, pc); else @@ -755,26 +764,26 @@ bool analyse::end_of_records() { switch (((Item_field*) (*f)->item)->field->real_type()) { - case FIELD_TYPE_TIMESTAMP: + case MYSQL_TYPE_TIMESTAMP: ans.append(STRING_WITH_LEN("TIMESTAMP")); break; - case FIELD_TYPE_DATETIME: + case MYSQL_TYPE_DATETIME: ans.append(STRING_WITH_LEN("DATETIME")); break; - case FIELD_TYPE_DATE: - case FIELD_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: ans.append(STRING_WITH_LEN("DATE")); break; - case FIELD_TYPE_SET: + case MYSQL_TYPE_SET: ans.append(STRING_WITH_LEN("SET")); break; - case FIELD_TYPE_YEAR: + case MYSQL_TYPE_YEAR: ans.append(STRING_WITH_LEN("YEAR")); break; - case FIELD_TYPE_TIME: + case MYSQL_TYPE_TIME: ans.append(STRING_WITH_LEN("TIME")); break; - case FIELD_TYPE_DECIMAL: + case MYSQL_TYPE_DECIMAL: ans.append(STRING_WITH_LEN("DECIMAL")); // if item is FIELD_ITEM, it _must_be_ Field_num in this case if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill) diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 0e7bd1b722a..ac671b85e1e 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_array.h b/sql/sql_array.h index c68caf74b25..e2e12bee241 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3fd09d909a4..15d616bdd4f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -41,7 +40,6 @@ static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list, char *cache_key, uint cache_key_length, MEM_ROOT *mem_root, uint flags); static void free_cache_entry(TABLE *entry); -static void mysql_rm_tmp_tables(void); static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, @@ -64,7 +62,6 @@ extern "C" byte *table_cache_key(const byte *record,uint *length, bool table_cache_init(void) { - mysql_rm_tmp_tables(); return hash_init(&open_cache, &my_charset_bin, table_cache_size+16, 0, 0,table_cache_key, (hash_free_key) free_cache_entry, 0) != 0; @@ -1064,9 +1061,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) handled either before writing a query log event (inside binlog_query()) or when preparing a pending event. */ -#ifdef HAVE_ROW_BASED_REPLICATION thd->binlog_flush_pending_rows_event(TRUE); -#endif /*HAVE_ROW_BASED_REPLICATION*/ mysql_unlock_tables(thd, thd->lock); thd->lock=0; } @@ -1083,7 +1078,6 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) if (!thd->active_transaction()) thd->transaction.xid_state.xid.null(); - /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */ if (!lock_in_use) VOID(pthread_mutex_lock(&LOCK_open)); @@ -1213,11 +1207,12 @@ void close_temporary_tables(THD *thd) const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "; uint stub_len= sizeof(stub) - 1; char buf[256]; - memcpy(buf, stub, stub_len); String s_query= String(buf, sizeof(buf), system_charset_info); - bool found_user_tables= false; + bool found_user_tables= FALSE; LINT_INIT(next); + memcpy(buf, stub, stub_len); + /* insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id @@ -1268,10 +1263,13 @@ void close_temporary_tables(THD *thd) { if (is_user_table(table)) { + my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); - /* Loop forward through all tables within the sublist of - common pseudo_thread_id to create single DROP query */ + /* + Loop forward through all tables within the sublist of + common pseudo_thread_id to create single DROP query. + */ for (s_query.length(stub_len); table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; @@ -1297,16 +1295,18 @@ void close_temporary_tables(THD *thd) 0, FALSE); thd->variables.character_set_client= cs_save; /* - Imagine the thread had created a temp table, then was doing a SELECT, and - the SELECT was killed. Then it's not clever to mark the statement above as - "killed", because it's not really a statement updating data, and there - are 99.99% chances it will succeed on slave. - If a real update (one updating a persistent table) was killed on the - master, then this real update will be logged with error_code=killed, - rightfully causing the slave to stop. + Imagine the thread had created a temp table, then was doing a + SELECT, and the SELECT was killed. Then it's not clever to + mark the statement above as "killed", because it's not really + a statement updating data, and there are 99.99% chances it + will succeed on slave. If a real update (one updating a + persistent table) was killed on the master, then this real + update will be logged with error_code=killed, rightfully + causing the slave to stop. */ qinfo.error_code= 0; mysql_bin_log.write(&qinfo); + thd->variables.pseudo_thread_id= save_pseudo_thread_id; } else { @@ -1524,9 +1524,15 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) { if (table->s->table_cache_key.length == key_length && !memcmp(table->s->table_cache_key.str, key, key_length)) + { + DBUG_PRINT("info", + ("Found table. server_id: %u pseudo_thread_id: %lu", + (uint) thd->server_id, + (ulong) thd->variables.pseudo_thread_id)); DBUG_RETURN(table); + } } - DBUG_RETURN(0); // Not a temporary table + DBUG_RETURN(0); // Not a temporary table } @@ -1862,6 +1868,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (table->query_id == thd->query_id || thd->prelocked_mode && table->query_id) { + DBUG_PRINT("error", + ("query_id: %lu server_id: %u pseudo_thread_id: %lu", + (ulong) table->query_id, (uint) thd->server_id, + (ulong) thd->variables.pseudo_thread_id)); my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); DBUG_RETURN(0); } @@ -3325,13 +3335,11 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) *need_reopen= FALSE; -#ifdef HAVE_ROW_BASED_REPLICATION /* CREATE ... SELECT UUID() locks no tables, we have to test here. */ if (thd->lex->binlog_row_based_if_mixed) thd->set_current_stmt_binlog_row_based_if_mixed(); -#endif /*HAVE_ROW_BASED_REPLICATION*/ if (!tables && !thd->lex->requires_prelocking()) DBUG_RETURN(0); @@ -3363,7 +3371,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) { thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; -#ifdef HAVE_ROW_BASED_REPLICATION /* If we have >= 2 different tables to update with auto_inc columns, statement-based binlogging won't work. We can solve this problem in @@ -3375,7 +3382,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) thd->lex->binlog_row_based_if_mixed= TRUE; thd->set_current_stmt_binlog_row_based_if_mixed(); } -#endif } if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), @@ -3516,8 +3522,11 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, uint key_length; TABLE_LIST table_list; DBUG_ENTER("open_temporary_table"); - DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", - db, table_name, path)); + DBUG_PRINT("enter", + ("table: '%s'.'%s' path: '%s' server_id: %u " + "pseudo_thread_id: %lu", + db, table_name, path, + (uint) thd->server_id, (ulong) thd->variables.pseudo_thread_id)); table_list.db= (char*) db; table_list.table_name= (char*) table_name; @@ -3773,7 +3782,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { List_iterator_fast<Natural_join_column> field_it(*(table_ref->join_columns)); - Natural_join_column *nj_col; + Natural_join_column *nj_col, *curr_nj_col; Field *found_field; Query_arena *arena, backup; DBUG_ENTER("find_field_in_natural_join"); @@ -3785,18 +3794,26 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, LINT_INIT(arena); LINT_INIT(found_field); - for (;;) + for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col; + curr_nj_col= field_it++) { - if (!(nj_col= field_it++)) - DBUG_RETURN(NULL); - - if (!my_strcasecmp(system_charset_info, nj_col->name(), name)) - break; + if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name)) + { + if (nj_col) + { + my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); + DBUG_RETURN(NULL); + } + nj_col= curr_nj_col; + } } + if (!nj_col) + DBUG_RETURN(NULL); if (nj_col->view_field) { Item *item; + LINT_INIT(arena); if (register_tree_change) arena= thd->activate_stmt_arena_if_needed(&backup); /* @@ -3804,6 +3821,19 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, column reference. See create_view_field() for details. */ item= nj_col->create_item(thd); + /* + *ref != NULL means that *ref contains the item that we need to + replace. If the item was aliased by the user, set the alias to + the replacing item. + We need to set alias on both ref itself and on ref real item. + */ + if (*ref && !(*ref)->is_autogenerated_name) + { + item->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + item->real_item()->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + } if (register_tree_change && arena) thd->restore_active_arena(arena, &backup); @@ -3967,6 +3997,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, { Field *fld; DBUG_ENTER("find_field_in_table_ref"); + DBUG_ASSERT(table_list->alias); + DBUG_ASSERT(name); + DBUG_ASSERT(item_name); DBUG_PRINT("enter", ("table: '%s' field name: '%s' item name: '%s' ref 0x%lx", table_list->alias, name, item_name, (ulong) ref)); @@ -4680,9 +4713,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { bool found= FALSE; const char *field_name_1; + /* true if field_name_1 is a member of using_fields */ + bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) goto err; field_name_1= nj_col_1->name(); + is_using_column_1= using_fields && + test_if_string_in_list(field_name_1, using_fields); + DBUG_PRINT ("info", ("field_name_1=%s.%s", + nj_col_1->table_name() ? nj_col_1->table_name() : "", + field_name_1)); /* Find a field with the same name in table_ref_2. @@ -4699,6 +4739,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); + DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", + cur_nj_col_2->table_name() ? + cur_nj_col_2->table_name() : "", + cur_field_name_2)); /* Compare the two columns and check for duplicate common fields. @@ -4706,10 +4750,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, table_ref_2 (then found == TRUE), or if a field in table_ref_2 was already matched by some previous field in table_ref_1 (then cur_nj_col_2->is_common == TRUE). + Note that it is too early to check the columns outside of the + USING list for ambiguity because they are not actually "referenced" + here. These columns must be checked only on unqualified reference + by name (e.g. in SELECT list). */ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { - if (found || cur_nj_col_2->is_common) + DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); + if (cur_nj_col_2->is_common || + (found && (!using_fields || is_using_column_1))) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; @@ -4735,9 +4785,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, clause (if present), mark them as common fields, and add a new equi-join condition to the ON clause. */ - if (nj_col_2 && - (!using_fields || - test_if_string_in_list(field_name_1, using_fields))) + if (nj_col_2 && (!using_fields ||is_using_column_1)) { Item *item_1= nj_col_1->create_item(thd); Item *item_2= nj_col_2->create_item(thd); @@ -4792,6 +4840,13 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, eq_cond); nj_col_1->is_common= nj_col_2->is_common= TRUE; + DBUG_PRINT ("info", ("%s.%s and %s.%s are common", + nj_col_1->table_name() ? + nj_col_1->table_name() : "", + nj_col_1->name(), + nj_col_2->table_name() ? + nj_col_2->table_name() : "", + nj_col_2->name())); if (field_1) { @@ -5317,6 +5372,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, bzero(ref_pointer_array, sizeof(Item *) * fields.elements); Item **ref= ref_pointer_array; + thd->lex->current_select->cur_pos_in_select_list= 0; while ((item= it++)) { if (!item->fixed && item->fix_fields(thd, it.ref()) || @@ -5333,7 +5389,10 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, sum_func_list) item->split_sum_func(thd, ref_pointer_array, *sum_func_list); thd->used_tables|= item->used_tables(); + thd->lex->current_select->cur_pos_in_select_list++; } + thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; + thd->lex->allow_sum_func= save_allow_sum_func; thd->mark_used_columns= save_mark_used_columns; DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns)); @@ -5454,7 +5513,12 @@ bool setup_tables(THD *thd, Name_resolution_context *context, get_key_map_from_key_list(&map, table, table_list->use_index); if (map.is_set_all()) DBUG_RETURN(1); - table->keys_in_use_for_query=map; + /* + Don't introduce keys in keys_in_use_for_query that weren't there + before. FORCE/USE INDEX should not add keys, it should only remove + all keys except the key(s) specified in the hint. + */ + table->keys_in_use_for_query.intersect(map); } if (table_list->ignore_index) { @@ -6073,14 +6137,21 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, } -static void mysql_rm_tmp_tables(void) +my_bool mysql_rm_tmp_tables(void) { uint i, idx; - char filePath[FN_REFLEN], *tmpdir; + char filePath[FN_REFLEN], *tmpdir, filePathCopy[FN_REFLEN]; MY_DIR *dirp; FILEINFO *file; + TABLE_SHARE share; + THD *thd; DBUG_ENTER("mysql_rm_tmp_tables"); + if (!(thd= new THD)) + DBUG_RETURN(1); + thd->thread_stack= (char*) &thd; + thd->store_globals(); + for (i=0; i<=mysql_tmpdir_list.max; i++) { tmpdir=mysql_tmpdir_list.list[i]; @@ -6101,13 +6172,40 @@ static void mysql_rm_tmp_tables(void) if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length)) { - sprintf(filePath,"%s%c%s",tmpdir,FN_LIBCHAR,file->name); - VOID(my_delete(filePath,MYF(MY_WME))); + char *ext= fn_ext(file->name); + uint ext_len= strlen(ext); + uint filePath_len= my_snprintf(filePath, sizeof(filePath), + "%s%c%s", tmpdir, FN_LIBCHAR, + file->name); + if (!bcmp(reg_ext, ext, ext_len)) + { + handler *handler_file= 0; + /* We should cut file extention before deleting of table */ + memcpy(filePathCopy, filePath, filePath_len - ext_len); + filePathCopy[filePath_len - ext_len]= 0; + init_tmp_table_share(&share, "", 0, "", filePathCopy); + if (!open_table_def(thd, &share, 0) && + ((handler_file= get_new_handler(&share, thd->mem_root, + share.db_type)))) + { + handler_file->delete_table(filePathCopy); + delete handler_file; + } + free_table_share(&share); + } + /* + File can be already deleted by tmp_table.file->delete_table(). + So we hide error messages which happnes during deleting of these + files(MYF(0)). + */ + VOID(my_delete(filePath, MYF(0))); } } my_dirend(dirp); } - DBUG_VOID_RETURN; + delete thd; + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_RETURN(0); } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 37094b992e5..b0a54bec664 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mysql_priv.h" #include "base64.h" @@ -164,7 +163,7 @@ void mysql_client_binlog_statement(THD* thd) (ulong) uint4korr(bufptr+EVENT_LEN_OFFSET))); #endif ev->thd= thd; - if (int err= ev->exec_event(thd->rli_fake)) + if (IF_DBUG(int err= ) ev->exec_event(thd->rli_fake)) { DBUG_PRINT("error", ("exec_event() returned: %d", err)); /* diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index 3a7fa4b661a..9a765120895 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in index 18705aa3dfb..3becdbaccfe 100644 --- a/sql/sql_builtin.cc.in +++ b/sql/sql_builtin.cc.in @@ -1,3 +1,17 @@ +/* Copyright (C) 2006 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <mysql/plugin.h> diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 1b9af26530e..8c0cb72e1f4 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_cache.h b/sql/sql_cache.h index a66067159e2..bc00f7ea629 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2001-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -128,7 +127,7 @@ struct Query_cache_query inline void tables_type(uint8 type) { tbls_type= type; } inline ulong length() { return len; } inline ulong add(ulong packet_len) { return(len+= packet_len); } - inline void length(ulong length) { len= length; } + inline void length(ulong length_arg) { len= length_arg; } inline gptr query() { return (gptr)(((byte*)this)+ @@ -156,7 +155,7 @@ struct Query_cache_table inline char *db() { return (char *) data(); } inline char *table() { return tbl; } - inline void table(char *table) { tbl= table; } + inline void table(char *table_arg) { tbl= table_arg; } inline uint32 key_length() { return key_len; } inline void key_length(uint32 len) { key_len= len; } inline uint8 type() { return table_type; } @@ -164,7 +163,7 @@ struct Query_cache_table inline qc_engine_callback callback() { return callback_func; } inline void callback(qc_engine_callback fn){ callback_func= fn; } inline ulonglong engine_data() { return engine_data_buff; } - inline void engine_data(ulonglong data) { engine_data_buff= data; } + inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } inline gptr data() { return (gptr)(((byte*)this)+ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b7c55d80c36..039fd71d670 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -204,9 +203,7 @@ THD::THD() Open_tables_state(refresh_version), rli_fake(0), lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), -#ifdef HAVE_ROW_BASED_REPLICATION binlog_table_maps(0), -#endif /*HAVE_ROW_BASED_REPLICATION*/ global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), arg_of_last_insert_id_function(FALSE), @@ -217,6 +214,8 @@ THD::THD() stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), spcont(NULL) { + ulong tmp; + stmt_arena= this; thread_stack= 0; db= 0; @@ -244,7 +243,7 @@ THD::THD() time_after_lock=(time_t) 0; current_linfo = 0; slave_thread = 0; - variables.pseudo_thread_id= 0; + thread_id= variables.pseudo_thread_id= 0; one_shot_set= 0; file_id = 0; query_id= 0; @@ -267,12 +266,7 @@ THD::THD() system_thread= NON_SYSTEM_THREAD; cleanup_done= abort_on_warning= no_warnings_for_error= 0; peer_port= 0; // For SHOW PROCESSLIST -#ifdef HAVE_ROW_BASED_REPLICATION transaction.m_pending_rows_event= 0; -#endif -#ifdef __WIN__ - real_id = 0; -#endif #ifdef SIGNAL_WITH_VIO_CLOSE active_vio = 0; #endif @@ -310,8 +304,8 @@ THD::THD() protocol_prep.init(this); tablespace_op=FALSE; - ulong tmp=sql_rnd_with_mutex(); - randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); + tmp= sql_rnd_with_mutex(); + randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id); substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ thr_lock_owner_init(&main_lock_id, &lock_info); @@ -332,9 +326,6 @@ void THD::init(void) variables.date_format); variables.datetime_format= date_time_format_copy((THD*) 0, variables.datetime_format); -#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE - variables.ndb_use_transactions= 1; -#endif pthread_mutex_unlock(&LOCK_global_system_variables); server_status= SERVER_STATUS_AUTOCOMMIT; if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) @@ -349,9 +340,7 @@ void THD::init(void) bzero((char*) warn_count, sizeof(warn_count)); total_warn_count= 0; update_charset(); -#ifdef HAVE_ROW_BASED_REPLICATION reset_current_stmt_binlog_row_based(); -#endif /*HAVE_ROW_BASED_REPLICATION*/ bzero((char *) &status_var, sizeof(status_var)); variables.lc_time_names = &my_locale_en_US; } @@ -409,6 +398,8 @@ void THD::change_user(void) void THD::cleanup(void) { DBUG_ENTER("THD::cleanup"); + DBUG_ASSERT(cleanup_done == 0); + #ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE if (transaction.xid_state.xa_state == XA_PREPARED) { @@ -444,7 +435,6 @@ void THD::cleanup(void) pthread_mutex_lock(&LOCK_user_locks); item_user_lock_release(ull); pthread_mutex_unlock(&LOCK_user_locks); - ull= 0; } cleanup_done=1; @@ -558,7 +548,9 @@ void THD::awake(THD::killed_state state_to_set) killed= state_to_set; if (state_to_set != THD::KILL_QUERY) { - thr_alarm_kill(real_id); + thr_alarm_kill(thread_id); + if (!slave_thread) + thread_scheduler.post_kill_notification(this); #ifdef SIGNAL_WITH_VIO_CLOSE close_active_vio(); #endif @@ -609,18 +601,19 @@ bool THD::store_globals() Assert that thread_stack is initialized: it's necessary to be able to track stack overrun. */ - DBUG_ASSERT(this->thread_stack); + DBUG_ASSERT(thread_stack); if (my_pthread_setspecific_ptr(THR_THD, this) || my_pthread_setspecific_ptr(THR_MALLOC, &mem_root)) return 1; mysys_var=my_thread_var; - dbug_thread_id=my_thread_id(); /* - By default 'slave_proxy_id' is 'thread_id'. They may later become different - if this is the slave SQL thread. + Let mysqld define the thread id (not mysys) + This allows us to move THD to different threads if needed. */ - variables.pseudo_thread_id= thread_id; + mysys_var->id= thread_id; + real_id= pthread_self(); // For debugging + /* We have to call thr_lock_info_init() again here as THD may have been created in another thread @@ -985,6 +978,13 @@ void select_result::cleanup() /* do nothing */ } +bool select_result::check_simple_select() const +{ + my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0)); + return TRUE; +} + + static String default_line_term("\n",default_charset_info); static String default_escaped("\\",default_charset_info); static String default_field_term("\t",default_charset_info); @@ -1535,7 +1535,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items) bool select_max_min_finder_subselect::cmp_real() { - Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0); double val1= cache->val_real(), val2= maxmin->val_real(); if (fmax) return (cache->null_value && !maxmin->null_value) || @@ -1548,7 +1548,7 @@ bool select_max_min_finder_subselect::cmp_real() bool select_max_min_finder_subselect::cmp_int() { - Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0); longlong val1= cache->val_int(), val2= maxmin->val_int(); if (fmax) return (cache->null_value && !maxmin->null_value) || @@ -1561,7 +1561,7 @@ bool select_max_min_finder_subselect::cmp_int() bool select_max_min_finder_subselect::cmp_decimal() { - Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0); my_decimal cval, *cvalue= cache->val_decimal(&cval); my_decimal mval, *mvalue= maxmin->val_decimal(&mval); if (fmax) @@ -1576,7 +1576,7 @@ bool select_max_min_finder_subselect::cmp_decimal() bool select_max_min_finder_subselect::cmp_str() { String *val1, *val2, buf1, buf2; - Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0); /* as far as both operand is Item_cache buf1 & buf2 will not be used, but added for safety @@ -1625,6 +1625,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) } +bool select_dumpvar::check_simple_select() const +{ + my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0)); + return TRUE; +} + + void select_dumpvar::cleanup() { row_count= 0; @@ -2294,7 +2301,6 @@ void xid_cache_delete(XID_STATE *xid_state) */ #ifndef MYSQL_CLIENT -#ifdef HAVE_ROW_BASED_REPLICATION /* Template member function for ensuring that there is an rows log @@ -2404,11 +2410,12 @@ THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*, my_size_t colcnt, my_size_t, bool, Update_rows_log_event *); #endif + +#ifdef NOT_USED static char const* field_type_name(enum_field_types type) { - switch (type) - { + switch (type) { case MYSQL_TYPE_DECIMAL: return "MYSQL_TYPE_DECIMAL"; case MYSQL_TYPE_TINY: @@ -2466,6 +2473,7 @@ field_type_name(enum_field_types type) } return "Unknown"; } +#endif my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const @@ -2504,7 +2512,7 @@ my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data, if (bitmap_is_set(cols,i)) { my_ptrdiff_t const offset= - field->is_null(rec_offset) ? def_offset : rec_offset; + field->is_null((uint) rec_offset) ? def_offset : rec_offset; field->move_field_offset(offset); ptr= (byte*)field->pack((char *) ptr, field->ptr); field->move_field_offset(-offset); @@ -2546,7 +2554,7 @@ namespace { : m_memory(0) { #ifndef DBUG_OFF - m_alloc_checked= false; + m_alloc_checked= FALSE; #endif allocate_memory(table, len1); m_ptr[0]= has_memory() ? m_memory : 0; @@ -2557,7 +2565,7 @@ namespace { : m_memory(0) { #ifndef DBUG_OFF - m_alloc_checked= false; + m_alloc_checked= FALSE; #endif allocate_memory(table, len1 + len2); m_ptr[0]= has_memory() ? m_memory : 0; @@ -2578,7 +2586,7 @@ namespace { */ bool has_memory() const { #ifndef DBUG_OFF - m_alloc_checked= true; + m_alloc_checked= TRUE; #endif return m_memory != 0; } @@ -2587,7 +2595,7 @@ namespace { { DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr)); DBUG_ASSERT(m_ptr[s] != 0); - DBUG_ASSERT(m_alloc_checked == true); + DBUG_ASSERT(m_alloc_checked == TRUE); return m_ptr[s]; } @@ -2617,12 +2625,12 @@ namespace { table->write_row_record= (byte *) alloc_root(&table->mem_root, 2 * maxlen); m_memory= table->write_row_record; - m_release_memory_on_destruction= false; + m_release_memory_on_destruction= FALSE; } else { m_memory= (byte *) my_malloc(total_length, MYF(MY_WME)); - m_release_memory_on_destruction= true; + m_release_memory_on_destruction= TRUE; } } @@ -2646,8 +2654,6 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. */ - int error= 0; - Row_data_memory memory(table, max_row_length(table, record)); if (!memory.has_memory()) return HA_ERR_OUT_OF_MEM; @@ -2674,7 +2680,6 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, { DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); - int error= 0; my_size_t const before_maxlen = max_row_length(table, before_record); my_size_t const after_maxlen = max_row_length(table, after_record); @@ -2724,8 +2729,6 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. */ - int error= 0; - Row_data_memory memory(table, max_row_length(table, record)); if (unlikely(!memory.has_memory())) return HA_ERR_OUT_OF_MEM; @@ -2787,8 +2790,6 @@ void THD::binlog_delete_pending_rows_event() } } -#endif /* HAVE_ROW_BASED_REPLICATION */ - /* Member function that will log query, either row-based or statement-based depending on the value of the 'current_stmt_binlog_row_based' @@ -2829,18 +2830,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, If we are in prelocked mode, the flushing will be done inside the top-most close_thread_tables(). */ -#ifdef HAVE_ROW_BASED_REPLICATION if (this->prelocked_mode == NON_PRELOCKED) if (int error= binlog_flush_pending_rows_event(TRUE)) DBUG_RETURN(error); -#endif /*HAVE_ROW_BASED_REPLICATION*/ switch (qtype) { case THD::ROW_QUERY_TYPE: -#ifdef HAVE_ROW_BASED_REPLICATION if (current_stmt_binlog_row_based) DBUG_RETURN(0); -#endif /* Otherwise, we fall through */ case THD::MYSQL_QUERY_TYPE: /* @@ -2858,9 +2855,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, */ { Query_log_event qinfo(this, query, query_len, is_trans, suppress_use); -#ifdef HAVE_ROW_BASED_REPLICATION qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; -#endif /* Binlog table maps will be irrelevant after a Query_log_event (they are just removed on the slave side) so after the query @@ -2868,9 +2863,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, table maps were written. */ int error= mysql_bin_log.write(&qinfo); -#ifdef HAVE_ROW_BASED_REPLICATION binlog_table_maps= 0; -#endif /*HAVE_ROW_BASED_REPLICATION*/ DBUG_RETURN(error); } break; diff --git a/sql/sql_class.h b/sql/sql_class.h index 4087281f1e9..cbfbc72d0aa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -218,7 +217,7 @@ struct system_variables ulong read_rnd_buff_size; ulong div_precincrement; ulong sortbuff_size; - handlerton *table_type; + ulong thread_handling; ulong tx_isolation; ulong completion_type; /* Determines which non-standard SQL behaviour should be enabled */ @@ -235,11 +234,15 @@ struct system_variables ulong trans_prealloc_size; ulong log_warnings; ulong group_concat_max_len; + ulong ndb_autoincrement_prefetch_sz; + ulong ndb_index_stat_cache_entries; + ulong ndb_index_stat_update_freq; + ulong binlog_format; // binlog format for this thd (see enum_binlog_format) /* In slave thread we need to know in behalf of which thread the query is being run to replicate temp tables properly */ - ulong pseudo_thread_id; + my_thread_id pseudo_thread_id; my_bool low_priority_updates; my_bool new_mode; @@ -252,14 +255,12 @@ struct system_variables my_bool ndb_use_exact_count; my_bool ndb_use_transactions; my_bool ndb_index_stat_enable; - ulong ndb_autoincrement_prefetch_sz; - ulong ndb_index_stat_cache_entries; - ulong ndb_index_stat_update_freq; - ulong binlog_format; // binlog format for this thd (see enum_binlog_format) my_bool old_alter_table; my_bool old_passwords; + handlerton *table_type; + /* Only charset part of these variables is sensible */ CHARSET_INFO *character_set_filesystem; CHARSET_INFO *character_set_client; @@ -945,12 +946,12 @@ public: #ifndef MYSQL_CLIENT int binlog_setup_trx_data(); -#ifdef HAVE_ROW_BASED_REPLICATION - /* Public interface to write RBR events to the binlog */ void binlog_start_trans_and_stmt(); + int binlog_flush_transaction_cache(); + void binlog_set_stmt_begin(); int binlog_write_table_map(TABLE *table, bool is_transactional); int binlog_write_row(TABLE* table, bool is_transactional, MY_BITMAP const* cols, my_size_t colcnt, @@ -1000,7 +1001,6 @@ public: uint get_binlog_table_maps() const { return binlog_table_maps; } -#endif /* HAVE_ROW_BASED_REPLICATION */ #endif /* MYSQL_CLIENT */ #ifndef MYSQL_CLIENT @@ -1039,9 +1039,7 @@ public: XID xid; // transaction identifier enum xa_states xa_state; // used by external XA only XID_STATE xid_state; -#ifdef HAVE_ROW_BASED_REPLICATION Rows_log_event *m_pending_rows_event; -#endif /* Tables changed in transaction (that must be invalidated in query cache). @@ -1071,7 +1069,7 @@ public: } transaction; Field *dup_field; #ifndef __WIN__ - sigset_t signals,block_signals; + sigset_t signals; #endif #ifdef SIGNAL_WITH_VIO_CLOSE Vio* active_vio; @@ -1262,7 +1260,7 @@ public: update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id, warn_id; - ulong thread_id, col_access; + ulong col_access; #ifdef ERROR_INJECT_SUPPORT ulong error_inject_value; @@ -1271,8 +1269,8 @@ public: ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; ulong row_count; // Row counter, mainly for errors and warnings - long dbug_thread_id; - pthread_t real_id; + pthread_t real_id; /* For debugging */ + my_thread_id thread_id; uint tmp_table, global_read_lock; uint server_status,open_options; enum enum_thread_type system_thread; @@ -1548,7 +1546,6 @@ public: void restore_active_arena(Query_arena *set, Query_arena *backup); inline void set_current_stmt_binlog_row_based_if_mixed() { -#ifdef HAVE_ROW_BASED_REPLICATION /* If in a stored/function trigger, the caller should already have done the change. We test in_sub_stmt to prevent introducing bugs where people @@ -1561,23 +1558,17 @@ public: if ((variables.binlog_format == BINLOG_FORMAT_MIXED) && (in_sub_stmt == 0)) current_stmt_binlog_row_based= TRUE; -#endif } inline void set_current_stmt_binlog_row_based() { -#ifdef HAVE_ROW_BASED_REPLICATION current_stmt_binlog_row_based= TRUE; -#endif } inline void clear_current_stmt_binlog_row_based() { -#ifdef HAVE_ROW_BASED_REPLICATION current_stmt_binlog_row_based= FALSE; -#endif } inline void reset_current_stmt_binlog_row_based() { -#ifdef HAVE_ROW_BASED_REPLICATION /* If there are temporary tables, don't reset back to statement-based. Indeed it could be that: @@ -1601,9 +1592,6 @@ public: current_stmt_binlog_row_based= test(variables.binlog_format == BINLOG_FORMAT_ROW); } -#else - current_stmt_binlog_row_based= FALSE; -#endif } /* @@ -1646,6 +1634,7 @@ public: *p_db_length= db_length; return FALSE; } + thd_scheduler scheduler; }; @@ -1706,7 +1695,14 @@ public: virtual bool initialize_tables (JOIN *join=0) { return 0; } virtual void send_error(uint errcode,const char *err); virtual bool send_eof()=0; - virtual bool simple_select() { return 0; } + /** + Check if this query returns a result set and therefore is allowed in + cursors and set an error message if it is not the case. + + @retval FALSE success + @retval TRUE error, an error message is set + */ + virtual bool check_simple_select() const; virtual void abort() {} /* Cleanup instance of this class for next execution of a prepared @@ -1744,7 +1740,7 @@ public: bool send_fields(List<Item> &list, uint flags); bool send_data(List<Item> &items); bool send_eof(); - bool simple_select() { return 1; } + virtual bool check_simple_select() const { return FALSE; } void abort(); }; @@ -1821,13 +1817,13 @@ class select_create: public select_insert { HA_CREATE_INFO *create_info; Field **field; public: - select_create (TABLE_LIST *table, + select_create (TABLE_LIST *table_arg, HA_CREATE_INFO *create_info_par, List<create_field> &fields_par, List<Key> &keys_par, List<Item> &select_fields,enum_duplicates duplic, bool ignore) :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), - create_table(table), extra_fields(&fields_par),keys(&keys_par), + create_table(table_arg), extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par) {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); @@ -1939,7 +1935,9 @@ public: class select_singlerow_subselect :public select_subselect { public: - select_singlerow_subselect(Item_subselect *item):select_subselect(item){} + select_singlerow_subselect(Item_subselect *item_arg) + :select_subselect(item_arg) + {} bool send_data(List<Item> &items); }; @@ -1950,8 +1948,8 @@ class select_max_min_finder_subselect :public select_subselect bool (select_max_min_finder_subselect::*op)(); bool fmax; public: - select_max_min_finder_subselect(Item_subselect *item, bool mx) - :select_subselect(item), cache(0), fmax(mx) + select_max_min_finder_subselect(Item_subselect *item_arg, bool mx) + :select_subselect(item_arg), cache(0), fmax(mx) {} void cleanup(); bool send_data(List<Item> &items); @@ -1965,7 +1963,8 @@ public: class select_exists_subselect :public select_subselect { public: - select_exists_subselect(Item_subselect *item):select_subselect(item){} + select_exists_subselect(Item_subselect *item_arg) + :select_subselect(item_arg){} bool send_data(List<Item> &items); }; @@ -2190,6 +2189,7 @@ public: int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &items); bool send_eof(); + virtual bool check_simple_select() const; void cleanup(); }; diff --git a/sql/sql_client.cc b/sql/sql_client.cc index 49d0d3087ad..d6f1183806e 100644 --- a/sql/sql_client.cc +++ b/sql/sql_client.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc new file mode 100644 index 00000000000..09ee4962235 --- /dev/null +++ b/sql/sql_connect.cc @@ -0,0 +1,1108 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* + Functions to autenticate and handle reqests for a connection +*/ + +#include "mysql_priv.h" + +#ifdef HAVE_OPENSSL +/* + Without SSL the handshake consists of one packet. This packet + has both client capabilites and scrambled password. + With SSL the handshake might consist of two packets. If the first + packet (client capabilities) has CLIENT_SSL flag set, we have to + switch to SSL and read the second packet. The scrambled password + is in the second packet and client_capabilites field will be ignored. + Maybe it is better to accept flags other than CLIENT_SSL from the + second packet? +*/ +#define SSL_HANDSHAKE_SIZE 2 +#define NORMAL_HANDSHAKE_SIZE 6 +#define MIN_HANDSHAKE_SIZE 2 +#else +#define MIN_HANDSHAKE_SIZE 6 +#endif /* HAVE_OPENSSL */ + +#ifdef __WIN__ +static void test_signal(int sig_ptr) +{ +#if !defined( DBUG_OFF) + MessageBox(NULL,"Test signal","DBUG",MB_OK); +#endif +#if defined(OS2) + fprintf(stderr, "Test signal %d\n", sig_ptr); + fflush(stderr); +#endif +} +static void init_signals(void) +{ + int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; + for (int i=0 ; i < 7 ; i++) + signal( signals[i], test_signal) ; +} +#endif + +/* + Get structure for logging connection data for the current user +*/ + +#ifndef NO_EMBEDDED_ACCESS_CHECKS +static HASH hash_user_connections; + +static int get_or_create_user_conn(THD *thd, const char *user, + const char *host, + USER_RESOURCES *mqh) +{ + int return_val= 0; + uint temp_len, user_len; + char temp_user[USER_HOST_BUFF_SIZE]; + struct user_conn *uc; + + DBUG_ASSERT(user != 0); + DBUG_ASSERT(host != 0); + + user_len= strlen(user); + temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; + (void) pthread_mutex_lock(&LOCK_user_conn); + if (!(uc = (struct user_conn *) hash_search(&hash_user_connections, + (byte*) temp_user, temp_len))) + { + /* First connection for user; Create a user connection object */ + if (!(uc= ((struct user_conn*) + my_malloc(sizeof(struct user_conn) + temp_len+1, + MYF(MY_WME))))) + { + net_send_error(thd, 0, NullS); // Out of memory + return_val= 1; + goto end; + } + uc->user=(char*) (uc+1); + memcpy(uc->user,temp_user,temp_len+1); + uc->host= uc->user + user_len + 1; + uc->len= temp_len; + uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; + uc->user_resources= *mqh; + uc->intime= thd->thr_create_time; + if (my_hash_insert(&hash_user_connections, (byte*) uc)) + { + my_free((char*) uc,0); + net_send_error(thd, 0, NullS); // Out of memory + return_val= 1; + goto end; + } + } + thd->user_connect=uc; + uc->connections++; +end: + (void) pthread_mutex_unlock(&LOCK_user_conn); + return return_val; + +} + + +/* + check if user has already too many connections + + SYNOPSIS + check_for_max_user_connections() + thd Thread handle + uc User connect object + + NOTES + If check fails, we decrease user connection count, which means one + shouldn't call decrease_user_connections() after this function. + + RETURN + 0 ok + 1 error +*/ + +int check_for_max_user_connections(THD *thd, USER_CONN *uc) +{ + int error=0; + DBUG_ENTER("check_for_max_user_connections"); + + (void) pthread_mutex_lock(&LOCK_user_conn); + if (max_user_connections && !uc->user_resources.user_conn && + max_user_connections < (uint) uc->connections) + { + net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user); + error=1; + goto end; + } + time_out_user_resource_limits(thd, uc); + if (uc->user_resources.user_conn && + uc->user_resources.user_conn < uc->connections) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, + "max_user_connections", + (long) uc->user_resources.user_conn); + error= 1; + goto end; + } + if (uc->user_resources.conn_per_hour && + uc->user_resources.conn_per_hour <= uc->conn_per_hour) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, + "max_connections_per_hour", + (long) uc->user_resources.conn_per_hour); + error=1; + goto end; + } + uc->conn_per_hour++; + + end: + if (error) + uc->connections--; // no need for decrease_user_connections() here + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_RETURN(error); +} + + +/* + Decrease user connection count + + SYNOPSIS + decrease_user_connections() + uc User connection object + + NOTES + If there is a n user connection object for a connection + (which only happens if 'max_user_connections' is defined or + if someone has created a resource grant for a user), then + the connection count is always incremented on connect. + + The user connect object is not freed if some users has + 'max connections per hour' defined as we need to be able to hold + count over the lifetime of the connection. +*/ + +void decrease_user_connections(USER_CONN *uc) +{ + DBUG_ENTER("decrease_user_connections"); + (void) pthread_mutex_lock(&LOCK_user_conn); + DBUG_ASSERT(uc->connections); + if (!--uc->connections && !mqh_used) + { + /* Last connection for user; Delete it */ + (void) hash_delete(&hash_user_connections,(byte*) uc); + } + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_VOID_RETURN; +} + + +/* + Reset per-hour user resource limits when it has been more than + an hour since they were last checked + + SYNOPSIS: + time_out_user_resource_limits() + thd Thread handler + uc User connection details + + NOTE: + This assumes that the LOCK_user_conn mutex has been acquired, so it is + safe to test and modify members of the USER_CONN structure. +*/ + +void time_out_user_resource_limits(THD *thd, USER_CONN *uc) +{ + time_t check_time = thd->start_time ? thd->start_time : time(NULL); + DBUG_ENTER("time_out_user_resource_limits"); + + /* If more than a hour since last check, reset resource checking */ + if (check_time - uc->intime >= 3600) + { + uc->questions=1; + uc->updates=0; + uc->conn_per_hour=0; + uc->intime=check_time; + } + + DBUG_VOID_RETURN; +} + +/* + Check if maximum queries per hour limit has been reached + returns 0 if OK. +*/ + +bool check_mqh(THD *thd, uint check_command) +{ + bool error= 0; + USER_CONN *uc=thd->user_connect; + DBUG_ENTER("check_mqh"); + DBUG_ASSERT(uc != 0); + + (void) pthread_mutex_lock(&LOCK_user_conn); + + time_out_user_resource_limits(thd, uc); + + /* Check that we have not done too many questions / hour */ + if (uc->user_resources.questions && + uc->questions++ >= uc->user_resources.questions) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", + (long) uc->user_resources.questions); + error=1; + goto end; + } + if (check_command < (uint) SQLCOM_END) + { + /* Check that we have not done too many updates / hour */ + if (uc->user_resources.updates && + (sql_command_flags[check_command] & CF_CHANGES_DATA) && + uc->updates++ >= uc->user_resources.updates) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", + (long) uc->user_resources.updates); + error=1; + goto end; + } + } +end: + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_RETURN(error); +} + +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ + + +/* + Check if user exist and password supplied is correct. + + SYNOPSIS + check_user() + thd thread handle, thd->security_ctx->{host,user,ip} are used + command originator of the check: now check_user is called + during connect and change user procedures; used for + logging. + passwd scrambled password received from client + passwd_len length of scrambled password + db database name to connect to, may be NULL + check_count dont know exactly + + Note, that host, user and passwd may point to communication buffer. + Current implementation does not depend on that, but future changes + should be done with this in mind; 'thd' is INOUT, all other params + are 'IN'. + + RETURN VALUE + 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and + thd->db are updated; OK is sent to client; + -1 access denied or handshake error; error is sent to client; + >0 error, not sent to client +*/ + +int check_user(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count) +{ + DBUG_ENTER("check_user"); + +#ifdef NO_EMBEDDED_ACCESS_CHECKS + thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights + /* Change database if necessary */ + if (db && db[0]) + { + /* + thd->db is saved in caller and needs to be freed by caller if this + function returns 0 + */ + thd->reset_db(NULL, 0); + if (mysql_change_db(thd, db, FALSE)) + { + /* Send the error to the client */ + net_send_error(thd); + DBUG_RETURN(-1); + } + } + send_ok(thd); + DBUG_RETURN(0); +#else + + my_bool opt_secure_auth_local; + pthread_mutex_lock(&LOCK_global_system_variables); + opt_secure_auth_local= opt_secure_auth; + pthread_mutex_unlock(&LOCK_global_system_variables); + + /* + If the server is running in secure auth mode, short scrambles are + forbidden. + */ + if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) + { + net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); + } + if (passwd_len != 0 && + passwd_len != SCRAMBLE_LENGTH && + passwd_len != SCRAMBLE_LENGTH_323) + DBUG_RETURN(ER_HANDSHAKE_ERROR); + + /* + Clear thd->db as it points to something, that will be freed when + connection is closed. We don't want to accidentally free a wrong pointer + if connect failed. Also in case of 'CHANGE USER' failure, current + database will be switched to 'no database selected'. + */ + thd->reset_db(NULL, 0); + + USER_RESOURCES ur; + int res= acl_getroot(thd, &ur, passwd, passwd_len); +#ifndef EMBEDDED_LIBRARY + if (res == -1) + { + /* + This happens when client (new) sends password scrambled with + scramble(), but database holds old value (scrambled with + scramble_323()). Here we please client to send scrambled_password + in old format. + */ + NET *net= &thd->net; + if (opt_secure_auth_local) + { + net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); + general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); + DBUG_RETURN(-1); + } + /* We have to read very specific packet size */ + if (send_old_password_request(thd) || + my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) + { + inc_host_errors(&thd->remote.sin_addr); + DBUG_RETURN(ER_HANDSHAKE_ERROR); + } + /* Final attempt to check the user based on reply */ + /* So as passwd is short, errcode is always >= 0 */ + res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); + } +#endif /*EMBEDDED_LIBRARY*/ + /* here res is always >= 0 */ + if (res == 0) + { + if (!(thd->main_security_ctx.master_access & + NO_ACCESS)) // authentication is OK + { + DBUG_PRINT("info", + ("Capabilities: %lu packet_length: %ld Host: '%s' " + "Login user: '%s' Priv_user: '%s' Using password: %s " + "Access: %lu db: '%s'", + thd->client_capabilities, + thd->max_client_packet_length, + thd->main_security_ctx.host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.priv_user, + passwd_len ? "yes": "no", + thd->main_security_ctx.master_access, + (thd->db ? thd->db : "*none*"))); + + if (check_count) + { + VOID(pthread_mutex_lock(&LOCK_thread_count)); + bool count_ok= thread_count <= max_connections + delayed_insert_threads + || (thd->main_security_ctx.master_access & SUPER_ACL); + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (!count_ok) + { // too many connections + net_send_error(thd, ER_CON_COUNT_ERROR); + DBUG_RETURN(-1); + } + } + + /* + Log the command before authentication checks, so that the user can + check the log for the tried login tried and also to detect + break-in attempts. + */ + general_log_print(thd, command, + (thd->main_security_ctx.priv_user == + thd->main_security_ctx.user ? + (char*) "%s@%s on %s" : + (char*) "%s@%s as anonymous on %s"), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + db ? db : (char*) ""); + + /* + This is the default access rights for the current database. It's + set to 0 here because we don't have an active database yet (and we + may not have an active database to set. + */ + thd->main_security_ctx.db_access=0; + + /* Don't allow user to connect if he has done too many queries */ + if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || + max_user_connections) && + get_or_create_user_conn(thd, + (opt_old_style_user_limits ? thd->main_security_ctx.user : + thd->main_security_ctx.priv_user), + (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : + thd->main_security_ctx.priv_host), + &ur)) + DBUG_RETURN(-1); + if (thd->user_connect && + (thd->user_connect->user_resources.conn_per_hour || + thd->user_connect->user_resources.user_conn || + max_user_connections) && + check_for_max_user_connections(thd, thd->user_connect)) + DBUG_RETURN(-1); + + /* Change database if necessary */ + if (db && db[0]) + { + if (mysql_change_db(thd, db, FALSE)) + { + /* Send error to the client */ + net_send_error(thd); + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + DBUG_RETURN(-1); + } + } + send_ok(thd); + thd->password= test(passwd_len); // remember for error messages + /* Ready to handle queries */ + DBUG_RETURN(0); + } + } + else if (res == 2) // client gave short hash, server has long hash + { + net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); + } + net_printf_error(thd, ER_ACCESS_DENIED_ERROR, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + DBUG_RETURN(-1); +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ +} + + +/* + Check for maximum allowable user connections, if the mysqld server is + started with corresponding variable that is greater then 0. +*/ + +extern "C" byte *get_key_conn(user_conn *buff, uint *length, + my_bool not_used __attribute__((unused))) +{ + *length=buff->len; + return (byte*) buff->user; +} + + +extern "C" void free_user(struct user_conn *uc) +{ + my_free((char*) uc,MYF(0)); +} + + +void init_max_user_conn(void) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + (void) hash_init(&hash_user_connections,system_charset_info,max_connections, + 0,0, + (hash_get_key) get_key_conn, (hash_free_key) free_user, + 0); +#endif +} + + +void free_max_user_conn(void) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + hash_free(&hash_user_connections); +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ +} + + +void reset_mqh(LEX_USER *lu, bool get_them= 0) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + (void) pthread_mutex_lock(&LOCK_user_conn); + if (lu) // for GRANT + { + USER_CONN *uc; + uint temp_len=lu->user.length+lu->host.length+2; + char temp_user[USER_HOST_BUFF_SIZE]; + + memcpy(temp_user,lu->user.str,lu->user.length); + memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); + temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0; + if ((uc = (struct user_conn *) hash_search(&hash_user_connections, + (byte*) temp_user, temp_len))) + { + uc->questions=0; + get_mqh(temp_user,&temp_user[lu->user.length+1],uc); + uc->updates=0; + uc->conn_per_hour=0; + } + } + else + { + /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */ + for (uint idx=0;idx < hash_user_connections.records; idx++) + { + USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, + idx); + if (get_them) + get_mqh(uc->user,uc->host,uc); + uc->questions=0; + uc->updates=0; + uc->conn_per_hour=0; + } + } + (void) pthread_mutex_unlock(&LOCK_user_conn); +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ +} + + +void thd_init_client_charset(THD *thd, uint cs_number) +{ + /* + Use server character set and collation if + - opt_character_set_client_handshake is not set + - client has not specified a character set + - client character set is the same as the servers + - client character set doesn't exists in server + */ + if (!opt_character_set_client_handshake || + !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) || + !my_strcasecmp(&my_charset_latin1, + global_system_variables.character_set_client->name, + thd->variables.character_set_client->name)) + { + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.character_set_results= + global_system_variables.character_set_results; + } + else + { + thd->variables.character_set_results= + thd->variables.collation_connection= + thd->variables.character_set_client; + } +} + + +/* + Initialize connection threads +*/ + +bool init_new_connection_handler_thread() +{ + pthread_detach_this_thread(); +#if defined(__WIN__) + init_signals(); +#else + /* Win32 calls this in pthread_create */ + if (my_thread_init()) + return 1; +#endif /* __WIN__ */ + return 0; +} + +/* + Perform handshake, authorize client and update thd ACL variables. + + SYNOPSIS + check_connection() + thd thread handle + + RETURN + 0 success, OK is sent to user, thd is updated. + -1 error, which is sent to user + > 0 error code (not sent to user) +*/ + +#ifndef EMBEDDED_LIBRARY +static int check_connection(THD *thd) +{ + uint connect_errors= 0; + NET *net= &thd->net; + ulong pkt_len= 0; + char *end; + + DBUG_PRINT("info", + ("New connection received on %s", vio_description(net->vio))); +#ifdef SIGNAL_WITH_VIO_CLOSE + thd->set_active_vio(net->vio); +#endif + + if (!thd->main_security_ctx.host) // If TCP/IP connection + { + char ip[30]; + + if (vio_peer_addr(net->vio, ip, &thd->peer_port)) + return (ER_BAD_HOST_ERROR); + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) + return (ER_OUT_OF_RESOURCES); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; + vio_in_addr(net->vio,&thd->remote.sin_addr); + if (!(specialflag & SPECIAL_NO_RESOLVE)) + { + vio_in_addr(net->vio,&thd->remote.sin_addr); + thd->main_security_ctx.host= + ip_to_hostname(&thd->remote.sin_addr, &connect_errors); + /* Cut very long hostnames to avoid possible overflows */ + if (thd->main_security_ctx.host) + { + if (thd->main_security_ctx.host != my_localhost) + thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), + HOSTNAME_LENGTH)]= 0; + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; + } + if (connect_errors > max_connect_errors) + return(ER_HOST_IS_BLOCKED); + } + DBUG_PRINT("info",("Host: %s ip: %s", + (thd->main_security_ctx.host ? + thd->main_security_ctx.host : "unknown host"), + (thd->main_security_ctx.ip ? + thd->main_security_ctx.ip : "unknown ip"))); + if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) + return(ER_HOST_NOT_PRIVILEGED); + } + else /* Hostname given means that the connection was on a socket */ + { + DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; + thd->main_security_ctx.ip= 0; + /* Reset sin_addr */ + bzero((char*) &thd->remote, sizeof(thd->remote)); + } + vio_keepalive(net->vio, TRUE); + { + /* buff[] needs to big enough to hold the server_version variable */ + char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; + ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | + CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); + + if (opt_using_transactions) + client_flags|=CLIENT_TRANSACTIONS; +#ifdef HAVE_COMPRESS + client_flags |= CLIENT_COMPRESS; +#endif /* HAVE_COMPRESS */ +#ifdef HAVE_OPENSSL + if (ssl_acceptor_fd) + client_flags |= CLIENT_SSL; /* Wow, SSL is available! */ +#endif /* HAVE_OPENSSL */ + + end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; + int4store((uchar*) end, thd->thread_id); + end+= 4; + /* + So as check_connection is the only entry point to authorization + procedure, scramble is set here. This gives us new scramble for + each handshake. + */ + create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); + /* + Old clients does not understand long scrambles, but can ignore packet + tail: that's why first part of the scramble is placed here, and second + part at the end of packet. + */ + end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; + + int2store(end, client_flags); + /* write server characteristics: up to 16 bytes allowed */ + end[2]=(char) default_charset_info->number; + int2store(end+3, thd->server_status); + bzero(end+5, 13); + end+= 18; + /* write scramble tail */ + end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; + + /* At this point we write connection message and read reply */ + if (net_write_command(net, (uchar) protocol_version, "", 0, buff, + (uint) (end-buff)) || + (pkt_len= my_net_read(net)) == packet_error || + pkt_len < MIN_HANDSHAKE_SIZE) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + } +#ifdef _CUSTOMCONFIG_ +#include "_cust_sql_parse.h" +#endif + if (connect_errors) + reset_host_errors(&thd->remote.sin_addr); + if (thd->packet.alloc(thd->variables.net_buffer_length)) + return(ER_OUT_OF_RESOURCES); + + thd->client_capabilities=uint2korr(net->read_pos); + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; + thd->max_client_packet_length= uint4korr(net->read_pos+4); + DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); + thd_init_client_charset(thd, (uint) net->read_pos[8]); + thd->update_charset(); + end= (char*) net->read_pos+32; + } + else + { + thd->max_client_packet_length= uint3korr(net->read_pos+2); + end= (char*) net->read_pos+5; + } + + if (thd->client_capabilities & CLIENT_IGNORE_SPACE) + thd->variables.sql_mode|= MODE_IGNORE_SPACE; +#ifdef HAVE_OPENSSL + DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); + if (thd->client_capabilities & CLIENT_SSL) + { + /* Do the SSL layering. */ + if (!ssl_acceptor_fd) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + DBUG_PRINT("info", ("IO layer change in progress...")); + if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) + { + DBUG_PRINT("error", ("Failed to accept new SSL connection")); + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + DBUG_PRINT("info", ("Reading user information over SSL layer")); + if ((pkt_len= my_net_read(net)) == packet_error || + pkt_len < NORMAL_HANDSHAKE_SIZE) + { + DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", + pkt_len)); + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + } +#endif /* HAVE_OPENSSL */ + + if (end >= (char*) net->read_pos+ pkt_len +2) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + + if (thd->client_capabilities & CLIENT_INTERACTIVE) + thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; + if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && + opt_using_transactions) + net->return_status= &thd->server_status; + + char *user= end; + char *passwd= strend(user)+1; + uint user_len= passwd - user - 1; + char *db= passwd; + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 + uint dummy_errors; + + /* + Old clients send null-terminated string as password; new clients send + the size (1 byte) + string (not null-terminated). Hence in case of empty + password both send '\0'. + + This strlen() can't be easily deleted without changing protocol. + */ + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? + db + passwd_len + 1 : 0; + /* strlen() can't be easily deleted without changing protocol */ + uint db_len= db ? strlen(db) : 0; + + if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) + { + inc_host_errors(&thd->remote.sin_addr); + return ER_HANDSHAKE_ERROR; + } + + /* Since 4.1 all database names are stored in utf8 */ + if (db) + { + db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, + system_charset_info, + db, db_len, + thd->charset(), &dummy_errors)]= 0; + db= db_buff; + } + + user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1, + system_charset_info, user, user_len, + thd->charset(), &dummy_errors)]= '\0'; + user= user_buff; + + /* If username starts and ends in "'", chop them off */ + if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'') + { + user[user_len-1]= 0; + user++; + user_len-= 2; + } + + if (thd->main_security_ctx.user) + x_free(thd->main_security_ctx.user); + if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) + return (ER_OUT_OF_RESOURCES); + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); +} + + +/* + Setup thread to be used with the current thread + + SYNOPSIS + bool setup_connection_thread_globals() + thd Thread/connection handler + + RETURN + 0 ok + 1 Error (out of memory) + In this case we will close the connection and increment status +*/ + +bool setup_connection_thread_globals(THD *thd) +{ + if (thd->store_globals()) + { + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + statistic_increment(aborted_connects,&LOCK_status); + thread_scheduler.end_thread(thd, 0); + return 1; // Error + } + return 0; +} + + +/* + Autenticate user, with error reporting + + SYNOPSIS + login_connection() + thd Thread handler + + NOTES + Connection is not closed in case of errors + + RETURN + 0 ok + 1 error +*/ + + +bool login_connection(THD *thd) +{ + int error; + NET *net= &thd->net; + Security_context *sctx= thd->security_ctx; + DBUG_ENTER("login_connection"); + DBUG_PRINT("info", ("handle_one_connection called by thread %lu", + thd->thread_id)); + + net->no_send_error= 0; + + /* Use "connect_timeout" value during connection phase */ + net_set_read_timeout(net, connect_timeout); + net_set_write_timeout(net, connect_timeout); + + if ((error=check_connection(thd))) + { // Wrong permissions + if (error > 0) + net_printf_error(thd, error, sctx->host_or_ip); +#ifdef __NT__ + if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) + my_sleep(1000); /* must wait after eof() */ +#endif + statistic_increment(aborted_connects,&LOCK_status); + DBUG_RETURN(1); + } + /* Connect completed, set read/write timeouts back to default */ + net_set_read_timeout(net, thd->variables.net_read_timeout); + net_set_write_timeout(net, thd->variables.net_write_timeout); + DBUG_RETURN(0); +} + + +/* + Close an established connection + + NOTES + This mainly updates status variables +*/ + +void end_connection(THD *thd) +{ + NET *net= &thd->net; + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + if (net->error && net->vio != 0 && net->report_error) + { + Security_context *sctx= thd->security_ctx; + if (!thd->killed && thd->variables.log_warnings > 1) + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), + thd->thread_id,(thd->db ? thd->db : "unconnected"), + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, + (net->last_errno ? ER(net->last_errno) : + ER(ER_UNKNOWN_ERROR))); + net_send_error(thd, net->last_errno, NullS); + statistic_increment(aborted_threads,&LOCK_status); + } + else if (thd->killed) + statistic_increment(aborted_threads,&LOCK_status); +} + + +/* + Initialize THD to handle queries +*/ + +void prepare_new_connection_state(THD* thd) +{ + Security_context *sctx= thd->security_ctx; + +#ifdef __NETWARE__ + netware_reg_user(sctx->ip, sctx->user, "MySQL"); +#endif + + if (thd->variables.max_join_size == HA_POS_ERROR) + thd->options |= OPTION_BIG_SELECTS; + if (thd->client_capabilities & CLIENT_COMPRESS) + thd->net.compress=1; // Use compression + + thd->version= refresh_version; + thd->proc_info= 0; + thd->command= COM_SLEEP; + thd->set_time(); + thd->init_for_queries(); + + if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) + { + execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); + if (thd->query_error) + { + thd->killed= THD::KILL_CONNECTION; + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), + thd->thread_id,(thd->db ? thd->db : "unconnected"), + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, "init_connect command failed"); + sql_print_warning("%s", thd->net.last_error); + } + thd->proc_info=0; + thd->set_time(); + thd->init_for_queries(); + } +} + + +/* + Thread handler for a connection + + SYNOPSIS + handle_one_connection() + arg Connection object (THD) + + IMPLEMENTATION + This function (normally) does the following: + - Initialize thread + - Initialize THD to be used with this thread + - Authenticate user + - Execute all queries sent on the connection + - Take connection down + - End thread / Handle next connection using thread from thread cache +*/ + +pthread_handler_t handle_one_connection(void *arg) +{ + THD *thd= (THD*) arg; + uint launch_time = + (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time); + + if (thread_scheduler.init_new_connection_thread()) + { + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + statistic_increment(aborted_connects,&LOCK_status); + thread_scheduler.end_thread(thd,0); + return 0; + } + if (launch_time >= slow_launch_time) + statistic_increment(slow_launch_threads,&LOCK_status); + + /* + handle_one_connection() is normally the only way a thread would + start and would always be on the very high end of the stack , + therefore, the thread stack always starts at the address of the + first local variable of handle_one_connection, which is thd. We + need to know the start of the stack so that we could check for + stack overruns. + */ + thd->thread_stack= (char*) &thd; + if (setup_connection_thread_globals(thd)) + return 0; + + for (;;) + { + NET *net= &thd->net; + + if (login_connection(thd)) + goto end_thread; + + prepare_new_connection_state(thd); + + while (!net->error && net->vio != 0 && + !(thd->killed == THD::KILL_CONNECTION)) + { + net->no_send_error= 0; + if (do_command(thd)) + break; + } + end_connection(thd); + +end_thread: + close_connection(thd, 0, 1); + if (thread_scheduler.end_thread(thd,1)) + return 0; // Probably no-threads + + /* + If end_thread() returns, we are either running with + thread-handler=no-threads or this thread has been schedule to + handle the next connection. + */ + thd= current_thd; + thd->thread_stack= (char*) &thd; + } +} +#endif /* EMBEDDED_LIBRARY */ diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc index 4e73941fb49..ebd424f00f0 100644 --- a/sql/sql_crypt.cc +++ b/sql/sql_crypt.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2003, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h index 25bc2d29e1d..f3db9adde25 100644 --- a/sql/sql_crypt.h +++ b/sql/sql_crypt.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 46fae3ffb99..d31c0af1163 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h index d1156dfba8d..6edd6b24b36 100644 --- a/sql/sql_cursor.h +++ b/sql/sql_cursor.h @@ -1,11 +1,8 @@ -#ifndef _sql_cursor_h_ -#define _sql_cursor_h_ -/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,6 +13,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef _sql_cursor_h_ +#define _sql_cursor_h_ + #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class interface */ #endif diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 4f9e19732fd..4fd35b7e6e8 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index df24dad2d4c..ea8c0e2d83e 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -70,13 +69,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, Test if the user wants to delete all rows and deletion doesn't have any side-effects (because of triggers), so we can use optimized handler::delete_all_rows() method. - - If row-based replication is used, we also delete the table row by - row. + We implement fast TRUNCATE for InnoDB even if triggers are present. + TRUNCATE ignores triggers. */ if (!using_limit && const_cond && (!conds || conds->val_int()) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !(table->triggers && table->triggers->has_delete_triggers()) && + (thd->lex->sql_command == SQLCOM_TRUNCATE || + !(table->triggers && table->triggers->has_delete_triggers())) && !thd->current_stmt_binlog_row_based) { /* Update the table->file->stats.records number */ @@ -154,7 +153,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (order && order->elements) { - uint length; + uint length= 0; SORT_FIELD *sortorder; TABLE_LIST tables; List<Item> fields; @@ -174,7 +173,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); } - if (!select && limit != HA_POS_ERROR) + if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR) usable_index= get_index_for_order(table, (ORDER*)(order->first), limit); if (usable_index == MAX_KEY) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 5a9871c07c5..5712fbceac8 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -110,8 +109,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) SELECT_LEX *first_select= unit->first_select(); TABLE *table= 0; select_union *derived_result; - bool is_union= first_select->next_select() && - first_select->next_select()->linkage == UNION_TYPE; /* prevent name resolving out of derived table */ for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 98483ce2de6..a3eb93f87da 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_error.cc b/sql/sql_error.cc index dc7a437d7d1..70882d8f4e8 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_error.h b/sql/sql_error.h index f4a7b14ba1a..f98264dce50 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 5951acdcc40..91e61be0478 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -1,8 +1,7 @@ /* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 69d21f8b7bb..7b7f7602163 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 191fc60dfd5..6f4cdbba3dd 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -61,7 +60,6 @@ #include "sql_select.h" #include "sql_show.h" -static int check_null_fields(THD *thd,TABLE *entry); #ifndef EMBEDDED_LIBRARY static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list); static int write_delayed(THD *thd, TABLE *table, enum_duplicates dup, @@ -82,6 +80,65 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); #define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0)) #endif +/* + Check that insert/update fields are from the same single table of a view. + + SYNOPSIS + check_view_single_update() + fields The insert/update fields to be checked. + view The view for insert. + map [in/out] The insert table map. + + DESCRIPTION + This function is called in 2 cases: + 1. to check insert fields. In this case *map will be set to 0. + Insert fields are checked to be all from the same single underlying + table of the given view. Otherwise the error is thrown. Found table + map is returned in the map parameter. + 2. to check update fields of the ON DUPLICATE KEY UPDATE clause. + In this case *map contains table_map found on the previous call of + the function to check insert fields. Update fields are checked to be + from the same table as the insert fields. + + RETURN + 0 OK + 1 Error +*/ + +bool check_view_single_update(List<Item> &fields, TABLE_LIST *view, + table_map *map) +{ + /* it is join view => we need to find the table for update */ + List_iterator_fast<Item> it(fields); + Item *item; + TABLE_LIST *tbl= 0; // reset for call to check_single_table() + table_map tables= 0; + + while ((item= it++)) + tables|= item->used_tables(); + + /* Check found map against provided map */ + if (*map) + { + if (tables != *map) + goto error; + return FALSE; + } + + if (view->check_single_table(&tbl, tables, view) || tbl == 0) + goto error; + + view->table= tbl->table; + *map= tables; + + return FALSE; + +error: + my_error(ER_VIEW_MULTIUPDATE, MYF(0), + view->view_db.str, view->view_name.str); + return TRUE; +} + /* Check if insert fields are correct. @@ -106,7 +163,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); static int check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, - bool check_unique) + bool check_unique, table_map *map) { TABLE *table= table_list->table; @@ -132,11 +189,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, #ifndef NO_EMBEDDED_ACCESS_CHECKS if (grant_option) { - Field_iterator_table fields; - fields.set_table(table); + Field_iterator_table field_it; + field_it.set_table(table); if (check_grant_all_columns(thd, INSERT_ACL, &table->grant, table->s->db.str, table->s->table_name.str, - &fields)) + &field_it)) return -1; } #endif @@ -184,21 +241,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) { - /* it is join view => we need to find table for update */ - List_iterator_fast<Item> it(fields); - Item *item; - TABLE_LIST *tbl= 0; // reset for call to check_single_table() - table_map map= 0; - - while ((item= it++)) - map|= item->used_tables(); - if (table_list->check_single_table(&tbl, map, table_list) || tbl == 0) - { - my_error(ER_VIEW_MULTIUPDATE, MYF(0), - table_list->view_db.str, table_list->view_name.str); + if (check_view_single_update(fields, table_list, map)) return -1; - } - table_list->table= table= tbl->table; + table= table_list->table; } if (check_unique && thd->dup_field) @@ -256,7 +301,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, */ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, - List<Item> &update_fields) + List<Item> &update_fields, table_map *map) { TABLE *table= insert_table_list->table; my_bool timestamp_mark; @@ -277,6 +322,10 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0)) return -1; + if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE && + check_view_single_update(update_fields, insert_table_list, map)) + return -1; + if (table->timestamp_field) { /* Don't set timestamp column if this is modified. */ @@ -301,13 +350,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, bool ignore) { int error, res; - /* - log_on is about delayed inserts only. - By default, both logs are enabled (this won't cause problems if the server - runs without --log-update or --log-bin). - */ - bool log_on= ((thd->options & OPTION_BIN_LOG) || - (!(thd->security_ctx->master_access & SUPER_ACL))); bool transactional_table, joins_freed= FALSE; bool changed; uint value_count; @@ -321,6 +363,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, Name_resolution_context_state ctx_state; #ifndef EMBEDDED_LIBRARY char *query= thd->query; + /* + log_on is about delayed inserts only. + By default, both logs are enabled (this won't cause problems if the server + runs without --log-update or --log-bin). + */ + bool log_on= ((thd->options & OPTION_BIN_LOG) || + (!(thd->security_ctx->master_access & SUPER_ACL))); #endif thr_lock_type lock_type = table_list->lock_type; Item *unused_conds= 0; @@ -347,6 +396,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY if (lock_type == TL_WRITE_DELAYED) { + res= 1; if (thd->locked_tables) { DBUG_ASSERT(table_list->db); /* Must be set in the parser */ @@ -741,7 +791,6 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) Field_translator *trans_start= view->field_translation, *trans_end= trans_start + num; Field_translator *trans; - Field **field_ptr= table->field; uint used_fields_buff_size= bitmap_buffer_size(table->s->fields); uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size); MY_BITMAP used_fields; @@ -893,6 +942,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, Name_resolution_context_state ctx_state; bool insert_into_view= (table_list->view != 0); bool res= 0; + table_map map= 0; DBUG_ENTER("mysql_prepare_insert"); DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", (ulong)table_list, (ulong)table, @@ -941,12 +991,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, /* Prepare the fields in the statement. */ if (values && !(res= check_insert_fields(thd, context->table_list, fields, *values, - !insert_into_view) || + !insert_into_view, &map) || setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) && duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; - res= check_update_fields(thd, context->table_list, update_fields); + res= check_update_fields(thd, context->table_list, update_fields, &map); select_lex->no_wrap_view_item= FALSE; /* When we are not using GROUP BY we can refer to other tables in the @@ -1154,25 +1204,30 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) { table->file->restore_auto_increment(prev_insert_id); + goto ok_or_after_trg_err; } goto err; - } - info->updated++; - /* - If ON DUP KEY UPDATE updates a row instead of inserting one, it's - like a regular UPDATE statement: it should not affect the value of a - next SELECT LAST_INSERT_ID() or mysql_insert_id(). - Except if LAST_INSERT_ID(#) was in the INSERT query, which is - handled separately by THD::arg_of_last_insert_id_function. - */ - insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; - if (table->next_number_field) - table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int()); - trg_error= (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, TRUE)); - info->copied++; + } + if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) || + compare_record(table)) + { + info->updated++; + /* + If ON DUP KEY UPDATE updates a row instead of inserting one, it's + like a regular UPDATE statement: it should not affect the value of a + next SELECT LAST_INSERT_ID() or mysql_insert_id(). + Except if LAST_INSERT_ID(#) was in the INSERT query, which is + handled separately by THD::arg_of_last_insert_id_function. + */ + insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; + if (table->next_number_field) + table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int()); + trg_error= (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, + TRG_ACTION_AFTER, TRUE)); + info->copied++; + } goto ok_or_after_trg_err; } else /* DUP_REPLACE */ @@ -1292,7 +1347,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, { if (!bitmap_is_set(write_set, (*field)->field_index) && ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && - ((*field)->real_type() != FIELD_TYPE_ENUM)) + ((*field)->real_type() != MYSQL_TYPE_ENUM)) { bool view= FALSE; if (table_list) @@ -1808,8 +1863,6 @@ void kill_delayed_threads(void) delayed_insert *tmp; while ((tmp=it++)) { - /* Ensure that the thread doesn't kill itself while we are looking at it */ - pthread_mutex_lock(&tmp->mutex); tmp->thd.killed= THD::KILL_CONNECTION; if (tmp->thd.mysys_var) { @@ -1828,7 +1881,6 @@ void kill_delayed_threads(void) } pthread_mutex_unlock(&tmp->thd.mysys_var->mutex); } - pthread_mutex_unlock(&tmp->mutex); } VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list } @@ -1846,7 +1898,7 @@ pthread_handler_t handle_delayed_insert(void *arg) pthread_detach_this_thread(); /* Add thread to THD list so that's it's visible in 'show processlist' */ pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id=thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; thd->end_time(); threads.append(thd); thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; @@ -1877,14 +1929,8 @@ pthread_handler_t handle_delayed_insert(void *arg) strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES)); goto err; } -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif /* open table */ - if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED))) { thd->fatal_error(); // Abort waiting inserts @@ -2281,7 +2327,6 @@ bool delayed_insert::handle_inserts(void) thd.proc_info=0; pthread_mutex_unlock(&mutex); -#ifdef HAVE_ROW_BASED_REPLICATION /* We need to flush the pending event when using row-based replication since the flushing normally done in binlog_query() is @@ -2296,7 +2341,6 @@ bool delayed_insert::handle_inserts(void) */ if (thd.current_stmt_binlog_row_based) thd.binlog_flush_pending_rows_event(TRUE); -#endif /* HAVE_ROW_BASED_REPLICATION */ if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { // This shouldn't happen @@ -2410,6 +2454,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { LEX *lex= thd->lex; int res; + table_map map= 0; SELECT_LEX *lex_current_select_save= lex->current_select; DBUG_ENTER("select_insert::prepare"); @@ -2422,7 +2467,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) */ lex->current_select= &lex->select_lex; res= check_insert_fields(thd, table_list, *fields, values, - !insert_into_view) || + !insert_into_view, &map) || setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0); if (info.handle_duplicates == DUP_UPDATE) @@ -2440,7 +2485,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) lex->select_lex.no_wrap_view_item= TRUE; res= res || check_update_fields(thd, context->table_list, - *info.update_fields); + *info.update_fields, &map); lex->select_lex.no_wrap_view_item= FALSE; /* When we are not using GROUP BY we can refer to other tables in the @@ -2648,8 +2693,7 @@ void select_insert::send_error(uint errcode,const char *err) If the creation of the table failed (due to a syntax error, for example), no table will have been opened and therefore 'table' will be NULL. In that case, we still need to execute the rollback - and the end of the function to truncate the binary log, but we can - skip all the intermediate steps. + and the end of the function. */ if (table) { @@ -2680,10 +2724,8 @@ void select_insert::send_error(uint errcode,const char *err) if (!table->file->has_transactions()) { if (mysql_bin_log.is_open()) - { thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, table->file->has_transactions(), FALSE); - } if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && !can_rollback_data()) thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; @@ -2950,7 +2992,24 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) DBUG_ENTER("select_create::prepare"); TABLEOP_HOOKS *hook_ptr= NULL; -#ifdef HAVE_ROW_BASED_REPLICATION + /* + For row-based replication, the CREATE-SELECT statement is written + in two pieces: the first one contain the CREATE TABLE statement + necessary to create the table and the second part contain the rows + that should go into the table. + + For non-temporary tables, the start of the CREATE-SELECT + implicitly commits the previous transaction, and all events + forming the statement will be stored the transaction cache. At end + of the statement, the entire statement is committed as a + transaction, and all events are written to the binary log. + + On the master, the table is locked for the duration of the + statement, but since the CREATE part is replicated as a simple + statement, there is no way to lock the table for accesses on the + slave. Hence, we have to hold on to the CREATE part of the + statement until the statement has finished. + */ class MY_HOOKS : public TABLEOP_HOOKS { public: MY_HOOKS(select_create *x) : ptr(x) { } @@ -2960,7 +3019,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { TABLE const *const table = *tables; if (ptr->get_thd()->current_stmt_binlog_row_based && - table->s->tmp_table == NO_TMP_TABLE && + !table->s->tmp_table && !ptr->get_create_info()->table_existed) { ptr->binlog_show_create_table(tables, count); @@ -2972,22 +3031,19 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) MY_HOOKS hooks(this); hook_ptr= &hooks; -#endif unit= u; -#ifdef HAVE_ROW_BASED_REPLICATION /* - Start a statement transaction before the create if we are creating - a non-temporary table and are using row-based replication for the - statement. + Start a statement transaction before the create if we are using + row-based replication for the statement. If we are creating a + temporary table, we need to start a statement transaction. */ if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 && thd->current_stmt_binlog_row_based) { thd->binlog_start_trans_and_stmt(); } -#endif if (!(table= create_table_from_items(thd, create_info, create_table, extra_fields, keys, &values, @@ -3031,8 +3087,6 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) DBUG_RETURN(0); } - -#ifdef HAVE_ROW_BASED_REPLICATION void select_create::binlog_show_create_table(TABLE **tables, uint count) { @@ -3073,7 +3127,6 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) /* is_trans */ TRUE, /* suppress_use */ FALSE); } -#endif // HAVE_ROW_BASED_REPLICATION void select_create::store_values(List<Item> &values) { @@ -3084,13 +3137,36 @@ void select_create::store_values(List<Item> &values) void select_create::send_error(uint errcode,const char *err) { + DBUG_ENTER("select_create::send_error"); + + DBUG_PRINT("info", + ("Current statement %s row-based", + thd->current_stmt_binlog_row_based ? "is" : "is NOT")); + DBUG_PRINT("info", + ("Current table (at 0x%lx) %s a temporary (or non-existing) " + "table", + (ulong) table, + table && !table->s->tmp_table ? "is NOT" : "is")); + DBUG_PRINT("info", + ("Table %s prior to executing this statement", + get_create_info()->table_existed ? "existed" : "did not exist")); + /* - Disable binlog, because we "roll back" partial inserts in ::abort - by removing the table, even for non-transactional tables. + This will execute any rollbacks that are necessary before writing + the transcation cache. + + We disable the binary log since nothing should be written to the + binary log. This disabling is important, since we potentially do + a "roll back" of non-transactional tables by removing the table, + and the actual rollback might generate events that should not be + written to the binary log. + */ tmp_disable_binlog(thd); select_insert::send_error(errcode, err); reenable_binlog(thd); + + DBUG_VOID_RETURN; } @@ -3101,6 +3177,14 @@ bool select_create::send_eof() abort(); else { + /* + Do an implicit commit at end of statement for non-temporary + tables. This can fail, but we should unlock the table + nevertheless. + */ + if (!table->s->tmp_table) + ha_commit(thd); // Can fail, but we proceed anyway + table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); VOID(pthread_mutex_lock(&LOCK_open)); @@ -3119,12 +3203,31 @@ bool select_create::send_eof() void select_create::abort() { + DBUG_ENTER("select_create::abort"); VOID(pthread_mutex_lock(&LOCK_open)); + + /* + We roll back the statement, including truncating the transaction + cache of the binary log, if the statement failed. + + We roll back the statement prior to deleting the table and prior + to releasing the lock on the table, since there might be potential + for failure if the rollback is executed after the drop or after + unlocking the table. + + We also roll back the statement regardless of whether the creation + of the table succeeded or not, since we need to reset the binary + log state. + */ + if (thd->current_stmt_binlog_row_based) + ha_rollback_stmt(thd); + if (thd->extra_lock) { mysql_unlock_tables(thd, thd->extra_lock); thd->extra_lock=0; } + if (table) { table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); @@ -3136,17 +3239,8 @@ void select_create::abort() table->s->version= 0; hash_delete(&open_cache,(byte*) table); if (!create_info->table_existed) - { quick_rm_table(table_type, create_table->db, create_table->table_name, 0); - /* - We roll back the statement, including truncating the - transaction cache of the binary log, if the statement - failed. - */ - if (thd->current_stmt_binlog_row_based) - ha_rollback_stmt(thd); - } /* Tell threads waiting for refresh that something has happened */ if (version != refresh_version) broadcast_refresh(); @@ -3156,6 +3250,7 @@ void select_create::abort() table=0; // Safety } VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_VOID_RETURN; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d156973a790..af2929b6268 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -183,6 +182,21 @@ void lex_start(THD *thd, const uchar *buf, uint length) lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; + /* + ok, there must be a better solution for this, long-term + I tried "bzero" in the sql_yacc.yy code, but that for + some reason made the values zero, even if they were set + */ + lex->server_options.server_name= 0; + lex->server_options.server_name_length= 0; + lex->server_options.host= 0; + lex->server_options.db= 0; + lex->server_options.username= 0; + lex->server_options.password= 0; + lex->server_options.scheme= 0; + lex->server_options.socket= 0; + lex->server_options.owner= 0; + lex->server_options.port= -1; DBUG_VOID_RETURN; } @@ -303,13 +317,15 @@ static char *get_text(LEX *lex) { c = yyGet(); #ifdef USE_MB - int l; - if (use_mb(cs) && - (l = my_ismbchar(cs, - (const char *)lex->ptr-1, - (const char *)lex->end_of_query))) { + { + int l; + if (use_mb(cs) && + (l = my_ismbchar(cs, + (const char *)lex->ptr-1, + (const char *)lex->end_of_query))) { lex->ptr += l-1; continue; + } } #endif if (c == '\\' && @@ -777,8 +793,8 @@ int MYSQLlex(void *arg, void *yythd) lex->tok_start=lex->ptr; // Skip first ` while ((c=yyGet())) { - int length; - if ((length= my_mbcharlen(cs, c)) == 1) + int var_length; + if ((var_length= my_mbcharlen(cs, c)) == 1) { if (c == quote_char) { @@ -790,9 +806,9 @@ int MYSQLlex(void *arg, void *yythd) } } #ifdef USE_MB - else if (length < 1) + else if (var_length < 1) break; // Error - lex->ptr+= length-1; + lex->ptr+= var_length-1; #endif } if (double_quotes) @@ -1179,7 +1195,6 @@ void st_select_lex::init_select() options= 0; sql_cache= SQL_CACHE_UNSPECIFIED; braces= 0; - when_list.empty(); expr_list.empty(); interval_list.empty(); use_index.empty(); @@ -1195,6 +1210,8 @@ void st_select_lex::init_select() offset_limit= 0; /* denotes the default offset = 0 */ with_sum_func= 0; is_correlated= 0; + cur_pos_in_select_list= UNDEF_POS; + non_agg_fields.empty(); } /* @@ -1384,9 +1401,17 @@ void st_select_lex::mark_as_dependent(SELECT_LEX *last) if (!(s->uncacheable & UNCACHEABLE_DEPENDENT)) { // Select is dependent of outer select - s->uncacheable|= UNCACHEABLE_DEPENDENT; + s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) | + UNCACHEABLE_DEPENDENT; SELECT_LEX_UNIT *munit= s->master_unit(); - munit->uncacheable|= UNCACHEABLE_DEPENDENT; + munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) | + UNCACHEABLE_DEPENDENT; + for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select()) + { + if (sl != s && + !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED))) + sl->uncacheable|= UNCACHEABLE_UNITED; + } } is_correlated= TRUE; this->master_unit()->item->is_correlated= TRUE; @@ -1667,9 +1692,7 @@ void Query_tables_list::reset_query_tables_list(bool init) sroutines_list.empty(); sroutines_list_own_last= sroutines_list.next; sroutines_list_own_elements= 0; -#ifdef HAVE_ROW_BASED_REPLICATION binlog_row_based_if_mixed= FALSE; -#endif } @@ -1734,13 +1757,14 @@ bool st_lex::can_be_merged() bool selects_allow_merge= select_lex.next_select() == 0; if (selects_allow_merge) { - for (SELECT_LEX_UNIT *unit= select_lex.first_inner_unit(); - unit; - unit= unit->next_unit()) + for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit(); + tmp_unit; + tmp_unit= tmp_unit->next_unit()) { - if (unit->first_select()->parent_lex == this && - (unit->item == 0 || - (unit->item->place() != IN_WHERE && unit->item->place() != IN_ON))) + if (tmp_unit->first_select()->parent_lex == this && + (tmp_unit->item == 0 || + (tmp_unit->item->place() != IN_WHERE && + tmp_unit->item->place() != IN_ON))) { selects_allow_merge= 0; break; @@ -1749,7 +1773,6 @@ bool st_lex::can_be_merged() } return (selects_allow_merge && - select_lex.order_list.elements == 0 && select_lex.group_list.elements == 0 && select_lex.having == 0 && select_lex.with_sum_func == 0 && @@ -2038,12 +2061,12 @@ void st_lex::first_lists_tables_same() FALSE - success */ -bool st_lex::add_time_zone_tables_to_query_tables(THD *thd) +bool st_lex::add_time_zone_tables_to_query_tables(THD *thd_arg) { /* We should not add these tables twice */ if (!time_zone_tables_used) { - time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last); + time_zone_tables_used= my_tz_get_table_list(thd_arg, &query_tables_last); if (time_zone_tables_used == &fake_time_zone_tables_list) return TRUE; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7fd60cbfa58..821af3f946d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -111,6 +110,7 @@ enum enum_sql_command { SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT, SQLCOM_SHOW_PLUGINS, SQLCOM_SHOW_CONTRIBUTORS, + SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER, SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, @@ -174,6 +174,14 @@ enum enum_drop_mode typedef List<Item> List_item; +/* SERVERS CACHE CHANGES */ +typedef struct st_lex_server_options +{ + long port; + uint server_name_length; + char *server_name, *host, *db, *username, *password, *scheme, *socket, *owner; +} LEX_SERVER_OPTIONS; + typedef struct st_lex_master_info { char *host, *user, *password, *log_file_name; @@ -424,7 +432,8 @@ protected: select_result *result; ulonglong found_rows_for_union; - bool res; + bool saved_error; + public: bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) @@ -496,7 +505,7 @@ public: void set_thd(THD *thd_arg) { thd= thd_arg; } friend void lex_start(THD *thd, const uchar *buf, uint length); - friend int subselect_union_engine::exec(bool); + friend int subselect_union_engine::exec(); List<Item> *get_unit_column_types(); }; @@ -544,7 +553,6 @@ public: SQL_LIST order_list; /* ORDER clause */ List<List_item> expr_list; - List<List_item> when_list; /* WHEN clause (expression) */ SQL_LIST *gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ // Arrays of pointers to top elements of all_fields list @@ -608,7 +616,26 @@ public: bool no_wrap_view_item; /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; + /* List of fields that aren't under an aggregate function */ + List<Item_field> non_agg_fields; + /* index in the select list of the expression currently being fixed */ + int cur_pos_in_select_list; + List<udf_func> udf_list; /* udf function calls stack */ + /* + This is a copy of the original JOIN USING list that comes from + the parser. The parser : + 1. Sets the natural_join of the second TABLE_LIST in the join + and the st_select_lex::prev_join_using. + 2. Makes a parent TABLE_LIST and sets its is_natural_join/ + join_using_fields members. + 3. Uses the wrapper TABLE_LIST as a table in the upper level. + We cannot assign directly to join_using_fields in the parser because + at stage (1.) the parent TABLE_LIST is not constructed yet and + the assignment will override the JOIN USING fields of the lower level + joins on the right. + */ + List<String> *prev_join_using; void init_query(); void init_select(); st_select_lex_unit* master_unit(); @@ -813,7 +840,6 @@ public: byte **sroutines_list_own_last; uint sroutines_list_own_elements; -#ifdef HAVE_ROW_BASED_REPLICATION /* Tells if the parsing stage detected that some items require row-based binlogging to give a reliable binlog/replication, or if we will use @@ -821,7 +847,6 @@ public: binlogging. */ bool binlog_row_based_if_mixed; -#endif /* These constructor and destructor serve for creation/destruction @@ -977,6 +1002,7 @@ typedef struct st_lex : public Query_tables_list HA_CREATE_INFO create_info; KEY_CREATE_INFO key_create_info; LEX_MASTER_INFO mi; // used by CHANGE MASTER + LEX_SERVER_OPTIONS server_options; USER_RESOURCES mqh; ulong type; /* diff --git a/sql/sql_list.cc b/sql/sql_list.cc index d57a7dfe4e3..01ab9b91424 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2003, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_list.h b/sql/sql_list.h index 070fd1e3d9a..af30cbe0d6a 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -39,6 +38,8 @@ public: static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* never called */ } + static void operator delete[](void *ptr, MEM_ROOT *mem_root) + { /* never called */ } static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } #ifdef HAVE_purify bool dummy; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index e08fc93beaf..364fda2c94b 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -83,10 +82,11 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, List<Item> &set_values, READ_INFO &read_info, String &enclosed, ulong skip_lines, bool ignore_check_option_errors); +#ifndef EMBEDDED_LIBRARY static bool write_execute_load_query_log_event(THD *thd, bool duplicates, bool ignore, bool transactional_table); - +#endif /* EMBEDDED_LIBRARY */ /* Execute LOAD DATA query @@ -465,7 +465,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY if (mysql_bin_log.is_open()) { -#ifdef HAVE_ROW_BASED_REPLICATION /* We need to do the job that is normally done inside binlog_query() here, which is to ensure that the pending event @@ -477,7 +476,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (thd->current_stmt_binlog_row_based) thd->binlog_flush_pending_rows_event(true); else -#endif { /* As already explained above, we need to call end_io_cache() or the last @@ -508,6 +506,8 @@ err: } +#ifndef EMBEDDED_LIBRARY + /* Not a very useful function; just to avoid duplication of code */ static bool write_execute_load_query_log_event(THD *thd, bool duplicates, bool ignore, @@ -524,6 +524,7 @@ static bool write_execute_load_query_log_event(THD *thd, return mysql_bin_log.write(&e); } +#endif /**************************************************************************** ** Read of rows of fixed size + optional garage + optonal newline @@ -721,7 +722,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, table->auto_increment_field_not_null= TRUE; if (!field->maybe_null()) { - if (field->type() == FIELD_TYPE_TIMESTAMP) + if (field->type() == MYSQL_TYPE_TIMESTAMP) ((Field_timestamp*) field)->set_time(); else if (field != table->next_number_field) field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index b947b9dfa98..4e61c664106 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,17 +23,6 @@ #include "mysql_priv.h" -MY_LOCALE *my_locale_by_name(const char *name) -{ - MY_LOCALE **locale; - for( locale= my_locales; *locale != NULL; locale++) - { - if(!strcmp((*locale)->name, name)) - return *locale; - } - return NULL; -} - /***** LOCALE BEGIN ar_AE: Arabic - United Arab Emirates *****/ static const char *my_locale_month_names_ar_AE[13] = {"يناير","Ùبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوÙمبر","ديسمبر", NullS }; @@ -52,7 +40,17 @@ static TYPELIB my_locale_typelib_day_names_ar_AE = { array_elements(my_locale_day_names_ar_AE)-1, "", my_locale_day_names_ar_AE, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ar_AE = { array_elements(my_locale_ab_day_names_ar_AE)-1, "", my_locale_ab_day_names_ar_AE, NULL }; -MY_LOCALE my_locale_ar_AE ( "ar_AE", "Arabic - United Arab Emirates", FALSE, &my_locale_typelib_month_names_ar_AE, &my_locale_typelib_ab_month_names_ar_AE, &my_locale_typelib_day_names_ar_AE, &my_locale_typelib_ab_day_names_ar_AE ); +MY_LOCALE my_locale_ar_AE +( + 6, + "ar_AE", + "Arabic - United Arab Emirates", + FALSE, + &my_locale_typelib_month_names_ar_AE, + &my_locale_typelib_ab_month_names_ar_AE, + &my_locale_typelib_day_names_ar_AE, + &my_locale_typelib_ab_day_names_ar_AE +); /***** LOCALE END ar_AE *****/ /***** LOCALE BEGIN ar_BH: Arabic - Bahrain *****/ @@ -72,7 +70,17 @@ static TYPELIB my_locale_typelib_day_names_ar_BH = { array_elements(my_locale_day_names_ar_BH)-1, "", my_locale_day_names_ar_BH, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ar_BH = { array_elements(my_locale_ab_day_names_ar_BH)-1, "", my_locale_ab_day_names_ar_BH, NULL }; -MY_LOCALE my_locale_ar_BH ( "ar_BH", "Arabic - Bahrain", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_BH +( + 7, + "ar_BH", + "Arabic - Bahrain", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_BH *****/ /***** LOCALE BEGIN ar_JO: Arabic - Jordan *****/ @@ -92,7 +100,17 @@ static TYPELIB my_locale_typelib_day_names_ar_JO = { array_elements(my_locale_day_names_ar_JO)-1, "", my_locale_day_names_ar_JO, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ar_JO = { array_elements(my_locale_ab_day_names_ar_JO)-1, "", my_locale_ab_day_names_ar_JO, NULL }; -MY_LOCALE my_locale_ar_JO ( "ar_JO", "Arabic - Jordan", FALSE, &my_locale_typelib_month_names_ar_JO, &my_locale_typelib_ab_month_names_ar_JO, &my_locale_typelib_day_names_ar_JO, &my_locale_typelib_ab_day_names_ar_JO ); +MY_LOCALE my_locale_ar_JO +( + 8, + "ar_JO", + "Arabic - Jordan", + FALSE, + &my_locale_typelib_month_names_ar_JO, + &my_locale_typelib_ab_month_names_ar_JO, + &my_locale_typelib_day_names_ar_JO, + &my_locale_typelib_ab_day_names_ar_JO +); /***** LOCALE END ar_JO *****/ /***** LOCALE BEGIN ar_SA: Arabic - Saudi Arabia *****/ @@ -112,7 +130,17 @@ static TYPELIB my_locale_typelib_day_names_ar_SA = { array_elements(my_locale_day_names_ar_SA)-1, "", my_locale_day_names_ar_SA, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ar_SA = { array_elements(my_locale_ab_day_names_ar_SA)-1, "", my_locale_ab_day_names_ar_SA, NULL }; -MY_LOCALE my_locale_ar_SA ( "ar_SA", "Arabic - Saudi Arabia", FALSE, &my_locale_typelib_month_names_ar_SA, &my_locale_typelib_ab_month_names_ar_SA, &my_locale_typelib_day_names_ar_SA, &my_locale_typelib_ab_day_names_ar_SA ); +MY_LOCALE my_locale_ar_SA +( + 9, + "ar_SA", + "Arabic - Saudi Arabia", + FALSE, + &my_locale_typelib_month_names_ar_SA, + &my_locale_typelib_ab_month_names_ar_SA, + &my_locale_typelib_day_names_ar_SA, + &my_locale_typelib_ab_day_names_ar_SA +); /***** LOCALE END ar_SA *****/ /***** LOCALE BEGIN ar_SY: Arabic - Syria *****/ @@ -132,7 +160,17 @@ static TYPELIB my_locale_typelib_day_names_ar_SY = { array_elements(my_locale_day_names_ar_SY)-1, "", my_locale_day_names_ar_SY, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ar_SY = { array_elements(my_locale_ab_day_names_ar_SY)-1, "", my_locale_ab_day_names_ar_SY, NULL }; -MY_LOCALE my_locale_ar_SY ( "ar_SY", "Arabic - Syria", FALSE, &my_locale_typelib_month_names_ar_SY, &my_locale_typelib_ab_month_names_ar_SY, &my_locale_typelib_day_names_ar_SY, &my_locale_typelib_ab_day_names_ar_SY ); +MY_LOCALE my_locale_ar_SY +( + 10, + "ar_SY", + "Arabic - Syria", + FALSE, + &my_locale_typelib_month_names_ar_SY, + &my_locale_typelib_ab_month_names_ar_SY, + &my_locale_typelib_day_names_ar_SY, + &my_locale_typelib_ab_day_names_ar_SY +); /***** LOCALE END ar_SY *****/ /***** LOCALE BEGIN be_BY: Belarusian - Belarus *****/ @@ -152,7 +190,17 @@ static TYPELIB my_locale_typelib_day_names_be_BY = { array_elements(my_locale_day_names_be_BY)-1, "", my_locale_day_names_be_BY, NULL }; static TYPELIB my_locale_typelib_ab_day_names_be_BY = { array_elements(my_locale_ab_day_names_be_BY)-1, "", my_locale_ab_day_names_be_BY, NULL }; -MY_LOCALE my_locale_be_BY ( "be_BY", "Belarusian - Belarus", FALSE, &my_locale_typelib_month_names_be_BY, &my_locale_typelib_ab_month_names_be_BY, &my_locale_typelib_day_names_be_BY, &my_locale_typelib_ab_day_names_be_BY ); +MY_LOCALE my_locale_be_BY +( + 11, + "be_BY", + "Belarusian - Belarus", + FALSE, + &my_locale_typelib_month_names_be_BY, + &my_locale_typelib_ab_month_names_be_BY, + &my_locale_typelib_day_names_be_BY, + &my_locale_typelib_ab_day_names_be_BY +); /***** LOCALE END be_BY *****/ /***** LOCALE BEGIN bg_BG: Bulgarian - Bulgaria *****/ @@ -172,7 +220,17 @@ static TYPELIB my_locale_typelib_day_names_bg_BG = { array_elements(my_locale_day_names_bg_BG)-1, "", my_locale_day_names_bg_BG, NULL }; static TYPELIB my_locale_typelib_ab_day_names_bg_BG = { array_elements(my_locale_ab_day_names_bg_BG)-1, "", my_locale_ab_day_names_bg_BG, NULL }; -MY_LOCALE my_locale_bg_BG ( "bg_BG", "Bulgarian - Bulgaria", FALSE, &my_locale_typelib_month_names_bg_BG, &my_locale_typelib_ab_month_names_bg_BG, &my_locale_typelib_day_names_bg_BG, &my_locale_typelib_ab_day_names_bg_BG ); +MY_LOCALE my_locale_bg_BG +( + 12, + "bg_BG", + "Bulgarian - Bulgaria", + FALSE, + &my_locale_typelib_month_names_bg_BG, + &my_locale_typelib_ab_month_names_bg_BG, + &my_locale_typelib_day_names_bg_BG, + &my_locale_typelib_ab_day_names_bg_BG +); /***** LOCALE END bg_BG *****/ /***** LOCALE BEGIN ca_ES: Catalan - Catalan *****/ @@ -192,7 +250,17 @@ static TYPELIB my_locale_typelib_day_names_ca_ES = { array_elements(my_locale_day_names_ca_ES)-1, "", my_locale_day_names_ca_ES, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ca_ES = { array_elements(my_locale_ab_day_names_ca_ES)-1, "", my_locale_ab_day_names_ca_ES, NULL }; -MY_LOCALE my_locale_ca_ES ( "ca_ES", "Catalan - Catalan", FALSE, &my_locale_typelib_month_names_ca_ES, &my_locale_typelib_ab_month_names_ca_ES, &my_locale_typelib_day_names_ca_ES, &my_locale_typelib_ab_day_names_ca_ES ); +MY_LOCALE my_locale_ca_ES +( + 13, + "ca_ES", + "Catalan - Catalan", + FALSE, + &my_locale_typelib_month_names_ca_ES, + &my_locale_typelib_ab_month_names_ca_ES, + &my_locale_typelib_day_names_ca_ES, + &my_locale_typelib_ab_day_names_ca_ES +); /***** LOCALE END ca_ES *****/ /***** LOCALE BEGIN cs_CZ: Czech - Czech Republic *****/ @@ -212,7 +280,17 @@ static TYPELIB my_locale_typelib_day_names_cs_CZ = { array_elements(my_locale_day_names_cs_CZ)-1, "", my_locale_day_names_cs_CZ, NULL }; static TYPELIB my_locale_typelib_ab_day_names_cs_CZ = { array_elements(my_locale_ab_day_names_cs_CZ)-1, "", my_locale_ab_day_names_cs_CZ, NULL }; -MY_LOCALE my_locale_cs_CZ ( "cs_CZ", "Czech - Czech Republic", FALSE, &my_locale_typelib_month_names_cs_CZ, &my_locale_typelib_ab_month_names_cs_CZ, &my_locale_typelib_day_names_cs_CZ, &my_locale_typelib_ab_day_names_cs_CZ ); +MY_LOCALE my_locale_cs_CZ +( + 14, + "cs_CZ", + "Czech - Czech Republic", + FALSE, + &my_locale_typelib_month_names_cs_CZ, + &my_locale_typelib_ab_month_names_cs_CZ, + &my_locale_typelib_day_names_cs_CZ, + &my_locale_typelib_ab_day_names_cs_CZ +); /***** LOCALE END cs_CZ *****/ /***** LOCALE BEGIN da_DK: Danish - Denmark *****/ @@ -232,7 +310,17 @@ static TYPELIB my_locale_typelib_day_names_da_DK = { array_elements(my_locale_day_names_da_DK)-1, "", my_locale_day_names_da_DK, NULL }; static TYPELIB my_locale_typelib_ab_day_names_da_DK = { array_elements(my_locale_ab_day_names_da_DK)-1, "", my_locale_ab_day_names_da_DK, NULL }; -MY_LOCALE my_locale_da_DK ( "da_DK", "Danish - Denmark", FALSE, &my_locale_typelib_month_names_da_DK, &my_locale_typelib_ab_month_names_da_DK, &my_locale_typelib_day_names_da_DK, &my_locale_typelib_ab_day_names_da_DK ); +MY_LOCALE my_locale_da_DK +( + 15, + "da_DK", + "Danish - Denmark", + FALSE, + &my_locale_typelib_month_names_da_DK, + &my_locale_typelib_ab_month_names_da_DK, + &my_locale_typelib_day_names_da_DK, + &my_locale_typelib_ab_day_names_da_DK +); /***** LOCALE END da_DK *****/ /***** LOCALE BEGIN de_AT: German - Austria *****/ @@ -252,7 +340,17 @@ static TYPELIB my_locale_typelib_day_names_de_AT = { array_elements(my_locale_day_names_de_AT)-1, "", my_locale_day_names_de_AT, NULL }; static TYPELIB my_locale_typelib_ab_day_names_de_AT = { array_elements(my_locale_ab_day_names_de_AT)-1, "", my_locale_ab_day_names_de_AT, NULL }; -MY_LOCALE my_locale_de_AT ( "de_AT", "German - Austria", FALSE, &my_locale_typelib_month_names_de_AT, &my_locale_typelib_ab_month_names_de_AT, &my_locale_typelib_day_names_de_AT, &my_locale_typelib_ab_day_names_de_AT ); +MY_LOCALE my_locale_de_AT +( + 16, + "de_AT", + "German - Austria", + FALSE, + &my_locale_typelib_month_names_de_AT, + &my_locale_typelib_ab_month_names_de_AT, + &my_locale_typelib_day_names_de_AT, + &my_locale_typelib_ab_day_names_de_AT +); /***** LOCALE END de_AT *****/ /***** LOCALE BEGIN de_DE: German - Germany *****/ @@ -272,7 +370,17 @@ static TYPELIB my_locale_typelib_day_names_de_DE = { array_elements(my_locale_day_names_de_DE)-1, "", my_locale_day_names_de_DE, NULL }; static TYPELIB my_locale_typelib_ab_day_names_de_DE = { array_elements(my_locale_ab_day_names_de_DE)-1, "", my_locale_ab_day_names_de_DE, NULL }; -MY_LOCALE my_locale_de_DE ( "de_DE", "German - Germany", FALSE, &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE ); +MY_LOCALE my_locale_de_DE +( + 4, + "de_DE", + "German - Germany", + FALSE, + &my_locale_typelib_month_names_de_DE, + &my_locale_typelib_ab_month_names_de_DE, + &my_locale_typelib_day_names_de_DE, + &my_locale_typelib_ab_day_names_de_DE +); /***** LOCALE END de_DE *****/ /***** LOCALE BEGIN en_US: English - United States *****/ @@ -292,7 +400,17 @@ static TYPELIB my_locale_typelib_day_names_en_US = { array_elements(my_locale_day_names_en_US)-1, "", my_locale_day_names_en_US, NULL }; static TYPELIB my_locale_typelib_ab_day_names_en_US = { array_elements(my_locale_ab_day_names_en_US)-1, "", my_locale_ab_day_names_en_US, NULL }; -MY_LOCALE my_locale_en_US ( "en_US", "English - United States", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_US +( + 0, + "en_US", + "English - United States", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_US *****/ /***** LOCALE BEGIN es_ES: Spanish - Spain *****/ @@ -312,7 +430,17 @@ static TYPELIB my_locale_typelib_day_names_es_ES = { array_elements(my_locale_day_names_es_ES)-1, "", my_locale_day_names_es_ES, NULL }; static TYPELIB my_locale_typelib_ab_day_names_es_ES = { array_elements(my_locale_ab_day_names_es_ES)-1, "", my_locale_ab_day_names_es_ES, NULL }; -MY_LOCALE my_locale_es_ES ( "es_ES", "Spanish - Spain", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_ES +( + 17, + "es_ES", + "Spanish - Spain", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_ES *****/ /***** LOCALE BEGIN et_EE: Estonian - Estonia *****/ @@ -332,7 +460,17 @@ static TYPELIB my_locale_typelib_day_names_et_EE = { array_elements(my_locale_day_names_et_EE)-1, "", my_locale_day_names_et_EE, NULL }; static TYPELIB my_locale_typelib_ab_day_names_et_EE = { array_elements(my_locale_ab_day_names_et_EE)-1, "", my_locale_ab_day_names_et_EE, NULL }; -MY_LOCALE my_locale_et_EE ( "et_EE", "Estonian - Estonia", FALSE, &my_locale_typelib_month_names_et_EE, &my_locale_typelib_ab_month_names_et_EE, &my_locale_typelib_day_names_et_EE, &my_locale_typelib_ab_day_names_et_EE ); +MY_LOCALE my_locale_et_EE +( + 18, + "et_EE", + "Estonian - Estonia", + FALSE, + &my_locale_typelib_month_names_et_EE, + &my_locale_typelib_ab_month_names_et_EE, + &my_locale_typelib_day_names_et_EE, + &my_locale_typelib_ab_day_names_et_EE +); /***** LOCALE END et_EE *****/ /***** LOCALE BEGIN eu_ES: Basque - Basque *****/ @@ -352,7 +490,17 @@ static TYPELIB my_locale_typelib_day_names_eu_ES = { array_elements(my_locale_day_names_eu_ES)-1, "", my_locale_day_names_eu_ES, NULL }; static TYPELIB my_locale_typelib_ab_day_names_eu_ES = { array_elements(my_locale_ab_day_names_eu_ES)-1, "", my_locale_ab_day_names_eu_ES, NULL }; -MY_LOCALE my_locale_eu_ES ( "eu_ES", "Basque - Basque", TRUE, &my_locale_typelib_month_names_eu_ES, &my_locale_typelib_ab_month_names_eu_ES, &my_locale_typelib_day_names_eu_ES, &my_locale_typelib_ab_day_names_eu_ES ); +MY_LOCALE my_locale_eu_ES +( + 19, + "eu_ES", + "Basque - Basque", + TRUE, + &my_locale_typelib_month_names_eu_ES, + &my_locale_typelib_ab_month_names_eu_ES, + &my_locale_typelib_day_names_eu_ES, + &my_locale_typelib_ab_day_names_eu_ES +); /***** LOCALE END eu_ES *****/ /***** LOCALE BEGIN fi_FI: Finnish - Finland *****/ @@ -372,7 +520,17 @@ static TYPELIB my_locale_typelib_day_names_fi_FI = { array_elements(my_locale_day_names_fi_FI)-1, "", my_locale_day_names_fi_FI, NULL }; static TYPELIB my_locale_typelib_ab_day_names_fi_FI = { array_elements(my_locale_ab_day_names_fi_FI)-1, "", my_locale_ab_day_names_fi_FI, NULL }; -MY_LOCALE my_locale_fi_FI ( "fi_FI", "Finnish - Finland", FALSE, &my_locale_typelib_month_names_fi_FI, &my_locale_typelib_ab_month_names_fi_FI, &my_locale_typelib_day_names_fi_FI, &my_locale_typelib_ab_day_names_fi_FI ); +MY_LOCALE my_locale_fi_FI +( + 20, + "fi_FI", + "Finnish - Finland", + FALSE, + &my_locale_typelib_month_names_fi_FI, + &my_locale_typelib_ab_month_names_fi_FI, + &my_locale_typelib_day_names_fi_FI, + &my_locale_typelib_ab_day_names_fi_FI +); /***** LOCALE END fi_FI *****/ /***** LOCALE BEGIN fo_FO: Faroese - Faroe Islands *****/ @@ -392,7 +550,17 @@ static TYPELIB my_locale_typelib_day_names_fo_FO = { array_elements(my_locale_day_names_fo_FO)-1, "", my_locale_day_names_fo_FO, NULL }; static TYPELIB my_locale_typelib_ab_day_names_fo_FO = { array_elements(my_locale_ab_day_names_fo_FO)-1, "", my_locale_ab_day_names_fo_FO, NULL }; -MY_LOCALE my_locale_fo_FO ( "fo_FO", "Faroese - Faroe Islands", FALSE, &my_locale_typelib_month_names_fo_FO, &my_locale_typelib_ab_month_names_fo_FO, &my_locale_typelib_day_names_fo_FO, &my_locale_typelib_ab_day_names_fo_FO ); +MY_LOCALE my_locale_fo_FO +( + 21, + "fo_FO", + "Faroese - Faroe Islands", + FALSE, + &my_locale_typelib_month_names_fo_FO, + &my_locale_typelib_ab_month_names_fo_FO, + &my_locale_typelib_day_names_fo_FO, + &my_locale_typelib_ab_day_names_fo_FO +); /***** LOCALE END fo_FO *****/ /***** LOCALE BEGIN fr_FR: French - France *****/ @@ -412,7 +580,17 @@ static TYPELIB my_locale_typelib_day_names_fr_FR = { array_elements(my_locale_day_names_fr_FR)-1, "", my_locale_day_names_fr_FR, NULL }; static TYPELIB my_locale_typelib_ab_day_names_fr_FR = { array_elements(my_locale_ab_day_names_fr_FR)-1, "", my_locale_ab_day_names_fr_FR, NULL }; -MY_LOCALE my_locale_fr_FR ( "fr_FR", "French - France", FALSE, &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR ); +MY_LOCALE my_locale_fr_FR +( + 5, + "fr_FR", + "French - France", + FALSE, + &my_locale_typelib_month_names_fr_FR, + &my_locale_typelib_ab_month_names_fr_FR, + &my_locale_typelib_day_names_fr_FR, + &my_locale_typelib_ab_day_names_fr_FR +); /***** LOCALE END fr_FR *****/ /***** LOCALE BEGIN gl_ES: Galician - Galician *****/ @@ -432,7 +610,17 @@ static TYPELIB my_locale_typelib_day_names_gl_ES = { array_elements(my_locale_day_names_gl_ES)-1, "", my_locale_day_names_gl_ES, NULL }; static TYPELIB my_locale_typelib_ab_day_names_gl_ES = { array_elements(my_locale_ab_day_names_gl_ES)-1, "", my_locale_ab_day_names_gl_ES, NULL }; -MY_LOCALE my_locale_gl_ES ( "gl_ES", "Galician - Galician", FALSE, &my_locale_typelib_month_names_gl_ES, &my_locale_typelib_ab_month_names_gl_ES, &my_locale_typelib_day_names_gl_ES, &my_locale_typelib_ab_day_names_gl_ES ); +MY_LOCALE my_locale_gl_ES +( + 22, + "gl_ES", + "Galician - Galician", + FALSE, + &my_locale_typelib_month_names_gl_ES, + &my_locale_typelib_ab_month_names_gl_ES, + &my_locale_typelib_day_names_gl_ES, + &my_locale_typelib_ab_day_names_gl_ES +); /***** LOCALE END gl_ES *****/ /***** LOCALE BEGIN gu_IN: Gujarati - India *****/ @@ -452,7 +640,17 @@ static TYPELIB my_locale_typelib_day_names_gu_IN = { array_elements(my_locale_day_names_gu_IN)-1, "", my_locale_day_names_gu_IN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_gu_IN = { array_elements(my_locale_ab_day_names_gu_IN)-1, "", my_locale_ab_day_names_gu_IN, NULL }; -MY_LOCALE my_locale_gu_IN ( "gu_IN", "Gujarati - India", FALSE, &my_locale_typelib_month_names_gu_IN, &my_locale_typelib_ab_month_names_gu_IN, &my_locale_typelib_day_names_gu_IN, &my_locale_typelib_ab_day_names_gu_IN ); +MY_LOCALE my_locale_gu_IN +( + 23, + "gu_IN", + "Gujarati - India", + FALSE, + &my_locale_typelib_month_names_gu_IN, + &my_locale_typelib_ab_month_names_gu_IN, + &my_locale_typelib_day_names_gu_IN, + &my_locale_typelib_ab_day_names_gu_IN +); /***** LOCALE END gu_IN *****/ /***** LOCALE BEGIN he_IL: Hebrew - Israel *****/ @@ -472,7 +670,17 @@ static TYPELIB my_locale_typelib_day_names_he_IL = { array_elements(my_locale_day_names_he_IL)-1, "", my_locale_day_names_he_IL, NULL }; static TYPELIB my_locale_typelib_ab_day_names_he_IL = { array_elements(my_locale_ab_day_names_he_IL)-1, "", my_locale_ab_day_names_he_IL, NULL }; -MY_LOCALE my_locale_he_IL ( "he_IL", "Hebrew - Israel", FALSE, &my_locale_typelib_month_names_he_IL, &my_locale_typelib_ab_month_names_he_IL, &my_locale_typelib_day_names_he_IL, &my_locale_typelib_ab_day_names_he_IL ); +MY_LOCALE my_locale_he_IL +( + 24, + "he_IL", + "Hebrew - Israel", + FALSE, + &my_locale_typelib_month_names_he_IL, + &my_locale_typelib_ab_month_names_he_IL, + &my_locale_typelib_day_names_he_IL, + &my_locale_typelib_ab_day_names_he_IL +); /***** LOCALE END he_IL *****/ /***** LOCALE BEGIN hi_IN: Hindi - India *****/ @@ -492,7 +700,17 @@ static TYPELIB my_locale_typelib_day_names_hi_IN = { array_elements(my_locale_day_names_hi_IN)-1, "", my_locale_day_names_hi_IN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_hi_IN = { array_elements(my_locale_ab_day_names_hi_IN)-1, "", my_locale_ab_day_names_hi_IN, NULL }; -MY_LOCALE my_locale_hi_IN ( "hi_IN", "Hindi - India", FALSE, &my_locale_typelib_month_names_hi_IN, &my_locale_typelib_ab_month_names_hi_IN, &my_locale_typelib_day_names_hi_IN, &my_locale_typelib_ab_day_names_hi_IN ); +MY_LOCALE my_locale_hi_IN +( + 25, + "hi_IN", + "Hindi - India", + FALSE, + &my_locale_typelib_month_names_hi_IN, + &my_locale_typelib_ab_month_names_hi_IN, + &my_locale_typelib_day_names_hi_IN, + &my_locale_typelib_ab_day_names_hi_IN +); /***** LOCALE END hi_IN *****/ /***** LOCALE BEGIN hr_HR: Croatian - Croatia *****/ @@ -512,7 +730,17 @@ static TYPELIB my_locale_typelib_day_names_hr_HR = { array_elements(my_locale_day_names_hr_HR)-1, "", my_locale_day_names_hr_HR, NULL }; static TYPELIB my_locale_typelib_ab_day_names_hr_HR = { array_elements(my_locale_ab_day_names_hr_HR)-1, "", my_locale_ab_day_names_hr_HR, NULL }; -MY_LOCALE my_locale_hr_HR ( "hr_HR", "Croatian - Croatia", FALSE, &my_locale_typelib_month_names_hr_HR, &my_locale_typelib_ab_month_names_hr_HR, &my_locale_typelib_day_names_hr_HR, &my_locale_typelib_ab_day_names_hr_HR ); +MY_LOCALE my_locale_hr_HR +( + 26, + "hr_HR", + "Croatian - Croatia", + FALSE, + &my_locale_typelib_month_names_hr_HR, + &my_locale_typelib_ab_month_names_hr_HR, + &my_locale_typelib_day_names_hr_HR, + &my_locale_typelib_ab_day_names_hr_HR +); /***** LOCALE END hr_HR *****/ /***** LOCALE BEGIN hu_HU: Hungarian - Hungary *****/ @@ -532,7 +760,17 @@ static TYPELIB my_locale_typelib_day_names_hu_HU = { array_elements(my_locale_day_names_hu_HU)-1, "", my_locale_day_names_hu_HU, NULL }; static TYPELIB my_locale_typelib_ab_day_names_hu_HU = { array_elements(my_locale_ab_day_names_hu_HU)-1, "", my_locale_ab_day_names_hu_HU, NULL }; -MY_LOCALE my_locale_hu_HU ( "hu_HU", "Hungarian - Hungary", FALSE, &my_locale_typelib_month_names_hu_HU, &my_locale_typelib_ab_month_names_hu_HU, &my_locale_typelib_day_names_hu_HU, &my_locale_typelib_ab_day_names_hu_HU ); +MY_LOCALE my_locale_hu_HU +( + 27, + "hu_HU", + "Hungarian - Hungary", + FALSE, + &my_locale_typelib_month_names_hu_HU, + &my_locale_typelib_ab_month_names_hu_HU, + &my_locale_typelib_day_names_hu_HU, + &my_locale_typelib_ab_day_names_hu_HU +); /***** LOCALE END hu_HU *****/ /***** LOCALE BEGIN id_ID: Indonesian - Indonesia *****/ @@ -552,7 +790,17 @@ static TYPELIB my_locale_typelib_day_names_id_ID = { array_elements(my_locale_day_names_id_ID)-1, "", my_locale_day_names_id_ID, NULL }; static TYPELIB my_locale_typelib_ab_day_names_id_ID = { array_elements(my_locale_ab_day_names_id_ID)-1, "", my_locale_ab_day_names_id_ID, NULL }; -MY_LOCALE my_locale_id_ID ( "id_ID", "Indonesian - Indonesia", TRUE, &my_locale_typelib_month_names_id_ID, &my_locale_typelib_ab_month_names_id_ID, &my_locale_typelib_day_names_id_ID, &my_locale_typelib_ab_day_names_id_ID ); +MY_LOCALE my_locale_id_ID +( + 28, + "id_ID", + "Indonesian - Indonesia", + TRUE, + &my_locale_typelib_month_names_id_ID, + &my_locale_typelib_ab_month_names_id_ID, + &my_locale_typelib_day_names_id_ID, + &my_locale_typelib_ab_day_names_id_ID +); /***** LOCALE END id_ID *****/ /***** LOCALE BEGIN is_IS: Icelandic - Iceland *****/ @@ -572,7 +820,17 @@ static TYPELIB my_locale_typelib_day_names_is_IS = { array_elements(my_locale_day_names_is_IS)-1, "", my_locale_day_names_is_IS, NULL }; static TYPELIB my_locale_typelib_ab_day_names_is_IS = { array_elements(my_locale_ab_day_names_is_IS)-1, "", my_locale_ab_day_names_is_IS, NULL }; -MY_LOCALE my_locale_is_IS ( "is_IS", "Icelandic - Iceland", FALSE, &my_locale_typelib_month_names_is_IS, &my_locale_typelib_ab_month_names_is_IS, &my_locale_typelib_day_names_is_IS, &my_locale_typelib_ab_day_names_is_IS ); +MY_LOCALE my_locale_is_IS +( + 29, + "is_IS", + "Icelandic - Iceland", + FALSE, + &my_locale_typelib_month_names_is_IS, + &my_locale_typelib_ab_month_names_is_IS, + &my_locale_typelib_day_names_is_IS, + &my_locale_typelib_ab_day_names_is_IS +); /***** LOCALE END is_IS *****/ /***** LOCALE BEGIN it_CH: Italian - Switzerland *****/ @@ -592,7 +850,17 @@ static TYPELIB my_locale_typelib_day_names_it_CH = { array_elements(my_locale_day_names_it_CH)-1, "", my_locale_day_names_it_CH, NULL }; static TYPELIB my_locale_typelib_ab_day_names_it_CH = { array_elements(my_locale_ab_day_names_it_CH)-1, "", my_locale_ab_day_names_it_CH, NULL }; -MY_LOCALE my_locale_it_CH ( "it_CH", "Italian - Switzerland", FALSE, &my_locale_typelib_month_names_it_CH, &my_locale_typelib_ab_month_names_it_CH, &my_locale_typelib_day_names_it_CH, &my_locale_typelib_ab_day_names_it_CH ); +MY_LOCALE my_locale_it_CH +( + 30, + "it_CH", + "Italian - Switzerland", + FALSE, + &my_locale_typelib_month_names_it_CH, + &my_locale_typelib_ab_month_names_it_CH, + &my_locale_typelib_day_names_it_CH, + &my_locale_typelib_ab_day_names_it_CH +); /***** LOCALE END it_CH *****/ /***** LOCALE BEGIN ja_JP: Japanese - Japan *****/ @@ -612,7 +880,17 @@ static TYPELIB my_locale_typelib_day_names_ja_JP = { array_elements(my_locale_day_names_ja_JP)-1, "", my_locale_day_names_ja_JP, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ja_JP = { array_elements(my_locale_ab_day_names_ja_JP)-1, "", my_locale_ab_day_names_ja_JP, NULL }; -MY_LOCALE my_locale_ja_JP ( "ja_JP", "Japanese - Japan", FALSE, &my_locale_typelib_month_names_ja_JP, &my_locale_typelib_ab_month_names_ja_JP, &my_locale_typelib_day_names_ja_JP, &my_locale_typelib_ab_day_names_ja_JP ); +MY_LOCALE my_locale_ja_JP +( + 2, + "ja_JP", + "Japanese - Japan", + FALSE, + &my_locale_typelib_month_names_ja_JP, + &my_locale_typelib_ab_month_names_ja_JP, + &my_locale_typelib_day_names_ja_JP, + &my_locale_typelib_ab_day_names_ja_JP +); /***** LOCALE END ja_JP *****/ /***** LOCALE BEGIN ko_KR: Korean - Korea *****/ @@ -632,7 +910,17 @@ static TYPELIB my_locale_typelib_day_names_ko_KR = { array_elements(my_locale_day_names_ko_KR)-1, "", my_locale_day_names_ko_KR, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ko_KR = { array_elements(my_locale_ab_day_names_ko_KR)-1, "", my_locale_ab_day_names_ko_KR, NULL }; -MY_LOCALE my_locale_ko_KR ( "ko_KR", "Korean - Korea", FALSE, &my_locale_typelib_month_names_ko_KR, &my_locale_typelib_ab_month_names_ko_KR, &my_locale_typelib_day_names_ko_KR, &my_locale_typelib_ab_day_names_ko_KR ); +MY_LOCALE my_locale_ko_KR +( + 31, + "ko_KR", + "Korean - Korea", + FALSE, + &my_locale_typelib_month_names_ko_KR, + &my_locale_typelib_ab_month_names_ko_KR, + &my_locale_typelib_day_names_ko_KR, + &my_locale_typelib_ab_day_names_ko_KR +); /***** LOCALE END ko_KR *****/ /***** LOCALE BEGIN lt_LT: Lithuanian - Lithuania *****/ @@ -652,7 +940,17 @@ static TYPELIB my_locale_typelib_day_names_lt_LT = { array_elements(my_locale_day_names_lt_LT)-1, "", my_locale_day_names_lt_LT, NULL }; static TYPELIB my_locale_typelib_ab_day_names_lt_LT = { array_elements(my_locale_ab_day_names_lt_LT)-1, "", my_locale_ab_day_names_lt_LT, NULL }; -MY_LOCALE my_locale_lt_LT ( "lt_LT", "Lithuanian - Lithuania", FALSE, &my_locale_typelib_month_names_lt_LT, &my_locale_typelib_ab_month_names_lt_LT, &my_locale_typelib_day_names_lt_LT, &my_locale_typelib_ab_day_names_lt_LT ); +MY_LOCALE my_locale_lt_LT +( + 32, + "lt_LT", + "Lithuanian - Lithuania", + FALSE, + &my_locale_typelib_month_names_lt_LT, + &my_locale_typelib_ab_month_names_lt_LT, + &my_locale_typelib_day_names_lt_LT, + &my_locale_typelib_ab_day_names_lt_LT +); /***** LOCALE END lt_LT *****/ /***** LOCALE BEGIN lv_LV: Latvian - Latvia *****/ @@ -672,7 +970,17 @@ static TYPELIB my_locale_typelib_day_names_lv_LV = { array_elements(my_locale_day_names_lv_LV)-1, "", my_locale_day_names_lv_LV, NULL }; static TYPELIB my_locale_typelib_ab_day_names_lv_LV = { array_elements(my_locale_ab_day_names_lv_LV)-1, "", my_locale_ab_day_names_lv_LV, NULL }; -MY_LOCALE my_locale_lv_LV ( "lv_LV", "Latvian - Latvia", FALSE, &my_locale_typelib_month_names_lv_LV, &my_locale_typelib_ab_month_names_lv_LV, &my_locale_typelib_day_names_lv_LV, &my_locale_typelib_ab_day_names_lv_LV ); +MY_LOCALE my_locale_lv_LV +( + 33, + "lv_LV", + "Latvian - Latvia", + FALSE, + &my_locale_typelib_month_names_lv_LV, + &my_locale_typelib_ab_month_names_lv_LV, + &my_locale_typelib_day_names_lv_LV, + &my_locale_typelib_ab_day_names_lv_LV +); /***** LOCALE END lv_LV *****/ /***** LOCALE BEGIN mk_MK: Macedonian - FYROM *****/ @@ -692,7 +1000,17 @@ static TYPELIB my_locale_typelib_day_names_mk_MK = { array_elements(my_locale_day_names_mk_MK)-1, "", my_locale_day_names_mk_MK, NULL }; static TYPELIB my_locale_typelib_ab_day_names_mk_MK = { array_elements(my_locale_ab_day_names_mk_MK)-1, "", my_locale_ab_day_names_mk_MK, NULL }; -MY_LOCALE my_locale_mk_MK ( "mk_MK", "Macedonian - FYROM", FALSE, &my_locale_typelib_month_names_mk_MK, &my_locale_typelib_ab_month_names_mk_MK, &my_locale_typelib_day_names_mk_MK, &my_locale_typelib_ab_day_names_mk_MK ); +MY_LOCALE my_locale_mk_MK +( + 34, + "mk_MK", + "Macedonian - FYROM", + FALSE, + &my_locale_typelib_month_names_mk_MK, + &my_locale_typelib_ab_month_names_mk_MK, + &my_locale_typelib_day_names_mk_MK, + &my_locale_typelib_ab_day_names_mk_MK +); /***** LOCALE END mk_MK *****/ /***** LOCALE BEGIN mn_MN: Mongolia - Mongolian *****/ @@ -712,7 +1030,17 @@ static TYPELIB my_locale_typelib_day_names_mn_MN = { array_elements(my_locale_day_names_mn_MN)-1, "", my_locale_day_names_mn_MN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_mn_MN = { array_elements(my_locale_ab_day_names_mn_MN)-1, "", my_locale_ab_day_names_mn_MN, NULL }; -MY_LOCALE my_locale_mn_MN ( "mn_MN", "Mongolia - Mongolian", FALSE, &my_locale_typelib_month_names_mn_MN, &my_locale_typelib_ab_month_names_mn_MN, &my_locale_typelib_day_names_mn_MN, &my_locale_typelib_ab_day_names_mn_MN ); +MY_LOCALE my_locale_mn_MN +( + 35, + "mn_MN", + "Mongolia - Mongolian", + FALSE, + &my_locale_typelib_month_names_mn_MN, + &my_locale_typelib_ab_month_names_mn_MN, + &my_locale_typelib_day_names_mn_MN, + &my_locale_typelib_ab_day_names_mn_MN +); /***** LOCALE END mn_MN *****/ /***** LOCALE BEGIN ms_MY: Malay - Malaysia *****/ @@ -732,7 +1060,17 @@ static TYPELIB my_locale_typelib_day_names_ms_MY = { array_elements(my_locale_day_names_ms_MY)-1, "", my_locale_day_names_ms_MY, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ms_MY = { array_elements(my_locale_ab_day_names_ms_MY)-1, "", my_locale_ab_day_names_ms_MY, NULL }; -MY_LOCALE my_locale_ms_MY ( "ms_MY", "Malay - Malaysia", TRUE, &my_locale_typelib_month_names_ms_MY, &my_locale_typelib_ab_month_names_ms_MY, &my_locale_typelib_day_names_ms_MY, &my_locale_typelib_ab_day_names_ms_MY ); +MY_LOCALE my_locale_ms_MY +( + 36, + "ms_MY", + "Malay - Malaysia", + TRUE, + &my_locale_typelib_month_names_ms_MY, + &my_locale_typelib_ab_month_names_ms_MY, + &my_locale_typelib_day_names_ms_MY, + &my_locale_typelib_ab_day_names_ms_MY +); /***** LOCALE END ms_MY *****/ /***** LOCALE BEGIN nb_NO: Norwegian(Bokml) - Norway *****/ @@ -752,7 +1090,17 @@ static TYPELIB my_locale_typelib_day_names_nb_NO = { array_elements(my_locale_day_names_nb_NO)-1, "", my_locale_day_names_nb_NO, NULL }; static TYPELIB my_locale_typelib_ab_day_names_nb_NO = { array_elements(my_locale_ab_day_names_nb_NO)-1, "", my_locale_ab_day_names_nb_NO, NULL }; -MY_LOCALE my_locale_nb_NO ( "nb_NO", "Norwegian(Bokml) - Norway", FALSE, &my_locale_typelib_month_names_nb_NO, &my_locale_typelib_ab_month_names_nb_NO, &my_locale_typelib_day_names_nb_NO, &my_locale_typelib_ab_day_names_nb_NO ); +MY_LOCALE my_locale_nb_NO +( + 37, + "nb_NO", + "Norwegian(Bokml) - Norway", + FALSE, + &my_locale_typelib_month_names_nb_NO, + &my_locale_typelib_ab_month_names_nb_NO, + &my_locale_typelib_day_names_nb_NO, + &my_locale_typelib_ab_day_names_nb_NO +); /***** LOCALE END nb_NO *****/ /***** LOCALE BEGIN nl_NL: Dutch - The Netherlands *****/ @@ -772,7 +1120,17 @@ static TYPELIB my_locale_typelib_day_names_nl_NL = { array_elements(my_locale_day_names_nl_NL)-1, "", my_locale_day_names_nl_NL, NULL }; static TYPELIB my_locale_typelib_ab_day_names_nl_NL = { array_elements(my_locale_ab_day_names_nl_NL)-1, "", my_locale_ab_day_names_nl_NL, NULL }; -MY_LOCALE my_locale_nl_NL ( "nl_NL", "Dutch - The Netherlands", TRUE, &my_locale_typelib_month_names_nl_NL, &my_locale_typelib_ab_month_names_nl_NL, &my_locale_typelib_day_names_nl_NL, &my_locale_typelib_ab_day_names_nl_NL ); +MY_LOCALE my_locale_nl_NL +( + 38, + "nl_NL", + "Dutch - The Netherlands", + TRUE, + &my_locale_typelib_month_names_nl_NL, + &my_locale_typelib_ab_month_names_nl_NL, + &my_locale_typelib_day_names_nl_NL, + &my_locale_typelib_ab_day_names_nl_NL +); /***** LOCALE END nl_NL *****/ /***** LOCALE BEGIN pl_PL: Polish - Poland *****/ @@ -792,7 +1150,17 @@ static TYPELIB my_locale_typelib_day_names_pl_PL = { array_elements(my_locale_day_names_pl_PL)-1, "", my_locale_day_names_pl_PL, NULL }; static TYPELIB my_locale_typelib_ab_day_names_pl_PL = { array_elements(my_locale_ab_day_names_pl_PL)-1, "", my_locale_ab_day_names_pl_PL, NULL }; -MY_LOCALE my_locale_pl_PL ( "pl_PL", "Polish - Poland", FALSE, &my_locale_typelib_month_names_pl_PL, &my_locale_typelib_ab_month_names_pl_PL, &my_locale_typelib_day_names_pl_PL, &my_locale_typelib_ab_day_names_pl_PL ); +MY_LOCALE my_locale_pl_PL +( + 39, + "pl_PL", + "Polish - Poland", + FALSE, + &my_locale_typelib_month_names_pl_PL, + &my_locale_typelib_ab_month_names_pl_PL, + &my_locale_typelib_day_names_pl_PL, + &my_locale_typelib_ab_day_names_pl_PL +); /***** LOCALE END pl_PL *****/ /***** LOCALE BEGIN pt_BR: Portugese - Brazil *****/ @@ -812,7 +1180,17 @@ static TYPELIB my_locale_typelib_day_names_pt_BR = { array_elements(my_locale_day_names_pt_BR)-1, "", my_locale_day_names_pt_BR, NULL }; static TYPELIB my_locale_typelib_ab_day_names_pt_BR = { array_elements(my_locale_ab_day_names_pt_BR)-1, "", my_locale_ab_day_names_pt_BR, NULL }; -MY_LOCALE my_locale_pt_BR ( "pt_BR", "Portugese - Brazil", FALSE, &my_locale_typelib_month_names_pt_BR, &my_locale_typelib_ab_month_names_pt_BR, &my_locale_typelib_day_names_pt_BR, &my_locale_typelib_ab_day_names_pt_BR ); +MY_LOCALE my_locale_pt_BR +( + 40, + "pt_BR", + "Portugese - Brazil", + FALSE, + &my_locale_typelib_month_names_pt_BR, + &my_locale_typelib_ab_month_names_pt_BR, + &my_locale_typelib_day_names_pt_BR, + &my_locale_typelib_ab_day_names_pt_BR +); /***** LOCALE END pt_BR *****/ /***** LOCALE BEGIN pt_PT: Portugese - Portugal *****/ @@ -832,7 +1210,17 @@ static TYPELIB my_locale_typelib_day_names_pt_PT = { array_elements(my_locale_day_names_pt_PT)-1, "", my_locale_day_names_pt_PT, NULL }; static TYPELIB my_locale_typelib_ab_day_names_pt_PT = { array_elements(my_locale_ab_day_names_pt_PT)-1, "", my_locale_ab_day_names_pt_PT, NULL }; -MY_LOCALE my_locale_pt_PT ( "pt_PT", "Portugese - Portugal", FALSE, &my_locale_typelib_month_names_pt_PT, &my_locale_typelib_ab_month_names_pt_PT, &my_locale_typelib_day_names_pt_PT, &my_locale_typelib_ab_day_names_pt_PT ); +MY_LOCALE my_locale_pt_PT +( + 41, + "pt_PT", + "Portugese - Portugal", + FALSE, + &my_locale_typelib_month_names_pt_PT, + &my_locale_typelib_ab_month_names_pt_PT, + &my_locale_typelib_day_names_pt_PT, + &my_locale_typelib_ab_day_names_pt_PT +); /***** LOCALE END pt_PT *****/ /***** LOCALE BEGIN ro_RO: Romanian - Romania *****/ @@ -852,7 +1240,17 @@ static TYPELIB my_locale_typelib_day_names_ro_RO = { array_elements(my_locale_day_names_ro_RO)-1, "", my_locale_day_names_ro_RO, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ro_RO = { array_elements(my_locale_ab_day_names_ro_RO)-1, "", my_locale_ab_day_names_ro_RO, NULL }; -MY_LOCALE my_locale_ro_RO ( "ro_RO", "Romanian - Romania", FALSE, &my_locale_typelib_month_names_ro_RO, &my_locale_typelib_ab_month_names_ro_RO, &my_locale_typelib_day_names_ro_RO, &my_locale_typelib_ab_day_names_ro_RO ); +MY_LOCALE my_locale_ro_RO +( + 42, + "ro_RO", + "Romanian - Romania", + FALSE, + &my_locale_typelib_month_names_ro_RO, + &my_locale_typelib_ab_month_names_ro_RO, + &my_locale_typelib_day_names_ro_RO, + &my_locale_typelib_ab_day_names_ro_RO +); /***** LOCALE END ro_RO *****/ /***** LOCALE BEGIN ru_RU: Russian - Russia *****/ @@ -872,7 +1270,17 @@ static TYPELIB my_locale_typelib_day_names_ru_RU = { array_elements(my_locale_day_names_ru_RU)-1, "", my_locale_day_names_ru_RU, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ru_RU = { array_elements(my_locale_ab_day_names_ru_RU)-1, "", my_locale_ab_day_names_ru_RU, NULL }; -MY_LOCALE my_locale_ru_RU ( "ru_RU", "Russian - Russia", FALSE, &my_locale_typelib_month_names_ru_RU, &my_locale_typelib_ab_month_names_ru_RU, &my_locale_typelib_day_names_ru_RU, &my_locale_typelib_ab_day_names_ru_RU ); +MY_LOCALE my_locale_ru_RU +( + 43, + "ru_RU", + "Russian - Russia", + FALSE, + &my_locale_typelib_month_names_ru_RU, + &my_locale_typelib_ab_month_names_ru_RU, + &my_locale_typelib_day_names_ru_RU, + &my_locale_typelib_ab_day_names_ru_RU +); /***** LOCALE END ru_RU *****/ /***** LOCALE BEGIN ru_UA: Russian - Ukraine *****/ @@ -892,7 +1300,17 @@ static TYPELIB my_locale_typelib_day_names_ru_UA = { array_elements(my_locale_day_names_ru_UA)-1, "", my_locale_day_names_ru_UA, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ru_UA = { array_elements(my_locale_ab_day_names_ru_UA)-1, "", my_locale_ab_day_names_ru_UA, NULL }; -MY_LOCALE my_locale_ru_UA ( "ru_UA", "Russian - Ukraine", FALSE, &my_locale_typelib_month_names_ru_UA, &my_locale_typelib_ab_month_names_ru_UA, &my_locale_typelib_day_names_ru_UA, &my_locale_typelib_ab_day_names_ru_UA ); +MY_LOCALE my_locale_ru_UA +( + 44, + "ru_UA", + "Russian - Ukraine", + FALSE, + &my_locale_typelib_month_names_ru_UA, + &my_locale_typelib_ab_month_names_ru_UA, + &my_locale_typelib_day_names_ru_UA, + &my_locale_typelib_ab_day_names_ru_UA +); /***** LOCALE END ru_UA *****/ /***** LOCALE BEGIN sk_SK: Slovak - Slovakia *****/ @@ -912,7 +1330,17 @@ static TYPELIB my_locale_typelib_day_names_sk_SK = { array_elements(my_locale_day_names_sk_SK)-1, "", my_locale_day_names_sk_SK, NULL }; static TYPELIB my_locale_typelib_ab_day_names_sk_SK = { array_elements(my_locale_ab_day_names_sk_SK)-1, "", my_locale_ab_day_names_sk_SK, NULL }; -MY_LOCALE my_locale_sk_SK ( "sk_SK", "Slovak - Slovakia", FALSE, &my_locale_typelib_month_names_sk_SK, &my_locale_typelib_ab_month_names_sk_SK, &my_locale_typelib_day_names_sk_SK, &my_locale_typelib_ab_day_names_sk_SK ); +MY_LOCALE my_locale_sk_SK +( + 45, + "sk_SK", + "Slovak - Slovakia", + FALSE, + &my_locale_typelib_month_names_sk_SK, + &my_locale_typelib_ab_month_names_sk_SK, + &my_locale_typelib_day_names_sk_SK, + &my_locale_typelib_ab_day_names_sk_SK +); /***** LOCALE END sk_SK *****/ /***** LOCALE BEGIN sl_SI: Slovenian - Slovenia *****/ @@ -932,7 +1360,17 @@ static TYPELIB my_locale_typelib_day_names_sl_SI = { array_elements(my_locale_day_names_sl_SI)-1, "", my_locale_day_names_sl_SI, NULL }; static TYPELIB my_locale_typelib_ab_day_names_sl_SI = { array_elements(my_locale_ab_day_names_sl_SI)-1, "", my_locale_ab_day_names_sl_SI, NULL }; -MY_LOCALE my_locale_sl_SI ( "sl_SI", "Slovenian - Slovenia", FALSE, &my_locale_typelib_month_names_sl_SI, &my_locale_typelib_ab_month_names_sl_SI, &my_locale_typelib_day_names_sl_SI, &my_locale_typelib_ab_day_names_sl_SI ); +MY_LOCALE my_locale_sl_SI +( + 46, + "sl_SI", + "Slovenian - Slovenia", + FALSE, + &my_locale_typelib_month_names_sl_SI, + &my_locale_typelib_ab_month_names_sl_SI, + &my_locale_typelib_day_names_sl_SI, + &my_locale_typelib_ab_day_names_sl_SI +); /***** LOCALE END sl_SI *****/ /***** LOCALE BEGIN sq_AL: Albanian - Albania *****/ @@ -952,7 +1390,17 @@ static TYPELIB my_locale_typelib_day_names_sq_AL = { array_elements(my_locale_day_names_sq_AL)-1, "", my_locale_day_names_sq_AL, NULL }; static TYPELIB my_locale_typelib_ab_day_names_sq_AL = { array_elements(my_locale_ab_day_names_sq_AL)-1, "", my_locale_ab_day_names_sq_AL, NULL }; -MY_LOCALE my_locale_sq_AL ( "sq_AL", "Albanian - Albania", FALSE, &my_locale_typelib_month_names_sq_AL, &my_locale_typelib_ab_month_names_sq_AL, &my_locale_typelib_day_names_sq_AL, &my_locale_typelib_ab_day_names_sq_AL ); +MY_LOCALE my_locale_sq_AL +( + 47, + "sq_AL", + "Albanian - Albania", + FALSE, + &my_locale_typelib_month_names_sq_AL, + &my_locale_typelib_ab_month_names_sq_AL, + &my_locale_typelib_day_names_sq_AL, + &my_locale_typelib_ab_day_names_sq_AL +); /***** LOCALE END sq_AL *****/ /***** LOCALE BEGIN sr_YU: Servian - Yugoslavia *****/ @@ -972,7 +1420,17 @@ static TYPELIB my_locale_typelib_day_names_sr_YU = { array_elements(my_locale_day_names_sr_YU)-1, "", my_locale_day_names_sr_YU, NULL }; static TYPELIB my_locale_typelib_ab_day_names_sr_YU = { array_elements(my_locale_ab_day_names_sr_YU)-1, "", my_locale_ab_day_names_sr_YU, NULL }; -MY_LOCALE my_locale_sr_YU ( "sr_YU", "Servian - Yugoslavia", FALSE, &my_locale_typelib_month_names_sr_YU, &my_locale_typelib_ab_month_names_sr_YU, &my_locale_typelib_day_names_sr_YU, &my_locale_typelib_ab_day_names_sr_YU ); +MY_LOCALE my_locale_sr_YU +( + 48, + "sr_YU", + "Servian - Yugoslavia", + FALSE, + &my_locale_typelib_month_names_sr_YU, + &my_locale_typelib_ab_month_names_sr_YU, + &my_locale_typelib_day_names_sr_YU, + &my_locale_typelib_ab_day_names_sr_YU +); /***** LOCALE END sr_YU *****/ /***** LOCALE BEGIN sv_SE: Swedish - Sweden *****/ @@ -992,7 +1450,17 @@ static TYPELIB my_locale_typelib_day_names_sv_SE = { array_elements(my_locale_day_names_sv_SE)-1, "", my_locale_day_names_sv_SE, NULL }; static TYPELIB my_locale_typelib_ab_day_names_sv_SE = { array_elements(my_locale_ab_day_names_sv_SE)-1, "", my_locale_ab_day_names_sv_SE, NULL }; -MY_LOCALE my_locale_sv_SE ( "sv_SE", "Swedish - Sweden", FALSE, &my_locale_typelib_month_names_sv_SE, &my_locale_typelib_ab_month_names_sv_SE, &my_locale_typelib_day_names_sv_SE, &my_locale_typelib_ab_day_names_sv_SE ); +MY_LOCALE my_locale_sv_SE +( + 3, + "sv_SE", + "Swedish - Sweden", + FALSE, + &my_locale_typelib_month_names_sv_SE, + &my_locale_typelib_ab_month_names_sv_SE, + &my_locale_typelib_day_names_sv_SE, + &my_locale_typelib_ab_day_names_sv_SE +); /***** LOCALE END sv_SE *****/ /***** LOCALE BEGIN ta_IN: Tamil - India *****/ @@ -1012,7 +1480,17 @@ static TYPELIB my_locale_typelib_day_names_ta_IN = { array_elements(my_locale_day_names_ta_IN)-1, "", my_locale_day_names_ta_IN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ta_IN = { array_elements(my_locale_ab_day_names_ta_IN)-1, "", my_locale_ab_day_names_ta_IN, NULL }; -MY_LOCALE my_locale_ta_IN ( "ta_IN", "Tamil - India", FALSE, &my_locale_typelib_month_names_ta_IN, &my_locale_typelib_ab_month_names_ta_IN, &my_locale_typelib_day_names_ta_IN, &my_locale_typelib_ab_day_names_ta_IN ); +MY_LOCALE my_locale_ta_IN +( + 49, + "ta_IN", + "Tamil - India", + FALSE, + &my_locale_typelib_month_names_ta_IN, + &my_locale_typelib_ab_month_names_ta_IN, + &my_locale_typelib_day_names_ta_IN, + &my_locale_typelib_ab_day_names_ta_IN +); /***** LOCALE END ta_IN *****/ /***** LOCALE BEGIN te_IN: Telugu - India *****/ @@ -1032,7 +1510,17 @@ static TYPELIB my_locale_typelib_day_names_te_IN = { array_elements(my_locale_day_names_te_IN)-1, "", my_locale_day_names_te_IN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_te_IN = { array_elements(my_locale_ab_day_names_te_IN)-1, "", my_locale_ab_day_names_te_IN, NULL }; -MY_LOCALE my_locale_te_IN ( "te_IN", "Telugu - India", FALSE, &my_locale_typelib_month_names_te_IN, &my_locale_typelib_ab_month_names_te_IN, &my_locale_typelib_day_names_te_IN, &my_locale_typelib_ab_day_names_te_IN ); +MY_LOCALE my_locale_te_IN +( + 50, + "te_IN", + "Telugu - India", + FALSE, + &my_locale_typelib_month_names_te_IN, + &my_locale_typelib_ab_month_names_te_IN, + &my_locale_typelib_day_names_te_IN, + &my_locale_typelib_ab_day_names_te_IN +); /***** LOCALE END te_IN *****/ /***** LOCALE BEGIN th_TH: Thai - Thailand *****/ @@ -1052,7 +1540,17 @@ static TYPELIB my_locale_typelib_day_names_th_TH = { array_elements(my_locale_day_names_th_TH)-1, "", my_locale_day_names_th_TH, NULL }; static TYPELIB my_locale_typelib_ab_day_names_th_TH = { array_elements(my_locale_ab_day_names_th_TH)-1, "", my_locale_ab_day_names_th_TH, NULL }; -MY_LOCALE my_locale_th_TH ( "th_TH", "Thai - Thailand", FALSE, &my_locale_typelib_month_names_th_TH, &my_locale_typelib_ab_month_names_th_TH, &my_locale_typelib_day_names_th_TH, &my_locale_typelib_ab_day_names_th_TH ); +MY_LOCALE my_locale_th_TH +( + 51, + "th_TH", + "Thai - Thailand", + FALSE, + &my_locale_typelib_month_names_th_TH, + &my_locale_typelib_ab_month_names_th_TH, + &my_locale_typelib_day_names_th_TH, + &my_locale_typelib_ab_day_names_th_TH +); /***** LOCALE END th_TH *****/ /***** LOCALE BEGIN tr_TR: Turkish - Turkey *****/ @@ -1072,7 +1570,17 @@ static TYPELIB my_locale_typelib_day_names_tr_TR = { array_elements(my_locale_day_names_tr_TR)-1, "", my_locale_day_names_tr_TR, NULL }; static TYPELIB my_locale_typelib_ab_day_names_tr_TR = { array_elements(my_locale_ab_day_names_tr_TR)-1, "", my_locale_ab_day_names_tr_TR, NULL }; -MY_LOCALE my_locale_tr_TR ( "tr_TR", "Turkish - Turkey", FALSE, &my_locale_typelib_month_names_tr_TR, &my_locale_typelib_ab_month_names_tr_TR, &my_locale_typelib_day_names_tr_TR, &my_locale_typelib_ab_day_names_tr_TR ); +MY_LOCALE my_locale_tr_TR +( + 52, + "tr_TR", + "Turkish - Turkey", + FALSE, + &my_locale_typelib_month_names_tr_TR, + &my_locale_typelib_ab_month_names_tr_TR, + &my_locale_typelib_day_names_tr_TR, + &my_locale_typelib_ab_day_names_tr_TR +); /***** LOCALE END tr_TR *****/ /***** LOCALE BEGIN uk_UA: Ukrainian - Ukraine *****/ @@ -1092,7 +1600,17 @@ static TYPELIB my_locale_typelib_day_names_uk_UA = { array_elements(my_locale_day_names_uk_UA)-1, "", my_locale_day_names_uk_UA, NULL }; static TYPELIB my_locale_typelib_ab_day_names_uk_UA = { array_elements(my_locale_ab_day_names_uk_UA)-1, "", my_locale_ab_day_names_uk_UA, NULL }; -MY_LOCALE my_locale_uk_UA ( "uk_UA", "Ukrainian - Ukraine", FALSE, &my_locale_typelib_month_names_uk_UA, &my_locale_typelib_ab_month_names_uk_UA, &my_locale_typelib_day_names_uk_UA, &my_locale_typelib_ab_day_names_uk_UA ); +MY_LOCALE my_locale_uk_UA +( + 53, + "uk_UA", + "Ukrainian - Ukraine", + FALSE, + &my_locale_typelib_month_names_uk_UA, + &my_locale_typelib_ab_month_names_uk_UA, + &my_locale_typelib_day_names_uk_UA, + &my_locale_typelib_ab_day_names_uk_UA +); /***** LOCALE END uk_UA *****/ /***** LOCALE BEGIN ur_PK: Urdu - Pakistan *****/ @@ -1112,7 +1630,17 @@ static TYPELIB my_locale_typelib_day_names_ur_PK = { array_elements(my_locale_day_names_ur_PK)-1, "", my_locale_day_names_ur_PK, NULL }; static TYPELIB my_locale_typelib_ab_day_names_ur_PK = { array_elements(my_locale_ab_day_names_ur_PK)-1, "", my_locale_ab_day_names_ur_PK, NULL }; -MY_LOCALE my_locale_ur_PK ( "ur_PK", "Urdu - Pakistan", FALSE, &my_locale_typelib_month_names_ur_PK, &my_locale_typelib_ab_month_names_ur_PK, &my_locale_typelib_day_names_ur_PK, &my_locale_typelib_ab_day_names_ur_PK ); +MY_LOCALE my_locale_ur_PK +( + 54, + "ur_PK", + "Urdu - Pakistan", + FALSE, + &my_locale_typelib_month_names_ur_PK, + &my_locale_typelib_ab_month_names_ur_PK, + &my_locale_typelib_day_names_ur_PK, + &my_locale_typelib_ab_day_names_ur_PK +); /***** LOCALE END ur_PK *****/ /***** LOCALE BEGIN vi_VN: Vietnamese - Vietnam *****/ @@ -1132,7 +1660,17 @@ static TYPELIB my_locale_typelib_day_names_vi_VN = { array_elements(my_locale_day_names_vi_VN)-1, "", my_locale_day_names_vi_VN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_vi_VN = { array_elements(my_locale_ab_day_names_vi_VN)-1, "", my_locale_ab_day_names_vi_VN, NULL }; -MY_LOCALE my_locale_vi_VN ( "vi_VN", "Vietnamese - Vietnam", FALSE, &my_locale_typelib_month_names_vi_VN, &my_locale_typelib_ab_month_names_vi_VN, &my_locale_typelib_day_names_vi_VN, &my_locale_typelib_ab_day_names_vi_VN ); +MY_LOCALE my_locale_vi_VN +( + 55, + "vi_VN", + "Vietnamese - Vietnam", + FALSE, + &my_locale_typelib_month_names_vi_VN, + &my_locale_typelib_ab_month_names_vi_VN, + &my_locale_typelib_day_names_vi_VN, + &my_locale_typelib_ab_day_names_vi_VN +); /***** LOCALE END vi_VN *****/ /***** LOCALE BEGIN zh_CN: Chinese - Peoples Republic of China *****/ @@ -1152,7 +1690,17 @@ static TYPELIB my_locale_typelib_day_names_zh_CN = { array_elements(my_locale_day_names_zh_CN)-1, "", my_locale_day_names_zh_CN, NULL }; static TYPELIB my_locale_typelib_ab_day_names_zh_CN = { array_elements(my_locale_ab_day_names_zh_CN)-1, "", my_locale_ab_day_names_zh_CN, NULL }; -MY_LOCALE my_locale_zh_CN ( "zh_CN", "Chinese - Peoples Republic of China", FALSE, &my_locale_typelib_month_names_zh_CN, &my_locale_typelib_ab_month_names_zh_CN, &my_locale_typelib_day_names_zh_CN, &my_locale_typelib_ab_day_names_zh_CN ); +MY_LOCALE my_locale_zh_CN +( + 56, + "zh_CN", + "Chinese - Peoples Republic of China", + FALSE, + &my_locale_typelib_month_names_zh_CN, + &my_locale_typelib_ab_month_names_zh_CN, + &my_locale_typelib_day_names_zh_CN, + &my_locale_typelib_ab_day_names_zh_CN +); /***** LOCALE END zh_CN *****/ /***** LOCALE BEGIN zh_TW: Chinese - Taiwan *****/ @@ -1172,217 +1720,754 @@ static TYPELIB my_locale_typelib_day_names_zh_TW = { array_elements(my_locale_day_names_zh_TW)-1, "", my_locale_day_names_zh_TW, NULL }; static TYPELIB my_locale_typelib_ab_day_names_zh_TW = { array_elements(my_locale_ab_day_names_zh_TW)-1, "", my_locale_ab_day_names_zh_TW, NULL }; -MY_LOCALE my_locale_zh_TW ( "zh_TW", "Chinese - Taiwan", FALSE, &my_locale_typelib_month_names_zh_TW, &my_locale_typelib_ab_month_names_zh_TW, &my_locale_typelib_day_names_zh_TW, &my_locale_typelib_ab_day_names_zh_TW ); +MY_LOCALE my_locale_zh_TW +( + 57, + "zh_TW", + "Chinese - Taiwan", + FALSE, + &my_locale_typelib_month_names_zh_TW, + &my_locale_typelib_ab_month_names_zh_TW, + &my_locale_typelib_day_names_zh_TW, + &my_locale_typelib_ab_day_names_zh_TW +); /***** LOCALE END zh_TW *****/ /***** LOCALE BEGIN ar_DZ: Arabic - Algeria *****/ -MY_LOCALE my_locale_ar_DZ ( "ar_DZ", "Arabic - Algeria", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_DZ +( + 58, + "ar_DZ", + "Arabic - Algeria", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_DZ *****/ /***** LOCALE BEGIN ar_EG: Arabic - Egypt *****/ -MY_LOCALE my_locale_ar_EG ( "ar_EG", "Arabic - Egypt", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_EG +( + 59, + "ar_EG", + "Arabic - Egypt", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_EG *****/ /***** LOCALE BEGIN ar_IN: Arabic - Iran *****/ -MY_LOCALE my_locale_ar_IN ( "ar_IN", "Arabic - Iran", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_IN +( + 60, + "ar_IN", + "Arabic - Iran", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_IN *****/ /***** LOCALE BEGIN ar_IQ: Arabic - Iraq *****/ -MY_LOCALE my_locale_ar_IQ ( "ar_IQ", "Arabic - Iraq", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_IQ +( + 61, + "ar_IQ", + "Arabic - Iraq", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_IQ *****/ /***** LOCALE BEGIN ar_KW: Arabic - Kuwait *****/ -MY_LOCALE my_locale_ar_KW ( "ar_KW", "Arabic - Kuwait", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_KW +( + 62, + "ar_KW", + "Arabic - Kuwait", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_KW *****/ /***** LOCALE BEGIN ar_LB: Arabic - Lebanon *****/ -MY_LOCALE my_locale_ar_LB ( "ar_LB", "Arabic - Lebanon", FALSE, &my_locale_typelib_month_names_ar_JO, &my_locale_typelib_ab_month_names_ar_JO, &my_locale_typelib_day_names_ar_JO, &my_locale_typelib_ab_day_names_ar_JO ); +MY_LOCALE my_locale_ar_LB +( + 63, + "ar_LB", + "Arabic - Lebanon", + FALSE, + &my_locale_typelib_month_names_ar_JO, + &my_locale_typelib_ab_month_names_ar_JO, + &my_locale_typelib_day_names_ar_JO, + &my_locale_typelib_ab_day_names_ar_JO +); /***** LOCALE END ar_LB *****/ /***** LOCALE BEGIN ar_LY: Arabic - Libya *****/ -MY_LOCALE my_locale_ar_LY ( "ar_LY", "Arabic - Libya", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_LY +( + 64, + "ar_LY", + "Arabic - Libya", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_LY *****/ /***** LOCALE BEGIN ar_MA: Arabic - Morocco *****/ -MY_LOCALE my_locale_ar_MA ( "ar_MA", "Arabic - Morocco", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_MA +( + 65, + "ar_MA", + "Arabic - Morocco", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_MA *****/ /***** LOCALE BEGIN ar_OM: Arabic - Oman *****/ -MY_LOCALE my_locale_ar_OM ( "ar_OM", "Arabic - Oman", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_OM +( + 66, + "ar_OM", + "Arabic - Oman", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_OM *****/ /***** LOCALE BEGIN ar_QA: Arabic - Qatar *****/ -MY_LOCALE my_locale_ar_QA ( "ar_QA", "Arabic - Qatar", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_QA +( + 67, + "ar_QA", + "Arabic - Qatar", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_QA *****/ /***** LOCALE BEGIN ar_SD: Arabic - Sudan *****/ -MY_LOCALE my_locale_ar_SD ( "ar_SD", "Arabic - Sudan", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_SD +( + 68, + "ar_SD", + "Arabic - Sudan", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_SD *****/ /***** LOCALE BEGIN ar_TN: Arabic - Tunisia *****/ -MY_LOCALE my_locale_ar_TN ( "ar_TN", "Arabic - Tunisia", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_TN +( + 69, + "ar_TN", + "Arabic - Tunisia", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_TN *****/ /***** LOCALE BEGIN ar_YE: Arabic - Yemen *****/ -MY_LOCALE my_locale_ar_YE ( "ar_YE", "Arabic - Yemen", FALSE, &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH ); +MY_LOCALE my_locale_ar_YE +( + 70, + "ar_YE", + "Arabic - Yemen", + FALSE, + &my_locale_typelib_month_names_ar_BH, + &my_locale_typelib_ab_month_names_ar_BH, + &my_locale_typelib_day_names_ar_BH, + &my_locale_typelib_ab_day_names_ar_BH +); /***** LOCALE END ar_YE *****/ /***** LOCALE BEGIN de_BE: German - Belgium *****/ -MY_LOCALE my_locale_de_BE ( "de_BE", "German - Belgium", FALSE, &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE ); +MY_LOCALE my_locale_de_BE +( + 71, + "de_BE", + "German - Belgium", + FALSE, + &my_locale_typelib_month_names_de_DE, + &my_locale_typelib_ab_month_names_de_DE, + &my_locale_typelib_day_names_de_DE, + &my_locale_typelib_ab_day_names_de_DE +); /***** LOCALE END de_BE *****/ /***** LOCALE BEGIN de_CH: German - Switzerland *****/ -MY_LOCALE my_locale_de_CH ( "de_CH", "German - Switzerland", FALSE, &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE ); +MY_LOCALE my_locale_de_CH +( + 72, + "de_CH", + "German - Switzerland", + FALSE, + &my_locale_typelib_month_names_de_DE, + &my_locale_typelib_ab_month_names_de_DE, + &my_locale_typelib_day_names_de_DE, + &my_locale_typelib_ab_day_names_de_DE +); /***** LOCALE END de_CH *****/ /***** LOCALE BEGIN de_LU: German - Luxembourg *****/ -MY_LOCALE my_locale_de_LU ( "de_LU", "German - Luxembourg", FALSE, &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE ); +MY_LOCALE my_locale_de_LU +( + 73, + "de_LU", + "German - Luxembourg", + FALSE, + &my_locale_typelib_month_names_de_DE, + &my_locale_typelib_ab_month_names_de_DE, + &my_locale_typelib_day_names_de_DE, + &my_locale_typelib_ab_day_names_de_DE +); /***** LOCALE END de_LU *****/ /***** LOCALE BEGIN en_AU: English - Australia *****/ -MY_LOCALE my_locale_en_AU ( "en_AU", "English - Australia", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_AU +( + 74, + "en_AU", + "English - Australia", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_AU *****/ /***** LOCALE BEGIN en_CA: English - Canada *****/ -MY_LOCALE my_locale_en_CA ( "en_CA", "English - Canada", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_CA +( + 75, + "en_CA", + "English - Canada", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_CA *****/ /***** LOCALE BEGIN en_GB: English - United Kingdom *****/ -MY_LOCALE my_locale_en_GB ( "en_GB", "English - United Kingdom", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_GB +( + 1, + "en_GB", + "English - United Kingdom", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_GB *****/ /***** LOCALE BEGIN en_IN: English - India *****/ -MY_LOCALE my_locale_en_IN ( "en_IN", "English - India", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_IN +( + 76, + "en_IN", + "English - India", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_IN *****/ /***** LOCALE BEGIN en_NZ: English - New Zealand *****/ -MY_LOCALE my_locale_en_NZ ( "en_NZ", "English - New Zealand", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_NZ +( + 77, + "en_NZ", + "English - New Zealand", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_NZ *****/ /***** LOCALE BEGIN en_PH: English - Philippines *****/ -MY_LOCALE my_locale_en_PH ( "en_PH", "English - Philippines", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_PH +( + 78, + "en_PH", + "English - Philippines", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_PH *****/ /***** LOCALE BEGIN en_ZA: English - South Africa *****/ -MY_LOCALE my_locale_en_ZA ( "en_ZA", "English - South Africa", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_ZA +( + 79, + "en_ZA", + "English - South Africa", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_ZA *****/ /***** LOCALE BEGIN en_ZW: English - Zimbabwe *****/ -MY_LOCALE my_locale_en_ZW ( "en_ZW", "English - Zimbabwe", TRUE, &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US ); +MY_LOCALE my_locale_en_ZW +( + 80, + "en_ZW", + "English - Zimbabwe", + TRUE, + &my_locale_typelib_month_names_en_US, + &my_locale_typelib_ab_month_names_en_US, + &my_locale_typelib_day_names_en_US, + &my_locale_typelib_ab_day_names_en_US +); /***** LOCALE END en_ZW *****/ /***** LOCALE BEGIN es_AR: Spanish - Argentina *****/ -MY_LOCALE my_locale_es_AR ( "es_AR", "Spanish - Argentina", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_AR +( + 81, + "es_AR", + "Spanish - Argentina", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_AR *****/ /***** LOCALE BEGIN es_BO: Spanish - Bolivia *****/ -MY_LOCALE my_locale_es_BO ( "es_BO", "Spanish - Bolivia", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_BO +( + 82, + "es_BO", + "Spanish - Bolivia", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_BO *****/ /***** LOCALE BEGIN es_CL: Spanish - Chile *****/ -MY_LOCALE my_locale_es_CL ( "es_CL", "Spanish - Chile", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_CL +( + 83, + "es_CL", + "Spanish - Chile", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_CL *****/ /***** LOCALE BEGIN es_CO: Spanish - Columbia *****/ -MY_LOCALE my_locale_es_CO ( "es_CO", "Spanish - Columbia", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_CO +( + 84, + "es_CO", + "Spanish - Columbia", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_CO *****/ /***** LOCALE BEGIN es_CR: Spanish - Costa Rica *****/ -MY_LOCALE my_locale_es_CR ( "es_CR", "Spanish - Costa Rica", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_CR +( + 85, + "es_CR", + "Spanish - Costa Rica", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_CR *****/ /***** LOCALE BEGIN es_DO: Spanish - Dominican Republic *****/ -MY_LOCALE my_locale_es_DO ( "es_DO", "Spanish - Dominican Republic", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_DO +( + 86, + "es_DO", + "Spanish - Dominican Republic", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_DO *****/ /***** LOCALE BEGIN es_EC: Spanish - Ecuador *****/ -MY_LOCALE my_locale_es_EC ( "es_EC", "Spanish - Ecuador", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_EC +( + 87, + "es_EC", + "Spanish - Ecuador", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_EC *****/ /***** LOCALE BEGIN es_GT: Spanish - Guatemala *****/ -MY_LOCALE my_locale_es_GT ( "es_GT", "Spanish - Guatemala", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_GT +( + 88, + "es_GT", + "Spanish - Guatemala", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_GT *****/ /***** LOCALE BEGIN es_HN: Spanish - Honduras *****/ -MY_LOCALE my_locale_es_HN ( "es_HN", "Spanish - Honduras", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_HN +( + 89, + "es_HN", + "Spanish - Honduras", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_HN *****/ /***** LOCALE BEGIN es_MX: Spanish - Mexico *****/ -MY_LOCALE my_locale_es_MX ( "es_MX", "Spanish - Mexico", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_MX +( + 90, + "es_MX", + "Spanish - Mexico", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_MX *****/ /***** LOCALE BEGIN es_NI: Spanish - Nicaragua *****/ -MY_LOCALE my_locale_es_NI ( "es_NI", "Spanish - Nicaragua", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_NI +( + 91, + "es_NI", + "Spanish - Nicaragua", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_NI *****/ /***** LOCALE BEGIN es_PA: Spanish - Panama *****/ -MY_LOCALE my_locale_es_PA ( "es_PA", "Spanish - Panama", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_PA +( + 92, + "es_PA", + "Spanish - Panama", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_PA *****/ /***** LOCALE BEGIN es_PE: Spanish - Peru *****/ -MY_LOCALE my_locale_es_PE ( "es_PE", "Spanish - Peru", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_PE +( + 93, + "es_PE", + "Spanish - Peru", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_PE *****/ /***** LOCALE BEGIN es_PR: Spanish - Puerto Rico *****/ -MY_LOCALE my_locale_es_PR ( "es_PR", "Spanish - Puerto Rico", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_PR +( + 94, + "es_PR", + "Spanish - Puerto Rico", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_PR *****/ /***** LOCALE BEGIN es_PY: Spanish - Paraguay *****/ -MY_LOCALE my_locale_es_PY ( "es_PY", "Spanish - Paraguay", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_PY +( + 95, + "es_PY", + "Spanish - Paraguay", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_PY *****/ /***** LOCALE BEGIN es_SV: Spanish - El Salvador *****/ -MY_LOCALE my_locale_es_SV ( "es_SV", "Spanish - El Salvador", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_SV +( + 96, + "es_SV", + "Spanish - El Salvador", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_SV *****/ /***** LOCALE BEGIN es_US: Spanish - United States *****/ -MY_LOCALE my_locale_es_US ( "es_US", "Spanish - United States", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_US +( + 97, + "es_US", + "Spanish - United States", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_US *****/ /***** LOCALE BEGIN es_UY: Spanish - Uruguay *****/ -MY_LOCALE my_locale_es_UY ( "es_UY", "Spanish - Uruguay", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_UY +( + 98, + "es_UY", + "Spanish - Uruguay", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_UY *****/ /***** LOCALE BEGIN es_VE: Spanish - Venezuela *****/ -MY_LOCALE my_locale_es_VE ( "es_VE", "Spanish - Venezuela", FALSE, &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES ); +MY_LOCALE my_locale_es_VE +( + 99, + "es_VE", + "Spanish - Venezuela", + FALSE, + &my_locale_typelib_month_names_es_ES, + &my_locale_typelib_ab_month_names_es_ES, + &my_locale_typelib_day_names_es_ES, + &my_locale_typelib_ab_day_names_es_ES +); /***** LOCALE END es_VE *****/ /***** LOCALE BEGIN fr_BE: French - Belgium *****/ -MY_LOCALE my_locale_fr_BE ( "fr_BE", "French - Belgium", FALSE, &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR ); +MY_LOCALE my_locale_fr_BE +( + 100, + "fr_BE", + "French - Belgium", + FALSE, + &my_locale_typelib_month_names_fr_FR, + &my_locale_typelib_ab_month_names_fr_FR, + &my_locale_typelib_day_names_fr_FR, + &my_locale_typelib_ab_day_names_fr_FR +); /***** LOCALE END fr_BE *****/ /***** LOCALE BEGIN fr_CA: French - Canada *****/ -MY_LOCALE my_locale_fr_CA ( "fr_CA", "French - Canada", FALSE, &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR ); +MY_LOCALE my_locale_fr_CA +( + 101, + "fr_CA", + "French - Canada", + FALSE, + &my_locale_typelib_month_names_fr_FR, + &my_locale_typelib_ab_month_names_fr_FR, + &my_locale_typelib_day_names_fr_FR, + &my_locale_typelib_ab_day_names_fr_FR +); /***** LOCALE END fr_CA *****/ /***** LOCALE BEGIN fr_CH: French - Switzerland *****/ -MY_LOCALE my_locale_fr_CH ( "fr_CH", "French - Switzerland", FALSE, &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR ); +MY_LOCALE my_locale_fr_CH +( + 102, + "fr_CH", + "French - Switzerland", + FALSE, + &my_locale_typelib_month_names_fr_FR, + &my_locale_typelib_ab_month_names_fr_FR, + &my_locale_typelib_day_names_fr_FR, + &my_locale_typelib_ab_day_names_fr_FR +); /***** LOCALE END fr_CH *****/ /***** LOCALE BEGIN fr_LU: French - Luxembourg *****/ -MY_LOCALE my_locale_fr_LU ( "fr_LU", "French - Luxembourg", FALSE, &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR ); +MY_LOCALE my_locale_fr_LU +( + 103, + "fr_LU", + "French - Luxembourg", + FALSE, + &my_locale_typelib_month_names_fr_FR, + &my_locale_typelib_ab_month_names_fr_FR, + &my_locale_typelib_day_names_fr_FR, + &my_locale_typelib_ab_day_names_fr_FR +); /***** LOCALE END fr_LU *****/ /***** LOCALE BEGIN it_IT: Italian - Italy *****/ -MY_LOCALE my_locale_it_IT ( "it_IT", "Italian - Italy", FALSE, &my_locale_typelib_month_names_it_CH, &my_locale_typelib_ab_month_names_it_CH, &my_locale_typelib_day_names_it_CH, &my_locale_typelib_ab_day_names_it_CH ); +MY_LOCALE my_locale_it_IT +( + 104, + "it_IT", + "Italian - Italy", + FALSE, + &my_locale_typelib_month_names_it_CH, + &my_locale_typelib_ab_month_names_it_CH, + &my_locale_typelib_day_names_it_CH, + &my_locale_typelib_ab_day_names_it_CH +); /***** LOCALE END it_IT *****/ /***** LOCALE BEGIN nl_BE: Dutch - Belgium *****/ -MY_LOCALE my_locale_nl_BE ( "nl_BE", "Dutch - Belgium", TRUE, &my_locale_typelib_month_names_nl_NL, &my_locale_typelib_ab_month_names_nl_NL, &my_locale_typelib_day_names_nl_NL, &my_locale_typelib_ab_day_names_nl_NL ); +MY_LOCALE my_locale_nl_BE +( + 105, + "nl_BE", + "Dutch - Belgium", + TRUE, + &my_locale_typelib_month_names_nl_NL, + &my_locale_typelib_ab_month_names_nl_NL, + &my_locale_typelib_day_names_nl_NL, + &my_locale_typelib_ab_day_names_nl_NL +); /***** LOCALE END nl_BE *****/ /***** LOCALE BEGIN no_NO: Norwegian - Norway *****/ -MY_LOCALE my_locale_no_NO ( "no_NO", "Norwegian - Norway", FALSE, &my_locale_typelib_month_names_nb_NO, &my_locale_typelib_ab_month_names_nb_NO, &my_locale_typelib_day_names_nb_NO, &my_locale_typelib_ab_day_names_nb_NO ); +MY_LOCALE my_locale_no_NO +( + 106, + "no_NO", + "Norwegian - Norway", + FALSE, + &my_locale_typelib_month_names_nb_NO, + &my_locale_typelib_ab_month_names_nb_NO, + &my_locale_typelib_day_names_nb_NO, + &my_locale_typelib_ab_day_names_nb_NO +); /***** LOCALE END no_NO *****/ /***** LOCALE BEGIN sv_FI: Swedish - Finland *****/ -MY_LOCALE my_locale_sv_FI ( "sv_FI", "Swedish - Finland", FALSE, &my_locale_typelib_month_names_sv_SE, &my_locale_typelib_ab_month_names_sv_SE, &my_locale_typelib_day_names_sv_SE, &my_locale_typelib_ab_day_names_sv_SE ); +MY_LOCALE my_locale_sv_FI +( + 107, + "sv_FI", + "Swedish - Finland", + FALSE, + &my_locale_typelib_month_names_sv_SE, + &my_locale_typelib_ab_month_names_sv_SE, + &my_locale_typelib_day_names_sv_SE, + &my_locale_typelib_ab_day_names_sv_SE +); /***** LOCALE END sv_FI *****/ /***** LOCALE BEGIN zh_HK: Chinese - Hong Kong SAR *****/ -MY_LOCALE my_locale_zh_HK ( "zh_HK", "Chinese - Hong Kong SAR", FALSE, &my_locale_typelib_month_names_zh_CN, &my_locale_typelib_ab_month_names_zh_CN, &my_locale_typelib_day_names_zh_CN, &my_locale_typelib_ab_day_names_zh_CN ); +MY_LOCALE my_locale_zh_HK +( + 108, + "zh_HK", + "Chinese - Hong Kong SAR", + FALSE, + &my_locale_typelib_month_names_zh_CN, + &my_locale_typelib_ab_month_names_zh_CN, + &my_locale_typelib_day_names_zh_CN, + &my_locale_typelib_ab_day_names_zh_CN +); /***** LOCALE END zh_HK *****/ + +/* + The list of all locales. + Note, locales must be ordered according to their + numbers to make my_locale_by_number() work fast. + Some debug asserts below check this. +*/ MY_LOCALE *my_locales[]= { &my_locale_en_US, @@ -1496,3 +2581,31 @@ MY_LOCALE *my_locales[]= &my_locale_zh_HK, NULL }; + + +MY_LOCALE *my_locale_by_number(uint number) +{ + MY_LOCALE *locale; + if (number >= array_elements(my_locales) - 1) + return NULL; + locale= my_locales[number]; + // Check that locale is on its correct position in the array + DBUG_ASSERT(locale == my_locales[locale->number]); + return locale; +} + + +MY_LOCALE *my_locale_by_name(const char *name) +{ + MY_LOCALE **locale; + for (locale= my_locales; *locale != NULL; locale++) + { + if (!my_strcasecmp(&my_charset_latin1, (*locale)->name, name)) + { + // Check that locale is on its correct position in the array + DBUG_ASSERT((*locale) == my_locales[(*locale)->number]); + return *locale; + } + } + return NULL; +} diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index b3c67ab5db7..b0ca7667a62 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000, 2002, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_map.cc b/sql/sql_map.cc index 8376b3bbfcc..36a47f1aefc 100644 --- a/sql/sql_map.cc +++ b/sql/sql_map.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2004-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_map.h b/sql/sql_map.h index bfa6011ac54..d8eb64995aa 100644 --- a/sql/sql_map.h +++ b/sql/sql_map.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 3d06030536f..818825d566b 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9a93a9cf2e7..ec2807750bd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,24 +28,6 @@ #include "events.h" #include "event_data_objects.h" -#ifdef HAVE_OPENSSL -/* - Without SSL the handshake consists of one packet. This packet - has both client capabilites and scrambled password. - With SSL the handshake might consist of two packets. If the first - packet (client capabilities) has CLIENT_SSL flag set, we have to - switch to SSL and read the second packet. The scrambled password - is in the second packet and client_capabilites field will be ignored. - Maybe it is better to accept flags other than CLIENT_SSL from the - second packet? -*/ -#define SSL_HANDSHAKE_SIZE 2 -#define NORMAL_HANDSHAKE_SIZE 6 -#define MIN_HANDSHAKE_SIZE 2 -#else -#define MIN_HANDSHAKE_SIZE 6 -#endif /* HAVE_OPENSSL */ - /* Used in error handling only */ #define SP_TYPE_STRING(LP) \ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE") @@ -57,12 +38,6 @@ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \ "FUNCTION" : "PROCEDURE") -static void time_out_user_resource_limits(THD *thd, USER_CONN *uc); -#ifndef NO_EMBEDDED_ACCESS_CHECKS -static int check_for_max_user_connections(THD *thd, USER_CONN *uc); -static void decrease_user_connections(USER_CONN *uc); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -static bool check_multi_update_lock(THD *thd); static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); const char *any_db="*any*"; // Special symbol for check_access @@ -105,20 +80,6 @@ const char *xa_state_names[]={ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" }; -#ifdef __WIN__ -static void test_signal(int sig_ptr) -{ -#if !defined( DBUG_OFF) - MessageBox(NULL,"Test signal","DBUG",MB_OK); -#endif -} -static void init_signals(void) -{ - int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; - for (int i=0 ; i < 7 ; i++) - signal( signals[i], test_signal) ; -} -#endif static void unlock_locked_tables(THD *thd) { @@ -162,6 +123,7 @@ bool end_active_trans(THD *thd) DBUG_RETURN(error); } + bool begin_trans(THD *thd) { int error=0; @@ -213,409 +175,6 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) return 0; } -#ifndef NO_EMBEDDED_ACCESS_CHECKS -static HASH hash_user_connections; - -static int get_or_create_user_conn(THD *thd, const char *user, - const char *host, - USER_RESOURCES *mqh) -{ - int return_val= 0; - uint temp_len, user_len; - char temp_user[USER_HOST_BUFF_SIZE]; - struct user_conn *uc; - - DBUG_ASSERT(user != 0); - DBUG_ASSERT(host != 0); - - user_len= strlen(user); - temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; - (void) pthread_mutex_lock(&LOCK_user_conn); - if (!(uc = (struct user_conn *) hash_search(&hash_user_connections, - (byte*) temp_user, temp_len))) - { - /* First connection for user; Create a user connection object */ - if (!(uc= ((struct user_conn*) - my_malloc(sizeof(struct user_conn) + temp_len+1, - MYF(MY_WME))))) - { - net_send_error(thd, 0, NullS); // Out of memory - return_val= 1; - goto end; - } - uc->user=(char*) (uc+1); - memcpy(uc->user,temp_user,temp_len+1); - uc->host= uc->user + user_len + 1; - uc->len= temp_len; - uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; - uc->user_resources= *mqh; - uc->intime= thd->thr_create_time; - if (my_hash_insert(&hash_user_connections, (byte*) uc)) - { - my_free((char*) uc,0); - net_send_error(thd, 0, NullS); // Out of memory - return_val= 1; - goto end; - } - } - thd->user_connect=uc; - uc->connections++; -end: - (void) pthread_mutex_unlock(&LOCK_user_conn); - return return_val; - -} -#endif /* !NO_EMBEDDED_ACCESS_CHECKS */ - - -/* - Check if user exist and password supplied is correct. - - SYNOPSIS - check_user() - thd thread handle, thd->security_ctx->{host,user,ip} are used - command originator of the check: now check_user is called - during connect and change user procedures; used for - logging. - passwd scrambled password received from client - passwd_len length of scrambled password - db database name to connect to, may be NULL - check_count dont know exactly - - Note, that host, user and passwd may point to communication buffer. - Current implementation does not depend on that, but future changes - should be done with this in mind; 'thd' is INOUT, all other params - are 'IN'. - - RETURN VALUE - 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and - thd->db are updated; OK is sent to client; - -1 access denied or handshake error; error is sent to client; - >0 error, not sent to client -*/ - -int check_user(THD *thd, enum enum_server_command command, - const char *passwd, uint passwd_len, const char *db, - bool check_count) -{ - DBUG_ENTER("check_user"); - -#ifdef NO_EMBEDDED_ACCESS_CHECKS - thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights - /* Change database if necessary */ - if (db && db[0]) - { - /* - thd->db is saved in caller and needs to be freed by caller if this - function returns 0 - */ - thd->reset_db(NULL, 0); - if (mysql_change_db(thd, db, FALSE)) - { - /* Send the error to the client */ - net_send_error(thd); - DBUG_RETURN(-1); - } - } - send_ok(thd); - DBUG_RETURN(0); -#else - - my_bool opt_secure_auth_local; - pthread_mutex_lock(&LOCK_global_system_variables); - opt_secure_auth_local= opt_secure_auth; - pthread_mutex_unlock(&LOCK_global_system_variables); - - /* - If the server is running in secure auth mode, short scrambles are - forbidden. - */ - if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) - { - net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); - general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); - DBUG_RETURN(-1); - } - if (passwd_len != 0 && - passwd_len != SCRAMBLE_LENGTH && - passwd_len != SCRAMBLE_LENGTH_323) - DBUG_RETURN(ER_HANDSHAKE_ERROR); - - /* - Clear thd->db as it points to something, that will be freed when - connection is closed. We don't want to accidentally free a wrong pointer - if connect failed. Also in case of 'CHANGE USER' failure, current - database will be switched to 'no database selected'. - */ - thd->reset_db(NULL, 0); - - USER_RESOURCES ur; - int res= acl_getroot(thd, &ur, passwd, passwd_len); -#ifndef EMBEDDED_LIBRARY - if (res == -1) - { - /* - This happens when client (new) sends password scrambled with - scramble(), but database holds old value (scrambled with - scramble_323()). Here we please client to send scrambled_password - in old format. - */ - NET *net= &thd->net; - if (opt_secure_auth_local) - { - net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip); - general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip); - DBUG_RETURN(-1); - } - /* We have to read very specific packet size */ - if (send_old_password_request(thd) || - my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) - { - inc_host_errors(&thd->remote.sin_addr); - DBUG_RETURN(ER_HANDSHAKE_ERROR); - } - /* Final attempt to check the user based on reply */ - /* So as passwd is short, errcode is always >= 0 */ - res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); - } -#endif /*EMBEDDED_LIBRARY*/ - /* here res is always >= 0 */ - if (res == 0) - { - if (!(thd->main_security_ctx.master_access & - NO_ACCESS)) // authentication is OK - { - DBUG_PRINT("info", - ("Capabilities: %lu packet_length: %ld Host: '%s' " - "Login user: '%s' Priv_user: '%s' Using password: %s " - "Access: %lu db: '%s'", - thd->client_capabilities, - thd->max_client_packet_length, - thd->main_security_ctx.host_or_ip, - thd->main_security_ctx.user, - thd->main_security_ctx.priv_user, - passwd_len ? "yes": "no", - thd->main_security_ctx.master_access, - (thd->db ? thd->db : "*none*"))); - - if (check_count) - { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool count_ok= thread_count <= max_connections + delayed_insert_threads - || (thd->main_security_ctx.master_access & SUPER_ACL); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - if (!count_ok) - { // too many connections - net_send_error(thd, ER_CON_COUNT_ERROR); - DBUG_RETURN(-1); - } - } - - /* Why logging is performed before all checks've passed? */ - general_log_print(thd, command, - (thd->main_security_ctx.priv_user == - thd->main_security_ctx.user ? - (char*) "%s@%s on %s" : - (char*) "%s@%s as anonymous on %s"), - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - db ? db : (char*) ""); - - /* - This is the default access rights for the current database. It's - set to 0 here because we don't have an active database yet (and we - may not have an active database to set. - */ - thd->main_security_ctx.db_access=0; - - /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || - max_user_connections) && - get_or_create_user_conn(thd, - (opt_old_style_user_limits ? thd->main_security_ctx.user : - thd->main_security_ctx.priv_user), - (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : - thd->main_security_ctx.priv_host), - &ur)) - DBUG_RETURN(-1); - if (thd->user_connect && - (thd->user_connect->user_resources.conn_per_hour || - thd->user_connect->user_resources.user_conn || - max_user_connections) && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(-1); - - /* Change database if necessary */ - if (db && db[0]) - { - if (mysql_change_db(thd, db, FALSE)) - { - /* Send error to the client */ - net_send_error(thd); - if (thd->user_connect) - decrease_user_connections(thd->user_connect); - DBUG_RETURN(-1); - } - } - send_ok(thd); - thd->password= test(passwd_len); // remember for error messages - /* Ready to handle queries */ - DBUG_RETURN(0); - } - } - else if (res == 2) // client gave short hash, server has long hash - { - net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); - general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); - DBUG_RETURN(-1); - } - net_printf_error(thd, ER_ACCESS_DENIED_ERROR, - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); - general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); - DBUG_RETURN(-1); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - -/* - Check for maximum allowable user connections, if the mysqld server is - started with corresponding variable that is greater then 0. -*/ - -extern "C" byte *get_key_conn(user_conn *buff, uint *length, - my_bool not_used __attribute__((unused))) -{ - *length=buff->len; - return (byte*) buff->user; -} - -extern "C" void free_user(struct user_conn *uc) -{ - my_free((char*) uc,MYF(0)); -} - -void init_max_user_conn(void) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - (void) hash_init(&hash_user_connections,system_charset_info,max_connections, - 0,0, - (hash_get_key) get_key_conn, (hash_free_key) free_user, - 0); -#endif -} - - -/* - check if user has already too many connections - - SYNOPSIS - check_for_max_user_connections() - thd Thread handle - uc User connect object - - NOTES - If check fails, we decrease user connection count, which means one - shouldn't call decrease_user_connections() after this function. - - RETURN - 0 ok - 1 error -*/ - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - -static int check_for_max_user_connections(THD *thd, USER_CONN *uc) -{ - int error=0; - DBUG_ENTER("check_for_max_user_connections"); - - (void) pthread_mutex_lock(&LOCK_user_conn); - if (max_user_connections && !uc->user_resources.user_conn && - max_user_connections < (uint) uc->connections) - { - net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user); - error=1; - goto end; - } - time_out_user_resource_limits(thd, uc); - if (uc->user_resources.user_conn && - uc->user_resources.user_conn < uc->connections) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_user_connections", - (long) uc->user_resources.user_conn); - error= 1; - goto end; - } - if (uc->user_resources.conn_per_hour && - uc->user_resources.conn_per_hour <= uc->conn_per_hour) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_connections_per_hour", - (long) uc->user_resources.conn_per_hour); - error=1; - goto end; - } - uc->conn_per_hour++; - - end: - if (error) - uc->connections--; // no need for decrease_user_connections() here - (void) pthread_mutex_unlock(&LOCK_user_conn); - DBUG_RETURN(error); -} - -/* - Decrease user connection count - - SYNOPSIS - decrease_user_connections() - uc User connection object - - NOTES - If there is a n user connection object for a connection - (which only happens if 'max_user_connections' is defined or - if someone has created a resource grant for a user), then - the connection count is always incremented on connect. - - The user connect object is not freed if some users has - 'max connections per hour' defined as we need to be able to hold - count over the lifetime of the connection. -*/ - -static void decrease_user_connections(USER_CONN *uc) -{ - DBUG_ENTER("decrease_user_connections"); - (void) pthread_mutex_lock(&LOCK_user_conn); - DBUG_ASSERT(uc->connections); - if (!--uc->connections && !mqh_used) - { - /* Last connection for user; Delete it */ - (void) hash_delete(&hash_user_connections,(byte*) uc); - } - (void) pthread_mutex_unlock(&LOCK_user_conn); - DBUG_VOID_RETURN; -} - -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ - - -void free_max_user_conn(void) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - hash_free(&hash_user_connections); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - - /* Mark all commands that somehow changes a table @@ -699,404 +258,6 @@ bool is_update_query(enum enum_sql_command command) return (sql_command_flags[command] & CF_CHANGES_DATA) != 0; } -/* - Reset per-hour user resource limits when it has been more than - an hour since they were last checked - - SYNOPSIS: - time_out_user_resource_limits() - thd Thread handler - uc User connection details - - NOTE: - This assumes that the LOCK_user_conn mutex has been acquired, so it is - safe to test and modify members of the USER_CONN structure. -*/ - -static void time_out_user_resource_limits(THD *thd, USER_CONN *uc) -{ - time_t check_time = thd->start_time ? thd->start_time : time(NULL); - DBUG_ENTER("time_out_user_resource_limits"); - - /* If more than a hour since last check, reset resource checking */ - if (check_time - uc->intime >= 3600) - { - uc->questions=1; - uc->updates=0; - uc->conn_per_hour=0; - uc->intime=check_time; - } - - DBUG_VOID_RETURN; -} - - -/* - Check if maximum queries per hour limit has been reached - returns 0 if OK. -*/ - -static bool check_mqh(THD *thd, uint check_command) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - bool error= 0; - USER_CONN *uc=thd->user_connect; - DBUG_ENTER("check_mqh"); - DBUG_ASSERT(uc != 0); - - (void) pthread_mutex_lock(&LOCK_user_conn); - - time_out_user_resource_limits(thd, uc); - - /* Check that we have not done too many questions / hour */ - if (uc->user_resources.questions && - uc->questions++ >= uc->user_resources.questions) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", - (long) uc->user_resources.questions); - error=1; - goto end; - } - if (check_command < (uint) SQLCOM_END) - { - /* Check that we have not done too many updates / hour */ - if (uc->user_resources.updates && - (sql_command_flags[check_command] & CF_CHANGES_DATA) && - uc->updates++ >= uc->user_resources.updates) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", - (long) uc->user_resources.updates); - error=1; - goto end; - } - } -end: - (void) pthread_mutex_unlock(&LOCK_user_conn); - DBUG_RETURN(error); -#else - return (0); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - - -static void reset_mqh(LEX_USER *lu, bool get_them= 0) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - (void) pthread_mutex_lock(&LOCK_user_conn); - if (lu) // for GRANT - { - USER_CONN *uc; - uint temp_len=lu->user.length+lu->host.length+2; - char temp_user[USER_HOST_BUFF_SIZE]; - - memcpy(temp_user,lu->user.str,lu->user.length); - memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); - temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0; - if ((uc = (struct user_conn *) hash_search(&hash_user_connections, - (byte*) temp_user, temp_len))) - { - uc->questions=0; - get_mqh(temp_user,&temp_user[lu->user.length+1],uc); - uc->updates=0; - uc->conn_per_hour=0; - } - } - else - { - /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */ - for (uint idx=0;idx < hash_user_connections.records; idx++) - { - USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, - idx); - if (get_them) - get_mqh(uc->user,uc->host,uc); - uc->questions=0; - uc->updates=0; - uc->conn_per_hour=0; - } - } - (void) pthread_mutex_unlock(&LOCK_user_conn); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - -void thd_init_client_charset(THD *thd, uint cs_number) -{ - /* - Use server character set and collation if - - opt_character_set_client_handshake is not set - - client has not specified a character set - - client character set is the same as the servers - - client character set doesn't exists in server - */ - if (!opt_character_set_client_handshake || - !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) || - !my_strcasecmp(&my_charset_latin1, - global_system_variables.character_set_client->name, - thd->variables.character_set_client->name)) - { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.character_set_results= - global_system_variables.character_set_results; - } - else - { - thd->variables.character_set_results= - thd->variables.collation_connection= - thd->variables.character_set_client; - } -} - - -/* - Perform handshake, authorize client and update thd ACL variables. - SYNOPSIS - check_connection() - thd thread handle - - RETURN - 0 success, OK is sent to user, thd is updated. - -1 error, which is sent to user - > 0 error code (not sent to user) -*/ - -#ifndef EMBEDDED_LIBRARY -static int check_connection(THD *thd) -{ - uint connect_errors= 0; - NET *net= &thd->net; - ulong pkt_len= 0; - char *end; - - DBUG_PRINT("info", - ("New connection received on %s", vio_description(net->vio))); -#ifdef SIGNAL_WITH_VIO_CLOSE - thd->set_active_vio(net->vio); -#endif - - if (!thd->main_security_ctx.host) // If TCP/IP connection - { - char ip[30]; - - if (vio_peer_addr(net->vio, ip, &thd->peer_port)) - return (ER_BAD_HOST_ERROR); - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) - return (ER_OUT_OF_RESOURCES); - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; - vio_in_addr(net->vio,&thd->remote.sin_addr); - if (!(specialflag & SPECIAL_NO_RESOLVE)) - { - vio_in_addr(net->vio,&thd->remote.sin_addr); - thd->main_security_ctx.host= - ip_to_hostname(&thd->remote.sin_addr, &connect_errors); - /* Cut very long hostnames to avoid possible overflows */ - if (thd->main_security_ctx.host) - { - if (thd->main_security_ctx.host != my_localhost) - thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), - HOSTNAME_LENGTH)]= 0; - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; - } - if (connect_errors > max_connect_errors) - return(ER_HOST_IS_BLOCKED); - } - DBUG_PRINT("info",("Host: %s ip: %s", - (thd->main_security_ctx.host ? - thd->main_security_ctx.host : "unknown host"), - (thd->main_security_ctx.ip ? - thd->main_security_ctx.ip : "unknown ip"))); - if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) - return(ER_HOST_NOT_PRIVILEGED); - } - else /* Hostname given means that the connection was on a socket */ - { - DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; - thd->main_security_ctx.ip= 0; - /* Reset sin_addr */ - bzero((char*) &thd->remote, sizeof(thd->remote)); - } - vio_keepalive(net->vio, TRUE); - { - /* buff[] needs to big enough to hold the server_version variable */ - char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; - ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); - - if (opt_using_transactions) - client_flags|=CLIENT_TRANSACTIONS; -#ifdef HAVE_COMPRESS - client_flags |= CLIENT_COMPRESS; -#endif /* HAVE_COMPRESS */ -#ifdef HAVE_OPENSSL - if (ssl_acceptor_fd) - client_flags |= CLIENT_SSL; /* Wow, SSL is available! */ -#endif /* HAVE_OPENSSL */ - - end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; - int4store((uchar*) end, thd->thread_id); - end+= 4; - /* - So as check_connection is the only entry point to authorization - procedure, scramble is set here. This gives us new scramble for - each handshake. - */ - create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); - /* - Old clients does not understand long scrambles, but can ignore packet - tail: that's why first part of the scramble is placed here, and second - part at the end of packet. - */ - end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; - - int2store(end, client_flags); - /* write server characteristics: up to 16 bytes allowed */ - end[2]=(char) default_charset_info->number; - int2store(end+3, thd->server_status); - bzero(end+5, 13); - end+= 18; - /* write scramble tail */ - end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, - SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; - - /* At this point we write connection message and read reply */ - if (net_write_command(net, (uchar) protocol_version, "", 0, buff, - (uint) (end-buff)) || - (pkt_len= my_net_read(net)) == packet_error || - pkt_len < MIN_HANDSHAKE_SIZE) - { - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - } -#ifdef _CUSTOMCONFIG_ -#include "_cust_sql_parse.h" -#endif - if (connect_errors) - reset_host_errors(&thd->remote.sin_addr); - if (thd->packet.alloc(thd->variables.net_buffer_length)) - return(ER_OUT_OF_RESOURCES); - - thd->client_capabilities=uint2korr(net->read_pos); - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; - thd->max_client_packet_length= uint4korr(net->read_pos+4); - DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); - thd_init_client_charset(thd, (uint) net->read_pos[8]); - thd->update_charset(); - end= (char*) net->read_pos+32; - } - else - { - thd->max_client_packet_length= uint3korr(net->read_pos+2); - end= (char*) net->read_pos+5; - } - - if (thd->client_capabilities & CLIENT_IGNORE_SPACE) - thd->variables.sql_mode|= MODE_IGNORE_SPACE; -#ifdef HAVE_OPENSSL - DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); - if (thd->client_capabilities & CLIENT_SSL) - { - /* Do the SSL layering. */ - if (!ssl_acceptor_fd) - { - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - DBUG_PRINT("info", ("IO layer change in progress...")); - if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout)) - { - DBUG_PRINT("error", ("Failed to accept new SSL connection")); - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - DBUG_PRINT("info", ("Reading user information over SSL layer")); - if ((pkt_len= my_net_read(net)) == packet_error || - pkt_len < NORMAL_HANDSHAKE_SIZE) - { - DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", - pkt_len)); - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - } -#endif - - if (end >= (char*) net->read_pos+ pkt_len +2) - { - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - - if (thd->client_capabilities & CLIENT_INTERACTIVE) - thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; - if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && - opt_using_transactions) - net->return_status= &thd->server_status; - net->read_timeout=(uint) thd->variables.net_read_timeout; - - char *user= end; - char *passwd= strend(user)+1; - uint user_len= passwd - user - 1; - char *db= passwd; - char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 - char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 - uint dummy_errors; - - /* - Old clients send null-terminated string as password; new clients send - the size (1 byte) + string (not null-terminated). Hence in case of empty - password both send '\0'. - - This strlen() can't be easily deleted without changing protocol. - */ - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); - db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? - db + passwd_len + 1 : 0; - /* strlen() can't be easily deleted without changing protocol */ - uint db_len= db ? strlen(db) : 0; - - if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - - /* Since 4.1 all database names are stored in utf8 */ - if (db) - { - db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, - system_charset_info, - db, db_len, - thd->charset(), &dummy_errors)]= 0; - db= db_buff; - } - - user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1, - system_charset_info, user, user_len, - thd->charset(), &dummy_errors)]= '\0'; - user= user_buff; - - /* If username starts and ends in "'", chop them off */ - if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'') - { - user[user_len-1]= 0; - user++; - user_len-= 2; - } - - if (thd->main_security_ctx.user) - x_free(thd->main_security_ctx.user); - if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) - return (ER_OUT_OF_RESOURCES); - return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); -} - void execute_init_command(THD *thd, sys_var_str *init_command_var, rw_lock_t *var_mutex) @@ -1129,145 +290,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, } -pthread_handler_t handle_one_connection(void *arg) -{ - THD *thd=(THD*) arg; - uint launch_time = - (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time); - if (launch_time >= slow_launch_time) - statistic_increment(slow_launch_threads,&LOCK_status ); - - pthread_detach_this_thread(); - -#if !defined( __WIN__) // Win32 calls this in pthread_create - /* The following calls needs to be done before we call DBUG_ macros */ - if (!(test_flags & TEST_NO_THREADS) & my_thread_init()) - { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); - statistic_increment(aborted_connects,&LOCK_status); - end_thread(thd,0); - return 0; - } -#endif - - /* - handle_one_connection() is the only way a thread would start - and would always be on top of the stack, therefore, the thread - stack always starts at the address of the first local variable - of handle_one_connection, which is thd. We need to know the - start of the stack so that we could check for stack overruns. - */ - DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n", - thd->thread_id)); - /* now that we've called my_thread_init(), it is safe to call DBUG_* */ - -#if defined(__WIN__) - init_signals(); -#elif !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif - thd->thread_stack= (char*) &thd; - if (thd->store_globals()) - { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); - statistic_increment(aborted_connects,&LOCK_status); - end_thread(thd,0); - return 0; - } - - do - { - int error; - NET *net= &thd->net; - Security_context *sctx= thd->security_ctx; - net->no_send_error= 0; - - if ((error=check_connection(thd))) - { // Wrong permissions - if (error > 0) - net_printf_error(thd, error, sctx->host_or_ip); -#ifdef __NT__ - if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) - my_sleep(1000); /* must wait after eof() */ -#endif - statistic_increment(aborted_connects,&LOCK_status); - goto end_thread; - } -#ifdef __NETWARE__ - netware_reg_user(sctx->ip, sctx->user, "MySQL"); -#endif - if (thd->variables.max_join_size == HA_POS_ERROR) - thd->options |= OPTION_BIG_SELECTS; - if (thd->client_capabilities & CLIENT_COMPRESS) - net->compress=1; // Use compression - - thd->version= refresh_version; - thd->proc_info= 0; - thd->command= COM_SLEEP; - thd->set_time(); - thd->init_for_queries(); - - if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) - { - execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); - if (thd->query_error) - { - thd->killed= THD::KILL_CONNECTION; - sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), - thd->thread_id,(thd->db ? thd->db : "unconnected"), - sctx->user ? sctx->user : "unauthenticated", - sctx->host_or_ip, "init_connect command failed"); - sql_print_warning("%s", net->last_error); - } - thd->proc_info=0; - thd->set_time(); - thd->init_for_queries(); - } - - while (!net->error && net->vio != 0 && - !(thd->killed == THD::KILL_CONNECTION)) - { - net->no_send_error= 0; - if (do_command(thd)) - break; - } - if (thd->user_connect) - decrease_user_connections(thd->user_connect); - if (net->error && net->vio != 0 && net->report_error) - { - if (!thd->killed && thd->variables.log_warnings > 1) - sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), - thd->thread_id,(thd->db ? thd->db : "unconnected"), - sctx->user ? sctx->user : "unauthenticated", - sctx->host_or_ip, - (net->last_errno ? ER(net->last_errno) : - ER(ER_UNKNOWN_ERROR))); - net_send_error(thd, net->last_errno, NullS); - statistic_increment(aborted_threads,&LOCK_status); - } - else if (thd->killed) - { - statistic_increment(aborted_threads,&LOCK_status); - } - -end_thread: - close_connection(thd, 0, 1); - end_thread(thd,1); - /* - If end_thread returns, we are either running with --one-thread - or this thread has been schedule to handle the next query - */ - thd= current_thd; - thd->thread_stack= (char*) &thd; - } while (!(test_flags & TEST_NO_THREADS)); - /* The following is only executed if we are not using --one-thread */ - return(0); /* purecov: deadcode */ -} - -#endif /* EMBEDDED_LIBRARY */ - /* Execute commands from bootstrap_file. Used when creating the initial grant tables @@ -1294,11 +316,6 @@ pthread_handler_t handle_bootstrap(void *arg) #ifndef EMBEDDED_LIBRARY pthread_detach_this_thread(); thd->thread_stack= (char*) &thd; -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif #endif /* EMBEDDED_LIBRARY */ if (thd->variables.max_join_size == HA_POS_ERROR) @@ -1557,7 +574,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) #ifndef EMBEDDED_LIBRARY /* - Read one command from socket and execute it (query or simple command). + Read one command from connection and execute it (query or simple command). This function is called in loop from thread function. SYNOPSIS do_command() @@ -1568,24 +585,26 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) bool do_command(THD *thd) { - char *packet; - uint old_timeout; + char *packet= 0; ulong packet_length; - NET *net; + NET *net= &thd->net; enum enum_server_command command; DBUG_ENTER("do_command"); - net= &thd->net; /* indicator of uninitialized lex => normal flow of errors handling (see my_message_sql) */ thd->lex->current_select= 0; - packet=0; - old_timeout=net->read_timeout; - /* Wait max for 8 hours */ - net->read_timeout=(uint) thd->variables.net_wait_timeout; + /* + This thread will do a blocking read from the client which + will be interrupted when the next command is received from + the client, the connection is closed or "net_wait_timeout" + number of seconds has passed + */ + net_set_read_timeout(net, thd->variables.net_wait_timeout); + thd->clear_error(); // Clear error message net_new_transaction(net); @@ -1614,7 +633,10 @@ bool do_command(THD *thd) vio_description(net->vio), command, command_name[command].str)); } - net->read_timeout=old_timeout; // restore it + + /* Restore read timeout value */ + net_set_read_timeout(net, thd->variables.net_read_timeout); + /* packet_length contains length of data, as it was stored in packet header. In case of malformed header, packet_length can be zero. @@ -1665,7 +687,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query_id=query_id; + thd->query_id= global_query_id; if (command != COM_STATISTICS && command != COM_PING) next_query_id(); thread_running++; @@ -1859,7 +881,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error) { - char *packet= thd->lex->found_semicolon; + char *next_packet= thd->lex->found_semicolon; net->no_send_error= 0; /* Multiple queries exits, execute them individually @@ -1867,24 +889,24 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (thd->lock || thd->open_tables || thd->derived_tables || thd->prelocked_mode) close_thread_tables(thd); - ulong length= (ulong)(packet_end-packet); + ulong length= (ulong)(packet_end - next_packet); log_slow_statement(thd); /* Remove garbage at start of query */ - while (my_isspace(thd->charset(), *packet) && length > 0) + while (my_isspace(thd->charset(), *next_packet) && length > 0) { - packet++; + next_packet++; length--; } VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_length= length; - thd->query= packet; + thd->query= next_packet; thd->query_id= next_query_id(); thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ VOID(pthread_mutex_unlock(&LOCK_thread_count)); - mysql_parse(thd, packet, length); + mysql_parse(thd, next_packet, length); } if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -1901,11 +923,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { char *fields, *packet_end= packet + packet_length - 1, *arg_end; /* Locked closure of all tables */ - TABLE_LIST *locked_tables= NULL; TABLE_LIST table_list; LEX_STRING conv_name; - /* Saved variable value */ - my_bool old_innodb_table_locks= thd->variables.innodb_table_locks; uint dummy; /* used as fields initializator */ @@ -2075,7 +1094,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, */ enum mysql_enum_shutdown_level level= (enum mysql_enum_shutdown_level) (uchar) packet[0]; - DBUG_PRINT("quit",("Got shutdown command for level %u", level)); if (level == SHUTDOWN_DEFAULT) level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable else if (level != SHUTDOWN_WAIT_ALL_BUFFERS) @@ -2119,7 +1137,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS], &LOCK_status); calc_sum_of_all_status(¤t_global_status_var); - uptime= (ulong) (thd->start_time - start_time); + uptime= (ulong) (thd->start_time - server_start_time); length= my_snprintf((char*) buff, buff_len - 1, "Uptime: %lu Threads: %d Questions: %lu " "Slow queries: %lu Opens: %lu Flush tables: %lu " @@ -2174,13 +1192,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION], &LOCK_status); - enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet); - switch (command) { - case MYSQL_OPTION_MULTI_STATEMENTS_ON: + uint opt_command= uint2korr(packet); + + switch (opt_command) { + case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON: thd->client_capabilities|= CLIENT_MULTI_STATEMENTS; send_eof(thd); break; - case MYSQL_OPTION_MULTI_STATEMENTS_OFF: + case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF: thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS; send_eof(thd); break; @@ -2488,6 +1507,7 @@ static void reset_one_shot_variables(THD *thd) thd->update_charset(); thd->variables.time_zone= global_system_variables.time_zone; + thd->variables.lc_time_names= &my_locale_en_US; thd->one_shot_set= 0; } @@ -2521,7 +1541,7 @@ mysql_execute_command(THD *thd) { bool res= FALSE; bool need_start_waiting= FALSE; // have protection against global read lock - int result= 0; + int up_result= 0; LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ SELECT_LEX *select_lex= &lex->select_lex; @@ -2955,6 +1975,12 @@ mysql_execute_command(THD *thd) goto end_with_restore_list; #ifndef HAVE_READLINK + if (lex->create_info.data_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "DATA DIRECTORY option ignored"); + if (lex->create_info.index_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "INDEX DIRECTORY option ignored"); lex->create_info.data_file_name=lex->create_info.index_file_name=0; #else /* Fix names if symlinked tables */ @@ -3371,22 +2397,23 @@ end_with_restore_list: break; DBUG_ASSERT(select_lex->offset_limit == 0); unit->set_limit(select_lex); - res= (result= mysql_update(thd, all_tables, - select_lex->item_list, - lex->value_list, - select_lex->where, - select_lex->order_list.elements, - (ORDER *) select_lex->order_list.first, - unit->select_limit_cnt, - lex->duplicates, lex->ignore)); + res= (up_result= mysql_update(thd, all_tables, + select_lex->item_list, + lex->value_list, + select_lex->where, + select_lex->order_list.elements, + (ORDER *) select_lex->order_list.first, + unit->select_limit_cnt, + lex->duplicates, lex->ignore)); /* mysql_update return 2 if we need to switch to multi-update */ - if (result != 2) + if (up_result != 2) break; + /* Fall through */ case SQLCOM_UPDATE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); /* if we switched from normal update, rights are checked */ - if (result != 2) + if (up_result != 2) { if ((res= multi_update_precheck(thd, all_tables))) break; @@ -3471,7 +2498,7 @@ end_with_restore_list: case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { - select_result *result; + select_result *sel_result; DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; @@ -3500,13 +2527,15 @@ end_with_restore_list: select_lex->context.table_list= select_lex->context.first_name_resolution_table= second_table; res= mysql_insert_select_prepare(thd); - if (!res && (result= new select_insert(first_table, first_table->table, - &lex->field_list, - &lex->update_list, - &lex->value_list, - lex->duplicates, lex->ignore))) + if (!res && (sel_result= new select_insert(first_table, + first_table->table, + &lex->field_list, + &lex->update_list, + &lex->value_list, + lex->duplicates, + lex->ignore))) { - res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); + res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE); /* Invalidate the table in the query cache if something changed after unlocking when changes become visible. @@ -3524,7 +2553,7 @@ end_with_restore_list: first_table->next_local= save_table; thd->lock=0; } - delete result; + delete sel_result; } /* revert changes for SP */ select_lex->table_list.first= (byte*) first_table; @@ -3549,7 +2578,7 @@ end_with_restore_list: break; } DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_one_table_access(thd, DELETE_ACL, all_tables)) + if (check_one_table_access(thd, DROP_ACL, all_tables)) goto error; /* Don't allow this within a transaction because we want to use @@ -3590,7 +2619,7 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxiliary_table_list.first; - multi_delete *result; + multi_delete *del_result; if (!thd->locked_tables && !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) @@ -3615,8 +2644,8 @@ end_with_restore_list: if ((res= mysql_multi_delete_prepare(thd))) goto error; - if (!thd->is_fatal_error && (result= new multi_delete(aux_tables, - lex->table_count))) + if (!thd->is_fatal_error && + (del_result= new multi_delete(aux_tables, lex->table_count))) { res= mysql_select(thd, &select_lex->ref_pointer_array, select_lex->get_table_list(), @@ -3628,8 +2657,8 @@ end_with_restore_list: select_lex->options | thd->options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, - result, unit, select_lex); - delete result; + del_result, unit, select_lex); + delete del_result; } else res= TRUE; // Error @@ -4037,7 +3066,6 @@ end_with_restore_list: lex->spname->m_name); else { - uint affected= 1; if (!(res= Events::get_instance()->drop_event(thd, lex->spname->m_db, lex->spname->m_name, @@ -4210,7 +3238,7 @@ end_with_restore_list: { if (!(user= get_current_user(thd, tmp_user))) goto error; - reset_mqh(user); + reset_mqh(user, 0); } } } @@ -4240,7 +3268,9 @@ end_with_restore_list: We WANT to write and we CAN write. ! we write after unlocking the table. */ - /* Presumably, RESET and binlog writing doesn't require synchronization */ + /* + Presumably, RESET and binlog writing doesn't require synchronization + */ if (!lex->no_write_to_binlog && write_to_binlog) { if (mysql_bin_log.is_open()) @@ -4436,7 +3466,7 @@ end_with_restore_list: { uint namelen; char *name; - int result= SP_INTERNAL_ERROR; + int sp_result= SP_INTERNAL_ERROR; DBUG_ASSERT(lex->sphead != 0); DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ @@ -4509,18 +3539,18 @@ end_with_restore_list: if (!lex->definer) { - bool res= FALSE; + bool local_res= FALSE; Query_arena original_arena; Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena); if (!(lex->definer= create_default_definer(thd))) - res= TRUE; + local_res= TRUE; if (ps_arena) thd->restore_active_arena(ps_arena, &original_arena); /* Error has been already reported. */ - if (res) + if (local_res) goto create_sp_error; if (thd->slave_thread) @@ -4560,8 +3590,8 @@ end_with_restore_list: } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - res= (result= lex->sphead->create(thd)); - switch (result) { + res= (sp_result= lex->sphead->create(thd)); + switch (sp_result) { case SP_OK: #ifndef NO_EMBEDDED_ACCESS_CHECKS /* only add privileges if really neccessary */ @@ -4601,7 +3631,7 @@ create_sp_error: lex->unit.cleanup(); delete lex->sphead; lex->sphead= 0; - if (result != SP_OK ) + if (sp_result != SP_OK ) goto error; send_ok(thd); break; /* break super switch */ @@ -4716,7 +3746,7 @@ create_sp_error: case SQLCOM_ALTER_PROCEDURE: case SQLCOM_ALTER_FUNCTION: { - int result; + int sp_result; sp_head *sp; st_sp_chistics chistics; @@ -4731,7 +3761,7 @@ create_sp_error: if (! sp) { if (lex->spname->m_db.str) - result= SP_KEY_NOT_FOUND; + sp_result= SP_KEY_NOT_FOUND; else { my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); @@ -4756,7 +3786,7 @@ create_sp_error: { my_message(ER_BINLOG_UNSAFE_ROUTINE, ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0)); - result= SP_INTERNAL_ERROR; + sp_result= SP_INTERNAL_ERROR; } else { @@ -4766,15 +3796,15 @@ create_sp_error: follow the restrictions that log-bin-trust-function-creators=0 already puts on CREATE FUNCTION. */ + /* Conditionally writes to binlog */ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) - /* Conditionally writes to binlog */ - result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics); + sp_result= sp_update_procedure(thd, lex->spname, + &lex->sp_chistics); else - /* Conditionally writes to binlog */ - result= sp_update_function(thd, lex->spname, &lex->sp_chistics); + sp_result= sp_update_function(thd, lex->spname, &lex->sp_chistics); } } - switch (result) + switch (sp_result) { case SP_OK: send_ok(thd); @@ -4793,13 +3823,13 @@ create_sp_error: case SQLCOM_DROP_PROCEDURE: case SQLCOM_DROP_FUNCTION: { - int result; + int sp_result; int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ? TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); - result= sp_routine_exists_in_table(thd, type, lex->spname); + sp_result= sp_routine_exists_in_table(thd, type, lex->spname); mysql_reset_errors(thd, 0); - if (result == SP_OK) + if (sp_result == SP_OK) { char *db= lex->spname->m_db.str; char *name= lex->spname->m_name.str; @@ -4820,12 +3850,11 @@ create_sp_error: ER(ER_PROC_AUTO_REVOKE_FAIL)); } #endif - if (lex->sql_command == SQLCOM_DROP_PROCEDURE) /* Conditionally writes to binlog */ - result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */ + if (lex->sql_command == SQLCOM_DROP_PROCEDURE) + sp_result= sp_drop_procedure(thd, lex->spname); else - /* Conditionally writes to binlog */ - result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */ + sp_result= sp_drop_function(thd, lex->spname); } else { @@ -4849,16 +3878,15 @@ create_sp_error: } #endif if (lex->spname->m_db.str) - result= SP_KEY_NOT_FOUND; + sp_result= SP_KEY_NOT_FOUND; else { my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); goto error; } } - res= result; - switch (result) - { + res= sp_result; + switch (sp_result) { case SP_OK: send_ok(thd); break; @@ -5189,6 +4217,58 @@ create_sp_error: #endif /* EMBEDDED_LIBRARY */ break; } + case SQLCOM_CREATE_SERVER: + { + int error; + LEX *lex= thd->lex; + DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER")); + if ((error= create_server(thd, &lex->server_options))) + { + DBUG_PRINT("info", ("problem creating server <%s>", + lex->server_options.server_name)); + my_error(error, MYF(0), lex->server_options.server_name); + break; + } + send_ok(thd, 1); + break; + } + case SQLCOM_ALTER_SERVER: + { + int error; + LEX *lex= thd->lex; + DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER")); + if ((error= alter_server(thd, &lex->server_options))) + { + DBUG_PRINT("info", ("problem altering server <%s>", + lex->server_options.server_name)); + my_error(error, MYF(0), lex->server_options.server_name); + break; + } + send_ok(thd, 1); + break; + } + case SQLCOM_DROP_SERVER: + { + int err_code; + LEX *lex= thd->lex; + DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER")); + if ((err_code= drop_server(thd, &lex->server_options))) + { + if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_EXISTS) + { + DBUG_PRINT("info", ("problem dropping server %s", + lex->server_options.server_name)); + my_error(err_code, MYF(0), lex->server_options.server_name); + } + else + { + send_ok(thd, 0); + } + break; + } + send_ok(thd, 1); + break; + } default: #ifndef EMBEDDED_LIBRARY DBUG_ASSERT(0); /* Impossible */ @@ -5574,7 +4654,9 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, { uint found=0; ulong found_access=0; +#ifndef EMBEDDED_LIBRARY TABLE_LIST *org_tables= tables; +#endif TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx; /* @@ -6214,7 +5296,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, */ if (default_value->type() == Item::FUNC_ITEM && !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC && - type == FIELD_TYPE_TIMESTAMP)) + type == MYSQL_TYPE_TIMESTAMP)) { my_error(ER_INVALID_DEFAULT, MYF(0), field_name); DBUG_RETURN(1); @@ -6236,13 +5318,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, } } - if (on_update_value && type != FIELD_TYPE_TIMESTAMP) + if (on_update_value && type != MYSQL_TYPE_TIMESTAMP) { my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name); DBUG_RETURN(1); } - if (type == FIELD_TYPE_TIMESTAMP && length) + if (type == MYSQL_TYPE_TIMESTAMP && length) { /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1. In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4), @@ -6508,6 +5590,7 @@ bool st_select_lex::init_nested_join(THD *thd) join_list->push_front(ptr); ptr->embedding= embedding; ptr->join_list= join_list; + ptr->alias= (char*) "(nested_join)"; embedding= ptr; join_list= &nested_join->join_list; join_list->empty(); @@ -6592,6 +5675,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) ptr->embedding= embedding; ptr->join_list= join_list; + ptr->alias= (char*) "(nest_last_join)"; embedded_list= &nested_join->join_list; embedded_list->empty(); @@ -6608,11 +5692,8 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) If this is a JOIN ... USING, move the list of joined fields to the table reference that describes the join. */ - if (table->join_using_fields) - { - ptr->join_using_fields= table->join_using_fields; - table->join_using_fields= NULL; - } + if (prev_join_using) + ptr->join_using_fields= prev_join_using; } } join_list->push_front(ptr); @@ -6748,18 +5829,18 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) 0 on success */ -bool st_select_lex_unit::add_fake_select_lex(THD *thd) +bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) { SELECT_LEX *first_sl= first_select(); DBUG_ENTER("add_fake_select_lex"); DBUG_ASSERT(!fake_select_lex); - if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX())) + if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX())) DBUG_RETURN(1); fake_select_lex->include_standalone(this, (SELECT_LEX_NODE**)&fake_select_lex); fake_select_lex->select_number= INT_MAX; - fake_select_lex->parent_lex= thd->lex; /* Used in init_query. */ + fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */ fake_select_lex->make_empty_select(); fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE; fake_select_lex->select_limit= 0; @@ -6779,9 +5860,9 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd) */ global_parameters= fake_select_lex; fake_select_lex->no_table_names_allowed= 1; - thd->lex->current_select= fake_select_lex; + thd_arg->lex->current_select= fake_select_lex; } - thd->lex->pop_context(); + thd_arg->lex->pop_context(); DBUG_RETURN(0); } @@ -6868,6 +5949,7 @@ void add_join_on(TABLE_LIST *b, Item *expr) a Left join argument b Right join argument using_fields Field names from USING clause + lex The current st_select_lex IMPLEMENTATION This function marks that table b should be joined with a either via @@ -6896,10 +5978,11 @@ void add_join_on(TABLE_LIST *b, Item *expr) None */ -void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields) +void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, + SELECT_LEX *lex) { b->natural_join= a; - b->join_using_fields= using_fields; + lex->prev_join_using= using_fields; } @@ -7087,7 +6170,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } #endif if (options & REFRESH_USER_RESOURCES) - reset_mqh((LEX_USER *) NULL); + reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ *write_to_binlog= tmp_write_to_binlog; return result; } @@ -7307,6 +6390,7 @@ bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) bzero((char*) &create_info,sizeof(create_info)); create_info.db_type= 0; create_info.default_table_charset= thd->variables.collation_database; + create_info.row_type= ROW_TYPE_NOT_USED; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name, &create_info, table_list, fields, keys, 0, (ORDER*)0, @@ -7323,6 +6407,7 @@ bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info) bzero((char*) &create_info,sizeof(create_info)); create_info.db_type= 0; create_info.default_table_charset= thd->variables.collation_database; + create_info.row_type= ROW_TYPE_NOT_USED; alter_info->clear(); alter_info->flags= ALTER_DROP_INDEX; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name, diff --git a/sql/sql_parse.cc.rej b/sql/sql_parse.cc.rej deleted file mode 100644 index 6e2bd03867d..00000000000 --- a/sql/sql_parse.cc.rej +++ /dev/null @@ -1,166 +0,0 @@ -*************** -*** 67,109 **** - static void decrease_user_connections(USER_CONN *uc); - #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - static bool check_multi_update_lock(THD *thd); -- static void remove_escape(char *name); - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); - - const char *any_db="*any*"; // Special symbol for check_access - -! LEX_STRING command_name[]={ -! (char *)STRING_WITH_LEN("Sleep"), -! (char *)STRING_WITH_LEN("Quit"), -! (char *)STRING_WITH_LEN("Init DB"), -! (char *)STRING_WITH_LEN("Query"), -! (char *)STRING_WITH_LEN("Field List"), -! (char *)STRING_WITH_LEN("Create DB"), -! (char *)STRING_WITH_LEN("Drop DB"), -! (char *)STRING_WITH_LEN("Refresh"), -! (char *)STRING_WITH_LEN("Shutdown"), -! (char *)STRING_WITH_LEN("Statistics"), -! (char *)STRING_WITH_LEN("Processlist"), -! (char *)STRING_WITH_LEN("Connect"), -! (char *)STRING_WITH_LEN("Kill"), -! (char *)STRING_WITH_LEN("Debug"), -! (char *)STRING_WITH_LEN("Ping"), -! (char *)STRING_WITH_LEN("Time"), -! (char *)STRING_WITH_LEN("Delayed insert"), -! (char *)STRING_WITH_LEN("Change user"), -! (char *)STRING_WITH_LEN("Binlog Dump"), -! (char *)STRING_WITH_LEN("Table Dump"), -! (char *)STRING_WITH_LEN("Connect Out"), -! (char *)STRING_WITH_LEN("Register Slave"), -! (char *)STRING_WITH_LEN("Prepare"), -! (char *)STRING_WITH_LEN("Execute"), -! (char *)STRING_WITH_LEN("Long Data"), -! (char *)STRING_WITH_LEN("Close stmt"), -! (char *)STRING_WITH_LEN("Reset stmt"), -! (char *)STRING_WITH_LEN("Set option"), -! (char *)STRING_WITH_LEN("Fetch"), -! (char *)STRING_WITH_LEN("Daemon"), -! (char *)STRING_WITH_LEN("Error") // Last command number - }; - - const char *xa_state_names[]={ ---- 67,108 ---- - static void decrease_user_connections(USER_CONN *uc); - #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - static bool check_multi_update_lock(THD *thd); - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); - - const char *any_db="*any*"; // Special symbol for check_access - -! const LEX_STRING command_name[]={ -! C_STRING_WITH_LEN("Sleep"), -! C_STRING_WITH_LEN("Quit"), -! C_STRING_WITH_LEN("Init DB"), -! C_STRING_WITH_LEN("Query"), -! C_STRING_WITH_LEN("Field List"), -! C_STRING_WITH_LEN("Create DB"), -! C_STRING_WITH_LEN("Drop DB"), -! C_STRING_WITH_LEN("Refresh"), -! C_STRING_WITH_LEN("Shutdown"), -! C_STRING_WITH_LEN("Statistics"), -! C_STRING_WITH_LEN("Processlist"), -! C_STRING_WITH_LEN("Connect"), -! C_STRING_WITH_LEN("Kill"), -! C_STRING_WITH_LEN("Debug"), -! C_STRING_WITH_LEN("Ping"), -! C_STRING_WITH_LEN("Time"), -! C_STRING_WITH_LEN("Delayed insert"), -! C_STRING_WITH_LEN("Change user"), -! C_STRING_WITH_LEN("Binlog Dump"), -! C_STRING_WITH_LEN("Table Dump"), -! C_STRING_WITH_LEN("Connect Out"), -! C_STRING_WITH_LEN("Register Slave"), -! C_STRING_WITH_LEN("Prepare"), -! C_STRING_WITH_LEN("Execute"), -! C_STRING_WITH_LEN("Long Data"), -! C_STRING_WITH_LEN("Close stmt"), -! C_STRING_WITH_LEN("Reset stmt"), -! C_STRING_WITH_LEN("Set option"), -! C_STRING_WITH_LEN("Fetch"), -! C_STRING_WITH_LEN("Daemon"), -! C_STRING_WITH_LEN("Error") // Last command number - }; - - const char *xa_state_names[]={ -*************** -*** 1738,1744 **** - password. New clients send the size (1 byte) + string (not null - terminated, so also '\0' for empty string). - */ -! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 - char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); ---- 1736,1742 ---- - password. New clients send the size (1 byte) + string (not null - terminated, so also '\0' for empty string). - */ -! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 - char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); -*************** -*** 2315,2321 **** - DBUG_RETURN(1); - } - db= lex->select_lex.db; -- remove_escape(db); // Fix escaped '_' - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); ---- 2312,2317 ---- - DBUG_RETURN(1); - } - db= lex->select_lex.db; - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); -*************** -*** 6310,6345 **** - } - - -- /* Fix escaping of _, % and \ in database and table names (for ODBC) */ -- -- static void remove_escape(char *name) -- { -- if (!*name) // For empty DB names -- return; -- char *to; -- #ifdef USE_MB -- char *strend=name+(uint) strlen(name); -- #endif -- for (to=name; *name ; name++) -- { -- #ifdef USE_MB -- int l; -- if (use_mb(system_charset_info) && -- (l = my_ismbchar(system_charset_info, name, strend))) -- { -- while (l--) -- *to++ = *name++; -- name--; -- continue; -- } -- #endif -- if (*name == '\\' && name[1]) -- name++; // Skip '\\' -- *to++= *name; -- } -- *to=0; -- } -- - /**************************************************************************** - ** save order by and tables in own lists - ****************************************************************************/ ---- 6296,6301 ---- - } - - - /**************************************************************************** - ** save order by and tables in own lists - ****************************************************************************/ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index dcc35293b84..dbac53ed5f6 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -2003,7 +2002,6 @@ char *generate_partition_syntax(partition_info *part_info, { uint i,j, tot_no_parts, no_subparts; partition_element *part_elem; - partition_element *save_part_elem= NULL; ulonglong buffer_length; char path[FN_REFLEN]; int err= 0; @@ -4739,6 +4737,7 @@ state of p1. } alt_part_info->part_type= tab_part_info->part_type; alt_part_info->subpart_type= tab_part_info->subpart_type; + alt_part_info->no_subparts= tab_part_info->no_subparts; DBUG_ASSERT(!alt_part_info->use_default_partitions); if (alt_part_info->set_up_defaults_for_partitioning(table->file, ULL(0), @@ -5369,7 +5368,6 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, List_iterator<partition_element> 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"); ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; @@ -5742,7 +5740,6 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) { partition_info *part_info= lpt->part_info; - uint count_loop= 0; DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); @@ -6016,8 +6013,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, uint fast_alter_partition) { /* Set-up struct used to write frm files */ - ulonglong copied= 0; - ulonglong deleted= 0; partition_info *part_info= table->part_info; ALTER_PARTITION_PARAM_TYPE lpt_obj; ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj; @@ -6736,7 +6731,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, } } else - DBUG_ASSERT(0); + assert(0); /* Find minimum: Do special handling if the interval has left bound in form diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 4372c26a851..7ed43527688 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 8cd4c661fb8..e3e24c1f375 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,25 +31,37 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]= { C_STRING_WITH_LEN("UDF") }, { C_STRING_WITH_LEN("STORAGE ENGINE") }, { C_STRING_WITH_LEN("FTPARSER") }, - { C_STRING_WITH_LEN("DAEMON") } + { C_STRING_WITH_LEN("DAEMON") }, + { C_STRING_WITH_LEN("INFORMATION SCHEMA") } }; +extern int initialize_schema_table(st_plugin_int *plugin); +extern int finalize_schema_table(st_plugin_int *plugin); + +/* + The number of elements in both plugin_type_initialize and + plugin_type_deinitialize should equal to the number of plugins + defined. +*/ plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]= { - 0,ha_initialize_handlerton,0,0 + 0,ha_initialize_handlerton,0,0,initialize_schema_table }; plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]= { - 0,ha_finalize_handlerton,0,0 + 0,ha_finalize_handlerton,0,0,finalize_schema_table }; +#ifdef HAVE_DLOPEN static const char *plugin_interface_version_sym= "_mysql_plugin_interface_version_"; static const char *sizeof_st_plugin_sym= "_mysql_sizeof_struct_st_plugin_"; static const char *plugin_declarations_sym= "_mysql_plugin_declarations_"; static int min_plugin_interface_version= MYSQL_PLUGIN_INTERFACE_VERSION & ~0xFF; +#endif + /* Note that 'int version' must be the first field of every plugin sub-structure (plugin->info). */ @@ -59,14 +70,16 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= 0x0000, MYSQL_HANDLERTON_INTERFACE_VERSION, MYSQL_FTPARSER_INTERFACE_VERSION, - MYSQL_DAEMON_INTERFACE_VERSION + MYSQL_DAEMON_INTERFACE_VERSION, + MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= { 0x0000, /* UDF: not implemented */ MYSQL_HANDLERTON_INTERFACE_VERSION, MYSQL_FTPARSER_INTERFACE_VERSION, - MYSQL_DAEMON_INTERFACE_VERSION + MYSQL_DAEMON_INTERFACE_VERSION, + MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; static DYNAMIC_ARRAY plugin_dl_array; @@ -81,6 +94,8 @@ static int plugin_array_version=0; my_bool plugin_register_builtin(struct st_mysql_plugin *plugin); void plugin_load(void); +#ifdef HAVE_DLOPEN + static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl) { uint i; @@ -118,6 +133,8 @@ static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl) DBUG_RETURN(dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1, struct st_plugin_dl *)); } +#endif /* HAVE_DLOPEN */ + static inline void free_plugin_mem(struct st_plugin_dl *p) { @@ -535,6 +552,8 @@ static void plugin_del(struct st_plugin_int *plugin) DBUG_VOID_RETURN; } +#ifdef NOT_USED + static void plugin_del(const LEX_STRING *name) { struct st_plugin_int *plugin; @@ -544,6 +563,8 @@ static void plugin_del(const LEX_STRING *name) DBUG_VOID_RETURN; } +#endif + void plugin_unlock(struct st_plugin_int *plugin) { DBUG_ENTER("plugin_unlock"); @@ -951,29 +972,28 @@ my_bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, state_mask= ~state_mask; // do it only once rw_rdlock(&THR_LOCK_plugin); + total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements + : plugin_hash[type].records; + /* + Do the alloca out here in case we do have a working alloca: + leaving the nested stack frame invalidates alloca allocation. + */ + plugins=(struct st_plugin_int **)my_alloca(total*sizeof(*plugins)); if (type == MYSQL_ANY_PLUGIN) { - total=plugin_array.elements; - plugins=(struct st_plugin_int **)my_alloca(total*sizeof(*plugins)); for (idx= 0; idx < total; idx++) { plugin= dynamic_element(&plugin_array, idx, struct st_plugin_int *); - if (plugin->state & state_mask) - continue; - plugins[idx]= plugin; + plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL; } } else { - HASH *hash= &plugin_hash[type]; - total=hash->records; - plugins=(struct st_plugin_int **)my_alloca(total*sizeof(*plugins)); + HASH *hash= plugin_hash + type; for (idx= 0; idx < total; idx++) { plugin= (struct st_plugin_int *) hash_element(hash, idx); - if (plugin->state & state_mask) - continue; - plugins[idx]= plugin; + plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL; } } rw_unlock(&THR_LOCK_plugin); @@ -984,7 +1004,7 @@ my_bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, { rw_rdlock(&THR_LOCK_plugin); for (uint i=idx; i < total; i++) - if (plugins[i]->state & state_mask) + if (plugins[i] && plugins[i]->state & state_mask) plugins[i]=0; rw_unlock(&THR_LOCK_plugin); } diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index fa3440f7f68..d86d9332a92 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6f810f13d9c..1acc08e095d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -977,19 +976,19 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, /* Insert @'escaped-varname' instead of parameter in the query */ if (entry) { - char *begin, *ptr; + char *start, *ptr; buf.length(0); if (buf.reserve(entry->name.length*2+3)) DBUG_RETURN(1); - begin= ptr= buf.c_ptr_quick(); + start= ptr= buf.c_ptr_quick(); *ptr++= '@'; *ptr++= '\''; ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci, ptr, 0, entry->name.str, entry->name.length); *ptr++= '\''; - buf.length(ptr - begin); + buf.length(ptr - start); val= &buf; } else @@ -1027,7 +1026,6 @@ static bool mysql_test_insert(Prepared_statement *stmt, enum_duplicates duplic) { THD *thd= stmt->thd; - LEX *lex= stmt->lex; List_iterator_fast<List_item> its(values_list); List_item *values; DBUG_ENTER("mysql_test_insert"); @@ -1254,7 +1252,6 @@ static int mysql_test_select(Prepared_statement *stmt, lex->select_lex.context.resolve_in_select_list= TRUE; -#ifndef NO_EMBEDDED_ACCESS_CHECKS ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) { @@ -1263,7 +1260,6 @@ static int mysql_test_select(Prepared_statement *stmt, } else if (check_access(thd, privilege, any_db,0,0,0,0)) goto error; -#endif if (!lex->result && !(lex->result= new (stmt->mem_root) select_send)) { @@ -1680,7 +1676,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_INSERT: res= mysql_test_insert(stmt, tables, lex->field_list, lex->many_values, - select_lex->item_list, lex->value_list, + lex->update_list, lex->value_list, lex->duplicates); break; @@ -2058,6 +2054,7 @@ void mysql_sql_stmt_prepare(THD *thd) uint query_len; DBUG_ENTER("mysql_sql_stmt_prepare"); DBUG_ASSERT(thd->protocol == &thd->protocol_simple); + LINT_INIT(query_len); if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) { @@ -2246,11 +2243,11 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) { uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround ulong stmt_id= uint4korr(packet); - ulong flags= (ulong) ((uchar) packet[4]); + ulong flags= (ulong) packet[4]; /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; #ifndef EMBEDDED_LIBRARY - uchar *packet_end= (uchar *) packet + packet_length - 1; + uchar *packet_end= packet + packet_length - 1; #endif Prepared_statement *stmt; bool error; @@ -2273,9 +2270,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) #ifndef EMBEDDED_LIBRARY if (stmt->param_count) { - uchar *null_array= (uchar *) packet; - if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) || - stmt->set_params(stmt, null_array, (uchar *) packet, packet_end, + uchar *null_array= packet; + if (setup_conversion_functions(stmt, &packet, packet_end) || + stmt->set_params(stmt, null_array, packet, packet_end, &expanded_query)) goto set_params_data_err; } @@ -2569,7 +2566,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) uint param_number; Prepared_statement *stmt; Item_param *param; +#ifndef EMBEDDED_LIBRARY char *packet_end= packet + packet_length - 1; +#endif DBUG_ENTER("mysql_stmt_get_longdata"); statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status); @@ -2623,8 +2622,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) Select_fetch_protocol_prep ****************************************************************************/ -Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd) - :protocol(thd) +Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd_arg) + :protocol(thd_arg) {} bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags) @@ -2946,10 +2945,9 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) in INSERT ... SELECT and similar commands. */ - if (open_cursor && lex->result && !lex->result->simple_select()) + if (open_cursor && lex->result && lex->result->check_simple_select()) { DBUG_PRINT("info",("Cursor asked for not SELECT stmt")); - my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0)); return TRUE; } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index c37227e7d28..f34ec83b29c 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 92c8aca0e0c..1a8446a86e9 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha +/* Copyright (C) 2000-2006 MySQL AB & Sasha This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,7 +23,9 @@ int max_binlog_dump_events = 0; // unlimited my_bool opt_sporadic_binlog_dump_fail = 0; +#ifndef DBUG_OFF static int binlog_dump_count = 0; +#endif /* fake_rotate_event() builds a fake (=which does not exist physically in any @@ -93,8 +94,8 @@ static int send_file(THD *thd) The client might be slow loading the data, give him wait_timeout to do the job */ - old_timeout = thd->net.read_timeout; - thd->net.read_timeout = thd->variables.net_wait_timeout; + old_timeout= net->read_timeout; + net_set_read_timeout(net, thd->variables.net_wait_timeout); /* We need net_flush here because the client will not know it needs to send @@ -138,7 +139,7 @@ static int send_file(THD *thd) error = 0; err: - thd->net.read_timeout = old_timeout; + net_set_read_timeout(net, old_timeout); if (fd >= 0) (void) my_close(fd, MYF(0)); if (errmsg) diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 789de64da85..b106391245d 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha +/* Copyright (C) 2000-2006 MySQL AB & Sasha This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c83872293df..f58433cd220 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000-2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -111,7 +110,6 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list, static COND *optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list, Item::cond_result *cond_value); -static bool resolve_nested_join (TABLE_LIST *table); static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); static bool open_tmp_table(TABLE *table); static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, @@ -508,72 +506,88 @@ err: /* - test if it is known for optimisation IN subquery + Remove the predicates pushed down into the subquery SYNOPSIS - JOIN::test_in_subselect() - where - pointer for variable in which conditions should be - stored if subquery is known + JOIN::remove_subq_pushed_predicates() + where IN Must be NULL + OUT The remaining WHERE condition, or NULL - RETURN - 1 - known - 0 - unknown + DESCRIPTION + Given that this join will be executed using (unique|index)_subquery, + without "checking NULL", remove the predicates that were pushed down + into the subquery. + + We can remove the equalities that will be guaranteed to be true by the + fact that subquery engine will be using index lookup. + + If the subquery compares scalar values, we can remove the condition that + was wrapped into trig_cond (it will be checked when needed by the subquery + engine) + + If the subquery compares row values, we need to keep the wrapped + equalities in the WHERE clause: when the left (outer) tuple has both NULL + and non-NULL values, we'll do a full table scan and will rely on the + equalities corresponding to non-NULL parts of left tuple to filter out + non-matching records. */ -bool JOIN::test_in_subselect(Item **where) +void JOIN::remove_subq_pushed_predicates(Item **where) { if (conds->type() == Item::FUNC_ITEM && ((Item_func *)this->conds)->functype() == Item_func::EQ_FUNC && ((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM && ((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM) { - join_tab->info= "Using index"; *where= 0; - return 1; + return; } if (conds->type() == Item::COND_ITEM && ((class Item_func *)this->conds)->functype() == Item_func::COND_AND_FUNC) { - if ((*where= remove_additional_cond(conds))) - join_tab->info= "Using index; Using where"; - else - join_tab->info= "Using index"; - return 1; + *where= remove_additional_cond(conds); } - return 0; } /* - Check if the passed HAVING clause is a clause added by subquery optimizer + Index lookup-based subquery: save some flags for EXPLAIN output SYNOPSIS - is_having_subq_predicates() - having Having clause + save_index_subquery_explain_info() + join_tab Subquery's join tab (there is only one as index lookup is + only used for subqueries that are single-table SELECTs) + where Subquery's WHERE clause - RETURN - TRUE The passed HAVING clause was added by the subquery optimizer - FALSE Otherwise + DESCRIPTION + For index lookup-based subquery (i.e. one executed with + subselect_uniquesubquery_engine or subselect_indexsubquery_engine), + check its EXPLAIN output row should contain + "Using index" (TAB_INFO_FULL_SCAN_ON_NULL) + "Using Where" (TAB_INFO_USING_WHERE) + "Full scan on NULL key" (TAB_INFO_FULL_SCAN_ON_NULL) + and set appropriate flags in join_tab->packed_info. */ -bool is_having_subq_predicates(Item *having) +static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where) { - if (having->type() == Item::FUNC_ITEM) + join_tab->packed_info= TAB_INFO_HAVE_VALUE; + if (join_tab->table->used_keys.is_set(join_tab->ref.key)) + join_tab->packed_info |= TAB_INFO_USING_INDEX; + if (where) + join_tab->packed_info |= TAB_INFO_USING_WHERE; + for (uint i = 0; i < join_tab->ref.key_parts; i++) { - if (((Item_func *) having)->functype() == Item_func::ISNOTNULLTEST_FUNC) - return TRUE; - if (((Item_func *) having)->functype() == Item_func::TRIG_COND_FUNC) + if (join_tab->ref.cond_guards[i]) { - having= ((Item_func*)having)->arguments()[0]; - if (((Item_func *) having)->functype() == Item_func::ISNOTNULLTEST_FUNC) - return TRUE; + join_tab->packed_info |= TAB_INFO_FULL_SCAN_ON_NULL; + break; } - return TRUE; } - return FALSE; } + /* global select optimisation. return 0 - success @@ -703,11 +717,20 @@ JOIN::optimize() { int res; /* - opt_sum_query() returns -1 if no rows match to the WHERE conditions, - or 1 if all items were resolved, or 0, or an error number HA_ERR_... + opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match + to the WHERE conditions, + or 1 if all items were resolved, + or 0, or an error number HA_ERR_... */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { + if (res == HA_ERR_KEY_NOT_FOUND) + { + DBUG_PRINT("info",("No matching min/max row")); + zero_result_cause= "No matching min/max row"; + error=0; + DBUG_RETURN(0); + } if (res > 1) { thd->fatal_error(); @@ -715,13 +738,6 @@ JOIN::optimize() DBUG_PRINT("error",("Error from opt_sum_query")); DBUG_RETURN(1); } - if (res < 0) - { - DBUG_PRINT("info",("No matching min/max row")); - zero_result_cause= "No matching min/max row"; - error=0; - DBUG_RETURN(0); - } DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved @@ -851,6 +867,13 @@ JOIN::optimize() { ORDER *org_order= order; order=remove_const(this, order,conds,1, &simple_order); + if (thd->net.report_error) + { + error= 1; + DBUG_PRINT("error",("Error from remove_const")); + DBUG_RETURN(1); + } + /* If we are using ORDER BY NULL or ORDER BY const_expression, return result in any order (even if we are using a GROUP BY) @@ -860,10 +883,11 @@ JOIN::optimize() } /* Check if we can optimize away GROUP BY/DISTINCT. - We can do that if there are no aggregate functions and the + We can do that if there are no aggregate functions, the fields in DISTINCT clause (if present) and/or columns in GROUP BY (if present) contain direct references to all key parts of - an unique index (in whatever order). + an unique index (in whatever order) and if the key parts of the + unique index cannot contain NULLs. Note that the unique keys for DISTINCT and GROUP BY should not be the same (as long as they are unique). @@ -958,6 +982,12 @@ JOIN::optimize() group_list= remove_const(this, (old_group_list= group_list), conds, rollup.state == ROLLUP::STATE_NONE, &simple_group); + if (thd->net.report_error) + { + error= 1; + DBUG_PRINT("error",("Error from remove_const")); + DBUG_RETURN(1); + } if (old_group_list && !group_list) select_distinct= 0; } @@ -974,6 +1004,12 @@ JOIN::optimize() { group_list= procedure->group= remove_const(this, procedure->group, conds, 1, &simple_group); + if (thd->net.report_error) + { + error= 1; + DBUG_PRINT("error",("Error from remove_const")); + DBUG_RETURN(1); + } calc_group_buffer(this, group_list); } @@ -1029,51 +1065,47 @@ JOIN::optimize() if (join_tab[0].type == JT_EQ_REF && join_tab[0].ref.items[0]->name == in_left_expr_name) { - if (test_in_subselect(&where)) - { - join_tab[0].type= JT_UNIQUE_SUBQUERY; - error= 0; - DBUG_RETURN(unit->item-> - change_engine(new - subselect_uniquesubquery_engine(thd, - join_tab, - unit->item, - where))); - } + remove_subq_pushed_predicates(&where); + save_index_subquery_explain_info(join_tab, where); + join_tab[0].type= JT_UNIQUE_SUBQUERY; + error= 0; + DBUG_RETURN(unit->item-> + change_engine(new + subselect_uniquesubquery_engine(thd, + join_tab, + unit->item, + where))); } else if (join_tab[0].type == JT_REF && join_tab[0].ref.items[0]->name == in_left_expr_name) { - if (test_in_subselect(&where)) - { - join_tab[0].type= JT_INDEX_SUBQUERY; - error= 0; - DBUG_RETURN(unit->item-> - change_engine(new - subselect_indexsubquery_engine(thd, - join_tab, - unit->item, - where, - 0))); - } + remove_subq_pushed_predicates(&where); + save_index_subquery_explain_info(join_tab, where); + join_tab[0].type= JT_INDEX_SUBQUERY; + error= 0; + DBUG_RETURN(unit->item-> + change_engine(new + subselect_indexsubquery_engine(thd, + join_tab, + unit->item, + where, + NULL, + 0))); } } else if (join_tab[0].type == JT_REF_OR_NULL && join_tab[0].ref.items[0]->name == in_left_expr_name && - is_having_subq_predicates(having)) + having->name == in_having_cond) { join_tab[0].type= JT_INDEX_SUBQUERY; error= 0; - - if ((conds= remove_additional_cond(conds))) - join_tab->info= "Using index; Using where"; - else - join_tab->info= "Using index"; - + conds= remove_additional_cond(conds); + save_index_subquery_explain_info(join_tab, conds); DBUG_RETURN(unit->item-> change_engine(new subselect_indexsubquery_engine(thd, join_tab, unit->item, conds, + having, 1))); } @@ -1476,7 +1508,7 @@ JOIN::exec() if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) && !thd->lex->describe && - get_schema_tables_result(curr_join)) + get_schema_tables_result(curr_join, PROCESSED_BY_JOIN_EXEC)) { DBUG_VOID_RETURN; } @@ -2199,7 +2231,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, s->key_dependent= 0; if (tables->schema_table) table->file->stats.records= 2; - table->quick_condition_rows= table->file->records(); + table->quick_condition_rows= table->file->stats.records; s->on_expr_ref= &tables->on_expr; if (*s->on_expr_ref) @@ -2335,8 +2367,18 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, substitution of a const table the key value happens to be null then we can state that there are no matches for this equi-join. */ - if ((keyuse= s->keyuse) && *s->on_expr_ref) + if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map) { + /* + When performing an outer join operation if there are no matching rows + for the single row of the outer table all the inner tables are to be + null complemented and thus considered as constant tables. + Here we apply this consideration to the case of outer join operations + with a single inner table only because the case with nested tables + would require a more thorough analysis. + TODO. Apply single row substitution to null complemented inner tables + for nested outer join operations. + */ while (keyuse->table == table) { if (!(keyuse->val->used_tables() & ~join->const_table_map) && @@ -2449,14 +2491,14 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, for( ; sargables->field ; sargables++) { Field *field= sargables->field; - JOIN_TAB *stat= field->table->reginfo.join_tab; + JOIN_TAB *join_tab= field->table->reginfo.join_tab; key_map possible_keys= field->key_start; possible_keys.intersect(field->table->keys_in_use_for_query); bool is_const= 1; - for (uint i=0; i< sargables->num_values; i++) - is_const&= sargables->arg_value[i]->const_item(); + for (uint j=0; j < sargables->num_values; j++) + is_const&= sargables->arg_value[j]->const_item(); if (is_const) - stat[0].const_keys.merge(possible_keys); + join_tab[0].const_keys.merge(possible_keys); } } @@ -2577,9 +2619,7 @@ typedef struct key_field_t { // Used when finding key fields when val IS NULL. */ bool null_rejecting; - - /* TRUE<=> This ref access is an outer subquery reference access */ - bool outer_ref; + bool *cond_guard; /* See KEYUSE::cond_guard */ } KEY_FIELD; /* Values in optimize */ @@ -2881,7 +2921,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, cond->functype() == Item_func::MULT_EQUAL_FUNC) && ((*value)->type() == Item::FIELD_ITEM) && ((Item_field*)*value)->field->maybe_null()); - (*key_fields)->outer_ref= FALSE; + (*key_fields)->cond_guard= NULL; (*key_fields)++; } @@ -2978,25 +3018,26 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, } /* - Subquery optimization: check if the encountered condition is one - added by condition push down into subquery. + Subquery optimization: Conditions that are pushed down into subqueries + are wrapped into Item_func_trig_cond. We process the wrapped condition + but need to set cond_guard for KEYUSE elements generated from it. */ { if (cond->type() == Item::FUNC_ITEM && ((Item_func*)cond)->functype() == Item_func::TRIG_COND_FUNC) { - cond= ((Item_func*)cond)->arguments()[0]; + Item *cond_arg= ((Item_func*)cond)->arguments()[0]; if (!join->group_list && !join->order && join->unit->item && join->unit->item->substype() == Item_subselect::IN_SUBS && !join->unit->first_select()->next_select()) { KEY_FIELD *save= *key_fields; - add_key_fields(join, key_fields, and_level, cond, usable_tables, + add_key_fields(join, key_fields, and_level, cond_arg, usable_tables, sargables); // Indicate that this ref access candidate is for subquery lookup: for (; save != *key_fields; save++) - save->outer_ref= TRUE; + save->cond_guard= ((Item_func_trig_cond*)cond)->get_trig_var(); } return; } @@ -3176,7 +3217,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) keyuse.used_tables=key_field->val->used_tables(); keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL; keyuse.null_rejecting= key_field->null_rejecting; - keyuse.outer_ref= key_field->outer_ref; + keyuse.cond_guard= key_field->cond_guard; VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } } @@ -3453,16 +3494,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, */ if (keyuse->elements) { - KEYUSE end,*prev,*save_pos,*use; + KEYUSE key_end,*prev,*save_pos,*use; qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), (qsort_cmp) sort_keyuse); - bzero((char*) &end,sizeof(end)); /* Add for easy testing */ - VOID(insert_dynamic(keyuse,(gptr) &end)); + bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */ + VOID(insert_dynamic(keyuse,(gptr) &key_end)); use=save_pos=dynamic_element(keyuse,0,KEYUSE*); - prev=&end; + prev= &key_end; found_eq_constant=0; for (i=0 ; i < keyuse->elements-1 ; i++,use++) { @@ -3480,7 +3521,11 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, continue; } - *save_pos= *use; +#ifdef HAVE_purify + /* Valgrind complains about overlapped memcpy when save_pos==use. */ + if (save_pos != use) +#endif + *save_pos= *use; prev=use; found_eq_constant= !use->used_tables; /* Save ptr to first use */ @@ -3490,7 +3535,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, save_pos++; } i=(uint) (save_pos-(KEYUSE*) keyuse->buffer); - VOID(set_dynamic(keyuse,(gptr) &end,i)); + VOID(set_dynamic(keyuse,(gptr) &key_end,i)); keyuse->elements=i; } return FALSE; @@ -3675,7 +3720,6 @@ best_access_path(JOIN *join, table_map best_ref_depends_map= 0; double tmp; ha_rows rec; - DBUG_ENTER("best_access_path"); if (s->keyuse) @@ -3723,12 +3767,12 @@ best_access_path(JOIN *join, if (!(keyuse->used_tables & ~join->const_table_map)) const_part|= keyuse->keypart_map; - double tmp= prev_record_reads(join, idx, (found_ref | + double tmp2= prev_record_reads(join, idx, (found_ref | keyuse->used_tables)); - if (tmp < best_prev_record_reads) + if (tmp2 < best_prev_record_reads) { best_part_found_ref= keyuse->used_tables & ~join->const_table_map; - best_prev_record_reads= tmp; + best_prev_record_reads= tmp2; } if (rec > keyuse->ref_table_rows) rec= keyuse->ref_table_rows; @@ -5136,7 +5180,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) || !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) * (keyparts+1)))) || - !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts))) + !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)) || + !(j->ref.cond_guards= (bool**) thd->alloc(sizeof(uint*)*keyparts))) { DBUG_RETURN(TRUE); } @@ -5151,6 +5196,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, if (ftkey) { j->ref.items[0]=((Item_func*)(keyuse->val))->key_item(); + /* Predicates pushed down into subquery can't be used FT access */ + j->ref.cond_guards[0]= NULL; if (keyuse->used_tables) DBUG_RETURN(TRUE); // not supported yet. SerG @@ -5167,6 +5214,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, uint maybe_null= test(keyinfo->key_part[i].null_bit); j->ref.items[i]=keyuse->val; // Save for cond removal + j->ref.cond_guards[i]= keyuse->cond_guard; if (keyuse->null_rejecting) j->ref.null_rejecting |= 1 << i; keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables; @@ -5894,37 +5942,42 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) */ COND *on_expr= *first_inner_tab->on_expr_ref; - table_map used_tables= join->const_table_map | - OUTER_REF_TABLE_BIT | RAND_TABLE_BIT; + table_map used_tables2= (join->const_table_map | + OUTER_REF_TABLE_BIT | RAND_TABLE_BIT); for (tab= join->join_tab+join->const_tables; tab <= last_tab ; tab++) { current_map= tab->table->map; - used_tables|= current_map; - COND *tmp= make_cond_for_table(on_expr, used_tables, current_map); - if (tmp) + used_tables2|= current_map; + COND *tmp_cond= make_cond_for_table(on_expr, used_tables2, + current_map); + if (tmp_cond) { JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab; /* First add the guards for match variables of all embedding outer join operations. */ - if (!(tmp= add_found_match_trig_cond(cond_tab->first_inner, - tmp, first_inner_tab))) + if (!(tmp_cond= add_found_match_trig_cond(cond_tab->first_inner, + tmp_cond, + first_inner_tab))) DBUG_RETURN(1); /* Now add the guard turning the predicate off for the null complemented row. */ DBUG_PRINT("info", ("Item_func_trig_cond")); - tmp= new Item_func_trig_cond(tmp, - &first_inner_tab->not_null_compl); - DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp)); - if (tmp) - tmp->quick_fix_field(); + tmp_cond= new Item_func_trig_cond(tmp_cond, + &first_inner_tab-> + not_null_compl); + DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", + (ulong) tmp_cond)); + if (tmp_cond) + tmp_cond->quick_fix_field(); /* Add the predicate to other pushed down predicates */ DBUG_PRINT("info", ("Item_cond_and")); - cond_tab->select_cond= !cond_tab->select_cond ? tmp : - new Item_cond_and(cond_tab->select_cond,tmp); + cond_tab->select_cond= !cond_tab->select_cond ? tmp_cond : + new Item_cond_and(cond_tab->select_cond, + tmp_cond); DBUG_PRINT("info", ("Item_cond_and 0x%lx", (ulong)cond_tab->select_cond)); if (!cond_tab->select_cond) @@ -6243,7 +6296,7 @@ void JOIN_TAB::cleanup() void JOIN::join_free() { - SELECT_LEX_UNIT *unit; + SELECT_LEX_UNIT *tmp_unit; SELECT_LEX *sl; /* Optimization: if not EXPLAIN and we are done with the JOIN, @@ -6255,8 +6308,10 @@ void JOIN::join_free() cleanup(full); - for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit()) - for (sl= unit->first_select(); sl; sl= sl->next_select()) + for (tmp_unit= select_lex->first_inner_unit(); + tmp_unit; + tmp_unit= tmp_unit->next_unit()) + for (sl= tmp_unit->first_select(); sl; sl= sl->next_select()) { Item_subselect *subselect= sl->master_unit()->item; bool full_local= full && (!subselect || subselect->is_evaluated()); @@ -6555,6 +6610,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, *simple_order=0; // Must do a temp table to sort else if (!(order_tables & not_const_tables)) { + if (order->item[0]->with_subselect) + order->item[0]->val_str(&order->item[0]->str_value); DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; // skip const item } @@ -6892,9 +6949,9 @@ static bool check_simple_equality(Item *left_item, Item *right_item, else { /* None of the fields was found in multiple equalities */ - Item_equal *item= new Item_equal((Item_field *) left_item, - (Item_field *) right_item); - cond_equal->current_level.push_back(item); + Item_equal *item_equal= new Item_equal((Item_field *) left_item, + (Item_field *) right_item); + cond_equal->current_level.push_back(item_equal); } } return TRUE; @@ -7001,8 +7058,8 @@ static bool check_row_equality(Item *left_row, Item_row *right_row, for (uint i= 0 ; i < n; i++) { bool is_converted; - Item *left_item= left_row->el(i); - Item *right_item= right_row->el(i); + Item *left_item= left_row->element_index(i); + Item *right_item= right_row->element_index(i); if (left_item->type() == Item::ROW_ITEM && right_item->type() == Item::ROW_ITEM) is_converted= check_row_equality((Item_row *) left_item, @@ -7392,14 +7449,15 @@ static COND *build_equal_items(THD *thd, COND *cond, { if (table->on_expr) { - List<TABLE_LIST> *join_list= table->nested_join ? - &table->nested_join->join_list : NULL; + List<TABLE_LIST> *nested_join_list= table->nested_join ? + &table->nested_join->join_list : NULL; /* We can modify table->on_expr because its old value will be restored before re-execution of PS/SP. */ table->on_expr= build_equal_items(thd, table->on_expr, inherited, - join_list, &table->cond_equal); + nested_join_list, + &table->cond_equal); } } } @@ -7714,6 +7772,22 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab) key_map possible_keys= field->key_start; possible_keys.intersect(field->table->keys_in_use_for_query); stat[0].const_keys.merge(possible_keys); + + /* + For each field in the multiple equality (for which we know that it + is a constant) we have to find its corresponding key part, and set + that key part in const_key_parts. + */ + if (!possible_keys.is_clear_all()) + { + TABLE *tab= field->table; + KEYUSE *use; + for (use= stat->keyuse; use && use->table == tab; use++) + if (possible_keys.is_set(use->key) && + tab->key_info[use->key].key_part[use->keypart].field == + field) + tab->const_key_parts[use->key]|= use->keypart_map; + } } } } @@ -7756,7 +7830,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, value->result_type() != STRING_RESULT || left_item->collation.collation == value->collation.collation)) { - Item *tmp=value->new_item(); + Item *tmp=value->clone_item(); tmp->collation.set(right_item->collation); if (tmp) @@ -7780,7 +7854,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, value->result_type() != STRING_RESULT || right_item->collation.collation == value->collation.collation)) { - Item *tmp=value->new_item(); + Item *tmp= value->clone_item(); tmp->collation.set(left_item->collation); if (tmp) @@ -7808,7 +7882,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, SYNOPSIS remove_additional_cond() - conds - condition for processing + conds Condition for processing RETURN VALUES new conditions @@ -8191,7 +8265,7 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list, */ if (nested_join->join_list.elements != 1) { - nested_join->nj_map= 1 << first_unused++; + nested_join->nj_map= (nested_join_map) 1 << first_unused++; first_unused= build_bitmap_for_nested_joins(&nested_join->join_list, first_unused); } @@ -8401,7 +8475,6 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list, Item::cond_result *cond_value) { THD *thd= join->thd; - SELECT_LEX *select= thd->lex->current_select; DBUG_ENTER("optimize_cond"); if (!conds) @@ -8551,8 +8624,8 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) thd->substitute_null_with_insert_id= FALSE; } /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */ - else if (((field->type() == FIELD_TYPE_DATE) || - (field->type() == FIELD_TYPE_DATETIME)) && + else if (((field->type() == MYSQL_TYPE_DATE) || + (field->type() == MYSQL_TYPE_DATETIME)) && (field->flags & NOT_NULL_FLAG) && !field->table->maybe_null) { @@ -8595,6 +8668,46 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) return cond; // Point at next and level } +/* + Check if equality can be used in removing components of GROUP BY/DISTINCT + + SYNOPSIS + test_if_equality_guarantees_uniqueness() + l the left comparison argument (a field if any) + r the right comparison argument (a const of any) + + DESCRIPTION + Checks if an equality predicate can be used to take away + DISTINCT/GROUP BY because it is known to be true for exactly one + distinct value (e.g. <expr> == <const>). + Arguments must be of the same type because e.g. + <string_field> = <int_const> may match more than 1 distinct value from + the column. + We must take into consideration and the optimization done for various + string constants when compared to dates etc (see Item_int_with_ref) as + well as the collation of the arguments. + + RETURN VALUE + TRUE can be used + FALSE cannot be used +*/ +static bool +test_if_equality_guarantees_uniqueness(Item *l, Item *r) +{ + return r->const_item() && + /* elements must be of the same result type */ + (r->result_type() == l->result_type() || + /* or dates compared to longs */ + (((l->type() == Item::FIELD_ITEM && + ((Item_field *)l)->field->can_be_compared_as_longlong()) || + (l->type() == Item::FUNC_ITEM && + ((Item_func *)l)->result_as_longlong())) && + r->result_type() == INT_RESULT)) + /* and must have the same collation if compared as strings */ + && (l->result_type() != STRING_RESULT || + l->collation.collation == r->collation.collation); +} + /* Return 1 if the item is a const value in all the WHERE clause */ @@ -8631,7 +8744,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) Item *right_item= ((Item_func*) cond)->arguments()[1]; if (left_item->eq(comp_item,1)) { - if (right_item->const_item()) + if (test_if_equality_guarantees_uniqueness (left_item, right_item)) { if (*const_item) return right_item->eq(*const_item, 1); @@ -8641,7 +8754,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) } else if (right_item->eq(comp_item,1)) { - if (left_item->const_item()) + if (test_if_equality_guarantees_uniqueness (right_item, left_item)) { if (*const_item) return left_item->eq(*const_item, 1); @@ -8713,6 +8826,8 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, if (org_field->type() == MYSQL_TYPE_VAR_STRING || org_field->type() == MYSQL_TYPE_VARCHAR) table->s->db_create_options|= HA_OPTION_PACK_RECORD; + else if (org_field->type() == FIELD_TYPE_DOUBLE) + ((Field_double *) new_field)->not_fixed= TRUE; } return new_field; } @@ -8753,7 +8868,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, switch (item->result_type()) { case REAL_RESULT: new_field= new Field_double(item->max_length, maybe_null, - item->name, item->decimals); + item->name, item->decimals, TRUE); break; case INT_RESULT: /* Select an integer type with the minimal fit precision */ @@ -8890,8 +9005,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, if (type != Item::FIELD_ITEM && item->real_item()->type() == Item::FIELD_ITEM && - (item->type() != Item::REF_ITEM || - !((Item_ref *) item)->depended_from)) + !((Item_ref *) item)->depended_from) { orig_item= item; item= item->real_item(); @@ -8927,7 +9041,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, field->result_field= result; } else if (table_cant_handle_bit_fields && field->field->type() == - FIELD_TYPE_BIT) + MYSQL_TYPE_BIT) { *from_field= field->field; result= create_tmp_field_from_item(thd, item, table, copy_func, @@ -9053,7 +9167,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, uint hidden_null_count, hidden_null_pack_length, hidden_field_count; uint blob_count,group_null_items, string_count; uint temp_pool_slot=MY_BIT_NONE; - ulong reclength, string_total_length, fieldnr= 0; + uint fieldnr= 0; + ulong reclength, string_total_length; bool using_unique_constraint= 0; bool use_packed_rows= 0; bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS); @@ -9244,7 +9359,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *blob_field++= fieldnr; blob_count++; } - if (new_field->type() == FIELD_TYPE_BIT) + if (new_field->type() == MYSQL_TYPE_BIT) total_uneven_bit_length+= new_field->field_length & 7; *(reg_field++)= new_field; if (new_field->real_type() == MYSQL_TYPE_STRING || @@ -9306,7 +9421,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, reclength+=new_field->pack_length(); if (!(new_field->flags & NOT_NULL_FLAG)) null_count++; - if (new_field->type() == FIELD_TYPE_BIT) + if (new_field->type() == MYSQL_TYPE_BIT) total_uneven_bit_length+= new_field->field_length & 7; if (new_field->flags & BLOB_FLAG) { @@ -9451,7 +9566,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } else field->move_field((char*) pos,(uchar*) 0,0); - if (field->type() == FIELD_TYPE_BIT) + if (field->type() == MYSQL_TYPE_BIT) { /* We have to reserve place for extra bits among null bits */ ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8, @@ -10219,7 +10334,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) else { DBUG_ASSERT(join->tables); - DBUG_ASSERT(join_tab); error= sub_select(join,join_tab,0); if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) error= sub_select(join,join_tab,1); @@ -10598,6 +10712,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, */ join->examined_rows++; join->thd->row_count++; + join_tab->read_record.file->unlock_row(); } return NESTED_LOOP_OK; } @@ -11081,7 +11196,9 @@ int rr_sequential(READ_RECORD *info); int init_read_record_seq(JOIN_TAB *tab) { tab->read_record.read_record= rr_sequential; - return tab->read_record.file->ha_rnd_init(1); + if (tab->read_record.file->ha_rnd_init(1)) + return 1; + return (*tab->read_record.read_record)(&tab->read_record); } static int @@ -11747,7 +11864,7 @@ static bool test_if_ref(Item_field *left_item,Item *right_item) if (field->binary() && field->real_type() != MYSQL_TYPE_STRING && field->real_type() != MYSQL_TYPE_VARCHAR && - (field->type() != FIELD_TYPE_FLOAT || field->decimals() == 0)) + (field->type() != MYSQL_TYPE_FLOAT || field->decimals() == 0)) { return !store_val_in_field(field, right_item, CHECK_FIELD_WARN); } @@ -12026,7 +12143,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, /* - Check if GROUP BY/DISTINCT can be optimized away because the set is + Check if GROUP BY/DISTINCT can be optimized away because the set is already known to be distinct. SYNOPSIS @@ -12034,7 +12151,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, table The table to operate on. find_func function to iterate over the list and search for a field - + DESCRIPTION Used in removing the GROUP BY/DISTINCT of the following types of statements: @@ -12045,12 +12162,13 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, then <any combination of a,b,c>,{whatever} is also distinct This function checks if all the key parts of any of the unique keys - of the table are referenced by a list : either the select list + of the table are referenced by a list : either the select list through find_field_in_item_list or GROUP BY list through find_field_in_order_list. - If the above holds then we can safely remove the GROUP BY/DISTINCT, + If the above holds and the key parts cannot contain NULLs then we + can safely remove the GROUP BY/DISTINCT, as no result set can be more distinct than an unique key. - + RETURN VALUE 1 found 0 not found. @@ -12073,7 +12191,8 @@ list_contains_unique_index(TABLE *table, key_part < key_part_end; key_part++) { - if (!find_func(key_part->field, data)) + if (key_part->field->maybe_null() || + !find_func(key_part->field, data)) break; } if (key_part == key_part_end) @@ -12181,13 +12300,14 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, DBUG_ENTER("test_if_skip_sort_order"); LINT_INIT(ref_key_parts); + /* Check which keys can be used to resolve ORDER BY. */ + usable_keys= table->keys_in_use_for_query; + /* - Check which keys can be used to resolve ORDER BY. - We must not try to use disabled keys. + Keys disabled by ALTER TABLE ... DISABLE KEYS should have already + been taken into account. */ - usable_keys= table->s->keys_in_use; - /* we must not consider keys that are disabled by IGNORE INDEX */ - usable_keys.intersect(table->keys_in_use_for_query); + DBUG_ASSERT(usable_keys.is_subset(table->s->keys_in_use)); for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { @@ -12435,7 +12555,7 @@ static int create_sort_index(THD *thd, JOIN *join, ORDER *order, ha_rows filesort_limit, ha_rows select_limit) { - uint length; + uint length= 0; ha_rows examined_rows; TABLE *table; SQL_SELECT *select; @@ -12456,8 +12576,10 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, !(join->select_options & SELECT_BIG_RESULT)) && test_if_skip_sort_order(tab,order,select_limit,0)) DBUG_RETURN(0); + for (ORDER *ord= join->order; ord; ord= ord->next) + length++; if (!(join->sortorder= - make_unireg_sortorder(order,&length,join->sortorder))) + make_unireg_sortorder(order, &length, join->sortorder))) goto err; /* purecov: inspected */ table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), @@ -12500,7 +12622,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, /* Fill schema tables with data before filesort if it's necessary */ if ((join->select_lex->options & OPTION_SCHEMA_TABLE) && !thd->lex->describe && - get_schema_tables_result(join)) + get_schema_tables_result(join, PROCESSED_BY_CREATE_SORT_INDEX)) goto err; if (table->s->tmp_table) @@ -12865,22 +12987,24 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length, for (ORDER *tmp = order; tmp; tmp=tmp->next) count++; if (!sortorder) - sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1)); - pos=sort=sortorder; + sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD) * + (max(count, *length) + 1)); + pos= sort= sortorder; + if (!pos) return 0; for (;order;order=order->next,pos++) { - pos->field=0; pos->item=0; - if (order->item[0]->type() == Item::FIELD_ITEM) - pos->field= ((Item_field*) (*order->item))->field; - else if (order->item[0]->type() == Item::SUM_FUNC_ITEM && - !order->item[0]->const_item()) - pos->field= ((Item_sum*) order->item[0])->get_tmp_table_field(); - else if (order->item[0]->type() == Item::COPY_STR_ITEM) + Item *item= order->item[0]->real_item(); + pos->field= 0; pos->item= 0; + if (item->type() == Item::FIELD_ITEM) + pos->field= ((Item_field*) item)->field; + else if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item()) + pos->field= ((Item_sum*) item)->get_tmp_table_field(); + else if (item->type() == Item::COPY_STR_ITEM) { // Blob patch - pos->item= ((Item_copy_string*) (*order->item))->item; + pos->item= ((Item_copy_string*) item)->item; } else pos->item= *order->item; @@ -13394,49 +13518,83 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, bool *hidden_group_fields) { *hidden_group_fields=0; + ORDER *ord; + if (!order) return 0; /* Everything is ok */ - if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) - { - Item *item; - List_iterator<Item> li(fields); - while ((item=li++)) - item->marker=0; /* Marker that field is not used */ - } uint org_fields=all_fields.elements; thd->where="group statement"; - for (; order; order=order->next) + for (ord= order; ord; ord= ord->next) { - if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, + if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields, all_fields, TRUE)) return 1; - (*order->item)->marker=1; /* Mark found */ - if ((*order->item)->with_sum_func) + (*ord->item)->marker= UNDEF_POS; /* Mark found */ + if ((*ord->item)->with_sum_func) { - my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*order->item)->full_name()); + my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name()); return 1; } } if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) { - /* Don't allow one to use fields that is not used in GROUP BY */ + /* + Don't allow one to use fields that is not used in GROUP BY + For each select a list of field references that aren't under an + aggregate function is created. Each field in this list keeps the + position of the select list expression which it belongs to. + + First we check an expression from the select list against the GROUP BY + list. If it's found there then it's ok. It's also ok if this expression + is a constant or an aggregate function. Otherwise we scan the list + of non-aggregated fields and if we'll find at least one field reference + that belongs to this expression and doesn't occur in the GROUP BY list + we throw an error. If there are no fields in the created list for a + select list expression this means that all fields in it are used under + aggregate functions. + */ Item *item; + Item_field *field; + int cur_pos_in_select_list= 0; List_iterator<Item> li(fields); + List_iterator<Item_field> naf_it(thd->lex->current_select->non_agg_fields); - while ((item=li++)) + field= naf_it++; + while (field && (item=li++)) { - if (item->type() != Item::SUM_FUNC_ITEM && !item->marker && - !item->const_item()) + if (item->type() != Item::SUM_FUNC_ITEM && item->marker >= 0 && + !item->const_item() && + !(item->real_item()->type() == Item::FIELD_ITEM && + item->used_tables() & OUTER_REF_TABLE_BIT)) { - /* - TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed - ER_NON_GROUPING_FIELD_USED - */ - my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), item->full_name()); - return 1; + while (field) + { + /* Skip fields from previous expressions. */ + if (field->marker < cur_pos_in_select_list) + goto next_field; + /* Found a field from the next expression. */ + if (field->marker > cur_pos_in_select_list) + break; + /* + Check whether the field occur in the GROUP BY list. + Throw the error later if the field isn't found. + */ + for (ord= order; ord; ord= ord->next) + if ((*ord->item)->eq((Item*)field, 0)) + goto next_field; + /* + TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed + ER_NON_GROUPING_FIELD_USED + */ + my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), field->full_name()); + return 1; +next_field: + field= naf_it++; + } } + cur_pos_in_select_list++; } } if (org_fields != all_fields.elements) @@ -13562,10 +13720,12 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, param->quick_group=1; while ((field=li++)) { - Item::Type type=field->real_item()->type(); - if (type == Item::FIELD_ITEM) + Item::Type type=field->type(); + Item::Type real_type= field->real_item()->type(); + if (type == Item::FIELD_ITEM || (real_type == Item::FIELD_ITEM && + !((Item_ref *) field)->depended_from)) param->field_count++; - else if (type == Item::SUM_FUNC_ITEM) + else if (real_type == Item::SUM_FUNC_ITEM) { if (! field->const_item()) { @@ -13662,11 +13822,11 @@ calc_group_buffer(JOIN *join,ORDER *group) if (field) { enum_field_types type; - if ((type= field->type()) == FIELD_TYPE_BLOB) + if ((type= field->type()) == MYSQL_TYPE_BLOB) key_length+=MAX_BLOB_WIDTH; // Can't be used as a key else if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_VAR_STRING) key_length+= field->field_length + HA_KEY_BLOB_LENGTH; - else if (type == FIELD_TYPE_BIT) + else if (type == MYSQL_TYPE_BIT) { /* Bit is usually stored as a longlong key for group fields */ key_length+= 8; // Big enough @@ -14703,7 +14863,7 @@ int JOIN::rollup_send_data(uint idx) 1 if write_data_failed() */ -int JOIN::rollup_write_data(uint idx, TABLE *table) +int JOIN::rollup_write_data(uint idx, TABLE *table_arg) { uint i; for (i= send_group_parts ; i-- > idx ; ) @@ -14714,7 +14874,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table) ref_pointer_array_size); if ((!having || having->val_int())) { - int error; + int write_error; Item *item; List_iterator_fast<Item> it(rollup.fields[i]); while ((item= it++)) @@ -14723,10 +14883,10 @@ int JOIN::rollup_write_data(uint idx, TABLE *table) item->save_in_result_field(1); } copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]); - if ((error= table->file->write_row(table->record[0]))) + if ((write_error= table_arg->file->write_row(table_arg->record[0]))) { - if (create_myisam_from_heap(thd, table, &tmp_table_param, - error, 0)) + if (create_myisam_from_heap(thd, table_arg, &tmp_table_param, + write_error, 0)) return 1; } } @@ -14922,9 +15082,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, } else { - TABLE_LIST *tab=table->pos_in_table_list; - item_list.push_back(new Item_string(tab->alias, - strlen(tab->alias), + TABLE_LIST *real_table= table->pos_in_table_list; + item_list.push_back(new Item_string(real_table->alias, + strlen(real_table->alias), cs)); } /* "partitions" column */ @@ -15037,7 +15197,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, Item_float *filtered; float f; if (examined_rows) - f= 100.0 * join->best_positions[i].records_read / examined_rows; + f= (float) (100.0 * join->best_positions[i].records_read / + examined_rows); else f= 0.0; item_list.push_back((filtered= new Item_float(f))); @@ -15056,6 +15217,24 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (tab->info) item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs)); + else if (tab->packed_info & TAB_INFO_HAVE_VALUE) + { + if (tab->packed_info & TAB_INFO_USING_INDEX) + extra.append(STRING_WITH_LEN("; Using index")); + if (tab->packed_info & TAB_INFO_USING_WHERE) + extra.append(STRING_WITH_LEN("; Using where")); + if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL) + extra.append(STRING_WITH_LEN("; Full scan on NULL key")); + /* Skip initial "; "*/ + const char *str= extra.ptr(); + uint32 len= extra.length(); + if (len) + { + str += 2; + len -= 2; + } + item_list.push_back(new Item_string(str, len, cs)); + } else { if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || @@ -15114,6 +15293,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, } if (distinct & test_all_bits(used_tables,thd->used_tables)) extra.append(STRING_WITH_LEN("; Distinct")); + + for (uint part= 0; part < tab->ref.key_parts; part++) + { + if (tab->ref.cond_guards[part]) + { + extra.append(STRING_WITH_LEN("; Full scan on NULL key")); + break; + } + } /* Skip initial "; "*/ const char *str= extra.ptr(); diff --git a/sql/sql_select.h b/sql/sql_select.h index 323df568271..1d1fa666c60 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -36,8 +35,17 @@ typedef struct keyuse_t { satisfied if val has NULL 'value'. */ bool null_rejecting; - /* TRUE<=> This ref access is an outer subquery reference access */ - bool outer_ref; + /* + !NULL - This KEYUSE was created from an equality that was wrapped into + an Item_func_trig_cond. This means the equality (and validity of + this KEYUSE element) can be turned on and off. The on/off state + is indicted by the pointed value: + *cond_guard == TRUE <=> equality condition is on + *cond_guard == FALSE <=> equality condition is off + + NULL - Otherwise (the source equality can't be turned off) + */ + bool *cond_guard; } KEYUSE; class store_key; @@ -52,6 +60,18 @@ typedef struct st_table_ref byte *key_buff2; // key_buff+key_length store_key **key_copy; // Item **items; // val()'s for each keypart + /* + Array of pointers to trigger variables. Some/all of the pointers may be + NULL. The ref access can be used iff + + for each used key part i, (!cond_guards[i] || *cond_guards[i]) + + This array is used by subquery code. The subquery code may inject + triggered conditions, i.e. conditions that can be 'switched off'. A ref + access created from such condition is not valid when at least one of the + underlying conditions is switched off (see subquery code for more details) + */ + bool **cond_guards; /* (null_rejecting & (1<<i)) means the condition is '=' and no matching rows will be produced if items[i] IS NULL (see add_not_null_conds()) @@ -100,6 +120,13 @@ enum enum_nested_loop_state NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4 }; + +/* Values for JOIN_TAB::packed_info */ +#define TAB_INFO_HAVE_VALUE 1 +#define TAB_INFO_USING_INDEX 2 +#define TAB_INFO_USING_WHERE 4 +#define TAB_INFO_FULL_SCAN_ON_NULL 8 + typedef enum_nested_loop_state (*Next_select_func)(JOIN *, struct st_join_table *, bool); typedef int (*Read_record_func)(struct st_join_table *tab); @@ -121,7 +148,15 @@ typedef struct st_join_table { st_join_table *last_inner; /* last table table for embedding outer join */ st_join_table *first_upper; /* first inner table for embedding outer join */ st_join_table *first_unmatched; /* used for optimization purposes only */ + + /* Special content for EXPLAIN 'Extra' column or NULL if none */ const char *info; + /* + Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra' + column, or 0 if there is no info. + */ + uint packed_info; + Read_record_func read_first_record; Next_select_func next_select; READ_RECORD read_record; @@ -426,7 +461,7 @@ public: Item_sum ***func); int rollup_send_data(uint idx); int rollup_write_data(uint idx, TABLE *table); - bool test_in_subselect(Item **where); + void remove_subq_pushed_predicates(Item **where); /* Release memory and, if possible, the open tables held by this execution plan (and nested plans). It's used to release some tables before @@ -502,7 +537,7 @@ public: store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length) :null_ptr(null), err(0), null_key(0) { - if (field_arg->type() == FIELD_TYPE_BLOB) + if (field_arg->type() == MYSQL_TYPE_BLOB) { /* Key segments are always packed with a 2 byte length prefix */ to_field= new Field_varstring(ptr, length, 2, (uchar*) null, 1, diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc new file mode 100644 index 00000000000..5fa97dc5c2b --- /dev/null +++ b/sql/sql_servers.cc @@ -0,0 +1,1234 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* + The servers are saved in the system table "servers" +*/ + +#include "mysql_priv.h" +#include "hash_filo.h" +#include <m_ctype.h> +#include <stdarg.h> +#include "sp_head.h" +#include "sp.h" + +HASH servers_cache; +pthread_mutex_t servers_cache_mutex; // To init the hash +uint servers_cache_initialised=FALSE; +/* Version of server table. incremented by servers_load */ +static uint servers_version=0; +static MEM_ROOT mem; +static rw_lock_t THR_LOCK_servers; + +static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length, + my_bool not_used __attribute__((unused))) +{ + DBUG_ENTER("servers_cache_get_key"); + DBUG_PRINT("info", ("server_name_length %d server_name %s", + server->server_name_length, + server->server_name)); + + *length= (uint) server->server_name_length; + DBUG_RETURN((byte*) server->server_name); +} + +/* + Initialize structures responsible for servers used in federated + server scheme information for them from the server + table in the 'mysql' database. + + SYNOPSIS + servers_init() + dont_read_server_table TRUE if we want to skip loading data from + server table and disable privilege checking. + + NOTES + This function is mostly responsible for preparatory steps, main work + on initialization and grants loading is done in servers_reload(). + + RETURN VALUES + 0 ok + 1 Could not initialize servers +*/ + +my_bool servers_init(bool dont_read_servers_table) +{ + THD *thd; + my_bool return_val= 0; + DBUG_ENTER("servers_init"); + + /* init the mutex */ + if (pthread_mutex_init(&servers_cache_mutex, MY_MUTEX_INIT_FAST)) + DBUG_RETURN(1); + + if (my_rwlock_init(&THR_LOCK_servers, NULL)) + DBUG_RETURN(1); + + /* initialise our servers cache */ + if (hash_init(&servers_cache, system_charset_info, 32, 0, 0, + (hash_get_key) servers_cache_get_key, 0, 0)) + { + return_val= 1; /* we failed, out of memory? */ + goto end; + } + + /* Initialize the mem root for data */ + init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0); + + /* + at this point, the cache is initialised, let it be known + */ + servers_cache_initialised= TRUE; + + if (dont_read_servers_table) + goto end; + + /* + To be able to run this from boot, we allocate a temporary THD + */ + if (!(thd=new THD)) + DBUG_RETURN(1); + thd->thread_stack= (char*) &thd; + thd->store_globals(); + /* + It is safe to call servers_reload() since servers_* arrays and hashes which + will be freed there are global static objects and thus are initialized + by zeros at startup. + */ + return_val= servers_reload(thd); + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + +end: + DBUG_RETURN(return_val); +} + +/* + Initialize server structures + + SYNOPSIS + servers_load() + thd Current thread + tables List containing open "mysql.servers" + + RETURN VALUES + FALSE Success + TRUE Error +*/ + +static my_bool servers_load(THD *thd, TABLE_LIST *tables) +{ + TABLE *table; + READ_RECORD read_record_info; + my_bool return_val= TRUE; + DBUG_ENTER("servers_load"); + + if (!servers_cache_initialised) + DBUG_RETURN(0); + + /* need to figure out how to utilise this variable */ + servers_version++; /* servers updated */ + + /* first, send all cached rows to sleep with the fishes, oblivion! + I expect this crappy comment replaced */ + free_root(&mem, MYF(MY_MARK_BLOCKS_FREE)); + my_hash_reset(&servers_cache); + + init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0); + while (!(read_record_info.read_record(&read_record_info))) + { + /* return_val is already TRUE, so no need to set */ + if ((get_server_from_table_to_cache(table))) + goto end; + } + + return_val=0; + +end: + end_read_record(&read_record_info); + DBUG_RETURN(return_val); +} + + +/* + Forget current servers cache and read new servers + from the conneciton table. + + SYNOPSIS + servers_reload() + thd Current thread + + NOTE + All tables of calling thread which were open and locked by LOCK TABLES + statement will be unlocked and closed. + This function is also used for initialization of structures responsible + for user/db-level privilege checking. + + RETURN VALUE + FALSE Success + TRUE Failure +*/ + +my_bool servers_reload(THD *thd) +{ + TABLE_LIST tables[1]; + my_bool return_val= 1; + DBUG_ENTER("servers_reload"); + + if (thd->locked_tables) + { // Can't have locked tables here + thd->lock=thd->locked_tables; + thd->locked_tables=0; + close_thread_tables(thd); + } + + /* + To avoid deadlocks we should obtain table locks before + obtaining servers_cache->lock mutex. + */ + bzero((char*) tables, sizeof(tables)); + tables[0].alias= tables[0].table_name= (char*) "servers"; + tables[0].db= (char*) "mysql"; + tables[0].lock_type= TL_READ; + + if (simple_open_n_lock_tables(thd, tables)) + { + sql_print_error("Fatal error: Can't open and lock privilege tables: %s", + thd->net.last_error); + goto end; + } + + DBUG_PRINT("info", ("locking servers_cache")); + VOID(pthread_mutex_lock(&servers_cache_mutex)); + + //old_servers_cache= servers_cache; + //old_mem=mem; + + if ((return_val= servers_load(thd, tables))) + { // Error. Revert to old list + /* blast, for now, we have no servers, discuss later way to preserve */ + + DBUG_PRINT("error",("Reverting to old privileges")); + servers_free(); + } + + DBUG_PRINT("info", ("unlocking servers_cache")); + VOID(pthread_mutex_unlock(&servers_cache_mutex)); + +end: + close_thread_tables(thd); + DBUG_RETURN(return_val); +} + +/* + Initialize structures responsible for servers used in federated + server scheme information for them from the server + table in the 'mysql' database. + + SYNOPSIS + get_server_from_table_to_cache() + TABLE *table open table pointer + + + NOTES + This function takes a TABLE pointer (pointing to an opened + table). With this open table, a FOREIGN_SERVER struct pointer + is allocated into root memory, then each member of the FOREIGN_SERVER + struct is populated. A char pointer takes the return value of get_field + for each column we're interested in obtaining, and if that pointer + isn't 0x0, the FOREIGN_SERVER member is set to that value, otherwise, + is set to the value of an empty string, since get_field would set it to + 0x0 if the column's value is empty, even if the default value for that + column is NOT NULL. + + RETURN VALUES + 0 ok + 1 could not insert server struct into global servers cache +*/ + +my_bool get_server_from_table_to_cache(TABLE *table) +{ + /* alloc a server struct */ + char *ptr; + char *blank= (char*)""; + FOREIGN_SERVER *server= (FOREIGN_SERVER *)alloc_root(&mem, + sizeof(FOREIGN_SERVER)); + DBUG_ENTER("get_server_from_table_to_cache"); + table->use_all_columns(); + + /* get each field into the server struct ptr */ + server->server_name= get_field(&mem, table->field[0]); + server->server_name_length= strlen(server->server_name); + ptr= get_field(&mem, table->field[1]); + server->host= ptr ? ptr : blank; + ptr= get_field(&mem, table->field[2]); + server->db= ptr ? ptr : blank; + ptr= get_field(&mem, table->field[3]); + server->username= ptr ? ptr : blank; + ptr= get_field(&mem, table->field[4]); + server->password= ptr ? ptr : blank; + ptr= get_field(&mem, table->field[5]); + server->sport= ptr ? ptr : blank; + + server->port= server->sport ? atoi(server->sport) : 0; + + ptr= get_field(&mem, table->field[6]); + server->socket= ptr && strlen(ptr) ? ptr : NULL; + ptr= get_field(&mem, table->field[7]); + server->scheme= ptr ? ptr : blank; + ptr= get_field(&mem, table->field[8]); + server->owner= ptr ? ptr : blank; + DBUG_PRINT("info", ("server->server_name %s", server->server_name)); + DBUG_PRINT("info", ("server->host %s", server->host)); + DBUG_PRINT("info", ("server->db %s", server->db)); + DBUG_PRINT("info", ("server->username %s", server->username)); + DBUG_PRINT("info", ("server->password %s", server->password)); + DBUG_PRINT("info", ("server->socket %s", server->socket)); + if (my_hash_insert(&servers_cache, (byte*) server)) + { + DBUG_PRINT("info", ("had a problem inserting server %s at %lx", + server->server_name, (long unsigned int) server)); + // error handling needed here + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + +/* + SYNOPSIS + server_exists_in_table() + THD *thd - thread pointer + LEX_SERVER_OPTIONS *server_options - pointer to Lex->server_options + + NOTES + This function takes a LEX_SERVER_OPTIONS struct, which is very much the + same type of structure as a FOREIGN_SERVER, it contains the values parsed + in any one of the [CREATE|DELETE|DROP] SERVER statements. Using the + member "server_name", index_read_idx either founds the record and returns + 1, or doesn't find the record, and returns 0 + + RETURN VALUES + 0 record not found + 1 record found +*/ + +my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options) +{ + int result= 1; + int error= 0; + TABLE_LIST tables; + TABLE *table; + DBUG_ENTER("server_exists"); + + bzero((char*) &tables, sizeof(tables)); + tables.db= (char*) "mysql"; + tables.alias= tables.table_name= (char*) "servers"; + + /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ + if (! (table= open_ltable(thd, &tables, TL_WRITE))) + DBUG_RETURN(TRUE); + + table->use_all_columns(); + + rw_wrlock(&THR_LOCK_servers); + VOID(pthread_mutex_lock(&servers_cache_mutex)); + + /* set the field that's the PK to the value we're looking for */ + table->field[0]->store(server_options->server_name, + server_options->server_name_length, + system_charset_info); + + if ((error= table->file->index_read_idx(table->record[0], 0, + (byte *)table->field[0]->ptr, + table->key_info[0].key_length, + HA_READ_KEY_EXACT))) + { + if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) + { + table->file->print_error(error, MYF(0)); + result= -1; + } + result= 0; + DBUG_PRINT("info",("record for server '%s' not found!", + server_options->server_name)); + } + + VOID(pthread_mutex_unlock(&servers_cache_mutex)); + rw_unlock(&THR_LOCK_servers); + DBUG_RETURN(result); +} + +/* + SYNOPSIS + insert_server() + THD *thd - thread pointer + FOREIGN_SERVER *server - pointer to prepared FOREIGN_SERVER struct + + NOTES + This function takes a server object that is has all members properly + prepared, ready to be inserted both into the mysql.servers table and + the servers cache. + + RETURN VALUES + 0 - no error + other - error code +*/ + +int insert_server(THD *thd, FOREIGN_SERVER *server) +{ + int error= 0; + TABLE_LIST tables; + TABLE *table; + + DBUG_ENTER("insert_server"); + + bzero((char*) &tables, sizeof(tables)); + tables.db= (char*) "mysql"; + tables.alias= tables.table_name= (char*) "servers"; + + /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ + if (! (table= open_ltable(thd, &tables, TL_WRITE))) + DBUG_RETURN(TRUE); + + /* lock mutex to make sure no changes happen */ + VOID(pthread_mutex_lock(&servers_cache_mutex)); + + /* lock table */ + rw_wrlock(&THR_LOCK_servers); + + /* insert the server into the table */ + if ((error= insert_server_record(table, server))) + goto end; + + /* insert the server into the cache */ + if ((error= insert_server_record_into_cache(server))) + goto end; + +end: + /* unlock the table */ + rw_unlock(&THR_LOCK_servers); + VOID(pthread_mutex_unlock(&servers_cache_mutex)); + DBUG_RETURN(error); +} + +/* + SYNOPSIS + int insert_server_record_into_cache() + FOREIGN_SERVER *server + + NOTES + This function takes a FOREIGN_SERVER pointer to an allocated (root mem) + and inserts it into the global servers cache + + RETURN VALUE + 0 - no error + >0 - error code + +*/ + +int insert_server_record_into_cache(FOREIGN_SERVER *server) +{ + int error=0; + DBUG_ENTER("insert_server_record_into_cache"); + /* + We succeded in insertion of the server to the table, now insert + the server to the cache + */ + DBUG_PRINT("info", ("inserting server %s at %lx, length %d", + server->server_name, (long unsigned int) server, + server->server_name_length)); + if (my_hash_insert(&servers_cache, (byte*) server)) + { + DBUG_PRINT("info", ("had a problem inserting server %s at %lx", + server->server_name, (long unsigned int) server)); + // error handling needed here + error= 1; + } + DBUG_RETURN(error); +} + +/* + SYNOPSIS + store_server_fields() + TABLE *table + FOREIGN_SERVER *server + + NOTES + This function takes an opened table object, and a pointer to an + allocated FOREIGN_SERVER struct, and then stores each member of + the FOREIGN_SERVER to the appropriate fields in the table, in + advance of insertion into the mysql.servers table + + RETURN VALUE + VOID + +*/ + +void store_server_fields(TABLE *table, FOREIGN_SERVER *server) +{ + + table->use_all_columns(); + /* + "server" has already been prepped by prepare_server_struct_for_<> + so, all we need to do is check if the value is set (> -1 for port) + + If this happens to be an update, only the server members that + have changed will be set. If an insert, then all will be set, + even if with empty strings + */ + if (server->host) + table->field[1]->store(server->host, + (uint) strlen(server->host), system_charset_info); + if (server->db) + table->field[2]->store(server->db, + (uint) strlen(server->db), system_charset_info); + if (server->username) + table->field[3]->store(server->username, + (uint) strlen(server->username), system_charset_info); + if (server->password) + table->field[4]->store(server->password, + (uint) strlen(server->password), system_charset_info); + if (server->port > -1) + table->field[5]->store(server->port); + + if (server->socket) + table->field[6]->store(server->socket, + (uint) strlen(server->socket), system_charset_info); + if (server->scheme) + table->field[7]->store(server->scheme, + (uint) strlen(server->scheme), system_charset_info); + if (server->owner) + table->field[8]->store(server->owner, + (uint) strlen(server->owner), system_charset_info); +} + +/* + SYNOPSIS + insert_server_record() + TABLE *table + FOREIGN_SERVER *server + + NOTES + This function takes the arguments of an open table object and a pointer + to an allocated FOREIGN_SERVER struct. It stores the server_name into + the first field of the table (the primary key, server_name column). With + this, index_read_idx is called, if the record is found, an error is set + to ER_FOREIGN_SERVER_EXISTS (the server with that server name exists in the + table), if not, then store_server_fields stores all fields of the + FOREIGN_SERVER to the table, then ha_write_row is inserted. If an error + is encountered in either index_read_idx or ha_write_row, then that error + is returned + + RETURN VALUE + 0 - no errors + >0 - error code + + */ + +int insert_server_record(TABLE *table, FOREIGN_SERVER *server) +{ + int error; + DBUG_ENTER("insert_server_record"); + table->use_all_columns(); + + /* set the field that's the PK to the value we're looking for */ + table->field[0]->store(server->server_name, + server->server_name_length, + system_charset_info); + + /* read index until record is that specified in server_name */ + if ((error= table->file->index_read_idx(table->record[0], 0, + (byte *)table->field[0]->ptr, + table->key_info[0].key_length, + HA_READ_KEY_EXACT))) + { + /* if not found, err */ + if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) + { + table->file->print_error(error, MYF(0)); + error= 1; + } + /* store each field to be inserted */ + store_server_fields(table, server); + + DBUG_PRINT("info",("record for server '%s' not found!", + server->server_name)); + /* write/insert the new server */ + if ((error=table->file->ha_write_row(table->record[0]))) + { + table->file->print_error(error, MYF(0)); + } + else + error= 0; + } + else + error= ER_FOREIGN_SERVER_EXISTS; + DBUG_RETURN(error); +} + +/* + SYNOPSIS + drop_server() + THD *thd + LEX_SERVER_OPTIONS *server_options + + NOTES + This function takes as its arguments a THD object pointer and a pointer + to a LEX_SERVER_OPTIONS struct from the parser. The member 'server_name' + of this LEX_SERVER_OPTIONS struct contains the value of the server to be + deleted. The mysql.servers table is opened via open_ltable, a table object + returned, the servers cache mutex locked, then delete_server_record is + called with this table object and LEX_SERVER_OPTIONS server_name and + server_name_length passed, containing the name of the server to be + dropped/deleted, then delete_server_record_in_cache is called to delete + the server from the servers cache. + + RETURN VALUE + 0 - no error + > 0 - error code +*/ + +int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) +{ + int error= 0; + TABLE_LIST tables; + TABLE *table; + + DBUG_ENTER("drop_server"); + DBUG_PRINT("info", ("server name server->server_name %s", + server_options->server_name)); + + bzero((char*) &tables, sizeof(tables)); + tables.db= (char*) "mysql"; + tables.alias= tables.table_name= (char*) "servers"; + + /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ + if (! (table= open_ltable(thd, &tables, TL_WRITE))) + DBUG_RETURN(TRUE); + + rw_wrlock(&THR_LOCK_servers); + VOID(pthread_mutex_lock(&servers_cache_mutex)); + + + if ((error= delete_server_record(table, + server_options->server_name, + server_options->server_name_length))) + goto end; + + + if ((error= delete_server_record_in_cache(server_options))) + goto end; + +end: + VOID(pthread_mutex_unlock(&servers_cache_mutex)); + rw_unlock(&THR_LOCK_servers); + DBUG_RETURN(error); +} +/* + + SYNOPSIS + delete_server_record_in_cache() + LEX_SERVER_OPTIONS *server_options + + NOTES + This function's argument is a LEX_SERVER_OPTIONS struct pointer. This + function uses the "server_name" and "server_name_length" members of the + lex->server_options to search for the server in the servers_cache. Upon + returned the server (pointer to a FOREIGN_SERVER struct), it then deletes + that server from the servers_cache hash. + + RETURN VALUE + 0 - no error + +*/ + +int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) +{ + + int error= 0; + FOREIGN_SERVER *server; + DBUG_ENTER("delete_server_record_in_cache"); + + DBUG_PRINT("info",("trying to obtain server name %s length %d", + server_options->server_name, + server_options->server_name_length)); + + + if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache, + (byte*) server_options->server_name, + server_options->server_name_length))) + { + DBUG_PRINT("info", ("server_name %s length %d not found!", + server_options->server_name, + server_options->server_name_length)); + // what should be done if not found in the cache? + } + /* + We succeded in deletion of the server to the table, now delete + the server from the cache + */ + DBUG_PRINT("info",("deleting server %s length %d", + server->server_name, + server->server_name_length)); + + if (server) + VOID(hash_delete(&servers_cache, (byte*) server)); + + servers_version++; /* servers updated */ + + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + update_server() + THD *thd + FOREIGN_SERVER *existing + FOREIGN_SERVER *altered + + NOTES + This function takes as arguments a THD object pointer, and two pointers, + one pointing to the existing FOREIGN_SERVER struct "existing" (which is + the current record as it is) and another pointer pointing to the + FOREIGN_SERVER struct with the members containing the modified/altered + values that need to be updated in both the mysql.servers table and the + servers_cache. It opens a table, passes the table and the altered + FOREIGN_SERVER pointer, which will be used to update the mysql.servers + table for the particular server via the call to update_server_record, + and in the servers_cache via update_server_record_in_cache. + + RETURN VALUE + 0 - no error + >0 - error code + +*/ + +int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) +{ + int error= 0; + TABLE *table; + TABLE_LIST tables; + DBUG_ENTER("update_server"); + + bzero((char*) &tables, sizeof(tables)); + tables.db= (char*)"mysql"; + tables.alias= tables.table_name= (char*)"servers"; + + if (!(table= open_ltable(thd, &tables, TL_WRITE))) + DBUG_RETURN(1); + + rw_wrlock(&THR_LOCK_servers); + if ((error= update_server_record(table, altered))) + goto end; + + update_server_record_in_cache(existing, altered); + +end: + rw_unlock(&THR_LOCK_servers); + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + update_server_record_in_cache() + FOREIGN_SERVER *existing + FOREIGN_SERVER *altered + + NOTES + This function takes as an argument the FOREIGN_SERVER structi pointer + for the existing server and the FOREIGN_SERVER struct populated with only + the members which have been updated. It then "merges" the "altered" struct + members to the existing server, the existing server then represents an + updated server. Then, the existing record is deleted from the servers_cache + HASH, then the updated record inserted, in essence replacing the old + record. + + RETURN VALUE + 0 - no error + 1 - error + +*/ + +int update_server_record_in_cache(FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered) +{ + int error= 0; + DBUG_ENTER("update_server_record_in_cache"); + + /* + update the members that haven't been change in the altered server struct + with the values of the existing server struct + */ + merge_server_struct(existing, altered); + + /* + delete the existing server struct from the server cache + */ + VOID(hash_delete(&servers_cache, (byte*)existing)); + + /* + Insert the altered server struct into the server cache + */ + if (my_hash_insert(&servers_cache, (byte*)altered)) + { + DBUG_PRINT("info", ("had a problem inserting server %s at %lx", + altered->server_name, (long unsigned int) altered)); + error= 1; + } + + servers_version++; /* servers updated */ + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + merge_server_struct() + FOREIGN_SERVER *from + FOREIGN_SERVER *to + + NOTES + This function takes as its arguments two pointers each to an allocated + FOREIGN_SERVER struct. The first FOREIGN_SERVER struct represents the struct + that we will obtain values from (hence the name "from"), the second + FOREIGN_SERVER struct represents which FOREIGN_SERVER struct we will be + "copying" any members that have a value to (hence the name "to") + + RETURN VALUE + VOID + +*/ + +void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) +{ + DBUG_ENTER("merge_server_struct"); + if (!to->host) + to->host= strdup_root(&mem, from->host); + if (!to->db) + to->db= strdup_root(&mem, from->db); + if (!to->username) + to->username= strdup_root(&mem, from->username); + if (!to->password) + to->password= strdup_root(&mem, from->password); + if (to->port == -1) + to->port= from->port; + if (!to->socket) + to->socket= strdup_root(&mem, from->socket); + if (!to->scheme) + to->scheme= strdup_root(&mem, from->scheme); + if (!to->owner) + to->owner= strdup_root(&mem, from->owner); + + DBUG_VOID_RETURN; +} + +/* + + SYNOPSIS + update_server_record() + TABLE *table + FOREIGN_SERVER *server + + NOTES + This function takes as its arguments an open TABLE pointer, and a pointer + to an allocated FOREIGN_SERVER structure representing an updated record + which needs to be inserted. The primary key, server_name is stored to field + 0, then index_read_idx is called to read the index to that record, the + record then being ready to be updated, if found. If not found an error is + set and error message printed. If the record is found, store_record is + called, then store_server_fields stores each field from the the members of + the updated FOREIGN_SERVER struct. + + RETURN VALUE + 0 - no error + +*/ + +int update_server_record(TABLE *table, FOREIGN_SERVER *server) +{ + int error=0; + DBUG_ENTER("update_server_record"); + table->use_all_columns(); + /* set the field that's the PK to the value we're looking for */ + table->field[0]->store(server->server_name, + server->server_name_length, + system_charset_info); + + if ((error= table->file->index_read_idx(table->record[0], 0, + (byte *)table->field[0]->ptr, + table->key_info[0].key_length, + HA_READ_KEY_EXACT))) + { + if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) + { + table->file->print_error(error, MYF(0)); + error= 1; + } + DBUG_PRINT("info",("server not found!")); + error= ER_FOREIGN_SERVER_DOESNT_EXIST; + } + else + { + /* ok, so we can update since the record exists in the table */ + store_record(table,record[1]); + store_server_fields(table, server); + if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) + { + DBUG_PRINT("info",("problems with ha_update_row %d", error)); + goto end; + } + } + +end: + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + delete_server_record() + TABLE *table + char *server_name + int server_name_length + + NOTES + + RETURN VALUE + 0 - no error + +*/ + +int delete_server_record(TABLE *table, + char *server_name, + int server_name_length) +{ + int error= 0; + DBUG_ENTER("delete_server_record"); + table->use_all_columns(); + + /* set the field that's the PK to the value we're looking for */ + table->field[0]->store(server_name, server_name_length, system_charset_info); + + if ((error= table->file->index_read_idx(table->record[0], 0, + (byte *)table->field[0]->ptr, + table->key_info[0].key_length, + HA_READ_KEY_EXACT))) + { + if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) + { + table->file->print_error(error, MYF(0)); + error= 1; + } + DBUG_PRINT("info",("server not found!")); + error= ER_FOREIGN_SERVER_DOESNT_EXIST; + } + else + { + if ((error= table->file->ha_delete_row(table->record[0]))) + table->file->print_error(error, MYF(0)); + } + + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + create_server() + THD *thd + LEX_SERVER_OPTIONS *server_options + + NOTES + + RETURN VALUE + 0 - no error + +*/ + +int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options) +{ + int error; + FOREIGN_SERVER *server; + + DBUG_ENTER("create_server"); + DBUG_PRINT("info", ("server_options->server_name %s", + server_options->server_name)); + + server= (FOREIGN_SERVER *)alloc_root(&mem, + sizeof(FOREIGN_SERVER)); + + if ((error= prepare_server_struct_for_insert(server_options, server))) + goto end; + + if ((error= insert_server(thd, server))) + goto end; + + DBUG_PRINT("info", ("error returned %d", error)); + +end: + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + alter_server() + THD *thd + LEX_SERVER_OPTIONS *server_options + + NOTES + + RETURN VALUE + 0 - no error + +*/ + +int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options) +{ + int error= 0; + FOREIGN_SERVER *altered, *existing; + DBUG_ENTER("alter_server"); + DBUG_PRINT("info", ("server_options->server_name %s", + server_options->server_name)); + + altered= (FOREIGN_SERVER *)alloc_root(&mem, + sizeof(FOREIGN_SERVER)); + + VOID(pthread_mutex_lock(&servers_cache_mutex)); + + if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache, + (byte*) server_options->server_name, + server_options->server_name_length))) + { + error= ER_FOREIGN_SERVER_DOESNT_EXIST; + goto end; + } + + if ((error= prepare_server_struct_for_update(server_options, existing, altered))) + goto end; + + if ((error= update_server(thd, existing, altered))) + goto end; + +end: + DBUG_PRINT("info", ("error returned %d", error)); + VOID(pthread_mutex_unlock(&servers_cache_mutex)); + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + prepare_server_struct_for_insert() + LEX_SERVER_OPTIONS *server_options + FOREIGN_SERVER *server + + NOTES + + RETURN VALUE + 0 - no error + +*/ + +int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *server) +{ + int error; + char *unset_ptr= (char*)""; + DBUG_ENTER("prepare_server_struct"); + + error= 0; + + /* these two MUST be set */ + server->server_name= strdup_root(&mem, server_options->server_name); + server->server_name_length= server_options->server_name_length; + + server->host= server_options->host ? + strdup_root(&mem, server_options->host) : unset_ptr; + + server->db= server_options->db ? + strdup_root(&mem, server_options->db) : unset_ptr; + + server->username= server_options->username ? + strdup_root(&mem, server_options->username) : unset_ptr; + + server->password= server_options->password ? + strdup_root(&mem, server_options->password) : unset_ptr; + + /* set to 0 if not specified */ + server->port= server_options->port > -1 ? + server_options->port : 0; + + server->socket= server_options->socket ? + strdup_root(&mem, server_options->socket) : unset_ptr; + + server->scheme= server_options->scheme ? + strdup_root(&mem, server_options->scheme) : unset_ptr; + + server->owner= server_options->owner ? + strdup_root(&mem, server_options->owner) : unset_ptr; + + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + prepare_server_struct_for_update() + LEX_SERVER_OPTIONS *server_options + + NOTES + + RETURN VALUE + 0 - no error + +*/ + +int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered) +{ + int error; + DBUG_ENTER("prepare_server_struct_for_update"); + error= 0; + + altered->server_name= strdup_root(&mem, server_options->server_name); + altered->server_name_length= server_options->server_name_length; + DBUG_PRINT("info", ("existing name %s altered name %s", + existing->server_name, altered->server_name)); + + /* + The logic here is this: is this value set AND is it different + than the existing value? + */ + altered->host= + (server_options->host && (strcmp(server_options->host, existing->host))) ? + strdup_root(&mem, server_options->host) : 0; + + altered->db= + (server_options->db && (strcmp(server_options->db, existing->db))) ? + strdup_root(&mem, server_options->db) : 0; + + altered->username= + (server_options->username && + (strcmp(server_options->username, existing->username))) ? + strdup_root(&mem, server_options->username) : 0; + + altered->password= + (server_options->password && + (strcmp(server_options->password, existing->password))) ? + strdup_root(&mem, server_options->password) : 0; + + /* + port is initialised to -1, so if unset, it will be -1 + */ + altered->port= (server_options->port > -1 && + server_options->port != existing->port) ? + server_options->port : -1; + + altered->socket= + (server_options->socket && + (strcmp(server_options->socket, existing->socket))) ? + strdup_root(&mem, server_options->socket) : 0; + + altered->scheme= + (server_options->scheme && + (strcmp(server_options->scheme, existing->scheme))) ? + strdup_root(&mem, server_options->scheme) : 0; + + altered->owner= + (server_options->owner && + (strcmp(server_options->owner, existing->owner))) ? + strdup_root(&mem, server_options->owner) : 0; + + DBUG_RETURN(error); +} + +/* + + SYNOPSIS + servers_free() + bool end + + NOTES + + RETURN VALUE + void + +*/ + +void servers_free(bool end) +{ + DBUG_ENTER("servers_free"); + if (!servers_cache_initialised) + DBUG_VOID_RETURN; + VOID(pthread_mutex_destroy(&servers_cache_mutex)); + servers_cache_initialised=0; + free_root(&mem,MYF(0)); + hash_free(&servers_cache); + DBUG_VOID_RETURN; +} + + + +/* + + SYNOPSIS + get_server_by_name() + const char *server_name + + NOTES + + RETURN VALUE + FOREIGN_SERVER * + +*/ + +FOREIGN_SERVER *get_server_by_name(const char *server_name) +{ + ulong error_num=0; + uint server_name_length; + FOREIGN_SERVER *server= 0; + DBUG_ENTER("get_server_by_name"); + DBUG_PRINT("info", ("server_name %s", server_name)); + + server_name_length= strlen(server_name); + + if (! server_name || !strlen(server_name)) + { + DBUG_PRINT("info", ("server_name not defined!")); + error_num= 1; + DBUG_RETURN((FOREIGN_SERVER *)NULL); + } + + DBUG_PRINT("info", ("locking servers_cache")); + VOID(pthread_mutex_lock(&servers_cache_mutex)); + if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache, + (byte*) server_name, + server_name_length))) + { + DBUG_PRINT("info", ("server_name %s length %d not found!", + server_name, server_name_length)); + server= (FOREIGN_SERVER *) NULL; + } + DBUG_PRINT("info", ("unlocking servers_cache")); + VOID(pthread_mutex_unlock(&servers_cache_mutex)); + DBUG_RETURN(server); + +} diff --git a/sql/sql_servers.h b/sql/sql_servers.h new file mode 100644 index 00000000000..23b8cefd5bb --- /dev/null +++ b/sql/sql_servers.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2006 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "slave.h" // for tables_ok(), rpl_filter + +/* structs */ +typedef struct st_federated_server +{ + char *server_name; + long port; + uint server_name_length; + char *db, *scheme, *username, *password, *socket, *owner, *host, *sport; +} FOREIGN_SERVER; + +/* cache handlers */ +my_bool servers_init(bool dont_read_server_table); +my_bool servers_reload(THD *thd); +my_bool get_server_from_table_to_cache(TABLE *table); +void servers_free(bool end=0); + +/* insert functions */ +int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options); +int insert_server(THD *thd, FOREIGN_SERVER *server_options); +int insert_server_record(TABLE *table, FOREIGN_SERVER *server); +int insert_server_record_into_cache(FOREIGN_SERVER *server); +void store_server_fields_for_insert(TABLE *table, FOREIGN_SERVER *server); +void store_server_fields_for_insert(TABLE *table, + FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered); +int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *server); + +/* drop functions */ +int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options); +int delete_server_record(TABLE *table, + char *server_name, + int server_name_length); +int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options); + +/* update functions */ +int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options); +int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered); +int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered); +int update_server_record(TABLE *table, FOREIGN_SERVER *server); +int update_server_record_in_cache(FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered); +/* utility functions */ +void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to); +FOREIGN_SERVER *get_server_by_name(const char *server_name); +my_bool server_exists_in_table(THD *thd, char *server_name); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0ebccba43ca..250d9d917eb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -33,7 +32,6 @@ #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" #endif - enum enum_i_s_events_fields { ISE_EVENT_CATALOG= 0, @@ -58,11 +56,11 @@ enum enum_i_s_events_fields }; +#ifndef NO_EMBEDDED_ACCESS_CHECKS static const char *grant_names[]={ "select","insert","update","delete","create","drop","reload","shutdown", "process","file","grant","references","index","alter"}; -#ifndef NO_EMBEDDED_ACCESS_CHECKS static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), "grant_types", grant_names, NULL}; @@ -141,7 +139,6 @@ static my_bool show_plugins(THD *thd, st_plugin_int *plugin, { TABLE *table= (TABLE*) arg; struct st_mysql_plugin *plug= plugin->plugin; - Protocol *protocol= thd->protocol; CHARSET_INFO *cs= system_charset_info; char version_buf[20]; @@ -154,8 +151,7 @@ static my_bool show_plugins(THD *thd, st_plugin_int *plugin, cs); - switch (plugin->state) - { + switch (plugin->state) { /* case PLUGIN_IS_FREED: does not happen */ case PLUGIN_IS_DELETED: table->field[2]->store(STRING_WITH_LEN("DELETED"), cs); @@ -689,10 +685,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create_info) { - Security_context *sctx= thd->security_ctx; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); #ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *sctx= thd->security_ctx; uint db_access; #endif HA_CREATE_INFO create; @@ -1021,7 +1017,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, HA_CREATE_INFO *create_info_arg) { List<Item> field_list; - char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end; + char tmp[MAX_FIELD_WIDTH], *for_str, buff[128]; const char *alias; String type(tmp, sizeof(tmp), system_charset_info); Field **ptr,*field; @@ -1116,7 +1112,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, if (flags & NOT_NULL_FLAG) packet->append(STRING_WITH_LEN(" NOT NULL")); - else if (field->type() == FIELD_TYPE_TIMESTAMP) + else if (field->type() == MYSQL_TYPE_TIMESTAMP) { /* TIMESTAMP field require explicit NULL flag, because unlike @@ -1132,7 +1128,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, has_now_default= table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_UN_FIELD; - has_default= (field->type() != FIELD_TYPE_BLOB && + has_default= (field->type() != MYSQL_TYPE_BLOB && !(field->flags & NO_DEFAULT_VALUE_FLAG) && field->unireg_check != Field::NEXT_NUMBER && !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) @@ -1267,7 +1263,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, to the CREATE TABLE statement */ - if ((for_str= file->get_tablespace_name(thd))) + if ((for_str= file->get_tablespace_name(thd,0,0))) { packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE ")); packet->append(for_str, strlen(for_str)); @@ -1308,8 +1304,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, but may extrapolate its existence from that of an AUTO_INCREMENT column. */ - if(create_info.auto_increment_value > 1) + if (create_info.auto_increment_value > 1) { + char *end; packet->append(STRING_WITH_LEN(" AUTO_INCREMENT=")); end= longlong10_to_str(create_info.auto_increment_value, buff,10); packet->append(buff, (uint) (end - buff)); @@ -1339,6 +1336,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, if (share->min_rows) { + char *end; packet->append(STRING_WITH_LEN(" MIN_ROWS=")); end= longlong10_to_str(share->min_rows, buff, 10); packet->append(buff, (uint) (end- buff)); @@ -1346,6 +1344,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, if (share->max_rows && !table_list->schema_table) { + char *end; packet->append(STRING_WITH_LEN(" MAX_ROWS=")); end= longlong10_to_str(share->max_rows, buff, 10); packet->append(buff, (uint) (end - buff)); @@ -1353,6 +1352,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, if (share->avg_row_length) { + char *end; packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH=")); end= longlong10_to_str(share->avg_row_length, buff,10); packet->append(buff, (uint) (end - buff)); @@ -1373,6 +1373,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, } if (table->s->key_block_size) { + char *end; packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE=")); end= longlong10_to_str(table->s->key_block_size, buff, 10); packet->append(buff, (uint) (end - buff)); @@ -1625,7 +1626,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) field_list.push_back(field=new Item_empty_string("db",NAME_LEN)); field->maybe_null=1; field_list.push_back(new Item_empty_string("Command",16)); - field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG)); + field_list.push_back(new Item_return_int("Time",7, MYSQL_TYPE_LONG)); field_list.push_back(field=new Item_empty_string("State",30)); field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); @@ -1686,10 +1687,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (mysys_var) pthread_mutex_unlock(&mysys_var->mutex); -#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO) - if (pthread_kill(tmp->real_id,0)) - tmp->proc_info="*** DEAD ***"; // This shouldn't happen -#endif #ifdef EXTRA_DEBUG thd_info->start_time= tmp->time_after_lock; #else @@ -2068,7 +2065,7 @@ static bool show_status_array(THD *thd, const char *wild, if (show_type == SHOW_SYS) { - show_type= ((sys_var*) value)->type(); + show_type= ((sys_var*) value)->show_type(); value= (char*) ((sys_var*) value)->value_ptr(thd, value_type, &null_lex_str); } @@ -2121,7 +2118,7 @@ static bool show_status_array(THD *thd, const char *wild, end= strend(pos); break; } - case SHOW_CHAR_PTR: + case SHOW_CHAR_PTR: { if (!(pos= *(char**) value)) pos= ""; @@ -2452,10 +2449,48 @@ int make_db_list(THD *thd, List<char> *files, mysql_data_home, NullS, 1) != FIND_FILES_OK); } +struct st_add_schema_table +{ + List<char> *files; + const char *wild; +}; + +static my_bool add_schema_table(THD *thd, st_plugin_int *plugin, + void* p_data) +{ + st_add_schema_table *data= (st_add_schema_table *)p_data; + List<char> *file_list= data->files; + const char *wild= data->wild; + ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data; + DBUG_ENTER("add_schema_table"); + + if (schema_table->hidden) + DBUG_RETURN(0); + if (wild) + { + if (lower_case_table_names) + { + if (wild_case_compare(files_charset_info, + schema_table->table_name, + wild)) + DBUG_RETURN(0); + } + else if (wild_compare(schema_table->table_name, wild, 0)) + DBUG_RETURN(0); + } + + if (file_list->push_back(thd->strdup(schema_table->table_name))) + DBUG_RETURN(1); + + DBUG_RETURN(0); +} int schema_tables_add(THD *thd, List<char> *files, const char *wild) { ST_SCHEMA_TABLE *tmp_schema_table= schema_tables; + st_add_schema_table add_data; + DBUG_ENTER("schema_tables_add"); + for (; tmp_schema_table->table_name; tmp_schema_table++) { if (tmp_schema_table->hidden) @@ -2473,9 +2508,16 @@ int schema_tables_add(THD *thd, List<char> *files, const char *wild) continue; } if (files->push_back(thd->strdup(tmp_schema_table->table_name))) - return 1; + DBUG_RETURN(1); } - return 0; + + add_data.files= files; + add_data.wild= wild; + if (plugin_foreach(thd, add_schema_table, + MYSQL_INFORMATION_SCHEMA_PLUGIN, &add_data)) + DBUG_RETURN(1); + + DBUG_RETURN(0); } @@ -2497,19 +2539,21 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) List<char> bases; List_iterator_fast<char> it(bases); COND *partial_cond; - Security_context *sctx= thd->security_ctx; uint derived_tables= lex->derived_tables; int error= 1; enum legacy_db_type not_used; Open_tables_state open_tables_state_backup; bool save_view_prepare_mode= lex->view_prepare_mode; Query_tables_list query_tables_list_backup; - lex->view_prepare_mode= TRUE; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *sctx= thd->security_ctx; +#endif DBUG_ENTER("get_all_tables"); LINT_INIT(end); LINT_INIT(len); + lex->view_prepare_mode= TRUE; lex->reset_n_backup_query_tables_list(&query_tables_list_backup); /* @@ -2748,7 +2792,9 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) bool with_i_schema; HA_CREATE_INFO create; TABLE *table= tables->table; +#ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *sctx= thd->security_ctx; +#endif DBUG_ENTER("fill_schema_shemata"); if (make_db_list(thd, &files, &idx_field_vals, @@ -2892,20 +2938,21 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, if (file->stats.create_time) { thd->variables.time_zone->gmt_sec_to_TIME(&time, - file->stats.create_time); + (my_time_t) file->stats.create_time); table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[14]->set_notnull(); } if (file->stats.update_time) { thd->variables.time_zone->gmt_sec_to_TIME(&time, - file->stats.update_time); + (my_time_t) file->stats.update_time); table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[15]->set_notnull(); } if (file->stats.check_time) { - thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time); + thd->variables.time_zone->gmt_sec_to_TIME(&time, + (my_time_t) file->stats.check_time); table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[16]->set_notnull(); } @@ -3098,12 +3145,12 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, pos=(byte*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES"); table->field[6]->store((const char*) pos, strlen((const char*) pos), cs); - is_blob= (field->type() == FIELD_TYPE_BLOB); + is_blob= (field->type() == MYSQL_TYPE_BLOB); if (field->has_charset() || is_blob || field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type field->real_type() == MYSQL_TYPE_STRING) // For binary type { - uint32 octet_max_length= field->max_length(); + uint32 octet_max_length= field->max_display_length(); if (is_blob && octet_max_length != (uint32) 4294967295U) octet_max_length /= field->charset()->mbmaxlen; longlong char_max_len= is_blob ? @@ -3122,25 +3169,25 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, decimals= field->decimals(); switch (field->type()) { - case FIELD_TYPE_NEWDECIMAL: + case MYSQL_TYPE_NEWDECIMAL: field_length= ((Field_new_decimal*) field)->precision; break; - case FIELD_TYPE_DECIMAL: + case MYSQL_TYPE_DECIMAL: field_length= field->field_length - (decimals ? 2 : 1); break; - case FIELD_TYPE_TINY: - case FIELD_TYPE_SHORT: - case FIELD_TYPE_LONG: - case FIELD_TYPE_LONGLONG: - case FIELD_TYPE_INT24: - field_length= field->max_length() - 1; + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + field_length= field->max_display_length() - 1; break; - case FIELD_TYPE_BIT: - field_length= field->max_length(); + case MYSQL_TYPE_BIT: + field_length= field->max_display_length(); decimals= -1; // return NULL break; - case FIELD_TYPE_FLOAT: - case FIELD_TYPE_DOUBLE: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: field_length= field->field_length; if (decimals == NOT_FIXED_DEC) decimals= -1; // return NULL @@ -3855,8 +3902,8 @@ static int get_schema_key_column_usage_record(THD *thd, show_table->file->get_foreign_key_list(thd, &f_key_list); FOREIGN_KEY_INFO *f_key_info; - List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list); - while ((f_key_info= it++)) + List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list); + while ((f_key_info= fkey_it++)) { LEX_STRING *f_info; LEX_STRING *r_info; @@ -3974,7 +4021,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, strlen(part_elem->tablespace_name), cs); else { - char *ts= showing_table->file->get_tablespace_name(thd); + char *ts= showing_table->file->get_tablespace_name(thd,0,0); if(ts) { table->field[24]->store(ts, strlen(ts), cs); @@ -4020,7 +4067,6 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, partition_element *part_elem; List_iterator<partition_element> part_it(part_info->partitions); uint part_pos= 0, part_id= 0; - uint no_parts= part_info->no_parts; restore_record(table, s->default_values); table->field[1]->store(base_name, strlen(base_name), cs); @@ -4190,6 +4236,7 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, } +#ifdef NOT_USED static interval_type get_real_interval_type(interval_type i_type) { switch (i_type) { @@ -4233,6 +4280,8 @@ static interval_type get_real_interval_type(interval_type i_type) return INTERVAL_SECOND; } +#endif + /* Loads an event from mysql.event and copies it's data to a row of @@ -4498,8 +4547,10 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables, f_key_info->forein_id->length, cs); table->field[4]->store(f_key_info->referenced_db->str, f_key_info->referenced_db->length, cs); - table->field[5]->store(f_key_info->referenced_table->str, + table->field[10]->store(f_key_info->referenced_table->str, f_key_info->referenced_table->length, cs); + table->field[5]->store(f_key_info->referenced_key_name->str, + f_key_info->referenced_key_name->length, cs); table->field[6]->store(STRING_WITH_LEN("NONE"), cs); table->field[7]->store(f_key_info->update_method->str, f_key_info->update_method->length, cs); @@ -4512,6 +4563,44 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables, DBUG_RETURN(0); } +struct schema_table_ref +{ + const char *table_name; + ST_SCHEMA_TABLE *schema_table; +}; + + +/* + Find schema_tables elment by name + + SYNOPSIS + find_schema_table_in_plugin() + thd thread handler + plugin plugin + table_name table name + + RETURN + 0 table not found + 1 found the schema table +*/ +static my_bool find_schema_table_in_plugin(THD *thd, st_plugin_int *plugin, + void* p_table) +{ + schema_table_ref *p_schema_table= (schema_table_ref *)p_table; + const char* table_name= p_schema_table->table_name; + ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data; + DBUG_ENTER("find_schema_table_in_plugin"); + + if (!my_strcasecmp(system_charset_info, + schema_table->table_name, + table_name)) { + p_schema_table->schema_table= schema_table; + DBUG_RETURN(1); + } + + DBUG_RETURN(0); +} + /* Find schema_tables elment by name @@ -4528,15 +4617,24 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables, ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name) { + schema_table_ref schema_table_a; ST_SCHEMA_TABLE *schema_table= schema_tables; + DBUG_ENTER("find_schema_table"); + for (; schema_table->table_name; schema_table++) { if (!my_strcasecmp(system_charset_info, schema_table->table_name, table_name)) - return schema_table; + DBUG_RETURN(schema_table); } - return 0; + + schema_table_a.table_name= table_name; + if (plugin_foreach(thd, find_schema_table_in_plugin, + MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a)) + DBUG_RETURN(schema_table_a.schema_table); + + DBUG_RETURN(NULL); } @@ -4949,13 +5047,15 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, SYNOPSIS get_schema_tables_result() join join which use schema tables + executed_place place where I_S table processed RETURN FALSE success TRUE error */ -bool get_schema_tables_result(JOIN *join) +bool get_schema_tables_result(JOIN *join, + enum enum_schema_table_state executed_place) { JOIN_TAB *tmp_join_tab= join->join_tab+join->tables; THD *thd= join->thd; @@ -4975,15 +5075,26 @@ bool get_schema_tables_result(JOIN *join) bool is_subselect= (&lex->unit != lex->current_select->master_unit() && lex->current_select->master_unit()->item); /* - The schema table is already processed and - the statement is not a subselect. - So we don't need to handle this table again. + If schema table is already processed and + the statement is not a subselect then + we don't need to fill this table again. + If schema table is already processed and + schema_table_state != executed_place then + table is already processed and + we should skip second data processing. */ - if (table_list->is_schema_table_processed && !is_subselect) + if (table_list->schema_table_state && + (!is_subselect || table_list->schema_table_state != executed_place)) continue; - if (is_subselect) // is subselect + /* + if table is used in a subselect and + table has been processed earlier with the same + 'executed_place' value then we should refresh the table. + */ + if (table_list->schema_table_state && is_subselect) { + table_list->table->file->extra(HA_EXTRA_NO_CACHE); table_list->table->file->extra(HA_EXTRA_RESET_STATE); table_list->table->file->delete_all_rows(); free_io_cache(table_list->table); @@ -4998,10 +5109,10 @@ bool get_schema_tables_result(JOIN *join) { result= 1; join->error= 1; - table_list->is_schema_table_processed= TRUE; + table_list->schema_table_state= executed_place; break; } - table_list->is_schema_table_processed= TRUE; + table_list->schema_table_state= executed_place; } } thd->no_warnings_for_error= 0; @@ -5027,7 +5138,6 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin, int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond) { - TABLE *table= tables->table; DBUG_ENTER("fill_schema_files"); struct run_hton_fill_schema_files_args args; @@ -5085,7 +5195,7 @@ int fill_schema_status(THD *thd, SHOW_VAR *variables, if (show_type == SHOW_SYS) { - show_type= ((sys_var*) value)->type(); + show_type= ((sys_var*) value)->show_type(); value= (char*) ((sys_var*) value)->value_ptr(thd, OPT_GLOBAL, &null_lex_str); } @@ -5669,6 +5779,7 @@ ST_FIELD_INFO referential_constraints_fields_info[]= {"UPDATE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, {"DELETE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"REFERENCED_TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} }; @@ -5753,3 +5864,54 @@ ST_SCHEMA_TABLE schema_tables[]= template class List_iterator_fast<char>; template class List<char>; #endif + +int initialize_schema_table(st_plugin_int *plugin) +{ + ST_SCHEMA_TABLE *schema_table; + DBUG_ENTER("initialize_schema_table"); + + if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE), + MYF(MY_WME | MY_ZEROFILL)))) + DBUG_RETURN(1); + /* Historical Requirement */ + plugin->data= schema_table; // shortcut for the future + if (plugin->plugin->init) + { + schema_table->create_table= create_schema_table; + schema_table->old_format= make_old_format; + schema_table->idx_field1= -1, + schema_table->idx_field2= -1; + + if (plugin->plugin->init(schema_table)) + { + sql_print_error("Plugin '%s' init function returned error.", + plugin->name.str); + goto err; + } + schema_table->table_name= plugin->name.str; + } + + DBUG_RETURN(0); +err: + my_free((gptr)schema_table, MYF(0)); + DBUG_RETURN(1); +} + +int finalize_schema_table(st_plugin_int *plugin) +{ + ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data; + DBUG_ENTER("finalize_schema_table"); + + if (schema_table && plugin->plugin->deinit) + { + DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str)); + if (plugin->plugin->deinit(NULL)) + { + DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.", + plugin->name.str)); + } + my_free((gptr)schema_table, MYF(0)); + } + + DBUG_RETURN(0); +} diff --git a/sql/sql_show.h b/sql/sql_show.h index 29cd52eb9fd..d5c3f3bf675 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -1,3 +1,17 @@ +/* Copyright (C) 2006 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_SHOW_H #define SQL_SHOW_H diff --git a/sql/sql_sort.h b/sql/sql_sort.h index e39ea1aaf38..1572f6304e1 100644 --- a/sql/sql_sort.h +++ b/sql/sql_sort.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_state.c b/sql/sql_state.c index 355b847f239..511dc65917b 100644 --- a/sql/sql_state.c +++ b/sql/sql_state.c @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 29b53560067..52af2f2dd90 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -608,27 +607,26 @@ skip: } /* -** replace substring with string -** If wrong parameter or not enough memory, do nothing + Replace substring with string + If wrong parameter or not enough memory, do nothing */ - bool String::replace(uint32 offset,uint32 arg_length,const String &to) { return replace(offset,arg_length,to.ptr(),to.length()); } bool String::replace(uint32 offset,uint32 arg_length, - const char *to,uint32 length) + const char *to, uint32 to_length) { - long diff = (long) length-(long) arg_length; + long diff = (long) to_length-(long) arg_length; if (offset+arg_length <= str_length) { if (diff < 0) { - if (length) - memcpy(Ptr+offset,to,length); - bmove(Ptr+offset+length,Ptr+offset+arg_length, + if (to_length) + memcpy(Ptr+offset,to,to_length); + bmove(Ptr+offset+to_length,Ptr+offset+arg_length, str_length-offset-arg_length); } else @@ -640,8 +638,8 @@ bool String::replace(uint32 offset,uint32 arg_length, bmove_upp(Ptr+str_length+diff,Ptr+str_length, str_length-offset-arg_length); } - if (length) - memcpy(Ptr+offset,to,length); + if (to_length) + memcpy(Ptr+offset,to,to_length); } str_length+=(uint32) diff; } @@ -1023,8 +1021,8 @@ void String::print(String *str) case '\r': str->append(STRING_WITH_LEN("\\r")); break; - case 26: //Ctrl-Z - str->append(STRING_WITH_LEN("\\z")); + case '\032': // Ctrl-Z + str->append(STRING_WITH_LEN("\\Z")); break; default: str->append(c); diff --git a/sql/sql_string.h b/sql/sql_string.h index 6481c20d042..128ed749b5f 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -85,7 +84,8 @@ public: { /* never called */ } ~String() { free(); } - inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; } + inline void set_charset(CHARSET_INFO *charset_arg) + { str_charset= charset_arg; } inline CHARSET_INFO *charset() const { return str_charset; } inline uint32 length() const { return str_length;} inline uint32 alloced_length() const { return Alloced_length;} diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c8f6e09fecb..0697fdd79b4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -42,7 +41,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, static bool prepare_blob_field(THD *thd, create_field *sql_field); static bool check_engine(THD *thd, const char *table_name, - HA_CREATE_INFO *create_info); + HA_CREATE_INFO *create_info); static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, List<create_field> *fields, List<Key> *keys, bool tmp_table, @@ -461,10 +460,10 @@ static bool write_ddl_log_header() global_ddl_log.num_entries); const_var= FN_LEN; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], - const_var); + (ulong) const_var); const_var= IO_SIZE; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], - const_var); + (ulong) const_var); if (write_ddl_log_file_entry(0UL)) { sql_print_error("Error writing ddl log header"); @@ -599,7 +598,6 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) static bool init_ddl_log() { - bool error= FALSE; char file_name[FN_REFLEN]; DBUG_ENTER("init_ddl_log"); @@ -2024,10 +2022,10 @@ int prepare_create_field(create_field *sql_field, DBUG_ASSERT(sql_field->charset); switch (sql_field->sql_type) { - case FIELD_TYPE_BLOB: - case FIELD_TYPE_MEDIUM_BLOB: - case FIELD_TYPE_TINY_BLOB: - case FIELD_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_LONG_BLOB: sql_field->pack_flag=FIELDFLAG_BLOB | pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr); @@ -2037,7 +2035,7 @@ int prepare_create_field(create_field *sql_field, sql_field->unireg_check=Field::BLOB_FIELD; (*blob_columns)++; break; - case FIELD_TYPE_GEOMETRY: + case MYSQL_TYPE_GEOMETRY: #ifdef HAVE_SPATIAL if (!(table_flags & HA_CAN_GEOMETRY)) { @@ -2077,12 +2075,12 @@ int prepare_create_field(create_field *sql_field, } #endif /* fall through */ - case FIELD_TYPE_STRING: + case MYSQL_TYPE_STRING: sql_field->pack_flag=0; if (sql_field->charset->state & MY_CS_BINSORT) sql_field->pack_flag|=FIELDFLAG_BINARY; break; - case FIELD_TYPE_ENUM: + case MYSQL_TYPE_ENUM: sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | FIELDFLAG_INTERVAL; if (sql_field->charset->state & MY_CS_BINSORT) @@ -2092,7 +2090,7 @@ int prepare_create_field(create_field *sql_field, sql_field->interval, sql_field->charset); break; - case FIELD_TYPE_SET: + case MYSQL_TYPE_SET: sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | FIELDFLAG_BITFIELD; if (sql_field->charset->state & MY_CS_BINSORT) @@ -2102,19 +2100,19 @@ int prepare_create_field(create_field *sql_field, sql_field->interval, sql_field->charset); break; - case FIELD_TYPE_DATE: // Rest of string types - case FIELD_TYPE_NEWDATE: - case FIELD_TYPE_TIME: - case FIELD_TYPE_DATETIME: - case FIELD_TYPE_NULL: + case MYSQL_TYPE_DATE: // Rest of string types + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_NULL: sql_field->pack_flag=f_settype((uint) sql_field->sql_type); break; - case FIELD_TYPE_BIT: + case MYSQL_TYPE_BIT: /* We have sql_field->pack_flag already set here, see mysql_prepare_table(). */ break; - case FIELD_TYPE_NEWDECIMAL: + case MYSQL_TYPE_NEWDECIMAL: sql_field->pack_flag=(FIELDFLAG_NUMBER | (sql_field->flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | @@ -2122,7 +2120,7 @@ int prepare_create_field(create_field *sql_field, FIELDFLAG_ZEROFILL : 0) | (sql_field->decimals << FIELDFLAG_DEC_SHIFT)); break; - case FIELD_TYPE_TIMESTAMP: + case MYSQL_TYPE_TIMESTAMP: /* We should replace old TIMESTAMP fields with their newer analogs */ if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD) { @@ -2247,10 +2245,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, */ if (sql_field->def && save_cs != sql_field->def->collation.collation && - (sql_field->sql_type == FIELD_TYPE_VAR_STRING || - sql_field->sql_type == FIELD_TYPE_STRING || - sql_field->sql_type == FIELD_TYPE_SET || - sql_field->sql_type == FIELD_TYPE_ENUM)) + (sql_field->sql_type == MYSQL_TYPE_VAR_STRING || + sql_field->sql_type == MYSQL_TYPE_STRING || + sql_field->sql_type == MYSQL_TYPE_SET || + sql_field->sql_type == MYSQL_TYPE_ENUM)) { Query_arena backup_arena; bool need_to_change_arena= !thd->stmt_arena->is_conventional(); @@ -2275,8 +2273,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } } - if (sql_field->sql_type == FIELD_TYPE_SET || - sql_field->sql_type == FIELD_TYPE_ENUM) + if (sql_field->sql_type == MYSQL_TYPE_SET || + sql_field->sql_type == MYSQL_TYPE_ENUM) { uint32 dummy; CHARSET_INFO *cs= sql_field->charset; @@ -2297,14 +2295,14 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, interval= sql_field->interval= typelib(stmt_root, sql_field->interval_list); - List_iterator<String> it(sql_field->interval_list); + List_iterator<String> int_it(sql_field->interval_list); String conv, *tmp; char comma_buf[2]; int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf, (uchar*) comma_buf + sizeof(comma_buf)); DBUG_ASSERT(comma_length > 0); - for (uint i= 0; (tmp= it++); i++) + for (uint i= 0; (tmp= int_it++); i++) { uint lengthsp; if (String::needs_conversion(tmp->length(), tmp->charset(), @@ -2322,7 +2320,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, interval->type_lengths[i]); interval->type_lengths[i]= lengthsp; ((uchar *)interval->type_names[i])[lengthsp]= '\0'; - if (sql_field->sql_type == FIELD_TYPE_SET) + if (sql_field->sql_type == MYSQL_TYPE_SET) { if (cs->coll->instr(cs, interval->type_names[i], interval->type_lengths[i], @@ -2336,7 +2334,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->interval_list.empty(); // Don't need interval_list anymore } - if (sql_field->sql_type == FIELD_TYPE_SET) + if (sql_field->sql_type == MYSQL_TYPE_SET) { uint32 field_length; if (sql_field->def != NULL) @@ -2372,10 +2370,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, calculate_interval_lengths(cs, interval, &dummy, &field_length); sql_field->length= field_length + (interval->count - 1); } - else /* FIELD_TYPE_ENUM */ + else /* MYSQL_TYPE_ENUM */ { uint32 field_length; - DBUG_ASSERT(sql_field->sql_type == FIELD_TYPE_ENUM); + DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM); if (sql_field->def != NULL) { String str, *def= sql_field->def->val_str(&str); @@ -2405,7 +2403,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1); } - if (sql_field->sql_type == FIELD_TYPE_BIT) + if (sql_field->sql_type == MYSQL_TYPE_BIT) { sql_field->pack_flag= FIELDFLAG_NUMBER; if (file->ha_table_flags() & HA_CAN_BIT_FIELD) @@ -3061,7 +3059,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field) MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen); DBUG_RETURN(1); } - sql_field->sql_type= FIELD_TYPE_BLOB; + sql_field->sql_type= MYSQL_TYPE_BLOB; sql_field->flags|= BLOB_FLAG; sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name, (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR", @@ -3072,7 +3070,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field) if ((sql_field->flags & BLOB_FLAG) && sql_field->length) { - if (sql_field->sql_type == FIELD_TYPE_BLOB) + if (sql_field->sql_type == MYSQL_TYPE_BLOB) { /* The user has given a length to the blob column */ sql_field->sql_type= get_blob_type_from_length(sql_field->length); @@ -3100,11 +3098,11 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field) void sp_prepare_create_field(THD *thd, create_field *sql_field) { - if (sql_field->sql_type == FIELD_TYPE_SET || - sql_field->sql_type == FIELD_TYPE_ENUM) + if (sql_field->sql_type == MYSQL_TYPE_SET || + sql_field->sql_type == MYSQL_TYPE_ENUM) { uint32 field_length, dummy; - if (sql_field->sql_type == FIELD_TYPE_SET) + if (sql_field->sql_type == MYSQL_TYPE_SET) { calculate_interval_lengths(sql_field->charset, sql_field->interval, &dummy, @@ -3112,7 +3110,7 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) sql_field->length= field_length + (sql_field->interval->count - 1); } - else /* FIELD_TYPE_ENUM */ + else /* MYSQL_TYPE_ENUM */ { calculate_interval_lengths(sql_field->charset, sql_field->interval, @@ -3122,7 +3120,7 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1); } - if (sql_field->sql_type == FIELD_TYPE_BIT) + if (sql_field->sql_type == MYSQL_TYPE_BIT) { sql_field->pack_flag= FIELDFLAG_NUMBER | FIELDFLAG_TREAT_BIT_AS_CHAR; @@ -3418,16 +3416,11 @@ bool mysql_create_table_internal(THD *thd, { #ifdef FN_DEVCHAR /* check if the table name contains FN_DEVCHAR when defined */ - const char *start= alias; - while (*start != '\0') + if (strchr(alias, FN_DEVCHAR)) { - if (*start == FN_DEVCHAR) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); - DBUG_RETURN(TRUE); - } - start++; - } + my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); + DBUG_RETURN(TRUE); + } #endif path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext, internal_tmp_table ? FN_IS_TMP : 0); @@ -4038,7 +4031,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *), int (view_operator_func)(THD *, TABLE_LIST*)) { - TABLE_LIST *table, *save_next_global, *save_next_local; + TABLE_LIST *table; SELECT_LEX *select= &thd->lex->select_lex; List<Item> field_list; Item *item; @@ -4072,46 +4065,48 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, thd->open_options|= extra_open_options; table->lock_type= lock_type; /* open only one table from local list of command */ - save_next_global= table->next_global; - table->next_global= 0; - save_next_local= table->next_local; - table->next_local= 0; - select->table_list.first= (byte*)table; - /* - Time zone tables and SP tables can be add to lex->query_tables list, - so it have to be prepared. - TODO: Investigate if we can put extra tables into argument instead of - using lex->query_tables - */ - lex->query_tables= table; - lex->query_tables_last= &table->next_global; - lex->query_tables_own_last= 0; - thd->no_warnings_for_error= no_warnings_for_error; - if (view_operator_func == NULL) - table->required_type=FRMTYPE_TABLE; - - /* - If we want to perform an admin operation on the log table - (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable - log tables - */ - - if (check_if_log_table(table->db_length, table->db, - table->table_name_length, - table->table_name, 1) && - lock_type >= TL_READ_NO_INSERT) { - disable_logs= 1; - logger.lock(); - logger.tmp_close_log_tables(thd); - } + TABLE_LIST *save_next_global, *save_next_local; + save_next_global= table->next_global; + table->next_global= 0; + save_next_local= table->next_local; + table->next_local= 0; + select->table_list.first= (byte*)table; + /* + Time zone tables and SP tables can be add to lex->query_tables list, + so it have to be prepared. + TODO: Investigate if we can put extra tables into argument instead of + using lex->query_tables + */ + lex->query_tables= table; + lex->query_tables_last= &table->next_global; + lex->query_tables_own_last= 0; + thd->no_warnings_for_error= no_warnings_for_error; + if (view_operator_func == NULL) + table->required_type=FRMTYPE_TABLE; - open_and_lock_tables(thd, table); - thd->no_warnings_for_error= 0; - table->next_global= save_next_global; - table->next_local= save_next_local; - thd->open_options&= ~extra_open_options; + /* + If we want to perform an admin operation on the log table + (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable + log tables + */ + + if (check_if_log_table(table->db_length, table->db, + table->table_name_length, + table->table_name, 1) && + lock_type >= TL_READ_NO_INSERT) + { + disable_logs= 1; + logger.lock(); + logger.tmp_close_log_tables(thd); + } + open_and_lock_tables(thd, table); + thd->no_warnings_for_error= 0; + table->next_global= save_next_global; + table->next_local= save_next_local; + thd->open_options&= ~extra_open_options; + } if (prepare_func) { switch ((*prepare_func)(thd, table, check_opt)) { @@ -4602,7 +4597,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, Table_ident *table_ident) { TABLE *tmp_table; - char src_path[FN_REFLEN], dst_path[FN_REFLEN], tmp_path[FN_REFLEN]; + char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char src_table_name_buff[FN_REFLEN], src_db_name_buff[FN_REFLEN]; uint dst_path_length; char *db= table->db; @@ -4613,7 +4608,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, bool res= TRUE, unlock_dst_table= FALSE; enum legacy_db_type not_used; HA_CREATE_INFO *create_info; - +#ifdef WITH_PARTITION_STORAGE_ENGINE + char tmp_path[FN_REFLEN]; +#endif TABLE_LIST src_tables_list, dst_tables_list; DBUG_ENTER("mysql_create_like_table"); @@ -4821,7 +4818,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, else unlock_dst_table= TRUE; - int result= store_create_info(thd, table, &query, create_info); + IF_DBUG(int result=) store_create_info(thd, table, &query, + create_info); DBUG_ASSERT(result == 0); // store_create_info() always return 0 write_bin_log(thd, TRUE, query.ptr(), query.length()); @@ -5304,10 +5302,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ALTER_INFO *alter_info, bool do_send_ok) { TABLE *table,*new_table=0; - int error; + int error= 0; char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN]; char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias; - char index_file[FN_REFLEN], data_file[FN_REFLEN]; + char index_file[FN_REFLEN], data_file[FN_REFLEN], tablespace[FN_LEN]; char path[FN_REFLEN]; char reg_path[FN_REFLEN+1]; ha_rows copied,deleted; @@ -5406,16 +5404,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } if (wait_if_global_read_lock(thd,0,1)) - DBUG_RETURN(1); + DBUG_RETURN(TRUE); VOID(pthread_mutex_lock(&LOCK_open)); if (lock_table_names(thd, table_list)) + { + error= 1; goto view_err; + } - error=0; if (!do_rename(thd, table_list, new_db, new_name, new_name, 1)) { if (mysql_bin_log.is_open()) @@ -5540,31 +5540,55 @@ view_err: if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { - VOID(pthread_mutex_lock(&LOCK_open)); - switch (alter_info->keys_onoff) { case LEAVE_AS_IS: - error= 0; break; case ENABLE: + /* + wait_while_table_is_used() ensures that table being altered is + opened only by this thread and that TABLE::TABLE_SHARE::version + of TABLE object corresponding to this table is 0. + The latter guarantees that no DML statement will open this table + until ALTER TABLE finishes (i.e. until close_thread_tables()) + while the fact that the table is still open gives us protection + from concurrent DDL statements. + */ + VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + VOID(pthread_mutex_unlock(&LOCK_open)); error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: + VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + VOID(pthread_mutex_unlock(&LOCK_open)); error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; + default: + DBUG_ASSERT(FALSE); + error= 0; + break; } if (error == HA_ERR_WRONG_COMMAND) { + error= 0; push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->alias); - error= 0; } + VOID(pthread_mutex_lock(&LOCK_open)); + /* + Unlike to the above case close_cached_table() below will remove ALL + instances of TABLE from table cache (it will also remove table lock + held by this thread). So to make actual table renaming and writing + to binlog atomic we have to put them into the same critical section + protected by LOCK_open mutex. This also removes gap for races between + access() and mysql_rename_table() calls. + */ + if (!error && (new_name != table_name || new_db != db)) { thd->proc_info="rename"; @@ -5593,10 +5617,10 @@ view_err: if (error == HA_ERR_WRONG_COMMAND) { + error= 0; push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->alias); - error= 0; } if (!error) @@ -5630,6 +5654,15 @@ view_err: if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) create_info->key_block_size= table->s->key_block_size; + if (!create_info->tablespace && create_info->storage_media != HA_SM_MEMORY) + { + /* + Regular alter table of disk stored table (no tablespace/storage change) + Copy tablespace name + */ + if ((table->file->get_tablespace_name(thd, tablespace, FN_LEN))) + create_info->tablespace= tablespace; + } restore_record(table, s->default_values); // Empty record for DEFAULT List_iterator<Alter_drop> drop_it(alter_info->drop_list); List_iterator<create_field> def_it(fields); @@ -5703,7 +5736,7 @@ view_err: } if (alter) { - if (def->sql_type == FIELD_TYPE_BLOB) + if (def->sql_type == MYSQL_TYPE_BLOB) { my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change); DBUG_RETURN(TRUE); @@ -6613,7 +6646,8 @@ view_err: thd->query, thd->query_length, db, table_name); - DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based && + DBUG_ASSERT(!(mysql_bin_log.is_open() && + thd->current_stmt_binlog_row_based && (create_info->options & HA_LEX_CREATE_TMP_TABLE))); write_bin_log(thd, TRUE, thd->query, thd->query_length); @@ -6676,7 +6710,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, Copy_field *copy,*copy_end; ulong found_count,delete_count; THD *thd= current_thd; - uint length; + uint length= 0; SORT_FIELD *sortorder; READ_RECORD info; TABLE_LIST tables; @@ -6805,7 +6839,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, uint key_nr= to->file->get_dup_key(error); if ((int) key_nr >= 0) { - const char *err_msg= ER(ER_DUP_ENTRY); + const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME); if (key_nr == 0 && (to->key_info[0].key_part[0].field->flags & AUTO_INCREMENT_FLAG)) @@ -6973,7 +7007,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, for (uint i= 0; i < t->s->fields; i++ ) { Field *f= t->field[i]; - if ((f->type() == FIELD_TYPE_BLOB) || + if ((f->type() == MYSQL_TYPE_BLOB) || (f->type() == MYSQL_TYPE_VARCHAR)) { String tmp; diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 470fa5bc862..84391a54642 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_test.cc b/sql/sql_test.cc index d2d65d662ea..07bd1390116 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -74,17 +73,18 @@ void print_cached_tables(void) uint idx,count,unused; TABLE *start_link,*lnk; + /* purecov: begin tested */ VOID(pthread_mutex_lock(&LOCK_open)); - puts("DB Table Version Thread L.thread Open Lock"); + puts("DB Table Version Thread Open Lock"); for (idx=unused=0 ; idx < open_cache.records ; idx++) { TABLE *entry=(TABLE*) hash_element(&open_cache,idx); - printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n", - entry->s->db.str, entry->s->table_name.str, entry->s->version, + printf("%-14.14s %-32s%6ld%8ld%6d %s\n", + entry->s->db.str, entry->s->table_name.str, entry->s->version, entry->in_use ? entry->in_use->thread_id : 0L, - entry->in_use ? entry->in_use->dbug_thread_id : 0L, - entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use"); + entry->db_stat ? 1 : 0, + entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use"); if (!entry->in_use) unused++; } @@ -111,6 +111,7 @@ void print_cached_tables(void) printf("Error: File hash table is corrupted\n"); fflush(stdout); VOID(pthread_mutex_unlock(&LOCK_open)); + /* purecov: end */ return; } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 8ca72eab8bf..df363c3c21c 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -782,7 +781,7 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) table == (*fld)->table))) return 1; (*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] - - table->record[0])); + table->record[0])); } *old_fld= 0; @@ -800,8 +799,8 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) void Table_triggers_list::set_table(TABLE *new_table) { - table= new_table; - for (Field **field= table->triggers->record1_field ; *field ; field++) + trigger_table= new_table; + for (Field **field= new_table->triggers->record1_field ; *field ; field++) { (*field)->table= (*field)->orig_table= new_table; (*field)->table_name= &new_table->alias; @@ -1364,7 +1363,8 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd, It is OK to allocate some memory on table's MEM_ROOT since this table instance will be thrown out at the end of rename anyway. */ - new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length()); + new_def.str= memdup_root(&trigger_table->mem_root, buff.ptr(), + buff.length()); new_def.length= buff.length(); on_table_name->str= new_def.str + before_on_len; on_table_name->length= on_q_table_name_len; @@ -1542,12 +1542,12 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, if (old_row_is_record1) { old_field= record1_field; - new_field= table->field; + new_field= trigger_table->field; } else { new_field= record1_field; - old_field= table->field; + old_field= trigger_table->field; } #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *save_ctx; @@ -1563,7 +1563,8 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, fill_effective_table_privileges(thd, &subject_table_grants[event][time_type], - table->s->db.str, table->s->table_name.str); + trigger_table->s->db.str, + trigger_table->s->table_name.str); /* Check that the definer has TRIGGER privilege on the subject table. */ @@ -1574,7 +1575,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc, thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, - table->s->table_name.str); + trigger_table->s->table_name.str); sp_restore_security_context(thd, save_ctx); return TRUE; @@ -1583,7 +1584,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); err_status= sp_trigger->execute_trigger - (thd, table->s->db.str, table->s->table_name.str, + (thd, trigger_table->s->db.str, trigger_table->s->table_name.str, &subject_table_grants[event][time_type]); thd->restore_sub_statement_state(&statement_state); @@ -1624,13 +1625,13 @@ void Table_triggers_list::mark_fields_used(trg_event_type event) /* We cannot mark fields which does not present in table. */ if (trg_field->field_idx != (uint)-1) { - bitmap_set_bit(table->read_set, trg_field->field_idx); + bitmap_set_bit(trigger_table->read_set, trg_field->field_idx); if (trg_field->get_settable_routine_parameter()) - bitmap_set_bit(table->write_set, trg_field->field_idx); + bitmap_set_bit(trigger_table->write_set, trg_field->field_idx); } } } - table->file->column_bitmaps_signal(); + trigger_table->file->column_bitmaps_signal(); } diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 09576f5e523..75dda6be1cf 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -43,8 +42,9 @@ class Table_triggers_list: public Sql_alloc */ Field **new_field; Field **old_field; + /* TABLE instance for which this triggers list object was created */ - TABLE *table; + TABLE *trigger_table; /* Names of triggers. Should correspond to order of triggers on definitions_list, @@ -84,7 +84,7 @@ public: List<LEX_STRING> definers_list; Table_triggers_list(TABLE *table_arg): - record1_field(0), table(table_arg) + record1_field(0), trigger_table(table_arg) { bzero((char *)bodies, sizeof(bodies)); bzero((char *)trigger_fields, sizeof(trigger_fields)); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index f0d31965573..7dec58d9b6e 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -482,6 +481,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) TABLE *table; TABLE_LIST tables; udf_func *udf; + char *exact_name_str; + uint exact_name_len; DBUG_ENTER("mysql_drop_function"); if (!initialized) { @@ -495,6 +496,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str); goto err; } + exact_name_str= udf->name.str; + exact_name_len= udf->name.length; del_udf(udf); /* Close the handle if this was function that was found during boot or @@ -509,7 +512,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; table->use_all_columns(); - table->field[0]->store(udf_name->str, udf_name->length, system_charset_info); + table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); if (!table->file->index_read_idx(table->record[0], 0, (byte*) table->field[0]->ptr, table->key_info[0].key_length, diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 21cf735f5ab..3cd9343610c 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2003-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 0715a0c4296..9fe20c502d6 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -112,7 +111,7 @@ bool select_union::flush() */ bool -select_union::create_result_table(THD *thd, List<Item> *column_types, +select_union::create_result_table(THD *thd_arg, List<Item> *column_types, bool is_union_distinct, ulonglong options, const char *alias) { @@ -120,7 +119,7 @@ select_union::create_result_table(THD *thd, List<Item> *column_types, tmp_table_param.init(); tmp_table_param.field_count= column_types->elements; - if (! (table= create_tmp_table(thd, &tmp_table_param, *column_types, + if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, (ORDER*) 0, is_union_distinct, 1, options, HA_POS_ERROR, (char*) alias))) return TRUE; @@ -142,9 +141,9 @@ select_union::create_result_table(THD *thd, List<Item> *column_types, */ void -st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) +st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg) { - thd->lex->current_select= fake_select_lex; + thd_arg->lex->current_select= fake_select_lex; fake_select_lex->table_list.link_in_list((byte *)&result_table_list, (byte **) &result_table_list.next_local); @@ -198,7 +197,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, DBUG_RETURN(FALSE); } prepared= 1; - res= FALSE; + saved_error= FALSE; thd_arg->lex->current_select= sl= first_sl; found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS; @@ -239,23 +238,25 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, can_skip_order_by= is_union && !(sl->braces && sl->explicit_limit); - res= join->prepare(&sl->ref_pointer_array, - (TABLE_LIST*) sl->table_list.first, sl->with_wild, - sl->where, - (can_skip_order_by ? 0 : sl->order_list.elements) + - sl->group_list.elements, - can_skip_order_by ? - (ORDER*) 0 : (ORDER *)sl->order_list.first, - (ORDER*) sl->group_list.first, - sl->having, - (is_union ? (ORDER*) 0 : - (ORDER*) thd_arg->lex->proc_list.first), - sl, this); + saved_error= join->prepare(&sl->ref_pointer_array, + (TABLE_LIST*) sl->table_list.first, + sl->with_wild, + sl->where, + (can_skip_order_by ? 0 : + sl->order_list.elements) + + sl->group_list.elements, + can_skip_order_by ? + (ORDER*) 0 : (ORDER *)sl->order_list.first, + (ORDER*) sl->group_list.first, + sl->having, + (is_union ? (ORDER*) 0 : + (ORDER*) thd_arg->lex->proc_list.first), + sl, this); /* There are no * in the statement anymore (for PS) */ sl->with_wild= 0; last_procedure= join->procedure; - if ((res= (res || thd_arg->is_fatal_error))) + if (saved_error || (saved_error= thd_arg->is_fatal_error)) goto err; /* Use items list of underlaid select for derived tables to preserve @@ -350,12 +351,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, arena= thd->activate_stmt_arena_if_needed(&backup_arena); - res= table->fill_item_list(&item_list); + saved_error= table->fill_item_list(&item_list); if (arena) thd->restore_active_arena(arena, &backup_arena); - if (res) + if (saved_error) goto err; if (thd->stmt_arena->is_stmt_prepare()) @@ -374,7 +375,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, fake_select_lex->item_list= item_list; thd_arg->lex->current_select= fake_select_lex; - res= fake_select_lex->join-> + saved_error= fake_select_lex->join-> prepare(&fake_select_lex->ref_pointer_array, (TABLE_LIST*) fake_select_lex->table_list.first, 0, 0, @@ -399,7 +400,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, thd_arg->lex->current_select= lex_select_save; - DBUG_RETURN(res || thd_arg->is_fatal_error); + DBUG_RETURN(saved_error || thd_arg->is_fatal_error); err: thd_arg->lex->current_select= lex_select_save; @@ -443,7 +444,7 @@ bool st_select_lex_unit::exec() thd->lex->current_select= sl; if (optimized) - res= sl->join->reinit(); + saved_error= sl->join->reinit(); else { set_limit(sl); @@ -466,9 +467,9 @@ bool st_select_lex_unit::exec() sl->join->select_options= (select_limit_cnt == HA_POS_ERROR || sl->braces) ? sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; - res= sl->join->optimize(); + saved_error= sl->join->optimize(); } - if (!res) + if (!saved_error) { records_at_start= table->file->stats.records; sl->join->exec(); @@ -478,11 +479,11 @@ bool st_select_lex_unit::exec() DBUG_RETURN(TRUE); table->no_keyread=1; } - res= sl->join->error; + saved_error= sl->join->error; offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : 0); - if (!res) + if (!saved_error) { examined_rows+= thd->examined_row_count; if (union_result->flush()) @@ -492,10 +493,10 @@ bool st_select_lex_unit::exec() } } } - if (res) + if (saved_error) { thd->lex->current_select= lex_select_save; - DBUG_RETURN(res); + DBUG_RETURN(saved_error); } /* Needed for the following test and for records_at_start in next loop */ int error= table->file->info(HA_STATUS_VARIABLE); @@ -521,7 +522,7 @@ bool st_select_lex_unit::exec() optimized= 1; /* Send result to 'result' */ - res= TRUE; + saved_error= TRUE; { List<Item_func_match> empty_list; empty_list.empty(); @@ -562,17 +563,17 @@ bool st_select_lex_unit::exec() } join->init(thd, item_list, fake_select_lex->options, result); } - res= mysql_select(thd, &fake_select_lex->ref_pointer_array, - &result_table_list, - 0, item_list, NULL, - global_parameters->order_list.elements, - (ORDER*)global_parameters->order_list.first, - (ORDER*) NULL, NULL, (ORDER*) NULL, - fake_select_lex->options | SELECT_NO_UNLOCK, - result, this, fake_select_lex); + saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, + &result_table_list, + 0, item_list, NULL, + global_parameters->order_list.elements, + (ORDER*)global_parameters->order_list.first, + (ORDER*) NULL, NULL, (ORDER*) NULL, + fake_select_lex->options | SELECT_NO_UNLOCK, + result, this, fake_select_lex); fake_select_lex->table_list.empty(); - if (!res) + if (!saved_error) { thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows; thd->examined_row_count+= examined_rows; @@ -584,7 +585,7 @@ bool st_select_lex_unit::exec() } } thd->lex->current_select= lex_select_save; - DBUG_RETURN(res); + DBUG_RETURN(saved_error); } @@ -661,18 +662,18 @@ void st_select_lex_unit::reinit_exec_mechanism() TRUE - error */ -bool st_select_lex_unit::change_result(select_subselect *result, +bool st_select_lex_unit::change_result(select_subselect *new_result, select_subselect *old_result) { bool res= FALSE; for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { if (sl->join && sl->join->result == old_result) - if (sl->join->change_result(result)) + if (sl->join->change_result(new_result)) return TRUE; } if (fake_select_lex && fake_select_lex->join) - res= fake_select_lex->join->change_result(result); + res= fake_select_lex->join->change_result(new_result); return (res); } @@ -735,6 +736,7 @@ bool st_select_lex::cleanup() { error= (bool) ((uint) error | (uint) lex_unit->cleanup()); } + non_agg_fields.empty(); DBUG_RETURN(error); } @@ -751,4 +753,3 @@ void st_select_lex::cleanup_all_joins(bool full) for (sl= unit->first_select(); sl; sl= sl->next_select()) sl->cleanup_all_joins(full); } - diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a379ea66db6..a8b7efcc1bd 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,11 +24,9 @@ #include "sp_head.h" #include "sql_trigger.h" -static bool safe_update_on_fly(JOIN_TAB *join_tab); - /* Return 0 if row hasn't changed */ -static bool compare_record(TABLE *table) +bool compare_record(TABLE *table) { if (table->s->blob_fields + table->s->varchar_fields == 0) return cmp_record(table,record[1]); @@ -67,7 +64,6 @@ static bool check_fields(THD *thd, List<Item> &items) List_iterator<Item> it(items); Item *item; Item_field *field; - Name_resolution_context *context= &thd->lex->select_lex.context; while ((item= it++)) { @@ -321,7 +317,7 @@ int mysql_update(THD *thd, to update NOTE: filesort will call table->prepare_for_position() */ - uint length; + uint length= 0; SORT_FIELD *sortorder; ha_rows examined_rows; @@ -1161,27 +1157,71 @@ int multi_update::prepare(List<Item> ¬_used_values, for (i=0 ; i < table_count ; i++) set_if_bigger(max_fields, fields_for_table[i]->elements); copy_field= new Copy_field[max_fields]; + DBUG_RETURN(thd->is_fatal_error != 0); +} - /* - Mark all copies of tables that are updates to ensure that - init_read_record() will not try to enable a cache on them - The problem is that for queries like +/* + Check if table is safe to update on fly - UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a; + SYNOPSIS + safe_update_on_fly() + thd Thread handler + join_tab How table is used in join + all_tables List of tables - the row buffer may contain things that doesn't match what is on disk - which will cause an error when reading a row. - (This issue is mostly relevent for MyISAM tables) - */ - for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) - { - TABLE *table=table_ref->table; - if ((tables_to_update & table->map) && - unique_table(thd, table_ref, update_tables)) - table->no_cache= 1; // Disable row cache + NOTES + We can update the first table in join on the fly if we know that + a row in this table will never be read twice. This is true under + the following conditions: + + - We are doing a table scan and the data is in a separate file (MyISAM) or + if we don't update a clustered key. + + - We are doing a range scan and we don't update the scan key or + the primary key for a clustered table handler. + + - Table is not joined to itself. + + This function gets information about fields to be updated from + the TABLE::write_set bitmap. + + WARNING + This code is a bit dependent of how make_join_readinfo() works. + + RETURN + 0 Not safe to update + 1 Safe to update +*/ + +static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab, + TABLE_LIST *table_ref, TABLE_LIST *all_tables) +{ + TABLE *table= join_tab->table; + if (unique_table(thd, table_ref, all_tables)) + return 0; + switch (join_tab->type) { + case JT_SYSTEM: + case JT_CONST: + case JT_EQ_REF: + return TRUE; // At most one matching row + case JT_REF: + case JT_REF_OR_NULL: + return !is_key_used(table, join_tab->ref.key, table->write_set); + case JT_ALL: + /* If range search on index */ + if (join_tab->quick) + return !join_tab->quick->is_keys_used(table->write_set); + /* If scanning in clustered key */ + if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && + table->s->primary_key < MAX_KEY) + return !is_key_used(table, table->s->primary_key, table->write_set); + return TRUE; + default: + break; // Avoid compler warning } - DBUG_RETURN(thd->is_fatal_error != 0); + return FALSE; + } @@ -1221,7 +1261,7 @@ multi_update::initialize_tables(JOIN *join) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (table == main_table) // First table in join { - if (safe_update_on_fly(join->join_tab)) + if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables)) { table_to_update= main_table; // Update table on the fly continue; @@ -1273,61 +1313,6 @@ multi_update::initialize_tables(JOIN *join) DBUG_RETURN(0); } -/* - Check if table is safe to update on fly - - SYNOPSIS - safe_update_on_fly - join_tab How table is used in join - - NOTES - We can update the first table in join on the fly if we know that - a row in this table will never be read twice. This is true under - the following conditions: - - - We are doing a table scan and the data is in a separate file (MyISAM) or - if we don't update a clustered key. - - - We are doing a range scan and we don't update the scan key or - the primary key for a clustered table handler. - - This function gets information about fields to be updated from - the TABLE::write_set bitmap. - - WARNING - This code is a bit dependent of how make_join_readinfo() works. - - RETURN - 0 Not safe to update - 1 Safe to update -*/ - -static bool safe_update_on_fly(JOIN_TAB *join_tab) -{ - TABLE *table= join_tab->table; - switch (join_tab->type) { - case JT_SYSTEM: - case JT_CONST: - case JT_EQ_REF: - return TRUE; // At most one matching row - case JT_REF: - case JT_REF_OR_NULL: - return !is_key_used(table, join_tab->ref.key, table->write_set); - case JT_ALL: - /* If range search on index */ - if (join_tab->quick) - return !join_tab->quick->is_keys_used(table->write_set); - /* If scanning in clustered key */ - if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && - table->s->primary_key < MAX_KEY) - return !is_key_used(table, table->s->primary_key, table->write_set); - return TRUE; - default: - break; // Avoid compler warning - } - return FALSE; -} - multi_update::~multi_update() { @@ -1584,6 +1569,15 @@ int multi_update::do_updates(bool from_send_error) if (!can_compare_record || compare_record(table)) { + int error; + if ((error= cur_table->view_check_option(thd, ignore)) != + VIEW_CHECK_OK) + { + if (error == VIEW_CHECK_SKIP) + continue; + else if (error == VIEW_CHECK_ERROR) + goto err; + } if ((local_error=table->file->ha_update_row(table->record[1], table->record[0]))) { diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 7a8a85dceed..622f7b99d33 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -714,7 +713,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, File_parser *parser; path.str= path_buff; - fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME); + fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME); path.length= strlen(path_buff); if (!access(path.str, F_OK)) @@ -863,7 +862,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, Query_arena *arena, backup; TABLE_LIST *top_view= table->top_table(); int res; - bool result; + bool result, view_is_mergeable; + TABLE_LIST *view_main_select_tables; DBUG_ENTER("mysql_make_view"); DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name)); @@ -1090,17 +1090,14 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, table->next_global= view_tables; } -#ifdef HAVE_ROW_BASED_REPLICATION /* If the view's body needs row-based binlogging (e.g. the VIEW is created from SELECT UUID()), the top statement also needs it. */ if (lex->binlog_row_based_if_mixed) old_lex->binlog_row_based_if_mixed= TRUE; -#endif - bool view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE && - lex->can_be_merged()); - TABLE_LIST *view_main_select_tables; + view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE && + lex->can_be_merged()); LINT_INIT(view_main_select_tables); if (view_is_mergeable) @@ -1147,13 +1144,17 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, /* Prepare a security context to check underlying objects of the view */ - Security_context *save_security_ctx= thd->security_ctx; if (!(table->view_sctx= (Security_context *) thd->stmt_arena->alloc(sizeof(Security_context)))) goto err; /* Assign the context to the tables referenced in the view */ - for (tbl= view_tables; tbl; tbl= tbl->next_global) - tbl->security_ctx= table->view_sctx; + if (view_tables) + { + DBUG_ASSERT(view_tables_tail); + for (tbl= view_tables; tbl != view_tables_tail->next_global; + tbl= tbl->next_global) + tbl->security_ctx= table->view_sctx; + } /* assign security context to SELECT name resolution contexts of view */ for(SELECT_LEX *sl= lex->all_selects_list; sl; @@ -1271,6 +1272,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, but it will not be included to SELECT_LEX tree, because it will not be executed */ + table->select_lex->order_list.push_back(&lex->select_lex.order_list); goto ok; } diff --git a/sql/sql_view.h b/sql/sql_view.h index fc480167216..d3c83c82f44 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -3,8 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 704c505ded9..9c062407921 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -55,6 +54,28 @@ const LEX_STRING null_lex_str={0,0}; YYABORT; \ } +/* + Work around for broken code generated by bison 1.875. + + The code generated by bison 1.875a and later, bison 2.1 and bison 2.2 is ok. + With bison 1.875 however, the generated code contains: +<pre> + yyerrlab1: + #if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) + __attribute__ ((__unused__)) + #endif +</pre> + This usage of __attribute__ is illegal, so we remove it. + See the following references for details: + http://lists.gnu.org/archive/html/bug-bison/2004-02/msg00014.html + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14273 +*/ + +#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) +#undef __attribute__ +#define __attribute__(X) +#endif + /* Helper for parsing "IS [NOT] truth_value" */ inline Item *is_truth_value(THD *thd, Item *A, bool v1, bool v2) { @@ -108,6 +129,187 @@ static bool is_native_function(THD *thd, const LEX_STRING *name) return false; } + +/** + Helper action for a case statement (entering the CASE). + This helper is used for both 'simple' and 'searched' cases. + This helper, with the other case_stmt_action_..., is executed when + the following SQL code is parsed: +<pre> +CREATE PROCEDURE proc_19194_simple(i int) +BEGIN + DECLARE str CHAR(10); + + CASE i + WHEN 1 THEN SET str="1"; + WHEN 2 THEN SET str="2"; + WHEN 3 THEN SET str="3"; + ELSE SET str="unknown"; + END CASE; + + SELECT str; +END +</pre> + The actions are used to generate the following code: +<pre> +SHOW PROCEDURE CODE proc_19194_simple; +Pos Instruction +0 set str@1 NULL +1 set_case_expr (12) 0 i@0 +2 jump_if_not 5(12) (case_expr@0 = 1) +3 set str@1 _latin1'1' +4 jump 12 +5 jump_if_not 8(12) (case_expr@0 = 2) +6 set str@1 _latin1'2' +7 jump 12 +8 jump_if_not 11(12) (case_expr@0 = 3) +9 set str@1 _latin1'3' +10 jump 12 +11 set str@1 _latin1'unknown' +12 stmt 0 "SELECT str" +</pre> + + @param lex the parser lex context +*/ + +void case_stmt_action_case(LEX *lex) +{ + lex->sphead->new_cont_backpatch(NULL); + + /* + BACKPATCH: Creating target label for the jump to + "case_stmt_action_end_case" + (Instruction 12 in the example) + */ + + lex->spcont->push_label((char *)"", lex->sphead->instructions()); +} + +/** + Helper action for a case expression statement (the expr in 'CASE expr'). + This helper is used for 'searched' cases only. + @param lex the parser lex context + @param expr the parsed expression + @return 0 on success +*/ + +int case_stmt_action_expr(LEX *lex, Item* expr) +{ + sp_head *sp= lex->sphead; + sp_pcontext *parsing_ctx= lex->spcont; + int case_expr_id= parsing_ctx->register_case_expr(); + sp_instr_set_case_expr *i; + + if (parsing_ctx->push_case_expr_id(case_expr_id)) + return 1; + + i= new sp_instr_set_case_expr(sp->instructions(), + parsing_ctx, case_expr_id, expr, lex); + + sp->add_cont_backpatch(i); + sp->add_instr(i); + + return 0; +} + +/** + Helper action for a case when condition. + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context + @param when the parsed expression for the WHEN clause + @param simple true for simple cases, false for searched cases +*/ + +void case_stmt_action_when(LEX *lex, Item *when, bool simple) +{ + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump_if_not *i; + Item_case_expr *var; + Item *expr; + + if (simple) + { + var= new Item_case_expr(ctx->get_current_case_expr_id()); + +#ifndef DBUG_OFF + if (var) + { + var->m_sp= sp; + } +#endif + + expr= new Item_func_eq(var, when); + i= new sp_instr_jump_if_not(ip, ctx, expr, lex); + } + else + i= new sp_instr_jump_if_not(ip, ctx, when, lex); + + /* + BACKPATCH: Registering forward jump from + "case_stmt_action_when" to "case_stmt_action_then" + (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example) + */ + + sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); + sp->add_instr(i); +} + +/** + Helper action for a case then statements. + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context +*/ + +void case_stmt_action_then(LEX *lex) +{ + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump *i = new sp_instr_jump(ip, ctx); + sp->add_instr(i); + + /* + BACKPATCH: Resolving forward jump from + "case_stmt_action_when" to "case_stmt_action_then" + (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example) + */ + + sp->backpatch(ctx->pop_label()); + + /* + BACKPATCH: Registering forward jump from + "case_stmt_action_then" to "case_stmt_action_end_case" + (jump from instruction 4 to 12, 7 to 12 ... in the example) + */ + + sp->push_backpatch(i, ctx->last_label()); +} + +/** + Helper action for an end case. + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context + @param simple true for simple cases, false for searched cases +*/ + +void case_stmt_action_end_case(LEX *lex, bool simple) +{ + /* + BACKPATCH: Resolving forward jump from + "case_stmt_action_then" to "case_stmt_action_end_case" + (jump from instruction 4 to 12, 7 to 12 ... in the example) + */ + lex->sphead->backpatch(lex->spcont->pop_label()); + + if (simple) + lex->spcont->pop_case_expr_id(); + + lex->sphead->do_cont_backpatch(); +} + %} %union { int num; @@ -354,9 +556,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token GLOBAL_SYM /* SQL-2003-R */ %token GRANT /* SQL-2003-R */ %token GRANTS -%token GROUP /* SQL-2003-R */ +%token GROUP_SYM /* SQL-2003-R */ %token GROUP_CONCAT_SYM -%token GROUP_UNIQUE_USERS %token GT_SYM /* OPERATOR */ %token HANDLER_SYM %token HASH_SYM @@ -364,6 +565,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token HELP_SYM %token HEX_NUM %token HIGH_PRIORITY +%token HOST_SYM %token HOSTS_SYM %token HOUR_MICROSECOND_SYM %token HOUR_MINUTE_SYM @@ -506,6 +708,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ONE_SYM %token OPEN_SYM /* SQL-2003-R */ %token OPTIMIZE +%token OPTIONS_SYM %token OPTION /* SQL-2003-N */ %token OPTIONALLY %token OR2_SYM @@ -515,6 +718,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OUTER %token OUTFILE %token OUT_SYM /* SQL-2003-R */ +%token OWNER_SYM %token PACK_KEYS_SYM %token PARAM_MARKER %token PARSER_SYM @@ -528,6 +732,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PLUGIN_SYM %token POINT_SYM %token POLYGON +%token PORT_SYM %token POSITION_SYM /* SQL-2003-N */ %token PRECISION /* SQL-2003-R */ %token PREPARE_SYM /* SQL-2003-R */ @@ -596,6 +801,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SERIALIZABLE_SYM /* SQL-2003-N */ %token SERIAL_SYM %token SESSION_SYM /* SQL-2003-N */ +%token SERVER_SYM +%token SERVER_OPTIONS %token SET /* SQL-2003-R */ %token SET_VAR %token SHARE_SYM @@ -608,6 +815,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SLAVE %token SMALLINT /* SQL-2003-R */ %token SNAPSHOT_SYM +%token SOCKET_SYM %token SONAME_SYM %token SOUNDS_SYM %token SPATIAL_SYM @@ -683,7 +891,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token UNINSTALL_SYM %token UNION_SYM /* SQL-2003-R */ %token UNIQUE_SYM -%token UNIQUE_USERS %token UNKNOWN_SYM /* SQL-2003-R */ %token UNLOCK_SYM %token UNSIGNED @@ -715,6 +922,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WHILE_SYM %token WITH /* SQL-2003-R */ %token WORK_SYM /* SQL-2003-N */ +%token WRAPPER_SYM %token WRITE_SYM /* SQL-2003-N */ %token X509_SYM %token XA_SYM @@ -879,7 +1087,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); select_item_list select_item values_list no_braces opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item - when_list2 expr_list2 udf_expr_list3 handler + expr_list2 udf_expr_list3 handler opt_precision opt_ignore opt_column opt_restrict grant revoke set lock unlock string_list field_options field_option field_opt_list opt_binary table_lock_list table_lock @@ -910,14 +1118,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); view_check_option trigger_tail sp_tail install uninstall partition_entry binlog_base64_event init_key_options key_options key_opts key_opt key_using_alg + server_def server_options_list server_option END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt %type <NONE> sp_proc_stmt_statement sp_proc_stmt_return -%type <NONE> sp_proc_stmt_if sp_proc_stmt_case_simple sp_proc_stmt_case +%type <NONE> sp_proc_stmt_if %type <NONE> sp_labeled_control sp_proc_stmt_unlabeled sp_proc_stmt_leave %type <NONE> sp_proc_stmt_iterate %type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close +%type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt %type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list %type <spcondtype> sp_cond sp_hcond @@ -1012,7 +1222,7 @@ statement: deallocate: deallocate_or_drop PREPARE_SYM ident { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; if (lex->stmt_prepare_mode) { @@ -1032,7 +1242,7 @@ deallocate_or_drop: prepare: PREPARE_SYM ident FROM prepare_src { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; if (lex->stmt_prepare_mode) { @@ -1046,14 +1256,14 @@ prepare: prepare_src: TEXT_STRING_sys { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; lex->prepared_stmt_code= $1; lex->prepared_stmt_code_is_varref= FALSE; } | '@' ident_or_text { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; lex->prepared_stmt_code= $2; lex->prepared_stmt_code_is_varref= TRUE; @@ -1062,7 +1272,7 @@ prepare_src: execute: EXECUTE_SYM ident { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; if (lex->stmt_prepare_mode) { @@ -1223,7 +1433,7 @@ create: CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident { THD *thd= YYTHD; - LEX *lex=Lex; + LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_TABLE; if (!lex->select_lex.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, @@ -1295,7 +1505,7 @@ create: { Lex->sql_command = SQLCOM_CREATE_USER; } - | CREATE LOGFILE_SYM GROUP logfile_group_info + | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info { Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP; } @@ -1303,8 +1513,61 @@ create: { Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE; } + | CREATE server_def + { + Lex->sql_command= SQLCOM_CREATE_SERVER; + } ; +server_def: + SERVER_SYM ident_or_text FOREIGN DATA_SYM WRAPPER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')' + { + Lex->server_options.server_name= $2.str; + Lex->server_options.server_name_length= $2.length; + Lex->server_options.scheme= $6.str; + } + ; +server_options_list: + server_option + | server_options_list ',' server_option + ; + +server_option: + USER TEXT_STRING_sys + { + Lex->server_options.username= $2.str; + } + | + HOST_SYM TEXT_STRING_sys + { + Lex->server_options.host= $2.str; + } + | + DATABASE TEXT_STRING_sys + { + Lex->server_options.db= $2.str; + } + | + OWNER_SYM TEXT_STRING_sys + { + Lex->server_options.owner= $2.str; + } + | + PASSWORD TEXT_STRING_sys + { + Lex->server_options.password= $2.str; + } + | + SOCKET_SYM TEXT_STRING_sys + { + Lex->server_options.socket= $2.str; + } + | + PORT_SYM ulong_num + { + Lex->server_options.port= $2; + } + ; event_tail: EVENT_SYM opt_if_not_exists sp_name @@ -1485,8 +1748,7 @@ ev_sql_stmt_inner: sp_proc_stmt_statement | sp_proc_stmt_return | sp_proc_stmt_if - | sp_proc_stmt_case_simple - | sp_proc_stmt_case + | case_stmt_specification | sp_labeled_control | sp_proc_stmt_unlabeled | sp_proc_stmt_leave @@ -1549,7 +1811,7 @@ create_function_tail: RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys { THD *thd= YYTHD; - LEX *lex=Lex; + LEX *lex= thd->lex; if (lex->definer != NULL) { /* @@ -1632,7 +1894,7 @@ create_function_tail: When collation support in SP is implemented, then this test should be removed. */ - if (($8 == FIELD_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR) + if (($8 == MYSQL_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR) && (lex->type & BINCMP_FLAG)) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation"); @@ -1656,7 +1918,7 @@ create_function_tail: sp_proc_stmt { THD *thd= YYTHD; - LEX *lex= Lex; + LEX *lex= thd->lex; sp_head *sp= lex->sphead; if (sp->is_not_allowed_in_function("function")) @@ -2250,8 +2512,7 @@ sp_proc_stmt: sp_proc_stmt_statement | sp_proc_stmt_return | sp_proc_stmt_if - | sp_proc_stmt_case_simple - | sp_proc_stmt_case + | case_stmt_specification | sp_labeled_control | sp_proc_stmt_unlabeled | sp_proc_stmt_leave @@ -2341,49 +2602,6 @@ sp_proc_stmt_return: } ; -sp_proc_stmt_case_simple: - CASE_SYM WHEN_SYM - { - Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE; - Lex->sphead->new_cont_backpatch(NULL); - } - sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); } - ; - -sp_proc_stmt_case: - CASE_SYM - { - Lex->sphead->reset_lex(YYTHD); - Lex->sphead->new_cont_backpatch(NULL); - } - expr WHEN_SYM - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - sp_pcontext *parsing_ctx= lex->spcont; - int case_expr_id= parsing_ctx->register_case_expr(); - sp_instr_set_case_expr *i; - - if (parsing_ctx->push_case_expr_id(case_expr_id)) - YYABORT; - - i= new sp_instr_set_case_expr(sp->instructions(), - parsing_ctx, - case_expr_id, - $3, - lex); - sp->add_cont_backpatch(i); - sp->add_instr(i); - sp->m_flags|= sp_head::IN_SIMPLE_CASE; - sp->restore_lex(YYTHD); - } - sp_case END CASE_SYM - { - Lex->spcont->pop_case_expr_id(); - Lex->sphead->do_cont_backpatch(); - } - ; - sp_proc_stmt_unlabeled: { /* Unlabeled controls get a secret label. */ LEX *lex= Lex; @@ -2608,72 +2826,114 @@ sp_elseifs: | ELSE sp_proc_stmts1 ; -sp_case: - { Lex->sphead->reset_lex(YYTHD); } - expr THEN_SYM - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - sp_pcontext *ctx= Lex->spcont; - uint ip= sp->instructions(); - sp_instr_jump_if_not *i; - - if (! (sp->m_flags & sp_head::IN_SIMPLE_CASE)) - i= new sp_instr_jump_if_not(ip, ctx, $2, lex); - else - { /* Simple case: <caseval> = <whenval> */ +case_stmt_specification: + simple_case_stmt + | searched_case_stmt + ; - Item_case_expr *var; - Item *expr; +simple_case_stmt: + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_case(lex); + lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + } + expr + { + LEX *lex= Lex; + if (case_stmt_action_expr(lex, $3)) + YYABORT; - var= new Item_case_expr(ctx->get_current_case_expr_id()); + lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + } + simple_when_clause_list + else_clause_opt + END + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_end_case(lex, true); + } + ; -#ifndef DBUG_OFF - if (var) - var->m_sp= sp; -#endif +searched_case_stmt: + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_case(lex); + } + searched_when_clause_list + else_clause_opt + END + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_end_case(lex, false); + } + ; - expr= new Item_func_eq(var, $2); +simple_when_clause_list: + simple_when_clause + | simple_when_clause_list simple_when_clause + ; - i= new sp_instr_jump_if_not(ip, ctx, expr, lex); - } - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - sp->add_cont_backpatch(i); - sp->add_instr(i); - sp->restore_lex(YYTHD); - } - sp_proc_stmts1 - { - sp_head *sp= Lex->sphead; - sp_pcontext *ctx= Lex->spcont; - uint ip= sp->instructions(); - sp_instr_jump *i = new sp_instr_jump(ip, ctx); +searched_when_clause_list: + searched_when_clause + | searched_when_clause_list searched_when_clause + ; - sp->add_instr(i); - sp->backpatch(ctx->pop_label()); - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - } - sp_whens - { - LEX *lex= Lex; +simple_when_clause: + WHEN_SYM + { + Lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + } + expr + { + /* Simple case: <caseval> = <whenval> */ - lex->sphead->backpatch(lex->spcont->pop_label()); - } - ; + LEX *lex= Lex; + case_stmt_action_when(lex, $3, true); + lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + } + THEN_SYM + sp_proc_stmts1 + { + LEX *lex= Lex; + case_stmt_action_then(lex); + } + ; -sp_whens: - /* Empty */ - { - sp_head *sp= Lex->sphead; - uint ip= sp->instructions(); - sp_instr_error *i= new sp_instr_error(ip, Lex->spcont, - ER_SP_CASE_NOT_FOUND); +searched_when_clause: + WHEN_SYM + { + Lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + } + expr + { + LEX *lex= Lex; + case_stmt_action_when(lex, $3, false); + lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + } + THEN_SYM + sp_proc_stmts1 + { + LEX *lex= Lex; + case_stmt_action_then(lex); + } + ; - sp->add_instr(i); - } - | ELSE sp_proc_stmts1 {} - | WHEN_SYM sp_case {} - ; +else_clause_opt: + /* empty */ + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint ip= sp->instructions(); + sp_instr_error *i= new sp_instr_error(ip, lex->spcont, + ER_SP_CASE_NOT_FOUND); + sp->add_instr(i); + } + | ELSE sp_proc_stmts1 + ; sp_labeled_control: label_ident ':' @@ -2821,11 +3081,11 @@ trg_event: ALTER TABLESPACE name CHANGE DATAFILE ... ALTER TABLESPACE name ADD DATAFILE ... ALTER TABLESPACE name access_mode - CREATE LOGFILE GROUP name ... - ALTER LOGFILE GROUP name ADD UNDOFILE .. - ALTER LOGFILE GROUP name ADD REDOFILE .. + CREATE LOGFILE GROUP_SYM name ... + ALTER LOGFILE GROUP_SYM name ADD UNDOFILE .. + ALTER LOGFILE GROUP_SYM name ADD REDOFILE .. DROP TABLESPACE name - DROP LOGFILE GROUP name + DROP LOGFILE GROUP_SYM name */ change_tablespace_access: tablespace_name @@ -2847,7 +3107,7 @@ tablespace_info: opt_logfile_group_name: /* empty */ {} - | USE_SYM LOGFILE_SYM GROUP ident + | USE_SYM LOGFILE_SYM GROUP_SYM ident { LEX *lex= Lex; lex->alter_tablespace_info->logfile_group_name= $4.str; @@ -3198,8 +3458,8 @@ create2: create3 {} | LIKE table_ident { - LEX *lex=Lex; - THD *thd= lex->thd; + THD *thd= YYTHD; + LEX *lex= thd->lex; if (!(lex->like_name= $2)) YYABORT; if ($2->db.str == NULL && @@ -3210,8 +3470,8 @@ create2: } | '(' LIKE table_ident ')' { - LEX *lex=Lex; - THD *thd= lex->thd; + THD *thd= YYTHD; + LEX *lex= thd->lex; if (!(lex->like_name= $3)) YYABORT; if ($3->db.str == NULL && @@ -3500,7 +3760,6 @@ 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; if (!p_elem || part_info->partitions.push_back(p_elem)) { @@ -3652,9 +3911,8 @@ part_bit_expr: bit_expr { Item *part_expr= $1; - int part_expression_ok= 1; - LEX *lex= Lex; THD *thd= YYTHD; + LEX *lex= thd->lex; Name_resolution_context *context= &lex->current_select->context; TABLE_LIST *save_list= context->table_list; const char *save_where= thd->where; @@ -3947,8 +4205,8 @@ create_table_option: | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.data_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR; } | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR; } | TABLESPACE ident {Lex->create_info.tablespace= $2.str;} - | STORAGE_SYM DISK_SYM {Lex->create_info.store_on_disk= TRUE;} - | STORAGE_SYM MEMORY_SYM {Lex->create_info.store_on_disk= FALSE;} + | STORAGE_SYM DISK_SYM {Lex->create_info.storage_media= HA_SM_DISK;} + | STORAGE_SYM MEMORY_SYM {Lex->create_info.storage_media= HA_SM_MEMORY;} | CONNECTION_SYM opt_equal TEXT_STRING_sys { Lex->create_info.connect_string.str= $3.str; Lex->create_info.connect_string.length= $3.length; Lex->create_info.used_fields|= HA_CREATE_USED_CONNECTION; } | KEY_BLOCK_SIZE opt_equal ulong_num { @@ -4145,31 +4403,31 @@ field_spec: type: int_type opt_len field_options { $$=$1; } | real_type opt_precision field_options { $$=$1; } - | FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; } + | FLOAT_SYM float_options field_options { $$=MYSQL_TYPE_FLOAT; } | BIT_SYM { Lex->length= (char*) "1"; - $$=FIELD_TYPE_BIT; } + $$=MYSQL_TYPE_BIT; } | BIT_SYM '(' NUM ')' { Lex->length= $3.str; - $$=FIELD_TYPE_BIT; } + $$=MYSQL_TYPE_BIT; } | BOOL_SYM { Lex->length=(char*) "1"; - $$=FIELD_TYPE_TINY; } + $$=MYSQL_TYPE_TINY; } | BOOLEAN_SYM { Lex->length=(char*) "1"; - $$=FIELD_TYPE_TINY; } + $$=MYSQL_TYPE_TINY; } | char '(' NUM ')' opt_binary { Lex->length=$3.str; - $$=FIELD_TYPE_STRING; } + $$=MYSQL_TYPE_STRING; } | char opt_binary { Lex->length=(char*) "1"; - $$=FIELD_TYPE_STRING; } + $$=MYSQL_TYPE_STRING; } | nchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str; - $$=FIELD_TYPE_STRING; + $$=MYSQL_TYPE_STRING; Lex->charset=national_charset_info; } | nchar opt_bin_mod { Lex->length=(char*) "1"; - $$=FIELD_TYPE_STRING; + $$=MYSQL_TYPE_STRING; Lex->charset=national_charset_info; } | BINARY '(' NUM ')' { Lex->length=$3.str; Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_STRING; } + $$=MYSQL_TYPE_STRING; } | BINARY { Lex->length= (char*) "1"; Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_STRING; } + $$=MYSQL_TYPE_STRING; } | varchar '(' NUM ')' opt_binary { Lex->length=$3.str; $$= MYSQL_TYPE_VARCHAR; } | nvarchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str; @@ -4178,33 +4436,33 @@ type: | VARBINARY '(' NUM ')' { Lex->length=$3.str; Lex->charset=&my_charset_bin; $$= MYSQL_TYPE_VARCHAR; } - | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; } - | DATE_SYM { $$=FIELD_TYPE_DATE; } - | TIME_SYM { $$=FIELD_TYPE_TIME; } + | YEAR_SYM opt_len field_options { $$=MYSQL_TYPE_YEAR; } + | DATE_SYM { $$=MYSQL_TYPE_DATE; } + | TIME_SYM { $$=MYSQL_TYPE_TIME; } | TIMESTAMP opt_len { if (YYTHD->variables.sql_mode & MODE_MAXDB) - $$=FIELD_TYPE_DATETIME; + $$=MYSQL_TYPE_DATETIME; else { /* Unlike other types TIMESTAMP fields are NOT NULL by default. */ Lex->type|= NOT_NULL_FLAG; - $$=FIELD_TYPE_TIMESTAMP; + $$=MYSQL_TYPE_TIMESTAMP; } } - | DATETIME { $$=FIELD_TYPE_DATETIME; } + | DATETIME { $$=MYSQL_TYPE_DATETIME; } | TINYBLOB { Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_TINY_BLOB; } + $$=MYSQL_TYPE_TINY_BLOB; } | BLOB_SYM opt_len { Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_BLOB; } + $$=MYSQL_TYPE_BLOB; } | spatial_type { #ifdef HAVE_SPATIAL Lex->charset=&my_charset_bin; Lex->uint_geom_type= (uint)$1; - $$=FIELD_TYPE_GEOMETRY; + $$=MYSQL_TYPE_GEOMETRY; #else my_error(ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, sym_group_geom.needed_define); @@ -4212,30 +4470,30 @@ type: #endif } | MEDIUMBLOB { Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_MEDIUM_BLOB; } + $$=MYSQL_TYPE_MEDIUM_BLOB; } | LONGBLOB { Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_LONG_BLOB; } + $$=MYSQL_TYPE_LONG_BLOB; } | LONG_SYM VARBINARY { Lex->charset=&my_charset_bin; - $$=FIELD_TYPE_MEDIUM_BLOB; } - | LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } - | TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_BLOB; } - | TEXT_SYM opt_len opt_binary { $$=FIELD_TYPE_BLOB; } - | MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } - | LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; } + $$=MYSQL_TYPE_MEDIUM_BLOB; } + | LONG_SYM varchar opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; } + | TINYTEXT opt_binary { $$=MYSQL_TYPE_TINY_BLOB; } + | TEXT_SYM opt_len opt_binary { $$=MYSQL_TYPE_BLOB; } + | MEDIUMTEXT opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; } + | LONGTEXT opt_binary { $$=MYSQL_TYPE_LONG_BLOB; } | DECIMAL_SYM float_options field_options - { $$=FIELD_TYPE_NEWDECIMAL;} + { $$=MYSQL_TYPE_NEWDECIMAL;} | NUMERIC_SYM float_options field_options - { $$=FIELD_TYPE_NEWDECIMAL;} + { $$=MYSQL_TYPE_NEWDECIMAL;} | FIXED_SYM float_options field_options - { $$=FIELD_TYPE_NEWDECIMAL;} + { $$=MYSQL_TYPE_NEWDECIMAL;} | ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary - { $$=FIELD_TYPE_ENUM; } + { $$=MYSQL_TYPE_ENUM; } | SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary - { $$=FIELD_TYPE_SET; } - | LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } + { $$=MYSQL_TYPE_SET; } + | LONG_SYM opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; } | SERIAL_SYM { - $$=FIELD_TYPE_LONGLONG; + $$=MYSQL_TYPE_LONGLONG; Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG | UNIQUE_FLAG); } @@ -4277,17 +4535,17 @@ nvarchar: ; int_type: - INT_SYM { $$=FIELD_TYPE_LONG; } - | TINYINT { $$=FIELD_TYPE_TINY; } - | SMALLINT { $$=FIELD_TYPE_SHORT; } - | MEDIUMINT { $$=FIELD_TYPE_INT24; } - | BIGINT { $$=FIELD_TYPE_LONGLONG; }; + INT_SYM { $$=MYSQL_TYPE_LONG; } + | TINYINT { $$=MYSQL_TYPE_TINY; } + | SMALLINT { $$=MYSQL_TYPE_SHORT; } + | MEDIUMINT { $$=MYSQL_TYPE_INT24; } + | BIGINT { $$=MYSQL_TYPE_LONGLONG; }; real_type: REAL { $$= YYTHD->variables.sql_mode & MODE_REAL_AS_FLOAT ? - FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; } - | DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; } - | DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; }; + MYSQL_TYPE_FLOAT : MYSQL_TYPE_DOUBLE; } + | DOUBLE_SYM { $$=MYSQL_TYPE_DOUBLE; } + | DOUBLE_SYM PRECISION { $$=MYSQL_TYPE_DOUBLE; }; float_options: @@ -4690,6 +4948,7 @@ alter: lex->alter_info.reset(); lex->alter_info.flags= 0; lex->no_write_to_binlog= 0; + lex->create_info.storage_media= HA_SM_DEFAULT; } alter_commands {} @@ -4700,8 +4959,8 @@ alter: } opt_create_database_options { - LEX *lex=Lex; - THD *thd= Lex->thd; + THD *thd= YYTHD; + LEX *lex= thd->lex; lex->sql_command=SQLCOM_ALTER_DB; lex->name= $3; if (lex->name.str == NULL && @@ -4814,7 +5073,7 @@ alter: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE; } - | ALTER LOGFILE_SYM GROUP alter_logfile_group_info + | ALTER LOGFILE_SYM GROUP_SYM alter_logfile_group_info { LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP; @@ -4829,6 +5088,13 @@ alter: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE; } + | ALTER SERVER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')' + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_ALTER_SERVER; + lex->server_options.server_name= $3.str; + lex->server_options.server_name_length= $3.length; + } ; ev_alter_on_schedule_completion: /* empty */ { $$= 0;} @@ -4853,7 +5119,6 @@ opt_ev_sql_stmt: /* empty*/ { $$= 0;} | DO_SYM ev_sql_stmt { $$= 1; } ; - ident_or_empty: /* empty */ { $$.str= 0; $$.length= 0; } | ident { $$= $1; }; @@ -5132,8 +5397,8 @@ alter_list_item: } | RENAME opt_to table_ident { - LEX *lex=Lex; - THD *thd= lex->thd; + THD *thd= YYTHD; + LEX *lex= thd->lex; uint dummy; lex->select_lex.db=$3->db.str; if (lex->select_lex.db == NULL && @@ -5180,7 +5445,7 @@ alter_list_item: { Lex->alter_info.flags|= ALTER_FORCE; } - | order_clause + | alter_order_clause { LEX *lex=Lex; lex->alter_info.flags|= ALTER_ORDER; @@ -5500,9 +5765,9 @@ db_to_db: ident TO_SYM ident { LEX *lex=Lex; - if (Lex->db_list.push_back((LEX_STRING*) + if (lex->db_list.push_back((LEX_STRING*) sql_memdup(&$1, sizeof(LEX_STRING))) || - Lex->db_list.push_back((LEX_STRING*) + lex->db_list.push_back((LEX_STRING*) sql_memdup(&$3, sizeof(LEX_STRING)))) YYABORT; }; @@ -6061,8 +6326,8 @@ simple_expr: if (!$$) YYABORT; } - | CASE_SYM opt_expr WHEN_SYM when_list opt_else END - { $$= new (YYTHD->mem_root) Item_func_case(* $4, $2, $5 ); } + | CASE_SYM opt_expr when_list opt_else END + { $$= new (YYTHD->mem_root) Item_func_case(* $3, $2, $4 ); } | CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast(YYTHD, $3, $5, @@ -6101,10 +6366,6 @@ simple_expr: } $$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1); } - | UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')' - { - $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9); - } ; /* @@ -6280,7 +6541,7 @@ function_call_nonkeyword: ; /* - Functions calls using a non reserved keywork, and using a regular syntax. + Functions calls using a non reserved keyword, and using a regular syntax. Because the non reserved keyword is used in another part of the grammar, a dedicated rule is needed here. */ @@ -6432,7 +6693,6 @@ function_call_generic: udf_expr_list ')' { THD *thd= YYTHD; - LEX *lex= Lex; Create_func *builder; Item *item= NULL; @@ -6455,7 +6715,6 @@ function_call_generic: #ifdef HAVE_DLOPEN /* Retrieving the result of find_udf */ udf_func *udf= $<udf>3; - LEX *lex= Lex; if (udf) { @@ -6495,7 +6754,7 @@ function_call_generic: parser and the implementation in item_create.cc clean, since this will change with WL#2128 (SQL PATH): - INFORMATION_SCHEMA.version() is the SQL 99 syntax for the native - funtion version(), + function version(), - MySQL.version() is the SQL 2003 syntax for the native function version() (a vendor can specify any schema). */ @@ -6591,13 +6850,11 @@ sum_expr: { Select->in_sum_expr--; } ')' { $$=new Item_sum_count_distinct(* $5); } - | GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')' - { $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); } | MIN_SYM '(' in_sum_expr ')' { $$=new Item_sum_min($3); } /* According to ANSI SQL, DISTINCT is allowed and has - no sence inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...) + no sense inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...) is processed like an ordinary MIN | MAX() */ | MIN_SYM '(' DISTINCT in_sum_expr ')' @@ -6761,23 +7018,19 @@ opt_else: | ELSE expr { $$= $2; }; when_list: - { Select->when_list.push_front(new List<Item>); } - when_list2 - { $$= Select->when_list.pop(); }; - -when_list2: - expr THEN_SYM expr - { - SELECT_LEX *sel=Select; - sel->when_list.head()->push_back($1); - sel->when_list.head()->push_back($3); - } - | when_list2 WHEN_SYM expr THEN_SYM expr - { - SELECT_LEX *sel=Select; - sel->when_list.head()->push_back($3); - sel->when_list.head()->push_back($5); - }; + WHEN_SYM expr THEN_SYM expr + { + $$= new List<Item>; + $$->push_back($2); + $$->push_back($4); + } + | when_list WHEN_SYM expr THEN_SYM expr + { + $1->push_back($3); + $1->push_back($5); + $$= $1; + } + ; /* Warning - may return NULL in case of incomplete SELECT */ table_ref: @@ -6855,15 +7108,14 @@ join_table: | table_ref normal_join table_ref USING { - SELECT_LEX *sel= Select; YYERROR_UNLESS($1 && $3); } '(' using_list ')' - { add_join_natural($1,$3,$7); $$=$3; } + { add_join_natural($1,$3,$7,Select); $$=$3; } | table_ref NATURAL JOIN_SYM table_factor { YYERROR_UNLESS($1 && ($$=$4)); - add_join_natural($1,$4,NULL); + add_join_natural($1,$4,NULL,Select); } /* LEFT JOIN variants */ @@ -6886,15 +7138,18 @@ join_table: } | table_ref LEFT opt_outer JOIN_SYM table_factor { - SELECT_LEX *sel= Select; YYERROR_UNLESS($1 && $5); } USING '(' using_list ')' - { add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } + { + add_join_natural($1,$5,$9,Select); + $5->outer_join|=JOIN_TYPE_LEFT; + $$=$5; + } | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor { YYERROR_UNLESS($1 && $6); - add_join_natural($1,$6,NULL); + add_join_natural($1,$6,NULL,Select); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } @@ -6920,7 +7175,6 @@ join_table: } | table_ref RIGHT opt_outer JOIN_SYM table_factor { - SELECT_LEX *sel= Select; YYERROR_UNLESS($1 && $5); } USING '(' using_list ')' @@ -6928,12 +7182,12 @@ join_table: LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; - add_join_natural($$,$5,$9); + add_join_natural($$,$5,$9,Select); } | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor { YYERROR_UNLESS($1 && $6); - add_join_natural($6,$1,NULL); + add_join_natural($6,$1,NULL,Select); LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; @@ -7298,7 +7552,7 @@ opt_escape: group_clause: /* empty */ - | GROUP BY group_list olap_opt; + | GROUP_SYM BY group_list olap_opt; group_list: group_list ',' order_ident order_dir @@ -7335,6 +7589,29 @@ olap_opt: ; /* + Order by statement in ALTER TABLE +*/ + +alter_order_clause: + ORDER_SYM BY alter_order_list + ; + +alter_order_list: + alter_order_list ',' alter_order_item + | alter_order_item + ; + +alter_order_item: + simple_ident_nospvar order_dir + { + THD *thd= YYTHD; + bool ascending= ($2 == 1) ? true : false; + if (add_order_to_list(thd, $1, ascending)) + YYABORT; + } + ; + +/* Order by statement in select */ @@ -7739,11 +8016,18 @@ drop: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE; } - | DROP LOGFILE_SYM GROUP logfile_group_name opt_ts_engine opt_ts_wait + | DROP LOGFILE_SYM GROUP_SYM logfile_group_name opt_ts_engine opt_ts_wait { LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP; } + | DROP SERVER_SYM if_exists ident_or_text + { + Lex->sql_command = SQLCOM_DROP_SERVER; + Lex->drop_if_exists= $3; + Lex->server_options.server_name= $4.str; + Lex->server_options.server_name_length= $4.length; + } ; table_list: @@ -8342,6 +8626,7 @@ show_param: if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL,0)) YYABORT; lex->only_view= 0; + lex->create_info.storage_media= HA_SM_DEFAULT; } | CREATE VIEW_SYM table_ident { @@ -8840,7 +9125,7 @@ text_string: param_marker: PARAM_MARKER { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; Item_param *item; if (! lex->parsing_options.allows_variable) @@ -9310,12 +9595,16 @@ keyword: | FLUSH_SYM {} | HANDLER_SYM {} | HELP_SYM {} + | HOST_SYM {} | INSTALL_SYM {} | LANGUAGE_SYM {} | NO_SYM {} | OPEN_SYM {} + | OPTIONS_SYM {} + | OWNER_SYM {} | PARSER_SYM {} | PARTITION_SYM {} + | PORT_SYM {} | PREPARE_SYM {} | REMOVE_SYM {} | REPAIR {} @@ -9324,7 +9613,9 @@ keyword: | ROLLBACK_SYM {} | SAVEPOINT_SYM {} | SECURITY_SYM {} + | SERVER_SYM {} | SIGNED_SYM {} + | SOCKET_SYM {} | SLAVE {} | SONAME_SYM {} | START_SYM {} @@ -9332,6 +9623,7 @@ keyword: | TRUNCATE_SYM {} | UNICODE_SYM {} | UNINSTALL_SYM {} + | WRAPPER_SYM {} | XA_SYM {} | UPGRADE_SYM {} ; @@ -9375,6 +9667,7 @@ keyword_sp: | COMPLETION_SYM {} | COMPRESSED_SYM {} | CONCURRENT {} + | CONNECTION_SYM {} | CONSISTENT_SYM {} | CONTRIBUTORS_SYM {} | CUBE_SYM {} @@ -9821,7 +10114,7 @@ option_value: | charset old_or_new_charset_name_or_default { THD *thd= YYTHD; - LEX *lex= Lex; + LEX *lex= thd->lex; $2= $2 ? $2: global_system_variables.character_set_client; lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2)); } @@ -9855,9 +10148,9 @@ option_value: } | PASSWORD equal text_or_password { - THD *thd=YYTHD; + THD *thd= YYTHD; + LEX *lex= thd->lex; LEX_USER *user; - LEX *lex= Lex; sp_pcontext *spc= lex->spcont; LEX_STRING pw; @@ -10338,8 +10631,8 @@ require_list_element: grant_ident: '*' { - LEX *lex= Lex; - THD *thd= lex->thd; + THD *thd= YYTHD; + LEX *lex= thd->lex; uint dummy; if (thd->copy_db_to(&lex->current_select->db, &dummy)) YYABORT; @@ -10702,7 +10995,6 @@ subselect: } | '(' subselect_start subselect ')' { - LEX *lex= Lex; THD *thd= YYTHD; /* note that a local variable can't be used for @@ -10902,7 +11194,7 @@ view_select: view_select_aux: SELECT_SYM remember_name select_init2 { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; char *stmt_beg= (lex->sphead ? (char *)lex->sphead->m_tmp_query : @@ -10911,7 +11203,7 @@ view_select_aux: } | '(' remember_name select_paren ')' union_opt { - THD *thd=YYTHD; + THD *thd= YYTHD; LEX *lex= thd->lex; char *stmt_beg= (lex->sphead ? (char *)lex->sphead->m_tmp_query : diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 77e7707592d..d8e9b7fd883 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/stacktrace.h b/sql/stacktrace.h index 527d10d70a2..f5c92e54e1c 100644 --- a/sql/stacktrace.h +++ b/sql/stacktrace.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/strfunc.cc b/sql/strfunc.cc index 2d2530eb876..71b52a5145d 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/structs.h b/sql/structs.h index 83ae6cac032..377d337dcfa 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/table.cc b/sql/table.cc index 52074ee1e7c..ed3cac85214 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -123,7 +122,6 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, share->version= refresh_version; share->flush_version= flush_version; -#ifdef HAVE_ROW_BASED_REPLICATION /* This constant is used to mark that no table map version has been assigned. No arithmetic is done on the value: it will be @@ -141,8 +139,6 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, share->table_map_id= ~0UL; share->cached_row_logging_check= -1; -#endif - memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root)); pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&share->cond, NULL); @@ -194,7 +190,6 @@ void init_tmp_table_share(TABLE_SHARE *share, const char *key, share->path.length= share->normalized_path.length= strlen(path); share->frm_version= FRM_VER_TRUE_VARCHAR; -#ifdef HAVE_ROW_BASED_REPLICATION /* Temporary tables are not replicated, but we set up these fields anyway to be able to catch errors. @@ -202,7 +197,6 @@ void init_tmp_table_share(TABLE_SHARE *share, const char *key, share->table_map_version= ~(ulonglong)0; share->table_map_id= ~0UL; share->cached_row_logging_check= -1; -#endif DBUG_VOID_RETURN; } @@ -786,6 +780,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, memcpy(comment_pos, disk_buff+read_length-com_length, com_length); fix_type_pointers(&interval_array, &share->fieldnames, 1, &names); + if (share->fieldnames.count != share->fields) + goto err; fix_type_pointers(&interval_array, share->intervals, interval_count, &names); @@ -804,17 +800,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, { char *val= (char*) interval->type_names[count]; interval->type_lengths[count]= strlen(val); - /* - Replace all ',' symbols with NAMES_SEP_CHAR. - See the comment in unireg.cc, pack_fields() function - for details. - */ - for (uint cnt= 0 ; cnt < interval->type_lengths[count] ; cnt++) - { - char c= val[cnt]; - if (c == ',') - val[cnt]= NAMES_SEP_CHAR; - } } interval->type_lengths[count]= 0; } @@ -877,7 +862,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, field_type=(enum_field_types) (uint) strpos[13]; /* charset and geometry_type share the same byte in frm */ - if (field_type == FIELD_TYPE_GEOMETRY) + if (field_type == MYSQL_TYPE_GEOMETRY) { #ifdef HAVE_SPATIAL geom_type= (Field::geometry_type) strpos[14]; @@ -952,7 +937,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, } #ifndef TO_BE_DELETED_ON_PRODUCTION - if (field_type == FIELD_TYPE_NEWDECIMAL && !share->mysql_version) + if (field_type == MYSQL_TYPE_NEWDECIMAL && !share->mysql_version) { /* Fix pack length of old decimal values from 5.0.3 -> 5.0.4 @@ -999,7 +984,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, reg_field->field_index= i; reg_field->comment=comment; - if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) + if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) { if ((null_bit_pos+= field_length & 7) > 7) { @@ -1089,10 +1074,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, keyinfo->extra_length+= HA_KEY_NULL_LENGTH; keyinfo->key_length+= HA_KEY_NULL_LENGTH; } - if (field->type() == FIELD_TYPE_BLOB || + if (field->type() == MYSQL_TYPE_BLOB || field->real_type() == MYSQL_TYPE_VARCHAR) { - if (field->type() == FIELD_TYPE_BLOB) + if (field->type() == MYSQL_TYPE_BLOB) key_part->key_part_flag|= HA_BLOB_PART; else key_part->key_part_flag|= HA_VAR_LENGTH_PART; @@ -1144,7 +1129,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, if (field->key_length() != key_part->length) { #ifndef TO_BE_DELETED_ON_PRODUCTION - if (field->type() == FIELD_TYPE_NEWDECIMAL) + if (field->type() == MYSQL_TYPE_NEWDECIMAL) { /* Fix a fatal error in decimal key handling that causes crashes @@ -1252,17 +1237,17 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, if (share->blob_fields) { Field **ptr; - uint i, *save; + uint k, *save; /* Store offsets to blob fields to find them fast */ if (!(share->blob_field= save= (uint*) alloc_root(&share->mem_root, (uint) (share->blob_fields* sizeof(uint))))) goto err; - for (i=0, ptr= share->field ; *ptr ; ptr++, i++) + for (k=0, ptr= share->field ; *ptr ; ptr++, k++) { if ((*ptr)->flags & BLOB_FLAG) - (*save++)= i; + (*save++)= k; } } @@ -1278,7 +1263,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, share->column_bitmap_size= bitmap_buffer_size(share->fields); if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root, - share->column_bitmap_size))) + share->column_bitmap_size))) goto err; bitmap_init(&share->all_set, bitmaps, share->fields, FALSE); bitmap_set_all(&share->all_set); @@ -2987,19 +2972,17 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) { if (check_option && check_option->val_int() == 0) { - TABLE_LIST *view= top_table(); + TABLE_LIST *main_view= top_table(); if (ignore_failure) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED), - view->view_db.str, view->view_name.str); + main_view->view_db.str, main_view->view_name.str); return(VIEW_CHECK_SKIP); } - else - { - my_error(ER_VIEW_CHECK_FAILED, MYF(0), view->view_db.str, view->view_name.str); - return(VIEW_CHECK_ERROR); - } + my_error(ER_VIEW_CHECK_FAILED, MYF(0), main_view->view_db.str, + main_view->view_name.str); + return(VIEW_CHECK_ERROR); } return(VIEW_CHECK_OK); } @@ -3011,19 +2994,20 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) SYNOPSIS st_table_list::check_single_table() - table reference on variable where to store found table + table_arg reference on variable where to store found table (should be 0 on call, to find table, or point to table for unique test) map bit mask of tables - view view for which we are looking table + view_arg view for which we are looking table RETURN FALSE table not found or found only one TRUE found several tables */ -bool st_table_list::check_single_table(st_table_list **table, table_map map, - st_table_list *view) +bool st_table_list::check_single_table(st_table_list **table_arg, + table_map map, + st_table_list *view_arg) { for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { @@ -3031,13 +3015,13 @@ bool st_table_list::check_single_table(st_table_list **table, table_map map, { if (tbl->table->map & map) { - if (*table) + if (*table_arg) return TRUE; - *table= tbl; - tbl->check_option= view->check_option; + *table_arg= tbl; + tbl->check_option= view_arg->check_option; } } - else if (tbl->check_single_table(table, map, view)) + else if (tbl->check_single_table(table_arg, map, view_arg)) return TRUE; } return FALSE; @@ -3362,18 +3346,19 @@ bool st_table_list::prepare_security(THD *thd) while ((tbl= tb++)) { DBUG_ASSERT(tbl->referencing_view); - char *db, *table_name; + char *local_db, *local_table_name; if (tbl->view) { - db= tbl->view_db.str; - table_name= tbl->view_name.str; + local_db= tbl->view_db.str; + local_table_name= tbl->view_name.str; } else { - db= tbl->db; - table_name= tbl->table_name; + local_db= tbl->db; + local_table_name= tbl->table_name; } - fill_effective_table_privileges(thd, &tbl->grant, db, table_name); + fill_effective_table_privileges(thd, &tbl->grant, local_db, + local_table_name); if (tbl->table) tbl->table->grant= grant; } @@ -3445,6 +3430,7 @@ Field *Natural_join_column::field() const char *Natural_join_column::table_name() { + DBUG_ASSERT(table_ref); return table_ref->alias; } @@ -3732,13 +3718,13 @@ Field_iterator_table_ref::get_or_create_column_ref(TABLE_LIST *parent_table_ref) uint field_count; TABLE_LIST *add_table_ref= parent_table_ref ? parent_table_ref : table_ref; - LINT_INIT(field_count); + if (field_it == &table_field_it) { /* The field belongs to a stored table. */ - Field *field= table_field_it.field(); - nj_col= new Natural_join_column(field, table_ref); + Field *tmp_field= table_field_it.field(); + nj_col= new Natural_join_column(tmp_field, table_ref); field_count= table_ref->table->s->fields; } else if (field_it == &view_field_it) @@ -4100,19 +4086,19 @@ void st_table_list::reinit_before_use(THD *thd) */ table= 0; /* Reset is_schema_table_processed value(needed for I_S tables */ - is_schema_table_processed= FALSE; + schema_table_state= NOT_PROCESSED; TABLE_LIST *embedded; /* The table at the current level of nesting. */ - TABLE_LIST *embedding= this; /* The parent nested table reference. */ + TABLE_LIST *parent_embedding= this; /* The parent nested table reference. */ do { - embedded= embedding; + embedded= parent_embedding; if (embedded->prep_on_expr) embedded->on_expr= embedded->prep_on_expr->copy_andor_structure(thd); - embedding= embedded->embedding; + parent_embedding= embedded->embedding; } - while (embedding && - embedding->nested_join->join_list.head() == embedded); + while (parent_embedding && + parent_embedding->nested_join->join_list.head() == embedded); } /* diff --git a/sql/table.cc.rej b/sql/table.cc.rej deleted file mode 100644 index fd728ba9965..00000000000 --- a/sql/table.cc.rej +++ /dev/null @@ -1,17 +0,0 @@ -*************** -*** 2246,2252 **** - - bool check_db_name(char *name) - { -! char *start=name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; - ---- 2257,2263 ---- - - bool check_db_name(char *name) - { -! char *start= name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; - diff --git a/sql/table.h b/sql/table.h index 13666c82f4b..fc2f25f3aa8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -159,7 +158,12 @@ typedef struct st_table_share LEX_STRING path; /* Path to .frm file (from datadir) */ LEX_STRING normalized_path; /* unpack_filename(path) */ LEX_STRING connect_string; - key_map keys_in_use; /* Keys in use for table */ + + /* + Set of keys in use, implemented as a Bitmap. + Excludes keys disabled by ALTER TABLE ... DISABLE KEYS. + */ + key_map keys_in_use; key_map keys_for_keyread; ha_rows min_rows, max_rows; /* create information */ ulong avg_row_length; /* create information */ @@ -314,7 +318,21 @@ struct st_table { byte *write_row_record; /* Used as optimisation in THD::write_row */ byte *insert_values; /* used by INSERT ... UPDATE */ - key_map quick_keys, used_keys, keys_in_use_for_query, merge_keys; + key_map quick_keys, used_keys; + + /* + A set of keys that can be used in the query that references this + table. + + All indexes disabled on the table's TABLE_SHARE (see TABLE::s) will be + subtracted from this set upon instantiation. Thus for any TABLE t it holds + that t.keys_in_use_for_query is a subset of t.s.keys_in_use. Generally we + must not introduce any new keys here (see setup_tables). + + The set is implemented as a bitmap. + */ + key_map keys_in_use_for_query; + key_map merge_keys; KEY *key_info; /* data of keys in database */ Field *next_number_field; /* Set if next_number is activated */ @@ -453,6 +471,12 @@ struct st_table { }; +enum enum_schema_table_state +{ + NOT_PROCESSED= 0, + PROCESSED_BY_CREATE_SORT_INDEX, + PROCESSED_BY_JOIN_EXEC +}; typedef struct st_foreign_key_info { @@ -461,6 +485,7 @@ typedef struct st_foreign_key_info LEX_STRING *referenced_table; LEX_STRING *update_method; LEX_STRING *delete_method; + LEX_STRING *referenced_key_name; List<LEX_STRING> foreign_fields; List<LEX_STRING> referenced_fields; } FOREIGN_KEY_INFO; @@ -711,7 +736,6 @@ typedef struct st_table_list st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ st_select_lex *schema_select_lex; - bool is_schema_table_processed; /* True when the view field translation table is used to convert schema table fields for backwards compatibility with SHOW command. @@ -821,6 +845,7 @@ typedef struct st_table_list */ bool prelocking_placeholder; + enum enum_schema_table_state schema_table_state; void calc_md5(char *buffer); void set_underlying_merge(); int view_check_option(THD *thd, bool ignore_failure); diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index 3a9ca397bba..392db9224c3 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2001, 2003-2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/time.cc b/sql/time.cc index 85096cd27ac..4854206b1c8 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/tzfile.h b/sql/tzfile.h index 623cddc1f12..1a57c0c5f69 100644 --- a/sql/tzfile.h +++ b/sql/tzfile.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/tztime.cc b/sql/tztime.cc index c44a907c07b..e236ceb11d7 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -547,8 +546,8 @@ sec_to_TIME(TIME * tmp, my_time_t t, long offset) int yleap; const uint *ip; - days= t / SECS_PER_DAY; - rem= t % SECS_PER_DAY; + days= (long) (t / SECS_PER_DAY); + rem= (long) (t % SECS_PER_DAY); /* We do this as separate step after dividing t, because this @@ -1770,8 +1769,8 @@ end_with_setting_default_tz: /* If we have default time zone try to load it */ if (default_tzname) { - String tmp_tzname(default_tzname, &my_charset_latin1); - if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname, tables))) + String tmp_tzname2(default_tzname, &my_charset_latin1); + if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname2, tables))) { sql_print_error("Fatal error: Illegal or unknown default time zone '%s'", default_tzname); diff --git a/sql/tztime.h b/sql/tztime.h index 95184c9b3d1..248a638074b 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/udf_example.c b/sql/udf_example.c index a71cc4b44f2..d37c6505ced 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -685,7 +684,7 @@ longlong sequence(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args, ****************************************************************************/ #ifdef __WIN__ -#include <winsock.h> +#include <winsock2.h> #else #include <sys/socket.h> #include <netinet/in.h> @@ -1087,7 +1086,7 @@ my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message) strmov(message, "IS_CONST accepts only one argument"); return 1; } - initid->ptr= (char*)(size_t)((args->args[0] != NULL) ? 1 : 0); + initid->ptr= (char*)((args->args[0] != NULL) ? 1UL : 0); return 0; } diff --git a/sql/udf_example.def b/sql/udf_example.def index ee107d58e51..7a87147d7b6 100644 --- a/sql/udf_example.def +++ b/sql/udf_example.def @@ -1,5 +1,4 @@ LIBRARY udf_example -DESCRIPTION 'MySQL Sample for UDF' VERSION 1.0 EXPORTS lookup diff --git a/sql/uniques.cc b/sql/uniques.cc index e32aa9c55b4..17c9c875659 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/unireg.cc b/sql/unireg.cc index a080de489e9..c55d6db3c85 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -83,7 +82,7 @@ bool mysql_create_frm(THD *thd, const char *file_name, uchar fileinfo[64],forminfo[288],*keybuff; TYPELIB formnames; uchar *screen_buff; - char buff[32]; + char buff[128]; #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *part_info= thd->work_part_info; #endif @@ -176,7 +175,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, create_info->comment.length, 60); if (tmp_len < create_info->comment.length) { - char buff[128]; (void) my_snprintf(buff, sizeof(buff), "Too long comment for table '%s'", table); if ((thd->variables.sql_mode & @@ -552,11 +550,11 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type, create_field *field; while ((field=it++)) { - uint tmp_len= system_charset_info->cset->charpos(system_charset_info, field->comment.str, field->comment.str + - field->comment.length, 255); + field->comment.length, + 255); if (tmp_len < field->comment.length) { char buff[128]; @@ -586,7 +584,7 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type, We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE as auto-update field. */ - if (field->sql_type == FIELD_TYPE_TIMESTAMP && + if (field->sql_type == MYSQL_TYPE_TIMESTAMP && MTYP_TYPENR(field->unireg_check) != Field::NONE && !time_stamp_pos) time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1; @@ -625,8 +623,9 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type, for (uint pos= 0; pos < field->interval->count; pos++) { char *dst; - uint length= field->save_interval->type_lengths[pos], hex_length; const char *src= field->save_interval->type_names[pos]; + uint hex_length; + length= field->save_interval->type_lengths[pos]; hex_length= length * 2; field->interval->type_lengths[pos]= hex_length; field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1); @@ -745,7 +744,7 @@ static bool pack_fields(File file, List<create_field> &create_fields, int2store(buff+10,field->unireg_check); buff[12]= (uchar) field->interval_id; buff[13]= (uchar) field->sql_type; - if (field->sql_type == FIELD_TYPE_GEOMETRY) + if (field->sql_type == MYSQL_TYPE_GEOMETRY) { buff[14]= (uchar) field->geom_type; #ifndef HAVE_SPATIAL @@ -791,29 +790,48 @@ static bool pack_fields(File file, List<create_field> &create_fields, { if (field->interval_id > int_count) { - int_count=field->interval_id; - tmp.append(NAMES_SEP_CHAR); - for (const char **pos=field->interval->type_names ; *pos ; pos++) - { - char *val= (char*) *pos; - uint str_len= strlen(val); - /* - Note, hack: in old frm NAMES_SEP_CHAR is used to separate - names in the interval (ENUM/SET). To allow names to contain - NAMES_SEP_CHAR, we replace it with a comma before writing frm. - Backward conversion is done during frm file opening, - See table.cc, openfrm() function - */ - for (uint cnt= 0 ; cnt < str_len ; cnt++) + unsigned char sep= 0; + unsigned char occ[256]; + uint i; + unsigned char *val= NULL; + + bzero(occ, sizeof(occ)); + + for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++) + for (uint j = 0; j < field->interval->type_lengths[i]; j++) + occ[(unsigned int) (val[j])]= 1; + + if (!occ[(unsigned char)NAMES_SEP_CHAR]) + sep= (unsigned char) NAMES_SEP_CHAR; + else if (!occ[(unsigned int)',']) + sep= ','; + else + { + for (uint i=1; i<256; i++) + { + if(!occ[i]) + { + sep= i; + break; + } + } + + if(!sep) /* disaster, enum uses all characters, none left as separator */ { - char c= val[cnt]; - if (c == NAMES_SEP_CHAR) - val[cnt]= ','; + my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS), + MYF(0)); + DBUG_RETURN(1); } - tmp.append(*pos); - tmp.append(NAMES_SEP_CHAR); - } - tmp.append('\0'); // End of intervall + } + + int_count= field->interval_id; + tmp.append(sep); + for (const char **pos=field->interval->type_names ; *pos ; pos++) + { + tmp.append(*pos); + tmp.append(sep); + } + tmp.append('\0'); // End of intervall } } if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW)) @@ -897,7 +915,10 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, field->interval, field->field_name); if (!regfield) + { + error= 1; goto err; // End of memory + } /* save_in_field() will access regfield->table->in_use */ regfield->init(&table); @@ -908,13 +929,13 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, null_count++; } - if (field->sql_type == FIELD_TYPE_BIT && !f_bit_as_char(field->pack_flag)) + if (field->sql_type == MYSQL_TYPE_BIT && !f_bit_as_char(field->pack_flag)) null_count+= field->length & 7; type= (Field::utype) MTYP_TYPENR(field->unireg_check); if (field->def && - (regfield->real_type() != FIELD_TYPE_YEAR || + (regfield->real_type() != MYSQL_TYPE_YEAR || field->def->val_int() != 0)) { if (field->def->save_in_field(regfield, 1)) @@ -925,7 +946,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, goto err; } } - else if (regfield->real_type() == FIELD_TYPE_ENUM && + else if (regfield->real_type() == MYSQL_TYPE_ENUM && (field->flags & NOT_NULL_FLAG)) { regfield->set_notnull(); diff --git a/sql/unireg.h b/sql/unireg.h index af91793e8fe..d67fa372083 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -1,9 +1,8 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |