diff options
author | Sergey Petrunya <psergey@askmonty.org> | 2010-10-10 17:18:11 +0300 |
---|---|---|
committer | Sergey Petrunya <psergey@askmonty.org> | 2010-10-10 17:18:11 +0300 |
commit | 72dd7575cd8b9372ddb79cc4c94050e4ee1e5ee1 (patch) | |
tree | 220c965bb467b020a4db171d7803586f9ed22cea /sql | |
parent | cfbd9270243e4b429cdc26e8554bcc99690f2422 (diff) | |
parent | 00a2f36bbf22a4d8b2367724e7919c0603cf6f71 (diff) | |
download | mariadb-git-72dd7575cd8b9372ddb79cc4c94050e4ee1e5ee1.tar.gz |
Merge 5.2->5.3
- Re-commit Monty's merge, partially fixed by Igor and SergeyP,
but still broken
Diffstat (limited to 'sql')
112 files changed, 4220 insertions, 2524 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index bae77f80b22..26957c5ea43 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -18,7 +18,7 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi") -SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /MAP /MAPINFO:EXPORTS") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MAP /MAPINFO:EXPORTS") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/extra/yassl/include @@ -160,3 +160,8 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def) ADD_DEPENDENCIES(udf_example strings GenError) TARGET_LINK_LIBRARIES(udf_example strings wsock32) + +INSTALL(TARGETS mysqld + RUNTIME DESTINATION bin COMPONENT runtime + LIBRARY DESTINATION lib COMPONENT runtime + ARCHIVE DESTINATION lib COMPONENT runtime) diff --git a/sql/Makefile.am b/sql/Makefile.am index 13a60ba5c79..f7a3945311f 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -201,6 +201,3 @@ install-exec-hook: test ! -x mysqld-debug$(EXEEXT) || $(INSTALL_PROGRAM) mysqld-debug$(EXEEXT) $(DESTDIR)$(libexecdir) test ! -f mysqld-debug.sym.gz || $(INSTALL_DATA) mysqld-debug.sym.gz $(DESTDIR)$(pkglibdir) test ! -f mysqld.sym.gz || $(INSTALL_DATA) mysqld.sym.gz $(DESTDIR)$(pkglibdir) - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/sql/authors.h b/sql/authors.h index 4a321bebb7d..bab319e3dcb 100644 --- a/sql/authors.h +++ b/sql/authors.h @@ -86,6 +86,7 @@ struct show_table_authors_st show_table_authors[]= { { "Eric Herman", "Amsterdam, Netherlands", "Bug fixing - federated" }, { "Andrey Hristov", "Walldorf, Germany", "Event scheduler (5.1)" }, { "Alexander (Alexi) Ivanov", "St. Petersburg, Russia", "Replication" }, + { "Mattias Jonsson", "Uppsala, Sweden", "Partitioning" }, { "Alexander (Salle) Keremidarski", "Sofia, Bulgaria", "Bug fixing" }, { "Mats Kindahl", "Storvreta, Sweden", "Replication" }, diff --git a/sql/create_options.cc b/sql/create_options.cc index 6d682853ae6..4478fc14791 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -136,9 +136,10 @@ static bool set_one_value(ha_create_table_option *opt, DBUG_RETURN(0); } - my_option optp= { opt->name, 1, 0, (uchar **)val, 0, 0, GET_ULL, - REQUIRED_ARG, opt->def_value, opt->min_value, opt->max_value, - 0, opt->block_size, 0}; + my_option optp= + { opt->name, 1, 0, (uchar **)val, 0, 0, GET_ULL, + REQUIRED_ARG, opt->def_value, opt->min_value, opt->max_value, + 0, (long) opt->block_size, 0}; ulonglong orig_val= strtoull(value->str, NULL, 10); my_bool unused; @@ -167,7 +168,7 @@ static bool set_one_value(ha_create_table_option *opt, { uint *val= (uint *)((char *)base + opt->offset), num; - *val= opt->def_value; + *val= (uint) opt->def_value; if (!value->str) DBUG_RETURN(0); @@ -600,6 +601,7 @@ engine_option_value *merge_engine_table_options(engine_option_value *first, { engine_option_value *end, *opt; DBUG_ENTER("merge_engine_table_options"); + LINT_INIT(end); /* find last element */ if (first && second) diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 9b428ed6ec9..959f6ec06c0 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -833,8 +833,9 @@ bool get_next_time(const Time_zone *time_zone, my_time_t *next, } else { - long diff_months= (long) (local_now.year - local_start.year)*12 + - (local_now.month - local_start.month); + long diff_months= ((long) local_now.year - (long) local_start.year)*12 + + ((long) local_now.month - (long) local_start.month); + /* Unlike for seconds above, the formula below returns the interval that, when added to the local_start, will give the time in the @@ -1432,7 +1433,10 @@ Event_job_data::execute(THD *thd, bool drop) thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length()); { - Parser_state parser_state(thd, thd->query(), thd->query_length()); + Parser_state parser_state; + if (parser_state.init(thd, thd->query(), thd->query_length())) + goto end; + lex_start(thd); if (parse_sql(thd, & parser_state, creation_ctx)) diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h index e32077b9c97..1ca619b8ed6 100644 --- a/sql/event_data_objects.h +++ b/sql/event_data_objects.h @@ -89,9 +89,9 @@ public: my_time_t execute_at; my_time_t starts; my_time_t ends; - my_bool starts_null; - my_bool ends_null; - my_bool execute_at_null; + bool starts_null; + bool ends_null; + bool execute_at_null; longlong expression; interval_type interval; diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 82f9d354888..d1fa971847b 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -474,7 +474,8 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table, READ_RECORD read_record_info; DBUG_ENTER("Event_db_repository::table_scan_all_for_i_s"); - init_read_record(&read_record_info, thd, event_table, NULL, 1, 0, FALSE); + if (init_read_record(&read_record_info, thd, event_table, NULL, 1, 0, FALSE)) + DBUG_RETURN(TRUE); /* rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE, @@ -609,7 +610,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, bool Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, - my_bool create_if_not) + bool create_if_not) { int ret= 1; TABLE *table= NULL; @@ -960,7 +961,9 @@ Event_db_repository::drop_events_by_field(THD *thd, DBUG_VOID_RETURN; /* only enabled events are in memory, so we go now and delete the rest */ - init_read_record(&read_record_info, thd, table, NULL, 1, 0, FALSE); + if (init_read_record(&read_record_info, thd, table, NULL, 1, 0, FALSE)) + goto end; + while (!ret && !(read_record_info.read_record(&read_record_info)) ) { char *et_field= get_field(thd->mem_root, table->field[field]); @@ -982,8 +985,9 @@ Event_db_repository::drop_events_by_field(THD *thd, } } end_read_record(&read_record_info); - close_thread_tables(thd); +end: + close_thread_tables(thd); DBUG_VOID_RETURN; } diff --git a/sql/event_db_repository.h b/sql/event_db_repository.h index ef778407d1e..7ff17558572 100644 --- a/sql/event_db_repository.h +++ b/sql/event_db_repository.h @@ -73,7 +73,7 @@ public: Event_db_repository(){} bool - create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not); + create_event(THD *thd, Event_parse_data *parse_data, bool create_if_not); bool update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname, diff --git a/sql/event_parse_data.h b/sql/event_parse_data.h index 8b42eb23937..01cdc685c46 100644 --- a/sql/event_parse_data.h +++ b/sql/event_parse_data.h @@ -70,9 +70,9 @@ public: my_time_t starts; my_time_t ends; my_time_t execute_at; - my_bool starts_null; - my_bool ends_null; - my_bool execute_at_null; + bool starts_null; + bool ends_null; + bool execute_at_null; sp_name *identifier; Item* item_expression; diff --git a/sql/events.cc b/sql/events.cc index 0f3fc8eee4a..1b794edb5ec 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -917,7 +917,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) */ bool -Events::init(my_bool opt_noacl_or_bootstrap) +Events::init(bool opt_noacl_or_bootstrap) { THD *thd; @@ -1214,7 +1214,12 @@ Events::load_events_from_db(THD *thd) DBUG_RETURN(TRUE); } - init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE); + if (init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE)) + { + close_thread_tables(thd); + DBUG_RETURN(TRUE); + } + while (!(read_record_info.read_record(&read_record_info))) { Event_queue_element *et; diff --git a/sql/events.h b/sql/events.h index 2bc87517748..a3c98d84f00 100644 --- a/sql/events.h +++ b/sql/events.h @@ -92,7 +92,7 @@ public: get_db_repository() { return db_repository; } static bool - init(my_bool opt_noacl); + init(bool opt_noacl); static void deinit(); diff --git a/sql/field.cc b/sql/field.cc index 03d78706f95..56f45158b7f 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -57,7 +57,7 @@ const char field_separator=','; ((ulong) ((LL(1) << min(arg, 4) * 8) - LL(1))) #define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))) -#define ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || bitmap_is_set(&table->vcol_set, field_index))) +#define ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || bitmap_is_set(table->vcol_set, field_index))) /* Rules for merging different types of fields in UNION @@ -1284,7 +1284,7 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) This is used for printing bit_fields as numbers while debugging. */ -String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val) +String *Field::val_int_as_str(String *val_buffer, bool unsigned_val) { ASSERT_COLUMN_MARKED_FOR_READ; CHARSET_INFO *cs= &my_charset_bin; @@ -5319,7 +5319,6 @@ String *Field_time::val_str(String *val_buffer, bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate) { - long tmp; THD *thd= table ? table->in_use : current_thd; if (!(fuzzydate & TIME_FUZZY_DATE)) { @@ -5329,19 +5328,7 @@ bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate) thd->row_count); return 1; } - tmp=(long) sint3korr(ptr); - ltime->neg=0; - if (tmp < 0) - { - ltime->neg= 1; - tmp=-tmp; - } - ltime->hour=tmp/10000; - tmp-=ltime->hour*10000; - ltime->minute= tmp/100; - ltime->second= tmp % 100; - ltime->year= ltime->month= ltime->day= ltime->second_part= 0; - return 0; + return Field_time::get_time(ltime); } @@ -6722,8 +6709,7 @@ void Field_string::sql_type(String &res) const length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(), "%s(%d)", - ((type() == MYSQL_TYPE_VAR_STRING && - !thd->variables.new_mode) ? + (type() == MYSQL_TYPE_VAR_STRING ? (has_charset() ? "varchar" : "varbinary") : (has_charset() ? "char" : "binary")), (int) field_length / charset()->mbmaxlen); @@ -6875,7 +6861,7 @@ int Field_string::do_save_field_metadata(uchar *metadata_ptr) */ int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length, - my_bool insert_or_update) + bool insert_or_update) { uint a_length, b_length; if (length > 255) @@ -6913,7 +6899,7 @@ int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length, */ int Field_string::pack_cmp(const uchar *key, uint length, - my_bool insert_or_update) + bool insert_or_update) { uint row_length, local_key_length; uchar *end; @@ -7392,7 +7378,7 @@ Field_varstring::unpack(uchar *to, const uchar *from, int Field_varstring::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg, - my_bool insert_or_update) + bool insert_or_update) { uint a_length, b_length; if (key_length_arg > 255) @@ -7413,7 +7399,7 @@ int Field_varstring::pack_cmp(const uchar *a, const uchar *b, int Field_varstring::pack_cmp(const uchar *b, uint key_length_arg, - my_bool insert_or_update) + bool insert_or_update) { uchar *a= ptr+ length_bytes; uint a_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); @@ -8144,7 +8130,7 @@ const uchar *Field_blob::unpack(uchar *to, /* Keys for blobs are like keys on varchars */ int Field_blob::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg, - my_bool insert_or_update) + bool insert_or_update) { uint a_length, b_length; if (key_length_arg > 255) @@ -8165,7 +8151,7 @@ int Field_blob::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg, int Field_blob::pack_cmp(const uchar *b, uint key_length_arg, - my_bool insert_or_update) + bool insert_or_update) { uchar *a; uint a_length, b_length; @@ -8715,7 +8701,13 @@ int Field_set::store(longlong nr, bool unsigned_val) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int error= 0; - ulonglong max_nr= set_bits(ulonglong, typelib->count); + ulonglong max_nr; + + if (sizeof(ulonglong)*8 <= typelib->count) + max_nr= ULONGLONG_MAX; + else + max_nr= (ULL(1) << typelib->count) - 1; + if ((ulonglong) nr > max_nr) { nr&= max_nr; diff --git a/sql/field.h b/sql/field.h index 9b31cbc7b70..ca400caac59 100644 --- a/sql/field.h +++ b/sql/field.h @@ -64,29 +64,20 @@ private: */ enum_field_types field_type; /* Real field type*/ /* Flag indicating that the field is physically stored in the database */ - my_bool stored_in_db; + bool stored_in_db; /* Flag indicating that the field used in a partitioning expression */ - my_bool in_partitioning_expr; + bool in_partitioning_expr; public: /* The expression to compute the value of the virtual column */ Item *expr_item; /* Text representation of the defining expression */ LEX_STRING expr_str; - /* - The list of items created when the defining expression for the virtual - column is being parsed and validated. These items are freed in the closefrm - function when the table containing this virtual column is removed from - the TABLE cache. - TODO. Items for all different virtual columns of a table should be put into - one list attached to the TABLE structure. - */ - Item *item_free_list; Virtual_column_info() : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), stored_in_db(FALSE), in_partitioning_expr(FALSE), - expr_item(NULL), item_free_list(NULL) + expr_item(NULL) { expr_str.str= NULL; expr_str.length= 0; @@ -226,7 +217,7 @@ public: This trickery is used to decrease a number of malloc calls. */ virtual String *val_str(String*,String *)=0; - String *val_int_as_str(String *val_buffer, my_bool unsigned_flag); + String *val_int_as_str(String *val_buffer, bool unsigned_flag); /* str_needs_quotes() returns TRUE if the value returned by val_str() needs to be quoted when used in constructing an SQL query. @@ -525,10 +516,10 @@ public: { return max_length;} virtual int pack_cmp(const uchar *a,const uchar *b, uint key_length_arg, - my_bool insert_or_update) + bool insert_or_update) { return cmp(a,b); } virtual int pack_cmp(const uchar *b, uint key_length_arg, - my_bool insert_or_update) + bool insert_or_update) { return cmp(ptr,b); } uint offset(uchar *record) { @@ -794,7 +785,7 @@ public: /* base class for float and double and decimal (old one) */ class Field_real :public Field_num { public: - my_bool not_fixed; + bool not_fixed; Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -1221,7 +1212,7 @@ public: NONE, field_name_arg, dec_arg, 0, 0) {} Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, - uint8 dec_arg, my_bool not_fixed_arg) + uint8 dec_arg, bool not_fixed_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, NONE, field_name_arg, dec_arg, 0, 0) {not_fixed= not_fixed_arg; } @@ -1312,7 +1303,7 @@ public: Field::set_default(); } /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */ - inline long get_timestamp(my_bool *null_value) + inline long get_timestamp(bool *null_value) { if ((*null_value= is_null())) return 0; @@ -1599,8 +1590,8 @@ public: const Relay_log_info *rli, uint16 mflags); uint row_pack_length() { return (field_length + 1); } int pack_cmp(const uchar *a,const uchar *b,uint key_length, - my_bool insert_or_update); - int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update); + bool insert_or_update); + int pack_cmp(const uchar *b,uint key_length,bool insert_or_update); uint packed_col_length(const uchar *to, uint length); uint max_packed_col_length(uint max_length); uint size_of() const { return sizeof(*this); } @@ -1682,8 +1673,8 @@ public: const uchar *unpack_key(uchar* to, const uchar *from, uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, - my_bool insert_or_update); - int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); + bool insert_or_update); + int pack_cmp(const uchar *b, uint key_length,bool insert_or_update); int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L); int key_cmp(const uchar *,const uchar*); int key_cmp(const uchar *str, uint length); @@ -1868,8 +1859,8 @@ public: const uchar *unpack_key(uchar* to, const uchar *from, uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, - my_bool insert_or_update); - int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); + bool insert_or_update); + int pack_cmp(const uchar *b, uint key_length,bool insert_or_update); uint packed_col_length(const uchar *col_ptr, uint length); uint max_packed_col_length(uint max_length); void free() { value.free(); } @@ -2231,7 +2222,7 @@ class Copy_field :public Sql_alloc { public: uchar *from_ptr,*to_ptr; uchar *from_null_ptr,*to_null_ptr; - my_bool *null_row; + bool *null_row; uint from_bit,to_bit; uint from_length,to_length; Field *from_field,*to_field; diff --git a/sql/filesort.cc b/sql/filesort.cc index 41410929f15..aa808a5e6b5 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -515,7 +515,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, THD *thd= current_thd; volatile THD::killed_state *killed= &thd->killed; handler *file; - MY_BITMAP *save_read_set, *save_write_set; + MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set; DBUG_ENTER("find_all_keys"); DBUG_PRINT("info",("using: %s", (select ? select->quick ? "ranges" : "where": @@ -537,7 +537,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, if (! indexfile && ! quick_select) { next_pos=(uchar*) 0; /* Find records in sequence */ - file->ha_rnd_init(1); + if (file->ha_rnd_init_with_error(1)) + DBUG_RETURN(HA_POS_ERROR); file->extra_opt(HA_EXTRA_CACHE, current_thd->variables.read_buff_size); } @@ -551,6 +552,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, /* Remember original bitmaps */ save_read_set= sort_form->read_set; save_write_set= sort_form->write_set; + save_vcol_set= sort_form->vcol_set; /* Set up temporary column read map for columns used by sort */ bitmap_clear_all(&sort_form->tmp_set); /* Temporary set for register_used_fields and register_field_in_read_map */ @@ -559,7 +561,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, if (select && select->cond) select->cond->walk(&Item::register_field_in_read_map, 1, (uchar*) sort_form); - sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set); + sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set, + &sort_form->tmp_set); for (;;) { @@ -568,7 +571,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, if ((error= select->quick->get_next())) break; if (!error) - update_virtual_fields(sort_form); + update_virtual_fields(thd, sort_form); file->position(sort_form->record[0]); DBUG_EXECUTE_IF("debug_filesort", dbug_print_record(sort_form, TRUE);); } @@ -587,7 +590,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, { error=file->ha_rnd_next(sort_form->record[0]); if (!error) - update_virtual_fields(sort_form); + update_virtual_fields(thd, sort_form); if (!flag) { my_store_ptr(ref_pos,ref_length,record); // Position to row @@ -642,7 +645,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, DBUG_RETURN(HA_POS_ERROR); /* Signal we should use orignal column read and write maps */ - sort_form->column_bitmaps_set(save_read_set, save_write_set); + sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set); DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos)); if (error != HA_ERR_END_OF_FILE) @@ -1009,7 +1012,14 @@ static void register_used_fields(SORTPARAM *param) if ((field= sort_field->field)) { if (field->table == table) - bitmap_set_bit(bitmap, field->field_index); + { + if (field->vcol_info) + { + Item *vcol_item= field->vcol_info->expr_item; + vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0); + } + bitmap_set_bit(bitmap, field->field_index); + } } else { // Item diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 26e14ab8dfb..7fd37143205 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4232,7 +4232,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows) /** End of an insert. */ -int ha_ndbcluster::end_bulk_insert(bool abort) +int ha_ndbcluster::end_bulk_insert() { int error= 0; DBUG_ENTER("end_bulk_insert"); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 9e6d697492a..7c9dba9e30e 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -332,7 +332,7 @@ class ha_ndbcluster: public handler double scan_time(); ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key); void start_bulk_insert(ha_rows rows); - int end_bulk_insert(bool abort); + int end_bulk_insert(); static Thd_ndb* seize_thd_ndb(); static void release_thd_ndb(Thd_ndb* thd_ndb); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 09c2fbef6f3..e76b3607249 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -59,6 +59,8 @@ #include <mysql/plugin.h> +#include "debug_sync.h" + static const char *ha_par_ext= ".par"; #ifdef NOT_USED static int free_share(PARTITION_SHARE * share); @@ -87,7 +89,9 @@ static int partition_initialize(void *p) partition_hton->create= partition_create_handler; partition_hton->partition_flags= partition_flags; partition_hton->alter_table_flags= alter_table_flags; - partition_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN; + partition_hton->flags= HTON_NOT_USER_SELECTABLE | + HTON_HIDDEN | + HTON_TEMPORARY_NOT_SUPPORTED; return 0; } @@ -356,7 +360,7 @@ bool ha_partition::initialize_partition(MEM_ROOT *mem_root) } else if (get_from_handler_file(table_share->normalized_path.str, mem_root)) { - mem_alloc_error(2); + my_message(ER_UNKNOWN_ERROR, "Failed to read from the .par file", MYF(0)); DBUG_RETURN(1); } /* @@ -691,6 +695,7 @@ int ha_partition::rename_partitions(const char *path) DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path, norm_name_buff))); + DEBUG_SYNC(ha_thd(), "before_rename_partitions"); if (temp_partitions) { /* @@ -992,7 +997,7 @@ static bool print_admin_msg(THD* thd, const char* msg_type, Protocol *protocol= thd->protocol; uint length, msg_length; char msgbuf[HA_MAX_MSG_BUF]; - char name[NAME_LEN*2+2]; + char name[SAFE_NAME_LEN*2+2]; va_start(args, fmt); msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); @@ -1661,7 +1666,7 @@ int ha_partition::copy_partitions(ulonglong * const copied, uint32 new_part; late_extra_cache(reorg_part); - if ((result= file->ha_rnd_init(1))) + if ((result= file->ha_rnd_init_with_error(1))) goto error; while (TRUE) { @@ -1835,6 +1840,13 @@ uint ha_partition::del_ren_cre_table(const char *from, handler **file, **abort_file; DBUG_ENTER("del_ren_cre_table()"); + /* Not allowed to create temporary partitioned tables */ + if (create_info && create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + my_error(ER_PARTITION_NO_TEMPORARY, MYF(0)); + DBUG_RETURN(TRUE); + } + if (get_from_handler_file(from, ha_thd()->mem_root)) DBUG_RETURN(TRUE); DBUG_ASSERT(m_file_buffer); @@ -2610,6 +2622,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) DBUG_RETURN(0); err_handler: + DEBUG_SYNC(ha_thd(), "partition_open_error"); while (file-- != m_file) (*file)->close(); bitmap_free(&m_bulk_insert_started); @@ -3416,18 +3429,17 @@ ha_rows ha_partition::guess_bulk_insert_rows() SYNOPSIS end_bulk_insert() - abort 1 if table will be deleted (error condition) RETURN VALUE >0 Error code 0 Success Note: end_bulk_insert can be called without start_bulk_insert - being called, see bug¤44108. + being called, see bug#44108. */ -int ha_partition::end_bulk_insert(bool abort) +int ha_partition::end_bulk_insert() { int error= 0; uint i; @@ -3440,7 +3452,7 @@ int ha_partition::end_bulk_insert(bool abort) { int tmp; if (bitmap_is_set(&m_bulk_insert_started, i) && - (tmp= m_file[i]->ha_end_bulk_insert(abort))) + (tmp= m_file[i]->ha_end_bulk_insert())) error= tmp; } bitmap_clear_all(&m_bulk_insert_started); @@ -4183,6 +4195,58 @@ int ha_partition::common_first_last(uchar *buf) /* + Optimization of the default implementation to take advantage of dynamic + partition pruning. +*/ +int ha_partition::index_read_idx_map(uchar *buf, uint index, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) +{ + int error= HA_ERR_KEY_NOT_FOUND; + DBUG_ENTER("ha_partition::index_read_idx_map"); + + if (find_flag == HA_READ_KEY_EXACT) + { + uint part; + m_start_key.key= key; + m_start_key.keypart_map= keypart_map; + m_start_key.flag= find_flag; + m_start_key.length= calculate_key_len(table, index, m_start_key.key, + m_start_key.keypart_map); + + get_partition_set(table, buf, index, &m_start_key, &m_part_spec); + + /* How can it be more than one partition with the current use? */ + DBUG_ASSERT(m_part_spec.start_part == m_part_spec.end_part); + + for (part= m_part_spec.start_part; part <= m_part_spec.end_part; part++) + { + if (bitmap_is_set(&(m_part_info->used_partitions), part)) + { + error= m_file[part]->index_read_idx_map(buf, index, key, + keypart_map, find_flag); + if (error != HA_ERR_KEY_NOT_FOUND && + error != HA_ERR_END_OF_FILE) + break; + } + } + } + else + { + /* + If not only used with READ_EXACT, we should investigate if possible + to optimize for other find_flag's as well. + */ + DBUG_ASSERT(0); + /* fall back on the default implementation */ + error= handler::index_read_idx_map(buf, index, key, keypart_map, find_flag); + } + DBUG_RETURN(error); +} + + +/* Read next record in a forward index scan SYNOPSIS diff --git a/sql/ha_partition.h b/sql/ha_partition.h index e1339abc081..1a9ec5bbf70 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -53,8 +53,7 @@ typedef struct st_ha_data_partition HA_CAN_FULLTEXT | \ HA_DUPLICATE_POS | \ HA_CAN_SQL_HANDLER | \ - HA_CAN_INSERT_DELAYED | \ - HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) + HA_CAN_INSERT_DELAYED) class ha_partition :public handler { private: @@ -364,7 +363,7 @@ public: virtual int delete_row(const uchar * buf); virtual int delete_all_rows(void); virtual void start_bulk_insert(ha_rows rows); - virtual int end_bulk_insert(bool); + virtual int end_bulk_insert(); private: ha_rows guess_bulk_insert_rows(); void start_part_bulk_insert(THD *thd, uint part_id); @@ -448,6 +447,15 @@ public: virtual int index_init(uint idx, bool sorted); virtual int index_end(); + /** + @breif + Positions an index cursor to the index specified in the hanlde. Fetches the + row if available. If the key value is null, begin at first key of the + index. + */ + virtual int index_read_idx_map(uchar *buf, uint index, const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); /* These methods are used to jump to next or previous entry in the index scan. There are also methods to jump to first and last entry. @@ -764,9 +772,6 @@ public: HA_PRIMARY_KEY_REQUIRED_FOR_POSITION: Does the storage engine need a PK for position? - Used with hidden primary key in InnoDB. - Hidden primary keys cannot be supported by partitioning, since the - partitioning expressions columns must be a part of the primary key. (InnoDB) HA_FILE_BASED is always set for partition handler since we use a diff --git a/sql/handler.cc b/sql/handler.cc index 1713510e980..94e16499c59 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -59,6 +59,7 @@ static const LEX_STRING sys_table_aliases[]= { C_STRING_WITH_LEN("NDB") }, { C_STRING_WITH_LEN("NDBCLUSTER") }, { C_STRING_WITH_LEN("HEAP") }, { C_STRING_WITH_LEN("MEMORY") }, { C_STRING_WITH_LEN("MERGE") }, { C_STRING_WITH_LEN("MRG_MYISAM") }, + { C_STRING_WITH_LEN("Maria") }, { C_STRING_WITH_LEN("Aria") }, {NullS, 0} }; @@ -2028,6 +2029,10 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, handler *handler::clone(MEM_ROOT *mem_root) { handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type()); + + if (!new_handler) + return NULL; + /* Allocate handler->ref here because otherwise ha_open will allocate it on this->table->mem_root and we will not be able to reclaim that memory @@ -2035,12 +2040,13 @@ handler *handler::clone(MEM_ROOT *mem_root) */ if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2))) return NULL; - if (new_handler && !new_handler->ha_open(table, - table->s->normalized_path.str, - table->db_stat, - HA_OPEN_IGNORE_IF_LOCKED)) - return new_handler; - return NULL; + if (new_handler->ha_open(table, + table->s->normalized_path.str, + table->db_stat, + HA_OPEN_IGNORE_IF_LOCKED)) + return NULL; + new_handler->cloned= 1; // Marker for debugging + return new_handler; } @@ -2114,6 +2120,18 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, } +/* Initialize handler for random reading, with error handling */ + +int handler::ha_rnd_init_with_error(bool scan) +{ + int error; + if (!(error= ha_rnd_init(scan))) + return 0; + table->file->print_error(error, MYF(0)); + return error; +} + + /** Read first row (only) from a table. @@ -2133,9 +2151,11 @@ int handler::read_first_row(uchar * buf, uint primary_key) if (stats.deleted < 10 || primary_key >= MAX_KEY || !(index_flags(primary_key, 0, 0) & HA_READ_ORDER)) { - (void) ha_rnd_init(1); - while ((error= ha_rnd_next(buf)) == HA_ERR_RECORD_DELETED) ; - (void) ha_rnd_end(); + if ((!(error= ha_rnd_init(1)))) + { + while ((error= ha_rnd_next(buf)) == HA_ERR_RECORD_DELETED) ; + (void) ha_rnd_end(); + } } else { @@ -4040,7 +4060,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 ? wild : "NULL", dir)); + val_or_null(db), val_or_null(path), + val_or_null(wild), dir)); st_find_files_args args= {db, path, wild, dir, files}; plugin_foreach(thd, find_files_handlerton, diff --git a/sql/handler.h b/sql/handler.h index e12048da18c..6eb496a38cc 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -100,7 +100,10 @@ #define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15) /* If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, it means that to position() - uses a primary key. Without primary key, we can't call position(). + uses a primary key given by the record argument. + Without primary key, we can't call position(). + If not set, the position is returned as the current rows position + regardless of what argument is given. */ #define HA_PRIMARY_KEY_REQUIRED_FOR_POSITION (1 << 16) #define HA_CAN_RTREEKEYS (1 << 17) @@ -1037,7 +1040,7 @@ typedef struct st_ha_create_information ulong avg_row_length; ulong used_fields; ulong key_block_size; - SQL_LIST merge_list; + SQL_I_List<TABLE_LIST> merge_list; handlerton *db_type; /** Row type of the table definition. @@ -1448,6 +1451,7 @@ public: bool locked; bool implicit_emptied; /* Can be !=0 only if HEAP */ bool mark_trx_done; + bool cloned; /* 1 if this was created with clone */ const COND *pushed_cond; Item *pushed_idx_cond; uint pushed_idx_cond_keyno; /* The index which the above condition is for */ @@ -1494,7 +1498,7 @@ public: key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), ft_handler(0), inited(NONE), - locked(FALSE), implicit_emptied(FALSE), mark_trx_done(FALSE), + locked(FALSE), implicit_emptied(FALSE), mark_trx_done(FALSE), cloned(0), pushed_cond(0), pushed_idx_cond(NULL), pushed_idx_cond_keyno(MAX_KEY), next_insert_id(0), insert_id_for_cur_row(0), @@ -1537,7 +1541,7 @@ public: } /* This is called after index_init() if we need to do a index scan */ virtual int prepare_index_scan() { return 0; } - int ha_rnd_init(bool scan) + int ha_rnd_init(bool scan) __attribute__ ((warn_unused_result)) { int result; DBUG_ENTER("ha_rnd_init"); @@ -1552,6 +1556,7 @@ public: inited=NONE; DBUG_RETURN(rnd_end()); } + int ha_rnd_init_with_error(bool scan) __attribute__ ((warn_unused_result)); int ha_reset(); /* Tell handler (not storage engine) this is start of a new statement */ void ha_start_of_new_statement() @@ -1591,10 +1596,10 @@ public: estimation_rows_to_insert= rows; start_bulk_insert(rows); } - int ha_end_bulk_insert(bool abort) + int ha_end_bulk_insert() { estimation_rows_to_insert= 0; - return end_bulk_insert(abort); + return end_bulk_insert(); } int ha_bulk_update_row(const uchar *old_data, uchar *new_data, uint *dup_key_found); @@ -1826,10 +1831,9 @@ private: virtual int rnd_next(uchar *buf)=0; virtual int rnd_pos(uchar * buf, uchar *pos)=0; /** - One has to use this method when to find - random position by record as the plain - position() call doesn't work for some - handlers for random position. + This function only works for handlers having + HA_PRIMARY_KEY_REQUIRED_FOR_POSITION set. + It will return the row with the PK given in the record argument. */ virtual int rnd_pos_by_record(uchar *record) { @@ -1860,6 +1864,12 @@ public: virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) { return (ha_rows) 10; } + /* + If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, then it sets ref + (reference to the row, aka position, with the primary key given in + the record). + Otherwise it set ref to the current row. + */ virtual void position(const uchar *record)=0; virtual int info(uint)=0; // see my_base.h for full description virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info, @@ -2278,7 +2288,7 @@ private: virtual int repair(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } virtual void start_bulk_insert(ha_rows rows) {} - virtual int end_bulk_insert(bool abort) { return 0; } + virtual int end_bulk_insert() { return 0; } virtual int index_read(uchar * buf, const uchar * key, uint key_len, enum ha_rkey_function find_flag) { return HA_ERR_WRONG_COMMAND; } diff --git a/sql/hash_filo.h b/sql/hash_filo.h index ab13d338695..8ddeeeb02fc 100644 --- a/sql/hash_filo.h +++ b/sql/hash_filo.h @@ -107,7 +107,7 @@ public: return entry; } - my_bool add(hash_filo_element *entry) + bool add(hash_filo_element *entry) { if (cache.records == size) { diff --git a/sql/item.cc b/sql/item.cc index 8f393eca79b..f5de67bf422 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -258,8 +258,9 @@ my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value) my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) { String *res; + if (!(res= val_str(&str_value))) - return 0; // NULL or EOM + return 0; if (str2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM, res->ptr(), res->length(), res->charset(), @@ -428,8 +429,8 @@ Item::Item(THD *thd, Item *item): with_sum_func(item->with_sum_func), fixed(item->fixed), is_autogenerated_name(item->is_autogenerated_name), - collation(item->collation), with_subselect(item->with_subselect), + collation(item->collation), cmp_context(item->cmp_context) { next= thd->free_list; // Put in free list @@ -2879,7 +2880,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) unsigned_flag= entry->unsigned_flag; if (limit_clause_param) { - my_bool unused; + bool unused; set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS); item_type= Item::INT_ITEM; DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0); @@ -3827,7 +3828,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) int found_match_degree= 0; Item_ident *cur_field; int cur_match_degree= 0; - char name_buff[NAME_LEN+1]; + char name_buff[SAFE_NAME_LEN+1]; if (find_item->type() == Item::FIELD_ITEM || find_item->type() == Item::REF_ITEM) @@ -3950,7 +3951,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) { Item **group_by_ref= NULL; Item **select_ref= NULL; - ORDER *group_list= (ORDER*) select->group_list.first; + ORDER *group_list= select->group_list.first; bool ambiguous_fields= FALSE; uint counter; enum_resolution_type resolution; @@ -4242,8 +4243,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) context->first_name_resolution_table, context->last_name_resolution_table, reference, REPORT_ALL_ERRORS, - !any_privileges && - TRUE, TRUE); + !any_privileges, TRUE); } return -1; } diff --git a/sql/item.h b/sql/item.h index 05e35e97e04..2158206441e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -539,17 +539,17 @@ public: uint name_length; /* Length of name */ 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; - my_bool with_sum_func; - my_bool fixed; /* If item fixed with fix_fields */ - my_bool is_autogenerated_name; /* indicate was name of this Item + bool maybe_null; /* If item may be null */ + bool null_value; /* if item is null */ + bool unsigned_flag; + bool with_sum_func; + bool fixed; /* If item fixed with fix_fields */ + bool is_autogenerated_name; /* indicate was name of this Item autogenerated or set by user */ - DTCollation collation; - my_bool with_subselect; /* If this item is a subselect or some + bool with_subselect; /* If this item is a subselect or some of its arguments is or contains a subselect */ + DTCollation collation; Item_result cmp_context; /* Comparison context */ // alloc & destruct is done as start of select using sql_alloc Item(); @@ -890,6 +890,7 @@ public: set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} + virtual void restore_to_before_no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } virtual Item *copy_andor_structure(THD *thd) { return this; } virtual Item *real_item() { return this; } @@ -947,6 +948,21 @@ public: virtual bool register_field_in_read_map(uchar *arg) { return 0; } virtual bool enumerate_field_refs_processor(uchar *arg) { return 0; } virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; } + + /* To call bool function for all arguments */ + struct bool_func_call_args + { + Item *original_func_item; + void (Item::*bool_function)(); + }; + bool call_bool_func_processor(uchar *org_item) + { + bool_func_call_args *info= (bool_func_call_args*) org_item; + /* Avoid recursion, as walk also calls for original item */ + if (info->original_func_item != this) + (this->*(info->bool_function))(); + return FALSE; + } /* The next function differs from the previous one that a bitmap to be updated is passed as uchar *arg. @@ -1938,7 +1954,7 @@ public: { return (uint)(max_length - test(value < 0)); } bool eq(const Item *, bool binary_cmp) const; bool check_partition_func_processor(uchar *bool_arg) { return FALSE;} - bool check_vcol_func_processor(uchar arg) { return FALSE;} + bool check_vcol_func_processor(uchar *arg) { return FALSE;} }; @@ -2477,6 +2493,14 @@ public: } bool enumerate_field_refs_processor(uchar *arg) { return (*ref)->enumerate_field_refs_processor(arg); } + void no_rows_in_result() + { + (*ref)->no_rows_in_result(); + } + void restore_to_before_no_rows_in_result() + { + (*ref)->restore_to_before_no_rows_in_result(); + } virtual void print(String *str, enum_query_type query_type); bool result_as_longlong() { @@ -2767,6 +2791,7 @@ public: { return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT; } + table_map not_null_tables() const { return 0; } virtual Ref_Type ref_type() { return OUTER_REF; } bool check_inner_refs_processor(uchar * arg); }; @@ -2826,7 +2851,7 @@ class Item_int_with_ref :public Item_int { Item *ref; public: - Item_int_with_ref(longlong i, Item *ref_arg, my_bool unsigned_arg) : + Item_int_with_ref(longlong i, Item *ref_arg, bool unsigned_arg) : Item_int(i), ref(ref_arg) { unsigned_flag= unsigned_arg; @@ -3071,7 +3096,7 @@ public: class Cached_item :public Sql_alloc { public: - my_bool null_value; + bool null_value; Cached_item() :null_value(0) {} virtual bool cmp(void)=0; virtual ~Cached_item(); /*line -e1509 */ @@ -3080,6 +3105,7 @@ public: class Cached_item_str :public Cached_item { Item *item; + uint32 value_max_length; String value,tmp_value; public: Cached_item_str(THD *thd, Item *arg); diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 13183a33e59..7d025ef518b 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -62,7 +62,9 @@ Cached_item::~Cached_item() {} */ Cached_item_str::Cached_item_str(THD *thd, Item *arg) - :item(arg), value(min(arg->max_length, thd->variables.max_sort_length)) + :item(arg), + value_max_length(min(arg->max_length, thd->variables.max_sort_length)), + value(value_max_length) {} bool Cached_item_str::cmp(void) @@ -71,7 +73,7 @@ bool Cached_item_str::cmp(void) bool tmp; if ((res=item->val_str(&tmp_value))) - res->length(min(res->length(), value.alloced_length())); + res->length(min(res->length(), value_max_length)); if (null_value != item->null_value) { if ((null_value= item->null_value)) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6b075c2d4aa..288fa439fad 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -825,7 +825,6 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value) return cmp_type; } - /* Retrieves correct TIME value from the given item. @@ -876,7 +875,12 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg, if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM || ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC)) { + Query_arena backup; + Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_int *cache= new Item_cache_int(); + if (save_arena) + thd->set_query_arena(save_arena); + /* Mark the cache as non-const to prevent re-caching. */ cache->set_used_tables(1); cache->store_longlong(item, value); @@ -912,7 +916,12 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, cache_converted_constant can't be used here because it can't correctly convert a DATETIME value from string to int representation. */ + Query_arena backup; + Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_int *cache= new Item_cache_int(); + if (save_arena) + thd->set_query_arena(save_arena); + /* Mark the cache as non-const to prevent re-caching. */ cache->set_used_tables(1); if (!(*a)->is_datetime()) @@ -1142,7 +1151,12 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM || ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC)) { + Query_arena backup; + Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME); + if (save_arena) + thd->set_query_arena(save_arena); + /* Mark the cache as non-const to prevent re-caching. */ cache->set_used_tables(1); cache->store_longlong(item, value); @@ -2884,6 +2898,8 @@ Item *Item_func_case::find_item(String *str) /* Compare every WHEN argument with it and return the first match */ for (uint i=0 ; i < ncases ; i+=2) { + if (args[i]->real_item()->type() == NULL_ITEM) + continue; cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); DBUG_ASSERT(cmp_type != ROW_RESULT); DBUG_ASSERT(cmp_items[(uint)cmp_type]); @@ -4122,9 +4138,17 @@ longlong Item_func_in::val_int() return (longlong) (!null_value && tmp != negated); } + if ((null_value= args[0]->real_item()->type() == NULL_ITEM)) + return 0; + have_null= 0; for (uint i= 1 ; i < arg_count ; i++) { + if (args[i]->real_item()->type() == NULL_ITEM) + { + have_null= TRUE; + continue; + } Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); in_item= cmp_items[(uint)cmp_type]; DBUG_ASSERT(in_item); @@ -4726,13 +4750,14 @@ Item_func::optimize_type Item_func_like::select_optimize() const if (args[1]->const_item()) { String* res2= args[1]->val_str((String *)&cmp.value2); + const char *ptr2; - if (!res2) + if (!res2 || !(ptr2= res2->ptr())) return OPTIMIZE_NONE; - if (*res2->ptr() != wild_many) + if (*ptr2 != wild_many) { - if (args[0]->result_type() != STRING_RESULT || *res2->ptr() != wild_one) + if (args[0]->result_type() != STRING_RESULT || *ptr2 != wild_one) return OPTIMIZE_OP; } } @@ -4808,8 +4833,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) We could also do boyer-more for non-const items, but as we would have to recompute the tables for each row it's not worth it. */ - if (args[1]->const_item() && !use_strnxfrm(collation.collation) && - !(specialflag & SPECIAL_NO_NEW_FUNC)) + if (args[1]->const_item() && !use_strnxfrm(collation.collation)) { String* res2 = args[1]->val_str(&cmp.value2); if (!res2) @@ -5646,7 +5670,7 @@ longlong Item_equal::val_int() return 0; List_iterator_fast<Item_field> it(fields); Item *item= const_item ? const_item : it++; - if ((null_value= item->null_value)) + if ((null_value= item->is_null())) return 0; eval_item->store_value(item); while ((item_field= it++)) @@ -5654,7 +5678,7 @@ longlong Item_equal::val_int() /* Skip fields of non-const tables. They haven't been read yet */ if (item_field->field->table->const_table) { - if ((null_value= item_field->null_value) || eval_item->cmp(item_field)) + if ((null_value= item_field->is_null()) || eval_item->cmp(item_field)) return 0; } } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 2eb419738e3..8a62f69de1f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -220,7 +220,7 @@ public: class Item_cache; -#define UNKNOWN ((my_bool)-1) +#define UNKNOWN (-1) /* @@ -250,7 +250,7 @@ protected: FALSE - result is FALSE TRUE - result is NULL */ - my_bool result_for_null_param; + int result_for_null_param; public: Item_in_optimizer(Item *a, Item_in_subselect *b): Item_bool_func(a, my_reinterpret_cast(Item *)(b)), cache(0), expr_cache(0), @@ -671,7 +671,7 @@ struct interval_range class Item_func_interval :public Item_int_func { Item_row *row; - my_bool use_decimal_comparison; + bool use_decimal_comparison; interval_range *intervals; public: Item_func_interval(Item_row *a) @@ -879,7 +879,7 @@ public: void value_to_item(uint pos, Item *item) { ((Item_int*) item)->value= ((packed_longlong*) base)[pos].val; - ((Item_int*) item)->unsigned_flag= (my_bool) + ((Item_int*) item)->unsigned_flag= (bool) ((packed_longlong*) base)[pos].unsigned_flag; } Item_result result_type() { return INT_RESULT; } @@ -1327,8 +1327,8 @@ public: else { args[0]->update_used_tables(); - if ((const_item_cache= !(used_tables_cache= args[0]->used_tables())) && - !with_subselect) + 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(); diff --git a/sql/item_create.cc b/sql/item_create.cc index 2e72ab24fb0..eade395a229 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5054,8 +5054,6 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, CHARSET_INFO *cs) { Item *UNINIT_VAR(res); - ulong len; - uint dec; switch (cast_type) { case ITEM_CAST_BINARY: @@ -5078,11 +5076,10 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, break; case ITEM_CAST_DECIMAL: { - if (c_len == NULL) - { - len= 0; - } - else + ulong len= 0; + uint dec= 0; + + if (c_len) { ulong decoded_size; errno= 0; @@ -5096,11 +5093,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, len= decoded_size; } - if (c_dec == NULL) - { - dec= 0; - } - else + if (c_dec) { ulong decoded_size; errno= 0; @@ -5136,12 +5129,9 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, } case ITEM_CAST_CHAR: { + int len= -1; CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection); - if (c_len == NULL) - { - len= (ulong) -1L; - } - else + if (c_len) { ulong decoded_size; errno= 0; @@ -5151,7 +5141,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH); return NULL; } - len= decoded_size; + len= (int) decoded_size; } res= new (thd->mem_root) Item_char_typecast(a, len, real_cs); break; diff --git a/sql/item_func.cc b/sql/item_func.cc index 82e0903be29..f0ed8110b79 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2065,10 +2065,12 @@ double Item_func_round::real_op() { double value= args[0]->val_real(); - if (!(null_value= args[0]->null_value || args[1]->null_value)) - return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag, - truncate); - + if (!(null_value= args[0]->null_value)) + { + longlong dec= args[1]->val_int(); + if (!(null_value= args[1]->null_value)) + return my_double_round(value, dec, args[1]->unsigned_flag, truncate); + } return 0.0; } @@ -2267,6 +2269,8 @@ void Item_func_min_max::fix_length_and_dec() max_length= my_decimal_precision_to_length_no_truncation(max_int_part + decimals, decimals, unsigned_flag); + else if (cmp_type == REAL_RESULT) + max_length= float_length(decimals); cached_field_type= agg_field_type(args, arg_count); } @@ -3143,11 +3147,15 @@ void Item_udf_func::print(String *str, enum_query_type query_type) double Item_func_udf_float::val_real() { + double res; + my_bool tmp_null_value; DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_func_udf_float::val"); DBUG_PRINT("info",("result_type: %d arg_count: %d", args[0]->result_type(), arg_count)); - DBUG_RETURN(udf.val(&null_value)); + res= udf.val(&tmp_null_value); + null_value= tmp_null_value; + DBUG_RETURN(res); } @@ -3164,9 +3172,13 @@ String *Item_func_udf_float::val_str(String *str) longlong Item_func_udf_int::val_int() { + longlong res; + my_bool tmp_null_value; DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_func_udf_int::val_int"); - DBUG_RETURN(udf.val_int(&null_value)); + res= udf.val_int(&tmp_null_value); + null_value= tmp_null_value; + DBUG_RETURN(res); } @@ -3183,8 +3195,10 @@ String *Item_func_udf_int::val_str(String *str) longlong Item_func_udf_decimal::val_int() { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + my_bool tmp_null_value; longlong result; + my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf); + null_value= tmp_null_value; if (null_value) return 0; my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); @@ -3194,8 +3208,10 @@ longlong Item_func_udf_decimal::val_int() double Item_func_udf_decimal::val_real() { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + my_bool tmp_null_value; double result; + my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf); + null_value= tmp_null_value; if (null_value) return 0.0; my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); @@ -3205,18 +3221,24 @@ double Item_func_udf_decimal::val_real() my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf) { + my_decimal *res; + my_bool tmp_null_value; DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_func_udf_decimal::val_decimal"); DBUG_PRINT("info",("result_type: %d arg_count: %d", args[0]->result_type(), arg_count)); - DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); + res= udf.val_decimal(&tmp_null_value, dec_buf); + null_value= tmp_null_value; + DBUG_RETURN(res); } String *Item_func_udf_decimal::val_str(String *str) { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + my_bool tmp_null_value; + my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf); + null_value= tmp_null_value; if (null_value) return 0; if (str->length() < DECIMAL_MAX_STR_LENGTH) @@ -3977,7 +3999,7 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, /** Get the value of a variable as a double. */ -double user_var_entry::val_real(my_bool *null_value) +double user_var_entry::val_real(bool *null_value) { if ((*null_value= (value == 0))) return 0.0; @@ -4006,7 +4028,7 @@ double user_var_entry::val_real(my_bool *null_value) /** Get the value of a variable as an integer. */ -longlong user_var_entry::val_int(my_bool *null_value) const +longlong user_var_entry::val_int(bool *null_value) const { if ((*null_value= (value == 0))) return LL(0); @@ -4038,7 +4060,7 @@ longlong user_var_entry::val_int(my_bool *null_value) const /** Get the value of a variable as a string. */ -String *user_var_entry::val_str(my_bool *null_value, String *str, +String *user_var_entry::val_str(bool *null_value, String *str, uint decimals) { if ((*null_value= (value == 0))) @@ -4071,7 +4093,7 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, /** Get the value of a variable as a decimal. */ -my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) +my_decimal *user_var_entry::val_decimal(bool *null_value, my_decimal *val) { if ((*null_value= (value == 0))) return 0; @@ -4763,6 +4785,7 @@ bool Item_func_get_user_var::set_value(THD *thd, bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); + DBUG_ASSERT(thd->lex->exchange); if (Item::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; @@ -4772,7 +4795,9 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) of fields in LOAD DATA INFILE. (Since Item_user_var_as_out_param is used only there). */ - entry->collation.set(thd->variables.collation_database); + entry->collation.set(thd->lex->exchange->cs ? + thd->lex->exchange->cs : + thd->variables.collation_database); entry->update_query_id= thd->query_id; return FALSE; } diff --git a/sql/item_func.h b/sql/item_func.h index 679348b1795..1aa8433b6dc 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -218,6 +218,21 @@ public: { return functype() == *(Functype *) arg; } + + void no_rows_in_result() + { + bool_func_call_args info; + info.original_func_item= this; + info.bool_function= &Item::no_rows_in_result; + walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info); + } + void restore_to_before_no_rows_in_result() + { + bool_func_call_args info; + info.original_func_item= this; + info.bool_function= &Item::restore_to_before_no_rows_in_result; + walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info); + } }; @@ -1504,7 +1519,7 @@ class Item_func_get_system_var :public Item_func longlong cached_llval; double cached_dval; String cached_strval; - my_bool cached_null_value; + bool cached_null_value; query_id_t used_query_id; uchar cache_present; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4c90eceec99..cafabe9a3ee 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2701,7 +2701,7 @@ String *Item_func_conv::val_str(String *str) from_base, &endptr, &err); } - ptr= longlong2str(dec, ans, to_base); + ptr= longlong2str(dec, ans, to_base, 1); if (str->copy(ans, (uint32) (ptr-ans), default_charset())) return &my_empty_string; return str; @@ -2868,7 +2868,7 @@ String *Item_func_hex::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; - ptr= longlong2str(dec,ans,16); + ptr= longlong2str(dec,ans,16,1); if (str->copy(ans,(uint32) (ptr-ans),default_charset())) return &my_empty_string; // End of memory return str; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 814bf14bb3e..2cc7ccfceaa 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -445,12 +445,12 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, if (item->walk(processor, walk_subquery, argument)) return 1; } - for (order= (ORDER*) lex->order_list.first ; order; order= order->next) + for (order= lex->order_list.first ; order; order= order->next) { if ((*order->item)->walk(processor, walk_subquery, argument)) return 1; } - for (order= (ORDER*) lex->group_list.first ; order; order= order->next) + for (order= lex->group_list.first ; order; order= order->next) { if ((*order->item)->walk(processor, walk_subquery, argument)) return 1; @@ -2519,15 +2519,15 @@ int subselect_single_select_engine::prepare() SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; if (join->prepare(&select_lex->ref_pointer_array, - (TABLE_LIST*) select_lex->table_list.first, + select_lex->table_list.first, select_lex->with_wild, select_lex->where, select_lex->order_list.elements + select_lex->group_list.elements, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, + select_lex->order_list.first, + select_lex->group_list.first, select_lex->having, - (ORDER*) 0, select_lex, + NULL, select_lex, select_lex->master_unit())) return 1; thd->lex->current_select= save_select; @@ -2778,7 +2778,8 @@ int subselect_uniquesubquery_engine::scan_table() if (table->file->inited) table->file->ha_index_end(); - table->file->ha_rnd_init(1); + if (table->file->ha_rnd_init_with_error(1)) + DBUG_RETURN(1); table->file->extra_opt(HA_EXTRA_CACHE, current_thd->variables.read_buff_size); table->null_row= 0; @@ -3297,14 +3298,13 @@ table_map subselect_engine::calc_const_tables(TABLE_LIST *table) table_map subselect_single_select_engine::upper_select_const_tables() { - return calc_const_tables((TABLE_LIST *) select_lex->outer_select()-> - leaf_tables); + return calc_const_tables(select_lex->outer_select()->leaf_tables); } table_map subselect_union_engine::upper_select_const_tables() { - return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables); + return calc_const_tables(unit->outer_select()->leaf_tables); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 3b0a9075a20..320c57b679f 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -32,8 +32,8 @@ class Cached_item; class Item_subselect :public Item_result_field { - my_bool value_assigned; /* value already assigned to subselect */ -public: + bool value_assigned; /* value already assigned to subselect */ +protected: /* thread handler, will be assigned in fix_fields only */ THD *thd; /* @@ -204,6 +204,8 @@ public: friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, Field*, Item*, Item_ident*); + friend bool convert_join_subqueries_to_semijoins(JOIN *join); + }; /* single value subselect */ @@ -564,9 +566,9 @@ protected: class subselect_single_select_engine: public subselect_engine { - my_bool prepared; /* simple subselect is prepared */ - my_bool optimized; /* simple subselect is optimized */ - my_bool executed; /* simple subselect is executed */ + bool prepared; /* simple subselect is prepared */ + bool optimized; /* simple subselect is optimized */ + bool executed; /* simple subselect is executed */ st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 75d98bc6d2a..f21d96a717a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1639,8 +1639,22 @@ void Item_sum_hybrid::cleanup() void Item_sum_hybrid::no_rows_in_result() { - was_values= FALSE; - clear(); + /* We may be called here twice in case of ref field in function */ + if (was_values) + { + was_values= FALSE; + was_null_value= value->null_value; + clear(); + } +} + +void Item_sum_hybrid::restore_to_before_no_rows_in_result() +{ + if (!was_values) + { + was_values= TRUE; + null_value= value->null_value= was_null_value; + } } @@ -2624,8 +2638,10 @@ void Item_udf_sum::clear() bool Item_udf_sum::add() { + my_bool tmp_null_value; DBUG_ENTER("Item_udf_sum::add"); - udf.add(&null_value); + udf.add(&tmp_null_value); + null_value= tmp_null_value; DBUG_RETURN(0); } @@ -2661,11 +2677,15 @@ Item *Item_sum_udf_float::copy_or_same(THD* thd) double Item_sum_udf_float::val_real() { + my_bool tmp_null_value; + double res; DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_sum_udf_float::val"); DBUG_PRINT("info",("result_type: %d arg_count: %d", args[0]->result_type(), arg_count)); - DBUG_RETURN(udf.val(&null_value)); + res= udf.val(&tmp_null_value); + null_value= tmp_null_value; + DBUG_RETURN(res); } @@ -2701,12 +2721,16 @@ longlong Item_sum_udf_decimal::val_int() my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf) { + my_decimal *res; + my_bool tmp_null_value; DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_func_udf_decimal::val_decimal"); DBUG_PRINT("info",("result_type: %d arg_count: %d", args[0]->result_type(), arg_count)); - DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); + res= udf.val_decimal(&tmp_null_value, dec_buf); + null_value= tmp_null_value; + DBUG_RETURN(res); } @@ -2723,11 +2747,15 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd) longlong Item_sum_udf_int::val_int() { + my_bool tmp_null_value; + longlong res; DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_sum_udf_int::val_int"); DBUG_PRINT("info",("result_type: %d arg_count: %d", args[0]->result_type(), arg_count)); - DBUG_RETURN(udf.val_int(&null_value)); + res= udf.val_int(&tmp_null_value); + null_value= tmp_null_value; + DBUG_RETURN(res); } @@ -2965,7 +2993,7 @@ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), Item_func_group_concat:: Item_func_group_concat(Name_resolution_context *context_arg, bool distinct_arg, List<Item> *select_list, - SQL_LIST *order_list, String *separator_arg) + SQL_I_List<ORDER> *order_list, String *separator_arg) :tmp_table_param(0), warning(0), separator(separator_arg), tree(0), unique_filter(NULL), table(0), order(0), context(context_arg), @@ -3009,7 +3037,7 @@ Item_func_group_concat(Name_resolution_context *context_arg, if (arg_count_order) { ORDER **order_ptr= order; - for (ORDER *order_item= (ORDER*) order_list->first; + for (ORDER *order_item= order_list->first; order_item != NULL; order_item= order_item->next) { @@ -3030,7 +3058,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, tree(item->tree), unique_filter(item->unique_filter), table(item->table), - order(item->order), context(item->context), arg_count_order(item->arg_count_order), arg_count_field(item->arg_count_field), @@ -3043,8 +3070,25 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, { quick_group= item->quick_group; result.set_charset(collation.collation); -} + /* + Since the ORDER structures pointed to by the elements of the 'order' array + may be modified in find_order_in_list() called from + Item_func_group_concat::setup(), create a copy of those structures so that + such modifications done in this object would not have any effect on the + object being copied. + */ + ORDER *tmp; + if (!(tmp= (ORDER *) thd->alloc(sizeof(ORDER *) * arg_count_order + + sizeof(ORDER) * arg_count_order))) + return; + order= (ORDER **)(tmp + arg_count_order); + for (uint i= 0; i < arg_count_order; i++, tmp++) + { + memcpy(tmp, item->order[i], sizeof(ORDER)); + order[i]= tmp; + } +} void Item_func_group_concat::cleanup() diff --git a/sql/item_sum.h b/sql/item_sum.h index 2922d6c9644..a47939187dd 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -500,7 +500,7 @@ public: enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } void reset_field() {} // not used void update_field() {} // not used - virtual void no_rows_in_result() {} + void no_rows_in_result() {} void fix_length_and_dec(); enum Item_result result_type () const { return val.traits->type(); } virtual void calculate_val_and_count(); @@ -857,6 +857,7 @@ protected: enum_field_types hybrid_field_type; int cmp_sign; bool was_values; // Set if we have found at least one row (for max/min only) + bool was_null_value; public: Item_sum_hybrid(Item *item_par,int sign) @@ -888,6 +889,7 @@ protected: void cleanup(); bool any_value() { return was_values; } void no_rows_in_result(); + void restore_to_before_no_rows_in_result(); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; @@ -1248,7 +1250,7 @@ class Item_func_group_concat : public Item_sum public: Item_func_group_concat(Name_resolution_context *context_arg, bool is_distinct, List<Item> *is_select, - SQL_LIST *is_order, String *is_separator); + SQL_I_List<ORDER> *is_order, String *is_separator); Item_func_group_concat(THD *thd, Item_func_group_concat *item); ~Item_func_group_concat(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d91ccee1575..57656f30294 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -288,11 +288,6 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, CHARSET_INFO *cs= &my_charset_bin; DBUG_ENTER("extract_date_time"); - LINT_INIT(strict_week_number); - /* Remove valgrind varnings when using gcc 3.3 and -O1 */ - VALGRIND_OR_LINT_INIT(strict_week_number_year_type); - VALGRIND_OR_LINT_INIT(sunday_first_n_first_week_non_iso); - if (!sub_pattern_end) bzero((char*) l_time, sizeof(*l_time)); @@ -2996,7 +2991,7 @@ String *Item_func_maketime::val_str(String *str) buf, len, MYSQL_TIMESTAMP_TIME, NullS); } - + if (make_time_with_warn((DATE_TIME_FORMAT *) 0, <ime, str)) { null_value= 1; diff --git a/sql/log.cc b/sql/log.cc index 90a60445716..8173b44c21f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -372,6 +372,7 @@ bool Log_to_csv_event_handler:: Open_tables_state open_tables_backup; ulonglong save_thd_options; bool save_time_zone_used; + DBUG_ENTER("log_general"); /* CSV uses TIME_to_timestamp() internally if table needs to be repaired @@ -412,7 +413,7 @@ bool Log_to_csv_event_handler:: need_close= TRUE; if (table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) || - table->file->ha_rnd_init(0)) + table->file->ha_rnd_init_with_error(0)) goto err; need_rnd_end= TRUE; @@ -490,7 +491,7 @@ err: thd->options= save_thd_options; thd->time_zone_used= save_time_zone_used; - return result; + DBUG_RETURN(result); } @@ -563,7 +564,7 @@ bool Log_to_csv_event_handler:: need_close= TRUE; if (table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) || - table->file->ha_rnd_init(0)) + table->file->ha_rnd_init_with_error(0)) goto err; need_rnd_end= TRUE; @@ -1474,11 +1475,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, trx_data->has_incident()); trx_data->reset(); - /* - We need to step the table map version after writing the - transaction cache to disk. - */ - mysql_bin_log.update_table_map_version(); statistic_increment(binlog_cache_use, &LOCK_status); if (trans_log->disk_writes != 0) { @@ -1504,13 +1500,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, } else // ...statement trx_data->truncate(trx_data->before_stmt_pos); - - /* - We need to step the table map version on a rollback to ensure - that a new table map event is generated instead of the one that - was written to the thrown-away transaction cache. - */ - mysql_bin_log.update_table_map_version(); } DBUG_ASSERT(thd->binlog_get_pending_rows_event() == NULL); @@ -1556,28 +1545,23 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) } /* - We commit the transaction if: - - - We are not in a transaction and committing a statement, or + We flush the cache if: - - We are in a transaction and a full transaction is committed + - we are committing a transaction or; + - no statement was committed before and just non-transactional + tables were updated. - Otherwise, we accumulate the statement + Otherwise, we collect the changes. */ - ulonglong const in_transaction= - thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); DBUG_PRINT("debug", - ("all: %d, empty: %s, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", + ("all: %d, empty: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", all, YESNO(trx_data->empty()), - YESNO(in_transaction), YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.stmt.modified_non_trans_table))); - - if (!in_transaction || all || - (!all && !trx_data->at_least_one_stmt_committed && - !stmt_has_updated_trans_table(thd) && - thd->transaction.stmt.modified_non_trans_table)) + if (ending_trans(thd, all) || + (trans_has_no_stmt_committed(thd, all) && + !stmt_has_updated_trans_table(thd) && stmt_has_updated_non_trans_table(thd))) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0); error= binlog_end_trans(thd, trx_data, &qev, all); @@ -1640,7 +1624,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) On the other hand, if a statement is transactional, we just safely roll it back. */ - if ((thd->transaction.stmt.modified_non_trans_table || + if ((stmt_has_updated_non_trans_table(thd) || (thd->options & OPTION_KEEP_LOG)) && mysql_bin_log.check_write_error(thd)) trx_data->set_incident(); @@ -1649,20 +1633,19 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) else { /* - We flush the cache with a rollback, wrapped in a beging/rollback if: - . aborting a transaction that modified a non-transactional table; + We flush the cache with a rollback, wrapped in a begin/rollback if: + . aborting a transaction that modified a non-transactional table or + the OPTION_KEEP_LOG is activate. . aborting a statement that modified both transactional and non-transactional tables but which is not in the boundaries of any transaction or there was no early change; - . the OPTION_KEEP_LOG is activate. */ - if ((all && thd->transaction.all.modified_non_trans_table) || - (!all && thd->transaction.stmt.modified_non_trans_table && - !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) || - (!all && thd->transaction.stmt.modified_non_trans_table && - !trx_data->at_least_one_stmt_committed && - thd->current_stmt_binlog_row_based) || - ((thd->options & OPTION_KEEP_LOG))) + if ((ending_trans(thd, all) && + (trans_has_updated_non_trans_table(thd) || + (thd->options & OPTION_KEEP_LOG))) || + (trans_has_no_stmt_committed(thd, all) && + stmt_has_updated_non_trans_table(thd) && + thd->current_stmt_binlog_row_based)) { Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0); error= binlog_end_trans(thd, trx_data, &qev, all); @@ -1671,8 +1654,8 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) Otherwise, we simply truncate the cache as there is no change on non-transactional tables as follows. */ - else if ((all && !thd->transaction.all.modified_non_trans_table) || - (!all && !thd->transaction.stmt.modified_non_trans_table)) + else if (ending_trans(thd, all) || + (!(thd->options & OPTION_KEEP_LOG) && !stmt_has_updated_non_trans_table(thd))) error= binlog_end_trans(thd, trx_data, 0, all); } if (!all) @@ -1680,6 +1663,19 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) DBUG_RETURN(error); } +/** + Cleanup the cache. + + @param thd The client thread that wants to clean up the cache. +*/ +void MYSQL_BIN_LOG::reset_gathered_updates(THD *thd) +{ + binlog_trx_data *const trx_data= + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + + trx_data->reset(); +} + void MYSQL_BIN_LOG::set_write_error(THD *thd) { DBUG_ENTER("MYSQL_BIN_LOG::set_write_error"); @@ -1769,7 +1765,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ - if (unlikely(thd->transaction.all.modified_non_trans_table || + if (unlikely(trans_has_updated_non_trans_table(thd) || (thd->options & OPTION_KEEP_LOG))) { String log_query; @@ -1788,17 +1784,17 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) int check_binlog_magic(IO_CACHE* log, const char** errmsg) { - char magic[4]; + uchar magic[4]; DBUG_ASSERT(my_b_tell(log) == 0); - if (my_b_read(log, (uchar*) magic, sizeof(magic))) + if (my_b_read(log, magic, sizeof(magic))) { *errmsg = "I/O error reading the header from the binary log"; sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno, log->error); return 1; } - if (memcmp(magic, BINLOG_MAGIC, sizeof(magic))) + if (bcmp(magic, BINLOG_MAGIC, sizeof(magic))) { *errmsg = "Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL"; return 1; @@ -1915,7 +1911,7 @@ static int find_uniq_filename(char *name) file_info= dir_info->dir_entry; for (i=dir_info->number_off_files ; i-- ; file_info++) { - if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 && + if (memcmp(file_info->name, start, length) == 0 && test_if_number(file_info->name+length, &number,0)) { set_if_bigger(max_found,(ulong) number); @@ -2493,7 +2489,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name, MYSQL_BIN_LOG::MYSQL_BIN_LOG() :bytes_written(0), prepared_xids(0), file_id(1), open_count(1), - need_start_event(TRUE), m_table_map_version(0), + need_start_event(TRUE), is_relay_log(0), description_event_for_exec(0), description_event_for_queue(0) { @@ -2693,7 +2689,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, an extension for the binary log files. In this case we write a standard header to it. */ - if (my_b_safe_write(&log_file, (uchar*) BINLOG_MAGIC, + if (my_b_safe_write(&log_file, BINLOG_MAGIC, BIN_LOG_HEADER_SIZE)) goto err; bytes_written+= BIN_LOG_HEADER_SIZE; @@ -4007,6 +4003,67 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) query_id_param >= thd->binlog_evt_union.first_query_id); } +/** + This function checks if a transaction, either a multi-statement + or a single statement transaction is about to commit or not. + + @param thd The client thread that executed the current statement. + @param all Committing a transaction (i.e. TRUE) or a statement + (i.e. FALSE). + @return + @c true if committing a transaction, otherwise @c false. +*/ +bool ending_trans(const THD* thd, const bool all) +{ + return (all || (!all && !(thd->options & + (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))); +} + +/** + This function checks if a non-transactional table was updated by + the current transaction. + + @param thd The client thread that executed the current statement. + @return + @c true if a non-transactional table was updated, @c false + otherwise. +*/ +bool trans_has_updated_non_trans_table(const THD* thd) +{ + return (thd->transaction.all.modified_non_trans_table || + thd->transaction.stmt.modified_non_trans_table); +} + +/** + This function checks if any statement was committed and cached. + + @param thd The client thread that executed the current statement. + @param all Committing a transaction (i.e. TRUE) or a statement + (i.e. FALSE). + @return + @c true if at a statement was committed and cached, @c false + otherwise. +*/ +bool trans_has_no_stmt_committed(const THD* thd, bool all) +{ + binlog_trx_data *const trx_data= + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + + return (!all && !trx_data->at_least_one_stmt_committed); +} + +/** + This function checks if a non-transactional table was updated by the + current statement. + + @param thd The client thread that executed the current statement. + @return + @c true if a non-transactional table was updated, @c false otherwise. +*/ +bool stmt_has_updated_non_trans_table(const THD* thd) +{ + return (thd->transaction.stmt.modified_non_trans_table); +} /* These functions are placed in this file since they need access to @@ -4139,7 +4196,6 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) DBUG_RETURN(error); binlog_table_maps++; - table->s->table_map_version= mysql_bin_log.table_map_version(); DBUG_RETURN(0); } @@ -4230,10 +4286,8 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, file= &trx_data->trans_log; /* - If we are writing to the log file directly, we could avoid - locking the log. This does not work since we need to step the - m_table_map_version below, and that change has to be protected - by the LOCK_log mutex. + If we are not writing to the log file directly, we could avoid + locking the log. */ pthread_mutex_lock(&LOCK_log); @@ -4247,24 +4301,6 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, DBUG_RETURN(1); } - /* - We step the table map version if we are writing an event - representing the end of a statement. We do this regardless of - wheather we write to the transaction cache or to directly to the - file. - - In an ideal world, we could avoid stepping the table map version - if we were writing to a transaction cache, since we could then - reuse the table map that was written earlier in the transaction - cache. This does not work since STMT_END_F implies closing all - table mappings on the slave side. - - TODO: Find a solution so that table maps does not have to be - written several times within a transaction. - */ - if (pending->get_flags(Rows_log_event::STMT_END_F)) - ++m_table_map_version; - delete pending; if (file == &log_file) @@ -4480,9 +4516,6 @@ err: set_write_error(thd); } - if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F) - ++m_table_map_version; - pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(error); } @@ -5106,6 +5139,22 @@ void sql_perror(const char *message) } +/* + Unfortunately, there seems to be no good way + to restore the original streams upon failure. +*/ +static bool redirect_std_streams(const char *file) +{ + if (freopen(file, "a+", stdout) && freopen(file, "a+", stderr)) + { + setbuf(stderr, NULL); + return FALSE; + } + + return TRUE; +} + + bool flush_error_log() { bool result=0; @@ -5134,11 +5183,7 @@ bool flush_error_log() setbuf(stderr, NULL); (void) my_delete(err_renamed, MYF(0)); my_rename(log_error_file,err_renamed,MYF(0)); - if (freopen(log_error_file,"a+",stdout)) - { - freopen(log_error_file,"a+",stderr); - setbuf(stderr, NULL); - } + redirect_std_streams(log_error_file); if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0) { @@ -5153,13 +5198,7 @@ bool flush_error_log() result= 1; #else my_rename(log_error_file,err_renamed,MYF(0)); - if (freopen(log_error_file,"a+",stdout)) - { - FILE *reopen; - reopen= freopen(log_error_file,"a+",stderr); - setbuf(stderr, NULL); - } - else + if (redirect_std_streams(log_error_file)) result= 1; #endif VOID(pthread_mutex_unlock(&LOCK_error_log)); @@ -5210,25 +5249,9 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, #endif /* __NT__ */ -/** - Prints a printf style message to the error log and, under NT, to the - Windows event log. - - This function prints the message into a buffer and then sends that buffer - to other functions to write that message to other logging sources. - - @param event_type Type of event to write (Error, Warning, or Info) - @param format Printf style format of message - @param args va_list list of arguments for the message - - @returns - The function always returns 0. The return value is present in the - signature to be compatible with other logging routines, which could - return an error (e.g. logging to the log tables) -*/ - #ifndef EMBEDDED_LIBRARY -static void print_buffer_to_file(enum loglevel level, const char *buffer) +static void print_buffer_to_file(enum loglevel level, const char *buffer, + size_t length) { time_t skr; struct tm tm_tmp; @@ -5242,7 +5265,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) localtime_r(&skr, &tm_tmp); start=&tm_tmp; - fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n", + fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %.*s\n", start->tm_year % 100, start->tm_mon+1, start->tm_mday, @@ -5251,7 +5274,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) start->tm_sec, (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ? "Warning" : "Note"), - buffer); + (int) length, buffer); fflush(stderr); @@ -5259,17 +5282,30 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) DBUG_VOID_RETURN; } +/** + Prints a printf style message to the error log and, under NT, to the + Windows event log. + + This function prints the message into a buffer and then sends that buffer + to other functions to write that message to other logging sources. + @param level The level of the msg significance + @param format Printf style format of message + @param args va_list list of arguments for the message + + @returns + The function always returns 0. The return value is present in the + signature to be compatible with other logging routines, which could + return an error (e.g. logging to the log tables) +*/ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) { char buff[1024]; + size_t length; DBUG_ENTER("vprint_msg_to_log"); -#ifdef __NT__ - size_t length= -#endif - my_vsnprintf(buff, sizeof(buff), format, args); - print_buffer_to_file(level, buff); + length= my_vsnprintf(buff, sizeof(buff), format, args); + print_buffer_to_file(level, buff, length); #ifdef __NT__ print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff)); @@ -5277,7 +5313,7 @@ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) DBUG_RETURN(0); } -#endif /*EMBEDDED_LIBRARY*/ +#endif /* EMBEDDED_LIBRARY */ void sql_print_error(const char *format, ...) @@ -5322,39 +5358,39 @@ void sql_print_information(const char *format, ...) /********* transaction coordinator log for 2pc - mmap() based solution *******/ /* - the log consists of a file, mmapped to a memory. - file is divided on pages of tc_log_page_size size. - (usable size of the first page is smaller because of log header) - there's PAGE control structure for each page - each page (or rather PAGE control structure) can be in one of three - states - active, syncing, pool. - there could be only one page in active or syncing states, - but many in pool - pool is fifo queue. - usual lifecycle of a page is pool->active->syncing->pool - "active" page - is a page where new xid's are logged. - the page stays active as long as syncing slot is taken. - "syncing" page is being synced to disk. no new xid can be added to it. - when the sync is done the page is moved to a pool and an active page + the log consists of a file, mapped to memory. + file is divided into pages of tc_log_page_size size. + (usable size of the first page is smaller because of the log header) + there is a PAGE control structure for each page + each page (or rather its PAGE control structure) can be in one of + the three states - active, syncing, pool. + there could be only one page in the active or syncing state, + but many in pool - pool is a fifo queue. + the usual lifecycle of a page is pool->active->syncing->pool. + the "active" page is a page where new xid's are logged. + the page stays active as long as the syncing slot is taken. + the "syncing" page is being synced to disk. no new xid can be added to it. + when the syncing is done the page is moved to a pool and an active page becomes "syncing". the result of such an architecture is a natural "commit grouping" - If commits are coming faster than the system can sync, they do not - stall. Instead, all commit that came since the last sync are - logged to the same page, and they all are synced with the next - + stall. Instead, all commits that came since the last sync are + logged to the same "active" page, and they all are synced with the next - one - sync. Thus, thought individual commits are delayed, throughput is not decreasing. - when a xid is added to an active page, the thread of this xid waits + when an xid is added to an active page, the thread of this xid waits for a page's condition until the page is synced. when syncing slot becomes vacant one of these waiters is awaken to take care of syncing. it syncs the page and signals all waiters that the page is synced. PAGE::waiters is used to count these waiters, and a page may never become active again until waiters==0 (that is all waiters from the - previous sync have noticed the sync was completed) + previous sync have noticed that the sync was completed) note, that the page becomes "dirty" and has to be synced only when a new xid is added into it. Removing a xid from a page does not make it - dirty - we don't sync removals to disk. + dirty - we don't sync xid removals to disk. */ ulong tc_log_page_waits= 0; @@ -5363,7 +5399,7 @@ ulong tc_log_page_waits= 0; #define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1) -static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74}; +static const uchar tc_log_magic[]={(uchar) 254, 0x23, 0x05, 0x74}; ulong opt_tc_log_size= TC_LOG_MIN_SIZE; ulong tc_log_max_pages_used=0, tc_log_page_size=0, tc_log_cur_pages_used=0; @@ -5420,7 +5456,8 @@ int TC_LOG_MMAP::open(const char *opt_name) inited=2; npages=(uint)file_length/tc_log_page_size; - DBUG_ASSERT(npages >= 3); // to guarantee non-empty pool + if (npages < 3) // to guarantee non-empty pool + goto err; if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL)))) goto err; inited=3; @@ -5477,7 +5514,7 @@ err: -# if there're waiters - take the one with the most free space. @todo - TODO page merging. try to allocate adjacent page first, + page merging. try to allocate adjacent page first, so that they can be flushed both in one sync */ @@ -5486,8 +5523,7 @@ void TC_LOG_MMAP::get_active_from_pool() PAGE **p, **best_p=0; int best_free; - if (syncing) - pthread_mutex_lock(&LOCK_pool); + pthread_mutex_lock(&LOCK_pool); do { @@ -5507,20 +5543,21 @@ void TC_LOG_MMAP::get_active_from_pool() } while ((*best_p == 0 || best_free == 0) && overflow()); + safe_mutex_assert_owner(&LOCK_active); active=*best_p; - if (active->free == active->size) // we've chosen an empty page - { - tc_log_cur_pages_used++; - set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used); - } if ((*best_p)->next) // unlink the page from the pool *best_p=(*best_p)->next; else pool_last=*best_p; + pthread_mutex_unlock(&LOCK_pool); - if (syncing) - pthread_mutex_unlock(&LOCK_pool); + pthread_mutex_lock(&active->lock); + if (active->free == active->size) // we've chosen an empty page + { + tc_log_cur_pages_used++; + set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used); + } } /** @@ -5575,7 +5612,7 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) pthread_mutex_lock(&LOCK_active); /* - if active page is full - just wait... + if the active page is full - just wait... frankly speaking, active->free here accessed outside of mutex protection, but it's safe, because it only means we may miss an unlog() for the active page, and we're not waiting for it here - @@ -5587,9 +5624,17 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) /* no active page ? take one from the pool */ if (active == 0) get_active_from_pool(); + else + pthread_mutex_lock(&active->lock); p=active; - pthread_mutex_lock(&p->lock); + + /* + p->free is always > 0 here because to decrease it one needs + to take p->lock and before it one needs to take LOCK_active. + But checked that active->free > 0 under LOCK_active and + haven't release it ever since + */ /* searching for an empty slot */ while (*p->ptr) @@ -5603,38 +5648,51 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) *p->ptr++= xid; p->free--; p->state= DIRTY; - - /* to sync or not to sync - this is the question */ - pthread_mutex_unlock(&LOCK_active); - pthread_mutex_lock(&LOCK_sync); pthread_mutex_unlock(&p->lock); + pthread_mutex_lock(&LOCK_sync); if (syncing) { // somebody's syncing. let's wait + pthread_mutex_unlock(&LOCK_active); + pthread_mutex_lock(&p->lock); p->waiters++; - /* - note - it must be while (), not do ... while () here - as p->state may be not DIRTY when we come here - */ - while (p->state == DIRTY && syncing) + for (;;) + { + int not_dirty = p->state != DIRTY; + pthread_mutex_unlock(&p->lock); + if (not_dirty || !syncing) + break; pthread_cond_wait(&p->cond, &LOCK_sync); + pthread_mutex_lock(&p->lock); + } p->waiters--; err= p->state == ERROR; if (p->state != DIRTY) // page was synced { + pthread_mutex_unlock(&LOCK_sync); if (p->waiters == 0) pthread_cond_signal(&COND_pool); // in case somebody's waiting - pthread_mutex_unlock(&LOCK_sync); + pthread_mutex_unlock(&p->lock); goto done; // we're done } - } // page was not synced! do it now - DBUG_ASSERT(active == p && syncing == 0); - pthread_mutex_lock(&LOCK_active); - syncing=p; // place is vacant - take it - active=0; // page is not active anymore - pthread_cond_broadcast(&COND_active); // in case somebody's waiting - pthread_mutex_unlock(&LOCK_active); - pthread_mutex_unlock(&LOCK_sync); + DBUG_ASSERT(!syncing); + pthread_mutex_unlock(&p->lock); + syncing = p; + pthread_mutex_unlock(&LOCK_sync); + + pthread_mutex_lock(&LOCK_active); + active=0; // page is not active anymore + pthread_cond_broadcast(&COND_active); + pthread_mutex_unlock(&LOCK_active); + } + else + { + syncing = p; // place is vacant - take it + pthread_mutex_unlock(&LOCK_sync); + active = 0; // page is not active anymore + pthread_cond_broadcast(&COND_active); + pthread_mutex_unlock(&LOCK_active); + } err= sync(); done: @@ -5651,7 +5709,7 @@ int TC_LOG_MMAP::sync() sit down and relax - this can take a while... note - no locks are held at this point */ - err= my_msync(fd, syncing->start, 1, MS_SYNC); + err= my_msync(fd, syncing->start, syncing->size * sizeof(my_xid), MS_SYNC); /* page is synced. let's move it to the pool */ pthread_mutex_lock(&LOCK_pool); @@ -5659,19 +5717,20 @@ int TC_LOG_MMAP::sync() pool_last=syncing; syncing->next=0; syncing->state= err ? ERROR : POOL; - pthread_cond_broadcast(&syncing->cond); // signal "sync done" pthread_cond_signal(&COND_pool); // in case somebody's waiting pthread_mutex_unlock(&LOCK_pool); /* marking 'syncing' slot free */ pthread_mutex_lock(&LOCK_sync); + pthread_cond_broadcast(&syncing->cond); // signal "sync done" syncing=0; /* we check the "active" pointer without LOCK_active. Still, it's safe - "active" can change from NULL to not NULL any time, but it will take LOCK_sync before waiting on active->cond. That is, it can never miss a signal. - And "active" can change to NULL only after LOCK_sync, so this is safe too. + And "active" can change to NULL only by the syncing thread + (the thread that will send a signal below) */ if (active) pthread_cond_signal(&active->cond); // wake up a new syncer @@ -5691,13 +5750,13 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) DBUG_ASSERT(*x == xid); DBUG_ASSERT(x >= p->start && x < p->end); - *x=0; pthread_mutex_lock(&p->lock); + *x=0; p->free++; DBUG_ASSERT(p->free <= p->size); set_if_smaller(p->ptr, x); - if (p->free == p->size) // the page is completely empty + if (p->free == p->size) // the page is completely empty statistic_decrement(tc_log_cur_pages_used, &LOCK_status); if (p->waiters == 0) // the page is in pool and ready to rock pthread_cond_signal(&COND_pool); // ping ... for overflow() @@ -5740,7 +5799,7 @@ int TC_LOG_MMAP::recover() HASH xids; PAGE *p=pages, *end_p=pages+npages; - if (memcmp(data, tc_log_magic, sizeof(tc_log_magic))) + if (bcmp(data, tc_log_magic, sizeof(tc_log_magic))) { sql_print_error("Bad magic header in tc log"); goto err1; diff --git a/sql/log.h b/sql/log.h index c6cf8780c04..8ee94ab5807 100644 --- a/sql/log.h +++ b/sql/log.h @@ -20,6 +20,11 @@ class Relay_log_info; class Format_description_log_event; +bool ending_trans(const THD* thd, const bool all); +bool trans_has_updated_non_trans_table(const THD* thd); +bool trans_has_no_stmt_committed(const THD* thd, const bool all); +bool stmt_has_updated_non_trans_table(const THD* thd); + /* Transaction Coordinator log - a base abstract class for two different implementations @@ -272,8 +277,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG */ bool no_auto_events; - ulonglong m_table_map_version; - int write_to_file(IO_CACHE *cache); /* This is used to start writing to a new log file. The difference from @@ -314,14 +317,6 @@ public: void unlog(ulong cookie, my_xid xid); int recover(IO_CACHE *log, Format_description_log_event *fdle); #if !defined(MYSQL_CLIENT) - bool is_table_mapped(TABLE *table) const - { - return table->s->table_map_version == table_map_version(); - } - - ulonglong table_map_version() const { return m_table_map_version; } - void update_table_map_version() { ++m_table_map_version; } - int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event); int remove_pending_rows_event(THD *thd); @@ -361,10 +356,10 @@ public: /* Use this to start writing a new log file */ void new_file(); + void reset_gathered_updates(THD *thd); bool write(Log_event* event_info); // binary log write bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident); bool write_incident(THD *thd, bool lock); - int write_cache(THD *thd, IO_CACHE *cache, bool lock_log, bool flush_and_sync); void set_write_error(THD *thd); diff --git a/sql/log_event.cc b/sql/log_event.cc index 0a658719eca..fa7bb01077d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1673,7 +1673,7 @@ beg: precision, decimals); return bin_size; } - + case MYSQL_TYPE_FLOAT: { float fl; @@ -1716,14 +1716,13 @@ beg: case MYSQL_TYPE_DATETIME: { - /* these must be size_t, because it's what my_b_printf expects for %d */ - size_t d, t; + ulong d, t; uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */ - d= (size_t)(i64 / 1000000); - t= (size_t)(i64 % 1000000); + d= (ulong) (i64 / 1000000); + t= (ulong) (i64 % 1000000); my_b_printf(file, "%04d-%02d-%02d %02d:%02d:%02d", - d / 10000, (d % 10000) / 100, d % 100, - t / 10000, (t % 10000) / 100, t % 100); + (int) (d / 10000), (int) (d % 10000) / 100, (int) (d % 100), + (int) (t / 10000), (int) (t % 10000) / 100, (int) t % 100); my_snprintf(typestr, typestr_length, "DATETIME"); return 8; } @@ -2307,6 +2306,53 @@ bool Query_log_event::write(IO_CACHE* file) start+= 4; } + if (thd && thd->is_current_user_used()) + { + LEX_STRING user; + LEX_STRING host; + memset(&user, 0, sizeof(user)); + memset(&host, 0, sizeof(host)); + + if (thd->slave_thread && thd->has_invoker()) + { + /* user will be null, if master is older than this patch */ + user= thd->get_invoker_user(); + host= thd->get_invoker_host(); + } + else if (thd->security_ctx->priv_user) + { + Security_context *ctx= thd->security_ctx; + + user.length= strlen(ctx->priv_user); + user.str= ctx->priv_user; + if (ctx->priv_host[0] != '\0') + { + host.str= ctx->priv_host; + host.length= strlen(ctx->priv_host); + } + } + + if (user.length > 0) + { + *start++= Q_INVOKER; + + /* + Store user length and user. The max length of use is 16, so 1 byte is + enough to store the user's length. + */ + *start++= (uchar)user.length; + memcpy(start, user.str, user.length); + start+= user.length; + + /* + Store host length and host. The max length of host is 60, so 1 byte is + enough to store the host's length. + */ + *start++= (uchar)host.length; + memcpy(start, host.str, host.length); + start+= host.length; + } + } /* NOTE: When adding new status vars, please don't forget to update the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function @@ -2349,6 +2395,8 @@ bool Query_log_event::write(IO_CACHE* file) Query_log_event::Query_log_event() :Log_event(), data_buf(0) { + memset(&user, 0, sizeof(user)); + memset(&host, 0, sizeof(host)); } @@ -2391,6 +2439,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, { time_t end_time; + memset(&user, 0, sizeof(user)); + memset(&host, 0, sizeof(host)); + error_code= errcode; time(&end_time); @@ -2406,13 +2457,29 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, charset_database_number= thd_arg->variables.collation_database->number; /* - If we don't use flags2 for anything else than options contained in - thd_arg->options, it would be more efficient to flags2=thd_arg->options - (OPTIONS_WRITTEN_TO_BIN_LOG would be used only at reading time). - But it's likely that we don't want to use 32 bits for 3 bits; in the future - we will probably want to reclaim the 29 bits. So we need the &. + We only replicate over the bits of flags2 that we need: the rest + are masked out by "& OPTIONS_WRITTEN_TO_BINLOG". + + We also force AUTOCOMMIT=1. Rationale (cf. BUG#29288): After + fixing BUG#26395, we always write BEGIN and COMMIT around all + transactions (even single statements in autocommit mode). This is + so that replication from non-transactional to transactional table + and error recovery from XA to non-XA table should work as + expected. The BEGIN/COMMIT are added in log.cc. However, there is + one exception: MyISAM bypasses log.cc and writes directly to the + binlog. So if autocommit is off, master has MyISAM, and slave has + a transactional engine, then the slave will just see one long + never-ending transaction. The only way to bypass explicit + BEGIN/COMMIT in the binlog is by using a non-transactional table. + So setting AUTOCOMMIT=1 will make this work as expected. + + Note: explicitly replicate AUTOCOMMIT=1 from master. We do not + assume AUTOCOMMIT=1 on slave; the slave still reads the state of + the autocommit flag as written by the master to the binlog. This + behavior may change after WL#4162 has been implemented. */ - flags2= (uint32) (thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG); + flags2= (uint32) (thd_arg->options & + (OPTIONS_WRITTEN_TO_BIN_LOG & ~OPTION_NOT_AUTOCOMMIT)); DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256); DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256); DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256); @@ -2559,6 +2626,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, bool catalog_nz= 1; DBUG_ENTER("Query_log_event::Query_log_event(char*,...)"); + memset(&user, 0, sizeof(user)); + memset(&host, 0, sizeof(host)); common_header_len= description_event->common_header_len; post_header_len= description_event->post_header_len[event_type-1]; DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d", @@ -2713,6 +2782,20 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, data_written= master_data_written= uint4korr(pos); pos+= 4; break; + case Q_INVOKER: + { + CHECK_SPACE(pos, end, 1); + user.length= *pos++; + CHECK_SPACE(pos, end, user.length); + user.str= (char *)pos; + pos+= user.length; + + CHECK_SPACE(pos, end, 1); + host.length= *pos++; + CHECK_SPACE(pos, end, host.length); + host.str= (char *)pos; + pos+= host.length; + } 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\ @@ -2726,12 +2809,16 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, time_zone_len + 1 + data_len + 1 + QUERY_CACHE_FLAGS_SIZE + + user.length + 1 + + host.length + 1 + db_len + 1, MYF(MY_WME)))) #else if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + time_zone_len + 1 + - data_len + 1, + data_len + 1 + + user.length + 1 + + host.length + 1, MYF(MY_WME)))) #endif DBUG_VOID_RETURN; @@ -2754,6 +2841,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (time_zone_len) copy_str_and_move(&time_zone_str, &start, time_zone_len); + if (user.length > 0) + copy_str_and_move((const char **)&(user.str), &start, user.length); + if (host.length > 0) + copy_str_and_move((const char **)&(host.str), &start, host.length); + /** if time_zone_len or catalog_len are 0, then time_zone and catalog are uninitialized at this point. shouldn't they point to the @@ -2889,7 +2981,7 @@ void Query_log_event::print_query_header(IO_CACHE* file, if (likely(charset_inited) && (unlikely(!print_event_info->charset_inited || - bcmp((uchar*) print_event_info->charset, (uchar*) charset, 6)))) + memcmp(print_event_info->charset, charset, 6)))) { CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME)); if (cs_info) @@ -2912,8 +3004,8 @@ void Query_log_event::print_query_header(IO_CACHE* file, } if (time_zone_len) { - if (bcmp((uchar*) print_event_info->time_zone_str, - (uchar*) time_zone_str, time_zone_len+1)) + if (memcmp(print_event_info->time_zone_str, + time_zone_str, time_zone_len+1)) { my_b_printf(file,"SET @@session.time_zone='%s'%s\n", time_zone_str, print_event_info->delimiter); @@ -3162,7 +3254,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, thd->variables.collation_database= thd->db_charset; thd->table_map_for_update= (table_map)table_map_for_update; - + thd->set_invoker(&user, &host); /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon); @@ -5573,7 +5665,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) double real_val; char real_buf[FMT_G_BUFSIZE(14)]; float8get(real_val, val); - my_sprintf(real_buf, (real_buf, "%.14g", real_val)); + sprintf(real_buf, "%.14g", real_val); my_b_printf(&cache, ":=%s%s\n", real_buf, print_event_info->delimiter); break; case INT_RESULT: @@ -6142,7 +6234,7 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Create_file_log_event::pack_info(Protocol *protocol) { - char buf[NAME_LEN*2 + 30 + 21*2], *pos; + char buf[SAFE_NAME_LEN*2 + 30 + 21*2], *pos; pos= strmov(buf, "db="); memcpy(pos, db, db_len); pos= strmov(pos + db_len, ";table="); @@ -7490,8 +7582,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) { int actual_error= convert_handler_error(error, thd, table); bool idempotent_error= (idempotent_error_code(error) && - ((bit_is_set(slave_exec_mode, - SLAVE_EXEC_MODE_IDEMPOTENT)) == 1)); + (slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT)); bool ignored_error= (idempotent_error == 0 ? ignored_error_code(actual_error) : 0); @@ -7547,12 +7638,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); error= 0; } - - if (!cache_stmt) - { - DBUG_PRINT("info", ("Marked that we need to keep log")); - thd->options|= OPTION_KEEP_LOG; - } } // if (table) /* @@ -8430,7 +8515,7 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability todo: to introduce a property for the event (handler?) which forces applying the event in the replace (idempotent) fashion. */ - if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1 || + if ((slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT) || m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER) { /* @@ -8509,7 +8594,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * int local_error= 0; m_table->next_number_field=0; m_table->auto_increment_field_not_null= FALSE; - if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1 || + if ((slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT) || m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER) { m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); @@ -8522,7 +8607,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * ultimately. Still todo: fix */ } - if ((local_error= m_table->file->ha_end_bulk_insert(0))) + if ((local_error= m_table->file->ha_end_bulk_insert())) { m_table->file->print_error(local_error, MYF(0)); } @@ -8612,7 +8697,7 @@ Rows_log_event::write_row(const Relay_log_info *const rli, TABLE *table= m_table; // pointer to event's table int error; - int keynum; + int UNINIT_VAR(keynum); auto_afree_ptr<char> key(NULL); /* fill table->record[0] with default values */ @@ -8810,10 +8895,8 @@ int Write_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); - int error= - write_row(rli, /* if 1 then overwrite */ - bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1); - + int error= write_row(rli, (slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT)); + if (error && !thd->is_error()) { DBUG_ASSERT(0); @@ -8866,11 +8949,28 @@ static bool record_compare(TABLE *table) { for (int i = 0 ; i < 2 ; ++i) { - saved_x[i]= table->record[i][0]; - saved_filler[i]= table->record[i][table->s->null_bytes - 1]; - table->record[i][0]|= 1U; - table->record[i][table->s->null_bytes - 1]|= - 256U - (1U << table->s->last_null_bit_pos); + /* + If we have an X bit then we need to take care of it. + */ + if (!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD)) + { + saved_x[i]= table->record[i][0]; + table->record[i][0]|= 1U; + } + + /* + If (last_null_bit_pos == 0 && null_bytes > 1), then: + + X bit (if any) + N nullable fields + M Field_bit fields = 8 bits + + Ie, the entire byte is used. + */ + if (table->s->last_null_bit_pos > 0) + { + saved_filler[i]= table->record[i][table->s->null_bytes - 1]; + table->record[i][table->s->null_bytes - 1]|= + 256U - (1U << table->s->last_null_bit_pos); + } } } @@ -8910,8 +9010,11 @@ record_compare_exit: { for (int i = 0 ; i < 2 ; ++i) { - table->record[i][0]= saved_x[i]; - table->record[i][table->s->null_bytes - 1]= saved_filler[i]; + if (!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD)) + table->record[i][0]= saved_x[i]; + + if (table->s->last_null_bit_pos) + table->record[i][table->s->null_bytes - 1]= saved_filler[i]; } } @@ -8921,10 +9024,10 @@ record_compare_exit: /** Locate the current row in event's table. - The current row is pointed by @c m_curr_row. Member @c m_width tells how many - columns are there in the row (this can be differnet from the number of columns - in the table). It is assumed that event's table is already open and pointed - by @c m_table. + The current row is pointed by @c m_curr_row. Member @c m_width tells + how many columns are there in the row (this can be differnet from + the number of columns in the table). It is assumed that event's + table is already open and pointed by @c m_table. If a corresponding record is found in the table it is stored in @c m_table->record[0]. Note that when record is located based on a primary @@ -9088,8 +9191,35 @@ int Rows_log_event::find_row(const Relay_log_info *rli) */ if (table->key_info->flags & HA_NOSAME) { - table->file->ha_index_end(); - goto ok; + /* Unique does not have non nullable part */ + if (!(table->key_info->flags & (HA_NULL_PART_KEY))) + { + table->file->ha_index_end(); + goto ok; + } + else + { + KEY *keyinfo= table->key_info; + /* + Unique has nullable part. We need to check if there is any field in the + BI image that is null and part of UNNI. + */ + bool null_found= FALSE; + for (uint i=0; i < keyinfo->key_parts && !null_found; i++) + { + uint fieldnr= keyinfo->key_part[i].fieldnr - 1; + Field **f= table->field+fieldnr; + null_found= (*f)->is_null(); + } + + if (!null_found) + { + table->file->ha_index_end(); + goto ok; + } + + /* else fall through to index scan */ + } } /* @@ -9140,11 +9270,10 @@ int Rows_log_event::find_row(const Relay_log_info *rli) int restart_count= 0; // Number of times scanning has restarted from top /* We don't have a key: search the table using rnd_next() */ - if ((error= table->file->ha_rnd_init(1))) + if ((error= table->file->ha_rnd_init_with_error(1))) { DBUG_PRINT("info",("error initializing table scan" " (ha_rnd_init returns %d)",error)); - table->file->print_error(error, MYF(0)); goto err; } @@ -9169,7 +9298,14 @@ int Rows_log_event::find_row(const Relay_log_info *rli) case HA_ERR_END_OF_FILE: if (++restart_count < 2) - table->file->ha_rnd_init(1); + { + int error2; + if ((error2= table->file->ha_rnd_init_with_error(1))) + { + error= error2; + goto err; + } + } break; default: diff --git a/sql/log_event.h b/sql/log_event.h index db3950e6c25..3c7ba766545 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -264,7 +264,8 @@ struct sql_ex_info 1 + 2 /* type, lc_time_names_number */ + \ 1 + 2 /* type, charset_database_number */ + \ 1 + 8 /* type, table_map_for_update */ + \ - 1 + 4 /* type, master_data_written */) + 1 + 4 /* type, master_data_written */ + \ + 1 + 16 + 1 + 60/* type, user_len, user, host_len, host */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -333,6 +334,8 @@ struct sql_ex_info #define Q_MASTER_DATA_WRITTEN_CODE 10 +#define Q_INVOKER 11 + /* Intvar event post-header */ /* Intvar event data */ @@ -395,7 +398,7 @@ struct sql_ex_info #define ELQ_DUP_HANDLING_OFFSET ELQ_FILE_ID_OFFSET + 12 /* 4 bytes which all binlogs should begin with */ -#define BINLOG_MAGIC "\xfe\x62\x69\x6e" +#define BINLOG_MAGIC (const uchar*) "\xfe\x62\x69\x6e" /* The 2 flags below were useless : @@ -463,10 +466,10 @@ struct sql_ex_info #define LOG_EVENT_SUPPRESS_USE_F 0x8 /* - The table map version internal to the log should be increased after - the event has been written to the binary log. + Note: this is a place holder for the flag + LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F (0x10), which is not used any + more, please do not reused this value for other flags. */ -#define LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F 0x10 /** @def LOG_EVENT_ARTIFICIAL_F @@ -1558,6 +1561,8 @@ protected: */ class Query_log_event: public Log_event { + LEX_STRING user; + LEX_STRING host; protected: Log_event::Byte* data_buf; public: diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index cf358bd757d..5d3ab1f17d5 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -229,11 +229,6 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event", const_cast<Relay_log_info*>(rli)->abort_slave= 1;); error= do_after_row_operations(table, error); - if (!ev->cache_stmt) - { - DBUG_PRINT("info", ("Marked that we need to keep log")); - ev_thd->options|= OPTION_KEEP_LOG; - } } /* @@ -342,12 +337,29 @@ static bool record_compare(TABLE *table) if (table->s->null_bytes > 0) { for (int i = 0 ; i < 2 ; ++i) - { - saved_x[i]= table->record[i][0]; - saved_filler[i]= table->record[i][table->s->null_bytes - 1]; - table->record[i][0]|= 1U; - table->record[i][table->s->null_bytes - 1]|= - 256U - (1U << table->s->last_null_bit_pos); + { + /* + If we have an X bit then we need to take care of it. + */ + if (!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD)) + { + saved_x[i]= table->record[i][0]; + table->record[i][0]|= 1U; + } + + /* + If (last_null_bit_pos == 0 && null_bytes > 1), then: + + X bit (if any) + N nullable fields + M Field_bit fields = 8 bits + + Ie, the entire byte is used. + */ + if (table->s->last_null_bit_pos > 0) + { + saved_filler[i]= table->record[i][table->s->null_bytes - 1]; + table->record[i][table->s->null_bytes - 1]|= + 256U - (1U << table->s->last_null_bit_pos); + } } } @@ -387,8 +399,11 @@ record_compare_exit: { for (int i = 0 ; i < 2 ; ++i) { - table->record[i][0]= saved_x[i]; - table->record[i][table->s->null_bytes - 1]= saved_filler[i]; + if (!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD)) + table->record[i][0]= saved_x[i]; + + if (table->s->last_null_bit_pos > 0) + table->record[i][table->s->null_bytes - 1]= saved_filler[i]; } } @@ -426,7 +441,7 @@ copy_extra_record_fields(TABLE *table, DBUG_ASSERT(master_reclength <= table->s->reclength); if (master_reclength < table->s->reclength) - bmove_align(table->record[0] + master_reclength, + memcpy(table->record[0] + master_reclength, table->record[1] + master_reclength, table->s->reclength - master_reclength); @@ -705,7 +720,7 @@ static int find_and_fetch_row(TABLE *table, uchar *key) rnd_pos() returns the record in table->record[0], so we have to move it to table->record[1]. */ - bmove_align(table->record[1], table->record[0], table->s->reclength); + memcpy(table->record[1], table->record[0], table->s->reclength); DBUG_RETURN(error); } @@ -816,7 +831,7 @@ static int find_and_fetch_row(TABLE *table, uchar *key) int error; /* We don't have a key: search the table using rnd_next() */ - if ((error= table->file->ha_rnd_init(1))) + if ((error= table->file->ha_rnd_init_with_error(1))) return error; /* Continue until we find the right record or have made a full loop */ @@ -840,15 +855,19 @@ static int find_and_fetch_row(TABLE *table, uchar *key) goto restart_rnd_next; case HA_ERR_END_OF_FILE: - if (++restart_count < 2) - table->file->ha_rnd_init(1); - break; + if (++restart_count < 2) + { + int error2; + if ((error2= table->file->ha_rnd_init_with_error(1))) + DBUG_RETURN(error2); + } + break; default: - table->file->print_error(error, MYF(0)); + table->file->print_error(error, MYF(0)); DBUG_PRINT("info", ("Record not found")); table->file->ha_rnd_end(); - DBUG_RETURN(error); + DBUG_RETURN(error); } } while (restart_count < 2 && record_compare(table)); @@ -944,7 +963,7 @@ int Write_rows_log_event_old::do_after_row_operations(TABLE *table, int error) fires bug#27077 todo: explain or fix */ - if ((local_error= table->file->ha_end_bulk_insert(0))) + if ((local_error= table->file->ha_end_bulk_insert())) { table->file->print_error(local_error, MYF(0)); } @@ -1199,7 +1218,7 @@ int Update_rows_log_event_old::do_exec_row(TABLE *table) overwriting the default values that where put there by the unpack_row() function. */ - bmove_align(table->record[0], m_after_image, table->s->reclength); + memcpy(table->record[0], m_after_image, table->s->reclength); copy_extra_record_fields(table, m_master_reclength, m_width); /* @@ -1756,11 +1775,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event", const_cast<Relay_log_info*>(rli)->abort_slave= 1;); error= do_after_row_operations(rli, error); - if (!cache_stmt) - { - DBUG_PRINT("info", ("Marked that we need to keep log")); - thd->options|= OPTION_KEEP_LOG; - } } // if (table) /* @@ -2409,8 +2423,35 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) */ if (table->key_info->flags & HA_NOSAME) { - table->file->ha_index_end(); - DBUG_RETURN(0); + /* Unique does not have non nullable part */ + if (!(table->key_info->flags & (HA_NULL_PART_KEY))) + { + table->file->ha_index_end(); + DBUG_RETURN(0); + } + else + { + KEY *keyinfo= table->key_info; + /* + Unique has nullable part. We need to check if there is any field in the + BI image that is null and part of UNNI. + */ + bool null_found= FALSE; + for (uint i=0; i < keyinfo->key_parts && !null_found; i++) + { + uint fieldnr= keyinfo->key_part[i].fieldnr - 1; + Field **f= table->field+fieldnr; + null_found= (*f)->is_null(); + } + + if (!null_found) + { + table->file->ha_index_end(); + DBUG_RETURN(0); + } + + /* else fall through to index scan */ + } } /* @@ -2461,11 +2502,10 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) int restart_count= 0; // Number of times scanning has restarted from top /* We don't have a key: search the table using rnd_next() */ - if ((error= table->file->ha_rnd_init(1))) + if ((error= table->file->ha_rnd_init_with_error(1))) { DBUG_PRINT("info",("error initializing table scan" " (ha_rnd_init returns %d)",error)); - table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -2485,7 +2525,11 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) case HA_ERR_END_OF_FILE: if (++restart_count < 2) - table->file->ha_rnd_init(1); + { + int error2; + if ((error2= table->file->ha_rnd_init_with_error(1))) + DBUG_RETURN(error2); + } break; default: @@ -2637,7 +2681,7 @@ Write_rows_log_event_old::do_after_row_operations(const Slave_reporting_capabili fires bug#27077 todo: explain or fix */ - if ((local_error= m_table->file->ha_end_bulk_insert(0))) + if ((local_error= m_table->file->ha_end_bulk_insert())) { m_table->file->print_error(local_error, MYF(0)); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ba60bab9b50..84c07dbf2b3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -702,49 +702,6 @@ enum enum_check_fields CHECK_FIELD_ERROR_FOR_NULL }; - -/** Struct to handle simple linked lists. */ -typedef struct st_sql_list { - uint elements; - uchar *first; - uchar **next; - - st_sql_list() {} /* Remove gcc warning */ - inline void empty() - { - elements=0; - first=0; - next= &first; - } - inline void link_in_list(uchar *element,uchar **next_ptr) - { - elements++; - (*next)=element; - next= next_ptr; - *next=0; - } - inline void save_and_clear(struct st_sql_list *save) - { - *save= *this; - empty(); - } - inline void push_front(struct st_sql_list *save) - { - *save->next= first; /* link current list last */ - first= save->first; - elements+= save->elements; - } - inline void push_back(struct st_sql_list *save) - { - if (save->first) - { - *next= save->first; - next= save->next; - elements+= save->elements; - } - } -} SQL_LIST; - #if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32) extern "C" THD *_current_thd_noinline(); #define _current_thd() _current_thd_noinline() @@ -1132,7 +1089,7 @@ bool mysql_opt_change_db(THD *thd, bool force_switch, bool *cur_db_changed); -void mysql_parse(THD *thd, const char *inBuf, uint length, +void mysql_parse(THD *thd, char *rawbuf, uint length, const char ** semicolon); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); @@ -1342,7 +1299,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, void prepare_triggers_for_insert_stmt(TABLE *table); int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_LIST *order, ha_rows rows, ulonglong options, + SQL_I_List<ORDER> *order, ha_rows rows, ulonglong options, bool reset_auto_increment); bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); @@ -1368,7 +1325,8 @@ bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last, TABLE_LIST *new_child_list, TABLE_LIST **new_last); bool reopen_table(TABLE *table); bool reopen_tables(THD *thd,bool get_locks,bool in_refresh); -thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table); +thr_lock_type read_lock_type_for_table(THD *thd, LEX *lex, + TABLE_LIST *table_list); void close_data_files_and_morph_locks(THD *thd, const char *db, const char *table_name); void close_handle_and_leave_table_as_lock(TABLE *table); @@ -1402,7 +1360,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, bool allow_rowid, uint *cached_field_index_ptr); Field * find_field_in_table_sef(TABLE *table, const char *name); -int update_virtual_fields(TABLE *table, bool ignore_stored= FALSE); +int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE); #endif /* MYSQL_SERVER */ @@ -1545,7 +1503,7 @@ Create_field * new_create_field(THD *thd, char *field_name, enum_field_types typ uint uint_geom_type, Virtual_column_info *vcol_info); void store_position_for_column(const char *name); -bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc); +bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *group,bool asc); bool push_new_name_resolution_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op); @@ -1820,7 +1778,7 @@ extern pthread_mutex_t LOCK_gdl; #define WFRM_PACK_FRM 4 #define WFRM_KEEP_SHARE 8 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); +int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); @@ -2091,6 +2049,7 @@ extern bool volatile abort_loop, shutdown_in_progress; extern bool in_bootstrap; extern uint volatile thread_count, thread_running, global_read_lock; extern ulong thread_created; +extern uint thread_handling; extern uint connection_count, extra_connection_count; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; @@ -2341,7 +2300,7 @@ longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(uchar *,uint,char,char); -void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, +bool init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors, bool disable_rr_cache); void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, @@ -2382,6 +2341,7 @@ char *fn_rext(char *name); /* Conversion functions */ #endif /* MYSQL_SERVER */ + #if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS uint strconvert(CHARSET_INFO *from_cs, const char *from, CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors); @@ -2398,6 +2358,7 @@ uint explain_filename(THD* thd, const char *from, char *to, uint to_length, uint filename_to_tablename(const char *from, char *to, uint to_length); uint tablename_to_filename(const char *from, char *to, uint to_length); uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length); +bool check_mysql50_prefix(const char *name); #endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */ #ifdef MYSQL_SERVER uint build_table_filename(char *buff, size_t bufflen, const char *db, @@ -2405,9 +2366,6 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db, const char *get_canonical_filename(handler *file, const char *path, char *tmp_path); -#define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" -#define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9 - uint build_table_shadow_filename(char *buff, size_t bufflen, ALTER_PARTITION_PARAM_TYPE *lpt); /* Flags for conversion functions. */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1593a584454..627827b39be 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -181,6 +181,21 @@ typedef fp_except fp_except_t; /* for IRIX to use set_fpc_csr() */ #include <sys/fpu.h> #endif +#ifdef HAVE_FPU_CONTROL_H +#include <fpu_control.h> +#endif +#if defined(__i386__) && !defined(HAVE_FPU_CONTROL_H) +# define fpu_control_t unsigned int +# define _FPU_EXTENDED 0x300 +# define _FPU_DOUBLE 0x200 +# if defined(__GNUC__) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) +# define _FPU_GETCW(cw) asm volatile ("fnstcw %0" : "=m" (*&cw)) +# define _FPU_SETCW(cw) asm volatile ("fldcw %0" : : "m" (*&cw)) +# else +# define _FPU_GETCW(cw) (cw= 0) +# define _FPU_SETCW(cw) +# endif +#endif inline void setup_fpu() { @@ -202,7 +217,26 @@ inline void setup_fpu() /* Set FPU rounding mode to "round-to-nearest" */ fesetround(FE_TONEAREST); #endif /* HAVE_FESETROUND */ - + + /* + x86 (32-bit) requires FPU precision to be explicitly set to 64 bit + (double precision) for portable results of floating point operations. + However, there is no need to do so if compiler is using SSE2 for floating + point, double values will be stored and processed in 64 bits anyway. + */ +#if defined(__i386__) && !defined(__SSE2_MATH__) +#if defined(_WIN32) +#if !defined(_WIN64) + _control87(_PC_53, MCW_PC); +#endif /* !_WIN64 */ +#else /* !_WIN32 */ + fpu_control_t cw; + _FPU_GETCW(cw); + cw= (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE; + _FPU_SETCW(cw); +#endif /* _WIN32 && */ +#endif /* __i386__ */ + #if defined(__sgi) && defined(HAVE_SYS_FPU_H) /* Enable denormalized DOUBLE values support for IRIX */ union fpc_csr n; @@ -361,6 +395,16 @@ TYPELIB thread_handling_typelib= thread_handling_names, NULL }; +const char *plugin_maturity_names[]= +{ "unknown", "experimental", "alpha", "beta", "gamma", "stable", 0 }; + +TYPELIB plugin_maturity_values= +{ + array_elements(plugin_maturity_names) - 1, "", plugin_maturity_names, 0 +}; + +const int server_maturity= MariaDB_PLUGIN_MATURITY_UNKNOWN; + const char *first_keyword= "first", *binary_keyword= "BINARY"; const char *my_localhost= "localhost", *delayed_user= "DELAYED"; #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) @@ -398,8 +442,10 @@ static bool volatile ready_to_exit; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; static my_bool opt_short_log_format= 0; static my_bool opt_ignore_wrong_options= 0, opt_expect_abort= 0; +static my_bool opt_sync= 0; static uint kill_cached_threads, wake_thread; ulong thread_created; +uint thread_handling; static ulong max_used_connections; static ulong my_bind_addr; /**< the address we bind to */ static volatile ulong cached_thread_count= 0; @@ -561,7 +607,7 @@ 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 slave_exec_mode_options; -const char *slave_exec_mode_str= "STRICT"; +static const char *slave_exec_mode_str= "STRICT"; ulong thread_cache_size=0, thread_pool_size= 0; ulong binlog_cache_size=0; ulonglong max_binlog_cache_size=0; @@ -1261,7 +1307,7 @@ extern "C" sig_handler print_signal_warning(int sig) { if (global_system_variables.log_warnings) sql_print_warning("Got signal %d from thread %ld", sig,my_thread_id()); -#ifdef DONT_REMEMBER_SIGNAL +#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY my_sigset(sig,print_signal_warning); /* int. thread system calls */ #endif #if !defined(__WIN__) && !defined(__NETWARE__) @@ -2554,7 +2600,9 @@ extern "C" sig_handler handle_segfault(int sig) { time_t curr_time; struct tm tm; +#ifdef HAVE_STACKTRACE THD *thd=current_thd; +#endif /* Strictly speaking, one needs a mutex here @@ -2621,13 +2669,14 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", #endif /* HAVE_LINUXTHREADS */ #ifdef HAVE_STACKTRACE + if (!(test_flags & TEST_NO_STACKTRACE)) { - fprintf(stderr,"thd: 0x%lx\n",(long) thd); - fprintf(stderr,"\ -Attempting backtrace. You can use the following information to find out\n\ -where mysqld died. If you see no messages after this, something went\n\ -terribly wrong...\n"); + fprintf(stderr, "thd: 0x%lx\n",(long) thd); + fprintf(stderr, "Attempting backtrace. You can use the following " + "information to find out\nwhere mysqld died. If " + "you see no messages after this, something went\n" + "terribly wrong...\n"); my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, my_thread_stack_size); } @@ -3020,7 +3069,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags) { /* At least, prevent new abuse ... */ DBUG_ASSERT(strncmp(str, "MyISAM table", 12) == 0 || - strncmp(str, "MARIA table", 11) == 0); + strncmp(str, "Aria table", 11) == 0); error= ER_UNKNOWN_ERROR; } @@ -3072,7 +3121,20 @@ int my_message_sql(uint error, const char *str, myf MyFlags) } else { - if (! thd->main_da.is_error()) // Return only first message + if (thd->main_da.is_ok() && !thd->main_da.can_overwrite_status) + { + /* + Client has already got ok packet and we are not in net_flush(), so + we write a message to error log. + This could happen if we get an error in implicit commit. + This should never happen in normal operation, so lets + assert here in debug builds. + */ + DBUG_ASSERT(0); + func= sql_print_error; + MyFlags|= ME_NOREFRESH; + } + else if (! thd->main_da.is_error()) // Return only first message { thd->main_da.set_error_status(thd, error, str); } @@ -3093,6 +3155,9 @@ int my_message_sql(uint error, const char *str, myf MyFlags) DBUG_RETURN(0); } + /* When simulating OOM, skip writing to error log to avoid mtr errors */ + DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(0);); + if (!thd->no_warnings_for_error && !(MyFlags & ME_NO_WARNING_FOR_ERROR)) { @@ -3105,7 +3170,11 @@ int my_message_sql(uint error, const char *str, myf MyFlags) thd->no_warnings_for_error= FALSE; } } + to_error_log: + /* When simulating OOM, skip writing to error log to avoid mtr errors */ + DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(0);); + if (!thd || (MyFlags & ME_NOREFRESH)) (*func)("%s: %s", my_progname_short, str); /* purecov: inspected */ DBUG_RETURN(0); @@ -3364,6 +3433,13 @@ static int init_common_variables(const char *conf_file_name, int argc, max_system_variables.pseudo_thread_id= (ulong)~0; server_start_time= flush_status_time= my_time(0); + /* TODO: remove this when my_time_t is 64 bit compatible */ + if (server_start_time >= (time_t) MY_TIME_T_MAX) + { + sql_print_error("This MySQL server doesn't support dates later then 2038"); + return 1; + } + rpl_filter= new Rpl_filter; binlog_filter= new Rpl_filter; if (!rpl_filter || !binlog_filter) @@ -4189,7 +4265,6 @@ a file name for --log-bin-index option", opt_binlog_index_name); unireg_abort(1); } -#ifdef WITH_CSV_STORAGE_ENGINE if (opt_bootstrap) log_output_options= LOG_FILE; else @@ -4223,10 +4298,6 @@ a file name for --log-bin-index option", opt_binlog_index_name); logger.set_handlers(LOG_FILE, opt_slow_log ? log_output_options:LOG_NONE, opt_log ? log_output_options:LOG_NONE); } -#else - logger.set_handlers(LOG_FILE, opt_slow_log ? LOG_FILE:LOG_NONE, - opt_log ? LOG_FILE:LOG_NONE); -#endif /* Check that the default storage engine is actually available. @@ -4268,10 +4339,10 @@ a file name for --log-bin-index option", opt_binlog_index_name); pthread_mutex_unlock(&LOCK_global_system_variables); } } -#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) +#if defined(WITH_ARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) if (!ha_storage_engine_is_enabled(maria_hton) && !opt_bootstrap) { - sql_print_error("Maria engine is not enabled or did not start. The Maria engine must be enabled to continue as mysqld was configured with --with-maria-tmp-tables"); + sql_print_error("Aria engine is not enabled or did not start. The Aria engine must be enabled to continue as mysqld was configured with --with-aria-tmp-tables"); unireg_abort(1); } #endif @@ -5791,7 +5862,7 @@ error: enum options_mysqld { - OPT_ISAM_LOG=256, OPT_SKIP_NEW, + OPT_ISAM_LOG=256, OPT_SKIP_GRANT, OPT_SKIP_LOCK, OPT_ENABLE_LOCK, OPT_USE_LOCKING, OPT_SOCKET, OPT_UPDATE_LOG, @@ -5912,7 +5983,7 @@ enum options_mysqld OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS, OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE, OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE, - OPT_SYNC_FRM, OPT_SYNC_BINLOG, + OPT_SYNC_FRM, OPT_SYNC_BINLOG, OPT_SYNC, OPT_SYNC_REPLICATION, OPT_SYNC_REPLICATION_SLAVE_ID, OPT_SYNC_REPLICATION_TIMEOUT, @@ -5950,6 +6021,7 @@ enum options_mysqld OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PLUGIN_LOAD, OPT_PLUGIN_DIR, + OPT_PLUGIN_MATURITY, OPT_SYMBOLIC_LINKS, OPT_WARNINGS, OPT_RECORD_BUFFER_OLD, @@ -5969,6 +6041,7 @@ enum options_mysqld #if defined(ENABLED_DEBUG_SYNC) OPT_DEBUG_SYNC_TIMEOUT, #endif /* defined(ENABLED_DEBUG_SYNC) */ + OPT_DEPRECATED_OPTION, OPT_SLAVE_EXEC_MODE, OPT_DEADLOCK_SEARCH_DEPTH_SHORT, OPT_DEADLOCK_SEARCH_DEPTH_LONG, @@ -5990,13 +6063,13 @@ enum options_mysqld struct my_option my_long_options[] = { - {"help", '?', "Display this help and exit.", - (uchar**) &opt_help, (uchar**) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + {"help", '?', "Display this help and exit.", + &opt_help, &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION {"abort-slave-event-count", OPT_ABORT_SLAVE_EVENT_COUNT, "Option used by mysql-test for debugging and testing of replication.", - (uchar**) &abort_slave_event_count, (uchar**) &abort_slave_event_count, + &abort_slave_event_count, &abort_slave_event_count, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_REPLICATION */ {"allow-suspicious-udfs", OPT_ALLOW_SUSPICIOUS_UDFS, @@ -6004,33 +6077,34 @@ struct my_option my_long_options[] = "without corresponding xxx_init() or xxx_deinit(). That also means " "that one can load any function from any library, for example exit() " "from libc.so", - (uchar**) &opt_allow_suspicious_udfs, (uchar**) &opt_allow_suspicious_udfs, + &opt_allow_suspicious_udfs, &opt_allow_suspicious_udfs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode will also set transaction isolation level 'serializable'.", 0, 0, 0, + {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode " + "will also set transaction isolation level 'serializable'.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"auto-increment-increment", OPT_AUTO_INCREMENT, "Auto-increment columns are incremented by this.", - (uchar**) &global_system_variables.auto_increment_increment, - (uchar**) &max_system_variables.auto_increment_increment, 0, GET_ULONG, + &global_system_variables.auto_increment_increment, + &max_system_variables.auto_increment_increment, 0, GET_ULONG, OPT_ARG, 1, 1, 65535, 0, 1, 0 }, {"auto-increment-offset", OPT_AUTO_INCREMENT_OFFSET, "Offset added to Auto-increment columns. Used when auto-increment-increment != 1.", - (uchar**) &global_system_variables.auto_increment_offset, - (uchar**) &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG, + &global_system_variables.auto_increment_offset, + &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG, 1, 1, 65535, 0, 1, 0 }, {"automatic-sp-privileges", OPT_SP_AUTOMATIC_PRIVILEGES, "Creating and dropping stored procedures alters ACLs. Disable with --skip-automatic-sp-privileges.", - (uchar**) &sp_automatic_privileges, (uchar**) &sp_automatic_privileges, + &sp_automatic_privileges, &sp_automatic_privileges, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"basedir", 'b', "Path to installation directory. All paths are usually resolved relative to this.", - (uchar**) &mysql_home_ptr, (uchar**) &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG, + &mysql_home_ptr, &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"big-tables", OPT_BIG_TABLES, "Allow big result sets by saving all temporary sets on file (solves most 'table full' errors).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", - (uchar**) &my_bind_addr_str, (uchar**) &my_bind_addr_str, 0, GET_STR, + &my_bind_addr_str, &my_bind_addr_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog_format", OPT_BINLOG_FORMAT, "Does not have any effect without '--log-bin'. " @@ -6043,10 +6117,11 @@ struct my_option my_long_options[] = "If ndbcluster is enabled and binlog_format is `mixed', the format switches" " to 'row' and back implicitly per each query accessing a NDB table." #endif - ,(uchar**) &opt_binlog_format, (uchar**) &opt_binlog_format, + , &opt_binlog_format, &opt_binlog_format, 0, GET_STR, REQUIRED_ARG, 0, 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.", + "Tells the master it should log updates for the specified database, " + "and exclude all others not explicitly mentioned.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, "Tells the master that updates to the given database should not be logged to the binary log.", @@ -6055,12 +6130,10 @@ struct my_option my_long_options[] = "The maximum size of a row-based binary log event in bytes. Rows will be " "grouped into events smaller than this size if possible. " "The value has to be a multiple of 256.", - (uchar**) &opt_binlog_rows_event_max_size, - (uchar**) &opt_binlog_rows_event_max_size, 0, - GET_ULONG, REQUIRED_ARG, - /* def_value */ 1024, /* min_value */ 256, - /* max_value */ (longlong) ULONG_MAX, - /* sub_size */ 0, /* block_size */ 256, + &opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, + 0, GET_ULONG, REQUIRED_ARG, + /* def_value */ 1024, /* min_value */ 256, /* max_value */ ULONG_MAX, + /* sub_size */ 0, /* block_size */ 256, /* app_type */ 0 }, #ifndef DISABLE_GRANT_OPTIONS @@ -6069,134 +6142,138 @@ struct my_option my_long_options[] = #endif {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, "Don't ignore client side character set value sent during handshake.", - (uchar**) &opt_character_set_client_handshake, - (uchar**) &opt_character_set_client_handshake, + &opt_character_set_client_handshake, + &opt_character_set_client_handshake, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"character-set-filesystem", OPT_CHARACTER_SET_FILESYSTEM, "Set the filesystem character set.", - (uchar**) &character_set_filesystem_name, - (uchar**) &character_set_filesystem_name, + &character_set_filesystem_name, + &character_set_filesystem_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"character-set-server", 'C', "Set the default character set.", - (uchar**) &default_character_set_name, (uchar**) &default_character_set_name, + &default_character_set_name, &default_character_set_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are.", (uchar**) &charsets_dir, - (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory where character sets are.", &charsets_dir, + &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"chroot", 'r', "Chroot mysqld daemon during startup.", - (uchar**) &mysqld_chroot, (uchar**) &mysqld_chroot, 0, GET_STR, REQUIRED_ARG, + &mysqld_chroot, &mysqld_chroot, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.", - (uchar**) &default_collation_name, (uchar**) &default_collation_name, + &default_collation_name, &default_collation_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"completion-type", OPT_COMPLETION_TYPE, "Default completion type.", - (uchar**) &global_system_variables.completion_type, - (uchar**) &max_system_variables.completion_type, 0, GET_ULONG, + &global_system_variables.completion_type, + &max_system_variables.completion_type, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 2, 0, 1, 0}, {"concurrent-insert", OPT_CONCURRENT_INSERT, "Use concurrent insert with MyISAM. Disable with --concurrent-insert=0.", - (uchar**) &myisam_concurrent_insert, (uchar**) &myisam_concurrent_insert, + &myisam_concurrent_insert, &myisam_concurrent_insert, 0, GET_ULONG, OPT_ARG, 1, 0, 2, 0, 0, 0}, {"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.", - (uchar**) &opt_console, (uchar**) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0, + &opt_console, &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"datadir", 'h', "Path to the database root.", (uchar**) &mysql_data_home, - (uchar**) &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"datadir", 'h', "Path to the database root.", &mysql_data_home, + &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"deadlock-search-depth-short", OPT_DEADLOCK_SEARCH_DEPTH_SHORT, "Short search depth for the two-step deadlock detection", - (uchar**) &global_system_variables.wt_deadlock_search_depth_short, - (uchar**) &max_system_variables.wt_deadlock_search_depth_short, + &global_system_variables.wt_deadlock_search_depth_short, + &max_system_variables.wt_deadlock_search_depth_short, 0, GET_ULONG, REQUIRED_ARG, 4, 0, 32, 0, 0, 0}, {"deadlock-search-depth-long", OPT_DEADLOCK_SEARCH_DEPTH_LONG, "Long search depth for the two-step deadlock detection", - (uchar**) &global_system_variables.wt_deadlock_search_depth_long, - (uchar**) &max_system_variables.wt_deadlock_search_depth_long, + &global_system_variables.wt_deadlock_search_depth_long, + &max_system_variables.wt_deadlock_search_depth_long, 0, GET_ULONG, REQUIRED_ARG, 15, 0, 33, 0, 0, 0}, {"deadlock-timeout-short", OPT_DEADLOCK_TIMEOUT_SHORT, "Short timeout for the two-step deadlock detection (in microseconds)", - (uchar**) &global_system_variables.wt_timeout_short, - (uchar**) &max_system_variables.wt_timeout_short, + &global_system_variables.wt_timeout_short, + &max_system_variables.wt_timeout_short, 0, GET_ULONG, REQUIRED_ARG, 10000, 0, ULONG_MAX, 0, 0, 0}, {"deadlock-timeout-long", OPT_DEADLOCK_TIMEOUT_LONG, "Long timeout for the two-step deadlock detection (in microseconds)", - (uchar**) &global_system_variables.wt_timeout_long, - (uchar**) &max_system_variables.wt_timeout_long, + &global_system_variables.wt_timeout_long, + &max_system_variables.wt_timeout_long, 0, GET_ULONG, REQUIRED_ARG, 50000000, 0, ULONG_MAX, 0, 0, 0}, #ifndef DBUG_OFF - {"debug", '#', "Debug log.", (uchar**) &default_dbug_option, - (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Debug log.", &default_dbug_option, + &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"debug-crc-break", OPT_DEBUG_CRC, "Call my_debug_put_break_here() if crc matches this number (for debug).", - (uchar**) &opt_my_crc_dbug_check, (uchar**) &opt_my_crc_dbug_check, + &opt_my_crc_dbug_check, &opt_my_crc_dbug_check, 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~(ulong) 0L, 0, 0, 0}, {"debug-flush", OPT_DEBUG_FLUSH, "Default debug log with flush after write", - (uchar**) 0, (uchar**) 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"default-character-set", OPT_DEFAULT_CHARACTER_SET_OLD, "Set the default character set (deprecated option, use --character-set-server instead).", - (uchar**) &default_character_set_name, (uchar**) &default_character_set_name, + &default_character_set_name, &default_character_set_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"default-collation", OPT_DEFAULT_COLLATION_OLD, "Set the default collation (deprecated option, use --collation-server instead).", - (uchar**) &default_collation_name, (uchar**) &default_collation_name, + {"default-collation", OPT_DEFAULT_COLLATION_OLD, "Set the default collation " + "(deprecated option, use --collation-server instead).", + &default_collation_name, &default_collation_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"default-storage-engine", OPT_STORAGE_ENGINE, "Set the default storage engine (table type) for tables.", - (uchar**)&default_storage_engine_str, (uchar**)&default_storage_engine_str, + &default_storage_engine_str, &default_storage_engine_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-table-type", OPT_STORAGE_ENGINE, "(deprecated) Use --default-storage-engine.", - (uchar**)&default_storage_engine_str, (uchar**)&default_storage_engine_str, + &default_storage_engine_str, &default_storage_engine_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-time-zone", OPT_DEFAULT_TIME_ZONE, "Set the default time zone.", - (uchar**) &default_tz_name, (uchar**) &default_tz_name, + &default_tz_name, &default_tz_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"delay-key-write", OPT_DELAY_KEY_WRITE, "Type of DELAY_KEY_WRITE.", 0,0,0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"delay-key-write-for-all-tables", OPT_DELAY_KEY_WRITE_ALL, - "Don't flush key buffers between writes for any MyISAM table. (Deprecated option, use --delay-key-write=all instead.)", + "Don't flush key buffers between writes for any MyISAM table. " + "(Deprecated option, use --delay-key-write=all instead.)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_OPENSSL {"des-key-file", OPT_DES_KEY_FILE, "Load keys for des_encrypt() and des_encrypt from given file.", - (uchar**) &des_key_file, (uchar**) &des_key_file, 0, GET_STR, REQUIRED_ARG, + &des_key_file, &des_key_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_OPENSSL */ #ifdef HAVE_REPLICATION {"disconnect-slave-event-count", OPT_DISCONNECT_SLAVE_EVENT_COUNT, "Option used by mysql-test for debugging and testing of replication.", - (uchar**) &disconnect_slave_event_count, - (uchar**) &disconnect_slave_event_count, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, - 0, 0, 0}, + &disconnect_slave_event_count, &disconnect_slave_event_count, + 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_REPLICATION */ {"enable-locking", OPT_ENABLE_LOCK, "Deprecated option, use --external-locking instead.", - (uchar**) &opt_external_locking, (uchar**) &opt_external_locking, + &opt_external_locking, &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NT__ {"enable-named-pipe", OPT_HAVE_NAMED_PIPE, "Enable the named pipe (NT).", - (uchar**) &opt_enable_named_pipe, (uchar**) &opt_enable_named_pipe, 0, GET_BOOL, + &opt_enable_named_pipe, &opt_enable_named_pipe, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif #ifdef HAVE_STACK_TRACE_ON_SEGV {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.", - (uchar**) &opt_do_pstack, (uchar**) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0, + &opt_do_pstack, &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_STACK_TRACE_ON_SEGV */ {"engine-condition-pushdown", OPT_ENGINE_CONDITION_PUSHDOWN, "Push supported query conditions to the storage engine.", - (uchar**) &global_system_variables.engine_condition_pushdown, - (uchar**) &global_system_variables.engine_condition_pushdown, + &global_system_variables.engine_condition_pushdown, + &global_system_variables.engine_condition_pushdown, 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}, {"exit-info", 'T', "Used for debugging. Use at your own risk.", 0, 0, 0, GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"external-locking", OPT_USE_LOCKING, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking.", - (uchar**) &opt_external_locking, (uchar**) &opt_external_locking, + {"external-locking", OPT_USE_LOCKING, "Use system (external) locking " + "(disabled by default). With this option enabled you can run myisamchk " + "to test (not repair) tables while the MySQL server is running. " + "Disable with --skip-external-locking.", + &opt_external_locking, &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -6204,73 +6281,70 @@ struct my_option my_long_options[] = easier to do */ {"extra-port", OPT_EXTRA_PORT, "Extra port number to use for tcp-connections in a one-thread-per-connection manner. 0 means don't use another port", - (uchar**) &mysqld_extra_port, - (uchar**) &mysqld_extra_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &mysqld_extra_port, + &mysqld_extra_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"extra-max-connections", OPT_MAX_CONNECTIONS, "The number of connections on 'extra-port.", - (uchar**) &extra_max_connections, - (uchar**) &extra_max_connections, 0, GET_ULONG, REQUIRED_ARG, 1, 1, 100000, + &extra_max_connections, + &extra_max_connections, 0, GET_ULONG, REQUIRED_ARG, 1, 1, 100000, 0, 1, 0}, {"gdb", OPT_DEBUGGING, "Set up signals usable for debugging.", - (uchar**) &opt_debugging, (uchar**) &opt_debugging, + &opt_debugging, &opt_debugging, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"general_log", OPT_GENERAL_LOG, - "Enable/disable general log.", (uchar**) &opt_log, - (uchar**) &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + "Enable/disable general log.", &opt_log, + &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_LARGE_PAGES - {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. \ -Disable with --skip-large-pages.", - (uchar**) &opt_large_pages, (uchar**) &opt_large_pages, 0, GET_BOOL, NO_ARG, 0, 0, 0, - 0, 0, 0}, + {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. " + "Disable with --skip-large-pages.", &opt_large_pages, &opt_large_pages, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"ignore-builtin-innodb", OPT_IGNORE_BUILTIN_INNODB , "Disable initialization of builtin InnoDB plugin.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"init-connect", OPT_INIT_CONNECT, "Command(s) that are executed for each new connection.", - (uchar**) &opt_init_connect, (uchar**) &opt_init_connect, 0, GET_STR_ALLOC, + &opt_init_connect, &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.", - (uchar**) &opt_init_file, (uchar**) &opt_init_file, 0, GET_STR, REQUIRED_ARG, + &opt_init_file, &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 by a slave server \ each time the SQL thread starts.", - (uchar**) &opt_init_slave, (uchar**) &opt_init_slave, 0, GET_STR_ALLOC, + &opt_init_slave, &opt_init_slave, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"language", 'L', "Client error messages in given language. May be given as a full path.", - (uchar**) &language_ptr, (uchar**) &language_ptr, 0, GET_STR, REQUIRED_ARG, + &language_ptr, &language_ptr, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lc-time-names", OPT_LC_TIME_NAMES, "Set the language used for the month names and the days of the week.", - (uchar**) &lc_time_names_name, - (uchar**) &lc_time_names_name, + &lc_time_names_name, &lc_time_names_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE (takes values 1 or 0).", - (uchar**) &opt_local_infile, - (uchar**) &opt_local_infile, 0, GET_BOOL, OPT_ARG, + &opt_local_infile, &opt_local_infile, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"log", 'l', "Log connections and queries to file (deprecated option, use " - "--general_log/--general_log_file instead).", (uchar**) &opt_logname, - (uchar**) &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + "--general_log/--general_log_file instead).", &opt_logname, + &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"general_log_file", OPT_GENERAL_LOG_FILE, - "Log connections and queries to given file.", (uchar**) &opt_logname, - (uchar**) &opt_logname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Log connections and queries to given file.", &opt_logname, + &opt_logname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"log-bin", OPT_BIN_LOG, "Log update queries in binary format. Optional (but strongly recommended " "to avoid replication problems if server's hostname changes) argument " "should be the chosen location for the binary log files.", - (uchar**) &opt_bin_logname, (uchar**) &opt_bin_logname, 0, GET_STR_ALLOC, + &opt_bin_logname, &opt_bin_logname, 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-bin-index", OPT_BIN_LOG_INDEX, "File that holds the names for last binary log files.", - (uchar**) &opt_binlog_index_name, (uchar**) &opt_binlog_index_name, 0, GET_STR, + &opt_binlog_index_name, &opt_binlog_index_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifndef TO_BE_REMOVED_IN_5_1_OR_6_0 /* @@ -6281,7 +6355,7 @@ each time the SQL thread starts.", */ {"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD, "(deprecated) Use log-bin-trust-function-creators.", - (uchar**) &trust_function_creators, (uchar**) &trust_function_creators, 0, + &trust_function_creators, &trust_function_creators, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif /* @@ -6296,195 +6370,200 @@ each time the SQL thread starts.", "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." - ,(uchar**) &trust_function_creators, (uchar**) &trust_function_creators, 0, + ,&trust_function_creators, &trust_function_creators, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-error", OPT_ERROR_LOG_FILE, "Error log file.", - (uchar**) &log_error_file_ptr, (uchar**) &log_error_file_ptr, 0, GET_STR, + &log_error_file_ptr, &log_error_file_ptr, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-isam", OPT_ISAM_LOG, "Log all MyISAM changes to file.", - (uchar**) &myisam_log_filename, (uchar**) &myisam_log_filename, 0, GET_STR, + &myisam_log_filename, &myisam_log_filename, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-long-format", '0', - "Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.", + "Log some extra information to update log. Please note that this option " + "is deprecated; see --log-short-format option.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef WITH_CSV_STORAGE_ENGINE {"log-output", OPT_LOG_OUTPUT, "Syntax: log-output[=value[,value...]], where \"value\" could be TABLE, " "FILE or NONE.", - (uchar**) &log_output_str, (uchar**) &log_output_str, 0, + &log_output_str, &log_output_str, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES, "Log queries that are executed without benefit of any index to the slow log if it is open.", - (uchar**) &opt_log_queries_not_using_indexes, (uchar**) &opt_log_queries_not_using_indexes, + &opt_log_queries_not_using_indexes, &opt_log_queries_not_using_indexes, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-short-format", OPT_SHORT_LOG_FORMAT, "Don't log extra information to update and slow-query logs.", - (uchar**) &opt_short_log_format, (uchar**) &opt_short_log_format, + &opt_short_log_format, &opt_short_log_format, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slave-updates", OPT_LOG_SLAVE_UPDATES, - "Tells the slave to log the updates from the slave thread to the binary log. You will need to turn it on if you plan to daisy-chain the slaves.", - (uchar**) &opt_log_slave_updates, (uchar**) &opt_log_slave_updates, 0, GET_BOOL, + "Tells the slave to log the updates from the slave thread to the binary log. " + "You will need to turn it on if you plan to daisy-chain the slaves.", + &opt_log_slave_updates, &opt_log_slave_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-admin-statements", OPT_LOG_SLOW_ADMIN_STATEMENTS, - "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to the slow log if it is open. . Please note that this option is deprecated; see --log-slow-filter for filtering slow query log output", - (uchar**) &opt_log_slow_admin_statements, - (uchar**) &opt_log_slow_admin_statements, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements " + "to the slow log if it is open.", &opt_log_slow_admin_statements, + &opt_log_slow_admin_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-slave-statements", OPT_LOG_SLOW_SLAVE_STATEMENTS, "Log slow statements executed by slave thread to the slow log if it is open.", - (uchar**) &opt_log_slow_slave_statements, - (uchar**) &opt_log_slow_slave_statements, + &opt_log_slow_slave_statements, + &opt_log_slow_slave_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-queries", OPT_SLOW_QUERY_LOG, "Log slow queries to a table or log file. Defaults logging to table " "mysql.slow_log or hostname-slow.log if --log-output=file is used. " "Must be enabled to activate other slow log options. " "(deprecated option, use --slow_query_log/--slow_query_log_file instead)", - (uchar**) &opt_slow_logname, (uchar**) &opt_slow_logname, 0, GET_STR, OPT_ARG, + &opt_slow_logname, &opt_slow_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"slow-query-log-file", OPT_SLOW_QUERY_LOG_FILE, - "Log slow queries to given log file. Defaults logging to hostname-slow.log.", - (uchar**) &opt_slow_logname, (uchar**) &opt_slow_logname, 0, GET_STR, + {"slow_query_log_file", OPT_SLOW_QUERY_LOG_FILE, + "Log slow queries to given log file. Defaults logging to hostname-slow.log. " + "Must be enabled to activate other slow log options.", + &opt_slow_logname, &opt_slow_logname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"log-tc", OPT_LOG_TC, "Path to transaction coordinator log (used for transactions that affect " "more than one storage engine, when binary log is disabled).", - (uchar**) &opt_tc_log_file, (uchar**) &opt_tc_log_file, 0, GET_STR, + &opt_tc_log_file, &opt_tc_log_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_MMAP {"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.", - (uchar**) &opt_tc_log_size, (uchar**) &opt_tc_log_size, 0, GET_ULONG, + &opt_tc_log_size, &opt_tc_log_size, 0, GET_ULONG, REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, (longlong) ULONG_MAX, 0, TC_LOG_PAGE_SIZE, 0}, #endif {"log-update", OPT_UPDATE_LOG, "The update log is deprecated since version 5.0, is replaced by the binary " "log and this option just turns on --log-bin instead.", - (uchar**) &opt_update_logname, (uchar**) &opt_update_logname, 0, GET_STR, + &opt_update_logname, &opt_update_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-warnings", 'W', "Log some not critical warnings to the log file.", - (uchar**) &global_system_variables.log_warnings, - (uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0, + &global_system_variables.log_warnings, + &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"low-priority-updates", OPT_LOW_PRIORITY_UPDATES, "INSERT/DELETE/UPDATE has lower priority than selects.", - (uchar**) &global_system_variables.low_priority_updates, - (uchar**) &max_system_variables.low_priority_updates, + &global_system_variables.low_priority_updates, + &max_system_variables.low_priority_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-connect-retry", OPT_MASTER_CONNECT_RETRY, "The number of seconds the slave thread will sleep before retrying to " "connect to the master, in case the master goes down or the connection " "is lost.", - (uchar**) &master_connect_retry, (uchar**) &master_connect_retry, 0, GET_UINT, + &master_connect_retry, &master_connect_retry, 0, GET_UINT, REQUIRED_ARG, 60, 0, 0, 0, 0, 0}, {"master-host", OPT_MASTER_HOST, - "Master hostname or IP address for replication. If not set, the slave thread will not be started. Note that the setting of master-host will be ignored if there exists a valid master.info file.", - (uchar**) &master_host, (uchar**) &master_host, 0, GET_STR, REQUIRED_ARG, 0, 0, + "Master hostname or IP address for replication. If not set, the slave " + "thread will not be started. Note that the setting of master-host will " + "be ignored if there exists a valid master.info file.", + &master_host, &master_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-info-file", OPT_MASTER_INFO_FILE, - "The location and name of the file that remembers the master and where the I/O replication \ -thread is in the master's binlogs.", - (uchar**) &master_info_file, (uchar**) &master_info_file, 0, GET_STR, + "The location and name of the file that remembers the master and where " + "the I/O replication thread is in the master's binlogs.", + &master_info_file, &master_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-password", OPT_MASTER_PASSWORD, "The password the slave thread will authenticate with when connecting to " "the master. If not set, an empty password is assumed. The value in " "master.info will take precedence if it can be read.", - (uchar**)&master_password, (uchar**)&master_password, 0, + &master_password, &master_password, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-port", OPT_MASTER_PORT, - "The port the master is listening on. If not set, the compiled setting of MYSQL_PORT is assumed. If you have not tinkered with configure options, this should be 3306. The value in master.info will take precedence if it can be read.", - (uchar**) &master_port, (uchar**) &master_port, 0, GET_UINT, REQUIRED_ARG, + "The port the master is listening on. If not set, the compiled setting of " + "MYSQL_PORT is assumed. If you have not tinkered with configure options, " + "this should be 3306. The value in master.info will take precedence if it " + "can be read.", &master_port, &master_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, {"master-retry-count", OPT_MASTER_RETRY_COUNT, "The number of tries the slave will make to connect to the master before giving up.", - (uchar**) &master_retry_count, (uchar**) &master_retry_count, 0, GET_ULONG, + &master_retry_count, &master_retry_count, 0, GET_ULONG, REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0}, {"master-ssl", OPT_MASTER_SSL, "Enable the slave to connect to the master using SSL.", - (uchar**) &master_ssl, (uchar**) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + &master_ssl, &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-ca", OPT_MASTER_SSL_CA, "Master SSL CA file. Only applies if you have enabled master-ssl.", - (uchar**) &master_ssl_ca, (uchar**) &master_ssl_ca, 0, GET_STR, OPT_ARG, + &master_ssl_ca, &master_ssl_ca, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-capath", OPT_MASTER_SSL_CAPATH, "Master SSL CA path. Only applies if you have enabled master-ssl.", - (uchar**) &master_ssl_capath, (uchar**) &master_ssl_capath, 0, GET_STR, OPT_ARG, + &master_ssl_capath, &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cert", OPT_MASTER_SSL_CERT, "Master SSL certificate file name. Only applies if you have enabled " "master-ssl.", - (uchar**) &master_ssl_cert, (uchar**) &master_ssl_cert, 0, GET_STR, OPT_ARG, + &master_ssl_cert, &master_ssl_cert, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER, "Master SSL cipher. Only applies if you have enabled master-ssl.", - (uchar**) &master_ssl_cipher, (uchar**) &master_ssl_capath, 0, GET_STR, OPT_ARG, + &master_ssl_cipher, &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-key", OPT_MASTER_SSL_KEY, "Master SSL keyfile name. Only applies if you have enabled master-ssl.", - (uchar**) &master_ssl_key, (uchar**) &master_ssl_key, 0, GET_STR, OPT_ARG, + &master_ssl_key, &master_ssl_key, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-user", OPT_MASTER_USER, - "The username the slave thread will use for authentication when connecting to the master. The user must have FILE privilege. If the master user is not set, user test is assumed. The value in master.info will take precedence if it can be read.", - (uchar**) &master_user, (uchar**) &master_user, 0, GET_STR, REQUIRED_ARG, 0, 0, + "The username the slave thread will use for authentication when " + "connecting to the master. The user must have FILE privilege. " + "If the master user is not set, user test is assumed. The value " + "in master.info will take precedence if it can be read.", + &master_user, &master_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION {"max-binlog-dump-events", OPT_MAX_BINLOG_DUMP_EVENTS, "Option used by mysql-test for debugging and testing of replication.", - (uchar**) &max_binlog_dump_events, (uchar**) &max_binlog_dump_events, 0, + &max_binlog_dump_events, &max_binlog_dump_events, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_REPLICATION */ - {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (uchar**) &locked_in_memory, - (uchar**) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", &locked_in_memory, + &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef SAFE_MUTEX {"mutex-deadlock-detector", OPT_MUTEX_DEADLOCK_DETECTOR, "Enable checking of wrong mutex usage.", - (uchar**) &safe_mutex_deadlock_detector, - (uchar**) &safe_mutex_deadlock_detector, + &safe_mutex_deadlock_detector, + &safe_mutex_deadlock_detector, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, #endif {"myisam-recover", OPT_MYISAM_RECOVER, "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (uchar**) &myisam_recover_options_str, (uchar**) &myisam_recover_options_str, 0, + &myisam_recover_options_str, &myisam_recover_options_str, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE {"ndb-connectstring", OPT_NDB_CONNECTSTRING, "Connect string for ndbcluster.", - (uchar**) &opt_ndb_connectstring, - (uchar**) &opt_ndb_connectstring, + &opt_ndb_connectstring, &opt_ndb_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ndb-mgmd-host", OPT_NDB_MGMD, "Set host and port for ndb_mgmd. Syntax: hostname[:port]", - (uchar**) &opt_ndb_mgmd, - (uchar**) &opt_ndb_mgmd, + &opt_ndb_mgmd, &opt_ndb_mgmd, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ndb-nodeid", OPT_NDB_NODEID, "Nodeid for this mysqlserver in the cluster.", - (uchar**) &opt_ndb_nodeid, - (uchar**) &opt_ndb_nodeid, + &opt_ndb_nodeid, + &opt_ndb_nodeid, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, "Specify number of autoincrement values that are prefetched.", - (uchar**) &global_system_variables.ndb_autoincrement_prefetch_sz, - (uchar**) &max_system_variables.ndb_autoincrement_prefetch_sz, + &global_system_variables.ndb_autoincrement_prefetch_sz, + &max_system_variables.ndb_autoincrement_prefetch_sz, 0, GET_ULONG, REQUIRED_ARG, 1, 1, 256, 0, 0, 0}, {"ndb-force-send", OPT_NDB_FORCE_SEND, "Force send of buffers to ndb immediately without waiting for " "other threads.", - (uchar**) &global_system_variables.ndb_force_send, - (uchar**) &global_system_variables.ndb_force_send, + &global_system_variables.ndb_force_send, + &global_system_variables.ndb_force_send, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"ndb_force_send", OPT_NDB_FORCE_SEND, "same as --ndb-force-send.", - (uchar**) &global_system_variables.ndb_force_send, - (uchar**) &global_system_variables.ndb_force_send, + &global_system_variables.ndb_force_send, + &global_system_variables.ndb_force_send, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"ndb-extra-logging", OPT_NDB_EXTRA_LOGGING, "Turn on more logging in the error log.", - (uchar**) &ndb_extra_logging, - (uchar**) &ndb_extra_logging, + &ndb_extra_logging, + &ndb_extra_logging, 0, GET_INT, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_NDB_BINLOG {"ndb-report-thresh-binlog-epoch-slip", OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP, @@ -6492,86 +6571,87 @@ thread is in the master's binlogs.", "E.g., 3 means that if the difference between what epoch has been received " "from the storage nodes and what has been applied to the binlog is 3 or more, " "a status message will be sent to the cluster log.", - (uchar**) &ndb_report_thresh_binlog_epoch_slip, - (uchar**) &ndb_report_thresh_binlog_epoch_slip, + &ndb_report_thresh_binlog_epoch_slip, + &ndb_report_thresh_binlog_epoch_slip, 0, GET_ULONG, REQUIRED_ARG, 3, 0, 256, 0, 0, 0}, {"ndb-report-thresh-binlog-mem-usage", OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE, "Threshold on percentage of free memory before reporting binlog status. E.g., " "10 means that if amount of available memory for receiving binlog data from " "the storage nodes goes below 10%, " "a status message will be sent to the cluster log.", - (uchar**) &ndb_report_thresh_binlog_mem_usage, - (uchar**) &ndb_report_thresh_binlog_mem_usage, + &ndb_report_thresh_binlog_mem_usage, + &ndb_report_thresh_binlog_mem_usage, 0, GET_ULONG, REQUIRED_ARG, 10, 0, 100, 0, 0, 0}, #endif {"ndb-use-exact-count", OPT_NDB_USE_EXACT_COUNT, "Use exact records count during query planning and for fast " "select count(*), disable for faster queries.", - (uchar**) &global_system_variables.ndb_use_exact_count, - (uchar**) &global_system_variables.ndb_use_exact_count, + &global_system_variables.ndb_use_exact_count, + &global_system_variables.ndb_use_exact_count, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"ndb_use_exact_count", OPT_NDB_USE_EXACT_COUNT, "Same as --ndb-use-exact-count.", - (uchar**) &global_system_variables.ndb_use_exact_count, - (uchar**) &global_system_variables.ndb_use_exact_count, + &global_system_variables.ndb_use_exact_count, + &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", - (uchar**) &global_system_variables.ndb_use_transactions, - (uchar**) &global_system_variables.ndb_use_transactions, + &global_system_variables.ndb_use_transactions, + &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.", - (uchar**) &global_system_variables.ndb_use_transactions, - (uchar**) &global_system_variables.ndb_use_transactions, + &global_system_variables.ndb_use_transactions, + &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.", - (uchar**) &opt_ndb_shm, - (uchar**) &opt_ndb_shm, + &opt_ndb_shm, &opt_ndb_shm, 0, GET_BOOL, OPT_ARG, OPT_NDB_SHM_DEFAULT, 0, 0, 0, 0, 0}, {"ndb-optimized-node-selection", OPT_NDB_OPTIMIZED_NODE_SELECTION, "Select nodes for transactions in a more optimal way.", - (uchar**) &opt_ndb_optimized_node_selection, - (uchar**) &opt_ndb_optimized_node_selection, + &opt_ndb_optimized_node_selection, + &opt_ndb_optimized_node_selection, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, { "ndb-cache-check-time", OPT_NDB_CACHE_CHECK_TIME, "A dedicated thread is created to, at the given milliseconds interval, " "invalidate the query cache if another MySQL server in the cluster has " "changed the data in the database.", - (uchar**) &opt_ndb_cache_check_time, (uchar**) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG, + &opt_ndb_cache_check_time, &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG, 0, 0, LONG_TIMEOUT, 0, 1, 0}, {"ndb-index-stat-enable", OPT_NDB_INDEX_STAT_ENABLE, "Use ndb index statistics in query optimization.", - (uchar**) &global_system_variables.ndb_index_stat_enable, - (uchar**) &max_system_variables.ndb_index_stat_enable, + &global_system_variables.ndb_index_stat_enable, + &max_system_variables.ndb_index_stat_enable, 0, GET_BOOL, OPT_ARG, 0, 0, 1, 0, 0, 0}, #endif {"ndb-use-copying-alter-table", OPT_NDB_USE_COPYING_ALTER_TABLE, - "Force ndbcluster to always copy tables at alter table (should only be used if on-line alter table fails).", - (uchar**) &global_system_variables.ndb_use_copying_alter_table, - (uchar**) &global_system_variables.ndb_use_copying_alter_table, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + "Force ndbcluster to always copy tables at alter table " + "(should only be used if on-line alter table fails).", + &global_system_variables.ndb_use_copying_alter_table, + &global_system_variables.ndb_use_copying_alter_table, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"new", 'n', "Use very new, possibly 'unsafe', functions.", - (uchar**) &global_system_variables.new_mode, - (uchar**) &max_system_variables.new_mode, + &global_system_variables.new_mode, + &max_system_variables.new_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef NOT_YET {"no-mix-table-types", OPT_NO_MIX_TYPE, "Don't allow commands that use two different table types.", - (uchar**) &opt_no_mix_types, (uchar**) &opt_no_mix_types, 0, GET_BOOL, NO_ARG, + &opt_no_mix_types, &opt_no_mix_types, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"old-alter-table", OPT_OLD_ALTER_TABLE, "Use old, non-optimized alter table.", - (uchar**) &global_system_variables.old_alter_table, - (uchar**) &max_system_variables.old_alter_table, 0, GET_BOOL, NO_ARG, + &global_system_variables.old_alter_table, + &max_system_variables.old_alter_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).", - (uchar**) &global_system_variables.old_passwords, - (uchar**) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, + {"old-passwords", OPT_OLD_PASSWORDS, "Use old password " + "encryption method (needed for 4.0 and older clients).", + &global_system_variables.old_passwords, + &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"one-thread", OPT_ONE_THREAD, "(Deprecated): Only use one thread (for debugging under Linux). Use " @@ -6580,10 +6660,10 @@ thread is in the master's binlogs.", {"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).", - (uchar**) &opt_old_style_user_limits, (uchar**) &opt_old_style_user_limits, + &opt_old_style_user_limits, &opt_old_style_user_limits, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.", - (uchar**) &pidfile_name_ptr, (uchar**) &pidfile_name_ptr, 0, GET_STR, + &pidfile_name_ptr, &pidfile_name_ptr, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " @@ -6591,64 +6671,85 @@ thread is in the master's binlogs.", "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (uchar**) &mysqld_port, - (uchar**) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &mysqld_port, + &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port-open-timeout", OPT_PORT_OPEN_TIMEOUT, "Maximum time in seconds to wait for the port to become free. " - "(Default: No wait).", (uchar**) &mysqld_port_timeout, - (uchar**) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "(Default: No wait).", &mysqld_port_timeout, + &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory.", - (uchar**) &global_system_variables.profiling_history_size, - (uchar**) &max_system_variables.profiling_history_size, + &global_system_variables.profiling_history_size, + &max_system_variables.profiling_history_size, 0, GET_ULONG, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, #endif {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs.", - (uchar**) &opt_relay_logname, (uchar**) &opt_relay_logname, 0, + &opt_relay_logname, &opt_relay_logname, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"relay-log-index", OPT_RELAY_LOG_INDEX, "The location and name to use for the file that keeps a list of the last \ relay logs.", - (uchar**) &opt_relaylog_index_name, (uchar**) &opt_relaylog_index_name, 0, + &opt_relaylog_index_name, &opt_relaylog_index_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE, "The location and name of the file that remembers where the SQL replication \ thread is in the relay logs.", - (uchar**) &relay_log_info_file, (uchar**) &relay_log_info_file, 0, GET_STR, + &relay_log_info_file, &relay_log_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-do-db", OPT_REPLICATE_DO_DB, - "Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database. Note that this will only work if you do not use cross-database queries such as UPDATE some_db.some_table SET foo='bar' while having selected a different or no database. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-do-table=db_name.%.", + "Tells the slave thread to restrict replication to the specified database. " + "To specify more than one database, use the directive multiple times, " + "once for each database. Note that this will only work if you do not use " + "cross-database queries such as UPDATE some_db.some_table SET foo='bar' " + "while having selected a different or no database. If you need cross " + "database updates to work, make sure you have 3.23.28 or later, and use " + "replicate-wild-do-table=db_name.%.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-do-table", OPT_REPLICATE_DO_TABLE, - "Tells the slave thread to restrict replication to the specified table. To specify more than one table, use the directive multiple times, once for each table. This will work for cross-database updates, in contrast to replicate-do-db.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Tells the slave thread to restrict replication to the specified table. " + "To specify more than one table, use the directive multiple times, once " + "for each table. This will work for cross-database updates, in contrast " + "to replicate-do-db.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-ignore-db", OPT_REPLICATE_IGNORE_DB, - "Tells the slave thread to not replicate to the specified database. To specify more than one database to ignore, use the directive multiple times, once for each database. This option will not work if you use cross database updates. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-ignore-table=db_name.%. ", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Tells the slave thread to not replicate to the specified database. To " + "specify more than one database to ignore, use the directive multiple " + "times, once for each database. This option will not work if you use " + "cross database updates. If you need cross database updates to work, " + "make sure you have 3.23.28 or later, and use replicate-wild-ignore-" + "table=db_name.%. ", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-ignore-table", OPT_REPLICATE_IGNORE_TABLE, "Tells the slave thread to not replicate to the specified table. To specify " "more than one table to ignore, use the directive multiple times, once for " "each table. This will work for cross-database updates, in contrast to " - "replicate-ignore-db.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "replicate-ignore-db.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB, - "Updates to a database with a different name than the original. Example: replicate-rewrite-db=master_db_name->slave_db_name.", + "Updates to a database with a different name than the original. Example: " + "replicate-rewrite-db=master_db_name->slave_db_name.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION {"replicate-same-server-id", OPT_REPLICATE_SAME_SERVER_ID, - "In replication, if set to 1, do not skip events having our server id. \ -Default value is 0 (to break infinite loops in circular replication). \ -Can't be set to 1 if --log-slave-updates is used.", - (uchar**) &replicate_same_server_id, - (uchar**) &replicate_same_server_id, + "In replication, if set to 1, do not skip events having our server id. " + "Default value is 0 (to break infinite loops in circular replication). " + "Can't be set to 1 if --log-slave-updates is used.", + &replicate_same_server_id, &replicate_same_server_id, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"replicate-wild-do-table", OPT_REPLICATE_WILD_DO_TABLE, - "Tells the slave thread to restrict replication to the tables that match the specified wildcard pattern. To specify more than one table, use the directive multiple times, once for each table. This will work for cross-database updates. Example: replicate-wild-do-table=foo%.bar% will replicate only updates to tables in all databases that start with foo and whose table names start with bar.", + "Tells the slave thread to restrict replication to the tables that match " + "the specified wildcard pattern. To specify more than one table, use the " + "directive multiple times, once for each table. This will work for cross-" + "database updates. Example: replicate-wild-do-table=foo%.bar% will " + "replicate only updates to tables in all databases that start with foo " + "and whose table names start with bar.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-wild-ignore-table", OPT_REPLICATE_WILD_IGNORE_TABLE, - "Tells the slave thread to not replicate to the tables that match the given wildcard pattern. To specify more than one table to ignore, use the directive multiple times, once for each table. This will work for cross-database updates. Example: replicate-wild-ignore-table=foo%.bar% will not do updates to tables in databases that start with foo and whose table names start with bar.", + "Tells the slave thread to not replicate to the tables that match the " + "given wildcard pattern. To specify more than one table to ignore, use " + "the directive multiple times, once for each table. This will work for " + "cross-database updates. Example: replicate-wild-ignore-table=foo%.bar% " + "will not do updates to tables in databases that start with foo and whose " + "table names start with bar.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, // In replication, we may need to tell the other servers how to connect {"report-host", OPT_REPORT_HOST, @@ -6659,19 +6760,22 @@ Can't be set to 1 if --log-slave-updates is used.", "from the socket once the slave connects. Due to NAT and other routing " "issues, that IP may not be valid for connecting to the slave from the " "master or other hosts.", - (uchar**) &report_host, (uchar**) &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0, + &report_host, &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"report-password", OPT_REPORT_PASSWORD, "Undocumented.", - (uchar**) &report_password, (uchar**) &report_password, 0, GET_STR, + &report_password, &report_password, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"report-port", OPT_REPORT_PORT, - "Port for connecting to slave reported to the master during slave registration. Set it only if the slave is listening on a non-default port or if you have a special tunnel from the master or other clients to the slave. If not sure, leave this option unset.", - (uchar**) &report_port, (uchar**) &report_port, 0, GET_UINT, REQUIRED_ARG, + "Port for connecting to slave reported to the master during slave " + "registration. Set it only if the slave is listening on a non-default " + "port or if you have a special tunnel from the master or other clients " + "to the slave. If not sure, leave this option unset.", + &report_port, &report_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, - {"report-user", OPT_REPORT_USER, "Undocumented.", (uchar**) &report_user, - (uchar**) &report_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"report-user", OPT_REPORT_USER, "Undocumented.", &report_user, + &report_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented.", - (uchar**) &rpl_recovery_rank, (uchar**) &rpl_recovery_rank, 0, GET_ULONG, + &rpl_recovery_rank, &rpl_recovery_rank, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -6682,21 +6786,21 @@ Can't be set to 1 if --log-slave-updates is used.", #endif {"safe-user-create", OPT_SAFE_USER_CREATE, "Don't allow new user creation by the user who has no write privileges to the mysql.user table.", - (uchar**) &opt_safe_user_create, (uchar**) &opt_safe_user_create, 0, GET_BOOL, + &opt_safe_user_create, &opt_safe_user_create, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"safemalloc-mem-limit", OPT_SAFEMALLOC_MEM_LIMIT, "Simulate memory shortage when compiled with the --with-debug=full option.", 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.", - (uchar**) &opt_secure_auth, (uchar**) &opt_secure_auth, 0, GET_BOOL, NO_ARG, + &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, my_bool(0), 0, 0, 0, 0, 0}, {"secure-file-priv", OPT_SECURE_FILE_PRIV, "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory.", - (uchar**) &opt_secure_file_priv, (uchar**) &opt_secure_file_priv, 0, + &opt_secure_file_priv, &opt_secure_file_priv, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-id", OPT_SERVER_ID, "Uniquely identifies the server instance in the community of replication partners.", - (uchar**) &server_id, (uchar**) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, UINT_MAX32, + &server_id, &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, UINT_MAX32, 0, 0, 0}, {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated; " @@ -6704,20 +6808,23 @@ Can't be set to 1 if --log-slave-updates is used.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_SMEM {"shared-memory", OPT_ENABLE_SHARED_MEMORY, - "Enable the shared memory.",(uchar**) &opt_enable_shared_memory, (uchar**) &opt_enable_shared_memory, + "Enable the shared memory.",&opt_enable_shared_memory, &opt_enable_shared_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"shared-memory-base-name",OPT_SHARED_MEMORY_BASE_NAME, - "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, + "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO, "Show user and password in SHOW SLAVE HOSTS on this master.", - (uchar**) &opt_show_slave_auth_info, (uchar**) &opt_show_slave_auth_info, 0, + &opt_show_slave_auth_info, &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"skip-bdb", OPT_DEPRECATED_OPTION, + "Deprecated option; Exist only for compatiblity with old my.cnf files", + 0, 0, 0, GET_NO_ARG, 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.", - (uchar**) &opt_noacl, (uchar**) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + &opt_noacl, &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, @@ -6731,8 +6838,6 @@ Can't be set to 1 if --log-slave-updates is used.", {"skip-networking", OPT_SKIP_NETWORKING, "Don't allow connection with TCP/IP.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-new", OPT_SKIP_NEW, "Don't use new, possibly wrong routines.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF #ifdef SAFEMALLOC {"skip-safemalloc", OPT_SKIP_SAFEMALLOC, @@ -6744,49 +6849,55 @@ Can't be set to 1 if --log-slave-updates is used.", "Don't allow 'SHOW DATABASE' commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-slave-start", OPT_SKIP_SLAVE_START, - "If set, slave is not autostarted.", (uchar**) &opt_skip_slave_start, - (uchar**) &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + "If set, slave is not autostarted.", &opt_skip_slave_start, + &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-stack-trace", OPT_SKIP_STACK_TRACE, "Don't print a stack trace on failure.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Deprecated option. Use --skip-symbolic-links instead.", + {"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. Deprecated option.", 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 \ -replicating a LOAD DATA INFILE command.", - (uchar**) &slave_load_tmpdir, (uchar**) &slave_load_tmpdir, 0, GET_STR_ALLOC, + "The location where the slave should put its temporary files when " + "replicating a LOAD DATA INFILE command.", + &slave_load_tmpdir, &slave_load_tmpdir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"slave-skip-errors", OPT_SLAVE_SKIP_ERRORS, "Tells the slave thread to continue replication when a query event returns an error from the provided list.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"slave-exec-mode", OPT_SLAVE_EXEC_MODE, - "Modes for how replication events should be executed. Legal values are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will not stop for operations that are idempotent. In STRICT mode, replication will stop on any unexpected difference between the master and the slave.", - (uchar**) &slave_exec_mode_str, (uchar**) &slave_exec_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Modes for how replication events should be executed. Legal values are " + "STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will " + "not stop for operations that are idempotent. In STRICT mode, replication " + "will stop on any unexpected difference between the master and the slave.", + &slave_exec_mode_str, &slave_exec_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"slow-query-log", OPT_SLOW_LOG, - "Enable/disable slow query log.", (uchar**) &opt_slow_log, - (uchar**) &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + "Enable/disable slow query log.", &opt_slow_log, + &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"socket", OPT_SOCKET, "Socket file to use for connection.", - (uchar**) &mysqld_unix_port, (uchar**) &mysqld_unix_port, 0, GET_STR, + &mysqld_unix_port, &mysqld_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION {"sporadic-binlog-dump-fail", OPT_SPORADIC_BINLOG_DUMP_FAIL, "Option used by mysql-test for debugging and testing of replication.", - (uchar**) &opt_sporadic_binlog_dump_fail, - (uchar**) &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + &opt_sporadic_binlog_dump_fail, + &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_REPLICATION */ {"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME, - "The update log is deprecated since version 5.0, is replaced by the binary \ -log and this option does nothing anymore.", + "The update log is deprecated since version 5.0, is replaced by the " + "binary log and this option does nothing anymore.", 0, 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0}, {"sql-mode", OPT_SQL_MODE, - "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.", - (uchar**) &sql_mode_str, (uchar**) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0, + "Syntax: sql-mode=option[,option[,option...]] where option can be one " + "of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, " + "ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.", + &sql_mode_str, &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_OPENSSL #include "sslopt-longopts.h" @@ -6797,7 +6908,7 @@ log and this option does nothing anymore.", NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"symbolic-links", 's', "Enable symbolic link support.", - (uchar**) &my_use_symdir, (uchar**) &my_use_symdir, 0, GET_BOOL, NO_ARG, + &my_use_symdir, &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 @@ -6805,41 +6916,43 @@ log and this option does nothing anymore.", */ IF_VALGRIND(0,1), 0, 0, 0, 0, 0}, {"sysdate-is-now", OPT_SYSDATE_IS_NOW, - "Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. Since 5.0, SYSDATE() returns a `dynamic' value different for different invocations, even within the same statement.", - (uchar**) &global_system_variables.sysdate_is_now, + "Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. " + "Since 5.0, SYSDATE() returns a `dynamic' value different for different " + "invocations, even within the same statement.", + &global_system_variables.sysdate_is_now, 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"tc-heuristic-recover", OPT_TC_HEURISTIC_RECOVER, - "Decision to use in heuristic recover process. Possible values are COMMIT or ROLLBACK.", - (uchar**) &opt_tc_heuristic_recover, (uchar**) &opt_tc_heuristic_recover, + "Decision to use in heuristic recover process. Possible values are COMMIT " + "or ROLLBACK.", &opt_tc_heuristic_recover, &opt_tc_heuristic_recover, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #if defined(ENABLED_DEBUG_SYNC) {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT, "Enable the debug sync facility " "and optionally specify a default wait timeout in seconds. " "A zero value keeps the facility disabled.", - (uchar**) &opt_debug_sync_timeout, 0, + &opt_debug_sync_timeout, 0, 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0}, #endif /* defined(ENABLED_DEBUG_SYNC) */ {"temp-pool", OPT_TEMP_POOL, #if (ENABLE_TEMP_POOL) - "Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.", + "Using this option will cause most temporary files created to use a small " + "set of names, rather than a unique name for each new file.", #else "This option is ignored on this OS.", #endif - (uchar**) &use_temp_pool, (uchar**) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, + &use_temp_pool, &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"test-ignore-wrong-options", OPT_TEST_IGNORE_WRONG_OPTIONS, "Ignore wrong enums values in command line arguments. Useful only for test scripts", - (uchar**) &opt_ignore_wrong_options, (uchar**) &opt_ignore_wrong_options, + &opt_ignore_wrong_options, &opt_ignore_wrong_options, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"test-expect-abort", OPT_TEST_RESTART, "Expect that server aborts with 'abort'; Don't write out server variables on 'abort'. Useful only for test scripts", - (uchar**) &opt_expect_abort, (uchar**) &opt_expect_abort, + &opt_expect_abort, &opt_expect_abort, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"timed_mutexes", OPT_TIMED_MUTEXES, "Specify whether to time mutexes (only InnoDB mutexes are currently supported).", - (uchar**) &timed_mutexes, (uchar**) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0, + &timed_mutexes, &timed_mutexes, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Path for temporary files. Several paths may be specified, separated by a " @@ -6849,138 +6962,145 @@ log and this option does nothing anymore.", "colon (:)" #endif ", in this case they are used in a round-robin fashion.", - (uchar**) &opt_mysql_tmpdir, - (uchar**) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &opt_mysql_tmpdir, &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, {"transaction-isolation", OPT_TX_ISOLATION, "Default transaction isolation level.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"use-symbolic-links", OPT_SYMBOLIC_LINKS, "Enable symbolic link support. Deprecated option; use --symbolic-links instead.", - (uchar**) &my_use_symdir, (uchar**) &my_use_symdir, 0, GET_BOOL, NO_ARG, + {"use-symbolic-links", OPT_SYMBOLIC_LINKS, + "Enable symbolic link support. " + "Deprecated option; use --symbolic-links instead.", + &my_use_symdir, &my_use_symdir, 0, GET_BOOL, NO_ARG, IF_VALGRIND(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}, {"verbose", 'v', "Used with --help option for detailed help.", - (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, - 0, 0}, + &opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"warnings", OPT_WARNINGS, "Deprecated; use --log-warnings instead.", - (uchar**) &global_system_variables.log_warnings, - (uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, - 1, 0, (longlong) ULONG_MAX, 0, 0, 0}, - { "back_log", OPT_BACK_LOG, - "The number of outstanding connection requests MySQL can have. This comes into play when the main MySQL thread gets very many connection requests in a very short time.", - (uchar**) &back_log, (uchar**) &back_log, 0, GET_ULONG, - REQUIRED_ARG, 50, 1, 65535, 0, 1, 0 }, + &global_system_variables.log_warnings, + &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, + 1, 0, ULONG_MAX, 0, 0, 0}, + {"back_log", OPT_BACK_LOG, + "The number of outstanding connection requests MySQL can have. This " + "comes into play when the main MySQL thread gets very many connection " + "requests in a very short time.", &back_log, &back_log, 0, GET_ULONG, + REQUIRED_ARG, 50, 1, 65535, 0, 1, 0 }, {"binlog_cache_size", OPT_BINLOG_CACHE_SIZE, - "The size of the cache to hold the SQL statements for the binary log during a transaction. If you often use big, multi-statement transactions you can increase this to get more performance.", - (uchar**) &binlog_cache_size, (uchar**) &binlog_cache_size, 0, GET_ULONG, + "The size of the cache to hold the SQL statements for the binary log " + "during a transaction. If you often use big, multi-statement " + "transactions you can increase this to get more performance.", + &binlog_cache_size, &binlog_cache_size, 0, GET_ULONG, REQUIRED_ARG, 32*1024L, IO_SIZE, (longlong) ULONG_MAX, 0, IO_SIZE, 0}, {"bulk_insert_buffer_size", OPT_BULK_INSERT_BUFFER_SIZE, - "Size of tree cache used in bulk insert optimization. Note that this is a limit per thread.", - (uchar**) &global_system_variables.bulk_insert_buff_size, - (uchar**) &max_system_variables.bulk_insert_buff_size, + "Size of tree cache used in bulk insert optimization. Note that this " + "is a limit per thread.", &global_system_variables.bulk_insert_buff_size, + &max_system_variables.bulk_insert_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, (longlong) ULONG_MAX, 0, 1, 0}, {"connect_timeout", OPT_CONNECT_TIMEOUT, - "The number of seconds the mysqld server is waiting for a connect packet before responding with 'Bad handshake'.", - (uchar**) &connect_timeout, (uchar**) &connect_timeout, + "The number of seconds the mysqld server is waiting for a connect packet " + "before responding with 'Bad handshake'.", &connect_timeout, &connect_timeout, 0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 }, { "date_format", OPT_DATE_FORMAT, "The DATE format (for future).", - (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE], - (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE], + &opt_date_time_formats[MYSQL_TIMESTAMP_DATE], + &opt_date_time_formats[MYSQL_TIMESTAMP_DATE], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "datetime_format", OPT_DATETIME_FORMAT, "The DATETIME/TIMESTAMP format (for future).", - (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME], - (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME], + &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME], + &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "default_week_format", OPT_DEFAULT_WEEK_FORMAT, "The default week format used by WEEK() functions.", - (uchar**) &global_system_variables.default_week_format, - (uchar**) &max_system_variables.default_week_format, + &global_system_variables.default_week_format, + &max_system_variables.default_week_format, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 0, 1, 0}, {"delayed_insert_limit", OPT_DELAYED_INSERT_LIMIT, - "After inserting delayed_insert_limit rows, the INSERT DELAYED handler will check if there are any SELECT statements pending. If so, it allows these to execute before continuing.", - (uchar**) &delayed_insert_limit, (uchar**) &delayed_insert_limit, 0, GET_ULONG, + "After inserting delayed_insert_limit rows, the INSERT DELAYED handler " + "will check if there are any SELECT statements pending. If so, it allows " + "these to execute before continuing.", + &delayed_insert_limit, &delayed_insert_limit, 0, GET_ULONG, REQUIRED_ARG, DELAYED_LIMIT, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"delayed_insert_timeout", OPT_DELAYED_INSERT_TIMEOUT, "How long a INSERT DELAYED thread should wait for INSERT statements before terminating.", - (uchar**) &delayed_insert_timeout, (uchar**) &delayed_insert_timeout, 0, + &delayed_insert_timeout, &delayed_insert_timeout, 0, GET_ULONG, REQUIRED_ARG, DELAYED_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, { "delayed_queue_size", OPT_DELAYED_QUEUE_SIZE, - "What size queue (in rows) should be allocated for handling INSERT DELAYED. If the queue becomes full, any client that does INSERT DELAYED will wait until there is room in the queue again.", - (uchar**) &delayed_queue_size, (uchar**) &delayed_queue_size, 0, GET_ULONG, + "What size queue (in rows) should be allocated for handling INSERT DELAYED. " + "If the queue becomes full, any client that does INSERT DELAYED will wait " + "until there is room in the queue again.", + &delayed_queue_size, &delayed_queue_size, 0, GET_ULONG, REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"div_precision_increment", OPT_DIV_PRECINCREMENT, "Precision of the result of '/' operator will be increased on that value.", - (uchar**) &global_system_variables.div_precincrement, - (uchar**) &max_system_variables.div_precincrement, 0, GET_ULONG, + &global_system_variables.div_precincrement, + &max_system_variables.div_precincrement, 0, GET_ULONG, REQUIRED_ARG, 4, 0, DECIMAL_MAX_SCALE, 0, 0, 0}, {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS, "If non-zero, binary logs will be purged after expire_logs_days " "days; possible purges happen at startup and at binary log rotation.", - (uchar**) &expire_logs_days, - (uchar**) &expire_logs_days, 0, GET_ULONG, + &expire_logs_days, &expire_logs_days, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 99, 0, 1, 0}, { "flush_time", OPT_FLUSH_TIME, "A dedicated thread is created to flush all tables at the given interval.", - (uchar**) &flush_time, (uchar**) &flush_time, 0, GET_ULONG, REQUIRED_ARG, + &flush_time, &flush_time, 0, GET_ULONG, REQUIRED_ARG, FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1, 0}, { "ft_boolean_syntax", OPT_FT_BOOLEAN_SYNTAX, "List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE).", - 0, 0, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, - "The maximum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.", - (uchar**) &ft_max_word_len, (uchar**) &ft_max_word_len, 0, GET_ULONG, + "The maximum length of the word to be included in a FULLTEXT index. " + "Note: FULLTEXT indexes must be rebuilt after changing this variable.", + &ft_max_word_len, &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10, HA_FT_MAXCHARLEN, 0, 1, 0}, { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, - "The minimum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.", - (uchar**) &ft_min_word_len, (uchar**) &ft_min_word_len, 0, GET_ULONG, + "The minimum length of the word to be included in a FULLTEXT index. " + "Note: FULLTEXT indexes must be rebuilt after changing this variable.", + &ft_min_word_len, &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN, 0, 1, 0}, { "ft_query_expansion_limit", OPT_FT_QUERY_EXPANSION_LIMIT, "Number of best matches to use for query expansion.", - (uchar**) &ft_query_expansion_limit, (uchar**) &ft_query_expansion_limit, 0, GET_ULONG, + &ft_query_expansion_limit, &ft_query_expansion_limit, 0, GET_ULONG, REQUIRED_ARG, 20, 0, 1000, 0, 1, 0}, { "ft_stopword_file", OPT_FT_STOPWORD_FILE, "Use stopwords from this file instead of built-in list.", - (uchar**) &ft_stopword_file, (uchar**) &ft_stopword_file, 0, GET_STR, + &ft_stopword_file, &ft_stopword_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "group_concat_max_len", OPT_GROUP_CONCAT_MAX_LEN, "The maximum length of the result of function group_concat.", - (uchar**) &global_system_variables.group_concat_max_len, - (uchar**) &max_system_variables.group_concat_max_len, 0, GET_ULONG, + &global_system_variables.group_concat_max_len, + &max_system_variables.group_concat_max_len, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, (longlong) ULONG_MAX, 0, 1, 0}, {"interactive_timeout", OPT_INTERACTIVE_TIMEOUT, - "The number of seconds the server waits for activity on an interactive connection before closing it.", - (uchar**) &global_system_variables.net_interactive_timeout, - (uchar**) &max_system_variables.net_interactive_timeout, 0, + "The number of seconds the server waits for activity on an interactive " + "connection before closing it.", + &global_system_variables.net_interactive_timeout, + &max_system_variables.net_interactive_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, {"join_buffer_size", OPT_JOIN_BUFF_SIZE, "The size of the buffer that is used for full joins.", - (uchar**) &global_system_variables.join_buff_size, - (uchar**) &max_system_variables.join_buff_size, 0, GET_ULONG, + &global_system_variables.join_buff_size, + &max_system_variables.join_buff_size, 0, GET_ULONG, REQUIRED_ARG, 128*1024L, 128+MALLOC_OVERHEAD, (longlong) ULONG_MAX, MALLOC_OVERHEAD, 128, 0}, {"join_cache_level", OPT_JOIN_CACHE_LEVEL, "Controls what join operations can be executed with join buffers. Odd numbers are used for plain join buffers while even numbers are used for linked buffers", - (uchar**) &global_system_variables.join_cache_level, - (uchar**) &max_system_variables.join_cache_level, + &global_system_variables.join_cache_level, + &max_system_variables.join_cache_level, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 8, 0, 1, 0}, {"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE, "Don't overwrite stale .MYD and .MYI even if no directory is specified.", - (uchar**) &global_system_variables.keep_files_on_create, - (uchar**) &max_system_variables.keep_files_on_create, + &global_system_variables.keep_files_on_create, + &max_system_variables.keep_files_on_create, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "The size of the buffer used for index blocks for MyISAM tables. Increase " "this to get better index handling (for all reads and multiple writes) to " "as much as you can afford; 1GB on a 4GB machine that mainly runs MySQL is " "quite common.", - (uchar**) &dflt_key_cache_var.param_buff_size, - (uchar**) 0, - 0, (GET_ULL | GET_ASK_ADDR), + &dflt_key_cache_var.param_buff_size, NULL, NULL, (GET_ULL | GET_ASK_ADDR), REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, SIZE_T_MAX, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, @@ -6988,60 +7108,58 @@ log and this option does nothing anymore.", "until it is considered aged enough to be downgraded to a warm block. " "This specifies the percentage ratio of that number of hits to the total " "number of blocks in key cache.", - (uchar**) &dflt_key_cache_var.param_age_threshold, - (uchar**) 0, - 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, - 300, 100, (longlong) ULONG_MAX, 0, 100, 0}, + &dflt_key_cache_var.param_age_threshold, 0, 0, + (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, 300, 100, (longlong) ULONG_MAX, + 0, 100, 0}, {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "The default size of key cache blocks.", - (uchar**) &dflt_key_cache_var.param_block_size, - (uchar**) 0, - 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, - KEY_CACHE_BLOCK_SIZE, 512, 1024 * 16, 0, 512, 0}, + &dflt_key_cache_var.param_block_size, NULL, NULL, (GET_ULONG | GET_ASK_ADDR), + REQUIRED_ARG, KEY_CACHE_BLOCK_SIZE, 512, 1024 * 16, 0, 512, 0}, {"key_cache_division_limit", OPT_KEY_CACHE_DIVISION_LIMIT, - "The minimum percentage of warm blocks in a key cache.", - (uchar**) &dflt_key_cache_var.param_division_limit, - (uchar**) 0, - 0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, - 1, 100, 0, 1, 0}, + "The minimum percentage of warm blocks in key cache.", + &dflt_key_cache_var.param_division_limit, 0, 0, + (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, 1, 100, 0, 1, 0}, {"key_cache_segments", OPT_KEY_CACHE_PARTITIONS, "The number of segments in a key cache", - (uchar**) &dflt_key_cache_var.param_partitions, - (uchar**) 0, + &dflt_key_cache_var.param_partitions, 0, 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, DEFAULT_KEY_CACHE_PARTITIONS, 0, MAX_KEY_CACHE_PARTITIONS, 0, 1, 0}, {"log-slow-filter", OPT_LOG_SLOW_FILTER, - "Log only the queries that followed certain execution plan. Multiple flags allowed in a comma-separated string. [admin, filesort, filesort_on_disk, full_join, full_scan, query_cache, query_cache_miss, tmp_table, tmp_table_on_disk]. Sets log-slow-admin-command to ON", + "Log only the queries that followed certain execution plan. Multiple flags " + "allowed in a comma-separated string. [admin, filesort, filesort_on_disk, " + "full_join, full_scan, query_cache, query_cache_miss, tmp_table, " + "tmp_table_on_disk]. Sets log-slow-admin-command to ON", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, QPLAN_ALWAYS_SET, 0, 0}, {"log-slow-rate_limit", OPT_LOG_SLOW_RATE_LIMIT, - "If set, only write to slow log every 'log_slow_rate_limit' query (use this to reduce output on slow query log)", - (uchar**) &global_system_variables.log_slow_rate_limit, - (uchar**) &max_system_variables.log_slow_rate_limit, 0, GET_ULONG, + "If set, only write to slow log every 'log_slow_rate_limit' query (use " + "this to reduce output on slow query log)", + &global_system_variables.log_slow_rate_limit, + &max_system_variables.log_slow_rate_limit, 0, GET_ULONG, REQUIRED_ARG, 1, 1, ~0L, 0, 1L, 0}, {"log-slow-verbosity", OPT_LOG_SLOW_VERBOSITY, - "Choose how verbose the messages to your slow log will be. Multiple flags allowed in a comma-separated string. [query_plan, innodb]", + "Choose how verbose the messages to your slow log will be. Multiple flags " + "allowed in a comma-separated string. [query_plan, innodb]", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"log-slow-file", OPT_SLOW_QUERY_LOG_FILE, "Log slow queries to given log file. Defaults logging to hostname-slow.log", - (uchar**) &opt_slow_logname, (uchar**) &opt_slow_logname, 0, GET_STR, + &opt_slow_logname, &opt_slow_logname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to " "execute. The argument will be treated as a decimal value with " "microsecond precision.", - (uchar**) &long_query_time, (uchar**) &long_query_time, 0, GET_DOUBLE, + &long_query_time, &long_query_time, 0, GET_DOUBLE, REQUIRED_ARG, 10, 0, LONG_TIMEOUT, 0, 0, 0}, {"log-slow-time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file. " "The argument will be treated as a decimal value with microsecond precission.", - (uchar**) &long_query_time, (uchar**) &long_query_time, 0, GET_DOUBLE, + &long_query_time, &long_query_time, 0, GET_DOUBLE, REQUIRED_ARG, 10, 0, LONG_TIMEOUT, 0, 0, 0}, {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES, "If set to 1, table names are stored in lowercase on disk and table names " "will be case-insensitive. Should be set to 2 if you are using a case-" "insensitive file system.", - (uchar**) &lower_case_table_names, - (uchar**) &lower_case_table_names, 0, GET_UINT, OPT_ARG, + &lower_case_table_names, &lower_case_table_names, 0, GET_UINT, OPT_ARG, #ifdef FN_NO_CASE_SENCE 1 #else @@ -7050,95 +7168,99 @@ log and this option does nothing anymore.", , 0, 2, 0, 1, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "The maximum packet length to send to or receive from server.", - (uchar**) &global_system_variables.max_allowed_packet, - (uchar**) &max_system_variables.max_allowed_packet, 0, GET_ULONG, - REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, 0, 1024, 0}, + &global_system_variables.max_allowed_packet, + &max_system_variables.max_allowed_packet, 0, GET_ULONG, + REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", - (uchar**) &max_binlog_cache_size, (uchar**) &max_binlog_cache_size, 0, + &max_binlog_cache_size, &max_binlog_cache_size, 0, GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, {"max_binlog_size", OPT_MAX_BINLOG_SIZE, - "Binary log will be rotated automatically when the size exceeds this \ -value. Will also apply to relay logs if max_relay_log_size is 0. \ -The minimum value for this variable is 4096.", - (uchar**) &max_binlog_size, (uchar**) &max_binlog_size, 0, GET_ULONG, + "Binary log will be rotated automatically when the size exceeds this " + "value. Will also apply to relay logs if max_relay_log_size is 0. " + "The minimum value for this variable is 4096.", + &max_binlog_size, &max_binlog_size, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L*1024L, IO_SIZE, 1024*1024L*1024L, 0, IO_SIZE, 0}, {"max_connect_errors", OPT_MAX_CONNECT_ERRORS, - "If there is more than this number of interrupted connections from a host this host will be blocked from further connections.", - (uchar**) &max_connect_errors, (uchar**) &max_connect_errors, 0, GET_ULONG, - REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, (longlong) ULONG_MAX, 0, 1, 0}, + "If there is more than this number of interrupted connections from a host " + "this host will be blocked from further connections.", + &max_connect_errors, &max_connect_errors, 0, GET_ULONG, + REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, (longlong) ULONG_MAX, 0, 1, 0}, // Default max_connections of 151 is larger than Apache's default max // children, to avoid "too many connections" error in a common setup {"max_connections", OPT_MAX_CONNECTIONS, - "The number of simultaneous clients allowed.", (uchar**) &max_connections, - (uchar**) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 100000, 0, 1, - 0}, + "The number of simultaneous clients allowed.", &max_connections, + &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.", - (uchar**) &global_system_variables.max_insert_delayed_threads, - (uchar**) &max_system_variables.max_insert_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.", + &global_system_variables.max_insert_delayed_threads, + &max_system_variables.max_insert_delayed_threads, 0, GET_ULONG, REQUIRED_ARG, 20, 0, 16384, 0, 1, 0}, {"max_error_count", OPT_MAX_ERROR_COUNT, "Max number of errors/warnings to store for a statement.", - (uchar**) &global_system_variables.max_error_count, - (uchar**) &max_system_variables.max_error_count, + &global_system_variables.max_error_count, + &max_system_variables.max_error_count, 0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 0, 65535, 0, 1, 0}, {"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE, "Don't allow creation of heap tables bigger than this.", - (uchar**) &global_system_variables.max_heap_table_size, - (uchar**) &max_system_variables.max_heap_table_size, 0, GET_ULL, + &global_system_variables.max_heap_table_size, + &max_system_variables.max_heap_table_size, 0, GET_ULL, REQUIRED_ARG, 16*1024*1024L, 16384, MAX_MEM_TABLE_SIZE, MALLOC_OVERHEAD, 1024, 0}, {"max_join_size", OPT_MAX_JOIN_SIZE, "Joins that are probably going to read more than max_join_size records return an error.", - (uchar**) &global_system_variables.max_join_size, - (uchar**) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG, + &global_system_variables.max_join_size, + &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG, HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, {"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA, "Max number of bytes in sorted records.", - (uchar**) &global_system_variables.max_length_for_sort_data, - (uchar**) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG, + &global_system_variables.max_length_for_sort_data, + &max_system_variables.max_length_for_sort_data, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0}, {"max_prepared_stmt_count", OPT_MAX_PREPARED_STMT_COUNT, "Maximum number of prepared statements in the server.", - (uchar**) &max_prepared_stmt_count, (uchar**) &max_prepared_stmt_count, + &max_prepared_stmt_count, &max_prepared_stmt_count, 0, GET_ULONG, REQUIRED_ARG, 16382, 0, 1*1024*1024, 0, 1, 0}, {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE, - "If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 excepted, the minimum value for this variable is 4096.", - (uchar**) &max_relay_log_size, (uchar**) &max_relay_log_size, 0, GET_ULONG, + "If non-zero: relay log will be rotated automatically when the size " + "exceeds this value; if zero (the default): when the size exceeds " + "max_binlog_size. 0 excepted, the minimum value for this variable is 4096.", + &max_relay_log_size, &max_relay_log_size, 0, GET_ULONG, REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0}, { "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY, "Limit assumed max number of seeks when looking up rows based on a key.", - (uchar**) &global_system_variables.max_seeks_for_key, - (uchar**) &max_system_variables.max_seeks_for_key, 0, GET_ULONG, + &global_system_variables.max_seeks_for_key, + &max_system_variables.max_seeks_for_key, 0, GET_ULONG, REQUIRED_ARG, (longlong) ULONG_MAX, 1, (longlong) ULONG_MAX, 0, 1, 0 }, {"max_sort_length", OPT_MAX_SORT_LENGTH, - "The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).", - (uchar**) &global_system_variables.max_sort_length, - (uchar**) &max_system_variables.max_sort_length, 0, GET_ULONG, + "The number of bytes to use when sorting BLOB or TEXT values (only the " + "first max_sort_length bytes of each value are used; the rest are ignored).", + &global_system_variables.max_sort_length, + &max_system_variables.max_sort_length, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0}, {"max_sp_recursion_depth", OPT_MAX_SP_RECURSION_DEPTH, "Maximum stored procedure recursion depth. (discussed with docs).", - (uchar**) &global_system_variables.max_sp_recursion_depth, - (uchar**) &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG, + &global_system_variables.max_sp_recursion_depth, + &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG, OPT_ARG, 0, 0, 255, 0, 1, 0 }, {"max_tmp_tables", OPT_MAX_TMP_TABLES, "Maximum number of temporary tables a client can keep open at a time.", - (uchar**) &global_system_variables.max_tmp_tables, - (uchar**) &max_system_variables.max_tmp_tables, 0, GET_ULONG, + &global_system_variables.max_tmp_tables, + &max_system_variables.max_tmp_tables, 0, GET_ULONG, REQUIRED_ARG, 32, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"max_user_connections", OPT_MAX_USER_CONNECTIONS, "The maximum number of active connections for a single user (0 = no limit).", - (uchar**) &max_user_connections, (uchar**) &max_user_connections, 0, GET_UINT, + &max_user_connections, &max_user_connections, 0, GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0}, {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, "After this many write locks, allow some read locks to run in between.", - (uchar**) &max_write_lock_count, (uchar**) &max_write_lock_count, 0, GET_ULONG, + &max_write_lock_count, &max_write_lock_count, 0, GET_ULONG, REQUIRED_ARG, (longlong) ULONG_MAX, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT, "Don't log queries which examine less than min_examined_row_limit rows to file.", - (uchar**) &global_system_variables.min_examined_row_limit, - (uchar**) &max_system_variables.min_examined_row_limit, 0, GET_ULONG, + &global_system_variables.min_examined_row_limit, + &max_system_variables.min_examined_row_limit, 0, GET_ULONG, REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1L, 0}, {"mrr_buffer_size", OPT_MRR_BUFFER_SIZE, "Size of buffer to use when using MRR with range access", @@ -7148,87 +7270,106 @@ The minimum value for this variable is 4096.", INT_MAX32, MALLOC_OVERHEAD, 1 /* Small to be able to do tests */ , 0}, {"myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "Block size to be used for MyISAM index pages.", - (uchar**) &opt_myisam_block_size, - (uchar**) &opt_myisam_block_size, 0, GET_ULONG, REQUIRED_ARG, + &opt_myisam_block_size, &opt_myisam_block_size, 0, GET_ULONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0}, {"myisam_data_pointer_size", OPT_MYISAM_DATA_POINTER_SIZE, "Default pointer size to be used for MyISAM tables.", - (uchar**) &myisam_data_pointer_size, - (uchar**) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, + &myisam_data_pointer_size, + &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, 6, 2, 7, 0, 1, 0}, + {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, + "This is a deprecated option that does nothing anymore. " + "It will be removed in MySQL " VER_CELOSIA, + &global_system_variables.myisam_max_extra_sort_file_size, + &max_system_variables.myisam_max_extra_sort_file_size, + 0, GET_ULL, REQUIRED_ARG, (ulonglong) INT_MAX32, + 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0}, {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE, - "Don't use the fast sort index method to created index if the temporary file would get bigger than this.", - (uchar**) &global_system_variables.myisam_max_sort_file_size, - (uchar**) &max_system_variables.myisam_max_sort_file_size, 0, + "Don't use the fast sort index method to created index if the temporary " + "file would get bigger than this.", + &global_system_variables.myisam_max_sort_file_size, + &max_system_variables.myisam_max_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE, 0, 1024*1024, 0}, {"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE, "Can be used to restrict the total memory used for memory mmaping of myisam files", - (uchar**) &myisam_mmap_size, (uchar**) &myisam_mmap_size, 0, + &myisam_mmap_size, &myisam_mmap_size, 0, GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0}, {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, "Specifies whether several threads should be used when repairing MyISAM " "tables. For values > 1, one thread is used per index. The value of 1 " "disables parallel repair.", - (uchar**) &global_system_variables.myisam_repair_threads, - (uchar**) &max_system_variables.myisam_repair_threads, 0, + &global_system_variables.myisam_repair_threads, + &max_system_variables.myisam_repair_threads, 0, GET_ULONG, REQUIRED_ARG, 1, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"myisam_sort_buffer_size", OPT_MYISAM_SORT_BUFFER_SIZE, - "The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", - (uchar**) &global_system_variables.myisam_sort_buff_size, - (uchar**) &max_system_variables.myisam_sort_buff_size, 0, + "The buffer that is allocated when sorting the index when doing a REPAIR " + "or when creating indexes with CREATE INDEX or ALTER TABLE.", + &global_system_variables.myisam_sort_buff_size, + &max_system_variables.myisam_sort_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, (longlong) ULONG_MAX, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, "Use memory mapping for reading and writing MyISAM tables.", - (uchar**) &opt_myisam_use_mmap, - (uchar**) &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, 0, - 0, 0, 0, 0, 0}, + &opt_myisam_use_mmap, &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"myisam_stats_method", OPT_MYISAM_STATS_METHOD, "Specifies how MyISAM index statistics collection code should threat NULLs. " "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), " "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".", - (uchar**) &myisam_stats_method_str, (uchar**) &myisam_stats_method_str, 0, + &myisam_stats_method_str, &myisam_stats_method_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "Buffer length for TCP/IP and socket communication.", - (uchar**) &global_system_variables.net_buffer_length, - (uchar**) &max_system_variables.net_buffer_length, 0, GET_ULONG, + &global_system_variables.net_buffer_length, + &max_system_variables.net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 16384, 1024, 1024*1024L, 0, 1024, 0}, {"net_read_timeout", OPT_NET_READ_TIMEOUT, "Number of seconds to wait for more data from a connection before aborting the read.", - (uchar**) &global_system_variables.net_read_timeout, - (uchar**) &max_system_variables.net_read_timeout, 0, GET_ULONG, + &global_system_variables.net_read_timeout, + &max_system_variables.net_read_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_READ_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, {"net_retry_count", OPT_NET_RETRY_COUNT, "If a read on a communication port is interrupted, retry this many times before giving up.", - (uchar**) &global_system_variables.net_retry_count, - (uchar**) &max_system_variables.net_retry_count,0, + &global_system_variables.net_retry_count, + &max_system_variables.net_retry_count,0, GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"net_write_timeout", OPT_NET_WRITE_TIMEOUT, "Number of seconds to wait for a block to be written to a connection before " "aborting the write.", - (uchar**) &global_system_variables.net_write_timeout, - (uchar**) &max_system_variables.net_write_timeout, 0, GET_ULONG, + &global_system_variables.net_write_timeout, + &max_system_variables.net_write_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, - {"old", OPT_OLD_MODE, "Use compatible behavior.", - (uchar**) &global_system_variables.old_mode, - (uchar**) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG, + { "old", OPT_OLD_MODE, "Use compatible behavior.", + &global_system_variables.old_mode, + &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"open_files_limit", OPT_OPEN_FILES_LIMIT, - "If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.", - (uchar**) &open_files_limit, (uchar**) &open_files_limit, 0, GET_ULONG, + "If this is not 0, then mysqld will use this value to reserve file " + "descriptors to use with setrlimit(). If this value is 0 then mysqld " + "will reserve max_connections*5 or max_connections + table_cache*2 " + "(whichever is larger) number of files.", + &open_files_limit, &open_files_limit, 0, GET_ULONG, REQUIRED_ARG, 0, 0, OS_FILE_LIMIT, 0, 1, 0}, {"optimizer_prune_level", OPT_OPTIMIZER_PRUNE_LEVEL, - "Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search; 1 - prune plans based on number of retrieved rows.", - (uchar**) &global_system_variables.optimizer_prune_level, - (uchar**) &max_system_variables.optimizer_prune_level, + "Controls the heuristic(s) applied during query optimization to prune " + "less-promising partial plans from the optimizer search space. Meaning: " + "0 - do not apply any heuristic, thus perform exhaustive search; 1 - " + "prune plans based on number of retrieved rows.", + &global_system_variables.optimizer_prune_level, + &max_system_variables.optimizer_prune_level, 0, GET_ULONG, OPT_ARG, 1, 0, 1, 0, 1, 0}, {"optimizer_search_depth", OPT_OPTIMIZER_SEARCH_DEPTH, - "Maximum depth of search performed by the query optimizer. Values larger than the number of relations in a query result in better query plans, but take longer to compile a query. Smaller values than the number of tables in a relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to MAX_TABLES+2, the optimizer will switch to the original find_best (used for testing/comparison).", - (uchar**) &global_system_variables.optimizer_search_depth, - (uchar**) &max_system_variables.optimizer_search_depth, + "Maximum depth of search performed by the query optimizer. Values larger " + "than the number of relations in a query result in better query plans, " + "but take longer to compile a query. Smaller values than the number of " + "tables in a relation result in faster optimization, but may produce " + "very bad query plans. If set to 0, the system will automatically pick " + "a reasonable value; if set to MAX_TABLES+2, the optimizer will switch " + "to the original find_best (used for testing/comparison).", + &global_system_variables.optimizer_search_depth, + &max_system_variables.optimizer_search_depth, 0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0}, {"optimizer_switch", OPT_OPTIMIZER_SWITCH, "optimizer_switch=option=val[,option=val...], where option={index_merge, " @@ -7240,68 +7381,72 @@ The minimum value for this variable is 4096.", ", table_elimination" #endif "} and val={on, off, default}.", - (uchar**) &optimizer_switch_str, (uchar**) &optimizer_switch_str, 0, GET_STR, REQUIRED_ARG, - /*OPTIMIZER_SWITCH_DEFAULT*/0, - 0, 0, 0, 0, 0}, + &optimizer_switch_str, &optimizer_switch_str, 0, GET_STR, REQUIRED_ARG, + /*OPTIMIZER_SWITCH_DEFAULT*/0, 0, 0, 0, 0, 0}, {"plugin_dir", OPT_PLUGIN_DIR, "Directory for plugins.", - (uchar**) &opt_plugin_dir_ptr, (uchar**) &opt_plugin_dir_ptr, 0, + &opt_plugin_dir_ptr, &opt_plugin_dir_ptr, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"plugin-load", OPT_PLUGIN_LOAD, "Optional semicolon-separated list of plugins to load, where each plugin is " "identified as name=library, where name is the plugin name and library " "is the plugin library in plugin_dir.", - (uchar**) &opt_plugin_load, (uchar**) &opt_plugin_load, 0, + &opt_plugin_load, &opt_plugin_load, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-maturity", OPT_PLUGIN_MATURITY, + "The lowest desirable plugin maturity. Plugins less mature than that will not be installed or loaded.", + (uchar**) &plugin_maturity, (uchar**) &plugin_maturity, &plugin_maturity_values, + GET_ENUM, REQUIRED_ARG, server_maturity, 0, 0, 0, 0, 0}, {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE, "The size of the buffer that is allocated when preloading indexes.", - (uchar**) &global_system_variables.preload_buff_size, - (uchar**) &max_system_variables.preload_buff_size, 0, GET_ULONG, + &global_system_variables.preload_buff_size, + &max_system_variables.preload_buff_size, 0, GET_ULONG, REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, {"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE, "Allocation block size for query parsing and execution.", - (uchar**) &global_system_variables.query_alloc_block_size, - (uchar**) &max_system_variables.query_alloc_block_size, 0, GET_ULONG, + &global_system_variables.query_alloc_block_size, + &max_system_variables.query_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, (longlong) ULONG_MAX, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_limit", OPT_QUERY_CACHE_LIMIT, "Don't cache results that are bigger than this.", - (uchar**) &query_cache_limit, (uchar**) &query_cache_limit, 0, GET_ULONG, + &query_cache_limit, &query_cache_limit, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L, 0, (longlong) ULONG_MAX, 0, 1, 0}, {"query_cache_min_res_unit", OPT_QUERY_CACHE_MIN_RES_UNIT, "Minimal size of unit in which space for results is allocated (last unit " "will be trimmed after writing all result data).", - (uchar**) &query_cache_min_res_unit, (uchar**) &query_cache_min_res_unit, + &query_cache_min_res_unit, &query_cache_min_res_unit, 0, GET_ULONG, REQUIRED_ARG, QUERY_CACHE_MIN_RESULT_DATA_SIZE, 0, (longlong) ULONG_MAX, 0, 1, 0}, #endif /*HAVE_QUERY_CACHE*/ {"query_cache_size", OPT_QUERY_CACHE_SIZE, "The memory allocated to store results from old queries.", - (uchar**) &query_cache_size, (uchar**) &query_cache_size, 0, GET_ULONG, + &query_cache_size, &query_cache_size, 0, GET_ULONG, REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_type", OPT_QUERY_CACHE_TYPE, - "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results except SELECT SQL_NO_CACHE ... queries. 2 = DEMAND = Cache only SELECT SQL_CACHE ... queries.", - (uchar**) &global_system_variables.query_cache_type, - (uchar**) &max_system_variables.query_cache_type, + "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results " + "except SELECT SQL_NO_CACHE ... queries. 2 = DEMAND = Cache only SELECT " + "SQL_CACHE ... queries.", &global_system_variables.query_cache_type, + &max_system_variables.query_cache_type, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0}, {"query_cache_wlock_invalidate", OPT_QUERY_CACHE_WLOCK_INVALIDATE, "Invalidate queries in query cache on LOCK for write.", - (uchar**) &global_system_variables.query_cache_wlock_invalidate, - (uchar**) &max_system_variables.query_cache_wlock_invalidate, + &global_system_variables.query_cache_wlock_invalidate, + &max_system_variables.query_cache_wlock_invalidate, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, #endif /*HAVE_QUERY_CACHE*/ {"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE, "Persistent buffer for query parsing and execution.", - (uchar**) &global_system_variables.query_prealloc_size, - (uchar**) &max_system_variables.query_prealloc_size, 0, GET_ULONG, + &global_system_variables.query_prealloc_size, + &max_system_variables.query_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE, (longlong) ULONG_MAX, 0, 1024, 0}, {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE, "Allocation block size for storing ranges during optimization.", - (uchar**) &global_system_variables.range_alloc_block_size, - (uchar**) &max_system_variables.range_alloc_block_size, 0, GET_ULONG, + &global_system_variables.range_alloc_block_size, + &max_system_variables.range_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, RANGE_ALLOC_BLOCK_SIZE, (longlong) ULONG_MAX, 0, 1024, 0}, {"rowid_merge_buff_size", OPT_ROWID_MERGE_BUFF_SIZE, @@ -7310,149 +7455,160 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.rowid_merge_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8*1024*1024L, 0, MAX_MEM_TABLE_SIZE/2, 0, 1, 0}, {"read_buffer_size", OPT_RECORD_BUFFER, - "Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.", - (uchar**) &global_system_variables.read_buff_size, - (uchar**) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, + "Each thread that does a sequential scan allocates a buffer of this size " + "for each table it scans. If you do many sequential scans, you may want " + "to increase this value.", &global_system_variables.read_buff_size, + &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, {"read_only", OPT_READONLY, "Make all non-temporary tables read-only, with the exception of replication " "(slave) threads and users with the SUPER privilege.", - (uchar**) &opt_readonly, - (uchar**) &opt_readonly, + &opt_readonly, + &opt_readonly, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"read_rnd_buffer_size", OPT_RECORD_RND_BUFFER, "When reading rows in sorted order after a sort, the rows are read through " "this buffer to avoid disk seeks. If not set, then it's set to the value of " "record_buffer.", - (uchar**) &global_system_variables.read_rnd_buff_size, - (uchar**) &max_system_variables.read_rnd_buff_size, 0, + &global_system_variables.read_rnd_buff_size, + &max_system_variables.read_rnd_buff_size, 0, GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, {"record_buffer", OPT_RECORD_BUFFER_OLD, "Alias for read_buffer_size. This variable is deprecated and will be removed in a future release.", - (uchar**) &global_system_variables.read_buff_size, - (uchar**) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, + &global_system_variables.read_buff_size, + &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, #ifdef HAVE_REPLICATION {"relay_log_purge", OPT_RELAY_LOG_PURGE, "0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.", - (uchar**) &relay_log_purge, - (uchar**) &relay_log_purge, 0, GET_BOOL, NO_ARG, + &relay_log_purge, + &relay_log_purge, 0, GET_BOOL, NO_ARG, 1, 0, 1, 0, 1, 0}, {"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT, "Maximum space to use for all relay logs.", - (uchar**) &relay_log_space_limit, - (uchar**) &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, + &relay_log_space_limit, + &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL, "Use compression on master/slave protocol.", - (uchar**) &opt_slave_compressed_protocol, - (uchar**) &opt_slave_compressed_protocol, + &opt_slave_compressed_protocol, + &opt_slave_compressed_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"slave_net_timeout", OPT_SLAVE_NET_TIMEOUT, "Number of seconds to wait for more data from a master/slave connection before aborting the read.", - (uchar**) &slave_net_timeout, (uchar**) &slave_net_timeout, 0, + &slave_net_timeout, &slave_net_timeout, 0, GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, {"slave_transaction_retries", OPT_SLAVE_TRANS_RETRIES, "Number of times the slave SQL thread will retry a transaction in case " "it failed with a deadlock or elapsed lock wait timeout, " "before giving up and stopping.", - (uchar**) &slave_trans_retries, (uchar**) &slave_trans_retries, 0, + &slave_trans_retries, &slave_trans_retries, 0, GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, #endif /* HAVE_REPLICATION */ {"slow_launch_time", OPT_SLOW_LAUNCH_TIME, - "If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.", - (uchar**) &slow_launch_time, (uchar**) &slow_launch_time, 0, GET_ULONG, + "If creating the thread takes longer than this value (in seconds), " + "the Slow_launch_threads counter will be incremented.", + &slow_launch_time, &slow_launch_time, 0, GET_ULONG, REQUIRED_ARG, 2L, 0L, LONG_TIMEOUT, 0, 1, 0}, {"sort_buffer_size", OPT_SORT_BUFFER, "Each thread that needs to do a sort allocates a buffer of this size.", - (uchar**) &global_system_variables.sortbuff_size, - (uchar**) &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG, + &global_system_variables.sortbuff_size, + &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG, MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, (longlong) ULONG_MAX, MALLOC_OVERHEAD, 1, 0}, {"sync-binlog", OPT_SYNC_BINLOG, "Synchronously flush binary log to disk after every #th event. " "Use 0 (default) to disable synchronous flushing.", - (uchar**) &sync_binlog_period, (uchar**) &sync_binlog_period, 0, GET_ULONG, + &sync_binlog_period, &sync_binlog_period, 0, GET_ULONG, REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1, 0}, {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", - (uchar**) &opt_sync_frm, (uchar**) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, + &opt_sync_frm, &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"sync-sys", OPT_SYNC, + "Enable/disable system sync calls. Should only be turned off when running " + "tests or debugging!!", + &opt_sync, &opt_sync, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"table_cache", OPT_TABLE_OPEN_CACHE, "Deprecated; use --table_open_cache instead.", - (uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG, + &table_cache_size, &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0}, {"table_definition_cache", OPT_TABLE_DEF_CACHE, "The number of cached table definitions.", - (uchar**) &table_def_size, (uchar**) &table_def_size, + &table_def_size, &table_def_size, 0, GET_ULONG, REQUIRED_ARG, TABLE_DEF_CACHE_DEFAULT, TABLE_DEF_CACHE_MIN, 512*1024L, 0, 1, 0}, {"table_open_cache", OPT_TABLE_OPEN_CACHE, "The number of cached open tables.", - (uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG, + &table_cache_size, &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0}, {"table_lock_wait_timeout", OPT_TABLE_LOCK_WAIT_TIMEOUT, "Timeout in seconds to wait for a table level lock before returning an " "error. Used only if the connection has active cursors.", - (uchar**) &table_lock_wait_timeout, (uchar**) &table_lock_wait_timeout, + &table_lock_wait_timeout, &table_lock_wait_timeout, 0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0}, {"thread_cache_size", OPT_THREAD_CACHE_SIZE, "How many threads we should keep in a cache for reuse.", - (uchar**) &thread_cache_size, (uchar**) &thread_cache_size, 0, GET_ULONG, + &thread_cache_size, &thread_cache_size, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 16384, 0, 1, 0}, {"thread_concurrency", OPT_THREAD_CONCURRENCY, - "Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.", - (uchar**) &concurrency, (uchar**) &concurrency, 0, GET_ULONG, REQUIRED_ARG, + "Permits the application to give the threads system a hint for the " + "desired number of threads that should be run at the same time.", + &concurrency, &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'.", - (uchar**) &thread_pool_size, (uchar**) &thread_pool_size, 0, GET_ULONG, + &thread_pool_size, &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.", (uchar**) &my_thread_stack_size, - (uchar**) &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, + "The stack size for each thread.", &my_thread_stack_size, + &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, (sizeof(void*)<=4)?1024L*128L: ((256-16)*1024L), (longlong) ULONG_MAX, 0, 1024, 0}, { "time_format", OPT_TIME_FORMAT, "The TIME format (for future).", - (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME], - (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME], + &opt_date_time_formats[MYSQL_TIMESTAMP_TIME], + &opt_date_time_formats[MYSQL_TIMESTAMP_TIME], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tmp_table_size", OPT_TMP_TABLE_SIZE, - "If an internal in-memory temporary table exceeds this size, MySQL will" - " automatically convert it to an on-disk MyISAM/Maria table.", - (uchar**) &global_system_variables.tmp_table_size, - (uchar**) &max_system_variables.tmp_table_size, 0, GET_ULL, - REQUIRED_ARG, 16*1024*1024L, 0, MAX_MEM_TABLE_SIZE, 0, 1, 0}, + "If an internal in-memory temporary table exceeds this size, MySQL will " + "automatically convert it to an on-disk MyISAM/Aria table.", + &global_system_variables.tmp_table_size, + &max_system_variables.tmp_table_size, 0, GET_ULL, + REQUIRED_ARG, 16*1024*1024L, 1024, MAX_MEM_TABLE_SIZE, 0, 1, 0}, {"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE, "Allocation block size for transactions to be stored in binary log.", - (uchar**) &global_system_variables.trans_alloc_block_size, - (uchar**) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG, + &global_system_variables.trans_alloc_block_size, + &max_system_variables.trans_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, (longlong) ULONG_MAX, 0, 1024, 0}, {"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE, "Persistent buffer for transactions to be stored in binary log.", - (uchar**) &global_system_variables.trans_prealloc_size, - (uchar**) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, + &global_system_variables.trans_prealloc_size, + &max_system_variables.trans_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, (longlong) ULONG_MAX, 0, 1024, 0}, {"thread_handling", OPT_THREAD_HANDLING, "Define threads usage for handling queries: " "one-thread-per-connection or no-threads.", - (uchar**) &opt_thread_handling, (uchar**) &opt_thread_handling, + &opt_thread_handling, &opt_thread_handling, 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).", - (uchar**) &global_system_variables.updatable_views_with_limit, - (uchar**) &max_system_variables.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).", + &global_system_variables.updatable_views_with_limit, + &max_system_variables.updatable_views_with_limit, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 1, 0, 1, 0}, {"wait_timeout", OPT_WAIT_TIMEOUT, "The number of seconds the server waits for activity on a connection before closing it.", - (uchar**) &global_system_variables.net_wait_timeout, - (uchar**) &max_system_variables.net_wait_timeout, 0, GET_ULONG, + &global_system_variables.net_wait_timeout, + &max_system_variables.net_wait_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT), 0, 1, 0}, {"userstat", OPT_USERSTAT, @@ -7465,8 +7621,9 @@ The minimum value for this variable is 4096.", "there are no dependencies between transactional and non-transactional " "tables such as in the statement INSERT INTO t_myisam SELECT * FROM " "t_innodb; otherwise, slaves may diverge from the master.", - (uchar**) &global_system_variables.binlog_direct_non_trans_update, (uchar**) &max_system_variables.binlog_direct_non_trans_update, 0, GET_BOOL, NO_ARG, 0, - 0, 0, 0, 0, 0}, + &global_system_variables.binlog_direct_non_trans_update, + &max_system_variables.binlog_direct_non_trans_update, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -8123,10 +8280,11 @@ static int mysql_init_variables(void) /* Things with default values that are not zero */ delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; - slave_exec_mode_options= 0; - slave_exec_mode_options= (uint) - find_bit_type_or_exit(slave_exec_mode_str, &slave_exec_mode_typelib, NULL, - &error); + slave_exec_mode_options= find_bit_type_or_exit(slave_exec_mode_str, + &slave_exec_mode_typelib, + NULL, &error); + /* Default mode string must not yield a error. */ + DBUG_ASSERT(!error); if (error) return 1; opt_specialflag= SPECIAL_ENGLISH; @@ -8374,6 +8532,10 @@ mysqld_get_one_option(int optid, case '0': WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-long-format", "--log-short-format"); break; + case OPT_DEPRECATED_OPTION: + sql_print_warning("'%s' is deprecated and exists only for compatiblity with old my.cnf files; Please remove this option from all your my.cnf files!", + opt->name); + break; case 'a': global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI); global_system_variables.tx_isolation= ISO_SERIALIZABLE; @@ -8417,8 +8579,9 @@ mysqld_get_one_option(int optid, init_slave_skip_errors(argument); break; case OPT_SLAVE_EXEC_MODE: - slave_exec_mode_options= (uint) - find_bit_type_or_exit(argument, &slave_exec_mode_typelib, "", &error); + slave_exec_mode_options= find_bit_type_or_exit(argument, + &slave_exec_mode_typelib, + "", &error); if (error) return 1; break; @@ -8523,7 +8686,7 @@ mysqld_get_one_option(int optid, *val= 0; val+= 2; while (*val && my_isspace(mysqld_charset, *val)) - *val++; + val++; if (!*val) { sql_print_error("Bad syntax in replicate-rewrite-db - empty TO db!\n"); @@ -8596,7 +8759,6 @@ mysqld_get_one_option(int optid, WARN_DEPRECATED(NULL, "7.0", "--log_slow_queries", "'--slow_query_log'/'--log-slow-file'"); opt_slow_log= 1; break; -#ifdef WITH_CSV_STORAGE_ENGINE case OPT_LOG_OUTPUT: { if (!argument || !argument[0]) @@ -8614,7 +8776,6 @@ mysqld_get_one_option(int optid, } break; } -#endif case OPT_EVENT_SCHEDULER: #ifndef HAVE_EVENT_SCHEDULER sql_perror("Event scheduler is not supported in embedded build."); @@ -8623,23 +8784,14 @@ mysqld_get_one_option(int optid, return 1; #endif break; - case (int) OPT_SKIP_NEW: - opt_specialflag|= SPECIAL_NO_NEW_FUNC; - delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; - myisam_concurrent_insert=0; - myisam_recover_options= HA_RECOVER_NONE; - sp_automatic_privileges=0; - my_use_symdir=0; - ha_open_options&= ~(HA_OPEN_ABORT_IF_CRASHED | HA_OPEN_DELAY_KEY_WRITE); -#ifdef HAVE_QUERY_CACHE - query_cache_size=0; -#endif - break; case (int) OPT_SAFE: - opt_specialflag|= SPECIAL_SAFE_MODE; + opt_specialflag|= SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC; delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; myisam_recover_options= HA_RECOVER_DEFAULT; ha_open_options&= ~(HA_OPEN_DELAY_KEY_WRITE); +#ifdef HAVE_QUERY_CACHE + query_cache_size=0; +#endif break; case (int) OPT_SKIP_PRIOR: opt_specialflag|= SPECIAL_NO_PRIOR; @@ -8739,8 +8891,7 @@ mysqld_get_one_option(int optid, if (!slave_warning_issued) //only show the warning once { slave_warning_issued = true; - WARN_DEPRECATED(NULL, "6.0", "for replication startup options", - "'CHANGE MASTER'"); + WARN_DEPRECATED(NULL, "6.0", opt->name, "'CHANGE MASTER'"); } break; case OPT_CONSOLE: @@ -8954,16 +9105,16 @@ mysqld_get_one_option(int optid, break; } case OPT_ONE_THREAD: - global_system_variables.thread_handling= SCHEDULER_NO_THREADS; - opt_thread_handling= thread_handling_typelib.type_names[global_system_variables.thread_handling]; + thread_handling= SCHEDULER_NO_THREADS; + opt_thread_handling= thread_handling_typelib.type_names[thread_handling]; break; case OPT_THREAD_HANDLING: { int id; LINT_INIT(id); if (!find_opt_type(argument, &thread_handling_typelib, opt->name, &id)) - global_system_variables.thread_handling= id - 1; - opt_thread_handling= thread_handling_typelib.type_names[global_system_variables.thread_handling]; + thread_handling= id - 1; + opt_thread_handling= thread_handling_typelib.type_names[thread_handling]; break; } case OPT_FT_BOOLEAN_SYNTAX: @@ -9009,13 +9160,12 @@ mysqld_get_one_option(int optid, /** Handle arguments for multiple key caches. */ +C_MODE_START +static void* mysql_getopt_value(const char *, uint, + const struct my_option *, int *); +C_MODE_END -extern "C" int mysql_getopt_value(uchar **value, - const char *keyname, uint key_length, - const struct my_option *option, - int *error); - -static uchar* * +static void* mysql_getopt_value(const char *keyname, uint key_length, const struct my_option *option, int *error) { @@ -9037,13 +9187,13 @@ mysql_getopt_value(const char *keyname, uint key_length, } switch (option->id) { case OPT_KEY_BUFFER_SIZE: - return (uchar**) &key_cache->param_buff_size; + return &key_cache->param_buff_size; case OPT_KEY_CACHE_BLOCK_SIZE: - return (uchar**) &key_cache->param_block_size; + return &key_cache->param_block_size; case OPT_KEY_CACHE_DIVISION_LIMIT: - return (uchar**) &key_cache->param_division_limit; + return &key_cache->param_division_limit; case OPT_KEY_CACHE_AGE_THRESHOLD: - return (uchar**) &key_cache->param_age_threshold; + return &key_cache->param_age_threshold; case OPT_KEY_CACHE_PARTITIONS: return (uchar**) &key_cache->param_partitions; } @@ -9117,7 +9267,7 @@ static int get_options(int *argc,char **argv) /* Set global MyISAM variables from delay_key_write_options */ fix_delay_key_write((THD*) 0, OPT_GLOBAL); /* Set global slave_exec_mode from its option */ - fix_slave_exec_mode(OPT_GLOBAL); + fix_slave_exec_mode(); global_system_variables.log_slow_filter= fix_log_slow_filter(global_system_variables.log_slow_filter); @@ -9125,7 +9275,7 @@ static int get_options(int *argc,char **argv) if (mysqld_chroot) set_root(mysqld_chroot); #else - global_system_variables.thread_handling = SCHEDULER_NO_THREADS; + thread_handling = SCHEDULER_NO_THREADS; max_allowed_packet= global_system_variables.max_allowed_packet; net_buffer_length= global_system_variables.net_buffer_length; #endif @@ -9137,6 +9287,7 @@ static int get_options(int *argc,char **argv) In most cases the global variables will not be used */ my_disable_locking= myisam_single_user= test(opt_external_locking == 0); + my_disable_sync= opt_sync == 0; my_default_record_cache_size=global_system_variables.read_buff_size; myisam_max_temp_length= (my_off_t) global_system_variables.myisam_max_sort_file_size; @@ -9164,11 +9315,10 @@ static int get_options(int *argc,char **argv) one_thread_scheduler(&thread_scheduler); one_thread_scheduler(&extra_thread_scheduler); #else - if (global_system_variables.thread_handling <= - SCHEDULER_ONE_THREAD_PER_CONNECTION) + if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION) one_thread_per_connection_scheduler(&thread_scheduler, &max_connections, &connection_count); - else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS) + else if (thread_handling == SCHEDULER_NO_THREADS) one_thread_scheduler(&thread_scheduler); else pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */ @@ -9282,6 +9432,8 @@ bool is_secure_file_path(char *path) static int fix_paths(void) { char buff[FN_REFLEN],*pos; + DBUG_ENTER("fix_paths"); + convert_dirname(mysql_home,mysql_home,NullS); /* Resolve symlinks to allow 'mysql_home' to be a relative symlink */ my_realpath(mysql_home,mysql_home,MYF(0)); @@ -9326,12 +9478,12 @@ static int fix_paths(void) charsets_dir=mysql_charsets_dir; if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) - return 1; + DBUG_RETURN(1); #ifdef HAVE_REPLICATION if (!slave_load_tmpdir) { if (!(slave_load_tmpdir = (char*) my_strdup(mysql_tmpdir, MYF(MY_FAE)))) - return 1; + DBUG_RETURN(1); } #endif /* HAVE_REPLICATION */ /* @@ -9352,7 +9504,7 @@ static int fix_paths(void) if (my_realpath(buff, opt_secure_file_priv, 0)) { sql_print_warning("Failed to normalize the argument for --secure-file-priv."); - return 1; + DBUG_RETURN(1); } secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); convert_dirname(secure_file_real_path, buff, NullS); @@ -9360,7 +9512,7 @@ static int fix_paths(void) opt_secure_file_priv= secure_file_real_path; } } - return 0; + DBUG_RETURN(0); } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index b2f40d576f7..8ca525994c9 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -16,11 +16,7 @@ /** @file - This file is the net layer API for the MySQL client/server protocol, - which is a tightly coupled, proprietary protocol owned by MySQL AB. - @note - Any re-implementations of this protocol must also be under GPL - unless one has got an license from MySQL AB stating otherwise. + This file is the net layer API for the MySQL client/server protocol. Write and read of logical packets to/from socket. @@ -914,13 +910,18 @@ my_real_read(NET *net, size_t *complen) ("Packets out of order (Found: %d, expected %u)", (int) net->buff[net->where_b + 3], net->pkt_nr)); -#ifdef EXTRA_DEBUG + /* + We don't make noise server side, since the client is expected + to break the protocol for e.g. --send LOAD DATA .. LOCAL where + the server expects the client to send a file, but the client + may reply with a new command instead. + */ +#if defined (EXTRA_DEBUG) && !defined (MYSQL_SERVER) fflush(stdout); fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n", (int) net->buff[net->where_b + 3], (uint) (uchar) net->pkt_nr); fflush(stderr); - DBUG_ASSERT(0); #endif } len= packet_error; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 1d521f78209..fd81236b343 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1259,7 +1259,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param, TABLE *table) - :pk_quick_select(NULL), thd(thd_param) + :unique(NULL), pk_quick_select(NULL), thd(thd_param) { DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT"); index= MAX_KEY; @@ -1301,6 +1301,7 @@ QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT() List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); QUICK_RANGE_SELECT* quick; DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT"); + delete unique; quick_it.rewind(); while ((quick= quick_it++)) quick->file= NULL; @@ -1498,7 +1499,7 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) quick->record= head->record[0]; } - if (need_to_fetch_row && head->file->ha_rnd_init(1)) + if (need_to_fetch_row && head->file->ha_rnd_init_with_error(1)) { DBUG_PRINT("error", ("ROR index_merge rnd_init call failed")); DBUG_RETURN(1); @@ -1669,7 +1670,7 @@ int QUICK_ROR_UNION_SELECT::reset() queue_insert(&queue, (uchar*)quick); } - if (head->file->ha_rnd_init(1)) + if (head->file->ha_rnd_init_with_error(1)) { DBUG_PRINT("error", ("ROR index_merge rnd_init call failed")); DBUG_RETURN(1); @@ -7754,7 +7755,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { KEY *table_key=quick->head->key_info+quick->index; flag=EQ_RANGE; - if ((table_key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME && + if ((table_key->flags & HA_NOSAME) && key->part == table_key->key_parts-1) { if (!(table_key->flags & HA_NULL_PART_KEY) || @@ -7804,7 +7805,7 @@ bool QUICK_RANGE_SELECT::unique_key_range() if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE) { KEY *key=head->key_info+index; - return ((key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME && + return ((key->flags & HA_NOSAME) && key->key_length == tmp->min_length); } } @@ -7951,8 +7952,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, range->min_length= range->max_length= ref->key_length; range->min_keypart_map= range->max_keypart_map= make_prev_keypart_map(ref->key_parts); - range->flag= ((ref->key_length == key_info->key_length && - (key_info->flags & HA_END_SPACE_KEY) == 0) ? EQ_RANGE : 0); + range->flag= (ref->key_length == key_info->key_length ? EQ_RANGE : 0); if (!(quick->key_parts=key_part=(KEY_PART *) alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) @@ -8038,7 +8038,6 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects); QUICK_RANGE_SELECT* cur_quick; int result; - Unique *unique= 0; handler *file= head->file; DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge"); @@ -8060,11 +8059,24 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() if (cur_quick->init() || cur_quick->reset()) goto err; - unique= new Unique(refpos_order_cmp, (void *)file, - file->ref_length, - thd->variables.sortbuff_size); - if (!unique) - goto err; + if (unique == NULL) + { + DBUG_EXECUTE_IF("index_merge_may_not_create_a_Unique", abort(); ); + DBUG_EXECUTE_IF("only_one_Unique_may_be_created", + DBUG_SET("+d,index_merge_may_not_create_a_Unique"); ); + + unique= new Unique(refpos_order_cmp, (void *)file, + file->ref_length, + thd->variables.sortbuff_size); + if (!unique) + goto err; + } + else + unique->reset(); + + DBUG_ASSERT(file->ref_length == unique->get_size()); + DBUG_ASSERT(thd->variables.sortbuff_size == unique->get_max_in_memory_size()); + for (;;) { while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE) @@ -8108,17 +8120,16 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() sequence. */ result= unique->get(head); - delete unique; doing_pk_scan= FALSE; /* index_merge currently doesn't support "using index" at all */ head->disable_keyread(); - init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE); + if (init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE)) + result= 1; DBUG_RETURN(result); err: - delete unique; head->disable_keyread(); DBUG_RETURN(1); } @@ -8233,6 +8244,7 @@ int QUICK_ROR_INTERSECT_SELECT::get_next() if ((error= quick->get_next())) DBUG_RETURN(error); } + quick->file->position(quick->record); } memcpy(last_rowid, quick->file->ref, head->file->ref_length); last_rowid_count= 1; @@ -8413,49 +8425,52 @@ int QUICK_RANGE_SELECT::get_next() /* Get the next record with a different prefix. - SYNOPSIS - QUICK_RANGE_SELECT::get_next_prefix() - prefix_length length of cur_prefix - cur_prefix prefix of a key to be searched for + @param prefix_length length of cur_prefix + @param group_key_parts The number of key parts in the group prefix + @param cur_prefix prefix of a key to be searched for - DESCRIPTION - Each subsequent call to the method retrieves the first record that has a - prefix with length prefix_length different from cur_prefix, such that the - record with the new prefix is within the ranges described by - this->ranges. The record found is stored into the buffer pointed by - this->record. - The method is useful for GROUP-BY queries with range conditions to - discover the prefix of the next group that satisfies the range conditions. + Each subsequent call to the method retrieves the first record that has a + prefix with length prefix_length and which is different from cur_prefix, + such that the record with the new prefix is within the ranges described by + this->ranges. The record found is stored into the buffer pointed by + this->record. The method is useful for GROUP-BY queries with range + conditions to discover the prefix of the next group that satisfies the range + conditions. + + @todo - TODO This method is a modified copy of QUICK_RANGE_SELECT::get_next(), so both methods should be unified into a more general one to reduce code duplication. - RETURN - 0 on success - HA_ERR_END_OF_FILE if returned all keys - other if some error occurred + @retval 0 on success + @retval HA_ERR_END_OF_FILE if returned all keys + @retval other if some error occurred */ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, - key_part_map keypart_map, + uint group_key_parts, uchar *cur_prefix) { DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix"); + const key_part_map keypart_map= make_prev_keypart_map(group_key_parts); for (;;) { int result; - key_range start_key, end_key; if (last_range) { /* Read the next record in the same range with prefix after cur_prefix. */ - DBUG_ASSERT(cur_prefix != 0); + DBUG_ASSERT(cur_prefix != NULL); result= file->ha_index_read_map(record, cur_prefix, keypart_map, HA_READ_AFTER_KEY); - if (result || (file->compare_key(file->end_range) <= 0)) + if (result || last_range->max_keypart_map == 0) DBUG_RETURN(result); + + key_range previous_endpoint; + last_range->make_max_endpoint(&previous_endpoint, prefix_length, keypart_map); + if (file->compare_key(&previous_endpoint) <= 0) + DBUG_RETURN(0); } uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); @@ -8467,21 +8482,9 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, } last_range= *(cur_range++); - start_key.key= (const uchar*) last_range->min_key; - start_key.length= min(last_range->min_length, prefix_length); - start_key.keypart_map= last_range->min_keypart_map & keypart_map; - 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 uchar*) last_range->max_key; - end_key.length= min(last_range->max_length, prefix_length); - end_key.keypart_map= last_range->max_keypart_map & keypart_map; - /* - 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= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : - HA_READ_AFTER_KEY); + key_range start_key, end_key; + last_range->make_min_endpoint(&start_key, prefix_length, keypart_map); + last_range->make_max_endpoint(&end_key, prefix_length, keypart_map); result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0, last_range->max_keypart_map ? &end_key : 0, @@ -8576,9 +8579,9 @@ bool QUICK_RANGE_SELECT::row_in_ranges() } /* - This is a hack: we inherit from QUICK_SELECT so that we can use the + This is a hack: we inherit from QUICK_RANGE_SELECT so that we can use the get_next() interface, but we have to hold a pointer to the original - QUICK_SELECT because its data are used all over the place. What + QUICK_RANGE_SELECT because its data are used all over the place. What should be done is to factor out the data that is needed into a base class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC) which handle the ranges and implement the get_next() function. But @@ -8854,7 +8857,7 @@ void QUICK_RANGE_SELECT::add_keys_and_lengths(String *key_names, uint length; KEY *key_info= head->key_info + index; key_names->append(key_info->name); - length= longlong2str(max_used_key_length, buf, 10) - buf; + length= longlong10_to_str(max_used_key_length, buf, 10) - buf; used_lengths->append(buf, length); } @@ -8879,7 +8882,7 @@ void QUICK_INDEX_MERGE_SELECT::add_keys_and_lengths(String *key_names, KEY *key_info= head->key_info + quick->index; key_names->append(key_info->name); - length= longlong2str(quick->max_used_key_length, buf, 10) - buf; + length= longlong10_to_str(quick->max_used_key_length, buf, 10) - buf; used_lengths->append(buf, length); } if (pk_quick_select) @@ -8887,7 +8890,8 @@ void QUICK_INDEX_MERGE_SELECT::add_keys_and_lengths(String *key_names, KEY *key_info= head->key_info + pk_quick_select->index; key_names->append(','); key_names->append(key_info->name); - length= longlong2str(pk_quick_select->max_used_key_length, buf, 10) - buf; + length= (longlong10_to_str(pk_quick_select->max_used_key_length, buf, 10) + - buf); used_lengths->append(','); used_lengths->append(buf, length); } @@ -8912,7 +8916,7 @@ void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names, used_lengths->append(','); } key_names->append(key_info->name); - length= longlong2str(quick->max_used_key_length, buf, 10) - buf; + length= longlong10_to_str(quick->max_used_key_length, buf, 10) - buf; used_lengths->append(buf, length); } @@ -8921,7 +8925,7 @@ void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names, KEY *key_info= head->key_info + cpk_quick->index; key_names->append(','); key_names->append(key_info->name); - length= longlong2str(cpk_quick->max_used_key_length, buf, 10) - buf; + length= longlong10_to_str(cpk_quick->max_used_key_length, buf, 10) - buf; used_lengths->append(','); used_lengths->append(buf, length); } @@ -10112,7 +10116,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, uint use_index, double read_cost_arg, ha_rows records_arg, uint key_infix_len_arg, uchar *key_infix_arg, MEM_ROOT *parent_alloc) - :join(join_arg), index_info(index_info_arg), + :file(table->file), join(join_arg), index_info(index_info_arg), group_prefix_len(group_prefix_len_arg), group_key_parts(group_key_parts_arg), have_min(have_min_arg), have_max(have_max_arg), seen_first_key(FALSE), doing_key_read(FALSE), @@ -10121,7 +10125,6 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, max_functions_it(NULL) { head= table; - file= head->file; index= use_index; record= head->record[0]; tmp_record= head->record[1]; @@ -10721,7 +10724,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() { uchar *cur_prefix= seen_first_key ? group_prefix : NULL; if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, - make_prev_keypart_map(group_key_parts), cur_prefix))) + group_key_parts, + cur_prefix))) DBUG_RETURN(result); seen_first_key= TRUE; } @@ -11093,7 +11097,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, char buf[64]; uint length; key_names->append(index_info->name); - length= longlong2str(max_used_key_length, buf, 10) - buf; + length= longlong10_to_str(max_used_key_length, buf, 10) - buf; used_lengths->append(buf, length); } diff --git a/sql/opt_range.h b/sql/opt_range.h index 5abad749b58..1f2df1d7d55 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -71,6 +71,85 @@ class QUICK_RANGE :public Sql_alloc { dummy=0; #endif } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the minimum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + + @param prefix_length The length of the search key prefix to be used for + lookup. + + @param keypart_map A set (bitmap) of keyparts to be used. + */ + void make_min_endpoint(key_range *kr, uint prefix_length, + key_part_map keypart_map) { + make_min_endpoint(kr); + kr->length= min(kr->length, prefix_length); + kr->keypart_map&= keypart_map; + } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the minimum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + */ + void make_min_endpoint(key_range *kr) { + kr->key= (const uchar*)min_key; + kr->length= min_length; + kr->keypart_map= min_keypart_map; + kr->flag= ((flag & NEAR_MIN) ? HA_READ_AFTER_KEY : + (flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); + } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the maximum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + + @param prefix_length The length of the search key prefix to be used for + lookup. + + @param keypart_map A set (bitmap) of keyparts to be used. + */ + void make_max_endpoint(key_range *kr, uint prefix_length, + key_part_map keypart_map) { + make_max_endpoint(kr); + kr->length= min(kr->length, prefix_length); + kr->keypart_map&= keypart_map; + } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the maximum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + */ + void make_max_endpoint(key_range *kr) { + kr->key= (const uchar*)max_key; + kr->length= max_length; + kr->keypart_map= max_keypart_map; + /* + We use READ_AFTER_KEY here because if we are reading on a key + prefix we want to find all keys with this prefix + */ + kr->flag= (flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); + } }; @@ -349,7 +428,7 @@ public: int reset(void); int get_next(); void range_end(); - int get_next_prefix(uint prefix_length, key_part_map keypart_map, + int get_next_prefix(uint prefix_length, uint group_key_parts, uchar *cur_prefix); bool reverse_sorted() { return 0; } bool unique_key_range(); @@ -462,6 +541,7 @@ public: class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I { + Unique *unique; public: QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table); ~QUICK_INDEX_MERGE_SELECT(); @@ -649,13 +729,13 @@ private: class QUICK_GROUP_MIN_MAX_SELECT : public QUICK_SELECT_I { private: - handler *file; /* The handler used to get data. */ + handler * const file; /* The handler used to get data. */ JOIN *join; /* Descriptor of the current query */ KEY *index_info; /* The index chosen for data access */ uchar *record; /* Buffer where the next record is returned. */ uchar *tmp_record; /* Temporary storage for next_min(), next_max(). */ uchar *group_prefix; /* Key prefix consisting of the GROUP fields. */ - uint group_prefix_len; /* Length of the group prefix. */ + const uint group_prefix_len; /* Length of the group prefix. */ uint group_key_parts; /* A number of keyparts in the group prefix */ uchar *last_prefix; /* Prefix of the last group for detecting EOF. */ bool have_min; /* Specify whether we are computing */ diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 974eea08871..450ded89653 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -89,6 +89,126 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) /** + Use index to read MIN(field) value. + + @param table Table object + @param ref Reference to the structure where we store the key value + @item_field Field used in MIN() + @range_fl Whether range endpoint is strict less than + @prefix_len Length of common key part for the range + + @retval + 0 No errors + HA_ERR_... Otherwise +*/ + +static int get_index_min_value(TABLE *table, TABLE_REF *ref, + Item_field *item_field, uint range_fl, + uint prefix_len) +{ + int error; + + if (!ref->key_length) + error= table->file->ha_index_first(table->record[0]); + else + { + /* + Use index to replace MIN/MAX functions with their values + according to the following rules: + + 1) Insert the minimum non-null values where the WHERE clause still + matches, or + 2) a NULL value if there are only NULL values for key_part_k. + 3) Fail, producing a row of nulls + + Implementation: Read the smallest value using the search key. If + the interval is open, read the next value after the search + key. If read fails, and we're looking for a MIN() value for a + nullable column, test if there is an exact match for the key. + */ + if (!(range_fl & NEAR_MIN)) + /* + Closed interval: Either The MIN argument is non-nullable, or + we have a >= predicate for the MIN argument. + */ + error= table->file->ha_index_read_map(table->record[0], + ref->key_buff, + make_prev_keypart_map(ref->key_parts), + HA_READ_KEY_OR_NEXT); + else + { + /* + Open interval: There are two cases: + 1) We have only MIN() and the argument column is nullable, or + 2) there is a > predicate on it, nullability is irrelevant. + We need to scan the next bigger record first. + Open interval is not used if the search key involves the last keypart, + and it would not work. + */ + DBUG_ASSERT(prefix_len < ref->key_length); + error= table->file->ha_index_read_map(table->record[0], + ref->key_buff, + make_prev_keypart_map(ref->key_parts), + HA_READ_AFTER_KEY); + /* + If the found record is outside the group formed by the search + prefix, or there is no such record at all, check if all + records in that group have NULL in the MIN argument + column. If that is the case return that NULL. + + Check if case 1 from above holds. If it does, we should read + the skipped tuple. + */ + if (item_field->field->real_maybe_null() && + ref->key_buff[prefix_len] == 1 && + /* + Last keypart (i.e. the argument to MIN) is set to NULL by + find_key_for_maxmin only if all other keyparts are bound + to constants in a conjunction of equalities. Hence, we + can detect this by checking only if the last keypart is + NULL. + */ + (error == HA_ERR_KEY_NOT_FOUND || + key_cmp_if_same(table, ref->key_buff, ref->key, prefix_len))) + { + DBUG_ASSERT(item_field->field->real_maybe_null()); + error= table->file->ha_index_read_map(table->record[0], + ref->key_buff, + make_prev_keypart_map(ref->key_parts), + HA_READ_KEY_EXACT); + } + } + } + return error; +} + + +/** + Use index to read MAX(field) value. + + @param table Table object + @param ref Reference to the structure where we store the key value + @range_fl Whether range endpoint is strict greater than + + @retval + 0 No errors + HA_ERR_... Otherwise +*/ + +static int get_index_max_value(TABLE *table, TABLE_REF *ref, uint range_fl) +{ + return (ref->key_length ? + table->file->ha_index_read_map(table->record[0], ref->key_buff, + make_prev_keypart_map(ref->key_parts), + range_fl & NEAR_MAX ? + HA_READ_BEFORE_KEY : + HA_READ_PREFIX_LAST_OR_PREV) : + table->file->ha_index_last(table->record[0])); +} + + + +/** Substitutes constants for some COUNT(), MIN() and MAX() functions. @param tables list of leaves of join table tree @@ -220,9 +340,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) const_result= 0; break; case Item_sum::MIN_FUNC: + case Item_sum::MAX_FUNC: { + int is_max= test(item_sum->sum_func() == Item_sum::MAX_FUNC); /* - If MIN(expr) is the first part of a key or if all previous + If MIN/MAX(expr) is the first part of a key or if all previous parts of the key is found in the COND, then we can use indexes to find the key. */ @@ -241,89 +363,25 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) Look for a partial key that can be used for optimization. If we succeed, ref.key_length will contain the length of this key, while prefix_len will contain the length of - the beginning of this key without field used in MIN(). + the beginning of this key without field used in MIN/MAX(). Type of range for the key part for this field will be returned in range_fl. */ if (table->file->inited || (outer_tables & table->map) || - !find_key_for_maxmin(0, &ref, item_field->field, conds, + !find_key_for_maxmin(is_max, &ref, item_field->field, conds, &range_fl, &prefix_len)) { const_result= 0; break; } - error= table->file->ha_index_init((uint) ref.key, 1); + if (!(error= table->file->ha_index_init((uint) ref.key, 1))) + error= (is_max ? + get_index_max_value(table, &ref, range_fl) : + get_index_min_value(table, &ref, item_field, range_fl, + prefix_len)); - if (!ref.key_length) - error= table->file->ha_index_first(table->record[0]); - else - { - /* - Use index to replace MIN/MAX functions with their values - according to the following rules: - - 1) Insert the minimum non-null values where the WHERE clause still - matches, or - 2) a NULL value if there are only NULL values for key_part_k. - 3) Fail, producing a row of nulls - - Implementation: Read the smallest value using the search key. If - the interval is open, read the next value after the search - key. If read fails, and we're looking for a MIN() value for a - nullable column, test if there is an exact match for the key. - */ - if (!(range_fl & NEAR_MIN)) - /* - Closed interval: Either The MIN argument is non-nullable, or - we have a >= predicate for the MIN argument. - */ - error= table->file->ha_index_read_map(table->record[0], - ref.key_buff, - make_prev_keypart_map(ref.key_parts), - HA_READ_KEY_OR_NEXT); - else - { - /* - Open interval: There are two cases: - 1) We have only MIN() and the argument column is nullable, or - 2) there is a > predicate on it, nullability is irrelevant. - We need to scan the next bigger record first. - */ - error= table->file->ha_index_read_map(table->record[0], - ref.key_buff, - make_prev_keypart_map(ref.key_parts), - HA_READ_AFTER_KEY); - /* - If the found record is outside the group formed by the search - prefix, or there is no such record at all, check if all - records in that group have NULL in the MIN argument - column. If that is the case return that NULL. - - Check if case 1 from above holds. If it does, we should read - the skipped tuple. - */ - if (item_field->field->real_maybe_null() && - ref.key_buff[prefix_len] == 1 && - /* - Last keypart (i.e. the argument to MIN) is set to NULL by - find_key_for_maxmin only if all other keyparts are bound - to constants in a conjunction of equalities. Hence, we - can detect this by checking only if the last keypart is - NULL. - */ - (error == HA_ERR_KEY_NOT_FOUND || - key_cmp_if_same(table, ref.key_buff, ref.key, prefix_len))) - { - DBUG_ASSERT(item_field->field->real_maybe_null()); - error= table->file->ha_index_read_map(table->record[0], - ref.key_buff, - make_prev_keypart_map(ref.key_parts), - HA_READ_KEY_EXACT); - } - } - } /* Verify that the read tuple indeed matches the search key */ - if (!error && reckey_in_range(0, &ref, item_field->field, + if (!error && reckey_in_range(is_max, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; table->disable_keyread(); @@ -352,98 +410,16 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) const_result= 0; break; } - if (!count) - { - /* If count == 0, then we know that is_exact_count == TRUE. */ - ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */ - } - else - ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */ - ((Item_sum_min*) item_sum)->make_const(); - recalc_const_item= 1; - break; - } - case Item_sum::MAX_FUNC: - { /* - If MAX(expr) is the first part of a key or if all previous - parts of the key is found in the COND, then we can use - indexes to find the key. + If count == 0 (so is_exact_count == TRUE) and + there're no outer joins, set to NULL, + otherwise set to the constant value. */ - Item *expr=item_sum->get_arg(0); - if (expr->real_item()->type() == Item::FIELD_ITEM) - { - uchar key_buff[MAX_KEY_LENGTH]; - TABLE_REF ref; - uint range_fl, prefix_len; - - ref.key_buff= key_buff; - Item_field *item_field= (Item_field*) (expr->real_item()); - TABLE *table= item_field->field->table; - - /* - Look for a partial key that can be used for optimization. - If we succeed, ref.key_length will contain the length of - this key, while prefix_len will contain the length of - the beginning of this key without field used in MAX(). - Type of range for the key part for this field will be - returned in range_fl. - */ - if (table->file->inited || (outer_tables & table->map) || - !find_key_for_maxmin(1, &ref, item_field->field, conds, - &range_fl, &prefix_len)) - { - const_result= 0; - break; - } - error= table->file->ha_index_init((uint) ref.key, 1); - - if (!ref.key_length) - error= table->file->ha_index_last(table->record[0]); - else - error= table->file->ha_index_read_map(table->record[0], key_buff, - make_prev_keypart_map(ref.key_parts), - range_fl & NEAR_MAX ? - HA_READ_BEFORE_KEY : - HA_READ_PREFIX_LAST_OR_PREV); - if (!error && reckey_in_range(1, &ref, item_field->field, - conds, range_fl, prefix_len)) - error= HA_ERR_KEY_NOT_FOUND; - table->disable_keyread(); - table->file->ha_index_end(); - if (error) - { - if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) - 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)); - table->in_use->fatal_error(); - return(error); - } - removed_tables|= table->map; - } - else if (!expr->const_item() || !is_exact_count) - { - /* - The optimization is not applicable in both cases: - (a) 'expr' is a non-constant expression. Then we can't - replace 'expr' by a constant. - (b) 'expr' is a costant. According to ANSI, MIN/MAX must return - NULL if the query does not return any rows. Thus, if we are not - able to determine if the query returns any rows, we can't apply - the optimization and replace MIN/MAX with a constant. - */ - const_result= 0; - break; - } - if (!count) - { - /* If count != 1, then we know that is_exact_count == TRUE. */ - ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */ - } + if (!count && !outer_tables) + item_sum->clear(); else - ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */ - ((Item_sum_max*) item_sum)->make_const(); + item_sum->reset(); + item_sum->make_const(); recalc_const_item= 1; break; } @@ -617,18 +593,19 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, key_part_map *key_part_used, uint *range_fl, uint *prefix_len) { + DBUG_ENTER("matching_cond"); if (!cond) - return 1; + DBUG_RETURN(TRUE); Field *field= field_part->field; if (!(cond->used_tables() & field->table->map)) { /* Condition doesn't restrict the used table */ - return 1; + DBUG_RETURN(TRUE); } if (cond->type() == Item::COND_ITEM) { if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC) - return 0; + DBUG_RETURN(FALSE); /* AND */ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); @@ -637,13 +614,13 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, { if (!matching_cond(max_fl, ref, keyinfo, field_part, item, key_part_used, range_fl, prefix_len)) - return 0; + DBUG_RETURN(FALSE); } - return 1; + DBUG_RETURN(TRUE); } if (cond->type() != Item::FUNC_ITEM) - return 0; // Not operator, can't optimize + DBUG_RETURN(FALSE); // Not operator, can't optimize bool eq_type= 0; // =, <=> or IS NULL bool is_null_safe_eq= FALSE; // The operator is NULL safe, e.g. <=> @@ -677,7 +654,7 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, eq_type= 1; break; default: - return 0; // Can't optimize function + DBUG_RETURN(FALSE); // Can't optimize function } Item *args[3]; @@ -685,11 +662,11 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, /* Test if this is a comparison of a field and constant */ if (!simple_pred((Item_func*) cond, args, &inv)) - return 0; + DBUG_RETURN(FALSE); if (!is_null_safe_eq && !is_null && (args[1]->is_null() || (between && args[2]->is_null()))) - return FALSE; + DBUG_RETURN(FALSE); if (inv && !eq_type) less_fl= 1-less_fl; // Convert '<' -> '>' (etc) @@ -701,14 +678,14 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, { if (part > field_part) - return 0; // Field is beyond the tested parts + DBUG_RETURN(FALSE); // Field is beyond the tested parts if (part->field->eq(((Item_field*) args[0])->field)) break; // Found a part of the key for the field } bool is_field_part= part == field_part; if (!(is_field_part || eq_type)) - return 0; + DBUG_RETURN(FALSE); key_part_map org_key_part_used= *key_part_used; if (eq_type || between || max_fl == less_fl) @@ -728,6 +705,17 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, *key_part_used|= (key_part_map) 1 << (part - keyinfo->key_part); } + if (org_key_part_used == *key_part_used && + /* + The current search key is not being extended with a new key part. This + means that the a condition is added a key part for which there was a + previous condition. We can only overwrite such key parts in some special + cases, e.g. a > 2 AND a > 1 (here range_fl must be set to something). In + all other cases the WHERE condition is always false anyway. + */ + (eq_type || *range_fl == 0)) + DBUG_RETURN(FALSE); + if (org_key_part_used != *key_part_used || (is_field_part && (between || eq_type || max_fl == less_fl) && !cond->val_int())) @@ -773,11 +761,11 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, { if ((!is_null && !cond->val_int()) || (is_null && !test(part->field->is_null()))) - return 0; // Impossible test + DBUG_RETURN(FALSE); // Impossible test } else if (is_field_part) *range_fl&= ~(max_fl ? NO_MIN_RANGE : NO_MAX_RANGE); - return 1; + DBUG_RETURN(TRUE); } diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc index e8f6a4fd4b9..1e4e87ebac7 100644 --- a/sql/opt_table_elimination.cc +++ b/sql/opt_table_elimination.cc @@ -1544,7 +1544,7 @@ Dep_value_table *Dep_analysis_context::create_table_value(TABLE *table) for (uint i=0; i < table->s->keys; i++) { KEY *key= table->key_info + i; - if ((key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME) + if (key->flags & HA_NOSAME) { Dep_module_key *key_dep; if (!(key_dep= new Dep_module_key(tbl_dep, i, key->key_parts))) diff --git a/sql/parse_file.h b/sql/parse_file.h index 84647e45927..1e649657c57 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -89,12 +89,12 @@ class File_parser: public Sql_alloc { char *buff, *start, *end; LEX_STRING file_type; - my_bool content_ok; + bool content_ok; public: File_parser() :buff(0), start(0), end(0), content_ok(0) { file_type.str= 0; file_type.length= 0; } - my_bool ok() { return content_ok; } + bool ok() { return content_ok; } LEX_STRING *type() { return &file_type; } my_bool parse(uchar* base, MEM_ROOT *mem_root, struct File_option *parameters, uint required, diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 0de8e478f03..9e07d735598 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -103,8 +103,8 @@ char *partition_info::create_default_partition_names(uint part_no, { do { - my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i))); - move_ptr+=MAX_PART_NAME_SIZE; + sprintf(move_ptr, "p%u", (start_no + i)); + move_ptr+= MAX_PART_NAME_SIZE; } while (++i < no_parts_arg); } else @@ -135,7 +135,7 @@ char *partition_info::create_subpartition_name(uint subpart_no, if (likely(ptr != NULL)) { - my_sprintf(ptr, (ptr, "%ssp%u", part_name, subpart_no)); + my_snprintf(ptr, size_alloc, "%ssp%u", part_name, subpart_no); } else { @@ -1104,8 +1104,8 @@ void partition_info::print_no_partition_found(TABLE *table) if (part_expr->null_value) buf_ptr= (char*)"NULL"; else - longlong2str(err_value, buf, - part_expr->unsigned_flag ? 10 : -10); + longlong10_to_str(err_value, buf, + part_expr->unsigned_flag ? 10 : -10); my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr); dbug_tmp_restore_column_map(table->read_set, old_map); } diff --git a/sql/protocol.cc b/sql/protocol.cc index 7721d43f936..786d6ef8544 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -578,7 +578,11 @@ void Protocol::end_partial_result_set(THD *thd_arg) bool Protocol::flush() { #ifndef EMBEDDED_LIBRARY - return net_flush(&thd->net); + bool error; + thd->main_da.can_overwrite_status= TRUE; + error= net_flush(&thd->net); + thd->main_da.can_overwrite_status= FALSE; + return error; #else return 0; #endif @@ -618,7 +622,8 @@ bool Protocol::send_fields(List<Item> *list, uint flags) if (flags & SEND_NUM_ROWS) { // Packet with number of elements uchar *pos= net_store_length(buff, list->elements); - (void) my_net_write(&thd->net, buff, (size_t) (pos-buff)); + if (my_net_write(&thd->net, buff, (size_t) (pos-buff))) + DBUG_RETURN(1); } #ifndef DBUG_OFF @@ -742,7 +747,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) if (flags & SEND_DEFAULTS) item->send(&prot, &tmp); // Send default value if (prot.write()) - break; /* purecov: inspected */ + DBUG_RETURN(1); #ifndef DBUG_OFF field_types[count++]= field.type; #endif @@ -755,7 +760,9 @@ bool Protocol::send_fields(List<Item> *list, uint flags) to show that there is no cursor. Send no warning information, as it will be sent at statement end. */ - write_eof_packet(thd, &thd->net, thd->server_status, thd->total_warn_count); + if (write_eof_packet(thd, &thd->net, thd->server_status, + thd->total_warn_count)) + DBUG_RETURN(1); } DBUG_RETURN(prepare_for_send(list)); diff --git a/sql/records.cc b/sql/records.cc index e2a1ea9b4af..bdb27322a28 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -157,7 +157,8 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, This is the most basic access method of a table using rnd_init, rnd_next and rnd_end. No indexes are used. */ -void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, + +bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, SQL_SELECT *select, int use_record_cache, bool print_error, bool disable_rr_cache) @@ -196,7 +197,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, tempfile= &select->file; else tempfile= table->sort.io_cache; - if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used + if (tempfile && my_b_inited(tempfile) && + !(select && select->quick)) { DBUG_PRINT("info",("using rr_from_tempfile")); info->read_record= (table->sort.addon_field ? @@ -205,7 +207,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0); info->ref_pos=table->file->ref; if (!table->file->inited) - table->file->ha_rnd_init(0); + if (table->file->ha_rnd_init_with_error(0)) + DBUG_RETURN(1); /* table->sort.addon_field is checked because if we use addon fields, @@ -214,7 +217,6 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, */ if (!disable_rr_cache && !table->sort.addon_field && - ! (specialflag & SPECIAL_SAFE_MODE) && thd->variables.read_rnd_buff_size && !(table->file->ha_table_flags() & HA_FAST_KEY_READ) && (table->db_stat & HA_READ_ONLY || @@ -242,7 +244,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, else if (table->sort.record_pointers) { DBUG_PRINT("info",("using record_pointers")); - table->file->ha_rnd_init(0); + if (table->file->ha_rnd_init_with_error(0)) + DBUG_RETURN(1); info->cache_pos=table->sort.record_pointers; info->cache_end=info->cache_pos+ table->sort.found_records*info->ref_length; @@ -253,7 +256,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, { DBUG_PRINT("info",("using rr_sequential")); info->read_record=rr_sequential; - table->file->ha_rnd_init(1); + if (table->file->ha_rnd_init_with_error(1)) + DBUG_RETURN(1); /* We can use record cache if we don't update dynamic length tables */ if (!table->no_cache && (use_record_cache > 0 || @@ -271,7 +275,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, !table->file->pushed_cond) table->file->cond_push(select->cond); - DBUG_VOID_RETURN; + DBUG_RETURN(0); } /* init_read_record */ @@ -327,7 +331,7 @@ static int rr_quick(READ_RECORD *info) break; } } - update_virtual_fields(info->table); + update_virtual_fields(info->thd, info->table); return tmp; } @@ -396,7 +400,7 @@ int rr_sequential(READ_RECORD *info) } } if (!tmp) - update_virtual_fields(info->table); + update_virtual_fields(info->thd, info->table); return tmp; } diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 0fa13949aba..9b1b1f70784 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -976,7 +976,7 @@ bool load_master_data(THD* thd) host was specified; there could have been a problem when replication started, which led to relay log's IO_CACHE to not be inited. */ - if (flush_master_info(active_mi, 0)) + if (flush_master_info(active_mi, FALSE, FALSE)) sql_print_error("Failed to flush master info file"); } mysql_free_result(master_status_res); diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index ffae94f733a..8c0523f6766 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -92,7 +92,7 @@ Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables) for (; tables; tables= tables->next_global) { - char hash_key[2*NAME_LEN+2]; + char hash_key[SAFE_NAME_LEN*2+2]; char *end; uint len; @@ -227,7 +227,7 @@ Rpl_filter::db_ok_with_wild_table(const char *db) { DBUG_ENTER("Rpl_filter::db_ok_with_wild_table"); - char hash_key[NAME_LEN+2]; + char hash_key[SAFE_NAME_LEN+2]; char *end; int len; end= strmov(hash_key, db); diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index b8af53849f1..47fc88c9a8a 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -322,7 +322,7 @@ file '%s')", fname); mi->inited = 1; // now change cache READ -> WRITE - must do this before flush_master_info reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1); - if ((error=test(flush_master_info(mi, 1)))) + if ((error=test(flush_master_info(mi, TRUE, TRUE)))) sql_print_error("Failed to flush master info file"); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); @@ -348,10 +348,13 @@ err: 1 - flush master info failed 0 - all ok */ -int flush_master_info(Master_info* mi, bool flush_relay_log_cache) +int flush_master_info(Master_info* mi, + bool flush_relay_log_cache, + bool need_lock_relay_log) { IO_CACHE* file = &mi->file; char lbuf[22]; + int err= 0; DBUG_ENTER("flush_master_info"); DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos)); @@ -368,9 +371,23 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) When we come to this place in code, relay log may or not be initialized; the caller is responsible for setting 'flush_relay_log_cache' accordingly. */ - if (flush_relay_log_cache && - flush_io_cache(mi->rli.relay_log.get_log_file())) - DBUG_RETURN(2); + if (flush_relay_log_cache) + { + pthread_mutex_t *log_lock= mi->rli.relay_log.get_log_lock(); + IO_CACHE *log_file= mi->rli.relay_log.get_log_file(); + + if (need_lock_relay_log) + pthread_mutex_lock(log_lock); + + safe_mutex_assert_owner(log_lock); + err= flush_io_cache(log_file); + + if (need_lock_relay_log) + pthread_mutex_unlock(log_lock); + + if (err) + DBUG_RETURN(2); + } /* We flushed the relay log BEFORE the master.info file, because if we crash diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 93fb0a98198..d63432545e5 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -66,10 +66,10 @@ class Master_info : public Slave_reporting_capability char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; char password[MAX_PASSWORD_LENGTH+1]; - my_bool ssl; // enables use of SSL connection if true + bool ssl; // enables use of SSL connection if true char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; - my_bool ssl_verify_server_cert; + bool ssl_verify_server_cert; my_off_t master_log_pos; File fd; // we keep the file open, so we need to remember the file pointer @@ -108,7 +108,8 @@ int init_master_info(Master_info* mi, const char* master_info_fname, bool abort_if_no_master_info_file, int thread_mask); void end_master_info(Master_info* mi); -int flush_master_info(Master_info* mi, bool flush_relay_log_cache); - +int flush_master_info(Master_info* mi, + bool flush_relay_log_cache, + bool need_lock_relay_log); #endif /* HAVE_REPLICATION */ #endif /* RPL_MI_H */ diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 26daac1b629..c37c4735e37 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -115,7 +115,7 @@ int init_relay_log_info(Relay_log_info* rli, /* The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. Note that the I/O thread flushes it to disk after writing every - event, in flush_master_info(mi, 1). + event, in flush_master_info(mi, 1, ?). */ /* @@ -1115,8 +1115,7 @@ bool Relay_log_info::cached_charset_compare(char *charset) const { DBUG_ENTER("Relay_log_info::cached_charset_compare"); - if (bcmp((uchar*) cached_charset, (uchar*) charset, - sizeof(cached_charset))) + if (memcmp(cached_charset, charset, sizeof(cached_charset))) { memcpy(const_cast<char*>(cached_charset), charset, sizeof(cached_charset)); DBUG_RETURN(1); diff --git a/sql/set_var.cc b/sql/set_var.cc index 56ebdbcade1..0eaa450d09c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -58,7 +58,7 @@ #include <my_getopt.h> #include <thr_alarm.h> #include <myisam.h> -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE #include <maria.h> #endif #include <my_dir.h> @@ -95,14 +95,13 @@ TYPELIB delay_key_write_typelib= delay_key_write_type_names, NULL }; -const char *slave_exec_mode_names[]= -{ "STRICT", "IDEMPOTENT", NullS }; -static const unsigned int slave_exec_mode_names_len[]= -{ sizeof("STRICT") - 1, sizeof("IDEMPOTENT") - 1, 0 }; +static const char *slave_exec_mode_names[]= { "STRICT", "IDEMPOTENT", NullS }; +static unsigned int slave_exec_mode_names_len[]= { sizeof("STRICT") - 1, + sizeof("IDEMPOTENT") - 1, 0 }; TYPELIB slave_exec_mode_typelib= { array_elements(slave_exec_mode_names)-1, "", - slave_exec_mode_names, (unsigned int *) slave_exec_mode_names_len + slave_exec_mode_names, slave_exec_mode_names_len }; static int sys_check_ftb_syntax(THD *thd, set_var *var); @@ -609,9 +608,8 @@ static sys_var_thd_ulong sys_trans_prealloc_size(&vars, "transaction_prealloc_si &SV::trans_prealloc_size, 0, fix_trans_mem_root); sys_var_enum_const sys_thread_handling(&vars, "thread_handling", - &SV::thread_handling, - &thread_handling_typelib, - NULL); + &thread_handling, + &thread_handling_typelib); #ifdef HAVE_QUERY_CACHE static sys_var_long_ptr sys_query_cache_limit(&vars, "query_cache_limit", @@ -974,6 +972,9 @@ static sys_var_readonly sys_myisam_mmap_size(&vars, "myisam_mmap_size", SHOW_LONGLONG, get_myisam_mmap_size); +static sys_var_enum_const sys_plugin_maturity(&vars, "plugin_maturity", + &plugin_maturity, + &plugin_maturity_values); bool sys_var::check(THD *thd, set_var *var) { @@ -1236,21 +1237,21 @@ extern void fix_delay_key_write(THD *thd, enum_var_type type) switch ((enum_delay_key_write) delay_key_write_options) { case DELAY_KEY_WRITE_NONE: myisam_delay_key_write=0; -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE maria_delay_key_write= 0; #endif ha_open_options&= ~HA_OPEN_DELAY_KEY_WRITE; break; case DELAY_KEY_WRITE_ON: myisam_delay_key_write=1; -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE maria_delay_key_write= 1; #endif ha_open_options&= ~HA_OPEN_DELAY_KEY_WRITE; break; case DELAY_KEY_WRITE_ALL: myisam_delay_key_write=1; -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE maria_delay_key_write= 1; #endif ha_open_options|= HA_OPEN_DELAY_KEY_WRITE; @@ -1290,7 +1291,7 @@ uchar *sys_var_set::value_ptr(THD *thd, enum_var_type type, void sys_var_set_slave_mode::set_default(THD *thd, enum_var_type type) { - slave_exec_mode_options= (ULL(1) << SLAVE_EXEC_MODE_STRICT); + slave_exec_mode_options= SLAVE_EXEC_MODE_STRICT; } bool sys_var_set_slave_mode::check(THD *thd, set_var *var) @@ -1298,8 +1299,7 @@ bool sys_var_set_slave_mode::check(THD *thd, set_var *var) bool rc= sys_var_set::check(thd, var); if (!rc && test_all_bits(var->save_result.ulong_value, - ((ULL(1) << SLAVE_EXEC_MODE_STRICT) | - (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT)))) + SLAVE_EXEC_MODE_STRICT | SLAVE_EXEC_MODE_IDEMPOTENT)) { rc= true; my_error(ER_SLAVE_AMBIGOUS_EXEC_MODE, MYF(0), ""); @@ -1316,21 +1316,18 @@ bool sys_var_set_slave_mode::update(THD *thd, set_var *var) return rc; } -void fix_slave_exec_mode(enum_var_type type) +void fix_slave_exec_mode(void) { DBUG_ENTER("fix_slave_exec_mode"); - compile_time_assert(sizeof(slave_exec_mode_options) * CHAR_BIT - > SLAVE_EXEC_MODE_LAST_BIT - 1); + if (test_all_bits(slave_exec_mode_options, - ((ULL(1) << SLAVE_EXEC_MODE_STRICT) | - (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT)))) + SLAVE_EXEC_MODE_STRICT | SLAVE_EXEC_MODE_IDEMPOTENT)) { - sql_print_error("Ambiguous slave modes combination." - " STRICT will be used"); - slave_exec_mode_options&= ~(ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT); + sql_print_error("Ambiguous slave modes combination. STRICT will be used"); + slave_exec_mode_options&= ~SLAVE_EXEC_MODE_IDEMPOTENT; } - if (!(slave_exec_mode_options & (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT))) - slave_exec_mode_options|= (ULL(1)<< SLAVE_EXEC_MODE_STRICT); + if (!(slave_exec_mode_options & SLAVE_EXEC_MODE_IDEMPOTENT)) + slave_exec_mode_options|= SLAVE_EXEC_MODE_STRICT; DBUG_VOID_RETURN; } @@ -1706,12 +1703,6 @@ uchar *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) return (uchar*) enum_names->type_names[*value]; } -uchar *sys_var_enum_const::value_ptr(THD *thd, enum_var_type type, - LEX_STRING *base) -{ - return (uchar*) enum_names->type_names[global_system_variables.*offset]; -} - bool sys_var_thd_ulong::check(THD *thd, set_var *var) { if (get_unsigned(thd, var, max_system_variables.*offset, GET_ULONG)) @@ -2850,10 +2841,26 @@ int set_var_collation_client::update(THD *thd) /****************************************************************************/ +bool sys_var_timestamp::check(THD *thd, set_var *var) +{ + time_t val; + var->save_result.ulonglong_value= var->value->val_int(); + val= (time_t) var->save_result.ulonglong_value; + if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX) + { + my_message(ER_UNKNOWN_ERROR, + "This version of MySQL doesn't support dates later than 2038", + MYF(0)); + return TRUE; + } + return FALSE; +} + + bool sys_var_timestamp::update(THD *thd, set_var *var) { thd->set_time((time_t) var->save_result.ulonglong_value); - return 0; + return FALSE; } @@ -4329,8 +4336,14 @@ bool sys_var_thd_dbug::check(THD *thd, set_var *var) bool sys_var_thd_dbug::update(THD *thd, set_var *var) { -#ifndef DBUG_OFF - const char *command= var ? var->value->str_value.c_ptr() : ""; + char buf[256]; + String str(buf, sizeof(buf), system_charset_info), *res; + const char *command; + + res= var->value->val_str(&str); + command= res ? res->c_ptr(): 0; + if (!command) + command= ""; if (var->type == OPT_GLOBAL) DBUG_SET_INITIAL(command); @@ -4350,7 +4363,6 @@ bool sys_var_thd_dbug::update(THD *thd, set_var *var) DBUG_PUSH(command); } } -#endif return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index 5b8fa1358cb..653f9b5155d 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -376,21 +376,14 @@ public: }; -class sys_var_enum_const :public sys_var +class sys_var_enum_const :public sys_var_enum { - ulong SV::*offset; - TYPELIB *enum_names; public: - sys_var_enum_const(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg, - TYPELIB *typelib, sys_after_update_func func) - :sys_var(name_arg,func), offset(offset_arg), enum_names(typelib) - { chain_sys_var(chain); } - bool check(THD *thd, set_var *var) { return 1; } - bool update(THD *thd, set_var *var) { return 1; } - SHOW_TYPE show_type() { return SHOW_CHAR; } - bool check_update_type(Item_result type) { return 1; } + sys_var_enum_const(sys_var_chain *chain, const char *name_arg, + uint *value_arg, TYPELIB *typelib) + :sys_var_enum(chain, name_arg, value_arg, typelib, 0) + { } bool is_readonly() const { return 1; } - uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -675,6 +668,7 @@ public: Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) :sys_var(name_arg, NULL, binlog_status_arg) { chain_sys_var(chain); } + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } @@ -1458,7 +1452,7 @@ sys_var *find_sys_var(THD *thd, const char *str, uint length=0); int sql_set_variables(THD *thd, List<set_var_base> *var_list); bool not_all_support_one_shot(List<set_var_base> *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); -void fix_slave_exec_mode(enum_var_type type); +void fix_slave_exec_mode(void); ulong fix_sql_mode(ulong sql_mode); extern sys_var_const_str sys_charset_system; extern sys_var_str sys_init_connect; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 117a4b8e1e6..54061931d5f 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6207,40 +6207,42 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" +ER_DEBUG_SYNC_TIMEOUT + eng "debug sync point wait timed out" + ger "Debug Sync Point Wartezeit überschritten" +ER_DEBUG_SYNC_HIT_LIMIT + eng "debug sync point hit limit reached" + ger "Debug Sync Point Hit Limit erreicht" + ER_VCOL_BASED_ON_VCOL eng "A computed column cannot be based on a computed column" ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED - eng "Function or expression is not allowed for column '%s'." + eng "Function or expression is not allowed for column '%s'" ER_DATA_CONVERSION_ERROR_FOR_VIRTUAL_COLUMN - eng "Generated value for computed column '%s' cannot be converted to type '%s'." + eng "Generated value for computed column '%s' cannot be converted to type '%s'" ER_PRIMARY_KEY_BASED_ON_VIRTUAL_COLUMN - eng "Primary key cannot be defined upon a computed column." + eng "Primary key cannot be defined upon a computed column" ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN - eng "Key/Index cannot be defined on a non-stored computed column." + eng "Key/Index cannot be defined on a non-stored computed column" ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN - eng "Cannot define foreign key with %s clause on a computed column." + eng "Cannot define foreign key with %s clause on a computed column" ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN - eng "The value specified for computed column '%s' in table '%s' ignored." + eng "The value specified for computed column '%s' in table '%s' ignored" ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN - eng "'%s' is not yet supported for computed columns." + eng "'%s' is not yet supported for computed columns" ER_CONST_EXPR_IN_VCOL - eng "Constant expression in computed column function is not allowed." - -ER_DEBUG_SYNC_TIMEOUT - eng "debug sync point wait timed out" - ger "Debug Sync Point Wartezeit überschritten" -ER_DEBUG_SYNC_HIT_LIMIT - eng "debug sync point hit limit reached" - ger "Debug Sync Point Hit Limit erreicht" + eng "Constant expression in computed column function is not allowed" +ER_ROW_EXPR_FOR_VCOL + eng "Expression for computed column cannot return a row" ER_UNKNOWN_OPTION eng "Unknown option '%-.64s'" ER_BAD_OPTION_VALUE diff --git a/sql/slave.cc b/sql/slave.cc index e92070ebcc1..55bfcceeb47 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1439,7 +1439,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi) " to the relay log, SHOW SLAVE STATUS may be" " inaccurate"); rli->relay_log.harvest_bytes_written(&rli->log_space_total); - if (flush_master_info(mi, 1)) + if (flush_master_info(mi, TRUE, TRUE)) sql_print_error("Failed to flush master info file"); delete ev; } @@ -2073,7 +2073,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), FLAGSTR(thd->options, OPTION_BEGIN), - rli->last_event_start_time)); + (ulong) rli->last_event_start_time)); /* Execute the event to change the database and update the binary @@ -2692,7 +2692,7 @@ Stopping slave I/O thread due to out-of-memory error from master"); "could not queue event from master"); goto err; } - if (flush_master_info(mi, 1)) + if (flush_master_info(mi, TRUE, TRUE)) { sql_print_error("Failed to flush master info file"); goto err; @@ -2846,8 +2846,8 @@ pthread_handler_t handle_slave_sql(void *arg) char llbuff[22],llbuff1[22]; char saved_log_name[FN_REFLEN]; char saved_master_log_name[FN_REFLEN]; - my_off_t saved_log_pos; - my_off_t saved_master_log_pos; + my_off_t UNINIT_VAR(saved_log_pos); + my_off_t UNINIT_VAR(saved_master_log_pos); my_off_t saved_skip= 0; Relay_log_info* rli = &((Master_info*)arg)->rli; const char *errmsg; @@ -3969,11 +3969,11 @@ bool flush_relay_log_info(Relay_log_info* rli) my_b_seek(file, 0L); pos=strmov(buff, rli->group_relay_log_name); *pos++='\n'; - pos=longlong2str(rli->group_relay_log_pos, pos, 10); + pos= longlong10_to_str(rli->group_relay_log_pos, pos, 10); *pos++='\n'; pos=strmov(pos, rli->group_master_log_name); *pos++='\n'; - pos=longlong2str(rli->group_master_log_pos, pos, 10); + pos=longlong10_to_str(rli->group_master_log_pos, pos, 10); *pos='\n'; if (my_b_write(file, (uchar*) buff, (size_t) (pos-buff)+1)) error=1; diff --git a/sql/sp.cc b/sql/sp.cc index ac509a3bb2d..ebf2b3c360d 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -719,7 +719,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, { LEX *old_lex= thd->lex, newlex; String defstr; - char saved_cur_db_name_buf[NAME_LEN+1]; + char saved_cur_db_name_buf[SAFE_NAME_LEN+1]; LEX_STRING saved_cur_db_name= { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; bool cur_db_changed; @@ -784,7 +784,12 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, thd->spcont= NULL; { - Parser_state parser_state(thd, defstr.c_ptr(), defstr.length()); + Parser_state parser_state; + if (parser_state.init(thd, defstr.c_ptr(), defstr.length())) + { + ret= SP_INTERNAL_ERROR; + goto end; + } lex_start(thd); @@ -1634,8 +1639,7 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen, void sp_get_prelocking_info(THD *thd, bool *need_prelocking, bool *first_no_prelocking) { - Sroutine_hash_entry *routine; - routine= (Sroutine_hash_entry*)thd->lex->sroutines_list.first; + Sroutine_hash_entry *routine= thd->lex->sroutines_list.first; DBUG_ASSERT(routine); bool first_is_procedure= (routine->key.str[0] == TYPE_ENUM_PROCEDURE); @@ -1698,7 +1702,7 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, memcpy(rn->key.str, key->str, key->length + 1); if (my_hash_insert(&lex->sroutines, (uchar *)rn)) return FALSE; - lex->sroutines_list.link_in_list((uchar *)rn, (uchar **)&rn->next); + lex->sroutines_list.link_in_list(rn, &rn->next); rn->belong_to_view= belong_to_view; return TRUE; } @@ -1744,7 +1748,7 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, void sp_remove_not_own_routines(LEX *lex) { Sroutine_hash_entry *not_own_rt, *next_rt; - for (not_own_rt= *(Sroutine_hash_entry **)lex->sroutines_list_own_last; + for (not_own_rt= *lex->sroutines_list_own_last; not_own_rt; not_own_rt= next_rt) { /* @@ -1755,7 +1759,7 @@ void sp_remove_not_own_routines(LEX *lex) hash_delete(&lex->sroutines, (uchar *)not_own_rt); } - *(Sroutine_hash_entry **)lex->sroutines_list_own_last= NULL; + *lex->sroutines_list_own_last= NULL; lex->sroutines_list.next= lex->sroutines_list_own_last; lex->sroutines_list.elements= lex->sroutines_list_own_elements; } @@ -1836,11 +1840,11 @@ sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src, It will also add elements to end of 'LEX::sroutines_list' list. */ -static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src, +static void sp_update_stmt_used_routines(THD *thd, LEX *lex, + SQL_I_List<Sroutine_hash_entry> *src, TABLE_LIST *belong_to_view) { - for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first; - rt; rt= rt->next) + for (Sroutine_hash_entry *rt= src->first; rt; rt= rt->next) (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view); } @@ -1928,7 +1932,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, Hence, the overrun happens only if the name is in length > 32 and uses multibyte (cyrillic, greek, etc.) */ - char n[NAME_LEN*2+2]; + char n[SAFE_NAME_LEN*2+2]; /* m_qname.str is not always \0 terminated */ memcpy(n, name.m_qname.str, name.m_qname.length); @@ -1975,8 +1979,7 @@ int sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock) { return sp_cache_routines_and_add_tables_aux(thd, lex, - (Sroutine_hash_entry *)lex->sroutines_list.first, - first_no_prelock); + lex->sroutines_list.first, first_no_prelock); } @@ -2000,8 +2003,7 @@ sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock) int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view) { - Sroutine_hash_entry **last_cached_routine_ptr= - (Sroutine_hash_entry **)lex->sroutines_list.next; + Sroutine_hash_entry **last_cached_routine_ptr= lex->sroutines_list.next; sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list, view->top_table()); return sp_cache_routines_and_add_tables_aux(thd, lex, @@ -2030,8 +2032,7 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, { int ret= 0; - Sroutine_hash_entry **last_cached_routine_ptr= - (Sroutine_hash_entry **)lex->sroutines_list.next; + Sroutine_hash_entry **last_cached_routine_ptr= lex->sroutines_list.next; if (static_cast<int>(table->lock_type) >= static_cast<int>(TL_WRITE_ALLOW_WRITE)) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f7dc2c83641..2f1aa042c61 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -34,6 +34,36 @@ extern "C" uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first); +/** + Helper function which operates on a THD object to set the query start_time to + the current time. + + @param[in, out] thd The session object + +*/ + +static void reset_start_time_for_sp(THD *thd) +{ + /* + Do nothing if the context is a trigger or function because time should be + constant during the execution of those. + */ + if (!thd->in_sub_stmt) + { + /* + First investigate if there is a cached time stamp + */ + if (thd->user_time) + { + thd->start_time= thd->user_time; + } + else + { + my_micro_time_and_time(&thd->start_time); + } + } +} + Item_result sp_map_result_type(enum enum_field_types type) { @@ -1057,7 +1087,7 @@ bool sp_head::execute(THD *thd) { DBUG_ENTER("sp_head::execute"); - char saved_cur_db_name_buf[NAME_LEN+1]; + char saved_cur_db_name_buf[SAFE_NAME_LEN+1]; LEX_STRING saved_cur_db_name= { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; bool cur_db_changed= FALSE; @@ -1227,10 +1257,13 @@ sp_head::execute(THD *thd) DBUG_PRINT("execute", ("Instruction %u", ip)); - /* Don't change NOW() in FUNCTION or TRIGGER */ - if (!thd->in_sub_stmt) - thd->set_time(); // Make current_time() et al work - + /* + We need to reset start_time to allow for time to flow inside a stored + procedure. This is only done for SP since time is suppose to be constant + during execution of triggers and functions. + */ + reset_start_time_for_sp(thd); + /* We have to set thd->stmt_arena before executing the instruction to store in the instruction free_list all new items, created @@ -1842,8 +1875,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) { bool err_status= FALSE; uint params = m_pcont->context_var_count(); - /* Query start time may be reset in a multi-stmt SP; keep this for later. */ - ulonglong utime_before_sp_exec= thd->utime_after_lock; sp_rcontext *save_spcont, *octx; sp_rcontext *nctx = NULL; bool save_enable_slow_log; @@ -2036,8 +2067,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) delete nctx; thd->spcont= save_spcont; - thd->utime_after_lock= utime_before_sp_exec; - DBUG_RETURN(err_status); } @@ -3827,7 +3856,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) for (; table ; table= table->next_global) if (!table->derived && !table->schema_table) { - char tname[(NAME_LEN + 1) * 3]; // db\0table\0alias\0 + char tname[(SAFE_NAME_LEN + 1) * 3]; // db\0table\0alias\0 uint tlen, alen; tlen= table->db_length; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 368a017da21..ecd11453e49 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -281,7 +281,7 @@ public: int close(THD *thd); - inline my_bool + inline bool is_open() { return test(server_side_cursor); diff --git a/sql/spatial.cc b/sql/spatial.cc index a23e8ec0d90..2305a8eb97d 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -53,7 +53,7 @@ static Geometry::Class_info **ci_collection_end= Geometry::ci_collection+Geometry::wkb_last + 1; Geometry::Class_info::Class_info(const char *name, int type_id, - void(*create_func)(void *)): + create_geom_t create_func): m_type_id(type_id), m_create_func(create_func) { m_name.str= (char *) name; @@ -62,39 +62,39 @@ Geometry::Class_info::Class_info(const char *name, int type_id, ci_collection[type_id]= this; } -static void create_point(void *buffer) +static Geometry *create_point(char *buffer) { - new(buffer) Gis_point; + return new (buffer) Gis_point; } -static void create_linestring(void *buffer) +static Geometry *create_linestring(char *buffer) { - new(buffer) Gis_line_string; + return new (buffer) Gis_line_string; } -static void create_polygon(void *buffer) +static Geometry *create_polygon(char *buffer) { - new(buffer) Gis_polygon; + return new (buffer) Gis_polygon; } -static void create_multipoint(void *buffer) +static Geometry *create_multipoint(char *buffer) { - new(buffer) Gis_multi_point; + return new (buffer) Gis_multi_point; } -static void create_multipolygon(void *buffer) +static Geometry *create_multipolygon(char *buffer) { - new(buffer) Gis_multi_polygon; + return new (buffer) Gis_multi_polygon; } -static void create_multilinestring(void *buffer) +static Geometry *create_multilinestring(char *buffer) { - new(buffer) Gis_multi_line_string; + return new (buffer) Gis_multi_line_string; } -static void create_geometrycollection(void *buffer) +static Geometry *create_geometrycollection(char *buffer) { - new(buffer) Gis_geometry_collection; + return new (buffer) Gis_geometry_collection; } @@ -145,6 +145,15 @@ Geometry::Class_info *Geometry::find_class(const char *name, uint32 len) } +Geometry *Geometry::create_by_typeid(Geometry_buffer *buffer, int type_id) +{ + Class_info *ci; + if (!(ci= find_class(type_id))) + return NULL; + return (*ci->m_create_func)(buffer->data); +} + + Geometry *Geometry::construct(Geometry_buffer *buffer, const char *data, uint32 data_len) { @@ -153,6 +162,7 @@ Geometry *Geometry::construct(Geometry_buffer *buffer, if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4) return NULL; + /* + 1 to skip the byte order (stored in position SRID_SIZE). */ geom_type= uint4korr(data + SRID_SIZE + 1); if (!(result= create_by_typeid(buffer, (int) geom_type))) return NULL; @@ -177,9 +187,7 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, if (!(ci= find_class(name.str, name.length)) || wkt->reserve(1 + 4, 512)) return NULL; - (*ci->m_create_func)((void *)buffer); - Geometry *result= (Geometry *)buffer; - + Geometry *result= (*ci->m_create_func)(buffer->data); wkt->q_append((char) wkb_ndr); wkt->q_append((uint32) result->get_class_info()->m_type_id); if (trs->check_next_symbol('(') || diff --git a/sql/spatial.h b/sql/spatial.h index 86c2ed8c197..f778acd6c34 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -225,15 +225,18 @@ public: { wkb_xdr= 0, /* Big Endian */ wkb_ndr= 1 /* Little Endian */ - }; + }; + + /** Callback which creates Geometry objects on top of a given placement. */ + typedef Geometry *(*create_geom_t)(char *); class Class_info { public: LEX_STRING m_name; int m_type_id; - void (*m_create_func)(void *); - Class_info(const char *name, int type_id, void(*create_func)(void *)); + create_geom_t m_create_func; + Class_info(const char *name, int type_id, create_geom_t create_func); }; virtual const Class_info *get_class_info() const=0; @@ -263,15 +266,7 @@ public: virtual int geometry_n(uint32 num, String *result) const { return -1; } public: - static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id) - { - Class_info *ci; - if (!(ci= find_class((int) type_id))) - return NULL; - (*ci->m_create_func)((void *)buffer); - return my_reinterpret_cast(Geometry *)(buffer); - } - + static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id); static Geometry *construct(Geometry_buffer *buffer, const char *data, uint32 data_len); static Geometry *create_from_wkt(Geometry_buffer *buffer, @@ -528,11 +523,8 @@ public: const Class_info *get_class_info() const; }; -const int geometry_buffer_size= sizeof(Gis_point); -struct Geometry_buffer -{ - void *arr[(geometry_buffer_size - 1)/sizeof(void *) + 1]; -}; +struct Geometry_buffer : public + my_aligned_storage<sizeof(Gis_point), MY_ALIGNOF(Gis_point)> {}; #endif /*HAVE_SPATAIAL*/ #endif diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index db20782037e..496e8c310dd 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -162,7 +162,9 @@ static LEX_STRING old_password_plugin_name= { LEX_STRING *default_auth_plugin_name= &native_password_plugin_name; static plugin_ref native_password_plugin; +#ifndef NO_EMBEDDED_ACCESS_CHECKS static plugin_ref old_password_plugin; +#endif /* Classes */ @@ -292,6 +294,7 @@ static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); static my_bool acl_load(THD *thd, TABLE_LIST *tables); static my_bool grant_load(THD *thd, TABLE_LIST *tables); +static inline void get_grantor(THD *thd, char* grantor); /* Convert scrambled password to binary form, according to scramble type, @@ -465,7 +468,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) READ_RECORD read_record_info; my_bool return_val= TRUE; bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; - char tmp_name[NAME_LEN+1]; + char tmp_name[SAFE_NAME_LEN+1]; int password_length; ulong old_sql_mode= thd->variables.sql_mode; DBUG_ENTER("acl_load"); @@ -477,8 +480,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) acl_cache->clear(1); // Clear locked hostname cache init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); - init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0, - FALSE); + if (init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0, + FALSE)) + goto end; + table->use_all_columns(); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); while (!(read_record_info.read_record(&read_record_info))) @@ -527,7 +532,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_hosts); - init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE); + if (init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0, + FALSE)) + goto end; + table->use_all_columns(); VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); password_length= table->field[2]->field_length / @@ -748,7 +756,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_users); - init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE); + if (init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0, + FALSE)) + goto end; + table->use_all_columns(); VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100)); while (!(read_record_info.read_record(&read_record_info))) @@ -2471,7 +2482,7 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, const char *user, const char *tname, bool exact, bool name_tolower) { - char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr; + char helping [SAFE_NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr; uint len; GRANT_NAME *grant_name,*found=0; HASH_SEARCH_STATE state; @@ -2724,6 +2735,20 @@ end: DBUG_RETURN(result); } +static inline void get_grantor(THD *thd, char *grantor) +{ + const char *user= thd->security_ctx->user; + const char *host= thd->security_ctx->host_or_ip; + +#if defined(HAVE_REPLICATION) + if (thd->slave_thread && thd->has_invoker()) + { + user= thd->get_invoker_user().str; + host= thd->get_invoker_host().str; + } +#endif + strxmov(grantor, user, "@", host, NullS); +} static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, TABLE *table, const LEX_USER &combo, @@ -2738,9 +2763,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, uchar user_key[MAX_KEY_LENGTH]; DBUG_ENTER("replace_table_table"); - strxmov(grantor, thd->security_ctx->user, "@", - thd->security_ctx->host_or_ip, NullS); - + get_grantor(thd, grantor); /* The following should always succeed as new users are created before this function is called! @@ -2870,9 +2893,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, DBUG_RETURN(-1); } - strxmov(grantor, thd->security_ctx->user, "@", - thd->security_ctx->host_or_ip, NullS); - + get_grantor(thd, grantor); /* New users are created before this function is called. @@ -3439,7 +3460,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, { List_iterator <LEX_USER> str_list (list); LEX_USER *Str, *tmp_Str; - char tmp_db[NAME_LEN+1]; + char tmp_db[SAFE_NAME_LEN+1]; bool create_new_users=0; TABLE_LIST tables[2]; bool save_binlog_row_based; @@ -4326,7 +4347,7 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash) bool check_grant_db(THD *thd,const char *db) { Security_context *sctx= thd->security_ctx; - char helping [NAME_LEN+USERNAME_LENGTH+2]; + char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2]; uint len; bool error= TRUE; @@ -7271,7 +7292,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) 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 db_buff[SAFE_NAME_LEN + 1]; // buffer to store db in utf8 char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 uint dummy_errors; @@ -7470,7 +7491,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, char *passwd= strend(user)+1; uint user_len= passwd - user - 1, db_len; char *db= passwd; - char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 + char db_buff[SAFE_NAME_LEN + 1]; // buffer to store db in utf8 char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 uint dummy_errors; diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 8807b40857e..b72ff62d592 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -71,7 +71,7 @@ class field_info :public Sql_alloc protected: ulong treemem, tree_elements, empty, nulls, min_length, max_length; uint room_in_tree; - my_bool found; + bool found; TREE tree; Item *item; analyse *pc; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a93b48bfe94..e8dcc557f05 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -613,7 +613,7 @@ void release_table_share(TABLE_SHARE *share, enum release_type type) TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) { - char key[NAME_LEN*2+2]; + char key[SAFE_NAME_LEN*2+2]; TABLE_LIST table_list; uint key_length; safe_mutex_assert_owner(&LOCK_open); @@ -1248,6 +1248,12 @@ void close_thread_tables(THD *thd) table->s->table_name.str, (long) table)); #endif +#if defined(ENABLED_DEBUG_SYNC) + /* debug_sync may not be initialized for some slave threads */ + if (thd->debug_sync_control) + DEBUG_SYNC(thd, "before_close_thread_tables"); +#endif + /* We are assuming here that thd->derived_tables contains ONLY derived tables for this substatement. i.e. instead of approach which uses @@ -2335,7 +2341,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= 0; + table->null_row= 0; + table->maybe_null= 0; table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; DBUG_RETURN(FALSE); @@ -2522,7 +2529,7 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists) put in the thread-open-list. flags Bitmap of flags to modify how open works: MYSQL_LOCK_IGNORE_FLUSH - Open table even if - someone has done a flush or namelock on it. + someone has done a flush on it. No version number checking is done. MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary table not the base table or view. @@ -2812,8 +2819,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ("Found table '%s.%s' with different refresh version", table_list->db, table_list->table_name)); - if (flags & MYSQL_LOCK_IGNORE_FLUSH) + /* Ignore FLUSH, but not name locks! */ + if (flags & MYSQL_LOCK_IGNORE_FLUSH && !table->open_placeholder) { + DBUG_ASSERT(table->db_stat); /* Force close at once after usage */ thd->version= table->s->version; continue; @@ -2999,7 +3008,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= 0; + table->null_row= 0; + table->maybe_null= 0; table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; table->insert_values= 0; @@ -4445,7 +4455,8 @@ bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last, Return a appropriate read lock type given a table object. @param thd Thread context - @param table TABLE object for table to be locked + @param lex LEX for the current statement. + @param table_list Table list element for table to be locked. @remark Due to a statement-based replication limitation, statements such as INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need @@ -4454,19 +4465,32 @@ bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last, source table. If such a statement gets applied on the slave before the INSERT .. SELECT statement finishes, data on the master could differ from data on the slave and end-up with a discrepancy between - the binary log and table state. Furthermore, this does not apply to - I_S and log tables as it's always unsafe to replicate such tables - under statement-based replication as the table on the slave might - contain other data (ie: general_log is enabled on the slave). The - statement will be marked as unsafe for SBR in decide_logging_format(). + the binary log and table state. + This also applies to SELECT/SET/DO statements which use stored + functions. Calls to such functions are going to be logged as a + whole and thus should be serialized against concurrent changes + to tables used by those functions. This can be avoided if functions + only read data but doing so requires more complex analysis than it + is done now (unfortunately, due to bug #53921 "Wrong locks for + SELECTs used stored functions may lead to broken SBR" this rule + is not followed in cases when stored function or trigger use + simple SELECT and not a subselect in their body). + Furthermore, this does not apply to I_S and log tables as it's + always unsafe to replicate such tables under statement-based + replication as the table on the slave might contain other data + (ie: general_log is enabled on the slave). The statement will + be marked as unsafe for SBR in decide_logging_format(). */ -thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table) +thr_lock_type read_lock_type_for_table(THD *thd, LEX *lex, + TABLE_LIST *table_list) { bool log_on= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); ulong binlog_format= thd->variables.binlog_format; if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) || - (table->s->table_category == TABLE_CATEGORY_PERFORMANCE)) + (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) || + (lex->sql_command == SQLCOM_SELECT && + ! table_list->prelocking_placeholder)) return TL_READ; else return TL_READ_NO_INSERT; @@ -4483,7 +4507,7 @@ thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table) counter - number of opened tables will be return using this parameter flags - bitmap of flags to modify how the tables will be open: MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has - done a flush or namelock on it. + done a flush on it. NOTE Unless we are already in prelocked mode, this function will also precache @@ -4762,7 +4786,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) tables->table->reginfo.lock_type= thd->update_lock_default; else if (tables->lock_type == TL_READ_DEFAULT) tables->table->reginfo.lock_type= - read_lock_type_for_table(thd, tables->table); + read_lock_type_for_table(thd, thd->lex, tables); else tables->table->reginfo.lock_type= tables->lock_type; } @@ -5082,7 +5106,7 @@ int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived) tables - list of tables for open flags - bitmap of flags to modify how the tables will be open: MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has - done a flush or namelock on it. + done a flush on it. RETURN FALSE - ok @@ -5181,53 +5205,75 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables) set with all the capabilities bits set and one with no capabilities bits set. */ - handler::Table_flags flags_some_set= 0; - handler::Table_flags flags_all_set= + handler::Table_flags flags_write_some_set= 0; + handler::Table_flags flags_access_some_set= 0; + handler::Table_flags flags_write_all_set= HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE; - my_bool multi_engine= FALSE; - void* prev_ht= NULL; + /* + If different types of engines are about to be updated. + For example: Innodb and Falcon; Innodb and MyIsam. + */ + my_bool multi_write_engine= FALSE; + void* prev_write_ht= NULL; + + /* + If different types of engines are about to be accessed + and any of them is about to be updated. For example: + Innodb and Falcon; Innodb and MyIsam. + */ + my_bool multi_access_engine= FALSE; + void* prev_access_ht= NULL; for (TABLE_LIST *table= tables; table; table= table->next_global) { if (table->placeholder()) continue; if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) thd->lex->set_stmt_unsafe(); + ulonglong const flags= table->table->file->ha_table_flags(); if (table->lock_type >= TL_WRITE_ALLOW_WRITE) { - ulonglong const flags= table->table->file->ha_table_flags(); DBUG_PRINT("info", ("table: %s; ha_table_flags: %s%s", table->table_name, FLAGSTR(flags, HA_BINLOG_STMT_CAPABLE), FLAGSTR(flags, HA_BINLOG_ROW_CAPABLE))); - if (prev_ht && prev_ht != table->table->file->ht) - multi_engine= TRUE; - prev_ht= table->table->file->ht; - flags_all_set &= flags; - flags_some_set |= flags; + if (prev_write_ht && prev_write_ht != table->table->file->ht) + multi_write_engine= TRUE; + prev_write_ht= table->table->file->ht; + flags_write_all_set &= flags; + flags_write_some_set |= flags; } - } - - DBUG_PRINT("info", ("flags_all_set: %s%s", - FLAGSTR(flags_all_set, HA_BINLOG_STMT_CAPABLE), - FLAGSTR(flags_all_set, HA_BINLOG_ROW_CAPABLE))); - DBUG_PRINT("info", ("flags_some_set: %s%s", - FLAGSTR(flags_some_set, HA_BINLOG_STMT_CAPABLE), - FLAGSTR(flags_some_set, HA_BINLOG_ROW_CAPABLE))); + if (prev_access_ht && prev_access_ht != table->table->file->ht) + multi_access_engine= TRUE; + prev_access_ht= table->table->file->ht; + flags_access_some_set |= flags; + } + + DBUG_PRINT("info", ("flags_write_all_set: %s%s", + FLAGSTR(flags_write_all_set, HA_BINLOG_STMT_CAPABLE), + FLAGSTR(flags_write_all_set, HA_BINLOG_ROW_CAPABLE))); + DBUG_PRINT("info", ("flags_write_some_set: %s%s", + FLAGSTR(flags_write_some_set, HA_BINLOG_STMT_CAPABLE), + FLAGSTR(flags_write_some_set, HA_BINLOG_ROW_CAPABLE))); + DBUG_PRINT("info", ("flags_access_some_set: %s%s", + FLAGSTR(flags_access_some_set, HA_BINLOG_STMT_CAPABLE), + FLAGSTR(flags_access_some_set, HA_BINLOG_ROW_CAPABLE))); + DBUG_PRINT("info", ("multi_write_engine: %s", + multi_write_engine ? "TRUE" : "FALSE")); + DBUG_PRINT("info", ("multi_access_engine: %s", + multi_access_engine ? "TRUE" : "FALSE")); DBUG_PRINT("info", ("thd->variables.binlog_format: %ld", thd->variables.binlog_format)); - DBUG_PRINT("info", ("multi_engine: %s", - multi_engine ? "TRUE" : "FALSE")); int error= 0; - if (flags_all_set == 0) + if (flags_write_all_set == 0) { my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0), "Statement cannot be logged to the binary log in" " row-based nor statement-based format"); } else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT && - (flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0) + (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0) { my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0), "Statement-based format required for this statement," @@ -5235,7 +5281,7 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables) } else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW || thd->lex->is_stmt_unsafe()) && - (flags_all_set & HA_BINLOG_ROW_CAPABLE) == 0) + (flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0) { my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0), "Row-based format required for this statement," @@ -5248,8 +5294,8 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables) statement cannot be logged atomically, so we generate an error rather than allowing the binlog to become corrupt. */ - if (multi_engine && - (flags_some_set & HA_HAS_OWN_BINLOGGING)) + if (multi_write_engine && + (flags_write_some_set & HA_HAS_OWN_BINLOGGING)) { error= ER_BINLOG_LOGGING_IMPOSSIBLE; my_error(error, MYF(0), @@ -5257,6 +5303,16 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables) " than one engine involved and at least one engine" " is self-logging"); } + /* + Reading from a self-logging engine and updating another engine + generates changes that are written to the binary log in the + statement format and may make slaves to diverge. In the mixed + mode, such changes should be written to the binary log in the + row format. + */ + else if (multi_access_engine && + (flags_access_some_set & HA_HAS_OWN_BINLOGGING)) + thd->lex->set_stmt_unsafe(); DBUG_PRINT("info", ("error: %d", error)); @@ -5276,7 +5332,7 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables) here. */ if (thd->lex->is_stmt_unsafe() || - (flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0) + (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0) { thd->set_current_stmt_binlog_row_based_if_mixed(); } @@ -5384,6 +5440,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) DBUG_RETURN(-1); } + DEBUG_SYNC(thd, "after_lock_tables_takes_lock"); + if (thd->lex->requires_prelocking() && thd->lex->sql_command != SQLCOM_LOCK_TABLES) { @@ -5653,7 +5711,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) DBUG_ENTER("update_field_dependencies"); if (thd->mark_used_columns != MARK_COLUMNS_NONE) { - MY_BITMAP *current_bitmap; + MY_BITMAP *bitmap; /* We always want to register the used keys, as the column bitmap may have @@ -5667,9 +5725,9 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) table->mark_virtual_col(field); if (thd->mark_used_columns == MARK_COLUMNS_READ) - current_bitmap= table->read_set; + bitmap= table->read_set; else - current_bitmap= table->write_set; + bitmap= table->write_set; /* The test-and-set mechanism in the bitmap is not reliable during @@ -5678,7 +5736,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) only those columns that are used in the SET clause. I.e they are being set here. See multi_update::prepare() */ - if (bitmap_fast_test_and_set(current_bitmap, field->field_index)) + if (bitmap_fast_test_and_set(bitmap, field->field_index)) { if (thd->mark_used_columns == MARK_COLUMNS_WRITE) { @@ -6271,7 +6329,7 @@ find_field_in_tables(THD *thd, Item_ident *item, const char *table_name= item->table_name; const char *name= item->field_name; uint length=(uint) strlen(name); - char name_buff[NAME_LEN+1]; + char name_buff[SAFE_NAME_LEN+1]; TABLE_LIST *cur_table= first_table; TABLE_LIST *actual_table; bool allow_rowid; @@ -6437,7 +6495,7 @@ find_field_in_tables(THD *thd, Item_ident *item, (report_error == REPORT_ALL_ERRORS || report_error == REPORT_EXCEPT_NON_UNIQUE)) { - char buff[NAME_LEN*2 + 2]; + char buff[SAFE_NAME_LEN*2 + 2]; if (db && db[0]) { strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); @@ -7823,7 +7881,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, { Field_iterator_table_ref field_iterator; bool found; - char name_buff[NAME_LEN+1]; + char name_buff[SAFE_NAME_LEN+1]; DBUG_ENTER("insert_fields"); DBUG_PRINT("arena", ("stmt arena: 0x%lx", (ulong)thd->stmt_arena)); @@ -8222,6 +8280,8 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values, table->auto_increment_field_not_null= FALSE; f.rewind(); } + else if (thd->lex->unit.insert_table_with_stored_vcol) + tbl_list.push_back(thd->lex->unit.insert_table_with_stored_vcol); while ((fld= f++)) { if (!(field= fld->filed_for_view_update())) @@ -8270,7 +8330,7 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values, prev_table= table; if (table->vfield) { - if (update_virtual_fields(table, TRUE)) + if (update_virtual_fields(thd, table, TRUE)) { goto err; } @@ -8338,7 +8398,7 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields, if (item_field && item_field->field && (table= item_field->field->table) && table->vfield) - result= update_virtual_fields(table, TRUE); + result= update_virtual_fields(thd, table, TRUE); } } return result; @@ -8434,7 +8494,7 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors, prev_table= table; if (table->vfield) { - if (update_virtual_fields(table, TRUE)) + if (update_virtual_fields(thd, table, TRUE)) { goto err; } @@ -8494,7 +8554,7 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, { TABLE *table= (*ptr)->table; if (table->vfield) - result= update_virtual_fields(table, TRUE); + result= update_virtual_fields(thd, table, TRUE); } return result; @@ -8534,15 +8594,15 @@ my_bool mysql_rm_tmp_tables(void) (file->name[1] == '.' && !file->name[2]))) continue; - if (!bcmp((uchar*) file->name, (uchar*) tmp_file_prefix, - tmp_file_prefix_length)) + if (!memcmp(file->name, tmp_file_prefix, + tmp_file_prefix_length)) { 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((uchar*) reg_ext, (uchar*) ext, ext_len)) + if (!strcmp(reg_ext, ext)) { handler *handler_file= 0; /* We should cut file extention before deleting of table */ @@ -8910,7 +8970,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) /* SYNOPSIS - abort_and_upgrade_lock() + abort_and_upgrade_lock_and_close_table() lpt Parameter passing struct All parameters passed through the ALTER_PARTITION_PARAM_TYPE object RETURN VALUE @@ -8919,7 +8979,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) Remember old lock level (for possible downgrade later on), abort all waiting threads and ensure that all keeping locks currently are completed such that we own the lock exclusively and no other interaction - is ongoing. + is ongoing. Close the table and hold the name lock. thd Thread object table Table object @@ -8928,18 +8988,26 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; - DBUG_ENTER("abort_and_upgrade_locks"); + const char *db= lpt->db; + const char *table_name= lpt->table_name; + THD *thd= lpt->thd; + DBUG_ENTER("abort_and_upgrade_lock_and_close_table"); lpt->old_lock_type= lpt->table->reginfo.lock_type; + safe_mutex_assert_not_owner(&LOCK_open); VOID(pthread_mutex_lock(&LOCK_open)); /* If MERGE child, forward lock handling to parent. */ - mysql_lock_abort(lpt->thd, lpt->table->parent ? lpt->table->parent : - lpt->table, TRUE); - VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags, - FALSE)); + mysql_lock_abort(thd, lpt->table->parent ? lpt->table->parent : lpt->table, + TRUE); + if (remove_table_from_cache(thd, db, table_name, flags, FALSE)) + { + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(1); + } + close_data_files_and_morph_locks(thd, db, table_name); VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(0); } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 07972d9b3e4..da582c37ae9 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -42,9 +42,13 @@ void mysql_client_binlog_statement(THD* thd) if (check_global_access(thd, SUPER_ACL)) DBUG_VOID_RETURN; - size_t coded_len= thd->lex->comment.length + 1; + size_t coded_len= thd->lex->comment.length; + if (!coded_len) + { + my_error(ER_SYNTAX_ERROR, MYF(0)); + DBUG_VOID_RETURN; + } size_t decoded_len= base64_needed_decoded_length(coded_len); - DBUG_ASSERT(coded_len > 0); /* Allocation @@ -145,14 +149,16 @@ void mysql_client_binlog_statement(THD* thd) /* Checking that the first event in the buffer is not truncated. */ - ulong event_len= uint4korr(bufptr + EVENT_LEN_OFFSET); - DBUG_PRINT("info", ("event_len=%lu, bytes_decoded=%d", - event_len, bytes_decoded)); - if (bytes_decoded < EVENT_LEN_OFFSET || (uint) bytes_decoded < event_len) + ulong event_len; + if (bytes_decoded < EVENT_LEN_OFFSET + 4 || + (event_len= uint4korr(bufptr + EVENT_LEN_OFFSET)) > + (uint) bytes_decoded) { my_error(ER_SYNTAX_ERROR, MYF(0)); goto end; } + DBUG_PRINT("info", ("event_len=%lu, bytes_decoded=%d", + event_len, bytes_decoded)); /* If we have not seen any Format_description_event, then we must @@ -190,17 +196,6 @@ void mysql_client_binlog_statement(THD* thd) bufptr += event_len; DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code())); -#ifndef HAVE_valgrind - /* - This debug printout should not be used for valgrind builds - since it will read from unassigned memory. - */ - DBUG_PRINT("info",("bufptr+EVENT_TYPE_OFFSET: 0x%lx", - (long) (bufptr+EVENT_TYPE_OFFSET))); - DBUG_PRINT("info", ("bytes_decoded: %d bufptr: 0x%lx buf[EVENT_LEN_OFFSET]: %lu", - bytes_decoded, (long) bufptr, - (ulong) uint4korr(bufptr+EVENT_LEN_OFFSET))); -#endif ev->thd= thd; /* We go directly to the application phase, since we don't need diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index e07806a56ab..5385acc934f 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -60,13 +60,13 @@ public: } void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); } void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); } - my_bool is_set(uint n) const { return bitmap_is_set(&map, n); } - my_bool is_prefix(uint n) const { return bitmap_is_prefix(&map, n); } - my_bool is_clear_all() const { return bitmap_is_clear_all(&map); } - my_bool is_set_all() const { return bitmap_is_set_all(&map); } - my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); } - my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); } - my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } + bool is_set(uint n) const { return bitmap_is_set(&map, n); } + bool is_prefix(uint n) const { return bitmap_is_prefix(&map, n); } + bool is_clear_all() const { return bitmap_is_clear_all(&map); } + bool is_set_all() const { return bitmap_is_set_all(&map); } + bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); } + bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); } + bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } char *print(char *buf) const { char *s=buf; @@ -155,14 +155,14 @@ public: void intersect_extended(ulonglong map2) { map&= map2; } void subtract(Bitmap<64>& map2) { map&= ~map2.map; } void merge(Bitmap<64>& map2) { map|= map2.map; } - my_bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); } - my_bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; } - my_bool is_clear_all() const { return map == (ulonglong)0; } - my_bool is_set_all() const { return map == ~(ulonglong)0; } - my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); } - my_bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; } - my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; } - char *print(char *buf) const { longlong2str(map,buf,16); return buf; } + bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); } + bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; } + bool is_clear_all() const { return map == (ulonglong)0; } + bool is_set_all() const { return map == ~(ulonglong)0; } + bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); } + bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; } + bool operator==(const Bitmap<64>& map2) const { return map == map2.map; } + char *print(char *buf) const { longlong2str(map,buf,16,1); return buf; } ulonglong to_ulonglong() const { return map; } class Iterator : public Table_map_iterator { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 302d5e95a28..fb3d201e222 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -740,7 +740,7 @@ inline void Query_cache_query::lock_writing() remove it. */ -my_bool Query_cache_query::try_lock_writing() +bool Query_cache_query::try_lock_writing() { DBUG_ENTER("Query_cache_block::try_lock_writing"); if (rw_trywrlock(&lock)!=0) @@ -1679,7 +1679,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", thd->limit_found_rows = query->found_rows(); thd->status_var.last_query_cost= 0.0; thd->query_plan_flags= (thd->query_plan_flags & ~QPLAN_QC_NO) | QPLAN_QC; - thd->main_da.disable_status(); + if (!thd->main_da.is_set()) + thd->main_da.disable_status(); BLOCK_UNLOCK_RD(query_block); DBUG_RETURN(1); // Result sent to client diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 44fc3123b98..91666625a12 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -121,7 +121,7 @@ struct Query_cache_block block_type type; TABLE_COUNTER_TYPE n_tables; // number of tables in query - inline my_bool is_free(void) { return type == FREE; } + inline bool is_free(void) { return type == FREE; } void init(ulong length); void destroy(); inline uint headers_len(); @@ -162,7 +162,7 @@ struct Query_cache_query } void lock_writing(); void lock_reading(); - my_bool try_lock_writing(); + bool try_lock_writing(); void unlock_writing(); void unlock_reading(); }; @@ -312,7 +312,7 @@ protected: uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin - my_bool initialized; + bool initialized; /* Exclude/include from cyclic double linked list */ static void double_linked_list_exclude(Query_cache_block *point, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c48a0b0e7fb..28450f7f223 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -803,6 +803,10 @@ THD::THD() thr_lock_owner_init(&main_lock_id, &lock_info); m_internal_handler= NULL; + arena_for_cached_items= 0; + current_user_used= FALSE; + memset(&invoker_user, 0, sizeof(invoker_user)); + memset(&invoker_host, 0, sizeof(invoker_host)); } @@ -1215,13 +1219,13 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, while (to != end) *(to++)+= *(from++) - *(dec++); - to_var->bytes_received= (from_var->bytes_received - - dec_var->bytes_received); - to_var->bytes_sent+= from_var->bytes_sent - dec_var->bytes_sent; - to_var->binlog_bytes_written= (from_var->binlog_bytes_written - - dec_var->binlog_bytes_written); - to_var->cpu_time+= from_var->cpu_time - dec_var->cpu_time; - to_var->busy_time+= from_var->busy_time - dec_var->busy_time; + to_var->bytes_received+= from_var->bytes_received - + dec_var->bytes_received; + to_var->bytes_sent+= from_var->bytes_sent - dec_var->bytes_sent; + to_var->binlog_bytes_written+= from_var->binlog_bytes_written - + dec_var->binlog_bytes_written; + to_var->cpu_time+= from_var->cpu_time - dec_var->cpu_time; + to_var->busy_time+= from_var->busy_time - dec_var->busy_time; } #define SECONDS_TO_WAIT_FOR_KILL 2 @@ -1428,6 +1432,7 @@ void THD::cleanup_after_query() where= THD::DEFAULT_WHERE; /* reset table map for multi-table update */ table_map_for_update= 0; + clean_current_user_used(); } @@ -2190,9 +2195,21 @@ bool select_export::send_data(List<Item> &items) const char *from_end_pos; const char *error_pos; uint32 bytes; - bytes= well_formed_copy_nchars(write_cs, cvt_buff, sizeof(cvt_buff), + uint64 estimated_bytes= + ((uint64) res->length() / res->charset()->mbminlen + 1) * + write_cs->mbmaxlen + 1; + set_if_smaller(estimated_bytes, UINT_MAX32); + if (cvt_str.realloc((uint32) estimated_bytes)) + { + my_error(ER_OUTOFMEMORY, MYF(0), (uint32) estimated_bytes); + goto err; + } + + bytes= well_formed_copy_nchars(write_cs, (char *) cvt_str.ptr(), + cvt_str.alloced_length(), res->charset(), res->ptr(), res->length(), - sizeof(cvt_buff), + UINT_MAX32, // copy all input chars, + // i.e. ignore nchars parameter &well_formed_error_pos, &cannot_convert_error_pos, &from_end_pos); @@ -2210,6 +2227,15 @@ bool select_export::send_data(List<Item> &items) "string", printable_buff, item->name, (ulong) row_count); } + else if (from_end_pos < res->ptr() + res->length()) + { + /* + result is longer than UINT_MAX32 and doesn't fit into String + */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED), + item->full_name(), row_count); + } cvt_str.length(bytes); res= &cvt_str; } @@ -3514,6 +3540,23 @@ void THD::set_query(char *query_arg, uint32 query_length_arg) pthread_mutex_unlock(&LOCK_thd_data); } +void THD::get_definer(LEX_USER *definer) +{ + set_current_user_used(); +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + if (slave_thread && has_invoker()) + { + definer->user = invoker_user; + definer->host= invoker_host; + definer->password= null_lex_str; + definer->plugin= empty_lex_str; + definer->auth= empty_lex_str; + } + else +#endif + get_default_definer(this, definer); +} + /** Mark transaction to rollback and mark error as fatal to a sub-statement. @@ -3612,9 +3655,13 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state) bool xid_cache_insert(XID_STATE *xid_state) { pthread_mutex_lock(&LOCK_xid_cache); - DBUG_ASSERT(hash_search(&xid_cache, xid_state->xid.key(), - xid_state->xid.key_length())==0); - my_bool res=my_hash_insert(&xid_cache, (uchar*)xid_state); + if (hash_search(&xid_cache, xid_state->xid.key(), xid_state->xid.key_length())) + { + pthread_mutex_unlock(&LOCK_xid_cache); + my_error(ER_XAER_DUPID, MYF(0)); + return TRUE; + } + my_bool res= my_hash_insert(&xid_cache, (uchar*)xid_state); pthread_mutex_unlock(&LOCK_xid_cache); return res; } @@ -4008,7 +4055,6 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end) if (stmt_end) { pending->set_flags(Rows_log_event::STMT_END_F); - pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; binlog_table_maps= 0; } @@ -4136,7 +4182,6 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, { Query_log_event qinfo(this, query_arg, query_len, is_trans, suppress_use, errcode); - qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; /* Binlog table maps will be irrelevant after a Query_log_event (they are just removed on the slave side) so after the query diff --git a/sql/sql_class.h b/sql/sql_class.h index bf84d12cc58..fc5b15b3916 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -156,9 +156,10 @@ enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE }; enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, DELAY_KEY_WRITE_ALL }; -enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, - SLAVE_EXEC_MODE_IDEMPOTENT, - SLAVE_EXEC_MODE_LAST_BIT}; + +#define SLAVE_EXEC_MODE_STRICT (1U << 0) +#define SLAVE_EXEC_MODE_IDEMPOTENT (1U << 1) + enum enum_mark_columns { MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE}; @@ -365,6 +366,9 @@ struct system_variables When attempting to access a dynamic variable, if the session version is out of date, then the session version is updated and realloced if neccessary and bytes copied from global to make up for missing data. + + Note that one should use my_bool instead of bool here, as the variables + are used with my_getopt.c */ ulong dynamic_variables_version; char* dynamic_variables_ptr; @@ -500,7 +504,11 @@ struct system_variables }; -/* per thread status variables */ +/** + Per thread status variables. + Must be long/ulong up to last_system_status_var so that + add_to_status/add_diff_to_status can work. +*/ typedef struct system_status_var { @@ -568,17 +576,15 @@ typedef struct system_status_var Number of statements sent from the client */ ulong questions; - ulong empty_queries; - ulong access_denied_errors; /* Can only be 0 or 1 */ - ulong lost_connections; /* IMPORTANT! SEE last_system_status_var DEFINITION BELOW. - Below 'last_system_status_var' are all variables which doesn't make any - sense to add to the /global/ status variable counter. - Status variables which it does not make sense to add to - global status variable counter + Below 'last_system_status_var' are all variables that cannot be handled + automatically by add_to_status()/add_diff_to_status(). */ + ulong empty_queries; + ulong access_denied_errors; /* Can only be 0 or 1 */ + ulong lost_connections; ulonglong bytes_received; ulonglong bytes_sent; ulonglong binlog_bytes_written; @@ -1842,8 +1848,15 @@ public: */ ha_rows sent_row_count; - /* - number of rows we read, sent or not, including in create_sort_index() + /** + Number of rows read and/or evaluated for a statement. Used for + slow log reporting. + + An examined row is defined as a row that is read and/or evaluated + according to a statement condition, including in + create_sort_index(). Rows may be counted more than once, e.g., a + statement including ORDER BY could possibly evaluate the row in + filesort() before reading it for e.g. update. */ ha_rows examined_row_count; @@ -1977,7 +1990,7 @@ public: bool no_warnings_for_error; /* no warnings on call to my_error() */ /* set during loop of derived table processing */ bool derived_tables_processing; - my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ + bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; @@ -2170,6 +2183,11 @@ public: start_time= user_time= t; start_utime= utime_after_lock= my_micro_time(); } + /*TODO: this will be obsolete when we have support for 64 bit my_time_t */ + inline bool is_valid_time() + { + return (start_time < (time_t) MY_TIME_T_MAX); + } void set_time_after_lock() { utime_after_lock= my_micro_time(); } ulonglong current_utime() { return my_micro_time(); } inline ulonglong found_rows(void) @@ -2476,6 +2494,39 @@ public: Protected with LOCK_thd_data mutex. */ void set_query(char *query_arg, uint32 query_length_arg); + void set_current_user_used() { current_user_used= TRUE; } + bool is_current_user_used() { return current_user_used; } + void clean_current_user_used() { current_user_used= FALSE; } + void get_definer(LEX_USER *definer); + void set_invoker(const LEX_STRING *user, const LEX_STRING *host) + { + invoker_user= *user; + invoker_host= *host; + } + LEX_STRING get_invoker_user() { return invoker_user; } + LEX_STRING get_invoker_host() { return invoker_host; } + bool has_invoker() { return invoker_user.length > 0; } + +private: + /* + This reference points to the table arena when the expression + for a virtual column is being evaluated + */ + Query_arena *arena_for_cached_items; + +public: + void reset_arena_for_cached_items(Query_arena *new_arena) + { + arena_for_cached_items= new_arena; + } + Query_arena *switch_to_arena_for_cached_items(Query_arena *backup) + { + if (!arena_for_cached_items) + return 0; + set_n_backup_active_arena(arena_for_cached_items, backup); + return backup; + } + private: /** The current internal error handler for this thread, or NULL. */ Internal_error_handler *m_internal_handler; @@ -2495,6 +2546,25 @@ private: tree itself is reused between executions and thus is stored elsewhere. */ MEM_ROOT main_mem_root; + + /** + It will be set TURE if CURRENT_USER() is called in account management + statements or default definer is set in CREATE/ALTER SP, SF, Event, + TRIGGER or VIEW statements. + + Current user will be binlogged into Query_log_event if current_user_used + is TRUE; It will be stored into invoker_host and invoker_user by SQL thread. + */ + bool current_user_used; + + /** + It points to the invoker in the Query_log_event. + SQL thread use it as the default definer in CREATE/ALTER SP, SF, Event, + TRIGGER or VIEW statements or current user in account management + statements if it is not NULL. + */ + LEX_STRING invoker_user; + LEX_STRING invoker_host; }; /** A short cut for thd->main_da.set_ok_status(). */ @@ -2553,7 +2623,7 @@ class select_result :public Sql_alloc { protected: THD *thd; SELECT_LEX_UNIT *unit; - uint nest_level; + int nest_level; public: select_result(); virtual ~select_result() {}; @@ -2694,7 +2764,7 @@ public: Creates a select_export to represent INTO OUTFILE <filename> with a defined level of subquery nesting. */ - select_export(sql_exchange *ex, uint nest_level_arg) :select_to_file(ex) + select_export(sql_exchange *ex, int nest_level_arg) :select_to_file(ex) { nest_level= nest_level_arg; } @@ -2711,7 +2781,7 @@ public: Creates a select_export to represent INTO DUMPFILE <filename> with a defined level of subquery nesting. */ - select_dump(sql_exchange *ex, uint nest_level_arg) : + select_dump(sql_exchange *ex, int nest_level_arg) : select_to_file(ex) { nest_level= nest_level_arg; @@ -2787,7 +2857,7 @@ public: }; -#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) +#if defined(WITH_ARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) #include <maria.h> #define ENGINE_COLUMNDEF MARIA_COLUMNDEF #else @@ -3162,10 +3232,10 @@ class user_var_entry Item_result type; bool unsigned_flag; - double val_real(my_bool *null_value); - longlong val_int(my_bool *null_value) const; - String *val_str(my_bool *null_value, String *str, uint decimals); - my_decimal *val_decimal(my_bool *null_value, my_decimal *result); + double val_real(bool *null_value); + longlong val_int(bool *null_value) const; + String *val_str(bool *null_value, String *str, uint decimals); + my_decimal *val_decimal(bool *null_value, my_decimal *result); DTCollation collation; }; @@ -3210,13 +3280,16 @@ public: ulonglong max_in_memory_size) { register ulonglong max_elems_in_tree= - (1 + max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size)); + max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size); return (int) (sizeof(uint)*(1 + nkeys/max_elems_in_tree)); } void reset(); bool walk(tree_walk_action action, void *walk_action_arg); + uint get_size() const { return size; } + ulonglong get_max_in_memory_size() const { return max_in_memory_size; } + friend int unique_write_to_file(uchar* key, element_count count, Unique *unique); friend int unique_write_to_ptrs(uchar* key, element_count count, Unique *unique); }; @@ -3325,7 +3398,7 @@ public: Creates a select_dumpvar to represent INTO <variable> with a defined level of subquery nesting. */ - select_dumpvar(uint nest_level_arg) + select_dumpvar(int nest_level_arg) { var_list.empty(); row_count= 0; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 30c6c4fc653..1c2ae915259 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -257,6 +257,7 @@ end: #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. diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index ea667543040..308c49fc15c 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -608,7 +608,7 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) thd->set_n_backup_active_arena(this, &backup_arena); /* Create a list of fields and start sequential scan */ rc= result->prepare(item_list, &fake_unit); - if (!rc && !(rc= table->file->ha_rnd_init(TRUE))) + if (!rc && !(rc= table->file->ha_rnd_init_with_error(TRUE))) is_rnd_inited= 1; thd->restore_active_arena(this, &backup_arena); @@ -658,7 +658,12 @@ void Materialized_cursor::fetch(ulong num_rows) if ((res= table->file->ha_rnd_next(table->record[0]))) break; /* Send data only if the read was successful. */ - result->send_data(item_list); + /* + If network write failed (i.e. due to a closed socked), + the error has already been set. Just return. + */ + if (result->send_data(item_list)) + return; } switch (res) { diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 94be8a5f240..1dd659283ac 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -642,6 +642,18 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, goto exit2; } + /* + Close and mark for re-open all HANDLER tables which are marked for flush + or which there are pending conflicing locks against. This is needed to + prevent deadlocks. + */ + if (thd->handler_tables_hash.records) + { + pthread_mutex_lock(&LOCK_open); + mysql_ha_flush(thd); + pthread_mutex_unlock(&LOCK_open); + } + VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); /* Check directory */ @@ -788,6 +800,18 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if ((error=wait_if_global_read_lock(thd,0,1))) goto exit2; + /* + Close and mark for re-open all HANDLER tables which are marked for flush + or which there are pending conflicing locks against. This is needed to + prevent deadlocks. + */ + if (thd->handler_tables_hash.records) + { + pthread_mutex_lock(&LOCK_open); + mysql_ha_flush(thd); + pthread_mutex_unlock(&LOCK_open); + } + VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); /* @@ -886,6 +910,18 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) goto exit2; } + /* + Close and mark for re-open all HANDLER tables which are marked for flush + or which there are pending conflicing locks against. This is needed to + prevent deadlocks. + */ + if (thd->handler_tables_hash.records) + { + pthread_mutex_lock(&LOCK_open); + mysql_ha_flush(thd); + pthread_mutex_unlock(&LOCK_open); + } + VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0); @@ -1539,12 +1575,9 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) Security_context *sctx= thd->security_ctx; ulong db_access= sctx->db_access; CHARSET_INFO *db_default_cl; - DBUG_ENTER("mysql_change_db"); - DBUG_PRINT("enter",("name: '%s'", new_db_name->str)); - if (new_db_name == NULL || - new_db_name->length == 0) + if (new_db_name->length == 0) { if (force_switch) { @@ -1553,8 +1586,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) after loading stored program. The thing is that loading of stored program can happen when there is no current database. - TODO: actually, new_db_name and new_db_name->str seem to be always - non-NULL. In case of stored program, new_db_name->str == "" and + In case of stored program, new_db_name->str == "" and new_db_name->length == 0. */ @@ -1569,6 +1601,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) DBUG_RETURN(TRUE); } } + DBUG_PRINT("enter",("name: '%s'", new_db_name->str)); if (is_schema_db(new_db_name->str, new_db_name->length)) { diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ddb6af97865..5564d628594 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -33,7 +33,7 @@ */ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_LIST *order, ha_rows limit, ulonglong options, + SQL_I_List<ORDER> *order, ha_rows limit, ulonglong options, bool reset_auto_increment) { bool will_batch; @@ -84,7 +84,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (select_lex->setup_ref_array(thd, order->elements) || setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, (ORDER*) order->first)) + fields, all_fields, order->first)) { delete select; free_underlaid_joins(thd, &thd->lex->select_lex); @@ -130,7 +130,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - there should be no delete triggers associated with the table. */ if (!using_limit && const_cond_result && - !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && (thd->lex->sql_command == SQLCOM_TRUNCATE || (!thd->current_stmt_binlog_row_based && !(table->triggers && table->triggers->has_delete_triggers())))) @@ -230,14 +229,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ha_rows examined_rows; if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR) - usable_index= get_index_for_order(table, (ORDER*)(order->first), limit); + usable_index= get_index_for_order(table, order->first, limit); if (usable_index == MAX_KEY) { table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE), MYF(MY_FAE | MY_ZEROFILL)); - if (!(sortorder= make_unireg_sortorder((ORDER*) order->first, + if (!(sortorder= make_unireg_sortorder(order->first, &length, NULL)) || (table->sort.found_records = filesort(thd, table, sortorder, length, select, HA_POS_ERROR, 1, @@ -248,6 +247,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, &thd->lex->select_lex); DBUG_RETURN(TRUE); } + thd->examined_row_count+= examined_rows; /* Filesort has already found and selected the rows we want to delete, so we don't need the where clause @@ -265,8 +265,15 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, select_lex); DBUG_RETURN(TRUE); } - if (usable_index==MAX_KEY) - init_read_record(&info, thd, table, select, 1, 1, FALSE); + if (usable_index == MAX_KEY || (select && select->quick)) + { + if (init_read_record(&info, thd, table, select, 1, 1, FALSE)) + { + delete select; + free_underlaid_joins(thd, select_lex); + DBUG_RETURN(TRUE); + } + } else init_read_record_idx(&info, thd, table, 1, usable_index); @@ -304,6 +311,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { + update_virtual_fields(thd, table); + thd->examined_row_count++; // thd->is_error() is tested to disallow delete row on error if (!select || select->skip_record(thd) > 0) { @@ -547,7 +556,7 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) int mysql_multi_delete_prepare(THD *thd) { LEX *lex= thd->lex; - TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxiliary_table_list.first; + TABLE_LIST *aux_tables= lex->auxiliary_table_list.first; TABLE_LIST *target_tbl; DBUG_ENTER("mysql_multi_delete_prepare"); @@ -943,7 +952,10 @@ int multi_delete::do_table_deletes(TABLE *table, bool ignore) READ_RECORD info; ha_rows last_deleted= deleted; DBUG_ENTER("do_deletes_for_table"); - init_read_record(&info, thd, table, NULL, 0, 1, FALSE); + + if (init_read_record(&info, thd, table, NULL, 0, 1, FALSE)) + DBUG_RETURN(1); + /* Ignore any rows not found in reference tables as they may already have been deleted by foreign key handling diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 22240d3a300..1c1e518e9c9 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -282,13 +282,13 @@ bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) lex->current_select= first_select; res= mysql_select(thd, &first_select->ref_pointer_array, - (TABLE_LIST*) first_select->table_list.first, + first_select->table_list.first, first_select->with_wild, first_select->item_list, first_select->where, (first_select->order_list.elements+ first_select->group_list.elements), - (ORDER *) first_select->order_list.first, - (ORDER *) first_select->group_list.first, + first_select->order_list.first, + first_select->group_list.first, first_select->having, (ORDER*) NULL, (first_select->options | thd->options | SELECT_NO_UNLOCK), diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 2f3ce99ab9c..69be8c8e9b4 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -539,6 +539,14 @@ retry: my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias); goto err; } + /* Check if the same index involved. */ + if ((uint) keyno != table->file->get_index()) + { + if (mode == RNEXT) + mode= RFIRST; + else if (mode == RPREV) + mode= RLAST; + } } if (insert_fields(thd, &thd->lex->select_lex.context, @@ -561,9 +569,16 @@ retry: case RNEXT: if (table->file->inited != handler::NONE) { - error=keyname ? - table->file->ha_index_next(table->record[0]) : - table->file->ha_rnd_next(table->record[0]); + if (keyname) + { + /* Check if we read from the same index. */ + DBUG_ASSERT((uint) keyno == table->file->get_index()); + error= table->file->ha_index_next(table->record[0]); + } + else + { + error= table->file->ha_rnd_next(table->record[0]); + } break; } /* else fall through */ @@ -584,6 +599,8 @@ retry: break; case RPREV: DBUG_ASSERT(keyname != 0); + /* Check if we read from the same index. */ + DBUG_ASSERT((uint) keyno == table->file->get_index()); if (table->file->inited != handler::NONE) { error=table->file->ha_index_prev(table->record[0]); @@ -664,7 +681,7 @@ retry: goto ok; } /* Generate values for virtual fields */ - update_virtual_fields(table); + update_virtual_fields(thd, table); if (cond && !cond->val_int()) continue; if (num_rows >= offset_limit_cnt) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 5658a3578ab..916557a46c4 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -182,11 +182,14 @@ int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields, SQL_SELECT *select, List<String> *names, String *name, String *description, String *example) { - DBUG_ENTER("search_topics"); int count= 0; - READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, topics, select, 1, 0, FALSE); + DBUG_ENTER("search_topics"); + + /* Should never happen. As this is part of help, we can ignore this */ + if (init_read_record(&read_record_info, thd, topics, select, 1, 0, FALSE)) + DBUG_RETURN(0); + while (!read_record_info.read_record(&read_record_info)) { if (!select->cond->val_int()) // Doesn't match like @@ -222,11 +225,13 @@ int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields, int search_keyword(THD *thd, TABLE *keywords, struct st_find_field *find_fields, SQL_SELECT *select, int *key_id) { - DBUG_ENTER("search_keyword"); int count= 0; - READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, keywords, select, 1, 0, FALSE); + DBUG_ENTER("search_keyword"); + /* Should never happen. As this is part of help, we can ignore this */ + if (init_read_record(&read_record_info, thd, keywords, select, 1, 0, FALSE)) + DBUG_RETURN(0); + while (!read_record_info.read_record(&read_record_info) && count<2) { if (!select->cond->val_int()) // Dosn't match like @@ -347,10 +352,11 @@ int search_categories(THD *thd, TABLE *categories, Field *pcat_id= find_fields[help_category_help_category_id].field; int count= 0; READ_RECORD read_record_info; - DBUG_ENTER("search_categories"); - init_read_record(&read_record_info, thd, categories, select,1,0,FALSE); + /* Should never happen. As this is part of help, we can ignore this */ + if (init_read_record(&read_record_info, thd, categories, select,1,0,FALSE)) + DBUG_RETURN(0); while (!read_record_info.read_record(&read_record_info)) { if (select && !select->cond->val_int()) @@ -381,10 +387,13 @@ int search_categories(THD *thd, TABLE *categories, void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname, SQL_SELECT *select, List<String> *res) { + READ_RECORD read_record_info; DBUG_ENTER("get_all_items_for_category"); - READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, items, select,1,0,FALSE); + /* Should never happen. As this is part of help, we can ignore this */ + if (init_read_record(&read_record_info, thd, items, select,1,0,FALSE)) + DBUG_VOID_RETURN; + while (!read_record_info.read_record(&read_record_info)) { if (!select->cond->val_int()) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 54234eb8ab4..bab92ca7368 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -273,7 +273,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } /* Mark virtual columns used in the insert statement */ if (table->vfield) - table->mark_virtual_columns_for_write(); + table->mark_virtual_columns_for_write(TRUE); // For the values we need select_priv #ifndef NO_EMBEDDED_ACCESS_CHECKS table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); @@ -881,7 +881,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, auto_inc values from the delayed_insert thread as they share TABLE. */ table->file->ha_release_auto_increment(); - if (using_bulk_insert && table->file->ha_end_bulk_insert(0) && !error) + if (using_bulk_insert && table->file->ha_end_bulk_insert() && !error) { table->file->print_error(my_errno,MYF(0)); error=1; @@ -1267,7 +1267,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert)) DBUG_RETURN(TRUE); - /* Prepare the fields in the statement. */ if (values) { @@ -1320,6 +1319,18 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!table) table= table_list->table; + if (!fields.elements && table->vfield) + { + for (Field **vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++) + { + if ((*vfield_ptr)->stored_in_db) + { + thd->lex->unit.insert_table_with_stored_vcol= table; + break; + } + } + } + if (!select_insert) { Item *fake_conds= 0; @@ -1504,7 +1515,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) table->file->adjust_next_insert_id_after_explicit_value( table->next_number_field->val_int()); info->touched++; - if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ && + if (((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) && !bitmap_is_subset(table->write_set, table->read_set)) || compare_record(table)) { @@ -2098,7 +2109,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) copy= (TABLE*) client_thd->alloc(sizeof(*copy)+ (share->fields+1)*sizeof(Field**)+ share->reclength + - share->column_bitmap_size*2); + share->column_bitmap_size*3); if (!copy) goto error; @@ -2108,7 +2119,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) /* Assign the pointers for the field pointers array and the record. */ field= copy->field= (Field**) (copy + 1); bitmap= (uchar*) (field + share->fields + 1); - copy->record[0]= (bitmap + share->column_bitmap_size * 2); + copy->record[0]= (bitmap + share->column_bitmap_size*3); memcpy((char*) copy->record[0], (char*) table->record[0], share->reclength); /* Make a copy of all fields. @@ -2150,10 +2161,13 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) copy->def_read_set.bitmap= (my_bitmap_map*) bitmap; copy->def_write_set.bitmap= ((my_bitmap_map*) (bitmap + share->column_bitmap_size)); + copy->def_vcol_set.bitmap= ((my_bitmap_map*) + (bitmap + 2*share->column_bitmap_size)); copy->tmp_set.bitmap= 0; // To catch errors - bzero((char*) bitmap, share->column_bitmap_size*2); + bzero((char*) bitmap, share->column_bitmap_size*3); copy->read_set= ©->def_read_set; copy->write_set= ©->def_write_set; + copy->vcol_set= ©->def_vcol_set; DBUG_RETURN(copy); @@ -3274,7 +3288,7 @@ bool select_insert::send_eof() DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); - error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert(0) : 0; + error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert() : 0; table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); @@ -3357,7 +3371,7 @@ void select_insert::abort() { before. */ if (!thd->prelocked_mode) - table->file->ha_end_bulk_insert(0); + table->file->ha_end_bulk_insert(); /* If at least one row has been inserted/modified and will stay in @@ -3473,7 +3487,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, tmp_table.s->db_low_byte_first= test(create_info->db_type == myisam_hton || create_info->db_type == heap_hton); - tmp_table.null_row=tmp_table.maybe_null=0; + tmp_table.null_row= 0; + tmp_table.maybe_null= 0; while ((item=it++)) { @@ -3910,6 +3925,17 @@ void select_create::abort() if (table) { + if (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + thd->current_stmt_binlog_row_based && + !(thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && + mysql_bin_log.is_open()) + { + /* + This should be removed after BUG#47899. + */ + mysql_bin_log.reset_gathered_updates(thd); + } + table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); if (!create_info->table_existed) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7b19b4874b1..0a4e112671e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -110,39 +110,31 @@ st_parsing_options::reset() allows_derived= TRUE; } -Lex_input_stream::Lex_input_stream(THD *thd, - const char* buffer, - unsigned int length) -: m_thd(thd), - yylineno(1), - yytoklen(0), - yylval(NULL), - m_ptr(buffer), - m_tok_start(NULL), - m_tok_end(NULL), - m_end_of_query(buffer + length), - m_tok_start_prev(NULL), - m_buf(buffer), - m_buf_length(length), - m_echo(TRUE), - m_cpp_tok_start(NULL), - m_cpp_tok_start_prev(NULL), - m_cpp_tok_end(NULL), - m_body_utf8(NULL), - m_cpp_utf8_processed_ptr(NULL), - next_state(MY_LEX_START), - found_semicolon(NULL), - ignore_space(test(thd->variables.sql_mode & MODE_IGNORE_SPACE)), - stmt_prepare_mode(FALSE), - in_comment(NO_COMMENT), - m_underscore_cs(NULL) + +bool Lex_input_stream::init(THD *thd, char *buff, unsigned int length) { + DBUG_EXECUTE_IF("bug42064_simulate_oom", + DBUG_SET("+d,simulate_out_of_memory");); + m_cpp_buf= (char*) thd->alloc(length + 1); + + DBUG_EXECUTE_IF("bug42064_simulate_oom", + DBUG_SET("-d,bug42064_simulate_oom");); + + if (m_cpp_buf == NULL) + return TRUE; + m_cpp_ptr= m_cpp_buf; + m_thd= thd; + m_ptr= buff; + m_end_of_query= buff + length; + m_buf= buff; + m_buf_length= length; + ignore_space= test(thd->variables.sql_mode & MODE_IGNORE_SPACE); + + return FALSE; } -Lex_input_stream::~Lex_input_stream() -{} /** The operation is called from the parser in order to @@ -1311,11 +1303,10 @@ int MYSQLlex(void *arg, void *yythd) ulong version; version=strtol(version_str, NULL, 10); - /* Accept 'M' 'm' 'm' 'd' 'd' */ - lip->yySkipn(5); - if (version <= MYSQL_VERSION_ID) { + /* Accept 'M' 'm' 'm' 'd' 'd' */ + lip->yySkipn(5); /* Expand the content of the special comment as real code */ lip->set_echo(TRUE); state=MY_LEX_START; @@ -1323,7 +1314,16 @@ int MYSQLlex(void *arg, void *yythd) } else { + /* + Patch and skip the conditional comment to avoid it + being propagated infinitely (eg. to a slave). + */ + char *pcom= lip->yyUnput(' '); comment_closed= ! consume_comment(lip, 1); + if (! comment_closed) + { + *pcom= '!'; + } /* version allowed to have one level of comment inside. */ } } @@ -1590,6 +1590,7 @@ void st_select_lex_unit::init_query() item_list.empty(); describe= 0; found_rows_for_union= 0; + insert_table_with_stored_vcol= 0; } void st_select_lex::init_query() @@ -1655,7 +1656,7 @@ void st_select_lex::init_select() linkage= UNSPECIFIED_TYPE; order_list.elements= 0; order_list.first= 0; - order_list.next= (uchar**) &order_list.first; + order_list.next= &order_list.first; /* Set limit and offset to default values */ select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ offset_limit= 0; /* denotes the default offset = 0 */ @@ -2036,7 +2037,7 @@ uint st_select_lex::get_in_sum_expr() TABLE_LIST* st_select_lex::get_table_list() { - return (TABLE_LIST*) table_list.first; + return table_list.first; } List<Item>* st_select_lex::get_item_list() @@ -2093,9 +2094,8 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type) if (fake_select_lex->order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); - fake_select_lex->print_order( - str, - (ORDER *) fake_select_lex->order_list.first, + fake_select_lex->print_order(str, + fake_select_lex->order_list.first, query_type); } fake_select_lex->print_limit(thd, str, query_type); @@ -2753,7 +2753,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) { select_lex.context.table_list= select_lex.context.first_name_resolution_table= first->next_local; - select_lex.table_list.first= (uchar*) (first->next_local); + select_lex.table_list.first= first->next_local; select_lex.table_list.elements--; //safety first->next_local= 0; /* @@ -2785,7 +2785,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) void st_lex::first_lists_tables_same() { - TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first; + TABLE_LIST *first_table= select_lex.table_list.first; if (query_tables != first_table && first_table != 0) { TABLE_LIST *next; @@ -2832,9 +2832,9 @@ void st_lex::link_first_table_back(TABLE_LIST *first, if (link_to_local) { - first->next_local= (TABLE_LIST*) select_lex.table_list.first; + first->next_local= select_lex.table_list.first; select_lex.context.table_list= first; - select_lex.table_list.first= (uchar*) first; + select_lex.table_list.first= first; select_lex.table_list.elements++; //safety } } @@ -3000,7 +3000,7 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, prep_having= *having_conds; *having_conds= having= prep_having->copy_andor_structure(thd); } - fix_prepare_info_in_table_list(thd, (TABLE_LIST *)table_list.first); + fix_prepare_info_in_table_list(thd, table_list.first); } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 335aa7f4ed4..8ec50a8b772 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -532,6 +532,13 @@ public: bool describe; /* union exec() called for EXPLAIN */ Procedure *last_procedure; /* Pointer to procedure, if such exists */ + /* + Insert table with stored virtual columns. + This is used only in those rare cases + when the list of inserted values is empty. + */ + TABLE *insert_table_with_stored_vcol; + void init_query(); st_select_lex_unit* master_unit(); st_select_lex* outer_select(); @@ -590,8 +597,8 @@ public: st_lex *parent_lex; enum olap_type olap; /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */ - SQL_LIST table_list; - SQL_LIST group_list; /* GROUP BY clause. */ + SQL_I_List<TABLE_LIST> table_list; + SQL_I_List<ORDER> group_list; /* GROUP BY clause. */ List<Item> item_list; /* list of fields & expressions */ List<String> interval_list; bool is_item_list_lookup; @@ -614,8 +621,8 @@ public: TABLE_LIST *leaf_tables; const char *type; /* type of select for EXPLAIN */ - SQL_LIST order_list; /* ORDER clause */ - SQL_LIST *gorder_list; + SQL_I_List<ORDER> order_list; /* ORDER clause */ + SQL_I_List<ORDER> *gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ // Arrays of pointers to top elements of all_fields list Item **ref_pointer_array; @@ -783,7 +790,7 @@ public: { order_list.elements= 0; order_list.first= 0; - order_list.next= (uchar**) &order_list.first; + order_list.next= &order_list.first; } /* This method created for reiniting LEX in mysql_admin_table() and can be @@ -964,6 +971,8 @@ enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE, extern const LEX_STRING null_lex_str; extern const LEX_STRING empty_lex_str; +struct Sroutine_hash_entry; + /* Class representing list of all tables used by statement. It also contains information about stored functions used by statement @@ -1004,9 +1013,9 @@ public: We use these two members for restoring of 'sroutines_list' to the state in which it was right after query parsing. */ - SQL_LIST sroutines_list; - uchar **sroutines_list_own_last; - uint sroutines_list_own_elements; + SQL_I_List<Sroutine_hash_entry> sroutines_list; + Sroutine_hash_entry **sroutines_list_own_last; + uint sroutines_list_own_elements; /* These constructor and destructor serve for creation/destruction @@ -1158,9 +1167,38 @@ enum enum_comment_state class Lex_input_stream { public: - Lex_input_stream(THD *thd, const char* buff, unsigned int length); - ~Lex_input_stream(); + Lex_input_stream() : + yylineno(1), + yytoklen(0), + yylval(NULL), + m_tok_start(NULL), + m_tok_end(NULL), + m_tok_start_prev(NULL), + m_echo(TRUE), + m_cpp_tok_start(NULL), + m_cpp_tok_start_prev(NULL), + m_cpp_tok_end(NULL), + m_body_utf8(NULL), + m_cpp_utf8_processed_ptr(NULL), + next_state(MY_LEX_START), + found_semicolon(NULL), + stmt_prepare_mode(FALSE), + in_comment(NO_COMMENT), + m_underscore_cs(NULL) + { + } + ~Lex_input_stream() + { + } + + /** + Object initializer. Must be called before usage. + + @retval FALSE OK + @retval TRUE Error + */ + bool init(THD *thd, char *buff, unsigned int length); /** Set the echo mode. @@ -1275,6 +1313,20 @@ public: } /** + Puts a character back into the stream, canceling + the effect of the last yyGet() or yySkip(). + Note that the echo mode should not change between calls + to unput, get, or skip from the stream. + */ + char *yyUnput(char ch) + { + *--m_ptr= ch; + if (m_echo) + m_cpp_ptr--; + return m_ptr; + } + + /** End of file indicator for the query text to parse. @return true if there are no more characters to parse */ @@ -1420,7 +1472,7 @@ public: private: /** Pointer to the current position in the raw input stream. */ - const char *m_ptr; + char *m_ptr; /** Starting position of the last token parsed, in the raw buffer. */ const char *m_tok_start; @@ -1611,7 +1663,8 @@ typedef struct st_lex : public Query_tables_list */ List<Name_resolution_context> context_stack; - SQL_LIST proc_list, auxiliary_table_list, save_list; + SQL_I_List<ORDER> proc_list; + SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list; Create_field *last_field; Item_sum *in_sum_func; udf_func udf; @@ -1741,7 +1794,7 @@ typedef struct st_lex : public Query_tables_list fields to TABLE object at table open (altough for latter pointer to table being opened is probably enough). */ - SQL_LIST trg_table_fields; + SQL_I_List<Item_trigger_field> trg_table_fields; /* stmt_definition_begin is intended to point to the next word after @@ -1955,10 +2008,21 @@ public: class Parser_state { public: - Parser_state(THD *thd, const char* buff, unsigned int length) - : m_lip(thd, buff, length), m_yacc() + Parser_state() + : m_yacc() {} + /** + Object initializer. Must be called before usage. + + @retval FALSE OK + @retval TRUE Error + */ + bool init(THD *thd, char *buff, unsigned int length) + { + return m_lip.init(thd, buff, length); + } + ~Parser_state() {} diff --git a/sql/sql_list.h b/sql/sql_list.h index 93cdd20c299..dc840cefc66 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -55,6 +55,73 @@ public: }; +/** + Simple intrusive linked list. + + @remark Similar in nature to base_list, but intrusive. It keeps a + a pointer to the first element in the list and a indirect + reference to the last element. +*/ +template <typename T> +class SQL_I_List :public Sql_alloc +{ +public: + uint elements; + /** The first element in the list. */ + T *first; + /** A reference to the next element in the list. */ + T **next; + + SQL_I_List() { empty(); } + + SQL_I_List(const SQL_I_List &tmp) : Sql_alloc() + { + elements= tmp.elements; + first= tmp.first; + next= elements ? tmp.next : &first; + } + + inline void empty() + { + elements= 0; + first= NULL; + next= &first; + } + + inline void link_in_list(T *element, T **next_ptr) + { + elements++; + (*next)= element; + next= next_ptr; + *next= NULL; + } + + inline void save_and_clear(SQL_I_List<T> *save) + { + *save= *this; + empty(); + } + + inline void push_front(SQL_I_List<T> *save) + { + /* link current list last */ + *save->next= first; + first= save->first; + elements+= save->elements; + } + + inline void push_back(SQL_I_List<T> *save) + { + if (save->first) + { + *next= save->first; + next= save->next; + elements+= save->elements; + } + } +}; + + /* Basic single linked list Used for item and item_buffs. diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 7399b442573..1b7f690259a 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -128,6 +128,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, bool is_fifo=0; #ifndef EMBEDDED_LIBRARY LOAD_FILE_INFO lf_info; + THD::killed_state killed_status; #endif char *db = table_list->db; // This is never null /* @@ -138,7 +139,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, char *tdb= thd->db ? thd->db : db; // Result is never null ulong skip_lines= ex->skip_lines; bool transactional_table; - THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -432,7 +432,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, error= read_sep_field(thd, info, table_list, fields_vars, set_fields, set_values, read_info, *enclosed, skip_lines, ignore); - if (!thd->prelocked_mode && table->file->ha_end_bulk_insert(0) && !error) + if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error) { table->file->print_error(my_errno, MYF(0)); error= 1; @@ -455,7 +455,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, error=1; thd->killed= THD::KILL_QUERY; };); - killed_status= (error == 0)? THD::NOT_KILLED : thd->killed; + +#ifndef EMBEDDED_LIBRARY + killed_status= (error == 0) ? THD::NOT_KILLED : thd->killed; +#endif + /* We must invalidate the table in query cache before binlog writing and ha_autocommit_... @@ -511,7 +515,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { Delete_file_log_event d(thd, db, transactional_table); - d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; (void) mysql_bin_log.write(&d); } } @@ -691,7 +694,6 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, errcode); - e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; return mysql_bin_log.write(&e); } @@ -929,6 +931,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, DBUG_RETURN(1); } } + + if (thd->is_error()) + read_info.error= 1; + if (read_info.error) break; if (skip_lines) @@ -1052,7 +1058,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, String &field_term, String &line_start, String &line_term, String &enclosed_par, int escape, bool get_it_from_net, bool is_fifo) - :file(file_par),escape_char(escape) + :file(file_par),buffer(0),escape_char(escape) { read_charset= cs; field_term_ptr=(char*) field_term.ptr(); @@ -1101,6 +1107,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, MYF(MY_WME))) { my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */ + buffer= 0; error=1; } else @@ -1131,9 +1138,8 @@ READ_INFO::~READ_INFO() { if (need_end_io_cache) ::end_io_cache(&cache); - my_free((uchar*) buffer,MYF(0)); - error=1; } + my_free((uchar*) buffer,MYF(MY_ALLOW_ZERO_PTR)); } @@ -1200,29 +1206,6 @@ int READ_INFO::read_field() while ( to < end_of_buff) { chr = GET; -#ifdef USE_MB - if ((my_mbcharlen(read_charset, chr) > 1) && - to+my_mbcharlen(read_charset, chr) <= end_of_buff) - { - uchar* p = (uchar*)to; - *to++ = chr; - int ml = my_mbcharlen(read_charset, chr); - int i; - for (i=1; i<ml; i++) { - chr = GET; - if (chr == my_b_EOF) - goto found_eof; - *to++ = chr; - } - if (my_ismbchar(read_charset, - (const char *)p, - (const char *)to)) - continue; - for (i=0; i<ml; i++) - PUSH((uchar) *--to); - chr = GET; - } -#endif if (chr == my_b_EOF) goto found_eof; if (chr == escape_char) @@ -1307,6 +1290,39 @@ int READ_INFO::read_field() return 0; } } +#ifdef USE_MB + if (my_mbcharlen(read_charset, chr) > 1 && + to + my_mbcharlen(read_charset, chr) <= end_of_buff) + { + uchar* p= (uchar*) to; + int ml, i; + *to++ = chr; + + ml= my_mbcharlen(read_charset, chr); + + for (i= 1; i < ml; i++) + { + chr= GET; + if (chr == my_b_EOF) + { + /* + Need to back up the bytes already ready from illformed + multi-byte char + */ + to-= i; + goto found_eof; + } + *to++ = chr; + } + if (my_ismbchar(read_charset, + (const char *)p, + (const char *)to)) + continue; + for (i= 0; i < ml; i++) + PUSH((uchar) *--to); + chr= GET; + } +#endif *to++ = (uchar) chr; } /* diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index dccfcbaf8ac..21deef8c664 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -146,14 +146,14 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) lex->last_selects=select_lex; - for (ORDER *order=(ORDER *)select_lex->group_list.first ; order ; order=order->next) + for (ORDER *order= select_lex->group_list.first ; order ; order=order->next) item_list_copy.push_back(*(order->item)); List<Item> all_fields(select_lex->item_list); if (setup_tables(lex->thd, &select_lex->context, &select_lex->top_join_list, - (TABLE_LIST *)select_lex->table_list.first + select_lex->table_list.first &select_lex->leaf_tables, FALSE) || setup_fields(lex->thd, 0, select_lex->item_list, MARK_COLUMNS_READ, &all_fields,1) || diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 971dc7c42d3..73862e79f12 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -28,7 +28,7 @@ #include "events.h" #include "sql_trigger.h" -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE #include "../storage/maria/ha_maria.h" #endif @@ -181,7 +181,7 @@ bool end_active_trans(THD *thd) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_commit(thd)) error=1; -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE ha_maria::implicit_commit(thd, TRUE); #endif } @@ -476,6 +476,7 @@ static void handle_bootstrap_impl(THD *thd) buff= (char*) thd->net.buff; if (!fgets(buff + length, thd->net.max_packet - length, file)) { + net_end_statement(thd); bootstrap_error= 1; break; } @@ -658,7 +659,7 @@ void cleanup_items(Item *item) */ static -int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name) +int mysql_table_dump(THD *thd, LEX_STRING *db, LEX_STRING *table_name) { TABLE* table; TABLE_LIST* table_list; @@ -672,7 +673,7 @@ int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name) if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST)))) DBUG_RETURN(1); // out of memory table_list->db= db->str; - table_list->table_name= table_list->alias= tbl_name; + table_list->table_name= table_list->alias= table_name->str; table_list->lock_type= TL_READ_NO_INSERT; table_list->prev_global= &table_list; // can be removed after merge with 4.1 @@ -683,8 +684,16 @@ int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name) goto err; /* purecov: end */ } + if (!table_name->length || + check_table_name(table_name->str, table_name->length, TRUE)) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), + table_name->str ? table_name->str : "NULL"); + error= 1; + goto err; + } if (lower_case_table_names) - my_casedn_str(files_charset_info, tbl_name); + my_casedn_str(files_charset_info, table_name->str); if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0))) DBUG_RETURN(1); @@ -692,7 +701,7 @@ int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name) if (check_one_table_access(thd, SELECT_ACL, table_list)) goto err; thd->free_list = 0; - thd->set_query(tbl_name, (uint) strlen(tbl_name)); + thd->set_query(table_name->str, table_name->length); if ((error = mysqld_dump_create_info(thd, table_list, -1))) { my_error(ER_GET_ERRNO, MYF(0), my_errno); @@ -992,7 +1001,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, NET *net= &thd->net; bool error= 0; DBUG_ENTER("dispatch_command"); - DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command)); + DBUG_PRINT("info", ("command: %d", command)); thd->command=command; /* @@ -1003,6 +1012,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->query_plan_flags= QPLAN_INIT; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); + if (!thd->is_valid_time()) + { + /* + If the time has got past 2038 we need to shut this server down + We do this by making sure every command is a shutdown and we + have enough privileges to shut the server down + + TODO: remove this when we have full 64 bit my_time_t support + */ + thd->security_ctx->master_access|= SHUTDOWN_ACL; + command= COM_SHUTDOWN; + } + VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id= global_query_id; @@ -1056,8 +1078,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif case COM_TABLE_DUMP: { - char *tbl_name; - LEX_STRING db; + LEX_STRING db, table; /* Safe because there is always a trailing \0 at the end of the packet */ uint db_len= *(uchar*) packet; if (db_len + 1 > packet_length || db_len > NAME_LEN) @@ -1083,9 +1104,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } db.length= db_len; - tbl_name= strmake(db.str, packet + 1, db_len)+1; - strmake(tbl_name, packet + db_len + 2, tbl_len); - if (mysql_table_dump(thd, &db, tbl_name) == 0) + table.length= tbl_len; + table.str= strmake(db.str, packet + 1, db_len) + 1; + strmake(table.str, packet + db_len + 2, tbl_len); + if (mysql_table_dump(thd, &db, &table) == 0) thd->main_da.disable_status(); break; } @@ -1187,7 +1209,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { char *beginning_of_next_stmt= (char*) end_of_stmt; -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE ha_maria::implicit_commit(thd, FALSE); #endif @@ -1244,7 +1266,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *fields, *packet_end= packet + packet_length, *wildcard; /* Locked closure of all tables */ TABLE_LIST table_list; - char db_buff[NAME_LEN+1]; + char db_buff[SAFE_NAME_LEN+1]; uint32 db_length; uint dummy_errors, query_length; @@ -1263,7 +1285,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, db_length= wildcard - packet; wildcard++; query_length= (uint) (packet_end - wildcard); // Don't count end \0 - if (db_length > NAME_LEN || query_length > NAME_LEN) + if (db_length > SAFE_NAME_LEN || query_length > NAME_LEN) { my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; @@ -1305,8 +1327,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_reset_thd_for_next_command(thd, opt_userstat_running); thd->lex-> - select_lex.table_list.link_in_list((uchar*) &table_list, - (uchar**) &table_list.next_local); + select_lex.table_list.link_in_list(&table_list, + &table_list.next_local); thd->lex->add_to_query_tables(&table_list); /* switch on VIEW optimisation: do not fill temporary tables */ @@ -1448,8 +1470,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in packet[0]. */ - enum mysql_enum_shutdown_level level= - (enum mysql_enum_shutdown_level) (uchar) packet[0]; + enum mysql_enum_shutdown_level level; + if (!thd->is_valid_time()) + level= SHUTDOWN_DEFAULT; + else + level= (enum mysql_enum_shutdown_level) (uchar) packet[0]; if (level == SHUTDOWN_DEFAULT) level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable else if (level != SHUTDOWN_WAIT_ALL_BUFFERS) @@ -1510,13 +1535,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (sf_malloc_max_memory+1023L)/1024L); } #endif -#ifdef EMBEDDED_LIBRARY - /* Store the buffer in permanent memory */ - my_ok(thd, 0, 0, buff); -#else +#ifndef EMBEDDED_LIBRARY VOID(my_net_write(net, (uchar*) buff, length)); VOID(net_flush(net)); thd->main_da.disable_status(); +#else + /* Store the buffer in permanent memory */ + my_ok(thd, 0, 0, buff); #endif break; } @@ -1598,7 +1623,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->transaction.stmt.reset(); -#ifdef WITH_MARIA_STORAGE_ENGINE +#ifdef WITH_ARIA_STORAGE_ENGINE ha_maria::implicit_commit(thd, FALSE); #endif @@ -1819,7 +1844,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, { DBUG_RETURN(1); } - TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; + TABLE_LIST *table_list= select_lex->table_list.first; table_list->schema_select_lex= schema_select_lex; table_list->schema_table_reformed= 1; DBUG_RETURN(0); @@ -2015,7 +2040,7 @@ mysql_execute_command(THD *thd) /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ SELECT_LEX *select_lex= &lex->select_lex; /* first table of first SELECT_LEX */ - TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; + TABLE_LIST *first_table= select_lex->table_list.first; /* list of all tables in query */ TABLE_LIST *all_tables; /* most outer SELECT_LEX_UNIT of query */ @@ -2050,7 +2075,7 @@ mysql_execute_command(THD *thd) all_tables= lex->query_tables; /* set context for commands which do not use setup_tables */ select_lex-> - context.resolve_in_table_list_only((TABLE_LIST*)select_lex-> + context.resolve_in_table_list_only(select_lex-> table_list.first); /* @@ -2396,7 +2421,7 @@ mysql_execute_command(THD *thd) thd->enable_slow_log= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; res = mysql_backup_table(thd, first_table); - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; lex->query_tables=all_tables; break; } @@ -2409,7 +2434,7 @@ mysql_execute_command(THD *thd) thd->enable_slow_log= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; res = mysql_restore_table(thd, first_table); - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; lex->query_tables=all_tables; break; } @@ -2703,7 +2728,7 @@ mysql_execute_command(THD *thd) if (create_info.used_fields & HA_CREATE_USED_UNION) { TABLE_LIST *tab; - for (tab= (TABLE_LIST*) create_info.merge_list.first; + for (tab= create_info.merge_list.first; tab; tab= tab->next_local) { @@ -2717,6 +2742,10 @@ mysql_execute_command(THD *thd) } } + /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ + if (create_info.options & HA_LEX_CREATE_TMP_TABLE) + thd->options|= OPTION_KEEP_LOG; + /* select_create is currently not re-execution friendly and needs to be created for every execution of a PS/SP. @@ -2876,7 +2905,6 @@ end_with_restore_list: check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0, is_schema_db(select_lex->db))|| check_merge_table_access(thd, first_table->db, - (TABLE_LIST *) create_info.merge_list.first)) goto error; /* purecov: inspected */ if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0)) @@ -3013,7 +3041,7 @@ end_with_restore_list: */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; lex->query_tables=all_tables; break; } @@ -3026,7 +3054,7 @@ end_with_restore_list: thd->enable_slow_log= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; res = mysql_check_table(thd, first_table, &lex->check_opt); - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; lex->query_tables=all_tables; break; } @@ -3047,7 +3075,7 @@ end_with_restore_list: */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; lex->query_tables=all_tables; break; } @@ -3060,9 +3088,7 @@ end_with_restore_list: goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; - res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? - mysql_recreate_table(thd, first_table) : - mysql_optimize_table(thd, first_table, &lex->check_opt); + res= mysql_optimize_table(thd, first_table, &lex->check_opt); /* ! we write after unlocking the table */ if (!res && !lex->no_write_to_binlog) { @@ -3071,7 +3097,7 @@ end_with_restore_list: */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; lex->query_tables=all_tables; break; } @@ -3089,7 +3115,7 @@ end_with_restore_list: lex->value_list, select_lex->where, select_lex->order_list.elements, - (ORDER *) select_lex->order_list.first, + 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 */ @@ -3249,7 +3275,7 @@ end_with_restore_list: { /* Skip first table, which is the table we are inserting in */ TABLE_LIST *second_table= first_table->next_local; - select_lex->table_list.first= (uchar*) second_table; + select_lex->table_list.first= second_table; select_lex->context.table_list= select_lex->context.first_name_resolution_table= second_table; res= mysql_insert_select_prepare(thd); @@ -3280,7 +3306,7 @@ end_with_restore_list: delete sel_result; } /* revert changes for SP */ - select_lex->table_list.first= (uchar*) first_table; + select_lex->table_list.first= first_table; } /* @@ -3342,8 +3368,7 @@ end_with_restore_list: case SQLCOM_DELETE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - TABLE_LIST *aux_tables= - (TABLE_LIST *)thd->lex->auxiliary_table_list.first; + TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; multi_delete *del_result; if (!thd->locked_tables && @@ -4716,7 +4741,7 @@ create_sp_error: my_error(ER_XAER_NOTA, MYF(0)); break; } - thd->transaction.xid_state.xa_state=XA_ACTIVE; + thd->transaction.xid_state.xa_state= XA_ACTIVE; my_ok(thd); break; } @@ -4736,16 +4761,16 @@ create_sp_error: my_error(ER_XAER_OUTSIDE, MYF(0)); break; } - if (xid_cache_search(thd->lex->xid)) - { - my_error(ER_XAER_DUPID, MYF(0)); - break; - } DBUG_ASSERT(thd->transaction.xid_state.xid.is_null()); - thd->transaction.xid_state.xa_state=XA_ACTIVE; + thd->transaction.xid_state.xa_state= XA_ACTIVE; thd->transaction.xid_state.rm_error= 0; thd->transaction.xid_state.xid.set(thd->lex->xid); - xid_cache_insert(&thd->transaction.xid_state); + if (xid_cache_insert(&thd->transaction.xid_state)) + { + thd->transaction.xid_state.xa_state= XA_NOTR; + thd->transaction.xid_state.xid.null(); + break; + } thd->transaction.all.modified_non_trans_table= FALSE; thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; @@ -4799,6 +4824,16 @@ create_sp_error: case SQLCOM_XA_COMMIT: if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) { + /* + xid_state.in_thd is always true beside of xa recovery + procedure. Note, that there is no race condition here + between xid_cache_search and xid_cache_delete, since we're always + deleting our own XID (thd->lex->xid == thd->transaction.xid_state.xid). + The only case when thd->lex->xid != thd->transaction.xid_state.xid + and xid_state->in_thd == 0 is in ha_recover() functionality, + which is called before starting client connections, and thus is + always single-threaded. + */ XID_STATE *xs=xid_cache_search(thd->lex->xid); if (!xs || xs->in_thd) my_error(ER_XAER_NOTA, MYF(0)); @@ -5364,7 +5399,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) case SCH_STATISTICS: { TABLE_LIST *dst_table; - dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first; + dst_table= table->schema_select_lex->table_list.first; DBUG_ASSERT(dst_table); @@ -5947,13 +5982,13 @@ void mysql_init_multi_delete(LEX *lex) Parse a query. @param thd Current thread - @param inBuf Begining of the query text + @param rawbuf Begining of the query text @param length Length of the query text @param[out] found_semicolon For multi queries, position of the character of the next query in the query text. */ -void mysql_parse(THD *thd, const char *inBuf, uint length, +void mysql_parse(THD *thd, char *rawbuf, uint length, const char ** found_semicolon) { DBUG_ENTER("mysql_parse"); @@ -5978,17 +6013,22 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, lex_start(thd); mysql_reset_thd_for_next_command(thd, opt_userstat_running); - if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0) + if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) { LEX *lex= thd->lex; sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); - Parser_state parser_state(thd, inBuf, length); - - bool err= parse_sql(thd, & parser_state, NULL); - *found_semicolon= parser_state.m_lip.found_semicolon; + Parser_state parser_state; + bool err; + if (!(err= parser_state.init(thd, rawbuf, length))) + { + err= parse_sql(thd, & parser_state, NULL); + *found_semicolon= parser_state.m_lip.found_semicolon; + } + else + *found_semicolon= NULL; if (!err) { @@ -6069,20 +6109,23 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, 1 can be ignored */ -bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) +bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) { LEX *lex= thd->lex; bool error= 0; DBUG_ENTER("mysql_test_parse_for_slave"); - Parser_state parser_state(thd, inBuf, length); - lex_start(thd); - mysql_reset_thd_for_next_command(thd, 0); + Parser_state parser_state; + if (!(error= parser_state.init(thd, rawbuf, length))) + { + lex_start(thd); + mysql_reset_thd_for_next_command(thd, opt_userstat_running); - if (!parse_sql(thd, & parser_state, NULL) && - all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) - error= 1; /* Ignore question */ - thd->end_statement(); + if (!parse_sql(thd, & parser_state, NULL) && + all_tables_not_ok(thd, lex->select_lex.table_list.first)) + error= 1; /* Ignore question */ + thd->end_statement(); + } thd->cleanup_after_query(); DBUG_RETURN(error); } @@ -6221,7 +6264,7 @@ add_proc_to_list(THD* thd, Item *item) *item_ptr= item; order->item=item_ptr; order->free_me=0; - thd->lex->proc_list.link_in_list((uchar*) order,(uchar**) &order->next); + thd->lex->proc_list.link_in_list(order, &order->next); return 0; } @@ -6230,7 +6273,7 @@ add_proc_to_list(THD* thd, Item *item) save order by and tables in own lists. */ -bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) +bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc) { ORDER *order; DBUG_ENTER("add_to_list"); @@ -6242,7 +6285,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) order->free_me=0; order->used=0; order->counter_used= 0; - list.link_in_list((uchar*) order,(uchar**) &order->next); + list.link_in_list(order, &order->next); DBUG_RETURN(0); } @@ -6356,7 +6399,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, /* check that used name is unique */ if (lock_type != TL_IGNORE) { - TABLE_LIST *first_table= (TABLE_LIST*) table_list.first; + TABLE_LIST *first_table= table_list.first; if (lex->sql_command == SQLCOM_CREATE_VIEW) first_table= first_table ? first_table->next_local : NULL; for (TABLE_LIST *tables= first_table ; @@ -6398,7 +6441,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, previous table reference to 'ptr'. Here we also add one element to the list 'table_list'. */ - table_list.link_in_list((uchar*) ptr, (uchar**) &ptr->next_local); + table_list.link_in_list(ptr, &ptr->next_local); ptr->next_name_resolution_table= NULL; /* Link table in global list (all used tables) */ lex->add_to_query_tables(ptr); @@ -6631,7 +6674,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) DBUG_ENTER("set_lock_for_tables"); DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type, for_update)); - for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first; + for (TABLE_LIST *tables= table_list.first; tables; tables= tables->next_local) { @@ -7358,8 +7401,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) { SELECT_LEX *select_lex= &thd->lex->select_lex; - TABLE_LIST *aux_tables= - (TABLE_LIST *)thd->lex->auxiliary_table_list.first; + TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last; DBUG_ENTER("multi_delete_precheck"); @@ -7405,13 +7447,13 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) { - TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first; + TABLE_LIST *tables= lex->select_lex.table_list.first; TABLE_LIST *target_tbl; DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables"); lex->table_count= 0; - for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first; + for (target_tbl= lex->auxiliary_table_list.first; target_tbl; target_tbl= target_tbl->next_local) { lex->table_count++; @@ -7581,8 +7623,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, &create_table->grant.privilege, 0, 0, test(create_table->schema_table)) || check_merge_table_access(thd, create_table->db, - (TABLE_LIST *) - lex->create_info.merge_list.first)) + lex->create_info.merge_list.first)) goto err; if (want_priv != CREATE_TMP_ACL && check_grant(thd, want_priv, create_table, 0, 1, 0)) @@ -7703,7 +7744,7 @@ LEX_USER *create_default_definer(THD *thd) if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) return 0; - get_default_definer(thd, definer); + thd->get_definer(definer); return definer; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 65a58ba2f5a..551f19694ef 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1905,7 +1905,7 @@ static int add_int(File fptr, longlong number) static int add_uint(File fptr, ulonglong number) { char buff[32]; - longlong2str(number, buff, 10); + longlong2str(number, buff, 10, 1); return add_string(fptr, buff); } @@ -3877,7 +3877,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, */ bool mysql_unpack_partition(THD *thd, - const char *part_buf, uint part_info_len, + char *part_buf, uint part_info_len, const char *part_state, uint part_state_len, TABLE* table, bool is_create_table_ind, handlerton *default_db_type, @@ -3893,7 +3893,9 @@ bool mysql_unpack_partition(THD *thd, thd->lex= &lex; thd->variables.character_set_client= system_charset_info; - Parser_state parser_state(thd, part_buf, part_info_len); + Parser_state parser_state; + if (parser_state.init(thd, part_buf, part_info_len)) + goto end; lex_start(thd); *work_part_info_used= false; @@ -5956,32 +5958,6 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) } } -/* - Unlock and close table before renaming and dropping partitions - SYNOPSIS - alter_close_tables() - lpt Struct carrying parameters - RETURN VALUES - 0 -*/ - -static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - THD *thd= lpt->thd; - const char *db= lpt->db; - const char *table_name= lpt->table_name; - DBUG_ENTER("alter_close_tables"); - /* - We need to also unlock tables and close all handlers. - We set lock to zero to ensure we don't do this twice - and we set db_stat to zero to ensure we don't close twice. - */ - pthread_mutex_lock(&LOCK_open); - close_data_files_and_morph_locks(thd, db, table_name); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(0); -} - /* Handle errors for ALTER TABLE for partitioning @@ -6279,9 +6255,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || (not_completed= FALSE) || - abort_and_upgrade_lock(lpt) || /* Always returns 0 */ - ERROR_INJECT_CRASH("crash_drop_partition_4") || - alter_close_tables(lpt) || + abort_and_upgrade_lock_and_close_table(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -6346,9 +6320,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - abort_and_upgrade_lock(lpt) || /* Always returns 0 */ - ERROR_INJECT_CRASH("crash_add_partition_4") || - alter_close_tables(lpt) || + abort_and_upgrade_lock_and_close_table(lpt) || ERROR_INJECT_CRASH("crash_add_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -6436,9 +6408,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || (not_completed= FALSE) || - abort_and_upgrade_lock(lpt) || /* Always returns 0 */ - ERROR_INJECT_CRASH("crash_change_partition_5") || - alter_close_tables(lpt) || + abort_and_upgrade_lock_and_close_table(lpt) || ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, diff --git a/sql/sql_partition.h b/sql/sql_partition.h index b9efbf25a00..02a5ead1117 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -78,7 +78,7 @@ void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info, const key_range *key_spec, part_id_range *part_spec); -bool mysql_unpack_partition(THD *thd, const char *part_buf, +bool mysql_unpack_partition(THD *thd, char *part_buf, uint part_info_len, const char *part_state, uint part_state_len, TABLE *table, bool is_create_table_ind, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 658688d7159..dd908e1b60e 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -37,6 +37,18 @@ static TYPELIB global_plugin_typelib= char *opt_plugin_load= NULL; char *opt_plugin_dir_ptr; char opt_plugin_dir[FN_REFLEN]; +uint plugin_maturity; + +/* + not really needed now, this map will become essential when we add more + maturity levels. We cannot change existing maturity constants, + so the next value - even if it will be MariaDB_PLUGIN_MATURITY_VERY_BUGGY - + will inevitably be larger than MariaDB_PLUGIN_MATURITY_STABLE. + To be able to compare them we use this mapping array +*/ +uint plugin_maturity_map[]= +{ 0, 1, 2, 3, 4, 5, 6 }; + /* When you ad a new plugin type, add both a string and make sure that the init and deinit array are correctly updated. @@ -460,32 +472,32 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl, i++) { - cur->type= old->type; - cur->info= old->info; - cur->name= old->name; - cur->author= old->author; - cur->descr= old->descr; - cur->license= old->license; - cur->init= old->init; - cur->deinit= old->deinit; - cur->version= old->version; - cur->status_vars= old->status_vars; - cur->system_vars= old->system_vars; + cur[i].type= old->type; + cur[i].info= old->info; + cur[i].name= old->name; + cur[i].author= old->author; + cur[i].descr= old->descr; + cur[i].license= old->license; + cur[i].init= old->init; + cur[i].deinit= old->deinit; + cur[i].version= old->version; + cur[i].status_vars= old->status_vars; + cur[i].system_vars= old->system_vars; /* Something like this should be added to process new mysql plugin versions: if (plugin_dl->mysqlversion > 0x0101) { - cur->newfield= CONSTANT_MEANS_UNKNOWN; + cur[i].newfield= CONSTANT_MEANS_UNKNOWN; } else { - cur->newfield= old->newfield; + cur[i].newfield= old->newfield; } */ /* Maria only fields */ - cur->version_info= "Unknown"; - cur->maturity= MariaDB_PLUGIN_MATURITY_UNKNOWN; + cur[i].version_info= "Unknown"; + cur[i].maturity= MariaDB_PLUGIN_MATURITY_UNKNOWN; } plugin_dl->allocated= true; plugin_dl->plugins= (struct st_maria_plugin *)cur; @@ -953,6 +965,17 @@ static bool plugin_add(MEM_ROOT *tmp_root, report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); goto err; } + if (plugin_maturity_map[plugin->maturity] < plugin_maturity) + { + char buf[256]; + strxnmov(buf, sizeof(buf) - 1, "Loading of ", + plugin_maturity_names[plugin->maturity], + " plugins is prohibited by --plugin-maturity=", + plugin_maturity_names[plugin_maturity], + NullS); + report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); + goto err; + } tmp.plugin= plugin; tmp.name.str= (char *)plugin->name; tmp.name.length= name_len; @@ -1598,7 +1621,12 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) goto end; } table= tables.table; - init_read_record(&read_record_info, new_thd, table, NULL, 1, 0, FALSE); + if (init_read_record(&read_record_info, new_thd, table, NULL, 1, 0, FALSE)) + { + sql_print_error("Could not initialize init_read_record; Plugins not " + "loaded"); + goto end; + } table->use_all_columns(); /* there're no other threads running yet, so we don't need a mutex. @@ -2112,10 +2140,6 @@ typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulonglong_t, ulonglong); -#define SET_PLUGIN_VAR_RESOLVE(opt)\ - *(mysql_sys_var_ptr_p*)&((opt)->resolve)= mysql_sys_var_ptr -typedef uchar *(*mysql_sys_var_ptr_p)(void* a_thd, int offset); - /**************************************************************************** default variable data check and update functions @@ -2644,11 +2668,49 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) return (uchar*)thd->variables.dynamic_variables_ptr + offset; } -static uchar *mysql_sys_var_ptr(void* a_thd, int offset) + +/** + For correctness and simplicity's sake, a pointer to a function + must be compatible with pointed-to type, that is, the return and + parameters types must be the same. Thus, a callback function is + defined for each scalar type. The functions are assigned in + construct_options to their respective types. +*/ + +static char *mysql_sys_var_char(THD* thd, int offset) +{ + return (char *) intern_sys_var_ptr(thd, offset, true); +} + +static int *mysql_sys_var_int(THD* thd, int offset) +{ + return (int *) intern_sys_var_ptr(thd, offset, true); +} + +static long *mysql_sys_var_long(THD* thd, int offset) +{ + return (long *) intern_sys_var_ptr(thd, offset, true); +} + +static unsigned long *mysql_sys_var_ulong(THD* thd, int offset) { - return intern_sys_var_ptr((THD *)a_thd, offset, true); + return (unsigned long *) intern_sys_var_ptr(thd, offset, true); } +static long long *mysql_sys_var_longlong(THD* thd, int offset) +{ + return (long long *) intern_sys_var_ptr(thd, offset, true); +} + +static unsigned long long *mysql_sys_var_ulonglong(THD* thd, int offset) +{ + return (unsigned long long *) intern_sys_var_ptr(thd, offset, true); +} + +static char **mysql_sys_var_str(THD* thd, int offset) +{ + return (char **) intern_sys_var_ptr(thd, offset, true); +} void plugin_thdvar_init(THD *thd) { @@ -3219,25 +3281,25 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, continue; switch (opt->flags & PLUGIN_VAR_TYPEMASK) { case PLUGIN_VAR_BOOL: - SET_PLUGIN_VAR_RESOLVE((thdvar_bool_t *) opt); + ((thdvar_bool_t *) opt)->resolve= mysql_sys_var_char; break; case PLUGIN_VAR_INT: - SET_PLUGIN_VAR_RESOLVE((thdvar_int_t *) opt); + ((thdvar_int_t *) opt)->resolve= mysql_sys_var_int; break; case PLUGIN_VAR_LONG: - SET_PLUGIN_VAR_RESOLVE((thdvar_long_t *) opt); + ((thdvar_long_t *) opt)->resolve= mysql_sys_var_long; break; case PLUGIN_VAR_LONGLONG: - SET_PLUGIN_VAR_RESOLVE((thdvar_longlong_t *) opt); + ((thdvar_longlong_t *) opt)->resolve= mysql_sys_var_longlong; break; case PLUGIN_VAR_STR: - SET_PLUGIN_VAR_RESOLVE((thdvar_str_t *) opt); + ((thdvar_str_t *) opt)->resolve= mysql_sys_var_str; break; case PLUGIN_VAR_ENUM: - SET_PLUGIN_VAR_RESOLVE((thdvar_enum_t *) opt); + ((thdvar_enum_t *) opt)->resolve= mysql_sys_var_ulong; break; case PLUGIN_VAR_SET: - SET_PLUGIN_VAR_RESOLVE((thdvar_set_t *) opt); + ((thdvar_set_t *) opt)->resolve= mysql_sys_var_ulonglong; break; default: sql_print_error("Unknown variable type code 0x%x in plugin '%s'.", @@ -3589,8 +3651,7 @@ void my_print_help_inc_plugins(my_option *main_options, uint size) { p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **); - if (!p->plugin->system_vars || - !(opt= construct_help_options(&mem_root, p))) + if (!(opt= construct_help_options(&mem_root, p))) continue; /* Only options with a non-NULL comment are displayed in help text */ diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 5822b096fa0..149b7e0cbb1 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -107,6 +107,9 @@ extern char *opt_plugin_load; extern char *opt_plugin_dir_ptr; extern char opt_plugin_dir[FN_REFLEN]; extern const LEX_STRING plugin_type_names[]; +extern uint plugin_maturity; +extern TYPELIB plugin_maturity_values; +extern const char *plugin_maturity_names[]; extern int plugin_init(int *argc, char **argv, int init_flags); extern void plugin_shutdown(void); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 863e7a36aab..7185b8ffdda 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -263,8 +263,11 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) &stmt->lex->param_list, Protocol::SEND_EOF); } - /* Flag that a response has already been sent */ - thd->main_da.disable_status(); + + if (!error) + /* Flag that a response has already been sent */ + thd->main_da.disable_status(); + DBUG_RETURN(error); } #else @@ -702,6 +705,19 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, } #ifndef EMBEDDED_LIBRARY + +/** + Check whether this parameter data type is compatible with long data. + Used to detect whether a long data stream has been supplied to a + incompatible data type. +*/ +inline bool is_param_long_data_type(Item_param *param) +{ + return ((param->param_type >= MYSQL_TYPE_TINY_BLOB) && + (param->param_type <= MYSQL_TYPE_STRING)); +} + + /** Routines to assign parameters from data supplied by the client. @@ -771,6 +787,14 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array, DBUG_RETURN(1); } } + /* + A long data stream was supplied for this parameter marker. + This was done after prepare, prior to providing a placeholder + type (the types are supplied at execute). Check that the + supplied type of placeholder can accept a data stream. + */ + else if (! is_param_long_data_type(param)) + DBUG_RETURN(1); res= param->query_val_str(&str); if (param->convert_str_value(thd)) DBUG_RETURN(1); /* out of memory */ @@ -809,6 +833,14 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array, DBUG_RETURN(1); } } + /* + A long data stream was supplied for this parameter marker. + This was done after prepare, prior to providing a placeholder + type (the types are supplied at execute). Check that the + supplied type of placeholder can accept a data stream. + */ + else if (! is_param_long_data_type(param)) + DBUG_RETURN(1); if (param->convert_str_value(stmt->thd)) DBUG_RETURN(1); /* out of memory */ } @@ -1242,7 +1274,7 @@ static int mysql_test_update(Prepared_statement *stmt, if (mysql_prepare_update(thd, table_list, &select->where, select->order_list.elements, - (ORDER *) select->order_list.first)) + select->order_list.first)) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1751,11 +1783,10 @@ error: static int mysql_insert_select_prepare_tester(THD *thd) { SELECT_LEX *first_select= &thd->lex->select_lex; - TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)-> - next_local; + TABLE_LIST *second_table= first_select->table_list.first->next_local; /* Skip first table, which is the table we are inserting in */ - first_select->table_list.first= (uchar *) second_table; + first_select->table_list.first= second_table; thd->lex->select_lex.context.table_list= thd->lex->select_lex.context.first_name_resolution_table= second_table; @@ -1792,7 +1823,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, return 1; /* store it, because mysql_insert_select_prepare_tester change it */ - first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first; + first_local_table= lex->select_lex.table_list.first; DBUG_ASSERT(first_local_table != 0); res= @@ -1800,7 +1831,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, &mysql_insert_select_prepare_tester, OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ - lex->select_lex.table_list.first= (uchar*) first_local_table; + lex->select_lex.table_list.first= first_local_table; return res; } @@ -2158,7 +2189,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len) lex->prepared_stmt_code.length)) && entry->value) { - my_bool is_var_null; + bool is_var_null; var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC); /* NULL value of variable checked early as entry->value so here @@ -2344,10 +2375,10 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) DBUG_ASSERT(sl->join == 0); ORDER *order; /* Fix GROUP list */ - for (order= (ORDER *)sl->group_list.first; order; order= order->next) + for (order= sl->group_list.first; order; order= order->next) order->item= &order->item_ptr; /* Fix ORDER list */ - for (order= (ORDER *)sl->order_list.first; order; order= order->next) + for (order= sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; /* clear the no_error flag for INSERT/UPDATE IGNORE */ @@ -2384,7 +2415,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) (multi-delete). We do a full clean up, although at the moment all we need to clean in the tables of MULTI-DELETE list is 'table' member. */ - for (TABLE_LIST *tables= (TABLE_LIST*) lex->auxiliary_table_list.first; + for (TABLE_LIST *tables= lex->auxiliary_table_list.first; tables; tables= tables->next_global) { @@ -3039,13 +3070,21 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) old_stmt_arena= thd->stmt_arena; thd->stmt_arena= this; - Parser_state parser_state(thd, thd->query(), thd->query_length()); + Parser_state parser_state; + if (parser_state.init(thd, thd->query(), thd->query_length())) + { + thd->restore_backup_statement(this, &stmt_backup); + thd->restore_active_arena(this, &stmt_backup); + thd->stmt_arena= old_stmt_arena; + DBUG_RETURN(TRUE); + } + parser_state.m_lip.stmt_prepare_mode= TRUE; lex_start(thd); error= parse_sql(thd, & parser_state, NULL) || - thd->is_error() || - init_param_array(this); + thd->is_error() || + init_param_array(this); lex->set_trg_event_type_for_tables(); @@ -3301,7 +3340,7 @@ reexecute: bool Prepared_statement::reprepare() { - char saved_cur_db_name_buf[NAME_LEN+1]; + char saved_cur_db_name_buf[SAFE_NAME_LEN+1]; LEX_STRING saved_cur_db_name= { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; LEX_STRING stmt_db_name= { db, db_length }; @@ -3462,7 +3501,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) Query_arena *old_stmt_arena; bool error= TRUE; - char saved_cur_db_name_buf[NAME_LEN+1]; + char saved_cur_db_name_buf[SAFE_NAME_LEN+1]; LEX_STRING saved_cur_db_name= { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; bool cur_db_changed; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 7772b4d1ed2..95e48c531be 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -218,8 +218,7 @@ bool log_in_use(const char* log_name) if ((linfo = tmp->current_linfo)) { pthread_mutex_lock(&linfo->lock); - result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name, - log_name_len); + result = !memcmp(log_name, linfo->log_file_name, log_name_len); pthread_mutex_unlock(&linfo->lock); if (result) break; @@ -357,6 +356,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, #ifndef DBUG_OFF int left_events = max_binlog_dump_events; #endif + int old_max_allowed_packet= thd->variables.max_allowed_packet; DBUG_ENTER("mysql_binlog_send"); DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos)); @@ -762,6 +762,7 @@ end: pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); + thd->variables.max_allowed_packet= old_max_allowed_packet; DBUG_VOID_RETURN; err: @@ -779,6 +780,7 @@ err: pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) (void) my_close(file, MYF(MY_WME)); + thd->variables.max_allowed_packet= old_max_allowed_packet; my_message(my_errno, errmsg, MYF(0)); DBUG_VOID_RETURN; @@ -1279,7 +1281,7 @@ bool change_master(THD* thd, Master_info* mi) Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never a slave before). */ - if (flush_master_info(mi, 0)) + if (flush_master_info(mi, FALSE, FALSE)) { my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file"); unlock_slave_threads(mi); @@ -1419,6 +1421,7 @@ bool mysql_show_binlog_events(THD* thd) bool ret = TRUE; IO_CACHE log; File file = -1; + int old_max_allowed_packet= thd->variables.max_allowed_packet; DBUG_ENTER("mysql_show_binlog_events"); Log_event::init_show_field_list(&field_list); @@ -1557,6 +1560,7 @@ err: pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); + thd->variables.max_allowed_packet= old_max_allowed_packet; DBUG_RETURN(ret); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 09d8be97eb4..d2a72bcb86b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -38,6 +38,12 @@ #include <my_bit.h> #include <hash.h> #include <ft_global.h> +//#if defined(WITH_ARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) +//#include "../storage/maria/ha_maria.h" +//#define TMP_ENGINE_HTON maria_hton +//#else +//#define TMP_ENGINE_HTON myisam_hton +//#endif const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "MAYBE_REF","ALL","range","index","fulltext", @@ -262,15 +268,15 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, setup_tables_done_option changed for next rexecution */ res= mysql_select(thd, &select_lex->ref_pointer_array, - (TABLE_LIST*) select_lex->table_list.first, + select_lex->table_list.first, select_lex->with_wild, select_lex->item_list, select_lex->where, select_lex->order_list.elements + select_lex->group_list.elements, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, + select_lex->order_list.first, + select_lex->group_list.first, select_lex->having, - (ORDER*) lex->proc_list.first, + lex->proc_list.first, select_lex->options | thd->options | setup_tables_done_option, result, unit, select_lex); @@ -561,13 +567,21 @@ JOIN::prepare(Item ***rref_pointer_array, { Item *item= *ord->item; /* - Disregard sort order if there's only "{VAR}CHAR(0) NOT NULL" fields - there. Such fields don't contain any data to sort. + Disregard sort order if there's only + zero length NOT NULL fields (e.g. {VAR}CHAR(0) NOT NULL") or + zero length NOT NULL string functions there. + Such tuples don't contain any data to sort. */ if (!real_order && - (item->type() != Item::FIELD_ITEM || - ((Item_field *) item)->field->maybe_null() || - ((Item_field *) item)->field->sort_length())) + /* Not a zero length NOT NULL field */ + ((item->type() != Item::FIELD_ITEM || + ((Item_field *) item)->field->maybe_null() || + ((Item_field *) item)->field->sort_length()) && + /* AND not a zero length NOT NULL string function. */ + (item->type() != Item::FUNC_ITEM || + item->maybe_null || + item->result_type() != STRING_RESULT || + item->max_length))) real_order= TRUE; if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) @@ -1038,6 +1052,30 @@ JOIN::optimize() { conds=new Item_int((longlong) 0,1); // Always false } + + /* + It's necessary to check const part of HAVING cond as there is a + chance that some cond parts may become const items after + make_join_statistics() (for example when Item is a reference to + cost table field from outer join). + + This check is performed only for those conditions which do not use + aggregate functions. In such case temporary table may not be used + and const condition elements may be lost during further having + condition transformation in JOIN::exec. + */ + if (having && const_table_map && !having->with_sum_func) + { + having->update_used_tables(); + having= remove_eq_conds(thd, having, &having_value); + if (having_value == Item::COND_FALSE) + { + having= new Item_int((longlong) 0,1); + zero_result_cause= "Impossible HAVING noticed after reading const tables"; + DBUG_RETURN(0); + } + } + if (make_join_select(this, select, conds)) { zero_result_cause= @@ -1664,6 +1702,16 @@ JOIN::reinit() func->clear(); } + if (no_rows_in_result_called) + { + /* Reset effect of possible no_rows_in_result() */ + List_iterator_fast<Item> it(fields_list); + Item *item; + + no_rows_in_result_called= 0; + while ((item= it++)) + item->restore_to_before_no_rows_in_result(); + } DBUG_RETURN(0); } @@ -2755,15 +2803,29 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, as well as allow us to catch illegal cross references/ Warshall's algorithm is used to build the transitive closure. As we use bitmaps to represent the relation the complexity - of the algorithm is O((number of tables)^2). + of the algorithm is O((number of tables)^2). + + The classic form of the Warshall's algorithm would look like: + for (i= 0; i < table_count; i++) + { + for (j= 0; j < table_count; j++) + { + for (k= 0; k < table_count; k++) + { + if (bitmap_is_set(stat[j].dependent, i) && + bitmap_is_set(stat[i].dependent, k)) + bitmap_set_bit(stat[j].dependent, k); + } + } */ - for (i= 0, s= stat ; i < table_count ; i++, s++) + + for (s= stat ; s < stat_end ; s++) { - for (uint j= 0 ; j < table_count ; j++) + table= s->table; + for (JOIN_TAB *t= stat ; t < stat_end ; t++) { - table= stat[j].table; - if (s->dependent & table->map) - s->dependent |= table->reginfo.join_tab->dependent; + if (t->dependent & table->map) + t->dependent |= table->reginfo.join_tab->dependent; } if (outer_join & s->table->map) s->table->maybe_null= 1; @@ -2926,8 +2988,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, !table->fulltext_searched && (!embedding || (embedding->sj_on_expr && !embedding->embedding))) { - if ((table->key_info[key].flags & (HA_NOSAME | HA_END_SPACE_KEY)) - == HA_NOSAME) + if (table->key_info[key].flags & HA_NOSAME) { if (const_ref == eq_part) { // Found everything for ref. @@ -6154,8 +6215,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, DBUG_RETURN(0); if (j->type == JT_CONST) j->table->const_table= 1; - else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY | - HA_END_SPACE_KEY)) != HA_NOSAME) || + else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) != HA_NOSAME) || keyparts != keyinfo->key_parts || null_ref_key) { /* Must read with repeat */ @@ -6962,6 +7022,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (tmp_cond) { JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab; + Item **sel_cond_ref= tab < first_inner_tab ? + &first_inner_tab->on_precond : + &tab->select_cond; /* First add the guards for match variables of all embedding outer join operations. @@ -6984,15 +7047,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *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_cond : - new Item_cond_and(cond_tab->select_cond, - tmp_cond); + *sel_cond_ref= !(*sel_cond_ref) ? + tmp_cond : + new Item_cond_and(*sel_cond_ref, tmp_cond); DBUG_PRINT("info", ("Item_cond_and 0x%lx", - (ulong)cond_tab->select_cond)); - if (!cond_tab->select_cond) - DBUG_RETURN(1); - cond_tab->select_cond->update_used_tables(); - cond_tab->select_cond->quick_fix_field(); + (ulong)(*sel_cond_ref))); + if (!(*sel_cond_ref)) + DBUG_RETURN(1); + (*sel_cond_ref)->update_used_tables(); + (*sel_cond_ref)->quick_fix_field(); if (cond_tab->select) cond_tab->select->cond= cond_tab->select_cond; } @@ -8126,8 +8189,6 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab) static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables) { - if (specialflag & SPECIAL_SAFE_MODE) - return 0; // skip this optimize /* purecov: inspected */ tables&= ~PSEUDO_TABLE_BITS; for (JOIN_TAB **tab=join->map2table ; tables ; tab++, tables>>=1) { @@ -8248,7 +8309,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) + if (order->item[0]->with_subselect && + !(join->select_lex->options & SELECT_DESCRIBE)) order->item[0]->val_str(&order->item[0]->str_value); DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; // skip const item @@ -9791,6 +9853,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, NESTED_JOIN *nested_join; TABLE_LIST *prev_table= 0; List_iterator<TABLE_LIST> li(*join_list); + bool straight_join= test(join->select_options & SELECT_STRAIGHT_JOIN); DBUG_ENTER("simplify_joins"); /* @@ -9904,7 +9967,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, if (prev_table) { /* The order of tables is reverse: prev_table follows table */ - if (prev_table->straight) + if (prev_table->straight || straight_join) prev_table->dep_tables|= used_tables; if (prev_table->on_expr) { @@ -10177,28 +10240,31 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab) Do update counters for "pairs of brackets" that we've left (marked as X,Y,Z in the above picture) */ - for (;next_emb; next_emb= next_emb->embedding) + for (;next_emb && next_emb != join->emb_sjm_nest; next_emb= next_emb->embedding) { - next_emb->nested_join->counter++; - if (next_emb->nested_join->counter == 1) + if (!next_emb->sj_on_expr) { - /* - next_emb is the first table inside a nested join we've "entered". In - the picture above, we're looking at the 'X' bracket. Don't exit yet as - X bracket might have Y pair bracket. + next_emb->nested_join->counter++; + if (next_emb->nested_join->counter == 1) + { + /* + next_emb is the first table inside a nested join we've "entered". In + the picture above, we're looking at the 'X' bracket. Don't exit yet as + X bracket might have Y pair bracket. + */ + join->cur_embedding_map |= next_emb->nested_join->nj_map; + } + + if (next_emb->nested_join->n_tables != + next_emb->nested_join->counter) + break; + + /* + We're currently at Y or Z-bracket as depicted in the above picture. + Mark that we've left it and continue walking up the brackets hierarchy. */ - join->cur_embedding_map |= next_emb->nested_join->nj_map; + join->cur_embedding_map &= ~next_emb->nested_join->nj_map; } - - if (next_emb->nested_join->n_tables != - next_emb->nested_join->counter) - break; - - /* - We're currently at Y or Z-bracket as depicted in the above picture. - Mark that we've left it and continue walking up the brackets hierarchy. - */ - join->cur_embedding_map &= ~next_emb->nested_join->nj_map; } return FALSE; } @@ -10207,6 +10273,46 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab) /** Nested joins perspective: Remove the last table from the join order. + The algorithm is the reciprocal of check_interleaving_with_nj(), hence + parent join nest nodes are updated only when the last table in its child + node is removed. The ASCII graphic below will clarify. + + %A table nesting such as <tt> t1 x [ ( t2 x t3 ) x ( t4 x t5 ) ] </tt>is + represented by the below join nest tree. + + @verbatim + NJ1 + _/ / \ + _/ / NJ2 + _/ / / \ + / / / \ + t1 x [ (t2 x t3) x (t4 x t5) ] + @endverbatim + + At the point in time when check_interleaving_with_nj() adds the table t5 to + the query execution plan, QEP, it also directs the node named NJ2 to mark + the table as covered. NJ2 does so by incrementing its @c counter + member. Since all of NJ2's tables are now covered by the QEP, the algorithm + proceeds up the tree to NJ1, incrementing its counter as well. All join + nests are now completely covered by the QEP. + + restore_prev_nj_state() does the above in reverse. As seen above, the node + NJ1 contains the nodes t2, t3, and NJ2. Its counter being equal to 3 means + that the plan covers t2, t3, and NJ2, @e and that the sub-plan (t4 x t5) + completely covers NJ2. The removal of t5 from the partial plan will first + decrement NJ2's counter to 1. It will then detect that NJ2 went from being + completely to partially covered, and hence the algorithm must continue + upwards to NJ1 and decrement its counter to 2. %A subsequent removal of t4 + will however not influence NJ1 since it did not un-cover the last table in + NJ2. + + SYNOPSIS + restore_prev_nj_state() + last join table to remove, it is assumed to be the last in current + partial join order. + + DESCRIPTION + Remove the last table from the partial join order and update the nested joins counters and join->cur_embedding_map. It is ok to call this function for the first table in join order (for which @@ -10220,19 +10326,24 @@ static void restore_prev_nj_state(JOIN_TAB *last) { TABLE_LIST *last_emb= last->table->pos_in_table_list->embedding; JOIN *join= last->join; - while (last_emb) + for (;last_emb != NULL && last_emb != join->emb_sjm_nest; + last_emb= last_emb->embedding) { - if (!(--last_emb->nested_join->counter)) - join->cur_embedding_map&= ~last_emb->nested_join->nj_map; - else if (last_emb->nested_join->n_tables-1 == - last_emb->nested_join->counter) + if (!last_emb->sj_on_expr) { - join->cur_embedding_map|= last_emb->nested_join->nj_map; - break; + NESTED_JOIN *nest= last_emb->nested_join; + DBUG_ASSERT(nest->counter > 0); + + bool was_fully_covered= nest->is_fully_covered(); + + if (--nest->counter == 0) + join->cur_embedding_map&= ~nest->nj_map; + + if (!was_fully_covered) + break; + + join->cur_embedding_map|= nest->nj_map; } - else - break; - last_emb= last_emb->embedding; } } @@ -10332,7 +10443,10 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list, DBUG_ENTER("optimize_cond"); if (!conds) + { *cond_value= Item::COND_TRUE; + build_equal_items(join->thd, NULL, NULL, join_list, &join->cond_equal); + } else { /* @@ -10690,6 +10804,8 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, table->s->db_create_options|= HA_OPTION_PACK_RECORD; else if (org_field->type() == FIELD_TYPE_DOUBLE) ((Field_double *) new_field)->not_fixed= TRUE; + new_field->vcol_info= 0; + new_field->stored_in_db= TRUE; } return new_field; } @@ -11005,11 +11121,11 @@ void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps) uint field_count= table->s->fields; bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, FALSE); - bitmap_init(&table->tmp_set, + bitmap_init(&table->def_vcol_set, (my_bitmap_map*) (bitmaps+ bitmap_buffer_size(field_count)), field_count, FALSE); - bitmap_init(&table->vcol_set, - (my_bitmap_map*) (bitmaps+ 2+bitmap_buffer_size(field_count)), + bitmap_init(&table->tmp_set, + (my_bitmap_map*) (bitmaps+ 2*bitmap_buffer_size(field_count)), field_count, FALSE); /* write_set and all_set are copies of read_set */ @@ -11107,7 +11223,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, /* No need to change table name to lower case as we are only creating - MyISAM, Maria or HEAP tables here + MyISAM, Aria or HEAP tables here */ fn_format(path, tmp_table_name, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME); @@ -11474,7 +11590,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->null_flags= (uchar*) table->record[0]; share->null_fields= null_count+ hidden_null_count; - share->null_bytes= null_pack_length; + share->null_bytes= share->null_bytes_for_compare= null_pack_length; } null_count= (blob_count == 0) ? 1 : 0; hidden_field_count=param->hidden_field_count; @@ -11872,7 +11988,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list) { table->null_flags= (uchar*) table->record[0]; share->null_fields= null_count; - share->null_bytes= null_pack_length; + share->null_bytes= share->null_bytes_for_compare= null_pack_length; } table->in_use= thd; /* field->reset() may access table->in_use */ @@ -11926,7 +12042,7 @@ bool open_tmp_table(TABLE *table) } -#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) +#if defined(WITH_ARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES) /* Create internal (MyISAM or Maria) temporary table @@ -11958,7 +12074,6 @@ bool open_tmp_table(TABLE *table) TRUE - Error */ -/* Create internal Maria temporary table */ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, ENGINE_COLUMNDEF *start_recinfo, @@ -12039,7 +12154,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]); /* We are using a GROUP BY on something that contains NULL - In this case we have to tell Maria that two NULL should + In this case we have to tell Aria that two NULL should on INSERT be regarded at the same value */ if (!using_unique_constraint) @@ -12087,7 +12202,7 @@ bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, start_recinfo, recinfo, error, ignore_last_dupp_key_error, maria_hton, - "converting HEAP to Maria"); + "converting HEAP to Aria"); } #else @@ -12308,7 +12423,8 @@ create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, if (table->file->indexes_are_disabled()) new_table.file->ha_disable_indexes(HA_KEY_SWITCH_ALL); table->file->ha_index_or_rnd_end(); - table->file->ha_rnd_init(1); + if (table->file->ha_rnd_init_with_error(1)) + DBUG_RETURN(1); if (table->no_rows) { new_table.file->extra(HA_EXTRA_NO_ROWS); @@ -12985,7 +13101,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) DBUG_RETURN(nls); } int error; - enum_nested_loop_state rc; + enum_nested_loop_state rc= NESTED_LOOP_OK; READ_RECORD *info= &join_tab->read_record; if (join_tab->flush_weedout_table) @@ -13018,18 +13134,23 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) /* Set first_unmatched for the last inner table of this group */ join_tab->last_inner->first_unmatched= join_tab; + if (join_tab->on_precond && !join_tab->on_precond->val_int()) + rc= NESTED_LOOP_NO_MORE_ROWS; } join->thd->row_count= 0; if (join_tab->loosescan_match_tab) join_tab->loosescan_match_tab->found_match= FALSE; + if (rc != NESTED_LOOP_NO_MORE_ROWS) + { - error= (*join_tab->read_first_record)(join_tab); + error= (*join_tab->read_first_record)(join_tab); if (join_tab->keep_current_rowid) join_tab->table->file->position(join_tab->table->record[0]); - rc= evaluate_join_record(join, join_tab, error); + rc= evaluate_join_record(join, join_tab, error); + } } /* @@ -13119,7 +13240,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } - update_virtual_fields(join_tab->table); + update_virtual_fields(join->thd, join_tab->table); if (select_cond) { @@ -13137,6 +13258,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, condition is true => a match is found. */ bool found= 1; + bool use_not_exists_opt= 0; while (join_tab->first_unmatched && found) { /* @@ -13153,7 +13275,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) { if (tab->table->reginfo.not_exists_optimize) - DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); + use_not_exists_opt= 1; /* Check all predicates that has just been activated. */ /* Actually all predicates non-guarded by first_unmatched->found @@ -13186,6 +13308,8 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, join_tab->first_unmatched= first_unmatched; } + if (use_not_exists_opt) + DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); JOIN_TAB *return_tab= join->return_tab; join_tab->found_match= TRUE; @@ -13320,13 +13444,22 @@ evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab) #ifdef MERGE_JUNK //psergey3-merge: remove: + SQL_SELECT *select; + select= join_tab->select; + int err= 0; (err= join_tab->cache.select->skip_record(join->thd)) != 0 )) + { + reset_cache_write(&join_tab->cache); return NESTED_LOOP_ERROR; - rc= NESTED_LOOP_OK; + } + if (!select || (err= select->skip_record(join->thd)) != 0) if (err < 0) + { + reset_cache_write(&join_tab->cache); return NESTED_LOOP_ERROR; + } rc= NESTED_LOOP_OK; #endif @@ -13476,7 +13609,7 @@ join_read_system(JOIN_TAB *tab) empty_record(table); // Make empty record return -1; } - update_virtual_fields(table); + update_virtual_fields(tab->join->thd, table); store_record(table,record[1]); } else if (!table->status) // Only happens with left join @@ -13525,7 +13658,7 @@ join_read_const(JOIN_TAB *tab) return report_error(table, error); return -1; } - update_virtual_fields(table); + update_virtual_fields(tab->join->thd, table); store_record(table,record[1]); } else if (!(table->status & ~STATUS_NULL_ROW)) // Only happens with left join @@ -13783,7 +13916,7 @@ join_init_quick_read_record(JOIN_TAB *tab) int init_read_record_seq(JOIN_TAB *tab) { tab->read_record.read_record= rr_sequential; - if (tab->read_record.file->ha_rnd_init(1)) + if (tab->read_record.file->ha_rnd_init_with_error(1)) return 1; return (*tab->read_record.read_record)(&tab->read_record); } @@ -13809,8 +13942,9 @@ int join_init_read_record(JOIN_TAB *tab) { if (tab->select && tab->select->quick && tab->select->quick->reset()) return 1; - init_read_record(&tab->read_record, tab->join->thd, tab->table, - tab->select,1,1, FALSE); + if (init_read_record(&tab->read_record, tab->join->thd, tab->table, + tab->select,1,1, FALSE)) + return 1; return (*tab->read_record.read_record)(&tab->read_record); } @@ -14103,8 +14237,11 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { List_iterator_fast<Item> it(*join->fields); Item *item; + DBUG_PRINT("info", ("no matching rows")); + /* No matching rows for group function */ join->clear(); + join->no_rows_in_result_called= 1; while ((item= it++)) item->no_rows_in_result(); @@ -15297,6 +15434,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, uint nr; key_map keys; uint best_key_parts; + uint saved_best_key_parts= 0; int best_key_direction; ha_rows best_records; double read_time; @@ -15498,6 +15636,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, { best_key= nr; best_key_parts= keyinfo->key_parts; + saved_best_key_parts= used_key_parts; best_records= quick_records; is_best_covering= is_covering; best_key_direction= direction; @@ -15596,8 +15735,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ } } - used_key_parts= best_key_parts; order_direction= best_key_direction; + /* + saved_best_key_parts is actual number of used keyparts found by the + test_if_order_by_key function. It could differ from keyinfo->key_parts, + thus we have to restore it in case of desc order as it affects + QUICK_SELECT_DESC behaviour. + */ + used_key_parts= (order_direction == -1) ? + saved_best_key_parts : best_key_parts; } else goto use_filesort; @@ -15952,7 +16098,9 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, org_record=(char*) (record=table->record[0])+offset; new_record=(char*) table->record[1]+offset; - file->ha_rnd_init(1); + if (file->ha_rnd_init_with_error(1)) + DBUG_RETURN(1); + error= file->ha_rnd_next(record); for (;;) { @@ -16081,7 +16229,9 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, DBUG_RETURN(1); } - file->ha_rnd_init(1); + if ((error= file->ha_rnd_init(1))) + goto err; + key_pos=key_buffer; for (;;) { @@ -18103,7 +18253,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, the UNION to provide precise EXPLAIN information will hardly be appreciated :) */ - char table_name_buffer[NAME_LEN]; + char table_name_buffer[SAFE_NAME_LEN]; item_list.empty(); /* id */ item_list.push_back(new Item_null); @@ -18185,7 +18335,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, char keylen_str_buf[64]; my_bool key_read; String extra(buff, sizeof(buff),cs); - char table_name_buffer[NAME_LEN]; + char table_name_buffer[SAFE_NAME_LEN]; String tmp1(buff1,sizeof(buff1),cs); String tmp2(buff2,sizeof(buff2),cs); String tmp3(buff3,sizeof(buff3),cs); @@ -18247,7 +18397,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string("unique_key", strlen("unique_key"), cs)); /* key_len */ uint klen= tab->emb_sj_nest->sj_mat_info->table->key_info[0].key_length; - uint buflen= longlong2str(klen, keylen_str_buf, 10) - keylen_str_buf; + uint buflen= longlong10_to_str(klen, keylen_str_buf, 10) - keylen_str_buf; item_list.push_back(new Item_string(keylen_str_buf, buflen, cs)); /* ref */ item_list.push_back(new Item_string("func", strlen("func"), cs)); @@ -18367,8 +18517,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string(key_info->name, strlen(key_info->name), system_charset_info)); - length= longlong2str(tab->ref.key_length, keylen_str_buf, 10) - - keylen_str_buf; + length= (longlong10_to_str(tab->ref.key_length, keylen_str_buf, 10) - + keylen_str_buf); item_list.push_back(new Item_string(keylen_str_buf, length, system_charset_info)); for (store_key **ref=tab->ref.key_copy ; *ref ; ref++) @@ -18386,8 +18536,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, register uint length; item_list.push_back(new Item_string(key_info->name, strlen(key_info->name),cs)); - length= longlong2str(key_info->key_length, keylen_str_buf, 10) - - keylen_str_buf; + length= (longlong10_to_str(key_info->key_length, keylen_str_buf, 10) - + keylen_str_buf); item_list.push_back(new Item_string(keylen_str_buf, length, system_charset_info)); @@ -18765,15 +18915,15 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) thd->lex->current_select= first; unit->set_limit(unit->global_parameters); res= mysql_select(thd, &first->ref_pointer_array, - (TABLE_LIST*) first->table_list.first, + first->table_list.first, first->with_wild, first->item_list, first->where, first->order_list.elements + first->group_list.elements, - (ORDER*) first->order_list.first, - (ORDER*) first->group_list.first, + first->order_list.first, + first->group_list.first, first->having, - (ORDER*) thd->lex->proc_list.first, + thd->lex->proc_list.first, first->options | thd->options | SELECT_DESCRIBE, result, unit, first); } @@ -19113,7 +19263,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) if (group_list.elements) { str->append(STRING_WITH_LEN(" group by ")); - print_order(str, (ORDER *) group_list.first, query_type); + print_order(str, group_list.first, query_type); switch (olap) { case CUBE_TYPE: @@ -19144,7 +19294,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) if (order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); - print_order(str, (ORDER *) order_list.first, query_type); + print_order(str, order_list.first, query_type); } // limit diff --git a/sql/sql_select.h b/sql/sql_select.h index affa0fd3ed4..76c7715e68f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -160,7 +160,9 @@ typedef struct st_join_table { TABLE *table; KEYUSE *keyuse; /**< pointer to first used key */ SQL_SELECT *select; - COND *select_cond; + COND *select_cond; + COND *on_precond; /**< part of on condition to check before + accessing the first inner table */ QUICK_SELECT_I *quick; /* The value of select_cond before we've attempted to do Index Condition @@ -1497,24 +1499,31 @@ public: the number of rows in it may vary from one subquery execution to another. */ bool no_const_tables; + /* + This flag is set if we call no_rows_in_result() as par of end_group(). + This is used as a simple speed optimization to avoiding calling + restore_no_rows_in_result() in ::reinit() + */ + bool no_rows_in_result_called; /** Copy of this JOIN to be used with temporary tables. - tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery - that gets re-executed several times) and we know will use temporary tables - for materialization. The materialization to a temporary table overwrites the - JOIN structure to point to the temporary table after the materialization is - done. This is where tmp_join is used : it's a copy of the JOIN before the - materialization and is used in restoring before re-execution by overwriting - the current JOIN structure with the saved copy. - Because of this we should pay extra care of not freeing up helper structures - that are referenced by the original contents of the JOIN. We can check for - this by making sure the "current" join is not the temporary copy, e.g. - !tmp_join || tmp_join != join + tmp_join is used when the JOIN needs to be "reusable" (e.g. in a + subquery that gets re-executed several times) and we know will use + temporary tables for materialization. The materialization to a + temporary table overwrites the JOIN structure to point to the + temporary table after the materialization is done. This is where + tmp_join is used : it's a copy of the JOIN before the + materialization and is used in restoring before re-execution by + overwriting the current JOIN structure with the saved copy. + Because of this we should pay extra care of not freeing up helper + structures that are referenced by the original contents of the + JOIN. We can check for this by making sure the "current" join is + not the temporary copy, e.g. !tmp_join || tmp_join != join - We should free these sub-structures at JOIN::destroy() if the "current" join - has a copy is not that copy. + We should free these sub-structures at JOIN::destroy() if the + "current" join has a copy is not that copy. */ JOIN *tmp_join; ROLLUP rollup; ///< Used with rollup @@ -1651,6 +1660,7 @@ public: optimized= 0; cond_equal= 0; group_optimized_away= 0; + no_rows_in_result_called= 0; all_fields= fields_arg; if (&fields_list != &fields_arg) /* Avoid valgrind-warning */ diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index b88320ed2bf..ba4dbaacbb9 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -182,8 +182,9 @@ static bool servers_load(THD *thd, TABLE_LIST *tables) free_root(&mem, MYF(0)); init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0); - init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0, - FALSE); + if (init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0, + FALSE)) + DBUG_RETURN(1); while (!(read_record_info.read_record(&read_record_info))) { /* return_val is already TRUE, so no need to set */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 44e0f726b2d..29fdf4dc58d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -9,9 +9,9 @@ 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 */ + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Function with list databases, tables or fields */ @@ -31,6 +31,7 @@ #include "event_data_objects.h" #endif #include <my_dir.h> +#include "debug_sync.h" #define STR_OR_NIL(S) ((S) ? (S) : "<nil>") @@ -510,8 +511,6 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, wild_length= strlen(wild); } - - bzero((char*) &table_list,sizeof(table_list)); if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0)))) @@ -525,7 +524,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, for (i=0 ; i < (uint) dirp->number_off_files ; i++) { - char uname[NAME_LEN + 1]; /* Unencoded name */ + char uname[SAFE_NAME_LEN + 1]; /* Unencoded name */ file=dirp->dir_entry+i; if (dir) { /* Return databases */ @@ -553,9 +552,20 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, continue; file_name_len= filename_to_tablename(file->name, uname, sizeof(uname)); - if (wild && wild_compare(uname, wild, 0)) - continue; - if (!(file_name= + if (wild) + { + if (lower_case_table_names) + { + if (my_wildcmp(files_charset_info, + uname, uname + file_name_len, + wild, wild + wild_length, + wild_prefix, wild_one, wild_many)) + continue; + } + else if (wild_compare(uname, wild, 0)) + continue; + } + if (!(file_name= thd->make_lex_string(file_name, uname, file_name_len, TRUE))) { my_dirend(dirp); @@ -1170,7 +1180,7 @@ static bool get_field_default_value(THD *thd, TABLE *table, if (field_type == MYSQL_TYPE_BIT) { longlong dec= field->val_int(); - char *ptr= longlong2str(dec, tmp + 2, 2); + char *ptr= longlong2str(dec, tmp + 2, 2, 1); uint32 length= (uint32) (ptr - tmp); tmp[0]= 'b'; tmp[1]= '\''; @@ -1348,19 +1358,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, field->sql_type(type); packet->append(type.ptr(), type.length(), system_charset_info); - if (field->vcol_info) - { - packet->append(STRING_WITH_LEN(" AS (")); - packet->append(field->vcol_info->expr_str.str, - field->vcol_info->expr_str.length, - system_charset_info); - packet->append(STRING_WITH_LEN(")")); - if (field->stored_in_db) - packet->append(STRING_WITH_LEN(" PERSISTENT")); - else - packet->append(STRING_WITH_LEN(" VIRTUAL")); - } - if (field->has_charset() && !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))) { @@ -1380,6 +1377,19 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, } } + if (field->vcol_info) + { + packet->append(STRING_WITH_LEN(" AS (")); + packet->append(field->vcol_info->expr_str.str, + field->vcol_info->expr_str.length, + system_charset_info); + packet->append(STRING_WITH_LEN(")")); + if (field->stored_in_db) + packet->append(STRING_WITH_LEN(" PERSISTENT")); + else + packet->append(STRING_WITH_LEN(" VIRTUAL")); + } + if (flags & NOT_NULL_FLAG) packet->append(STRING_WITH_LEN(" NOT NULL")); else if (field->type() == MYSQL_TYPE_TIMESTAMP) @@ -2318,8 +2328,8 @@ static bool show_status_array(THD *thd, const char *wild, bool ucase_names, COND *cond) { - MY_ALIGNED_BYTE_ARRAY(buff_data, SHOW_VAR_FUNC_BUFF_SIZE, long); - char * const buff= (char *) &buff_data; + my_aligned_storage<SHOW_VAR_FUNC_BUFF_SIZE, MY_ALIGNOF(long)> buffer; + char * const buff= buffer.data; char *prefix_end; /* the variable name should not be longer than 64 characters */ char name_buffer[64]; @@ -3124,36 +3134,54 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables, { LEX *lex= thd->lex; const char *wild= lex->wild ? lex->wild->ptr() : NullS; + bool rc= 0; + bzero((char*) lookup_field_values, sizeof(LOOKUP_FIELD_VALUES)); switch (lex->sql_command) { case SQLCOM_SHOW_DATABASES: if (wild) { - lookup_field_values->db_value.str= (char*) wild; - lookup_field_values->db_value.length= strlen(wild); + thd->make_lex_string(&lookup_field_values->db_value, + wild, strlen(wild), 0); lookup_field_values->wild_db_value= 1; } - return 0; + break; case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TRIGGERS: case SQLCOM_SHOW_EVENTS: - lookup_field_values->db_value.str= lex->select_lex.db; - lookup_field_values->db_value.length=strlen(lex->select_lex.db); + thd->make_lex_string(&lookup_field_values->db_value, + lex->select_lex.db, strlen(lex->select_lex.db), 0); if (wild) { - lookup_field_values->table_value.str= (char*)wild; - lookup_field_values->table_value.length= strlen(wild); + thd->make_lex_string(&lookup_field_values->table_value, + wild, strlen(wild), 0); lookup_field_values->wild_table_value= 1; } - return 0; + break; default: /* The "default" is for queries over I_S. All previous cases handle SHOW commands. */ - return calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values); + rc= calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values); + break; + } + + if (lower_case_table_names && !rc) + { + /* + We can safely do in-place upgrades here since all of the above cases + are allocating a new memory buffer for these strings. + */ + if (lookup_field_values->db_value.str && lookup_field_values->db_value.str[0]) + my_casedn_str(system_charset_info, lookup_field_values->db_value.str); + if (lookup_field_values->table_value.str && + lookup_field_values->table_value.str[0]) + my_casedn_str(system_charset_info, lookup_field_values->table_value.str); } + + return rc; } @@ -3355,9 +3383,15 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, { if (with_i_schema) { - if (find_schema_table(thd, lookup_field_vals->table_value.str)) + LEX_STRING *name; + ST_SCHEMA_TABLE *schema_table= + find_schema_table(thd, lookup_field_vals->table_value.str); + if (schema_table && !schema_table->hidden) { - if (table_names->push_back(&lookup_field_vals->table_value)) + if (!(name= + thd->make_lex_string(NULL, schema_table->table_name, + strlen(schema_table->table_name), TRUE)) || + table_names->push_back(name)) return 1; } } @@ -3396,7 +3430,7 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, */ if (res == FIND_FILES_DIR) { - if (lex->sql_command != SQLCOM_SELECT) + if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) return 1; thd->clear_error(); return 2; @@ -3432,8 +3466,7 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, bool res; LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name; enum_sql_command save_sql_command= lex->sql_command; - TABLE_LIST *show_table_list= (TABLE_LIST*) tables->schema_select_lex-> - table_list.first; + TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first; TABLE *table= tables->table; int error= 1; DBUG_ENTER("fill_schema_show"); @@ -3757,6 +3790,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) error= 0; goto err; } + DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'", STR_OR_NIL(lookup_field_vals.db_value.str), STR_OR_NIL(lookup_field_vals.table_value.str))); @@ -3879,12 +3913,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) goto err; if (make_table_list(thd, &sel, db_name, table_name)) goto err; - TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; + TABLE_LIST *show_table_list= sel.table_list.first; lex->all_selects_list= &sel; lex->derived_tables= 0; lex->sql_command= SQLCOM_SHOW_FIELDS; show_table_list->i_s_requested_object= schema_table->i_s_requested_object; + DEBUG_SYNC(thd, "before_open_in_get_all_tables"); res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); lex->sql_command= save_sql_command; @@ -3981,9 +4016,9 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond) if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals)) DBUG_RETURN(0); - DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'", - lookup_field_vals.db_value.str, - lookup_field_vals.table_value.str)); + DBUG_PRINT("INDEX VALUES",("db_name: %s table_name: %s", + val_or_null(lookup_field_vals.db_value.str), + val_or_null(lookup_field_vals.table_value.str))); if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema)) DBUG_RETURN(1); @@ -4283,7 +4318,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, uint flags=field->flags; char tmp[MAX_FIELD_WIDTH]; String type(tmp,sizeof(tmp), system_charset_info); - char *end; int decimals, field_length; if (wild && wild[0] && @@ -4304,7 +4338,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, field->field_name) & COL_ACLS; if (!tables->schema_table && !col_access) continue; - end= tmp; + char *end= tmp; for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) { if (col_access & 1) @@ -4380,10 +4414,13 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, 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 MYSQL_TYPE_LONGLONG: + field_length= field->max_display_length() - + ((field->flags & UNSIGNED_FLAG) ? 0 : 1); + break; case MYSQL_TYPE_BIT: field_length= field->max_display_length(); decimals= -1; // return NULL @@ -4427,7 +4464,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, table->field[15]->store((const char*) pos, strlen((const char*) pos), cs); - end= tmp; if (field->unireg_check == Field::NEXT_NUMBER) table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs); if (show_table->timestamp_field == field && @@ -4623,24 +4659,37 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond) } +static inline void copy_field_as_string(Field *to_field, Field *from_field) +{ + char buff[MAX_FIELD_WIDTH]; + String tmp_str(buff, sizeof(buff), system_charset_info); + from_field->val_str(&tmp_str); + to_field->store(tmp_str.ptr(), tmp_str.length(), system_charset_info); +} + + bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, const char *wild, bool full_access, const char *sp_user) { - String tmp_string; - String sp_db, sp_name, definer; MYSQL_TIME time; LEX *lex= thd->lex; CHARSET_INFO *cs= system_charset_info; - get_field(thd->mem_root, proc_table->field[0], &sp_db); - get_field(thd->mem_root, proc_table->field[1], &sp_name); - get_field(thd->mem_root, proc_table->field[11], &definer); + char sp_db_buff[SAFE_NAME_LEN + 1], sp_name_buff[SAFE_NAME_LEN + 1], + definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2]; + String sp_db(sp_db_buff, sizeof(sp_db_buff), cs); + String sp_name(sp_name_buff, sizeof(sp_name_buff), cs); + String definer(definer_buff, sizeof(definer_buff), cs); + + proc_table->field[0]->val_str(&sp_db); + proc_table->field[1]->val_str(&sp_name); + proc_table->field[11]->val_str(&definer); + if (!full_access) - full_access= !strcmp(sp_user, definer.ptr()); - if (!full_access && check_some_routine_access(thd, sp_db.ptr(), - sp_name.ptr(), - proc_table->field[2]-> - val_int() == - TYPE_ENUM_PROCEDURE)) + full_access= !strcmp(sp_user, definer.c_ptr_safe()); + if (!full_access && + check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(), + proc_table->field[2]->val_int() == + TYPE_ENUM_PROCEDURE)) return 0; if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC && @@ -4650,55 +4699,42 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0) { restore_record(table, s->default_values); - if (!wild || !wild[0] || !wild_compare(sp_name.ptr(), wild, 0)) + if (!wild || !wild[0] || !wild_compare(sp_name.c_ptr_safe(), wild, 0)) { int enum_idx= (int) proc_table->field[5]->val_int(); table->field[3]->store(sp_name.ptr(), sp_name.length(), cs); - get_field(thd->mem_root, proc_table->field[3], &tmp_string); - table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[0], proc_table->field[3]); table->field[2]->store(sp_db.ptr(), sp_db.length(), cs); - get_field(thd->mem_root, proc_table->field[2], &tmp_string); - table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[4], proc_table->field[2]); if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) { - get_field(thd->mem_root, proc_table->field[9], &tmp_string); - table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[5], proc_table->field[9]); table->field[5]->set_notnull(); } if (full_access) { - get_field(thd->mem_root, proc_table->field[19], &tmp_string); - table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[7], proc_table->field[19]); table->field[7]->set_notnull(); } table->field[6]->store(STRING_WITH_LEN("SQL"), cs); table->field[10]->store(STRING_WITH_LEN("SQL"), cs); - get_field(thd->mem_root, proc_table->field[6], &tmp_string); - table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); - table->field[12]->store(sp_data_access_name[enum_idx].str, + copy_field_as_string(table->field[11], proc_table->field[6]); + table->field[12]->store(sp_data_access_name[enum_idx].str, sp_data_access_name[enum_idx].length , cs); - get_field(thd->mem_root, proc_table->field[7], &tmp_string); - table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[14], proc_table->field[7]); + bzero((char *)&time, sizeof(time)); ((Field_timestamp *) proc_table->field[12])->get_time(&time); table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); bzero((char *)&time, sizeof(time)); ((Field_timestamp *) proc_table->field[13])->get_time(&time); table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); - get_field(thd->mem_root, proc_table->field[14], &tmp_string); - table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs); - get_field(thd->mem_root, proc_table->field[15], &tmp_string); - table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[17], proc_table->field[14]); + copy_field_as_string(table->field[18], proc_table->field[15]); table->field[19]->store(definer.ptr(), definer.length(), cs); - - get_field(thd->mem_root, proc_table->field[16], &tmp_string); - table->field[20]->store(tmp_string.ptr(), tmp_string.length(), cs); - - get_field(thd->mem_root, proc_table->field[17], &tmp_string); - table->field[21]->store(tmp_string.ptr(), tmp_string.length(), cs); - - get_field(thd->mem_root, proc_table->field[18], &tmp_string); - table->field[22]->store(tmp_string.ptr(), tmp_string.length(), cs); + copy_field_as_string(table->field[20], proc_table->field[16]); + copy_field_as_string(table->field[21], proc_table->field[17]); + copy_field_as_string(table->field[22], proc_table->field[18]); return schema_table_store_record(thd, table); } @@ -5993,56 +6029,56 @@ struct schema_table_ref ST_FIELD_INFO user_stats_fields_info[]= { {"USER", USERNAME_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE}, - {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections",SKIP_OPEN_TABLE}, - {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections",SKIP_OPEN_TABLE}, - {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time",SKIP_OPEN_TABLE}, + {"TOTAL_CONNECTIONS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections",SKIP_OPEN_TABLE}, + {"CONCURRENT_CONNECTIONS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections",SKIP_OPEN_TABLE}, + {"CONNECTED_TIME", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time",SKIP_OPEN_TABLE}, {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Busy_time",SKIP_OPEN_TABLE}, {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Cpu_time",SKIP_OPEN_TABLE}, - {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received",SKIP_OPEN_TABLE}, - {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent",SKIP_OPEN_TABLE}, - {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written",SKIP_OPEN_TABLE}, - {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, - {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_sent",SKIP_OPEN_TABLE}, - {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_deleted",SKIP_OPEN_TABLE}, - {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_inserted",SKIP_OPEN_TABLE}, - {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated",SKIP_OPEN_TABLE}, - {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands",SKIP_OPEN_TABLE}, - {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands",SKIP_OPEN_TABLE}, - {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands",SKIP_OPEN_TABLE}, - {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions",SKIP_OPEN_TABLE}, - {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions",SKIP_OPEN_TABLE}, - {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections",SKIP_OPEN_TABLE}, - {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections",SKIP_OPEN_TABLE}, - {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied",SKIP_OPEN_TABLE}, - {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries",SKIP_OPEN_TABLE}, + {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_received",SKIP_OPEN_TABLE}, + {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_sent",SKIP_OPEN_TABLE}, + {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Binlog_bytes_written",SKIP_OPEN_TABLE}, + {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, + {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_sent",SKIP_OPEN_TABLE}, + {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_deleted",SKIP_OPEN_TABLE}, + {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_inserted",SKIP_OPEN_TABLE}, + {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated",SKIP_OPEN_TABLE}, + {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands",SKIP_OPEN_TABLE}, + {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands",SKIP_OPEN_TABLE}, + {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands",SKIP_OPEN_TABLE}, + {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions",SKIP_OPEN_TABLE}, + {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions",SKIP_OPEN_TABLE}, + {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Denied_connections",SKIP_OPEN_TABLE}, + {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Lost_connections",SKIP_OPEN_TABLE}, + {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Access_denied",SKIP_OPEN_TABLE}, + {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Empty_queries",SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} }; ST_FIELD_INFO client_stats_fields_info[]= { {"CLIENT", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Client",SKIP_OPEN_TABLE}, - {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections",SKIP_OPEN_TABLE}, - {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections",SKIP_OPEN_TABLE}, - {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time",SKIP_OPEN_TABLE}, + {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Total_connections",SKIP_OPEN_TABLE}, + {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Concurrent_connections",SKIP_OPEN_TABLE}, + {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Connected_time",SKIP_OPEN_TABLE}, {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Busy_time",SKIP_OPEN_TABLE}, {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Cpu_time",SKIP_OPEN_TABLE}, - {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received",SKIP_OPEN_TABLE}, - {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent",SKIP_OPEN_TABLE}, - {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written",SKIP_OPEN_TABLE}, - {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, - {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_sent",SKIP_OPEN_TABLE}, - {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_deleted",SKIP_OPEN_TABLE}, - {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_inserted",SKIP_OPEN_TABLE}, - {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated",SKIP_OPEN_TABLE}, - {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands",SKIP_OPEN_TABLE}, - {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands",SKIP_OPEN_TABLE}, - {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands",SKIP_OPEN_TABLE}, - {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions",SKIP_OPEN_TABLE}, - {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions",SKIP_OPEN_TABLE}, - {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections",SKIP_OPEN_TABLE}, - {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections",SKIP_OPEN_TABLE}, - {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied",SKIP_OPEN_TABLE}, - {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries",SKIP_OPEN_TABLE}, + {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_received",SKIP_OPEN_TABLE}, + {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_sent",SKIP_OPEN_TABLE}, + {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Binlog_bytes_written",SKIP_OPEN_TABLE}, + {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, + {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_sent",SKIP_OPEN_TABLE}, + {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_deleted",SKIP_OPEN_TABLE}, + {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_inserted",SKIP_OPEN_TABLE}, + {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated",SKIP_OPEN_TABLE}, + {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands",SKIP_OPEN_TABLE}, + {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands",SKIP_OPEN_TABLE}, + {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands",SKIP_OPEN_TABLE}, + {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions",SKIP_OPEN_TABLE}, + {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions",SKIP_OPEN_TABLE}, + {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Denied_connections",SKIP_OPEN_TABLE}, + {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Lost_connections",SKIP_OPEN_TABLE}, + {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Access_denied",SKIP_OPEN_TABLE}, + {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Empty_queries",SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} }; @@ -6051,9 +6087,9 @@ ST_FIELD_INFO table_stats_fields_info[]= { {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",SKIP_OPEN_TABLE}, - {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, - {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_changed",SKIP_OPEN_TABLE}, - {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_changed_x_#indexes",SKIP_OPEN_TABLE}, + {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, + {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed",SKIP_OPEN_TABLE}, + {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed_x_#indexes",SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} }; @@ -6062,7 +6098,7 @@ ST_FIELD_INFO index_stats_fields_info[]= {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",SKIP_OPEN_TABLE}, {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name",SKIP_OPEN_TABLE}, - {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, + {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0,0} }; @@ -6907,7 +6943,7 @@ ST_FIELD_INFO engines_fields_info[]= { {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE}, {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support", SKIP_OPEN_TABLE}, - {"COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE}, + {"COMMENT", 160, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE}, {"TRANSACTIONS", 3, MYSQL_TYPE_STRING, 0, 1, "Transactions", SKIP_OPEN_TABLE}, {"XA", 3, MYSQL_TYPE_STRING, 0, 1, "XA", SKIP_OPEN_TABLE}, {"SAVEPOINTS", 3 ,MYSQL_TYPE_STRING, 0, 1, "Savepoints", SKIP_OPEN_TABLE}, @@ -7132,8 +7168,8 @@ ST_FIELD_INFO table_names_fields_info[]= { {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_", - SKIP_OPEN_TABLE}, + {"TABLE_NAME", NAME_CHAR_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH, + MYSQL_TYPE_STRING, 0, 0, "Tables_in_", SKIP_OPEN_TABLE}, {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type", OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 624aab93e33..0ef18a237dd 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -48,6 +48,7 @@ static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *, bool, uint *, handler *, KEY **, uint *, int); static bool mysql_prepare_alter_table(THD *, TABLE *, HA_CREATE_INFO *, Alter_info *); +static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list); #ifndef DBUG_OFF @@ -386,6 +387,25 @@ uint filename_to_tablename(const char *from, char *to, uint to_length) /** + Check if given string begins with "#mysql50#" prefix + + @param name string to check cut + + @retval + FALSE no prefix found + @retval + TRUE prefix found +*/ + +bool check_mysql50_prefix(const char *name) +{ + return (name[0] == '#' && + !strncmp(name, MYSQL50_TABLE_NAME_PREFIX, + MYSQL50_TABLE_NAME_PREFIX_LENGTH)); +} + + +/** Check if given string begins with "#mysql50#" prefix, cut it if so. @param from string to check and cut @@ -400,9 +420,7 @@ uint filename_to_tablename(const char *from, char *to, uint to_length) uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length) { - if (from[0] == '#' && - !strncmp(from, MYSQL50_TABLE_NAME_PREFIX, - MYSQL50_TABLE_NAME_PREFIX_LENGTH)) + if (check_mysql50_prefix(from)) return (uint) (strmake(to, from + MYSQL50_TABLE_NAME_PREFIX_LENGTH, to_length - 1) - to); return 0; @@ -2232,10 +2250,10 @@ static int sort_keys(KEY *a, KEY *b) { if (!(b_flags & HA_NOSAME)) return -1; - if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) + if ((a_flags ^ b_flags) & HA_NULL_PART_KEY) { /* Sort NOT NULL keys before other keys */ - return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; + return (a_flags & HA_NULL_PART_KEY) ? 1 : -1; } if (a->name == primary_key_name) return -1; @@ -4202,7 +4220,7 @@ mysql_rename_table(handlerton *base, const char *old_db, char from[FN_REFLEN + 1], to[FN_REFLEN + 1], lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1]; char *from_base= from, *to_base= to; - char tmp_name[NAME_LEN+1]; + char tmp_name[SAFE_NAME_LEN+1]; handler *file; int error=0; DBUG_ENTER("mysql_rename_table"); @@ -4597,6 +4615,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Protocol *protocol= thd->protocol; LEX *lex= thd->lex; int result_code; + bool need_repair_or_alter= 0; DBUG_ENTER("mysql_admin_table"); if (end_active_trans(thd)) @@ -4617,7 +4636,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, for (table= tables; table; table= table->next_local) { - char table_name[NAME_LEN*2+2]; + char table_name[SAFE_NAME_LEN*2+2]; char* db = table->db; bool fatal_error=0; @@ -4633,7 +4652,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, table->next_global= 0; save_next_local= table->next_local; table->next_local= 0; - select->table_list.first= (uchar*)table; + select->table_list.first= table; /* Time zone tables and SP tables can be add to lex->query_tables list, so it have to be prepared. @@ -4825,32 +4844,38 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (operator_func == &handler::ha_repair && !(check_opt->sql_flags & TT_USEFRM)) { - if ((table->table->file->check_old_types() == HA_ADMIN_NEEDS_ALTER) || - (table->table->file->ha_check_for_upgrade(check_opt) == - HA_ADMIN_NEEDS_ALTER)) + handler *file= table->table->file; + int check_old_types= file->check_old_types(); + int check_for_upgrade= file->ha_check_for_upgrade(check_opt); + + if (check_old_types == HA_ADMIN_NEEDS_ALTER || + check_for_upgrade == HA_ADMIN_NEEDS_ALTER) { - DBUG_PRINT("admin", ("recreating table")); - ha_autocommit_or_rollback(thd, 1); - close_thread_tables(thd); - tmp_disable_binlog(thd); // binlogging is done by caller if wanted - result_code= mysql_recreate_table(thd, table); - reenable_binlog(thd); - /* - mysql_recreate_table() can push OK or ERROR. - Clear 'OK' status. If there is an error, keep it: - we will store the error message in a result set row - and then clear. - */ - if (thd->main_da.is_ok()) - thd->main_da.reset_diagnostics_area(); + /* We use extra_open_options to be able to open crashed tables */ + thd->open_options|= extra_open_options; + result_code= admin_recreate_table(thd, table); + thd->open_options= ~extra_open_options; goto send_result; } + if (check_old_types || check_for_upgrade) + { + /* If repair is not implemented for the engine, run ALTER TABLE */ + need_repair_or_alter= 1; + } } DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name)); result_code = (table->table->file->*operator_func)(thd, check_opt); DBUG_PRINT("admin", ("operator_func returned: %d", result_code)); + if (result_code == HA_ADMIN_NOT_IMPLEMENTED && need_repair_or_alter) + { + /* + repair was not implemented and we need to upgrade the table + to a new version so we recreate the table with ALTER TABLE + */ + result_code= admin_recreate_table(thd, table); + } send_result: lex->cleanup_after_one_table_open(); @@ -4950,23 +4975,13 @@ send_result_message: system_charset_info); if (protocol->write()) goto err; - ha_autocommit_or_rollback(thd, 0); - close_thread_tables(thd); DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze...")); TABLE_LIST *save_next_local= table->next_local, *save_next_global= table->next_global; table->next_local= table->next_global= 0; - tmp_disable_binlog(thd); // binlogging is done by caller if wanted - result_code= mysql_recreate_table(thd, table); - reenable_binlog(thd); - /* - mysql_recreate_table() can push OK or ERROR. - Clear 'OK' status. If there is an error, keep it: - we will store the error message in a result set row - and then clear. - */ - if (thd->main_da.is_ok()) - thd->main_da.reset_diagnostics_area(); + + result_code= admin_recreate_table(thd, table); + ha_autocommit_or_rollback(thd, 0); close_thread_tables(thd); if (!result_code) // recreation went ok @@ -5347,6 +5362,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, */ if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { + if (src_table->table->file->ht == partition_hton) + { + my_error(ER_PARTITION_NO_TEMPORARY, MYF(0)); + goto err; + } if (find_temporary_table(thd, db, table_name)) goto table_exists; dst_path_length= build_tmptable_filename(thd, dst_path, sizeof(dst_path)); @@ -5411,14 +5431,15 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, /* For partitioned tables we need to copy the .par file as well since it is used in open_table_def to even be able to create a new handler. - There is no way to find out here if the original table is a - partitioned table so we copy the file and ignore any errors. */ - fn_format(tmp_path, dst_path, reg_ext, ".par", MYF(MY_REPLACE_EXT)); - strmov(dst_path, tmp_path); - fn_format(tmp_path, src_path, reg_ext, ".par", MYF(MY_REPLACE_EXT)); - strmov(src_path, tmp_path); - my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)); + if (src_table->table->file->ht == partition_hton) + { + fn_format(tmp_path, dst_path, reg_ext, ".par", MYF(MY_REPLACE_EXT)); + strmov(dst_path, tmp_path); + fn_format(tmp_path, src_path, reg_ext, ".par", MYF(MY_REPLACE_EXT)); + strmov(src_path, tmp_path); + my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)); + } #endif DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000);); @@ -6604,6 +6625,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, uint *index_add_buffer= NULL; uint candidate_key_count= 0; bool no_pk; + ulong explicit_used_fields= 0; DBUG_ENTER("mysql_alter_table"); /* @@ -6874,6 +6896,7 @@ view_err: change the row format in update_create_info(). */ create_info->used_fields|= HA_CREATE_USED_ROW_FORMAT; + explicit_used_fields|= HA_CREATE_USED_ROW_FORMAT; } DBUG_PRINT("info", ("old type: %s new type: %s", @@ -6948,6 +6971,20 @@ view_err: if (!error && (new_name != table_name || new_db != db)) { thd_proc_info(thd, "rename"); + + /* + Workaround InnoDB ending the transaction when the table instance + is unlocked/closed (close_cached_table below), otherwise the trx + state will differ between the server and storage engine layers. + + We have to unlock LOCK_open here as otherwise we can get deadlock + in wait_if_global_readlock(). This is still safe as we have a + name lock on the table object. + */ + VOID(pthread_mutex_unlock(&LOCK_open)); + ha_autocommit_or_rollback(thd, 0); + VOID(pthread_mutex_lock(&LOCK_open)); + /* Then do a 'simple' rename of the table. First we need to close all instances of 'source' table. @@ -7034,6 +7071,9 @@ view_err: if (mysql_prepare_alter_table(thd, table, create_info, alter_info)) goto err; + /* Remove markers set for update_create_info */ + create_info->used_fields&= ~explicit_used_fields; + if (need_copy_table == ALTER_TABLE_METADATA_ONLY) need_copy_table= alter_info->change_level; @@ -7492,6 +7532,11 @@ view_err: mysql_unlock_tables(thd, thd->lock); thd->lock=0; } + /* + If LOCK TABLES list is not empty and contains this table, + unlock the table and remove the table from this list. + */ + mysql_lock_remove(thd, thd->locked_tables, table, FALSE); /* Remove link to old table and rename the new one */ close_temporary_table(thd, table, 1, 1); /* Should pass the 'new_name' as we store table name in the cache */ @@ -7876,8 +7921,9 @@ copy_data_between_tables(TABLE *from,TABLE *to, /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); - to->mark_virtual_columns_for_write(); - init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE); + to->mark_virtual_columns_for_write(TRUE); + if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE)) + goto err; errpos= 4; if (ignore) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); @@ -7891,7 +7937,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, error= 1; break; } - update_virtual_fields(from); + update_virtual_fields(thd, from); thd->row_count++; /* Return error if source table isn't empty. */ if (error_if_not_empty) @@ -7912,7 +7958,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, copy_ptr->do_copy(copy_ptr); } prev_insert_id= to->file->next_insert_id; - update_virtual_fields(to, TRUE); + update_virtual_fields(thd, to, TRUE); if (thd->is_error()) { error= 1; @@ -7958,7 +8004,7 @@ err: if (error > 0) to->file->extra(HA_EXTRA_PREPARE_FOR_DROP); - if (errpos >= 3 && to->file->ha_end_bulk_insert(error > 1) && error <= 0) + if (errpos >= 3 && to->file->ha_end_bulk_insert() && error <= 0) { to->file->print_error(my_errno,MYF(0)); error= 1; @@ -7990,6 +8036,30 @@ err: } +/* Prepare, run and cleanup for mysql_recreate_table() */ + +static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list) +{ + bool result_code; + DBUG_ENTER("admin_recreate_table"); + + ha_autocommit_or_rollback(thd, 1); + close_thread_tables(thd); + tmp_disable_binlog(thd); // binlogging is done by caller if wanted + result_code= mysql_recreate_table(thd, table_list); + reenable_binlog(thd); + /* + mysql_recreate_table() can push OK or ERROR. + Clear 'OK' status. If there is an error, keep it: + we will store the error message in a result set row + and then clear. + */ + if (thd->main_da.is_ok()) + thd->main_da.reset_diagnostics_area(); + DBUG_RETURN(result_code); +} + + /* Recreates tables by calling mysql_alter_table(). @@ -8046,7 +8116,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, /* Open one table after the other to keep lock time as short as possible. */ for (table= tables; table; table= table->next_local) { - char table_name[NAME_LEN*2+2]; + char table_name[SAFE_NAME_LEN*2+2]; TABLE *t; strxmov(table_name, table->db ,".", table->table_name, NullS); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index aafb25013f6..e8a382ca8f6 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -653,7 +653,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, */ old_field= new_field= table->field; - for (trg_field= (Item_trigger_field *)(lex->trg_table_fields.first); + for (trg_field= lex->trg_table_fields.first; trg_field; trg_field= trg_field->next_trg_field) { /* @@ -1297,9 +1297,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->variables.sql_mode= (ulong)*trg_sql_mode; - Parser_state parser_state(thd, - trg_create_str->str, - trg_create_str->length); + Parser_state parser_state; + if (parser_state.init(thd, trg_create_str->str, trg_create_str->length)) + goto err_with_lex_cleanup; Trigger_creation_ctx *creation_ctx= Trigger_creation_ctx::create(thd, @@ -1391,7 +1391,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, To remove this prefix we use check_n_cut_mysql50_prefix(). */ - char fname[NAME_LEN + 1]; + char fname[SAFE_NAME_LEN + 1]; DBUG_ASSERT((!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) || (check_n_cut_mysql50_prefix(db, fname, sizeof(fname)) && !my_strcasecmp(table_alias_charset, lex.query_tables->db, fname))) && @@ -1413,7 +1413,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, */ triggers->trigger_fields[lex.trg_chistics.event] [lex.trg_chistics.action_time]= - (Item_trigger_field *)(lex.trg_table_fields.first); + lex.trg_table_fields.first; /* Also let us bind these objects to Field objects in table being opened. @@ -1423,8 +1423,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, SELECT)... Anyway some things can be checked only during trigger execution. */ - for (Item_trigger_field *trg_field= - (Item_trigger_field *)(lex.trg_table_fields.first); + for (Item_trigger_field *trg_field= lex.trg_table_fields.first; trg_field; trg_field= trg_field->next_trg_field) { @@ -1918,7 +1917,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, */ if (my_strcasecmp(table_alias_charset, db, new_db)) { - char dbname[NAME_LEN + 1]; + char dbname[SAFE_NAME_LEN + 1]; if (check_n_cut_mysql50_prefix(db, dbname, sizeof(dbname)) && !my_strcasecmp(table_alias_charset, dbname, new_db)) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index b18f0c28bdf..754a6f18536 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -152,7 +152,13 @@ void udf_init() } table= tables.table; - init_read_record(&read_record_info, new_thd, table, NULL,1,0,FALSE); + if (init_read_record(&read_record_info, new_thd, table, NULL,1,0,FALSE)) + { + sql_print_error("Could not initialize init_read_record; udf's not " + "loaded"); + goto end; + } + table->use_all_columns(); while (!(error= read_record_info.read_record(&read_record_info))) { @@ -209,7 +215,7 @@ void udf_init() } tmp->dlhandle = dl; { - char buf[NAME_LEN+16], *missing; + char buf[SAFE_NAME_LEN+16], *missing; if ((missing= init_syms(tmp, buf))) { sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing); @@ -463,7 +469,7 @@ int mysql_create_function(THD *thd,udf_func *udf) } udf->dlhandle=dl; { - char buf[NAME_LEN+16], *missing; + char buf[SAFE_NAME_LEN+16], *missing; if ((missing= init_syms(udf, buf))) { my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 374e92c6a52..33fedb67ac4 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -167,20 +167,19 @@ void st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg) { thd_arg->lex->current_select= fake_select_lex; - fake_select_lex->table_list.link_in_list((uchar *)&result_table_list, - (uchar **) - &result_table_list.next_local); + fake_select_lex->table_list.link_in_list(&result_table_list, + &result_table_list.next_local); fake_select_lex->context.table_list= fake_select_lex->context.first_name_resolution_table= fake_select_lex->get_table_list(); if (!fake_select_lex->first_execution) { - for (ORDER *order= (ORDER *) global_parameters->order_list.first; + for (ORDER *order= global_parameters->order_list.first; order; order= order->next) order->item= &order->item_ptr; } - for (ORDER *order= (ORDER *)global_parameters->order_list.first; + for (ORDER *order= global_parameters->order_list.first; order; order=order->next) { @@ -272,18 +271,18 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); saved_error= join->prepare(&sl->ref_pointer_array, - (TABLE_LIST*) sl->table_list.first, + 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, + NULL : sl->order_list.first, + sl->group_list.first, sl->having, - (is_union_select ? (ORDER*) 0 : - (ORDER*) thd_arg->lex->proc_list.first), + (is_union_select ? NULL : + thd_arg->lex->proc_list.first), sl, this); /* There are no * in the statement anymore (for PS) */ sl->with_wild= 0; @@ -377,7 +376,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { ORDER *ord; Item_func::Functype ft= Item_func::FT_FUNC; - for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next) + for (ord= global_parameters->order_list.first; ord; ord= ord->next) if ((*ord->item)->walk (&Item::find_function_processor, FALSE, (uchar *) &ft)) { @@ -439,12 +438,11 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, thd_arg->lex->current_select= fake_select_lex; saved_error= fake_select_lex->join-> prepare(&fake_select_lex->ref_pointer_array, - (TABLE_LIST*) fake_select_lex->table_list.first, + fake_select_lex->table_list.first, 0, 0, fake_select_lex->order_list.elements, - (ORDER*) fake_select_lex->order_list.first, - (ORDER*) NULL, NULL, - (ORDER*) NULL, + fake_select_lex->order_list.first, + NULL, NULL, NULL, fake_select_lex, this); fake_select_lex->table_list.empty(); } @@ -620,8 +618,8 @@ bool st_select_lex_unit::exec() &result_table_list, 0, item_list, NULL, global_parameters->order_list.elements, - (ORDER*)global_parameters->order_list.first, - (ORDER*) NULL, NULL, (ORDER*) NULL, + global_parameters->order_list.first, + NULL, NULL, NULL, fake_select_lex->options | SELECT_NO_UNLOCK, result, this, fake_select_lex); } @@ -643,8 +641,8 @@ bool st_select_lex_unit::exec() &result_table_list, 0, item_list, NULL, global_parameters->order_list.elements, - (ORDER*)global_parameters->order_list.first, - (ORDER*) NULL, NULL, (ORDER*) NULL, + global_parameters->order_list.first, + NULL, NULL, NULL, fake_select_lex->options | SELECT_NO_UNLOCK, result, this, fake_select_lex); } @@ -720,7 +718,7 @@ bool st_select_lex_unit::cleanup() if (global_parameters->order_list.elements) { ORDER *ord; - for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next) + for (ord= global_parameters->order_list.first; ord; ord= ord->next) (*ord->item)->walk (&Item::cleanup_processor, 0, 0); } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a7d12ce6efd..531227eb76f 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -29,12 +29,12 @@ bool compare_record(TABLE *table) { - if (table->s->blob_fields + table->s->varchar_fields == 0) + if (table->s->can_cmp_whole_record) return cmp_record(table,record[1]); /* Compare null bits */ if (memcmp(table->null_flags, table->null_flags+table->s->rec_buff_length, - table->s->null_bytes)) + table->s->null_bytes_for_compare)) return TRUE; // Diff in NULL value /* Compare updated fields */ for (Field **ptr= table->field ; *ptr ; ptr++) @@ -394,7 +394,7 @@ int mysql_update(THD *thd, matching rows before updating the table! */ if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) - table->mark_columns_used_by_index(used_index); + table->add_read_columns_used_by_index(used_index); else { table->use_all_columns(); @@ -422,6 +422,7 @@ int mysql_update(THD *thd, { goto err; } + thd->examined_row_count+= examined_rows; /* Filesort has already found and selected the rows we want to update, so we don't need the where clause @@ -459,17 +460,21 @@ int mysql_update(THD *thd, */ if (used_index == MAX_KEY || (select && select->quick)) - init_read_record(&info, thd, table, select, 0, 1, FALSE); + { + if (init_read_record(&info, thd, table, select, 0, 1, FALSE)) + goto err; + } else init_read_record_idx(&info, thd, table, 1, used_index); thd_proc_info(thd, "Searching rows for update"); ha_rows tmp_limit= limit; - while (!(error=info.read_record(&info)) && - !thd->killed && !thd->is_error()) + while (!(error=info.read_record(&info)) && !thd->killed) { - if (!select || select->skip_record(thd) > 0) + update_virtual_fields(thd, table); + thd->examined_row_count++; + if (!select || (error= select->skip_record(thd)) > 0) { if (table->file->was_semi_consistent_read()) continue; /* repeat the read of the same row if it still exists */ @@ -488,7 +493,15 @@ int mysql_update(THD *thd, } } else + { table->file->unlock_row(); + if (error < 0) + { + /* Fatal error from select->skip_record() */ + error= 1; + break; + } + } } if (thd->killed && !error) error= 1; // Aborted @@ -526,7 +539,8 @@ int mysql_update(THD *thd, if (select && select->quick && select->quick->reset()) goto err; table->file->try_semi_consistent_read(1); - init_read_record(&info, thd, table, select, 0, 1, FALSE); + if (init_read_record(&info, thd, table, select, 0, 1, FALSE)) + goto err; updated= found= 0; /* @@ -575,6 +589,8 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { + update_virtual_fields(thd, table); + thd->examined_row_count++; if (!select || select->skip_record(thd) > 0) { if (table->file->was_semi_consistent_read()) @@ -1048,7 +1064,7 @@ reopen_tables: correct order of statements. Otherwise, we use a TL_READ lock to improve performance. */ - tl->lock_type= read_lock_type_for_table(thd, table); + tl->lock_type= read_lock_type_for_table(thd, lex, tl); tl->updating= 0; /* Update TABLE::lock_type accordingly. */ if (!tl->placeholder() && !using_lock_tables) @@ -1326,7 +1342,7 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *lex_unit) { TABLE_LIST *table_ref; - SQL_LIST update; + SQL_I_List<TABLE_LIST> update; table_map tables_to_update; Item_field *item; List_iterator_fast<Item> field_it(*fields); @@ -1406,11 +1422,11 @@ int multi_update::prepare(List<Item> ¬_used_values, leaf_table_count++; if (tables_to_update & table->map) { - TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref, + TABLE_LIST *tl= (TABLE_LIST*) thd->memdup(table_ref, sizeof(*tl)); if (!tl) DBUG_RETURN(1); - update.link_in_list((uchar*) tl, (uchar**) &tl->next_local); + update.link_in_list(tl, &tl->next_local); tl->shared= table_count++; table->no_keyread=1; table->covering_keys.clear_all(); @@ -1431,7 +1447,7 @@ int multi_update::prepare(List<Item> ¬_used_values, table_count= update.elements; - update_tables= (TABLE_LIST*) update.first; + update_tables= update.first; tmp_tables = (TABLE**) thd->calloc(sizeof(TABLE *) * table_count); tmp_table_param = (TMP_TABLE_PARAM*) thd->calloc(sizeof(TMP_TABLE_PARAM) * @@ -1954,7 +1970,7 @@ int multi_update::do_updates() TABLE_LIST *cur_table; int local_error= 0; ha_rows org_updated; - TABLE *table, *tmp_table; + TABLE *table, *tmp_table, *err_table; List_iterator_fast<TABLE> check_opt_it(unupdated_check_opt_tables); DBUG_ENTER("multi_update::do_updates"); @@ -1972,14 +1988,21 @@ int multi_update::do_updates() org_updated= updated; tmp_table= tmp_tables[cur_table->shared]; tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache - (void) table->file->ha_rnd_init(0); + if ((local_error= table->file->ha_rnd_init(0))) + { + err_table= table; + goto err; + } table->file->extra(HA_EXTRA_NO_CACHE); check_opt_it.rewind(); while(TABLE *tbl= check_opt_it++) { - if (tbl->file->ha_rnd_init(1)) + if ((local_error= tbl->file->ha_rnd_init(1))) + { + err_table= tbl; goto err; + } tbl->file->extra(HA_EXTRA_CACHE); } @@ -1987,9 +2010,11 @@ int multi_update::do_updates() Setup copy functions to copy fields from temporary table */ List_iterator_fast<Item> field_it(*fields_for_table[offset]); - Field **field= tmp_table->field + - 1 + unupdated_check_opt_tables.elements; // Skip row pointers + Field **field; Copy_field *copy_field_ptr= copy_field, *copy_field_end; + + /* Skip row pointers */ + field= tmp_table->field + 1 + unupdated_check_opt_tables.elements; for ( ; *field ; field++) { Item_field *item= (Item_field* ) field_it++; @@ -1997,8 +2022,11 @@ int multi_update::do_updates() } copy_field_end=copy_field_ptr; - if ((local_error = tmp_table->file->ha_rnd_init(1))) + if ((local_error= tmp_table->file->ha_rnd_init(1))) + { + err_table= tmp_table; goto err; + } can_compare_record= (!(table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) || @@ -2008,13 +2036,17 @@ int multi_update::do_updates() for (;;) { if (thd->killed && trans_safe) - goto err; + { + thd->fatal_error(); + goto err2; + } if ((local_error= tmp_table->file->ha_rnd_next(tmp_table->record[0]))) { if (local_error == HA_ERR_END_OF_FILE) break; if (local_error == HA_ERR_RECORD_DELETED) continue; // May happen on dup key + err_table= tmp_table; goto err; } @@ -2027,7 +2059,10 @@ int multi_update::do_updates() if ((local_error= tbl->file->ha_rnd_pos(tbl->record[0], (uchar*) tmp_table->field[field_num]->ptr))) + { + err_table= tbl; goto err; + } field_num++; } while ((tbl= check_opt_it++)); @@ -2054,7 +2089,10 @@ int multi_update::do_updates() if (error == VIEW_CHECK_SKIP) continue; else if (error == VIEW_CHECK_ERROR) - goto err; + { + thd->fatal_error(); + goto err2; + } } if ((local_error=table->file->ha_update_row(table->record[1], table->record[0])) && @@ -2062,7 +2100,10 @@ int multi_update::do_updates() { if (!ignore || table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY)) + { + err_table= table; goto err; + } } if (local_error != HA_ERR_RECORD_IS_THE_SAME) updated++; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 5381ce94411..204100f6034 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -887,7 +887,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, view->algorithm != VIEW_ALGORITHM_TMPTABLE))) { /* TODO: change here when we will support UNIONs */ - for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first; + for (TABLE_LIST *tbl= lex->select_lex.table_list.first; tbl; tbl= tbl->next_local) { @@ -1006,7 +1006,7 @@ loop_out: */ if (view->updatable_view && !lex->select_lex.master_unit()->is_union() && - !((TABLE_LIST*)lex->select_lex.table_list.first)->next_local && + !(lex->select_lex.table_list.first)->next_local && find_table_in_global_list(lex->query_tables->next_global, lex->query_tables->db, lex->query_tables->table_name)) @@ -1189,12 +1189,13 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; { - char old_db_buf[NAME_LEN+1]; + char old_db_buf[SAFE_NAME_LEN+1]; LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; bool dbchanged; - Parser_state parser_state(thd, - table->select_stmt.str, - table->select_stmt.length); + Parser_state parser_state; + if (parser_state.init(thd, table->select_stmt.str, + table->select_stmt.length)) + goto err; /* Use view db name as thread default database, in order to ensure @@ -1351,8 +1352,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, This may change in future, for example if we enable merging of views with subqueries in select list. */ - view_main_select_tables= - (TABLE_LIST*)lex->select_lex.table_list.first; + view_main_select_tables= lex->select_lex.table_list.first; /* Let us set proper lock type for tables of the view's main diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b63fc0eae4a..75a16e19d83 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -516,8 +516,7 @@ set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val) Let us add this item to list of all Item_trigger_field objects in trigger. */ - lex->trg_table_fields.link_in_list((uchar *) trg_fld, - (uchar **) &trg_fld->next_trg_field); + lex->trg_table_fields.link_in_list(trg_fld, &trg_fld->next_trg_field); return lex->sphead->add_instr(sp_fld); } @@ -4710,11 +4709,9 @@ create_table_option: TABLE_LIST *table_list= lex->select_lex.get_table_list(); lex->create_info.merge_list= lex->select_lex.table_list; lex->create_info.merge_list.elements--; - lex->create_info.merge_list.first= - (uchar*) (table_list->next_local); + lex->create_info.merge_list.first= table_list->next_local; lex->select_lex.table_list.elements=1; - lex->select_lex.table_list.next= - (uchar**) &(table_list->next_local); + lex->select_lex.table_list.next= &(table_list->next_local); table_list->next_local= 0; lex->create_info.used_fields|= HA_CREATE_USED_UNION; } @@ -5847,8 +5844,7 @@ alter: lex->alter_info.reset(); lex->col_list.empty(); lex->select_lex.init_order(); - lex->select_lex.db= - ((TABLE_LIST*) lex->select_lex.table_list.first)->db; + lex->select_lex.db= (lex->select_lex.table_list.first)->db; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.db_type= 0; lex->create_info.default_table_charset= NULL; @@ -6761,8 +6757,6 @@ cache_keys_spec: { Lex->select_lex.alloc_index_hints(YYTHD); Select->set_index_hint_type(INDEX_HINT_USE, - global_system_variables.old_mode ? - INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL); } cache_key_list_or_empty @@ -8560,9 +8554,8 @@ opt_gorder_clause: | order_clause { SELECT_LEX *select= Select; - select->gorder_list= - (SQL_LIST*) sql_memdup((char*) &select->order_list, - sizeof(st_sql_list)); + select->gorder_list= new (YYTHD->mem_root) + SQL_I_List<ORDER>(select->order_list); if (select->gorder_list == NULL) MYSQL_YYABORT; select->order_list.empty(); @@ -9512,7 +9505,7 @@ procedure_clause: } lex->proc_list.elements=0; lex->proc_list.first=0; - lex->proc_list.next= (uchar**) &lex->proc_list.first; + lex->proc_list.next= &lex->proc_list.first; Item_field *item= new (YYTHD->mem_root) Item_field(&lex->current_select->context, NULL, NULL, $2.str); @@ -11500,8 +11493,8 @@ simple_ident_q: Let us add this item to list of all Item_trigger_field objects in trigger. */ - lex->trg_table_fields.link_in_list((uchar*) trg_fld, - (uchar**) &trg_fld->next_trg_field); + lex->trg_table_fields.link_in_list(trg_fld, + &trg_fld->next_trg_field); $$= trg_fld; } @@ -11587,7 +11580,7 @@ field_ident: ident { $$=$1;} | ident '.' ident '.' ident { - TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first; + TABLE_LIST *table= Select->table_list.first; if (my_strcasecmp(table_alias_charset, $1.str, table->db)) { my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); @@ -11603,7 +11596,7 @@ field_ident: } | ident '.' ident { - TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first; + TABLE_LIST *table= Select->table_list.first; if (my_strcasecmp(table_alias_charset, $1.str, table->alias)) { my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str); diff --git a/sql/table.cc b/sql/table.cc index 2b1a85a74ea..302c5090925 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -54,6 +54,8 @@ static uint find_field(Field **fields, uchar *record, uint start, uint length); inline bool is_system_table_name(const char *name, uint length); +static ulong get_form_pos(File file, uchar *head); + /************************************************************************** Object_creation_ctx implementation. **************************************************************************/ @@ -306,13 +308,6 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, share->version= refresh_version; /* - This constant is used to mark that no table map version has been - assigned. No arithmetic is done on the value: it will be - overwritten with a value taken from MYSQL_BIN_LOG. - */ - share->table_map_version= ~(ulonglong)0; - - /* Since alloc_table_share() can be called without any locking (for example, ha_create_table... functions), we do not assign a table map id here. Instead we assign a value that is not used @@ -375,11 +370,6 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, share->path.length= share->normalized_path.length= strlen(path); share->frm_version= FRM_VER_TRUE_VARCHAR; - /* - Temporary tables are not replicated, but we set up these fields - anyway to be able to catch errors. - */ - share->table_map_version= ~(ulonglong)0; share->cached_row_logging_check= -1; /* @@ -708,15 +698,20 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, const char **interval_array; enum legacy_db_type legacy_db_type; my_bitmap_map *bitmaps; + bool null_bits_are_used; DBUG_ENTER("open_binary_frm"); + LINT_INIT(options); + LINT_INIT(options_len); + new_field_pack_flag= head[27]; new_frm_ver= (head[2] - FRM_VER); field_pack_length= new_frm_ver < 2 ? 11 : 17; disk_buff= 0; error= 3; - if (!(pos=get_form_pos(file,head,(TYPELIB*) 0))) + /* Position of the form in the form file. */ + if (!(pos= get_form_pos(file, head))) goto err; /* purecov: inspected */ share->frm_version= head[2]; @@ -885,7 +880,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, /* Read extra data segment */ uchar *next_chunk, *buff_end; DBUG_PRINT("info", ("extra segment size is %u bytes", n_length)); - if (!(next_chunk= buff= (uchar*) my_malloc(n_length, MYF(MY_WME)))) + if (!(next_chunk= buff= (uchar*) my_malloc(n_length+1, MYF(MY_WME)))) goto err; if (my_pread(file, buff, n_length, record_offset + share->reclength, MYF(MY_NABP))) @@ -960,6 +955,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, { /* purecov: begin inspected */ error= 8; + name.str[name.length]= 0; my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str); goto free_and_err; /* purecov: end */ @@ -1154,6 +1150,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, goto free_and_err; record= share->default_values-1; /* Fieldstart = 1 */ + null_bits_are_used= share->null_fields != 0; if (share->null_field_first) { null_flags= null_pos= (uchar*) record+1; @@ -1372,6 +1369,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, reg_field->stored_in_db= fld_stored_in_db; if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) { + null_bits_are_used= 1; if ((null_bit_pos+= field_length & 7) > 7) { null_pos++; @@ -1505,12 +1503,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, keyinfo->extra_length+=HA_KEY_BLOB_LENGTH; key_part->store_length+=HA_KEY_BLOB_LENGTH; keyinfo->key_length+= HA_KEY_BLOB_LENGTH; - /* - Mark that there may be many matching values for one key - combination ('a', 'a ', 'a '...) - */ - if (!(field->flags & BINARY_FLAG)) - keyinfo->flags|= HA_END_SPACE_KEY; } if (field->type() == MYSQL_TYPE_BIT) key_part->key_part_flag|= HA_BIT_PART; @@ -1694,6 +1686,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, share->null_bytes= (null_pos - (uchar*) null_flags + (null_bit_pos + 7) / 8); share->last_null_bit_pos= null_bit_pos; + share->null_bytes_for_compare= null_bits_are_used ? share->null_bytes : 0; + share->can_cmp_whole_record= (share->blob_fields == 0 && + share->varchar_fields == 0); share->db_low_byte_first= handler_file->low_byte_first(); share->column_bitmap_size= bitmap_buffer_size(share->fields); @@ -1851,6 +1846,11 @@ bool fix_vcol_expr(THD *thd, goto end; } thd->where= save_where; + if (unlikely(func_expr->result_type() == ROW_RESULT)) + { + my_error(ER_ROW_EXPR_FOR_VCOL, MYF(0)); + goto end; + } #ifdef PARANOID /* Walk through the Item tree checking if all items are valid @@ -1915,10 +1915,8 @@ end: parses it, building an item object for it. The pointer to this item is placed into in field->vcol_info.expr_item. After this the function performs semantic analysis of the item by calling the the function fix_vcol_expr. - Since the defining expression is part of the table definition the item - for it is created in table->memroot within a separate Query_arena. - The free_list of this arena is saved in field->vcol_info.item_free_list - to be freed when the table defition is removed from the TABLE_SHARE cache. + Since the defining expression is part of the table definition the item for + it is created in table->memroot within the special arena TABLE::expr_arena. @note Before passing 'vcol_expr" to the parser the function embraces it in @@ -1935,18 +1933,25 @@ bool unpack_vcol_info_from_frm(THD *thd, LEX_STRING *vcol_expr, bool *error_reported) { - bool rc= FALSE; + bool rc; + char *vcol_expr_str; + int str_len; + CHARSET_INFO *old_character_set_client; + Query_arena *backup_stmt_arena_ptr; + Query_arena backup_arena; + Query_arena *vcol_arena= 0; + Parser_state parser_state; DBUG_ENTER("unpack_vcol_info_from_frm"); DBUG_ASSERT(vcol_expr); + old_character_set_client= thd->variables.character_set_client; + backup_stmt_arena_ptr= thd->stmt_arena; + /* Step 1: Construct the input string for the parser. The string to be parsed has to be of the following format: "PARSE_VCOL_EXPR (<expr_string_from_frm>)". */ - char *vcol_expr_str; - int str_len= 0; - CHARSET_INFO *old_character_set_client; if (!(vcol_expr_str= (char*) alloc_root(&table->mem_root, vcol_expr->length + @@ -1968,19 +1973,27 @@ bool unpack_vcol_info_from_frm(THD *thd, str_len++; memcpy(vcol_expr_str + str_len, "\0", 1); str_len++; - Parser_state parser_state(thd, vcol_expr_str, str_len); + + if (parser_state.init(thd, vcol_expr_str, str_len)) + goto err; /* Step 2: Setup thd for parsing. */ - Query_arena *backup_stmt_arena_ptr= thd->stmt_arena; - Query_arena backup_arena; - Query_arena vcol_arena(&table->mem_root, Query_arena::INITIALIZED); - thd->set_n_backup_active_arena(&vcol_arena, &backup_arena); - thd->stmt_arena= &vcol_arena; + vcol_arena= table->expr_arena; + if (!vcol_arena) + { + Query_arena expr_arena(&table->mem_root, Query_arena::INITIALIZED); + if (!(vcol_arena= (Query_arena *) alloc_root(&table->mem_root, + sizeof(Query_arena)))) + goto err; + *vcol_arena= expr_arena; + table->expr_arena= vcol_arena; + } + thd->set_n_backup_active_arena(vcol_arena, &backup_arena); + thd->stmt_arena= vcol_arena; thd->lex->parse_vcol_expr= TRUE; - old_character_set_client= thd->variables.character_set_client; /* Step 3: Use the parser to build an Item object from vcol_expr_str. @@ -1999,7 +2012,7 @@ bool unpack_vcol_info_from_frm(THD *thd, field->vcol_info= 0; goto err; } - field->vcol_info->item_free_list= thd->free_list; + rc= FALSE; goto end; err: @@ -2008,7 +2021,8 @@ err: thd->free_items(); end: thd->stmt_arena= backup_stmt_arena_ptr; - thd->restore_active_arena(&vcol_arena, &backup_arena); + if (vcol_arena) + thd->restore_active_arena(vcol_arena, &backup_arena); thd->variables.character_set_client= old_character_set_client; DBUG_RETURN(rc); @@ -2323,9 +2337,9 @@ partititon_err: (my_bitmap_map*) bitmaps, share->fields, FALSE); bitmap_init(&outparam->def_write_set, (my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE); - bitmap_init(&outparam->tmp_set, + bitmap_init(&outparam->def_vcol_set, (my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE); - bitmap_init(&outparam->vcol_set, + bitmap_init(&outparam->tmp_set, (my_bitmap_map*) (bitmaps+bitmap_size*3), share->fields, FALSE); outparam->default_column_bitmaps(); @@ -2431,12 +2445,12 @@ int closefrm(register TABLE *table, bool free_share) } my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR)); table->alias= 0; + if (table->expr_arena) + table->expr_arena->free_items(); if (table->field) { for (Field **ptr=table->field ; *ptr ; ptr++) { - if ((*ptr)->vcol_info) - free_items((*ptr)->vcol_info->item_free_list); delete *ptr; } table->field= 0; @@ -2497,55 +2511,46 @@ void free_field_buffers_larger_than(TABLE *table, uint32 size) } } - /* Find where a form starts */ - /* if formname is NullS then only formnames is read */ +/** + Find where a form starts. + + @param head The start of the form file. + + @remark If formname is NULL then only formnames is read. + + @retval The form position. +*/ -ulong get_form_pos(File file, uchar *head, TYPELIB *save_names) +static ulong get_form_pos(File file, uchar *head) { - uint a_length,names,length; - uchar *pos,*buf; + uchar *pos, *buf; + uint names, length; ulong ret_value=0; DBUG_ENTER("get_form_pos"); - LINT_INIT(buf); + names= uint2korr(head+8); - names=uint2korr(head+8); - a_length=(names+2)*sizeof(char *); /* Room for two extra */ + if (!(names= uint2korr(head+8))) + DBUG_RETURN(0); - if (!save_names) - a_length=0; - else - save_names->type_names=0; /* Clear if error */ - - if (names) - { - length=uint2korr(head+4); - VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0))); - if (!(buf= (uchar*) my_malloc((size_t) length+a_length+names*4, - MYF(MY_WME))) || - my_read(file, buf+a_length, (size_t) (length+names*4), - MYF(MY_NABP))) - { /* purecov: inspected */ - x_free((uchar*) buf); /* purecov: inspected */ - DBUG_RETURN(0L); /* purecov: inspected */ - } - pos= buf+a_length+length; - ret_value=uint4korr(pos); - } - if (! save_names) - { - if (names) - my_free((uchar*) buf,MYF(0)); - } - else if (!names) - bzero((char*) save_names,sizeof(save_names)); - else + length= uint2korr(head+4); + + my_seek(file, 64L, MY_SEEK_SET, MYF(0)); + + if (!(buf= (uchar*) my_malloc(length+names*4, MYF(MY_WME)))) + DBUG_RETURN(0); + + if (my_read(file, buf, length+names*4, MYF(MY_NABP))) { - char *str; - const char **tmp = (const char**) buf; - str=(char *) (buf+a_length); - fix_type_pointers(&tmp, save_names, 1, &str); + x_free(buf); + DBUG_RETURN(0); } + + pos= buf+length; + ret_value= uint4korr(pos); + + my_free(buf, MYF(0)); + DBUG_RETURN(ret_value); } @@ -3143,6 +3148,13 @@ bool check_db_name(LEX_STRING *org_name) { char *name= org_name->str; uint name_length= org_name->length; + bool check_for_path_chars; + + if ((check_for_path_chars= check_mysql50_prefix(name))) + { + name+= MYSQL50_TABLE_NAME_PREFIX_LENGTH; + name_length-= MYSQL50_TABLE_NAME_PREFIX_LENGTH; + } if (!name_length || name_length > NAME_LEN) return 1; @@ -3150,41 +3162,29 @@ bool check_db_name(LEX_STRING *org_name) if (lower_case_table_names && name != any_db) my_casedn_str(files_charset_info, name); -#if defined(USE_MB) && defined(USE_MB_IDENT) - if (use_mb(system_charset_info)) - { - name_length= 0; - bool last_char_is_space= TRUE; - char *end= name + org_name->length; - while (name < end) - { - int len; - last_char_is_space= my_isspace(system_charset_info, *name); - len= my_ismbchar(system_charset_info, name, end); - if (!len) - len= 1; - name+= len; - name_length++; - } - return (last_char_is_space || name_length > NAME_CHAR_LEN); - } - else -#endif - return ((org_name->str[org_name->length - 1] != ' ') || - (name_length > NAME_CHAR_LEN)); /* purecov: inspected */ + return check_table_name(name, name_length, check_for_path_chars); } + /* Allow anything as a table name, as long as it doesn't contain an ' ' at the end returns 1 on error */ - bool check_table_name(const char *name, uint length, bool check_for_path_chars) { uint name_length= 0; // name length in symbols const char *end= name+length; + + + if (!check_for_path_chars && + (check_for_path_chars= check_mysql50_prefix(name))) + { + name+= MYSQL50_TABLE_NAME_PREFIX_LENGTH; + length-= MYSQL50_TABLE_NAME_PREFIX_LENGTH; + } + if (!length || length > NAME_LEN) return 1; #if defined(USE_MB) && defined(USE_MB_IDENT) @@ -3208,10 +3208,10 @@ bool check_table_name(const char *name, uint length, bool check_for_path_chars) continue; } } +#endif if (check_for_path_chars && (*name == '/' || *name == '\\' || *name == '~' || *name == FN_EXTCHAR)) return 1; -#endif name++; name_length++; } @@ -4789,10 +4789,10 @@ void st_table::clear_column_bitmaps() Reset column read/write usage. It's identical to: bitmap_clear_all(&table->def_read_set); bitmap_clear_all(&table->def_write_set); + bitmap_clear_all(&table->def_vcol_set); */ - bzero((char*) def_read_set.bitmap, s->column_bitmap_size*2); - bzero((char*) def_read_set.bitmap, s->column_bitmap_size*4); - column_bitmaps_set(&def_read_set, &def_write_set); + bzero((char*) def_read_set.bitmap, s->column_bitmap_size*3); + column_bitmaps_set(&def_read_set, &def_write_set, &def_vcol_set); } @@ -4844,6 +4844,27 @@ void st_table::mark_columns_used_by_index(uint index) /* + Add fields used by a specified index to the table's read_set. + + NOTE: + The original state can be restored with + restore_column_maps_after_mark_index(). +*/ + +void st_table::add_read_columns_used_by_index(uint index) +{ + MY_BITMAP *bitmap= &tmp_set; + DBUG_ENTER("st_table::add_read_columns_used_by_index"); + + enable_keyread(); + bitmap_copy(bitmap, read_set); + mark_columns_used_by_index_no_reset(index, bitmap); + column_bitmaps_set(bitmap, write_set); + DBUG_VOID_RETURN; +} + + +/* Restore to use normal column maps after key read NOTES @@ -5011,7 +5032,7 @@ void st_table::mark_columns_needed_for_update() } } /* Mark all virtual columns needed for update */ - mark_virtual_columns_for_write(); + mark_virtual_columns_for_write(FALSE); DBUG_VOID_RETURN; } @@ -5039,7 +5060,7 @@ void st_table::mark_columns_needed_for_insert() if (found_next_number_field) mark_auto_increment_column(); /* Mark virtual columns for insert */ - mark_virtual_columns_for_write(); + mark_virtual_columns_for_write(TRUE); } @@ -5065,7 +5086,7 @@ bool st_table::mark_virtual_col(Field *field) { bool res; DBUG_ASSERT(field->vcol_info); - if (!(res= bitmap_fast_test_and_set(&vcol_set, field->field_index))) + if (!(res= bitmap_fast_test_and_set(vcol_set, field->field_index))) { Item *vcol_item= field->vcol_info->expr_item; DBUG_ASSERT(vcol_item); @@ -5077,10 +5098,14 @@ bool st_table::mark_virtual_col(Field *field) /* @brief Mark virtual columns for update/insert commands + + @param insert_fl <-> virtual columns are marked for insert command @details The function marks virtual columns used in a update/insert commands in the vcol_set bitmap. + For an insert command a virtual column is always marked in write_set if + it is a stored column. If a virtual column is from write_set it is always marked in vcol_set. If a stored virtual column is not from write_set but it is computed through columns from write_set it is also marked in vcol_set, and, @@ -5099,7 +5124,7 @@ bool st_table::mark_virtual_col(Field *field) be added to read_set either. */ -void st_table::mark_virtual_columns_for_write(void) +void st_table::mark_virtual_columns_for_write(bool insert_fl) { Field **vfield_ptr, *tmp_vfield; bool bitmap_updated= FALSE; @@ -5111,16 +5136,21 @@ void st_table::mark_virtual_columns_for_write(void) bitmap_updated= mark_virtual_col(tmp_vfield); else if (tmp_vfield->stored_in_db) { - MY_BITMAP *save_read_set; - Item *vcol_item= tmp_vfield->vcol_info->expr_item; - DBUG_ASSERT(vcol_item); - bitmap_clear_all(&tmp_set); - save_read_set= read_set; - read_set= &tmp_set; - vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0); - read_set= save_read_set; - bitmap_intersect(&tmp_set, write_set); - if (!bitmap_is_clear_all(&tmp_set)) + bool mark_fl= insert_fl; + if (!mark_fl) + { + MY_BITMAP *save_read_set; + Item *vcol_item= tmp_vfield->vcol_info->expr_item; + DBUG_ASSERT(vcol_item); + bitmap_clear_all(&tmp_set); + save_read_set= read_set; + read_set= &tmp_set; + vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0); + read_set= save_read_set; + bitmap_intersect(&tmp_set, write_set); + mark_fl= !bitmap_is_clear_all(&tmp_set); + } + if (mark_fl) { bitmap_set_bit(write_set, tmp_vfield->field_index); mark_virtual_col(tmp_vfield); @@ -5529,6 +5559,7 @@ size_t max_row_length(TABLE *table, const uchar *data) /* @brief Compute values for virtual columns used in query + @param thd Thread handle @param table The TABLE object @param for_write Requests to compute only fields needed for write @@ -5545,7 +5576,7 @@ size_t max_row_length(TABLE *table, const uchar *data) >0 Error occurred when storing a virtual field value */ -int update_virtual_fields(TABLE *table, bool for_write) +int update_virtual_fields(THD *thd, TABLE *table, bool for_write) { DBUG_ENTER("update_virtual_fields"); Field **vfield_ptr, *vfield; @@ -5553,13 +5584,14 @@ int update_virtual_fields(TABLE *table, bool for_write) if (!table || !table->vfield) DBUG_RETURN(0); + thd->reset_arena_for_cached_items(table->expr_arena); /* Iterate over virtual fields in the table */ for (vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++) { vfield= (*vfield_ptr); DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item); /* Only update those fields that are marked in the vcol_set bitmap */ - if (bitmap_is_set(&table->vcol_set, vfield->field_index) && + if (bitmap_is_set(table->vcol_set, vfield->field_index) && (for_write || !vfield->stored_in_db)) { /* Compute the actual value of the virtual fields */ @@ -5571,6 +5603,7 @@ int update_virtual_fields(TABLE *table, bool for_write) DBUG_PRINT("info", ("field '%s' - skipped", vfield->field_name)); } } + thd->reset_arena_for_cached_items(0); DBUG_RETURN(0); } diff --git a/sql/table.h b/sql/table.h index 3922e1dd6bd..99b5601c307 100644 --- a/sql/table.h +++ b/sql/table.h @@ -27,6 +27,7 @@ class st_select_lex; class partition_info; class COND_EQUAL; class Security_context; +class Query_arena; /*************************************************************************/ @@ -57,7 +58,6 @@ typedef struct st_order { struct st_order *next; Item **item; /* Point at item in select fields */ Item *item_ptr; /* Storage for initial item */ - Item **item_copy; /* For SPs; the original item ptr */ int counter; /* position in SELECT list, correct only if counter_used is true*/ bool asc; /* true if ascending */ @@ -407,6 +407,11 @@ typedef struct st_table_share uint blob_ptr_size; /* 4 or 8 */ uint key_block_size; /* create key_block_size, if used */ uint null_bytes, last_null_bit_pos; + /* + Same as null_bytes, except that if there is only a 'delete-marker' in + the record then this value is 0. + */ + uint null_bytes_for_compare; uint fields; /* Number of fields */ /* Number of stored fields, generated-only virtual fields are not included */ uint stored_fields; @@ -441,8 +446,8 @@ typedef struct st_table_share bool name_lock, replace_with_name_lock; bool waiting_on_cond; /* Protection against free */ bool deleting; /* going to delete this table */ + bool can_cmp_whole_record; ulong table_map_id; /* for row-based replication */ - ulonglong table_map_version; /* Cache for row-based replication table share checks that does not @@ -455,7 +460,7 @@ typedef struct st_table_share #ifdef WITH_PARTITION_STORAGE_ENGINE /** @todo: Move into *ha_data for partitioning */ bool auto_partitioned; - const char *partition_info; + char *partition_info; uint partition_info_len; uint partition_info_buffer_size; const char *part_state; @@ -718,9 +723,8 @@ struct st_table { const char *alias; /* alias or table name */ uchar *null_flags; my_bitmap_map *bitmap_init_value; - MY_BITMAP def_read_set, def_write_set, tmp_set; /* containers */ - MY_BITMAP vcol_set; /* set of used virtual columns */ - MY_BITMAP *read_set, *write_set; /* Active column sets */ + MY_BITMAP def_read_set, def_write_set, def_vcol_set, tmp_set; + MY_BITMAP *read_set, *write_set, *vcol_set; /* Active column sets */ /* The ID of the query that opened and is using this table. Has different meanings depending on the table type. @@ -789,7 +793,7 @@ struct st_table { /* number of select if it is derived table */ uint derived_select_number; int current_lock; /* Type of lock on table */ - my_bool copy_blobs; /* copy_blobs when storing */ + bool copy_blobs; /* copy_blobs when storing */ /* 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0. @@ -801,34 +805,34 @@ struct st_table { If true, the current table row is considered to have all columns set to NULL, including columns declared as "not null" (see maybe_null). */ - my_bool null_row; + bool null_row; /* TODO: Each of the following flags take up 8 bits. They can just as easily be put into one single unsigned long and instead of taking up 18 bytes, it would take up 4. */ - my_bool force_index; + bool force_index; /** Flag set when the statement contains FORCE INDEX FOR ORDER BY See TABLE_LIST::process_index_hints(). */ - my_bool force_index_order; + bool force_index_order; /** Flag set when the statement contains FORCE INDEX FOR GROUP BY See TABLE_LIST::process_index_hints(). */ - my_bool force_index_group; - my_bool distinct,const_table,no_rows; + bool force_index_group; + bool distinct,const_table,no_rows; /** If set, the optimizer has found that row retrieval should access index tree only. */ - my_bool key_read; - my_bool no_keyread; + bool key_read; + bool no_keyread; /* Placeholder for an open table which prevents other connections from taking name-locks on this table. Typically used with @@ -846,30 +850,38 @@ struct st_table { object associated with it (db_stat is always 0), but please do not rely on that. */ - my_bool open_placeholder; - my_bool locked_by_logger; - my_bool no_replicate; - my_bool locked_by_name; - my_bool fulltext_searched; - my_bool no_cache; + bool open_placeholder; + bool locked_by_logger; + bool no_replicate; + bool locked_by_name; + bool fulltext_searched; + bool no_cache; /* To signal that the table is associated with a HANDLER statement */ - my_bool open_by_handler; + bool open_by_handler; /* To indicate that a non-null value of the auto_increment field was provided by the user or retrieved from the current record. Used only in the MODE_NO_AUTO_VALUE_ON_ZERO mode. */ - my_bool auto_increment_field_not_null; - my_bool insert_or_update; /* Can be used by the handler */ - my_bool alias_name_used; /* true if table_name is alias */ - my_bool get_fields_in_item_tree; /* Signal to fix_field */ + bool auto_increment_field_not_null; + bool insert_or_update; /* Can be used by the handler */ + bool alias_name_used; /* true if table_name is alias */ + bool get_fields_in_item_tree; /* Signal to fix_field */ /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */ - my_bool children_attached; + bool children_attached; REGINFO reginfo; /* field connections */ MEM_ROOT mem_root; GRANT_INFO grant; FILESORT_INFO sort; + /* + The arena which the items for expressions from the table definition + are associated with. + Currently only the items of the expressions for virtual columns are + associated with this arena. + TODO: To attach the partitioning expressions to this arena. + */ + Query_arena *expr_arena; #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *part_info; /* Partition related information */ bool no_partitions_used; /* If true, all partitions have been pruned away */ @@ -881,13 +893,14 @@ struct st_table { void prepare_for_position(void); void mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *map); void mark_columns_used_by_index(uint index); + void add_read_columns_used_by_index(uint index); void restore_column_maps_after_mark_index(); void mark_auto_increment_column(void); void mark_columns_needed_for_update(void); void mark_columns_needed_for_delete(void); void mark_columns_needed_for_insert(void); bool mark_virtual_col(Field *field); - void mark_virtual_columns_for_write(void); + void mark_virtual_columns_for_write(bool insert_fl); inline void column_bitmaps_set(MY_BITMAP *read_set_arg, MY_BITMAP *write_set_arg) { @@ -896,12 +909,30 @@ struct st_table { if (file) file->column_bitmaps_signal(); } + inline void column_bitmaps_set(MY_BITMAP *read_set_arg, + MY_BITMAP *write_set_arg, + MY_BITMAP *vcol_set_arg) + { + read_set= read_set_arg; + write_set= write_set_arg; + vcol_set= vcol_set_arg; + if (file) + file->column_bitmaps_signal(); + } inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg, MY_BITMAP *write_set_arg) { read_set= read_set_arg; write_set= write_set_arg; } + inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg, + MY_BITMAP *write_set_arg, + MY_BITMAP *vcol_set_arg) + { + read_set= read_set_arg; + write_set= write_set_arg; + vcol_set= vcol_set_arg; + } inline void use_all_columns() { column_bitmaps_set(&s->all_set, &s->all_set); @@ -910,6 +941,7 @@ struct st_table { { read_set= &def_read_set; write_set= &def_write_set; + vcol_set= &def_vcol_set; } /* Is table open or should be treated as such by name-locking? */ inline bool is_name_opened() { return db_stat || open_placeholder; } @@ -1200,7 +1232,7 @@ struct TABLE_LIST } /* - List of tables local to a subquery (used by SQL_LIST). Considers + List of tables local to a subquery (used by SQL_I_List). Considers views as leaves (unlike 'next_leaf' below). Created at parse time in st_select_lex::add_table_to_list() -> table_list.link_in_list(). */ @@ -1745,7 +1777,11 @@ typedef struct st_nested_join */ table_map used_tables; table_map not_null_tables; /* tables that rejects nulls */ - struct st_join_table *first_nested;/* the first nested table in the plan */ + /** + Used for pointing out the first table in the plan being covered by this + join nest. It is used exclusively within make_outerjoin_info(). + */ + struct st_join_table *first_nested; /* Used to count tables in the nested join in 2 isolated places: 1. In make_outerjoin_info(). @@ -1768,6 +1804,15 @@ typedef struct st_nested_join /* Outer non-trivially correlated tables */ table_map sj_corr_tables; List<Item> sj_outer_expr_list; + /** + True if this join nest node is completely covered by the query execution + plan. This means two things. + + 1. All tables on its @c join_list are covered by the plan. + + 2. All child join nest nodes are fully covered. + */ + bool is_fully_covered() const { return join_list.elements == counter; } } NESTED_JOIN; diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index 83c4a8ee2a0..da0c25b54dd 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -21,8 +21,6 @@ extern "C" { void sql_alloc_error_handler(void) { - sql_print_error("%s", ER(ER_OUT_OF_RESOURCES)); - THD *thd= current_thd; if (thd) { @@ -49,6 +47,12 @@ extern "C" { ER(ER_OUT_OF_RESOURCES)); } } + + /* Skip writing to the error log to avoid mtr complaints */ + DBUG_EXECUTE_IF("simulate_out_of_memory", return;); + + sql_print_error("%s", ER(ER_OUT_OF_RESOURCES)); + } } diff --git a/sql/tztime.cc b/sql/tztime.cc index ee151b1e515..3f3060fbc10 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1814,6 +1814,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) my_time_t ttime; char buff[MAX_FIELD_WIDTH]; uchar keybuff[32]; + Field *field; String abbr(buff, sizeof(buff), &my_charset_latin1); char *alloc_buff, *tz_name_buff; /* @@ -1891,8 +1892,12 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) */ table= tz_tables->table; tz_tables= tz_tables->next_local; - table->field[0]->store((longlong) tzid, TRUE); - table->field[0]->get_key_image(keybuff, table->field[0]->pack_length(), Field::itRAW); + field= table->field[0]; + field->store((longlong) tzid, TRUE); + DBUG_ASSERT(field->key_length() <= sizeof(keybuff)); + field->get_key_image(keybuff, + min(field->key_length(), sizeof(keybuff)), + Field::itRAW); (void)table->file->ha_index_init(0, 1); if (table->file->ha_index_read_map(table->record[0], keybuff, @@ -1919,8 +1924,12 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) */ table= tz_tables->table; tz_tables= tz_tables->next_local; - table->field[0]->store((longlong) tzid, TRUE); - table->field[0]->get_key_image(keybuff, sizeof(keybuff), Field::itRAW); + field= table->field[0]; + field->store((longlong) tzid, TRUE); + DBUG_ASSERT(field->key_length() <= sizeof(keybuff)); + field->get_key_image(keybuff, + min(field->key_length(), sizeof(keybuff)), + Field::itRAW); (void)table->file->ha_index_init(0, 1); res= table->file->ha_index_read_map(table->record[0], keybuff, diff --git a/sql/udf_example.c b/sql/udf_example.c index 788582e32b6..979aebd4b23 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -1067,7 +1067,7 @@ char *myfunc_argument_name(UDF_INIT *initid __attribute__((unused)), { if (!args->attributes[0]) { - null_value= 0; + *null_value= 1; return 0; } (*length)--; /* space for ending \0 (for debugging purposes) */ diff --git a/sql/unireg.cc b/sql/unireg.cc index a048adbef72..9859d27dd3b 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -113,7 +113,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, ulong filepos, data_offset; uint options_len; uchar fileinfo[64],forminfo[288],*keybuff; - TYPELIB formnames; uchar *screen_buff; char buff[128]; #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -124,7 +123,7 @@ bool mysql_create_frm(THD *thd, const char *file_name, DBUG_ENTER("mysql_create_frm"); DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension - formnames.type_names=0; + if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0))) DBUG_RETURN(1); DBUG_ASSERT(db_file != NULL); @@ -210,8 +209,15 @@ bool mysql_create_frm(THD *thd, const char *file_name, key_buff_length= uint4korr(fileinfo+47); keybuff=(uchar*) my_malloc(key_buff_length, MYF(0)); key_info_length= pack_keys(keybuff, keys, key_info, data_offset); - VOID(get_form_pos(file,fileinfo,&formnames)); - if (!(filepos=make_new_entry(file,fileinfo,&formnames,""))) + + /* + Ensure that there are no forms in this newly created form file. + Even if the form file exists, create_frm must truncate it to + ensure one form per form file. + */ + DBUG_ASSERT(uint2korr(fileinfo+8) == 0); + + if (!(filepos= make_new_entry(file, fileinfo, NULL, ""))) goto err; maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000)); int2store(forminfo+2,maxlength); diff --git a/sql/unireg.h b/sql/unireg.h index ec4ecf6a10f..57a9038d5f7 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -129,8 +129,8 @@ #define SPECIAL_LOG_QUERIES_NOT_USING_INDEXES 4096 /* Obsolete */ /* Extern defines */ -#define store_record(A,B) bmove_align((A)->B,(A)->record[0],(size_t) (A)->s->reclength) -#define restore_record(A,B) bmove_align((A)->record[0],(A)->B,(size_t) (A)->s->reclength) +#define store_record(A,B) memcpy((A)->B,(A)->record[0],(size_t) (A)->s->reclength) +#define restore_record(A,B) memcpy((A)->record[0],(A)->B,(size_t) (A)->s->reclength) #define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->s->reclength) #define empty_record(A) { \ restore_record((A),s->default_values); \ |