diff options
Diffstat (limited to 'sql')
267 files changed, 4804 insertions, 1579 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index b3c99cc4788..8a03692598d 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -77,7 +77,8 @@ ENDIF() SET (SQL_SOURCE ../sql-common/client.c compat56.cc derror.cc des_key_file.cc - discover.cc ../sql-common/errmsg.c field.cc field_conv.cc + discover.cc ../sql-common/errmsg.c + field.cc field_conv.cc field_comp.cc filesort_utils.cc filesort.cc gstream.cc signal_handler.cc @@ -143,6 +144,7 @@ SET (SQL_SOURCE sql_sequence.cc sql_sequence.h ha_sequence.h ${WSREP_SOURCES} table_cache.cc encryption.cc temporary_tables.cc + proxy_protocol.cc ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc ${GEN_SOURCES} ${MYSYS_LIBWRAP_SOURCE} diff --git a/sql/bounded_queue.h b/sql/bounded_queue.h index 3573c5ceb27..d7c28215631 100644 --- a/sql/bounded_queue.h +++ b/sql/bounded_queue.h @@ -16,9 +16,8 @@ #ifndef BOUNDED_QUEUE_INCLUDED #define BOUNDED_QUEUE_INCLUDED -#include "my_global.h" #include "my_base.h" -#include "my_sys.h" +#include <my_sys.h> #include "queues.h" #include <string.h> diff --git a/sql/compat56.cc b/sql/compat56.cc index 704d1db9a98..6cbf4a66ac8 100644 --- a/sql/compat56.cc +++ b/sql/compat56.cc @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "my_global.h" +#include "mariadb.h" #include "compat56.h" #include "myisampack.h" #include "my_time.h" diff --git a/sql/create_options.cc b/sql/create_options.cc index 22e58f8801b..d010b73c222 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -19,6 +19,7 @@ Engine defined options of tables/fields/keys in CREATE/ALTER TABLE. */ +#include "mariadb.h" #include "create_options.h" #include <my_getopt.h> #include "set_var.h" diff --git a/sql/datadict.cc b/sql/datadict.cc index edc9fe5681b..7ea83236cd6 100644 --- a/sql/datadict.cc +++ b/sql/datadict.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "datadict.h" #include "sql_priv.h" #include "sql_class.h" diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 6b09978d128..d44b313ec24 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -15,7 +15,7 @@ /* see include/mysql/service_debug_sync.h for debug sync documentation */ -#include <my_global.h> +#include "mariadb.h" #include "debug_sync.h" #if defined(ENABLED_DEBUG_SYNC) @@ -1457,7 +1457,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ER_DEBUG_SYNC_TIMEOUT, ER_THD(thd, ER_DEBUG_SYNC_TIMEOUT)); thd->abort_on_warning= save_abort_on_warning; - DBUG_EXECUTE_IF("debug_sync_abort_on_timeout", DBUG_ABORT();); + DBUG_EXECUTE_IF("debug_sync_abort_on_timeout", DBUG_ASSERT(0);); break; } error= 0; diff --git a/sql/debug_sync.h b/sql/debug_sync.h index 999667b9efc..70d28cb982b 100644 --- a/sql/debug_sync.h +++ b/sql/debug_sync.h @@ -26,8 +26,6 @@ #pragma interface /* gcc class implementation */ #endif -#include <my_global.h> - class THD; #if defined(ENABLED_DEBUG_SYNC) diff --git a/sql/derror.cc b/sql/derror.cc index 5a1bee23f4a..8be1c26b7e4 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -21,7 +21,7 @@ Read language depeneded messagefile */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "derror.h" diff --git a/sql/derror.h b/sql/derror.h index 9f2aee71c7e..a171a248190 100644 --- a/sql/derror.h +++ b/sql/derror.h @@ -16,8 +16,6 @@ #ifndef DERROR_INCLUDED #define DERROR_INCLUDED -#include "my_global.h" /* uint */ - bool init_errmessage(void); void free_error_messages(); bool read_texts(const char *file_name, const char *language, diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc index ede2e9fa9d4..e7785a0a223 100644 --- a/sql/des_key_file.cc +++ b/sql/des_key_file.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> // HAVE_* +#include "mariadb.h" // HAVE_* #include "sql_priv.h" #include "des_key_file.h" // st_des_keyschedule, st_des_keyblock #include "log.h" // sql_print_error diff --git a/sql/discover.cc b/sql/discover.cc index 62a0084e2e7..a683166fb7f 100644 --- a/sql/discover.cc +++ b/sql/discover.cc @@ -21,7 +21,7 @@ Functions for discover of frm file from handler */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "discover.h" diff --git a/sql/discover.h b/sql/discover.h index e1508107235..c3127c3bff3 100644 --- a/sql/discover.h +++ b/sql/discover.h @@ -16,8 +16,6 @@ #ifndef DISCOVER_INCLUDED #define DISCOVER_INCLUDED -#include "my_global.h" /* uchar */ - int extension_based_table_discovery(MY_DIR *dirp, const char *ext, handlerton::discovered_list *tl); diff --git a/sql/encryption.cc b/sql/encryption.cc index 52eab262570..3174968f9b3 100644 --- a/sql/encryption.cc +++ b/sql/encryption.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include <mysql/plugin_encryption.h> #include "log.h" #include "sql_plugin.h" diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 4df981700ef..69d17725bea 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -15,7 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define MYSQL_LEX 1 -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_parse.h" // parse_sql @@ -1236,7 +1236,7 @@ Event_timed::get_create_event(THD *thd, String *buf) append_unescaped(buf, comment.str, comment.length); } buf->append(STRING_WITH_LEN(" DO ")); - buf->append(body.str, body.length); + buf->append(&body); DBUG_RETURN(0); } @@ -1284,7 +1284,7 @@ Event_job_data::construct_sp_sql(THD *thd, String *sp_sql) */ sp_sql->append(C_STRING_WITH_LEN("() SQL SECURITY INVOKER ")); - sp_sql->append(body.str, body.length); + sp_sql->append(&body); DBUG_RETURN(thd->is_fatal_error); } diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 20c2384ff04..9d899cb637e 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_base.h" // close_thread_tables @@ -499,7 +499,7 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table, */ do { - ret= read_record_info.read_record(&read_record_info); + ret= read_record_info.read_record(); if (ret == 0) ret= copy_event_to_schema_table(thd, schema_table, event_table); } while (ret == 0); @@ -1008,7 +1008,7 @@ Event_db_repository::drop_schema_events(THD *thd, const LEX_CSTRING *schema) if (init_read_record(&read_record_info, thd, table, NULL, NULL, 1, 0, FALSE)) goto end; - while (!ret && !(read_record_info.read_record(&read_record_info)) ) + while (!ret && !(read_record_info.read_record())) { char *et_field= get_field(thd->mem_root, table->field[field]); diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc index e203712e229..b2ff80626db 100644 --- a/sql/event_parse_data.cc +++ b/sql/event_parse_data.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sp_head.h" diff --git a/sql/event_parse_data.h b/sql/event_parse_data.h index e1aed36aa01..d2e14d74cf8 100644 --- a/sql/event_parse_data.h +++ b/sql/event_parse_data.h @@ -17,7 +17,7 @@ #ifndef _EVENT_PARSE_DATA_H_ #define _EVENT_PARSE_DATA_H_ -#include "sql_list.h" /* Sql_alloc */ +#include "sql_alloc.h" class Item; class THD; diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 208ad55c5f5..e46326afe18 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "event_queue.h" diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 1e808a17604..d9db7afe1ab 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "event_scheduler.h" @@ -85,7 +85,7 @@ Event_worker_thread::print_warnings(THD *thd, Event_job_data *et) char prefix_buf[5 * STRING_BUFFER_USUAL_SIZE]; String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info); prefix.length(0); - prefix.append("Event Scheduler: ["); + prefix.append(STRING_WITH_LEN("Event Scheduler: [")); prefix.append(et->definer.str, et->definer.length, system_charset_info); prefix.append("][", 2); diff --git a/sql/events.cc b/sql/events.cc index 6a38d4d3a1f..069fa97aa36 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_parse.h" // check_access @@ -625,7 +625,7 @@ Events::drop_schema_events(THD *thd, const char *db) DBUG_ENTER("Events::drop_schema_events"); DBUG_PRINT("enter", ("dropping events from %s", db)); - DBUG_ASSERT(ok_for_lower_case_names(db)); + DBUG_SLOW_ASSERT(ok_for_lower_case_names(db)); /* Sic: no check if the scheduler is disabled or system tables @@ -1156,7 +1156,7 @@ Events::load_events_from_db(THD *thd) DBUG_RETURN(TRUE); } - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { Event_queue_element *et; bool created, dropped; diff --git a/sql/field.cc b/sql/field.cc index c7aa0dce16e..e10c82347d5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -27,7 +27,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_select.h" #include "rpl_rli.h" // Pull in Relay_log_info @@ -51,7 +51,7 @@ *****************************************************************************/ static const char *zero_timestamp="0000-00-00 00:00:00.000000"; -LEX_CSTRING temp_lex_str= {"temp", 4}; +LEX_CSTRING temp_lex_str= {STRING_WITH_LEN("temp")}; uchar Field_null::null[1]={1}; const char field_separator=','; @@ -3236,7 +3236,7 @@ void Field_new_decimal::sql_type(String &str) const @returns number of bytes written to metadata_ptr */ -int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr) +int Field_new_decimal::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= precision; *(metadata_ptr + 1)= decimals(); @@ -4445,7 +4445,7 @@ bool Field_float::send_binary(Protocol *protocol) @returns number of bytes written to metadata_ptr */ -int Field_float::do_save_field_metadata(uchar *metadata_ptr) +int Field_float::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= pack_length(); return 1; @@ -4753,7 +4753,7 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused))) @returns number of bytes written to metadata_ptr */ -int Field_double::do_save_field_metadata(uchar *metadata_ptr) +int Field_double::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= pack_length(); return 1; @@ -5191,36 +5191,6 @@ static longlong read_lowendian(const uchar *from, uint bytes) } } -static void store_bigendian(ulonglong num, uchar *to, uint bytes) -{ - switch(bytes) { - case 1: mi_int1store(to, num); break; - case 2: mi_int2store(to, num); break; - case 3: mi_int3store(to, num); break; - case 4: mi_int4store(to, num); break; - case 5: mi_int5store(to, num); break; - case 6: mi_int6store(to, num); break; - case 7: mi_int7store(to, num); break; - case 8: mi_int8store(to, num); break; - default: DBUG_ASSERT(0); - } -} - -static longlong read_bigendian(const uchar *from, uint bytes) -{ - switch(bytes) { - case 1: return mi_uint1korr(from); - case 2: return mi_uint2korr(from); - case 3: return mi_uint3korr(from); - case 4: return mi_uint4korr(from); - case 5: return mi_uint5korr(from); - case 6: return mi_uint6korr(from); - case 7: return mi_uint7korr(from); - case 8: return mi_sint8korr(from); - default: DBUG_ASSERT(0); return 0; - } -} - void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { mi_int4store(ptr, timestamp); @@ -6804,6 +6774,20 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) } +int Field_str::store(longlong nr, bool unsigned_val) +{ + char buff[64]; + uint length; + length= (uint) (field_charset->cset->longlong10_to_str)(field_charset, + buff, + sizeof(buff), + (unsigned_val ? 10: + -10), + nr); + return store(buff, length, field_charset); +} + + /** Store double value in Field_string or Field_varstring. @@ -6816,7 +6800,8 @@ int Field_str::store(double nr) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - uint local_char_length= field_length / charset()->mbmaxlen; + uint local_char_length= MY_MIN(sizeof(buff), + field_length / field_charset->mbmaxlen); size_t length= 0; my_bool error= (local_char_length == 0); @@ -6848,17 +6833,6 @@ uint Field_str::is_equal(Create_field *new_field) } -int Field_string::store(longlong nr, bool unsigned_val) -{ - char buff[64]; - int l; - CHARSET_INFO *cs=charset(); - l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff), - unsigned_val ? 10 : -10, nr); - return Field_string::store(buff,(uint)l,cs); -} - - int Field_longstr::store_decimal(const my_decimal *d) { char buff[DECIMAL_MAX_STR_LENGTH+1]; @@ -7138,7 +7112,7 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) the master. @note For information about how the length is packed, see @c - Field_string::do_save_field_metadata + Field_string::save_field_metadata @param to Destination of the data @param from Source of the data @@ -7221,7 +7195,7 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end, @returns number of bytes written to metadata_ptr */ -int Field_string::do_save_field_metadata(uchar *metadata_ptr) +int Field_string::save_field_metadata(uchar *metadata_ptr) { DBUG_ASSERT(field_length < 1024); DBUG_ASSERT((real_type() & 0xF0) == 0xF0); @@ -7318,7 +7292,7 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; @returns number of bytes written to metadata_ptr */ -int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) +int Field_varstring::save_field_metadata(uchar *metadata_ptr) { DBUG_ASSERT(field_length <= 65535); int2store((char*)metadata_ptr, field_length); @@ -7345,20 +7319,6 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) } -int Field_varstring::store(longlong nr, bool unsigned_val) -{ - char buff[64]; - uint length; - length= (uint) (field_charset->cset->longlong10_to_str)(field_charset, - buff, - sizeof(buff), - (unsigned_val ? 10: - -10), - nr); - return Field_varstring::store(buff, length, field_charset); -} - - double Field_varstring::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -7475,26 +7435,29 @@ int Field_varstring::key_cmp(const uchar *a,const uchar *b) void Field_varstring::sort_string(uchar *to,uint length) { - uint tot_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); + String buf; + + val_str(&buf, &buf); if (field_charset == &my_charset_bin) { /* Store length last in high-byte order to sort longer strings first */ if (length_bytes == 1) - to[length-1]= tot_length; + to[length - 1]= buf.length(); else - mi_int2store(to+length-2, tot_length); + mi_int2store(to + length - 2, buf.length()); length-= length_bytes; } - - tot_length= field_charset->coll->strnxfrm(field_charset, - to, length, - char_length() * - field_charset->strxfrm_multiply, - ptr + length_bytes, tot_length, - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); - DBUG_ASSERT(tot_length == length); + +#ifndef DBUG_OFF + uint rc= +#endif + field_charset->coll->strnxfrm(field_charset, to, length, + char_length() * field_charset->strxfrm_multiply, + (const uchar*) buf.ptr(), buf.length(), + MY_STRXFRM_PAD_WITH_SPACE | + MY_STRXFRM_PAD_TO_MAXLEN); + DBUG_ASSERT(rc == length); } @@ -7510,6 +7473,11 @@ enum ha_base_keytype Field_varstring::key_type() const } +/* + Compressed columns need one extra byte to store the compression method. + This byte is invisible to the end user, but not for the storage engine. +*/ + void Field_varstring::sql_type(String &res) const { THD *thd= table->in_use; @@ -7519,7 +7487,8 @@ void Field_varstring::sql_type(String &res) const length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(), "%s(%d)", (has_charset() ? "varchar" : "varbinary"), - (int) field_length / charset()->mbmaxlen); + (int) field_length / charset()->mbmaxlen - + MY_TEST(compression_method())); res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) @@ -7621,32 +7590,36 @@ uint Field_varstring::max_packed_col_length(uint max_length) uint Field_varstring::get_key_image(uchar *buff, uint length, imagetype type_arg) { - uint f_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - uint local_char_length= length / field_charset->mbmaxlen; - uchar *pos= ptr+length_bytes; - local_char_length= my_charpos(field_charset, pos, pos + f_length, - local_char_length); - set_if_smaller(f_length, local_char_length); + String val; + uint local_char_length; + my_bitmap_map *old_map; + + old_map= dbug_tmp_use_all_columns(table, table->read_set); + val_str(&val, &val); + dbug_tmp_restore_column_map(table->read_set, old_map); + + local_char_length= val.charpos(length / field_charset->mbmaxlen); + if (local_char_length < val.length()) + val.length(local_char_length); /* Key is always stored with 2 bytes */ - int2store(buff,f_length); - memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length); - if (f_length < length) + int2store(buff, val.length()); + memcpy(buff + HA_KEY_BLOB_LENGTH, val.ptr(), val.length()); + if (val.length() < length) { /* Must clear this as we do a memcmp in opt_range.cc to detect identical keys */ - bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length)); + memset(buff + HA_KEY_BLOB_LENGTH + val.length(), 0, length - val.length()); } - return HA_KEY_BLOB_LENGTH+f_length; + return HA_KEY_BLOB_LENGTH + val.length(); } void Field_varstring::set_key_image(const uchar *buff,uint length) { length= uint2korr(buff); // Real length is here - (void) Field_varstring::store((const char*) buff+HA_KEY_BLOB_LENGTH, length, - field_charset); + (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset); } @@ -7703,13 +7676,14 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root, TABLE *new_table, uint Field_varstring::is_equal(Create_field *new_field) { if (new_field->type_handler() == type_handler() && - new_field->charset == field_charset) + new_field->charset == field_charset && + !new_field->compression_method() == !compression_method()) { - if (new_field->length == max_display_length()) + if (new_field->length == field_length) return IS_EQUAL_YES; - if (new_field->length > max_display_length() && - ((new_field->length <= 255 && max_display_length() <= 255) || - (new_field->length > 255 && max_display_length() > 255))) + if (new_field->length > field_length && + ((new_field->length <= 255 && field_length <= 255) || + (new_field->length > 255 && field_length > 255))) return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length } return IS_EQUAL_NO; @@ -7731,6 +7705,201 @@ void Field_varstring::hash(ulong *nr, ulong *nr2) } +/** + Compress field + + @param[out] to destination buffer for compressed data + @param[in,out] to_length in: size of to, out: compressed data length + @param[in] from data to compress + @param[in] length from length + @param[in] cs from character set + + In worst case (no compression performed) storage requirement is increased by + 1 byte to store header. If it exceeds field length, normal data truncation is + performed. + + Generic compressed header format (1 byte): + + Bits 1-4: method specific bits + Bits 5-8: compression method + + If compression method is 0 then header is immediately followed by + uncompressed data. + + If compression method is zlib: + + Bits 1-3: number of bytes occupied by original data length + Bits 4: true if zlib wrapper not present + Bits 5-8: store 8 (zlib) + + Header is immediately followed by original data length, + followed by compressed data. +*/ + +int Field_longstr::compress(char *to, uint *to_length, + const char *from, uint length, + CHARSET_INFO *cs) +{ + THD *thd= get_thd(); + char *buf= 0; + int rc= 0; + + if (length == 0) + { + *to_length= 0; + return 0; + } + + if (String::needs_conversion_on_storage(length, cs, field_charset) || + *to_length <= length) + { + String_copier copier; + const char *end= from + length; + + if (!(buf= (char*) my_malloc(*to_length - 1, MYF(MY_WME)))) + { + *to_length= 0; + return -1; + } + + length= copier.well_formed_copy(field_charset, buf, *to_length - 1, + cs, from, length, + (*to_length - 1) / field_charset->mbmaxlen); + rc= check_conversion_status(&copier, end, cs, true); + from= buf; + DBUG_ASSERT(length > 0); + } + + if (length >= thd->variables.column_compression_threshold && + (*to_length= compression_method()->compress(thd, to, from, length))) + status_var_increment(thd->status_var.column_compressions); + else + { + /* Store uncompressed */ + to[0]= 0; + memcpy(to + 1, from, length); + *to_length= length + 1; + } + + if (buf) + my_free(buf); + return rc; +} + + +/* + Memory is allocated only when original data was actually compressed. + Otherwise val_ptr points at data located immediately after header. + + Data can be stored uncompressed if data was shorter than threshold + or compressed data was longer than original data. +*/ + +String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, + const uchar *from, uint from_length) +{ + if (from_length) + { + uchar method= (*from & 0xF0) >> 4; + + /* Uncompressed data */ + if (!method) + { + val_ptr->set((const char*) from + 1, from_length - 1, field_charset); + return val_ptr; + } + + if (compression_methods[method].uncompress) + { + if (!compression_methods[method].uncompress(val_buffer, from, from_length, + field_length)) + { + val_buffer->set_charset(field_charset); + status_var_increment(get_thd()->status_var.column_decompressions); + return val_buffer; + } + } + } + + /* + It would be better to return 0 in case of errors, but to take the + safer route, let's return a zero string and let the general + handler catch the error. + */ + val_ptr->set("", 0, field_charset); + return val_ptr; +} + + +int Field_varstring_compressed::store(const char *from, uint length, + CHARSET_INFO *cs) +{ + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + uint to_length= MY_MIN(field_length, field_charset->mbmaxlen * length + 1); + int rc= compress((char*) get_data(), &to_length, from, length, cs); + store_length(to_length); + return rc; +} + + +String *Field_varstring_compressed::val_str(String *val_buffer, String *val_ptr) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + return uncompress(val_buffer, val_ptr, get_data(), get_length()); +} + + +double Field_varstring_compressed::val_real(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); +} + + +longlong Field_varstring_compressed::val_int(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); +} + + +int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr, + uint max_len) +{ + String a, b; + uint a_length, b_length; + + if (length_bytes == 1) + { + a_length= (uint) *a_ptr; + b_length= (uint) *b_ptr; + } + else + { + a_length= uint2korr(a_ptr); + b_length= uint2korr(b_ptr); + } + + uncompress(&a, &a, a_ptr + length_bytes, a_length); + uncompress(&b, &b, b_ptr + length_bytes, b_length); + + if (a.length() > max_len) + a.length(max_len); + if (b.length() > max_len) + b.length(max_len); + + return sortcmp(&a, &b, field_charset); +} + + /**************************************************************************** ** blob type ** A blob is saved as a length and a pointer. The length is stored in the @@ -7773,6 +7942,7 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg) const int Field_blob::copy_value(Field_blob *from) { DBUG_ASSERT(field_charset == from->charset()); + DBUG_ASSERT(!compression_method() == !from->compression_method()); int rc= 0; uint32 length= from->get_length(); uchar *data= from->get_ptr(); @@ -7880,22 +8050,6 @@ oom_error: } -int Field_blob::store(double nr) -{ - CHARSET_INFO *cs=charset(); - value.set_real(nr, NOT_FIXED_DEC, cs); - return Field_blob::store(value.ptr(),(uint) value.length(), cs); -} - - -int Field_blob::store(longlong nr, bool unsigned_val) -{ - CHARSET_INFO *cs=charset(); - value.set_int(nr, unsigned_val, cs); - return Field_blob::store(value.ptr(), (uint) value.length(), cs); -} - - double Field_blob::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -8112,9 +8266,9 @@ Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table, @returns number of bytes written to metadata_ptr */ -int Field_blob::do_save_field_metadata(uchar *metadata_ptr) +int Field_blob::save_field_metadata(uchar *metadata_ptr) { - DBUG_ENTER("Field_blob::do_save_field_metadata"); + DBUG_ENTER("Field_blob::save_field_metadata"); *metadata_ptr= pack_length_no_ptr(); DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr)); DBUG_RETURN(1); @@ -8130,33 +8284,30 @@ uint32 Field_blob::sort_length() const void Field_blob::sort_string(uchar *to,uint length) { - uchar *blob; - uint blob_length=get_length(); + String buf; - if (!blob_length && field_charset->pad_char == 0) + val_str(&buf, &buf); + if (!buf.length() && field_charset->pad_char == 0) bzero(to,length); else { if (field_charset == &my_charset_bin) { - uchar *pos; - /* Store length of blob last in blob to shorter blobs before longer blobs */ length-= packlength; - pos= to+length; - - store_bigendian(blob_length, pos, packlength); + store_bigendian(buf.length(), to + length, packlength); } - memcpy(&blob, ptr+packlength, sizeof(char*)); - - blob_length= field_charset->coll->strnxfrm(field_charset, - to, length, length, - blob, blob_length, - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); - DBUG_ASSERT(blob_length == length); + +#ifndef DBUG_OFF + uint rc= +#endif + field_charset->coll->strnxfrm(field_charset, to, length, length, + (const uchar*) buf.ptr(), buf.length(), + MY_STRXFRM_PAD_WITH_SPACE | + MY_STRXFRM_PAD_TO_MAXLEN); + DBUG_ASSERT(rc == length); } } @@ -8251,11 +8402,9 @@ const uchar *Field_blob::unpack(uchar *to, const uchar *from, DBUG_RETURN(0); // Error in data uint32 const length= get_length(from, master_packlength); DBUG_DUMP("packed", from, length + master_packlength); - bitmap_set_bit(table->write_set, field_index); if (from + master_packlength + length > from_end) DBUG_RETURN(0); - store(reinterpret_cast<const char*>(from) + master_packlength, - length, field_charset); + set_ptr(length, const_cast<uchar*> (from) + master_packlength); DBUG_DUMP("record", to, table->s->reclength); DBUG_RETURN(from + master_packlength + length); } @@ -8275,11 +8424,68 @@ uint Field_blob::max_packed_col_length(uint max_length) } +/* + Blob fields are regarded equal if they have same character set, + same blob store length and if either both are compressed or both are + uncompressed. + The logic for compression is that we don't have to uncompress and compress + again an already compressed field just because compression method changes. +*/ + uint Field_blob::is_equal(Create_field *new_field) { return new_field->type_handler() == type_handler() && new_field->charset == field_charset && - new_field->pack_length == pack_length(); + new_field->pack_length == pack_length() && + !new_field->compression_method() == !compression_method(); +} + + +int Field_blob_compressed::store(const char *from, uint length, + CHARSET_INFO *cs) +{ + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + uint to_length= MY_MIN(max_data_length(), field_charset->mbmaxlen * length + 1); + int rc; + + if (value.alloc(to_length)) + { + set_ptr((uint32) 0, NULL); + return -1; + } + + rc= compress((char*) value.ptr(), &to_length, from, length, cs); + set_ptr(to_length, (uchar*) value.ptr()); + return rc; +} + + +String *Field_blob_compressed::val_str(String *val_buffer, String *val_ptr) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + return uncompress(val_buffer, val_ptr, get_ptr(), get_length()); +} + + +double Field_blob_compressed::val_real(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); +} + + +longlong Field_blob_compressed::val_int(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); } @@ -8642,7 +8848,7 @@ longlong Field_enum::val_int(void) @returns number of bytes written to metadata_ptr */ -int Field_enum::do_save_field_metadata(uchar *metadata_ptr) +int Field_enum::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= real_type(); *(metadata_ptr + 1)= pack_length(); @@ -9361,9 +9567,9 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg) @returns number of bytes written to metadata_ptr */ -int Field_bit::do_save_field_metadata(uchar *metadata_ptr) +int Field_bit::save_field_metadata(uchar *metadata_ptr) { - DBUG_ENTER("Field_bit::do_save_field_metadata"); + DBUG_ENTER("Field_bit::save_field_metadata"); DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d", bit_len, bytes_in_rec)); /* @@ -10137,6 +10343,16 @@ Field *make_field(TABLE_SHARE *share, unireg_check, field_name, field_charset); if (field_type == MYSQL_TYPE_VARCHAR) + { + if (unireg_check == Field::TMYSQL_COMPRESSED) + return new (mem_root) + Field_varstring_compressed( + ptr, field_length, + HA_VARCHAR_PACKLENGTH(field_length), + null_pos, null_bit, + unireg_check, field_name, + share, field_charset, zlib_compression_method); + return new (mem_root) Field_varstring(ptr,field_length, HA_VARCHAR_PACKLENGTH(field_length), @@ -10144,6 +10360,7 @@ Field *make_field(TABLE_SHARE *share, unireg_check, field_name, share, field_charset); + } return 0; // Error } @@ -10165,10 +10382,18 @@ Field *make_field(TABLE_SHARE *share, } #endif if (f_is_blob(pack_flag)) + { + if (unireg_check == Field::TMYSQL_COMPRESSED) + return new (mem_root) + Field_blob_compressed(ptr, null_pos, null_bit, + unireg_check, field_name, share, + pack_length, field_charset, zlib_compression_method); + return new (mem_root) Field_blob(ptr,null_pos,null_bit, unireg_check, field_name, share, pack_length, field_charset); + } if (interval) { if (f_is_enum(pack_flag)) @@ -10347,10 +10572,25 @@ Column_definition::Column_definition(THD *thd, Field *old_field, comment= old_field->comment; decimals= old_field->decimals(); vcol_info= old_field->vcol_info; - default_value= orig_field ? orig_field->default_value : 0; - check_constraint= orig_field ? orig_field->check_constraint : 0; option_list= old_field->option_list; pack_flag= 0; + compression_method_ptr= 0; + + if (orig_field) + { + default_value= orig_field->default_value; + check_constraint= orig_field->check_constraint; + if (orig_field->unireg_check == Field::TMYSQL_COMPRESSED) + { + unireg_check= Field::TMYSQL_COMPRESSED; + compression_method_ptr= zlib_compression_method; + } + } + else + { + default_value= 0; + check_constraint= 0; + } switch (real_field_type()) { case MYSQL_TYPE_TINY_BLOB: @@ -10371,7 +10611,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field, case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: /* This is corrected in create_length_to_internal_length */ - length= (length+charset->mbmaxlen-1) / charset->mbmaxlen; + length= (length+charset->mbmaxlen-1) / charset->mbmaxlen - + MY_TEST(old_field->compression_method()); break; #ifdef HAVE_SPATIAL case MYSQL_TYPE_GEOMETRY: @@ -10535,6 +10776,29 @@ bool Column_definition::has_default_expression() (flags & BLOB_FLAG))); } + +bool Column_definition::set_compressed(const char *method) +{ + enum enum_field_types sql_type= real_field_type(); + /* We can't use f_is_blob here as pack_flag is not yet set */ + if (sql_type == MYSQL_TYPE_VARCHAR || sql_type == MYSQL_TYPE_TINY_BLOB || + sql_type == MYSQL_TYPE_BLOB || sql_type == MYSQL_TYPE_MEDIUM_BLOB || + sql_type == MYSQL_TYPE_LONG_BLOB) + { + if (!method || !strcmp(method, zlib_compression_method->name)) + { + unireg_check= Field::TMYSQL_COMPRESSED; + compression_method_ptr= zlib_compression_method; + return false; + } + my_error(ER_UNKNOWN_COMPRESSION_METHOD, MYF(0), method); + } + else + my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name.str); + return true; +} + + /** maximum possible display length for blob. diff --git a/sql/field.h b/sql/field.h index 17b84e058a8..bf115b38816 100644 --- a/sql/field.h +++ b/sql/field.h @@ -32,6 +32,7 @@ #include "sql_error.h" /* Sql_condition */ #include "compat56.h" #include "sql_type.h" /* Type_std_attributes */ +#include "field_comp.h" class Send_field; class Copy_field; @@ -712,7 +713,8 @@ public: TIMESTAMP_OLD_FIELD=18, // TIMESTAMP created before 4.1.3 TIMESTAMP_DN_FIELD=21, // TIMESTAMP DEFAULT NOW() TIMESTAMP_UN_FIELD=22, // TIMESTAMP ON UPDATE NOW() - TIMESTAMP_DNUN_FIELD=23 // TIMESTAMP DEFAULT NOW() ON UPDATE NOW() + TIMESTAMP_DNUN_FIELD=23, // TIMESTAMP DEFAULT NOW() ON UPDATE NOW() + TMYSQL_COMPRESSED= 24, // Compatibility with TMySQL }; enum geometry_type { @@ -912,8 +914,21 @@ public: DBUG_RETURN(field_metadata); } virtual uint row_pack_length() const { return 0; } + + + /** + Retrieve the field metadata for fields. + + This default implementation returns 0 and saves 0 in the first_byte value. + + @param first_byte First byte of field metadata + + @returns 0 no bytes written. + */ + virtual int save_field_metadata(uchar *first_byte) - { return do_save_field_metadata(first_byte); } + { return 0; } + /* data_length() return the "real size" of the data in memory. @@ -1510,6 +1525,8 @@ public: /* Mark field in read map. Updates also virtual fields */ void register_field_in_read_map(); + virtual Compression_method *compression_method() const { return 0; } + friend int cre_myisam(char * name, register TABLE *form, uint options, ulonglong auto_increment_value); friend class Copy_field; @@ -1538,19 +1555,6 @@ private: */ virtual size_t do_last_null_byte() const; -/** - Retrieve the field metadata for fields. - - This default implementation returns 0 and saves 0 in the metadata_ptr - value. - - @param metadata_ptr First byte of field metadata - - @returns 0 no bytes written. -*/ - virtual int do_save_field_metadata(uchar *metadata_ptr) - { return 0; } - protected: uchar *pack_int(uchar *to, const uchar *from, size_t size) { @@ -1691,7 +1695,7 @@ public: charset() == from->charset(); } int store(double nr); - int store(longlong nr, bool unsigned_val)=0; + int store(longlong nr, bool unsigned_val); int store_decimal(const my_decimal *); int store(const char *to,uint length,CHARSET_INFO *cs)=0; int store_hex_hybrid(const char *str, uint length) @@ -1739,6 +1743,11 @@ protected: const Item *item) const; bool cmp_to_string_with_stricter_collation(const Item_bool_func *cond, const Item *item) const; + int compress(char *to, uint *to_length, + const char *from, uint length, + CHARSET_INFO *cs); + String *uncompress(String *val_buffer, String *val_ptr, + const uchar *from, uint from_length); public: Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -1849,7 +1858,7 @@ public: /* New decimal/numeric field which use fixed point arithmetic */ class Field_new_decimal :public Field_num { private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); public: /* The maximum number of decimal digits can be stored */ uint precision; @@ -2171,7 +2180,7 @@ public: uint row_pack_length() const { return pack_length(); } void sql_type(String &str) const; private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); }; @@ -2228,7 +2237,7 @@ public: uint row_pack_length() const { return pack_length(); } void sql_type(String &str) const; private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); }; @@ -2515,7 +2524,7 @@ public: TIMESTAMP(0..6) - MySQL56 version */ class Field_timestampf :public Field_timestamp_with_dec { - int do_save_field_metadata(uchar *metadata_ptr) + int save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= (uchar) decimals(); return 1; @@ -2783,7 +2792,7 @@ public: */ class Field_timef :public Field_time_with_dec { void store_TIME(MYSQL_TIME *ltime); - int do_save_field_metadata(uchar *metadata_ptr) + int save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= (uchar) decimals(); return 1; @@ -2945,7 +2954,7 @@ public: class Field_datetimef :public Field_datetime_with_dec { void store_TIME(MYSQL_TIME *ltime); bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; - int do_save_field_metadata(uchar *metadata_ptr) + int save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= (uchar) decimals(); return 1; @@ -3076,8 +3085,7 @@ public: return 0; } int store(const char *to,uint length,CHARSET_INFO *charset); - int store(longlong nr, bool unsigned_val); - int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ + using Field_str::store; double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -3110,7 +3118,7 @@ public: Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); virtual uint get_key_image(uchar *buff,uint length, imagetype type); private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); }; @@ -3124,6 +3132,15 @@ public: { return length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); } +protected: + void store_length(uint32 number) + { + if (length_bytes == 1) + *ptr= (uchar) number; + else + int2store(ptr, number); + } +public: /* The maximum space available in a Field_varstring, in bytes. See length_bytes. @@ -3168,11 +3185,11 @@ public: bool memcpy_field_possible(const Field *from) const { return Field_str::memcpy_field_possible(from) && + !compression_method() == !from->compression_method() && length_bytes == ((Field_varstring*) from)->length_bytes; } int store(const char *to,uint length,CHARSET_INFO *charset); - int store(longlong nr, bool unsigned_val); - int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ + using Field_str::store; double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -3206,10 +3223,91 @@ public: void hash(ulong *nr, ulong *nr2); uint length_size() { return length_bytes; } private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); +}; + + +class Field_varstring_compressed: public Field_varstring { +public: + Field_varstring_compressed(uchar *ptr_arg, + uint32 len_arg, uint length_bytes_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const LEX_CSTRING *field_name_arg, + TABLE_SHARE *share, const DTCollation &collation, + Compression_method *compression_method_arg): + Field_varstring(ptr_arg, len_arg, length_bytes_arg, null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, + share, collation), + compression_method_ptr(compression_method_arg) { DBUG_ASSERT(len_arg > 0); } + Compression_method *compression_method() const + { return compression_method_ptr; } +private: + Compression_method *compression_method_ptr; + int store(const char *to, uint length, CHARSET_INFO *charset); + using Field_str::store; + String *val_str(String *, String *); + double val_real(void); + longlong val_int(void); + uint size_of() const { return sizeof(*this); } + enum_field_types binlog_type() const { return MYSQL_TYPE_VARCHAR_COMPRESSED; } + void sql_type(String &str) const + { + Field_varstring::sql_type(str); + str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/")); + } + uint32 max_display_length() { return field_length - 1; } + int cmp_max(const uchar *a_ptr, const uchar *b_ptr, uint max_len); + + /* + Compressed fields can't have keys as two rows may have different + compression methods or compression levels. + */ + + int key_cmp(const uchar *str, uint length) + { DBUG_ASSERT(0); return 0; } + using Field_varstring::key_cmp; }; +static inline uint8 number_storage_requirement(uint32 n) +{ + return n < 256 ? 1 : n < 65536 ? 2 : n < 16777216 ? 3 : 4; +} + + +static inline void store_bigendian(ulonglong num, uchar *to, uint bytes) +{ + switch(bytes) { + case 1: mi_int1store(to, num); break; + case 2: mi_int2store(to, num); break; + case 3: mi_int3store(to, num); break; + case 4: mi_int4store(to, num); break; + case 5: mi_int5store(to, num); break; + case 6: mi_int6store(to, num); break; + case 7: mi_int7store(to, num); break; + case 8: mi_int8store(to, num); break; + default: DBUG_ASSERT(0); + } +} + + +static inline longlong read_bigendian(const uchar *from, uint bytes) +{ + switch(bytes) { + case 1: return mi_uint1korr(from); + case 2: return mi_uint2korr(from); + case 3: return mi_uint3korr(from); + case 4: return mi_uint4korr(from); + case 5: return mi_uint5korr(from); + case 6: return mi_uint6korr(from); + case 7: return mi_uint7korr(from); + case 8: return mi_sint8korr(from); + default: DBUG_ASSERT(0); return 0; + } +} + + extern LEX_CSTRING temp_lex_str; class Field_blob :public Field_longstr { @@ -3252,13 +3350,7 @@ public: NONE, field_name_arg, collation) { flags|= BLOB_FLAG; - packlength= 4; - if (set_packlength) - { - packlength= len_arg <= 255 ? 1 : - len_arg <= 65535 ? 2 : - len_arg <= 16777215 ? 3 : 4; - } + packlength= set_packlength ? number_storage_requirement(len_arg) : 4; } Field_blob(uint32 packlength_arg) :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, &temp_lex_str, @@ -3291,7 +3383,8 @@ public: if (from->type() == MYSQL_TYPE_BIT) return do_field_int; */ - if (!(from->flags & BLOB_FLAG) || from->charset() != charset()) + if (!(from->flags & BLOB_FLAG) || from->charset() != charset() || + !from->compression_method() != !compression_method()) return do_conv_blob; if (from->pack_length() != Field_blob::pack_length()) return do_copy_blob; @@ -3308,11 +3401,11 @@ public: bool memcpy_field_possible(const Field *from) const { return Field_str::memcpy_field_possible(from) && + !compression_method() == !from->compression_method() && !table->copy_blobs; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); + int store(const char *to, uint length, CHARSET_INFO *charset); + using Field_str::store; double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -3446,7 +3539,54 @@ public: uint32 char_length() const; uint is_equal(Create_field *new_field); private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); +}; + + +class Field_blob_compressed: public Field_blob { +public: + Field_blob_compressed(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, + uint blob_pack_length, const DTCollation &collation, + Compression_method *compression_method_arg): + Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, share, blob_pack_length, collation), + compression_method_ptr(compression_method_arg) {} + Compression_method *compression_method() const + { return compression_method_ptr; } +private: + Compression_method *compression_method_ptr; + int store(const char *to, uint length, CHARSET_INFO *charset); + using Field_str::store; + String *val_str(String *, String *); + double val_real(void); + longlong val_int(void); + uint size_of() const { return sizeof(*this); } + enum_field_types binlog_type() const { return MYSQL_TYPE_BLOB_COMPRESSED; } + void sql_type(String &str) const + { + Field_blob::sql_type(str); + str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/")); + } + + /* + Compressed fields can't have keys as two rows may have different + compression methods or compression levels. + */ + + uint get_key_image(uchar *buff, uint length, imagetype type_arg) + { DBUG_ASSERT(0); return 0; } + void set_key_image(const uchar *buff, uint length) + { DBUG_ASSERT(0); } + int key_cmp(const uchar *a, const uchar *b) + { DBUG_ASSERT(0); return 0; } + int key_cmp(const uchar *str, uint length) + { DBUG_ASSERT(0); return 0; } + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit) + { DBUG_ASSERT(0); return 0; } }; @@ -3610,7 +3750,7 @@ public: const Item *item, bool is_eq_func) const; private: - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); uint is_equal(Create_field *new_field); }; @@ -3788,7 +3928,7 @@ public: private: virtual size_t do_last_null_byte() const; - int do_save_field_metadata(uchar *first_byte); + int save_field_metadata(uchar *first_byte); }; @@ -3873,6 +4013,7 @@ class Column_definition: public Sql_alloc, bool prepare_stage1_check_typelib_default(); bool prepare_stage1_convert_default(THD *, MEM_ROOT *, CHARSET_INFO *to); const Type_handler *field_type() const; // Prevent using this + Compression_method *compression_method_ptr; public: LEX_CSTRING field_name; LEX_CSTRING comment; // Comment for field @@ -3910,6 +4051,7 @@ public: Column_definition() :Type_handler_hybrid_field_type(&type_handler_null), + compression_method_ptr(0), comment(null_clex_str), on_update(NULL), length(0), decimals(0), flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE), @@ -3934,6 +4076,8 @@ public: void create_length_to_internal_length_string() { length*= charset->mbmaxlen; + if (real_field_type() == MYSQL_TYPE_VARCHAR && compression_method()) + length++; DBUG_ASSERT(length <= UINT_MAX32); key_length= (uint) length; pack_length= type_handler()->calc_pack_length((uint32) length); @@ -4066,6 +4210,11 @@ public: { *this= *def; } + bool set_compressed(const char *method); + void set_compression_method(Compression_method *compression_method_arg) + { compression_method_ptr= compression_method_arg; } + Compression_method *compression_method() const + { return compression_method_ptr; } }; diff --git a/sql/field_comp.cc b/sql/field_comp.cc new file mode 100644 index 00000000000..473d470940d --- /dev/null +++ b/sql/field_comp.cc @@ -0,0 +1,128 @@ +/* Copyright (C) 2017 MariaDB Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#include <my_global.h> +#include "sql_string.h" +#include "sql_class.h" +#include "field_comp.h" +#include <zlib.h> + + +static uint compress_zlib(THD *thd, char *to, const char *from, uint length) +{ + uint level= thd->variables.column_compression_zlib_level; + + if (level > 0) + { + z_stream stream; + int wbits= thd->variables.column_compression_zlib_wrap ? MAX_WBITS : + -MAX_WBITS; + uint strategy= thd->variables.column_compression_zlib_strategy; + /* Store only meaningful bytes of original data length. */ + uchar original_pack_length= number_storage_requirement(length); + + *to= 0x80 + original_pack_length + (wbits < 0 ? 8 : 0); + store_bigendian(length, (uchar*) to + 1, original_pack_length); + + stream.avail_in= length; + stream.next_in= (Bytef*) from; + + stream.avail_out= length - original_pack_length - 1; + stream.next_out= (Bytef*) to + original_pack_length + 1; + + stream.zalloc= 0; + stream.zfree= 0; + stream.opaque= 0; + + if (deflateInit2(&stream, level, Z_DEFLATED, wbits, 8, strategy) == Z_OK && + deflate(&stream, Z_FINISH) == Z_STREAM_END && + deflateEnd(&stream) == Z_OK) + return (uint) (stream.next_out - (Bytef*) to); + } + return 0; +} + + +static int uncompress_zlib(String *to, const uchar *from, uint from_length, + uint field_length) +{ + z_stream stream; + uchar original_pack_length; + int wbits; + + original_pack_length= *from & 0x07; + wbits= *from & 8 ? -MAX_WBITS : MAX_WBITS; + + from++; + from_length--; + + if (from_length < original_pack_length) + { + my_error(ER_ZLIB_Z_DATA_ERROR, MYF(0)); + return 1; + } + + stream.avail_out= read_bigendian(from, original_pack_length); + + if (stream.avail_out > field_length) + { + my_error(ER_ZLIB_Z_DATA_ERROR, MYF(0)); + return 1; + } + + if (to->alloc(stream.avail_out)) + return 1; + + stream.next_out= (Bytef*) to->ptr(); + + stream.avail_in= from_length - original_pack_length; + stream.next_in= (Bytef*) from + original_pack_length; + + stream.zalloc= 0; + stream.zfree= 0; + stream.opaque= 0; + + if (inflateInit2(&stream, wbits) == Z_OK && + inflate(&stream, Z_FINISH) == Z_STREAM_END && + inflateEnd(&stream) == Z_OK) + { + to->length(stream.total_out); + return 0; + } + my_error(ER_ZLIB_Z_DATA_ERROR, MYF(0)); + return 1; +} + + +Compression_method compression_methods[MAX_COMPRESSION_METHODS]= +{ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { "zlib", compress_zlib, uncompress_zlib }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 } +}; diff --git a/sql/field_comp.h b/sql/field_comp.h new file mode 100644 index 00000000000..7eb8ab1e75e --- /dev/null +++ b/sql/field_comp.h @@ -0,0 +1,33 @@ +#ifndef FIELD_COMP_H_INCLUDED +#define FIELD_COMP_H_INCLUDED +/* Copyright (C) 2017 MariaDB Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#define MAX_COMPRESSION_METHODS 16 + +struct Compression_method +{ + const char *name; + uint (*compress)(THD *thd, char *to, const char *from, uint length); + int (*uncompress)(String *to, const uchar *from, uint from_length, + uint field_length); +}; + + +extern Compression_method compression_methods[MAX_COMPRESSION_METHODS]; +#define zlib_compression_method (&compression_methods[8]) + +#endif diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 932188d56a8..a817db51569 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -25,7 +25,7 @@ gives much more speed. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_class.h" // THD #include <m_ctype.h> @@ -754,7 +754,8 @@ Field::Copy_func *Field_varstring::get_copy_func(const Field *from) const return do_field_varbinary_pre50; if (Field_varstring::real_type() != from->real_type() || Field_varstring::charset() != from->charset() || - length_bytes != ((const Field_varstring*) from)->length_bytes) + length_bytes != ((const Field_varstring*) from)->length_bytes || + !compression_method() != !from->compression_method()) return do_field_string; return length_bytes == 1 ? (from->charset()->mbmaxlen == 1 ? do_varstring1 : do_varstring1_mb) : diff --git a/sql/filesort.cc b/sql/filesort.cc index fc6453b904b..d2e167ce7bf 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -22,7 +22,7 @@ Sorts a database */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "filesort.h" #ifdef HAVE_STDDEF_H @@ -37,7 +37,6 @@ #include "bounded_queue.h" #include "filesort_utils.h" #include "sql_select.h" -#include "log_slow.h" #include "debug_sync.h" /// How to write record_ref. diff --git a/sql/filesort.h b/sql/filesort.h index 2b4f7ac2654..bd1d81f91ef 100644 --- a/sql/filesort.h +++ b/sql/filesort.h @@ -17,7 +17,7 @@ #define FILESORT_INCLUDED #include "my_base.h" /* ha_rows */ -#include "sql_list.h" /* Sql_alloc */ +#include "sql_alloc.h" #include "filesort_utils.h" class SQL_SELECT; diff --git a/sql/filesort_utils.cc b/sql/filesort_utils.cc index a0bc5ee6aa2..11be9229c1d 100644 --- a/sql/filesort_utils.cc +++ b/sql/filesort_utils.cc @@ -13,11 +13,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include "filesort_utils.h" #include "sql_const.h" #include "sql_sort.h" #include "table.h" -#include "my_sys.h" namespace { diff --git a/sql/filesort_utils.h b/sql/filesort_utils.h index d537b602edf..544cd3e0f2b 100644 --- a/sql/filesort_utils.h +++ b/sql/filesort_utils.h @@ -16,7 +16,6 @@ #ifndef FILESORT_UTILS_INCLUDED #define FILESORT_UTILS_INCLUDED -#include "my_global.h" #include "my_base.h" #include "sql_array.h" diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index ab48542add6..da70daea4a8 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -15,7 +15,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include <my_sys.h> #include <m_string.h> diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 71118ae1c9f..2aeaafc1a76 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -15,7 +15,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #ifdef HAVE_SPATIAL diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 3a3273d279b..b2bc1aee091 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -78,11 +78,9 @@ So, we can read full search-structure as 32-bit word */ #define NO_YACC_SYMBOLS -#include <my_global.h> +#include "mariadb.h" #include "mysql_version.h" #include "lex.h" -#include <stdlib.h> -#include <stdio.h> #include <string.h> #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ diff --git a/sql/gen_lex_token.cc b/sql/gen_lex_token.cc index bd2b9728177..ebd966d9301 100644 --- a/sql/gen_lex_token.cc +++ b/sql/gen_lex_token.cc @@ -14,9 +14,7 @@ along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ -#include <my_global.h> -#include <stdlib.h> -#include <stdio.h> +#include "mariadb.h" #include <string.h> /* We only need the tokens here */ diff --git a/sql/group_by_handler.cc b/sql/group_by_handler.cc index c1b5cfbe254..e75800d8986 100644 --- a/sql/group_by_handler.cc +++ b/sql/group_by_handler.cc @@ -21,6 +21,7 @@ upper level. */ +#include "mariadb.h" #include "sql_priv.h" #include "sql_select.h" diff --git a/sql/gstream.cc b/sql/gstream.cc index adb46083621..ff3604ac7a4 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -18,7 +18,7 @@ NOTE: These functions assumes that the string is end \0 terminated! */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "gstream.h" #include "m_string.h" // LEX_STRING diff --git a/sql/gstream.h b/sql/gstream.h index f10b7e9b830..b9310b716ba 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -17,8 +17,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "my_global.h" /* NULL, NullS */ -#include "my_sys.h" /* MY_ALLOW_ZERO_PTR */ +#include <my_sys.h> /* MY_ALLOW_ZERO_PTR */ #include "m_ctype.h" /* my_charset_latin1, my_charset_bin */ class Gis_read_stream diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 2076379cd61..effabc3a3c0 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -46,7 +46,7 @@ if this file. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_parse.h" // append_file_to_dir #include "create_options.h" @@ -166,12 +166,8 @@ bool Partition_share::init(uint num_parts) auto_inc_initialized= false; partition_name_hash_initialized= false; next_auto_inc_val= 0; - partitions_share_refs= new Parts_share_refs; - if (!partitions_share_refs) - DBUG_RETURN(true); - if (partitions_share_refs->init(num_parts)) + if (partitions_share_refs.init(num_parts)) { - delete partitions_share_refs; DBUG_RETURN(true); } DBUG_RETURN(false); @@ -3305,9 +3301,8 @@ bool ha_partition::set_ha_share_ref(Handler_share **ha_share_arg) DBUG_RETURN(true); if (!(part_share= get_share())) DBUG_RETURN(true); - DBUG_ASSERT(part_share->partitions_share_refs); - DBUG_ASSERT(part_share->partitions_share_refs->num_parts >= m_tot_parts); - ha_shares= part_share->partitions_share_refs->ha_shares; + DBUG_ASSERT(part_share->partitions_share_refs.num_parts >= m_tot_parts); + ha_shares= part_share->partitions_share_refs.ha_shares; for (i= 0; i < m_tot_parts; i++) { if (m_file[i]->set_ha_share_ref(&ha_shares[i])) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 42081546988..0402908c640 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -48,10 +48,8 @@ public: { uint i; for (i= 0; i < num_parts; i++) - if (ha_shares[i]) - delete ha_shares[i]; - if (ha_shares) - delete [] ha_shares; + delete ha_shares[i]; + delete[] ha_shares; } bool init(uint arg_num_parts) { @@ -86,7 +84,7 @@ public: bool partition_name_hash_initialized; HASH partition_name_hash; /** Storage for each partitions Handler_share */ - Parts_share_refs *partitions_share_refs; + Parts_share_refs partitions_share_refs; Partition_share() {} ~Partition_share() { @@ -94,8 +92,6 @@ public: mysql_mutex_destroy(&auto_inc_mutex); if (partition_name_hash_initialized) my_hash_free(&partition_name_hash); - if (partitions_share_refs) - delete partitions_share_refs; DBUG_VOID_RETURN; } bool init(uint num_parts); diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 7f2248bf3cb..e5db6781464 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -16,7 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_list.h" #include "table.h" #include "sql_sequence.h" diff --git a/sql/handler.cc b/sql/handler.cc index d072e750e09..7609ed047a0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -20,7 +20,7 @@ Handler-calling-functions */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "rpl_handler.h" @@ -1558,6 +1558,7 @@ static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) { int error= 0; + uint count= 0; Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; DBUG_ENTER("commit_one_phase_2"); if (is_real_trans) @@ -1575,6 +1576,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) } /* Should this be done only if is_real_trans is set ? */ status_var_increment(thd->status_var.ha_commit_count); + if (is_real_trans && ht != binlog_hton && ha_info->is_trx_read_write()) + ++count; ha_info_next= ha_info->next(); ha_info->reset(); /* keep it conveniently zero-filled */ } @@ -1593,6 +1596,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) { thd->has_waiter= false; thd->transaction.cleanup(); + if (count >= 2) + statistic_increment(transactions_multi_engine, LOCK_status); } DBUG_RETURN(error); @@ -2385,6 +2390,18 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, /**************************************************************************** ** General handler functions ****************************************************************************/ + + +/** + Clone a handler + + @param name name of new table instance + @param mem_root Where 'this->ref' should be allocated. It can't be + in this->table->mem_root as otherwise we will not be + able to reclaim that memory when the clone handler + object is destroyed. +*/ + handler *handler::clone(const char *name, MEM_ROOT *mem_root) { handler *new_handler= get_new_handler(table->s, mem_root, ht); @@ -2395,16 +2412,6 @@ handler *handler::clone(const char *name, MEM_ROOT *mem_root) goto err; /* - 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 - when the clone handler object is destroyed. - */ - - if (!(new_handler->ref= (uchar*) alloc_root(mem_root, - ALIGN_SIZE(ref_length)*2))) - goto err; - - /* TODO: Implement a more efficient way to have more than one index open for the same table instance. The ha_open call is not cachable for clone. @@ -2412,7 +2419,7 @@ handler *handler::clone(const char *name, MEM_ROOT *mem_root) and should be able to use the original instance of the table. */ if (new_handler->ha_open(table, name, table->db_stat, - HA_OPEN_IGNORE_IF_LOCKED)) + HA_OPEN_IGNORE_IF_LOCKED, mem_root)) goto err; return new_handler; @@ -2490,7 +2497,7 @@ PSI_table_share *handler::ha_table_share_psi() const Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set */ int handler::ha_open(TABLE *table_arg, const char *name, int mode, - uint test_if_locked) + uint test_if_locked, MEM_ROOT *mem_root) { int error; DBUG_ENTER("handler::ha_open"); @@ -2537,9 +2544,9 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, table->db_stat|=HA_READ_ONLY; (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL - /* ref is already allocated for us if we're called from handler::clone() */ - if (!ref && !(ref= (uchar*) alloc_root(&table->mem_root, - ALIGN_SIZE(ref_length)*2))) + /* Allocate ref in thd or on the table's mem_root */ + if (!(ref= (uchar*) alloc_root(mem_root ? mem_root : &table->mem_root, + ALIGN_SIZE(ref_length)*2))) { ha_close(); error=HA_ERR_OUT_OF_MEM; @@ -3325,6 +3332,10 @@ void handler::ha_release_auto_increment() @param msg Error message template to which key value should be added. @param errflag Flags for my_error() call. + + @notes + The error message is from ER_DUP_ENTRY_WITH_KEY_NAME but to keep things compatibly + with old code, the error number is ER_DUP_ENTRY */ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag) @@ -3349,7 +3360,8 @@ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag) str.length(max_length-4); str.append(STRING_WITH_LEN("...")); } - my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr_safe(), key->name); + my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr_safe(), + key->name.str); } } @@ -3584,7 +3596,7 @@ void handler::print_error(int error, myf errflag) const char *ptr= "???"; uint key_nr= get_dup_key(error); if ((int) key_nr >= 0) - ptr= table->key_info[key_nr].name; + ptr= table->key_info[key_nr].name.str; my_error(ER_DROP_INDEX_FK, errflag, ptr); DBUG_VOID_RETURN; } @@ -4660,7 +4672,7 @@ void handler::update_global_index_stats() DBUG_ASSERT(key_info->cache_name); if (!key_info->cache_name) continue; - key_length= table->s->table_cache_key.length + key_info->name_length + 1; + key_length= table->s->table_cache_key.length + key_info->name.length + 1; mysql_mutex_lock(&LOCK_global_index_stats); // Gets the global index stats, creating one if necessary. if (!(index_stats= (INDEX_STATS*) my_hash_search(&global_index_stats, @@ -5708,7 +5720,7 @@ bool handler::check_table_binlog_row_based_internal(bool binlog_row) } #endif - return (table->s->cached_row_logging_check && + return (table->s->can_do_row_logging && thd->is_current_stmt_binlog_format_row() && /* Wsrep partially enables binary logging if it have not been @@ -6568,7 +6580,7 @@ end: int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) { INDEX_STATS *index_stats; - uint key_length= table->s->table_cache_key.length + key_info->name_length + 1; + uint key_length= table->s->table_cache_key.length + key_info->name.length + 1; int res = 0; DBUG_ENTER("del_global_index_stat"); mysql_mutex_lock(&LOCK_global_index_stats); diff --git a/sql/handler.h b/sql/handler.h index 9ada2ccbe7c..f681040db39 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -25,7 +25,6 @@ #pragma interface /* gcc class implementation */ #endif -#include <my_global.h> /* For handlers */ #include "sql_const.h" #include "sql_basic_types.h" #include "mysqld.h" /* server_id */ @@ -1511,6 +1510,7 @@ struct THD_TRANS bool trans_did_wait() const { return (m_unsafe_rollback_flags & DID_WAIT) != 0; } + bool is_trx_read_write() const; void mark_trans_did_ddl() { m_unsafe_rollback_flags|= DID_DDL; } bool trans_did_ddl() const { return (m_unsafe_rollback_flags & DID_DDL) != 0; @@ -1615,6 +1615,16 @@ private: }; +inline bool THD_TRANS::is_trx_read_write() const +{ + Ha_trx_info *ha_info; + for (ha_info= ha_list; ha_info; ha_info= ha_info->next()) + if (ha_info->is_trx_read_write()) + return TRUE; + return FALSE; +} + + enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, ISO_REPEATABLE_READ, ISO_SERIALIZABLE}; @@ -2818,7 +2828,8 @@ public: } /* ha_ methods: pubilc wrappers for private virtual API */ - int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked); + int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked, + MEM_ROOT *mem_root= 0); int ha_index_init(uint idx, bool sorted) { DBUG_EXECUTE_IF("ha_index_init_fail", return HA_ERR_TABLE_DEF_CHANGED;); diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc index fc89bb83a9d..641d1a20f73 100644 --- a/sql/hash_filo.cc +++ b/sql/hash_filo.cc @@ -23,7 +23,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "hash_filo.h" diff --git a/sql/hostname.cc b/sql/hostname.cc index e8d6780d095..0e60dde893c 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -24,7 +24,7 @@ Hostnames are checked with reverse name lookup and checked that they doesn't resemble an IP address. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" // SPECIAL_NO_HOST_CACHE #include "hostname.h" diff --git a/sql/hostname.h b/sql/hostname.h index d6137b7c260..3e1669b29ed 100644 --- a/sql/hostname.h +++ b/sql/hostname.h @@ -16,7 +16,6 @@ #ifndef HOSTNAME_INCLUDED #define HOSTNAME_INCLUDED -#include "my_global.h" /* uint */ #include "my_net.h" #include "hash_filo.h" diff --git a/sql/init.cc b/sql/init.cc index 8001e60b65e..0d00e3cf846 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -21,10 +21,9 @@ Init and dummy functions for interface with unireg */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "init.h" -#include "my_sys.h" #include "mysqld.h" // abort_loop, ... #include "my_time.h" // my_init_time #include "unireg.h" // SPECIAL_SAME_DB_NAME diff --git a/sql/init.h b/sql/init.h index af2621e5e70..e8dec0c1e2e 100644 --- a/sql/init.h +++ b/sql/init.h @@ -16,8 +16,6 @@ #ifndef INIT_INCLUDED #define INIT_INCLUDED -#include "my_global.h" /* ulong */ - void unireg_init(ulong options); ATTRIBUTE_NORETURN void unireg_end(void); diff --git a/sql/item.cc b/sql/item.cc index f609bfdf082..ad17cd5811c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -19,7 +19,7 @@ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include <mysql.h> #include <m_ctype.h> @@ -1239,8 +1239,7 @@ bool Item::eq(const Item *item, bool binary_cmp) const type() can be only among basic constant types. */ return type() == item->type() && name.str && item->name.str && - name.length == item->name.length && - !my_strcasecmp(system_charset_info, name.str, item->name.str); + !lex_string_cmp(system_charset_info, &name, &item->name); } @@ -1804,7 +1803,7 @@ Item_splocal::this_item_addr(THD *thd, Item **) void Item_splocal::print(String *str, enum_query_type) { str->reserve(m_name.length+8); - str->append(m_name.str, m_name.length); + str->append(&m_name); str->append('@'); str->qs_append(m_var_idx); } @@ -1929,9 +1928,9 @@ Item_splocal_row_field::this_item_addr(THD *thd, Item **) void Item_splocal_row_field::print(String *str, enum_query_type) { str->reserve(m_name.length + m_field_name.length + 8); - str->append(m_name.str, m_name.length); + str->append(&m_name); str->append('.'); - str->append(m_field_name.str, m_field_name.length); + str->append(&m_field_name); str->append('@'); str->qs_append(m_var_idx); str->append('['); @@ -1967,13 +1966,13 @@ void Item_splocal_row_field_by_name::print(String *str, enum_query_type) // +16 should be enough for .NNN@[""] if (str->reserve(m_name.length + 2 * m_field_name.length + 16)) return; - str->qs_append(m_name.str, m_name.length); + str->qs_append(&m_name); str->qs_append('.'); - str->qs_append(m_field_name.str, m_field_name.length); + str->qs_append(&m_field_name); str->qs_append('@'); str->qs_append(m_var_idx); str->qs_append("[\"", 2); - str->qs_append(m_field_name.str, m_field_name.length); + str->qs_append(&m_field_name); str->qs_append("\"]", 2); } @@ -3202,8 +3201,8 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const (In cases where we would choose wrong we would have to generate a ER_NON_UNIQ_ERROR). */ - return (!my_strcasecmp(system_charset_info, item_field->name.str, - field_name.str) && + return (!lex_string_cmp(system_charset_info, &item_field->name, + &field_name) && (!item_field->table_name || !table_name || (!my_strcasecmp(table_alias_charset, item_field->table_name, table_name) && @@ -5146,8 +5145,8 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) /* SELECT list element with explicit alias */ if ((*(cur_group->item))->name.str && !table_name && !(*(cur_group->item))->is_autogenerated_name && - !my_strcasecmp(system_charset_info, - (*(cur_group->item))->name.str, field_name->str)) + !lex_string_cmp(system_charset_info, + &(*(cur_group->item))->name, field_name)) { ++cur_match_degree; } @@ -5162,8 +5161,8 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) DBUG_ASSERT(l_field_name->str != 0); - if (!my_strcasecmp(system_charset_info, - l_field_name->str, field_name->str)) + if (!lex_string_cmp(system_charset_info, + l_field_name, field_name)) ++cur_match_degree; else continue; @@ -8929,7 +8928,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) goto error; memcpy((void *)def_field, (void *)field_arg->field, field_arg->field->size_of()); - IF_DBUG(def_field->is_stat_field=1,); // a hack to fool ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED + IF_DBUG_ASSERT(def_field->is_stat_field=1,); // a hack to fool ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED if (def_field->default_value && def_field->default_value->flags) { uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length()); @@ -9232,8 +9231,8 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const { return item->type() == TRIGGER_FIELD_ITEM && row_version == ((Item_trigger_field *)item)->row_version && - !my_strcasecmp(system_charset_info, field_name.str, - ((Item_trigger_field *)item)->field_name.str); + !lex_string_cmp(system_charset_info, &field_name, + &((Item_trigger_field *)item)->field_name); } diff --git a/sql/item.h b/sql/item.h index a926ee9aa85..0e7db0d6575 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2266,7 +2266,7 @@ public: LEX_CSTRING m_name; public: -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS /* Routine to which this Item_splocal belongs. Used for checking if correct runtime context is used for variable handling. diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 488eb52fb77..4d03462d7c3 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -22,7 +22,7 @@ Buffers to save and compare item values */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9954c66ebc2..0d57066c2d2 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -26,7 +26,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include <m_ctype.h> #include "sql_select.h" diff --git a/sql/item_create.cc b/sql/item_create.cc index fdfa95912ac..6edeade0244 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -22,7 +22,7 @@ Functions to create an item. Used by sql_yac.yy */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there diff --git a/sql/item_func.cc b/sql/item_func.cc index fc7417411e8..28690ff2bee 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -933,6 +933,7 @@ double Item_func_hybrid_field_type::val_real_from_date_op() ltime.time_type= mysql_timestamp_type(); return TIME_to_double(<ime); } + longlong Item_func_hybrid_field_type::val_int_from_date_op() { MYSQL_TIME ltime; @@ -3722,7 +3723,9 @@ longlong Item_master_gtid_wait::val_int() timeout_us= (longlong)-1; result= rpl_global_gtid_waiting.wait_for_pos(thd, gtid_pos, timeout_us); -#endif +#else + null_value= 0; +#endif /* REPLICATION */ return result; } @@ -5047,7 +5050,7 @@ bool Item_func_set_user_var::is_null_result() void Item_func_set_user_var::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("@")); - str->append(name.str, name.length); + str->append(&name); str->append(STRING_WITH_LEN(":=")); args[0]->print_parenthesised(str, query_type, precedence()); } @@ -5057,7 +5060,7 @@ void Item_func_set_user_var::print_as_stmt(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("set @")); - str->append(name.str, name.length); + str->append(&name); str->append(STRING_WITH_LEN(":=")); args[0]->print_parenthesised(str, query_type, precedence()); } @@ -5640,7 +5643,7 @@ void Item_func_get_system_var::fix_length_and_dec() void Item_func_get_system_var::print(String *str, enum_query_type query_type) { if (name.length) - str->append(name.str, name.length); + str->append(&name); else { str->append(STRING_WITH_LEN("@@")); @@ -6174,39 +6177,41 @@ longlong Item_func_bit_xor::val_int() */ -Item *get_system_var(THD *thd, enum_var_type var_type, LEX_CSTRING name, - LEX_CSTRING component) +Item *get_system_var(THD *thd, enum_var_type var_type, + const LEX_CSTRING *name, + const LEX_CSTRING *component) { sys_var *var; - LEX_CSTRING *base_name, *component_name; + LEX_CSTRING base_name, component_name; - if (component.str) + if (component->str) { - base_name= &component; - component_name= &name; + base_name= *component; + component_name= *name; } else { - base_name= &name; - component_name= &component; // Empty string + base_name= *name; + component_name= *component; // Empty string } - if (!(var= find_sys_var(thd, base_name->str, base_name->length))) + if (!(var= find_sys_var(thd, base_name.str, base_name.length))) return 0; - if (component.str) + if (component->str) { if (!var->is_struct()) { - my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), base_name->str); + my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), base_name.str); return 0; } } thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - set_if_smaller(component_name->length, MAX_SYS_VAR_LENGTH); + set_if_smaller(component_name.length, MAX_SYS_VAR_LENGTH); - return new (thd->mem_root) Item_func_get_system_var(thd, var, var_type, component_name, - NULL, 0); + return new (thd->mem_root) Item_func_get_system_var(thd, var, var_type, + &component_name, + NULL, 0); } diff --git a/sql/item_func.h b/sql/item_func.h index 409a712a5c5..de213df0fc5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -3047,8 +3047,8 @@ public: }; -Item *get_system_var(THD *thd, enum_var_type var_type, LEX_CSTRING name, - LEX_CSTRING component); +Item *get_system_var(THD *thd, enum_var_type var_type, + const LEX_CSTRING *name, const LEX_CSTRING *component); extern bool check_reserved_words(const LEX_CSTRING *name); Item *find_date_time_item(Item **args, uint nargs, uint col); double my_double_round(double value, longlong dec, bool dec_unsigned, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 04952739e85..3047595b58c 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -26,7 +26,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there diff --git a/sql/item_inetfunc.cc b/sql/item_inetfunc.cc index 9aaa64823f7..c434953ad43 100644 --- a/sql/item_inetfunc.cc +++ b/sql/item_inetfunc.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "item_inetfunc.h" #include "my_net.h" diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 2f4c1ef8e46..f804f83f122 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -14,7 +14,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_class.h" #include "item.h" diff --git a/sql/item_row.cc b/sql/item_row.cc index fc484f560ee..8b7cc814694 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 69f8ff185b5..d9b375e7be1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -31,7 +31,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> // HAVE_* +#include "mariadb.h" // HAVE_* #include "sql_priv.h" /* @@ -4499,6 +4499,9 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg) case MYSQL_TYPE_GEOMETRY: type= DYN_COL_STRING; break; + case MYSQL_TYPE_VARCHAR_COMPRESSED: + case MYSQL_TYPE_BLOB_COMPRESSED: + DBUG_ASSERT(0); } } if (type == DYN_COL_STRING && diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 71594c0478b..84e1aae1ad5 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -29,7 +29,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there @@ -950,7 +950,7 @@ void Item_subselect::print(String *str, enum_query_type query_type) { if (query_type & QT_ITEM_SUBSELECT_ID_ONLY) { - str->append("(subquery#"); + str->append(STRING_WITH_LEN("(subquery#")); if (unit && unit->first_select()) { char buf[64]; @@ -3828,8 +3828,8 @@ int subselect_single_select_engine::exec() { /* Change the access method to full table scan */ tab->save_read_first_record= tab->read_first_record; - tab->save_read_record= tab->read_record.read_record; - tab->read_record.read_record= rr_sequential; + tab->save_read_record= tab->read_record.read_record_func; + tab->read_record.read_record_func= rr_sequential; tab->read_first_record= read_first_record_seq; tab->read_record.record= tab->table->record[0]; tab->read_record.thd= join->thd; @@ -3851,8 +3851,8 @@ int subselect_single_select_engine::exec() JOIN_TAB *tab= *ptab; tab->read_record.record= 0; tab->read_record.ref_length= 0; - tab->read_first_record= tab->save_read_first_record; - tab->read_record.read_record= tab->save_read_record; + tab->read_first_record= tab->save_read_first_record; + tab->read_record.read_record_func= tab->save_read_record; } executed= 1; if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN) && @@ -4360,7 +4360,6 @@ void subselect_union_engine::print(String *str, enum_query_type query_type) void subselect_uniquesubquery_engine::print(String *str, enum_query_type query_type) { - const char *table_name= tab->table->s->table_name.str; str->append(STRING_WITH_LEN("<primary_index_lookup>(")); tab->ref.items[0]->print(str, query_type); str->append(STRING_WITH_LEN(" in ")); @@ -4373,10 +4372,10 @@ void subselect_uniquesubquery_engine::print(String *str, str->append(STRING_WITH_LEN("<temporary table>")); } else - str->append(table_name, tab->table->s->table_name.length); + str->append(&tab->table->s->table_name); KEY *key_info= tab->table->key_info+ tab->ref.key; str->append(STRING_WITH_LEN(" on ")); - str->append(key_info->name); + str->append(&key_info->name); if (cond) { str->append(STRING_WITH_LEN(" where ")); @@ -4397,9 +4396,9 @@ void subselect_uniquesubquery_engine::print(String *str) for (uint i= 0; i < key_info->user_defined_key_parts; i++) tab->ref.items[i]->print(str); str->append(STRING_WITH_LEN(" in ")); - str->append(tab->table->s->table_name.str, tab->table->s->table_name.length); + str->append(&tab->table->s->table_name); str->append(STRING_WITH_LEN(" on ")); - str->append(key_info->name); + str->append(&key_info->name); if (cond) { str->append(STRING_WITH_LEN(" where ")); @@ -4418,7 +4417,7 @@ void subselect_indexsubquery_engine::print(String *str, str->append(tab->table->s->table_name.str, tab->table->s->table_name.length); KEY *key_info= tab->table->key_info+ tab->ref.key; str->append(STRING_WITH_LEN(" on ")); - str->append(key_info->name); + str->append(&key_info->name); if (check_null) str->append(STRING_WITH_LEN(" checking NULL")); if (cond) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0c0b5a64953..d6e42efd11c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -26,7 +26,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_select.h" #include "uniques.h" @@ -3310,7 +3310,7 @@ void Item_func_group_concat::cleanup() table= 0; if (tree) { - delete_tree(tree); + delete_tree(tree, 0); tree= 0; } if (unique_filter) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 885db3a64f1..d00120018b8 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -30,7 +30,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index a216930cad6..835a3cbfdae 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -1,6 +1,21 @@ +/* + Copyright (c) 2016,2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "mariadb.h" #include "item_windowfunc.h" -#include "my_dbug.h" -#include "my_global.h" #include "sql_select.h" // test if group changed diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index 9fe95ed6cee..64a974d55d6 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -1,7 +1,22 @@ +/* + Copyright (c) 2016,2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + #ifndef ITEM_WINDOWFUNC_INCLUDED #define ITEM_WINDOWFUNC_INCLUDED -#include "my_global.h" #include "item.h" class Window_spec; diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index ba33d103d0c..ba24ebe76c5 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" /* It is necessary to include set_var.h instead of item.h because there @@ -2622,7 +2622,7 @@ my_xpath_parse_VariableReference(MY_XPATH *xpath) { Item_splocal *splocal= new (thd->mem_root) Item_splocal(thd, &name, spv->offset, spv->sql_type(), 0); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS if (splocal) splocal->m_sp= lex->sphead; #endif diff --git a/sql/key.cc b/sql/key.cc index db44e4780c4..3ee083e560f 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -16,7 +16,7 @@ /* Functions to handle keys and fields in forms */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "key.h" // key_rec_cmp #include "field.h" // Field diff --git a/sql/key.h b/sql/key.h index 7b83d74c901..523d0b7f10b 100644 --- a/sql/key.h +++ b/sql/key.h @@ -16,8 +16,6 @@ #ifndef KEY_INCLUDED #define KEY_INCLUDED -#include "my_global.h" /* uchar */ - class Field; class String; struct TABLE; diff --git a/sql/keycaches.cc b/sql/keycaches.cc index 336f2611a7e..6de775d3f2d 100644 --- a/sql/keycaches.cc +++ b/sql/keycaches.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mariadb.h" #include "keycaches.h" /**************************************************************************** diff --git a/sql/lex.h b/sql/lex.h index 67c3bc8620d..ef03afb7a32 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -423,6 +423,7 @@ static SYMBOL symbols[] = { { "NOCACHE", SYM(NOCACHE_SYM)}, { "NOCYCLE", SYM(NOCYCLE_SYM)}, { "NO_WAIT", SYM(NO_WAIT_SYM)}, + { "NOWAIT", SYM(NOWAIT_SYM)}, { "NODEGROUP", SYM(NODEGROUP_SYM)}, { "NONE", SYM(NONE_SYM)}, { "NOT", SYM(NOT_SYM)}, diff --git a/sql/lock.cc b/sql/lock.cc index 83a0896808f..6fa68786b93 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -70,7 +70,7 @@ in case external_lock() fails. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "debug_sync.h" #include "lock.h" @@ -911,7 +911,7 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type, MDL_request schema_request; MDL_request mdl_request; - DBUG_ASSERT(ok_for_lower_case_names(db)); + DBUG_SLOW_ASSERT(ok_for_lower_case_names(db)); if (thd->locked_tables_mode) { diff --git a/sql/log.cc b/sql/log.cc index 02d83a89bef..450f677d363 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -25,7 +25,7 @@ Abort logging when we get an error in reading or writing log files */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "log.h" #include "sql_base.h" // open_log_table @@ -39,11 +39,9 @@ #include "rpl_filter.h" #include "rpl_rli.h" #include "sql_audit.h" -#include "log_slow.h" #include "mysqld.h" #include <my_dir.h> -#include <stdarg.h> #include <m_ctype.h> // For test_if_number #ifdef _WIN32 @@ -56,6 +54,8 @@ #include "sql_show.h" #include "my_pthread.h" #include "wsrep_mysqld.h" +#include "sp_rcontext.h" +#include "sp_head.h" /* max size of the log message */ #define MAX_LOG_BUFFER_SIZE 1024 @@ -2672,7 +2672,7 @@ bool MYSQL_LOG::open( mysqld_port, mysqld_unix_port #endif ); - end= strnmov(buff + len, "Time Id Command Argument\n", + end= strnmov(buff + len, "Time\t\t Id Command\tArgument\n", sizeof(buff) - len); if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) || flush_io_cache(&log_file)) @@ -2887,27 +2887,27 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host, DBUG_EXECUTE_IF("reset_log_last_time", last_time= 0;); /* Note that my_b_write() assumes it knows the length for this */ - if (event_time != last_time) - { - last_time= event_time; + if (event_time != last_time) + { + last_time= event_time; - localtime_r(&event_time, &start); + localtime_r(&event_time, &start); - time_buff_len= my_snprintf(local_time_buff, MAX_TIME_SIZE, - "%02d%02d%02d %2d:%02d:%02d\t", - start.tm_year % 100, start.tm_mon + 1, - start.tm_mday, start.tm_hour, - start.tm_min, start.tm_sec); + time_buff_len= my_snprintf(local_time_buff, MAX_TIME_SIZE, + "%02d%02d%02d %2d:%02d:%02d\t", + start.tm_year % 100, start.tm_mon + 1, + start.tm_mday, start.tm_hour, + start.tm_min, start.tm_sec); - if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len)) - goto err; - } - else - if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0) - goto err; + if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len)) + goto err; + } + else + if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0) + goto err; - /* command_type, thread_id */ - size_t length= my_snprintf(buff, 32, "%5llu ", thread_id_arg); + /* command_type, thread_id */ + size_t length= my_snprintf(buff, 32, "%6llu ", thread_id_arg); if (my_b_write(&log_file, (uchar*) buff, length)) goto err; @@ -2976,6 +2976,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, const char *sql_text, uint sql_text_len) { bool error= 0; + char llbuff[22]; DBUG_ENTER("MYSQL_QUERY_LOG::write"); mysql_mutex_lock(&LOCK_log); @@ -3018,22 +3019,39 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0); sprintf(lock_time_buff, "%.6f", ulonglong2double(lock_utime)/1000000.0); if (my_b_printf(&log_file, - "# Thread_id: %lu Schema: %s QC_hit: %s\n" \ - "# Query_time: %s Lock_time: %s Rows_sent: %lu Rows_examined: %lu\n" \ - "# Rows_affected: %lu\n", + "# Thread_id: %lu Schema: %s QC_hit: %s\n" + "# Query_time: %s Lock_time: %s Rows_sent: %lu Rows_examined: %lu\n" + "# Rows_affected: %lu Bytes_sent: %lu\n", (ulong) thd->thread_id, (thd->db ? thd->db : ""), ((thd->query_plan_flags & QPLAN_QC) ? "Yes" : "No"), query_time_buff, lock_time_buff, (ulong) thd->get_sent_row_count(), (ulong) thd->get_examined_row_count(), - thd->get_stmt_da()->is_ok() ? - (ulong) thd->get_stmt_da()->affected_rows() : - 0) == (size_t) -1) + (ulong) thd->get_affected_rows(), + (ulong) (thd->status_var.bytes_sent - thd->bytes_sent_old)) + == (size_t) -1) + tmp_errno= errno; + + if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) + && thd->tmp_tables_used && + my_b_printf(&log_file, + "# Tmp_tables: %lu Tmp_disk_tables: %lu " + "Tmp_table_sizes: %s\n", + (ulong) thd->tmp_tables_used, + (ulong) thd->tmp_tables_disk_used, + llstr(thd->tmp_tables_size, llbuff)) == (uint) -1) tmp_errno= errno; + + if (thd->spcont) + if (my_b_printf(&log_file, "# Stored_routine: %s\n", + ErrConvDQName(thd->spcont->sp).ptr()) == (uint) -1) + tmp_errno= errno; + if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) && (thd->query_plan_flags & (QPLAN_FULL_SCAN | QPLAN_FULL_JOIN | QPLAN_TMP_TABLE | - QPLAN_TMP_DISK | QPLAN_FILESORT | QPLAN_FILESORT_DISK)) && + QPLAN_TMP_DISK | QPLAN_FILESORT | QPLAN_FILESORT_DISK | + QPLAN_FILESORT_PRIORITY_QUEUE)) && my_b_printf(&log_file, "# Full_scan: %s Full_join: %s " "Tmp_table: %s Tmp_table_on_disk: %s\n" @@ -3041,8 +3059,8 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, "Priority_queue: %s\n", ((thd->query_plan_flags & QPLAN_FULL_SCAN) ? "Yes" : "No"), ((thd->query_plan_flags & QPLAN_FULL_JOIN) ? "Yes" : "No"), - ((thd->query_plan_flags & QPLAN_TMP_TABLE) ? "Yes" : "No"), - ((thd->query_plan_flags & QPLAN_TMP_DISK) ? "Yes" : "No"), + (thd->tmp_tables_used ? "Yes" : "No"), + (thd->tmp_tables_disk_used ? "Yes" : "No"), ((thd->query_plan_flags & QPLAN_FILESORT) ? "Yes" : "No"), ((thd->query_plan_flags & QPLAN_FILESORT_DISK) ? "Yes" : "No"), @@ -5433,13 +5451,14 @@ stmt_has_updated_trans_table(const THD *thd) */ bool use_trans_cache(const THD* thd, bool is_transactional) { + if (is_transactional) + return 1; binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - return - ((thd->is_current_stmt_binlog_format_row() || - thd->variables.binlog_direct_non_trans_update) ? is_transactional : - (is_transactional || !cache_mngr->trx_cache.empty())); + return ((thd->is_current_stmt_binlog_format_row() || + thd->variables.binlog_direct_non_trans_update) ? 0 : + !cache_mngr->trx_cache.empty()); } /** @@ -5870,6 +5889,8 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, local_server_id= thd->variables.server_id; seq_no= thd->variables.gtid_seq_no; + DBUG_ASSERT(local_server_id != 0); + if (thd->variables.option_bits & OPTION_GTID_BEGIN) { DBUG_PRINT("error", ("OPTION_GTID_BEGIN is set. " @@ -6358,7 +6379,6 @@ err: */ update_binlog_end_pos(offset); - signal_update(); if ((error= rotate(false, &check_purge))) check_purge= false; } @@ -6425,31 +6445,29 @@ bool slow_log_print(THD *thd, const char *query, uint query_length, } +/** + Decide if we should log the command to general log + + @retval + FALSE No logging + TRUE Ok to log +*/ + bool LOGGER::log_command(THD *thd, enum enum_server_command command) { -#ifndef NO_EMBEDDED_ACCESS_CHECKS - Security_context *sctx= thd->security_ctx; -#endif /* Log command if we have at least one log event handler enabled and want to log this king of commands */ - if (*general_log_handler_list && (what_to_log & (1L << (uint) command))) - { - if ((thd->variables.option_bits & OPTION_LOG_OFF) -#ifndef NO_EMBEDDED_ACCESS_CHECKS - && (sctx->master_access & SUPER_ACL) -#endif - ) - { - /* No logging */ - return FALSE; - } - - return TRUE; - } + if (!(*general_log_handler_list && (what_to_log & (1L << (uint) command)))) + return FALSE; - return FALSE; + /* + If LOG_SLOW_DISABLE_SLAVE is set when slave thread starts, then + OPTION_LOG_OFF is set. + Only the super user can set this bit. + */ + return !(thd->variables.option_bits & OPTION_LOG_OFF); } @@ -6459,7 +6477,7 @@ bool general_log_print(THD *thd, enum enum_server_command command, va_list args; uint error= 0; - /* Print the message to the buffer if we want to log this king of commands */ + /* Print the message to the buffer if we want to log this kind of commands */ if (! logger.log_command(thd, command)) return FALSE; @@ -7673,7 +7691,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) else { bool any_error= false; - bool all_error= true; mysql_mutex_assert_not_owner(&LOCK_prepare_ordered); mysql_mutex_assert_owner(&LOCK_log); @@ -7695,8 +7712,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) current->error_cache= NULL; any_error= true; } - else - all_error= false; first= false; } @@ -7710,8 +7725,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) if (any_error) sql_print_error("Failed to run 'after_flush' hooks"); - if (!all_error) - signal_update(); } /* @@ -8115,23 +8128,6 @@ void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd) LOCK_log is released by the caller. */ -int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd, - const struct timespec *timeout) -{ - int ret= 0; - DBUG_ENTER("wait_for_update_bin_log"); - - thd_wait_begin(thd, THD_WAIT_BINLOG); - mysql_mutex_assert_owner(&LOCK_log); - if (!timeout) - mysql_cond_wait(&update_cond, &LOCK_log); - else - ret= mysql_cond_timedwait(&update_cond, &LOCK_log, - const_cast<struct timespec *>(timeout)); - thd_wait_end(thd); - DBUG_RETURN(ret); -} - int MYSQL_BIN_LOG::wait_for_update_binlog_end_pos(THD* thd, struct timespec *timeout) { @@ -8458,7 +8454,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, time_t skr; struct tm tm_tmp; struct tm *start; - THD *thd; + THD *thd= 0; int tag_length= 0; char tag[NAME_LEN]; DBUG_ENTER("print_buffer_to_file"); @@ -8492,7 +8488,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, start->tm_hour, start->tm_min, start->tm_sec, - (unsigned long) pthread_self(), + (unsigned long) (thd ? thd->thread_id : 0), (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ? "Warning" : "Note"), tag_length, tag, diff --git a/sql/log.h b/sql/log.h index eaa63d4072d..30829bdb33c 100644 --- a/sql/log.h +++ b/sql/log.h @@ -711,7 +711,6 @@ public: void wait_for_sufficient_commits(); void binlog_trigger_immediate_group_commit(); void wait_for_update_relay_log(THD* thd); - int wait_for_update_bin_log(THD* thd, const struct timespec * timeout); void init(ulong max_size); void init_pthread_objects(); void cleanup(); @@ -1096,6 +1095,7 @@ void make_default_log_name(char **out, const char* log_ext, bool once); void binlog_reset_cache(THD *thd); extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; +extern handlerton *binlog_hton; extern LOGGER logger; extern const char *log_bin_index; diff --git a/sql/log_event.cc b/sql/log_event.cc index 177e6c2c775..21cc26905a9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -16,7 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "mysqld_error.h" @@ -319,7 +319,7 @@ public: LEX_STRING tmp_str; if (copy_event_cache_to_string_and_reinit(m_cache, &tmp_str)) exit(1); - m_ev->output_buf.append(tmp_str.str, tmp_str.length); + m_ev->output_buf.append(&tmp_str); my_free(tmp_str.str); } #else /* MySQL_SERVER */ @@ -4987,6 +4987,7 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error) return 1; switch (expected_error) { case ER_DUP_ENTRY: + case ER_DUP_ENTRY_WITH_KEY_NAME: case ER_AUTOINC_READ_FAILED: return (actual_error == ER_AUTOINC_READ_FAILED || actual_error == HA_ERR_AUTOINC_ERANGE); @@ -5023,6 +5024,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, int expected_error,actual_error= 0; Schema_specification_st db_options; uint64 sub_id= 0; + void *hton= NULL; rpl_gtid gtid; Relay_log_info const *rli= rgi->rli; Rpl_filter *rpl_filter= rli->mi->rpl_filter; @@ -5193,7 +5195,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, gtid= rgi->current_gtid; if (rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, - true, false)) + true, false, &hton)) { int errcode= thd->get_stmt_da()->sql_errno(); if (!is_parallel_retry_error(rgi, errcode)) @@ -5246,13 +5248,13 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, if (thd->slave_thread) { /* - The opt_log_slow_slave_statements variable can be changed - dynamically, so we have to set the sql_log_slow respectively. + To be compatible with previous releases, the slave thread uses the global + log_slow_disabled_statements value, wich can be changed dynamically, so we + have to set the sql_log_slow respectively. */ - thd->variables.sql_log_slow= opt_log_slow_slave_statements; + thd->variables.sql_log_slow= !MY_TEST(global_system_variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE); } - thd->enable_slow_log= thd->variables.sql_log_slow; mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, FALSE, FALSE); /* Finalize server status flags after executing a statement. */ @@ -5414,7 +5416,7 @@ compare_errors: end: if (sub_id && !thd->is_slave_error) - rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, rgi); + rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi); /* Probably we have set thd->query, thd->db, thd->catalog to point to places @@ -6005,7 +6007,7 @@ bool Format_description_log_event::write() FD_queue checksum_alg value. */ compile_time_assert(BINLOG_CHECKSUM_ALG_DESC_LEN == 1); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS data_written= 0; // to prepare for need_checksum assert #endif uint8 checksum_byte= (uint8) @@ -7898,15 +7900,17 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi) int ret; if (gl_flags & FLAG_IGN_GTIDS) { + void *hton= NULL; uint32 i; + for (i= 0; i < count; ++i) { if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i], - sub_id_list[i], - false, false))) + sub_id_list[i], + false, false, &hton))) return ret; rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i], - NULL); + hton, NULL); } } ret= Log_event::do_apply_event(rgi); @@ -8387,6 +8391,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) rpl_gtid gtid; uint64 sub_id= 0; Relay_log_info const *rli= rgi->rli; + void *hton= NULL; /* XID_EVENT works like a COMMIT statement. And it also updates the @@ -8411,7 +8416,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) gtid= rgi->current_gtid; err= rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, true, - false); + false, &hton); if (err) { int ec= thd->get_stmt_da()->sql_errno(); @@ -8444,7 +8449,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) thd->mdl_context.release_transactional_locks(); if (!res && sub_id) - rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, rgi); + rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi); /* Increment the global status commit count variable @@ -8676,7 +8681,7 @@ User_var_log_event(const char* buf, uint event_len, we keep the flags set to UNDEF_F. */ size_t bytes_read= ((val + val_len) - buf_start); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS bool old_pre_checksum_fd= description_event->is_version_before_checksum( &description_event->server_version_split); #endif @@ -12901,7 +12906,7 @@ int Rows_log_event::find_key() */ last_part= key->user_defined_key_parts - 1; DBUG_PRINT("info", ("Index %s rec_per_key[%u]= %lu", - key->name, last_part, key->rec_per_key[last_part])); + key->name.str, last_part, key->rec_per_key[last_part])); if (!(m_table->file->index_flags(i, last_part, 1) & HA_READ_NEXT)) continue; @@ -12952,13 +12957,13 @@ void issue_long_find_row_warning(Log_event_type type, if ((global_system_variables.log_warnings > 1 && !rgi->is_long_find_row_note_printed())) { - time_t now= my_time(0); - time_t stmt_ts= rgi->get_row_stmt_start_timestamp(); + ulonglong now= microsecond_interval_timer(); + ulonglong stmt_ts= rgi->get_row_stmt_start_timestamp(); DBUG_EXECUTE_IF("inject_long_find_row_note", - stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2);); + stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2*HRTIME_RESOLUTION);); - long delta= (long) (now - stmt_ts); + longlong delta= (now - stmt_ts)/HRTIME_RESOLUTION; if (delta > LONG_FIND_ROW_THRESHOLD) { @@ -13088,10 +13093,10 @@ int Rows_log_event::find_row(rpl_group_info *rgi) if (m_key_info) { DBUG_PRINT("info",("locating record using key #%u [%s] (index_read)", - m_key_nr, m_key_info->name)); + m_key_nr, m_key_info->name.str)); /* We use this to test that the correct key is used in test cases. */ DBUG_EXECUTE_IF("slave_crash_if_wrong_index", - if(0 != strcmp(m_key_info->name,"expected_key")) abort();); + if(0 != strcmp(m_key_info->name.str,"expected_key")) abort();); /* The key is active: search the table using the index */ if (!table->file->inited && @@ -13364,7 +13369,6 @@ int Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const, int error) { - /*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/ m_table->file->ha_index_or_rnd_end(); my_free(m_key); m_key= NULL; @@ -13999,43 +14003,6 @@ Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len, #endif #if defined(MYSQL_SERVER) -/* - Access to the current replication position. - - There is a dummy replacement for this in the embedded library that returns - FALSE; this is used by XtraDB to allow it to access replication stuff while - still being able to use the same plugin in both stand-alone and embedded. - - In this function it's ok to use active_mi, as this is only called for - the main replication server. -*/ -bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos, - const char **group_relay_log_name, - ulonglong *relay_log_pos) -{ -#if defined(EMBEDDED_LIBRARY) || !defined(HAVE_REPLICATION) - return FALSE; -#else - const Relay_log_info *rli= &(active_mi->rli); - if (!rli->mi->using_parallel()) - { - *log_file_name= rli->group_master_log_name; - *log_pos= rli->group_master_log_pos + - (rli->future_event_relay_log_pos - rli->group_relay_log_pos); - *group_relay_log_name= rli->group_relay_log_name; - *relay_log_pos= rli->future_event_relay_log_pos; - } - else - { - *log_file_name= ""; - *log_pos= 0; - *group_relay_log_name= ""; - *relay_log_pos= 0; - } - return TRUE; -#endif -} - /** Check if we should write event to the relay log diff --git a/sql/log_event.h b/sql/log_event.h index 428616fcb0d..c8f3241cb3d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -5206,10 +5206,6 @@ inline int Log_event_writer::write(Log_event *ev) bool slave_execute_deferred_events(THD *thd); #endif -bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos, - const char **group_relay_log_name, - ulonglong *relay_log_pos); - bool event_that_should_be_ignored(const char *buf); bool event_checksum_test(uchar *buf, ulong event_len, enum_binlog_checksum_alg alg); enum enum_binlog_checksum_alg get_checksum_alg(const char* buf, ulong len); diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 68ffa32fafe..2c079a34d56 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #ifndef MYSQL_CLIENT #include "unireg.h" diff --git a/sql/log_slow.h b/sql/log_slow.h index c52722f0cd7..069c35173b9 100644 --- a/sql/log_slow.h +++ b/sql/log_slow.h @@ -15,6 +15,9 @@ /* Defining what to log to slow log */ +#ifndef LOG_SLOW_INCLUDED +#define LOG_SLOW_INCLUDED + #define LOG_SLOW_VERBOSITY_INIT 0 #define LOG_SLOW_VERBOSITY_INNODB (1U << 0) #define LOG_SLOW_VERBOSITY_QUERY_PLAN (1U << 1) @@ -25,13 +28,26 @@ #define QPLAN_ADMIN (1U << 0) #define QPLAN_FILESORT (1U << 1) #define QPLAN_FILESORT_DISK (1U << 2) -#define QPLAN_FULL_JOIN (1U << 3) -#define QPLAN_FULL_SCAN (1U << 4) -#define QPLAN_QC (1U << 5) -#define QPLAN_QC_NO (1U << 6) -#define QPLAN_TMP_DISK (1U << 7) -#define QPLAN_TMP_TABLE (1U << 8) -#define QPLAN_FILESORT_PRIORITY_QUEUE (1U << 9) +#define QPLAN_FILESORT_PRIORITY_QUEUE (1U << 3) +#define QPLAN_FULL_JOIN (1U << 4) +#define QPLAN_FULL_SCAN (1U << 5) +#define QPLAN_NOT_USING_INDEX (1U << 6) +#define QPLAN_QC (1U << 7) +#define QPLAN_QC_NO (1U << 8) +#define QPLAN_TMP_TABLE (1U << 9) +#define QPLAN_TMP_DISK (1U << 10) /* ... */ #define QPLAN_MAX (1UL << 31) /* reserved as placeholder */ + +/* Bits for log_slow_disabled_statements */ +#define LOG_SLOW_DISABLE_ADMIN (1 << 0) +#define LOG_SLOW_DISABLE_CALL (1 << 1) +#define LOG_SLOW_DISABLE_SLAVE (1 << 2) +#define LOG_SLOW_DISABLE_SP (1 << 3) + +/* Bits for log_disabled_statements */ +#define LOG_DISABLE_SLAVE (1 << 0) +#define LOG_DISABLE_SP (1 << 1) + +#endif /* LOG_SLOW_INCLUDED */ diff --git a/sql/mariadb.h b/sql/mariadb.h new file mode 100644 index 00000000000..00cf2ed1d9c --- /dev/null +++ b/sql/mariadb.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2010, 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* + Include file that should always be included first in all file in the sql + directory. Used to ensure that some files, like my_global.h and my_config.h + are always included first. + It can also be used to speed up compilation by using precompiled headers. + + This file should include a minum set of header files used by all files + and header files that are very seldom changed. + It can also include some defines that all files should be aware of. +*/ + +#ifndef MARIADB_INCLUDED +#define MARIADB_INCLUDED +#include <my_global.h> +#endif /* MARIADB_INCLUDED */ diff --git a/sql/mdl.cc b/sql/mdl.cc index f751a8e298e..4efc8b0e361 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -14,6 +14,7 @@ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ +#include "mariadb.h" #include "sql_class.h" #include "debug_sync.h" #include "sql_array.h" @@ -2086,6 +2087,14 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) */ lock= ticket->m_lock; + if (lock_wait_timeout == 0) + { + mysql_prlock_unlock(&lock->m_rwlock); + MDL_ticket::destroy(ticket); + my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); + DBUG_RETURN(TRUE); + } + lock->m_waiting.add_ticket(ticket); /* @@ -2110,11 +2119,11 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) the parallel replication scheduler should never schedule a DDL while DML's are still running. */ - DBUG_ASSERT((mdl_request->type != MDL_INTENTION_EXCLUSIVE && - mdl_request->type != MDL_EXCLUSIVE) || - !(get_thd()->rgi_slave && - get_thd()->rgi_slave->is_parallel_exec && - lock->check_if_conflicting_replication_locks(this))); + DBUG_SLOW_ASSERT((mdl_request->type != MDL_INTENTION_EXCLUSIVE && + mdl_request->type != MDL_EXCLUSIVE) || + !(get_thd()->rgi_slave && + get_thd()->rgi_slave->is_parallel_exec && + lock->check_if_conflicting_replication_locks(this))); mysql_prlock_unlock(&lock->m_rwlock); @@ -2635,7 +2644,7 @@ void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket) void MDL_context::release_lock(MDL_ticket *ticket) { - DBUG_ASSERT(ticket->m_duration == MDL_EXPLICIT); + DBUG_SLOW_ASSERT(ticket->m_duration == MDL_EXPLICIT); release_lock(MDL_EXPLICIT, ticket); } @@ -2895,8 +2904,8 @@ bool MDL_context::has_lock(const MDL_savepoint &mdl_savepoint, void MDL_context::set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration) { - DBUG_ASSERT(mdl_ticket->m_duration == MDL_TRANSACTION && - duration != MDL_TRANSACTION); + DBUG_SLOW_ASSERT(mdl_ticket->m_duration == MDL_TRANSACTION && + duration != MDL_TRANSACTION); m_tickets[MDL_TRANSACTION].remove(mdl_ticket); m_tickets[duration].push_front(mdl_ticket); diff --git a/sql/mdl.h b/sql/mdl.h index 97216b8e7b1..f30c976ac94 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -349,7 +349,7 @@ public: NAME_LEN) - m_ptr + 1); m_hash_value= my_hash_sort(&my_charset_bin, (uchar*) m_ptr + 1, m_length - 1); - DBUG_ASSERT(mdl_namespace_arg == USER_LOCK || ok_for_lower_case_names(db)); + DBUG_SLOW_ASSERT(mdl_namespace_arg == USER_LOCK || ok_for_lower_case_names(db)); } void mdl_key_init(const MDL_key *rhs) { diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index 6535f16445b..3d3b4da11db 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -32,7 +32,7 @@ flush_io_cache(). */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_class.h" // THD #ifdef HAVE_REPLICATION diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 50918d8dcf2..c532a489684 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include "sql_parse.h" #include <my_bit.h> #include "sql_select.h" diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h index b8234998f74..56761e3623f 100644 --- a/sql/multi_range_read.h +++ b/sql/multi_range_read.h @@ -57,7 +57,7 @@ Storage engine internals - Currently DS-MRR is used by MyISAM, InnoDB/XtraDB and Maria storage engines. + Currently DS-MRR is used by MyISAM, InnoDB and Maria storage engines. Potentially it can be used with any table handler that has disk-based data storage and has better performance when reading data in rowid order. */ diff --git a/sql/my_apc.cc b/sql/my_apc.cc index b165a801ce5..c86e554e591 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -17,6 +17,7 @@ #ifndef MY_APC_STANDALONE +#include "mariadb.h" #include "sql_class.h" #endif diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index be732d4a927..6d1c746fca8 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include <time.h> diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 265b370a154..918213568fc 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -132,8 +132,8 @@ public: void sanity_check() { - DBUG_ASSERT(foo1 == test_value); - DBUG_ASSERT(foo2 == test_value); + DBUG_SLOW_ASSERT(foo1 == test_value); + DBUG_SLOW_ASSERT(foo2 == test_value); } void fix_buffer_pointer() { buf= buffer; } diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc index 390123fbba9..1d61986034a 100644 --- a/sql/my_json_writer.cc +++ b/sql/my_json_writer.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_string.h" diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc index 5960346c60e..30f2d4f6526 100644 --- a/sql/mysql_install_db.cc +++ b/sql/mysql_install_db.cc @@ -18,9 +18,8 @@ on Windows. */ #define DONT_DEFINE_VOID -#include <my_global.h> +#include "mariadb.h" #include <my_getopt.h> -#include <my_sys.h> #include <m_string.h> #include <windows.h> diff --git a/sql/mysql_upgrade_service.cc b/sql/mysql_upgrade_service.cc index 36de05e54e4..2f242bebb0d 100644 --- a/sql/mysql_upgrade_service.cc +++ b/sql/mysql_upgrade_service.cc @@ -20,8 +20,8 @@ */ #define DONT_DEFINE_VOID +#include "mariadb.h" #include <process.h> -#include <my_global.h> #include <my_getopt.h> #include <my_sys.h> #include <m_string.h> @@ -519,4 +519,4 @@ int main(int argc, char **argv) CloseHandle(logfile_handle); my_end(0); exit(0); -}
\ No newline at end of file +} diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d0993151f76..8f9a62de4c6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "sql_plugin.h" // Includes my_global.h +#include "sql_plugin.h" // Includes mariadb.h #include "sql_priv.h" #include "unireg.h" #include <signal.h> @@ -75,6 +75,7 @@ #include "wsrep_var.h" #include "wsrep_thd.h" #include "wsrep_sst.h" +#include "proxy_protocol.h" #include "sql_callback.h" #include "threadpool.h" @@ -373,6 +374,8 @@ char *my_bind_addr_str; static char *default_collation_name; char *default_storage_engine, *default_tmp_storage_engine; char *enforced_storage_engine=NULL; +char *gtid_pos_auto_engines; +plugin_ref *opt_gtid_pos_auto_plugins; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; static I_List<CONNECT> thread_cache; static bool binlog_format_used= false; @@ -393,7 +396,6 @@ my_bool disable_log_notes, opt_support_flashback= 0; static my_bool opt_abort; ulonglong log_output_options; my_bool opt_userstat_running; -my_bool opt_log_queries_not_using_indexes= 0; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; bool opt_skip_name_resolve=0; @@ -455,8 +457,6 @@ my_bool relay_log_recovery; my_bool opt_sync_frm, opt_allow_suspicious_udfs; my_bool opt_secure_auth= 0; char* opt_secure_file_priv; -my_bool opt_log_slow_admin_statements= 0; -my_bool opt_log_slow_slave_statements= 0; my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; my_bool opt_super_large_pages= 0; @@ -524,6 +524,9 @@ ulong max_connections, max_connect_errors; ulong extra_max_connections; uint max_digest_length= 0; ulong slave_retried_transactions; +ulong transactions_multi_engine; +ulong rpl_transactions_multi_engine; +ulong transactions_gtid_foreign_engine; ulonglong slave_skipped_errors; ulong feature_files_opened_with_delayed_keys= 0, feature_check_constraint= 0; ulonglong denied_connections; @@ -2159,7 +2162,7 @@ static void mysqld_exit(int exit_code) set_malloc_size_cb(NULL); if (!opt_debugging && !my_disable_leak_check) { - DBUG_ASSERT(global_status_var.global_memory_used == 0); + DBUG_SLOW_ASSERT(global_status_var.global_memory_used == 0); } cleanup_tls(); DBUG_LEAVE; @@ -2286,6 +2289,7 @@ void clean_up(bool print_message) my_free(const_cast<char*>(relay_log_index)); #endif free_list(opt_plugin_load_list_ptr); + cleanup_proxy_protocol_networks(); /* The following lines may never be executed as the main thread may have @@ -2682,6 +2686,9 @@ static void network_init(void) if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0)) unireg_abort(1); /* purecov: inspected */ + if (set_proxy_protocol_networks(my_proxy_protocol_networks)) + unireg_abort(1); + set_ports(); if (report_port == 0) @@ -3317,6 +3324,20 @@ static size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize) } #endif +#ifdef DBUG_ASSERT_AS_PRINTF +extern "C" void +mariadb_dbug_assert_failed(const char *assert_expr, const char *file, + unsigned long line) +{ + fprintf(stderr, "Warning: assertion failed: %s at %s line %lu\n", + assert_expr, file, line); + if (opt_stack_trace) + { + fprintf(stderr, "Attempting backtrace to find out the reason for the assert:\n"); + my_print_stacktrace(NULL, (ulong) my_thread_stack_size, 1); + } +} +#endif /* DBUG_ASSERT_AS_PRINT */ #if !defined(__WIN__) #ifndef SA_RESETHAND @@ -4138,7 +4159,10 @@ static int init_common_variables() #ifdef SAFEMALLOC sf_malloc_dbug_id= mariadb_dbug_id; -#endif +#endif /* SAFEMALLOC */ +#ifdef DBUG_ASSERT_AS_PRINTF + my_dbug_assert_failed= mariadb_dbug_assert_failed; +#endif /* DBUG_ASSERT_AS_PRINTF */ if (!(type_handler_data= new Type_handler_data) || type_handler_data->init()) @@ -4260,12 +4284,13 @@ static int init_common_variables() (except in the embedded server, where the default continues to be MyISAM) */ -#if defined(WITH_INNOBASE_STORAGE_ENGINE) || defined(WITH_XTRADB_STORAGE_ENGINE) +#if defined(WITH_INNOBASE_STORAGE_ENGINE) default_storage_engine= const_cast<char *>("InnoDB"); #else default_storage_engine= const_cast<char *>("MyISAM"); #endif default_tmp_storage_engine= NULL; + gtid_pos_auto_engines= const_cast<char *>(""); /* Add server status variables to the dynamic list of @@ -4957,6 +4982,34 @@ static int init_default_storage_engine_impl(const char *opt_name, return 0; } + +static int +init_gtid_pos_auto_engines(void) +{ + plugin_ref *plugins; + + /* + For the command-line option --gtid_pos_auto_engines, we allow (and ignore) + engines that are unknown. This is convenient, since it allows to set + default auto-create engines that might not be used by particular users. + The option sets a list of storage engines that will have gtid position + table auto-created for them if needed. And if the engine is not available, + then it will certainly not be needed. + */ + if (gtid_pos_auto_engines) + plugins= resolve_engine_list(NULL, gtid_pos_auto_engines, + strlen(gtid_pos_auto_engines), false, false); + else + plugins= resolve_engine_list(NULL, "", 0, false, false); + if (!plugins) + return 1; + mysql_mutex_lock(&LOCK_global_system_variables); + opt_gtid_pos_auto_plugins= plugins; + mysql_mutex_unlock(&LOCK_global_system_variables); + return 0; +} + + static int init_server_components() { DBUG_ENTER("init_server_components"); @@ -5400,6 +5453,9 @@ static int init_server_components() if (init_default_storage_engine(enforced_storage_engine, enforced_table_plugin)) unireg_abort(1); + if (init_gtid_pos_auto_engines()) + unireg_abort(1); + #ifdef USE_ARIA_FOR_TMP_TABLES if (!ha_storage_engine_is_enabled(maria_hton) && !opt_bootstrap) { @@ -6361,6 +6417,7 @@ static void bootstrap(MYSQL_FILE *file) sql_print_warning("Can't create thread to handle bootstrap (errno= %d)", error); bootstrap_error=-1; + delete thd; DBUG_VOID_RETURN; } /* Wait for thread to die */ @@ -7393,6 +7450,14 @@ struct my_option my_long_options[]= "Set up signals usable for debugging. Deprecated, use --debug-gdb instead.", &opt_debugging, &opt_debugging, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"gtid-pos-auto-engines", 0, + "List of engines for which to automatically create a " + "mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine " + "is replicated. This can be used to avoid introducing cross-engine " + "transactions, if engines are used different from that used by table " + "mysql.gtid_slave_pos", + >id_pos_auto_engines, 0, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0 }, #ifdef HAVE_LARGE_PAGE_OPTION {"super-large-pages", 0, "Enable support for super large pages.", &opt_super_large_pages, &opt_super_large_pages, 0, @@ -7790,7 +7855,7 @@ static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff) var->type= SHOW_LONGLONG; var->value= buff; - *((longlong *)buff)= any_slave_sql_running(); + *((longlong *)buff)= any_slave_sql_running(false); return 0; } @@ -8392,6 +8457,8 @@ SHOW_VAR status_vars[]= { {"Busy_time", (char*) offsetof(STATUS_VAR, busy_time), SHOW_DOUBLE_STATUS}, {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONGLONG_STATUS}, {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONGLONG_STATUS}, + {"Column_compressions", (char*) offsetof(STATUS_VAR, column_compressions), SHOW_LONG_STATUS}, + {"Column_decompressions", (char*) offsetof(STATUS_VAR, column_decompressions), SHOW_LONG_STATUS}, {"Com", (char*) com_status_vars, SHOW_ARRAY}, {"Compression", (char*) &show_net_compression, SHOW_SIMPLE_FUNC}, {"Connections", (char*) &global_thread_id, SHOW_LONG_NOFLUSH}, @@ -8565,6 +8632,9 @@ SHOW_VAR status_vars[]= { {"Threads_connected", (char*) &connection_count, SHOW_INT}, {"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH}, {"Threads_running", (char*) &thread_running, SHOW_INT}, + {"Transactions_multi_engine", (char*) &transactions_multi_engine, SHOW_LONG}, + {"Rpl_transactions_multi_engine", (char*) &rpl_transactions_multi_engine, SHOW_LONG}, + {"Transactions_gtid_foreign_engine", (char*) &transactions_gtid_foreign_engine, SHOW_LONG}, {"Update_scan", (char*) offsetof(STATUS_VAR, update_scan_count), SHOW_LONG_STATUS}, {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING @@ -8808,6 +8878,9 @@ static int mysql_init_variables(void) report_user= report_password = report_host= 0; /* TO BE DELETED */ opt_relay_logname= opt_relaylog_index_name= 0; slave_retried_transactions= 0; + transactions_multi_engine= 0; + rpl_transactions_multi_engine= 0; + transactions_gtid_foreign_engine= 0; log_bin_basename= NULL; log_bin_index= NULL; diff --git a/sql/mysqld.h b/sql/mysqld.h index aa08f77d468..15208d4e2f5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -17,8 +17,8 @@ #ifndef MYSQLD_INCLUDED #define MYSQLD_INCLUDED -#include <my_global.h> /* MYSQL_PLUGIN_IMPORT, FN_REFLEN, FN_EXTLEN */ #include "sql_basic_types.h" /* query_id_t */ +#include "sql_plugin.h" #include "sql_bitmap.h" /* Bitmap */ #include "my_decimal.h" /* my_decimal */ #include "mysql_com.h" /* SERVER_VERSION_LENGTH */ @@ -116,7 +116,6 @@ extern my_bool opt_backup_progress_log; extern my_bool opt_support_flashback; extern ulonglong log_output_options; extern ulong log_backup_output_options; -extern my_bool opt_log_queries_not_using_indexes; extern bool opt_disable_networking, opt_skip_show_db; extern bool opt_skip_name_resolve; extern bool opt_ignore_builtin_innodb; @@ -130,6 +129,9 @@ extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern ulong slave_exec_mode_options, slave_ddl_exec_mode_options; extern ulong slave_retried_transactions; +extern ulong transactions_multi_engine; +extern ulong rpl_transactions_multi_engine; +extern ulong transactions_gtid_foreign_engine; extern ulong slave_run_triggers_for_rbr; extern ulonglong slave_type_conversions_options; extern my_bool read_only, opt_readonly; @@ -140,7 +142,6 @@ extern const char *current_dbug_option; extern char* opt_secure_file_priv; extern char* opt_secure_backup_file_priv; extern size_t opt_secure_backup_file_priv_len; -extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements; extern my_bool sp_automatic_privileges, opt_noacl; extern ulong use_stat_tables; extern my_bool opt_old_style_user_limits, trust_function_creators; @@ -153,6 +154,8 @@ extern char *default_tz_name; extern Time_zone *default_tz; extern char *default_storage_engine, *default_tmp_storage_engine; extern char *enforced_storage_engine; +extern char *gtid_pos_auto_engines; +extern plugin_ref *opt_gtid_pos_auto_plugins; extern bool opt_endinfo, using_udf_functions; extern my_bool locked_in_memory; extern bool opt_using_transactions; @@ -552,6 +555,7 @@ extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[]; extern char mysql_unpacked_real_data_home[]; extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables; extern char default_logfile_name[FN_REFLEN]; +extern char *my_proxy_protocol_networks; #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index d9d35c5ed3f..fd0139c1e03 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -35,7 +35,7 @@ embedded library */ -#include <my_global.h> +#include "mariadb.h" #include <mysql.h> #include <mysql_com.h> #include <mysqld_error.h> @@ -45,12 +45,7 @@ #include <violite.h> #include <signal.h> #include "probes_mysql.h" - -#ifdef EMBEDDED_LIBRARY -#undef MYSQL_SERVER -#undef MYSQL_CLIENT -#define MYSQL_CLIENT -#endif /*EMBEDDED_LIBRARY */ +#include "proxy_protocol.h" /* to reduce the number of ifdef's in the code @@ -63,8 +58,11 @@ static void inline EXTRA_DEBUG_fprintf(...) {} #ifndef MYSQL_SERVER static int inline EXTRA_DEBUG_fflush(...) { return 0; } #endif -#endif +#endif /* EXTRA_DEBUG */ + #ifdef MYSQL_SERVER +#include <sql_class.h> +#include <sql_connect.h> #define MYSQL_SERVER_my_error my_error #else static void inline MYSQL_SERVER_my_error(...) {} @@ -118,7 +116,6 @@ extern my_bool thd_net_is_killed(); #define thd_net_is_killed() 0 #endif -#define TEST_BLOCKING 8 static my_bool net_write_buff(NET *, const uchar *, ulong); @@ -829,6 +826,70 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed, /** + Try to parse and process proxy protocol header. + + This function is called in case MySQL packet header cannot be parsed. + It checks if proxy header was sent, and that it was send from allowed remote + host, as defined by proxy-protocol-networks parameter. + + If proxy header is parsed, then THD and ACL structures and changed to indicate + the new peer address and port. + + Note, that proxy header can only be sent either when the connection is established, + or as the client reply packet to +*/ +#undef IGNORE /* for Windows */ +typedef enum { RETRY, ABORT, IGNORE} handle_proxy_header_result; +static handle_proxy_header_result handle_proxy_header(NET *net) +{ +#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) + return IGNORE; +#else + THD *thd= (THD *)net->thd; + + if (!has_proxy_protocol_header(net) || !thd || + thd->get_command() != COM_CONNECT) + return IGNORE; + + /* + Proxy information found in the first 4 bytes received so far. + Read and parse proxy header , change peer ip address and port in THD. + */ + proxy_peer_info peer_info; + + if (!thd->net.vio) + { + DBUG_ASSERT(0); + return ABORT; + } + + if (!is_proxy_protocol_allowed((sockaddr *)&(thd->net.vio->remote))) + { + /* proxy-protocol-networks variable needs to be set to allow this remote address */ + my_printf_error(ER_HOST_NOT_PRIVILEGED, "Proxy header is not accepted from %s", + MYF(0), thd->main_security_ctx.ip); + return ABORT; + } + + if (parse_proxy_protocol_header(net, &peer_info)) + { + /* Failed to parse proxy header*/ + my_printf_error(ER_UNKNOWN_ERROR, "Failed to parse proxy header", MYF(0)); + return ABORT; + } + + if (peer_info.is_local_command) + /* proxy header indicates LOCAL connection, no action necessary */ + return RETRY; + /* Change peer address in THD and ACL structures.*/ + uint host_errors; + return (handle_proxy_header_result)thd_set_peer_addr(thd, + &(peer_info.peer_addr), NULL, peer_info.port, + false, &host_errors); +#endif +} + +/** Reads one packet to net->buff + net->where_b. Long packets are handled by my_net_read(). This function reallocates the net->buff buffer if necessary. @@ -850,6 +911,9 @@ my_real_read(NET *net, size_t *complen, #ifndef NO_ALARM ALARM alarm_buff; #endif + +retry: + my_bool net_blocking=vio_is_blocking(net->vio); uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE : NET_HEADER_SIZE); @@ -1081,6 +1145,17 @@ end: packets_out_of_order: { + switch (handle_proxy_header(net)) { + case ABORT: + /* error happened, message is already written. */ + len= packet_error; + goto end; + case RETRY: + goto retry; + case IGNORE: + break; + } + DBUG_PRINT("error", ("Packets out of order (Found: %d, expected %u)", (int) net->buff[net->where_b + 3], @@ -1171,6 +1246,7 @@ my_net_read_packet_reallen(NET *net, my_bool read_from_server, ulong* reallen) len+= total_length; net->where_b = save_pos; } + net->read_pos = net->buff + net->where_b; if (len != packet_error) { diff --git a/sql/opt_index_cond_pushdown.cc b/sql/opt_index_cond_pushdown.cc index 1dde5228263..b21cbb33c64 100644 --- a/sql/opt_index_cond_pushdown.cc +++ b/sql/opt_index_cond_pushdown.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include "sql_select.h" #include "sql_test.h" diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 5d31dd1662a..404c5a1f6d3 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -108,7 +108,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "key.h" // is_key_used, key_copy, key_cmp, key_restore #include "sql_parse.h" // check_stack_overrun @@ -6273,7 +6273,7 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info, DBUG_ENTER("ror_intersect_add"); DBUG_PRINT("info", ("Current out_rows= %g", info->out_rows)); DBUG_PRINT("info", ("Adding scan on %s", - info->param->table->key_info[ror_scan->keynr].name)); + info->param->table->key_info[ror_scan->keynr].name.str)); DBUG_PRINT("info", ("is_cpk_scan: %d",is_cpk_scan)); selectivity_mult = ror_scan_selectivity(info, ror_scan); @@ -6656,7 +6656,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, total_cost += (*ror_scan_mark)->index_read_cost; records += (*ror_scan_mark)->records; DBUG_PRINT("info", ("Adding scan on %s", - param->table->key_info[(*ror_scan_mark)->keynr].name)); + param->table->key_info[(*ror_scan_mark)->keynr].name.str)); if (total_cost > read_time) DBUG_RETURN(NULL); /* F=F-covered by first(I) */ @@ -6818,7 +6818,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, read_plan->mrr_buf_size= best_buf_size; DBUG_PRINT("info", ("Returning range plan for key %s, cost %g, records %lu", - param->table->key_info[param->real_keynr[best_idx]].name, + param->table->key_info[param->real_keynr[best_idx]].name.str, read_plan->read_cost, (ulong) read_plan->records)); } } @@ -10928,7 +10928,7 @@ int read_keys_and_merge_scans(THD *thd, if (unique == NULL) { - DBUG_EXECUTE_IF("index_merge_may_not_create_a_Unique", DBUG_ABORT(); ); + DBUG_EXECUTE_IF("index_merge_may_not_create_a_Unique", DBUG_SUICIDE(); ); DBUG_EXECUTE_IF("only_one_Unique_may_be_created", DBUG_SET("+d,index_merge_may_not_create_a_Unique"); ); @@ -11042,7 +11042,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next() if (doing_pk_scan) DBUG_RETURN(pk_quick_select->get_next()); - if ((result= read_record.read_record(&read_record)) == -1) + if ((result= read_record.read_record()) == -1) { result= HA_ERR_END_OF_FILE; end_read_record(&read_record); @@ -11078,7 +11078,7 @@ int QUICK_INDEX_INTERSECT_SELECT::get_next() int result; DBUG_ENTER("QUICK_INDEX_INTERSECT_SELECT::get_next"); - if ((result= read_record.read_record(&read_record)) == -1) + if ((result= read_record.read_record()) == -1) { result= HA_ERR_END_OF_FILE; end_read_record(&read_record); @@ -11830,7 +11830,7 @@ void QUICK_SELECT_I::add_key_name(String *str, bool *first) *first= FALSE; else str->append(','); - str->append(key_info->name); + str->append(&key_info->name); } @@ -11985,7 +11985,7 @@ void QUICK_SELECT_I::add_key_and_length(String *key_names, key_names->append(','); used_lengths->append(','); } - key_names->append(key_info->name); + key_names->append(&key_info->name); length= longlong10_to_str(max_used_key_length, buf, 10) - buf; used_lengths->append(buf, length); } @@ -14628,7 +14628,7 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, uint keynr= param->real_keynr[idx]; if (tmp.length()) tmp.append(','); - tmp.append(param->table->key_info[keynr].name); + tmp.append(¶m->table->key_info[keynr].name); } } if (!tmp.length()) @@ -14654,7 +14654,7 @@ static void print_ror_scans_arr(TABLE *table, const char *msg, { if (tmp.length()) tmp.append(','); - tmp.append(table->key_info[(*start)->keynr].name); + tmp.append(&table->key_info[(*start)->keynr].name); } if (!tmp.length()) tmp.append(STRING_WITH_LEN("(empty)")); @@ -14736,7 +14736,7 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose) { /* purecov: begin inspected */ fprintf(DBUG_FILE, "%*squick range select, key %s, length: %d\n", - indent, "", head->key_info[index].name, max_used_key_length); + indent, "", head->key_info[index].name.str, max_used_key_length); if (verbose) { @@ -14840,7 +14840,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose) { fprintf(DBUG_FILE, "%*squick_group_min_max_select: index %s (%d), length: %d\n", - indent, "", index_info->name, index, max_used_key_length); + indent, "", index_info->name.str, index, max_used_key_length); if (key_infix_len > 0) { fprintf(DBUG_FILE, "%*susing key_infix with length %d:\n", diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 4024ae26b8b..5335001683c 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -26,7 +26,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_base.h" #include "sql_select.h" #include "filesort.h" @@ -432,9 +432,9 @@ referred to, we can only generate equalities that refer to the outer (or inner) tables. Note that this will disallow handling of cases like (CASE-FOR-SUBST). Currently, solution #2 is implemented. - */ +LEX_CSTRING weedout_key= {STRING_WITH_LEN("weedout_key")}; static bool subquery_types_allow_materialization(Item_in_subselect *in_subs); @@ -3872,7 +3872,7 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab) sjm_tab->read_record.copy_field= sjm->copy_field; sjm_tab->read_record.copy_field_end= sjm->copy_field + sjm->sjm_table_cols.elements; - sjm_tab->read_record.read_record= rr_sequential_and_unpack; + sjm_tab->read_record.read_record_func= rr_sequential_and_unpack; } sjm_tab->bush_children->end[-1].next_select= end_sj_materialize; @@ -4242,7 +4242,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd) keyinfo->key_length=0; keyinfo->rec_per_key=0; keyinfo->algorithm= HA_KEY_ALG_UNDEF; - keyinfo->name= (char*) "weedout_key"; + keyinfo->name= weedout_key; { key_part_info->null_bit=0; key_part_info->field= field; diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 7954becfad4..9cb19e0cc6c 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -298,7 +298,7 @@ public: pos->table= tab; // todo need ref_depend_map ? DBUG_PRINT("info", ("Produced a LooseScan plan, key %s, %s", - tab->table->key_info[best_loose_scan_key].name, + tab->table->key_info[best_loose_scan_key].name.str, best_loose_scan_start_key? "(ref access)": "(range/index access)")); } diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index ab587b8b279..6cdf0e0f26a 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -48,7 +48,7 @@ (assuming a index for column d of table t2 is defined) */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "key.h" // key_cmp_if_same #include "sql_select.h" diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc index d3d1bc97a70..1d6fb4dabfe 100644 --- a/sql/opt_table_elimination.cc +++ b/sql/opt_table_elimination.cc @@ -28,6 +28,7 @@ #pragma implementation // gcc: Class implementation #endif +#include "mariadb.h" #include "my_bit.h" #include "sql_select.h" diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 196feabb235..ebb08a23009 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -20,13 +20,12 @@ Text .frm files management routines */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "parse_file.h" #include "unireg.h" // CREATE_MODE #include "sql_table.h" // build_table_filename #include <m_ctype.h> -#include <my_sys.h> #include <my_dir.h> /* from sql_db.cc */ diff --git a/sql/parse_file.h b/sql/parse_file.h index 3f48b2072db..19c7883f8cc 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -17,9 +17,8 @@ #ifndef _PARSE_FILE_H_ #define _PARSE_FILE_H_ -#include "my_global.h" // uchar #include "sql_string.h" // LEX_STRING -#include "sql_list.h" // Sql_alloc +#include "sql_alloc.h" // Sql_alloc class THD; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 31e48a85104..a52c7873817 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -20,7 +20,7 @@ #pragma implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" // Required to get server definitions for mysql/plugin.h right #include "sql_plugin.h" diff --git a/sql/password.c b/sql/password.c index 1f0a55a10fe..47f4fd1d422 100644 --- a/sql/password.c +++ b/sql/password.c @@ -60,7 +60,7 @@ *****************************************************************************/ -#include <my_global.h> +#include "mariadb.h" #include <my_sys.h> #include <m_string.h> #include <password.h> diff --git a/sql/procedure.cc b/sql/procedure.cc index 3d36b7adfa3..e4bf589958e 100644 --- a/sql/procedure.cc +++ b/sql/procedure.cc @@ -20,7 +20,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "procedure.h" #include "sql_analyse.h" // Includes procedure diff --git a/sql/protocol.cc b/sql/protocol.cc index 33742dc01a2..dbaa8ae6a1e 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -25,7 +25,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "protocol.h" #include "sql_class.h" // THD @@ -1235,7 +1235,7 @@ bool Protocol_text::store(Field *field) char buff[MAX_FIELD_WIDTH]; String str(buff,sizeof(buff), &my_charset_bin); CHARSET_INFO *tocs= this->thd->variables.character_set_results; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS TABLE *table= field->table; my_bitmap_map *old_map= 0; if (table->file) @@ -1243,7 +1243,7 @@ bool Protocol_text::store(Field *field) #endif field->val_str(&str); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS if (old_map) dbug_tmp_restore_column_map(table->read_set, old_map); #endif diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc new file mode 100644 index 00000000000..0309cf42ddf --- /dev/null +++ b/sql/proxy_protocol.cc @@ -0,0 +1,491 @@ +/* Copyright (c) 2017, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +#include <my_global.h> +#include <mysql.h> +#include <mysql_com.h> +#include <mysqld_error.h> +#include <my_sys.h> +#include <m_string.h> +#include <my_net.h> +#include <violite.h> +#include <proxy_protocol.h> +#include <log.h> + +#define PROXY_PROTOCOL_V1_SIGNATURE "PROXY" +#define PROXY_PROTOCOL_V2_SIGNATURE "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A" +#define MAX_PROXY_HEADER_LEN 256 + +/* + Parse proxy protocol version 1 header (text) +*/ +static int parse_v1_header(char *hdr, size_t len, proxy_peer_info *peer_info) +{ + char address_family[MAX_PROXY_HEADER_LEN + 1]; + char client_address[MAX_PROXY_HEADER_LEN + 1]; + char server_address[MAX_PROXY_HEADER_LEN + 1]; + int client_port; + int server_port; + + int ret = sscanf(hdr, "PROXY %s %s %s %d %d", + address_family, client_address, server_address, + &client_port, &server_port); + + if (ret != 5) + { + if (ret >= 1 && !strcmp(address_family, "UNKNOWN")) + { + peer_info->is_local_command= true; + return 0; + } + return -1; + } + + if (client_port < 0 || client_port > 0xffff + || server_port < 0 || server_port > 0xffff) + return -1; + + if (!strcmp(address_family, "UNKNOWN")) + { + peer_info->is_local_command= true; + return 0; + } + else if (!strcmp(address_family, "TCP4")) + { + /* Initialize IPv4 peer address.*/ + peer_info->peer_addr.ss_family= AF_INET; + if (!inet_pton(AF_INET, client_address, + &((struct sockaddr_in *)(&peer_info->peer_addr))->sin_addr)) + return -1; + } + else if (!strcmp(address_family, "TCP6")) + { + /* Initialize IPv6 peer address.*/ + peer_info->peer_addr.ss_family= AF_INET6; + if (!inet_pton(AF_INET6, client_address, + &((struct sockaddr_in6 *)(&peer_info->peer_addr))->sin6_addr)) + return -1; + } + peer_info->port= client_port; + /* Check if server address is legal.*/ + char addr_bin[16]; + if (!inet_pton(peer_info->peer_addr.ss_family, + server_address, addr_bin)) + return -1; + + return 0; +} + + +/* + Parse proxy protocol V2 (binary) header +*/ +static int parse_v2_header(uchar *hdr, size_t len,proxy_peer_info *peer_info) +{ + /* V2 Signature */ + if (memcmp(hdr, PROXY_PROTOCOL_V2_SIGNATURE, 12)) + return -1; + + /* version + command */ + uint8 ver= (hdr[12] & 0xF0); + if (ver != 0x20) + return -1; /* Wrong version*/ + + uint cmd= (hdr[12] & 0xF); + + /* Address family */ + uchar fam= hdr[13]; + + if (cmd == 0) + { + /* LOCAL command*/ + peer_info->is_local_command= true; + return 0; + } + + if (cmd != 0x01) + { + /* Not PROXY COMMAND */ + return -1; + } + + struct sockaddr_in *sin= (struct sockaddr_in *)(&peer_info->peer_addr); + struct sockaddr_in6 *sin6= (struct sockaddr_in6 *)(&peer_info->peer_addr); + switch (fam) + { + case 0x11: /* TCPv4 */ + sin->sin_family= AF_INET; + memcpy(&(sin->sin_addr), hdr + 16, 4); + peer_info->port= (hdr[24] << 8) + hdr[25]; + break; + case 0x21: /* TCPv6 */ + sin6->sin6_family= AF_INET6; + memcpy(&(sin6->sin6_addr), hdr + 16, 16); + peer_info->port= (hdr[48] << 8) + hdr[49]; + break; + case 0x31: /* AF_UNIX, stream */ + peer_info->peer_addr.ss_family= AF_UNIX; + break; + default: + return -1; + } + return 0; +} + + +bool has_proxy_protocol_header(NET *net) +{ + compile_time_assert(NET_HEADER_SIZE < sizeof(PROXY_PROTOCOL_V1_SIGNATURE)); + compile_time_assert(NET_HEADER_SIZE < sizeof(PROXY_PROTOCOL_V2_SIGNATURE)); + + const uchar *preread_bytes= net->buff + net->where_b; + return !memcmp(preread_bytes, PROXY_PROTOCOL_V1_SIGNATURE, NET_HEADER_SIZE)|| + !memcmp(preread_bytes, PROXY_PROTOCOL_V2_SIGNATURE, NET_HEADER_SIZE); +} + + +/** + Try to parse proxy header. + https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt + + Whenever this function is called, client is connecting, and + we have have pre-read 4 bytes (NET_HEADER_SIZE) from the network already. + These 4 bytes did not match MySQL packet header, and (unless the client + is buggy), those bytes must be proxy header. + + @param[in] net - vio and already preread bytes from the header + @param[out] peer_info - parsed proxy header with client host and port + @return 0 in case of success, -1 if error. +*/ +int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info) +{ + uchar hdr[MAX_PROXY_HEADER_LEN]; + size_t pos= 0; + + DBUG_ASSERT(!net->compress); + const uchar *preread_bytes= net->buff + net->where_b; + bool have_v1_header= !memcmp(preread_bytes, PROXY_PROTOCOL_V1_SIGNATURE, NET_HEADER_SIZE); + bool have_v2_header= + !have_v1_header && !memcmp(preread_bytes, PROXY_PROTOCOL_V2_SIGNATURE, NET_HEADER_SIZE); + if (!have_v1_header && !have_v2_header) + { + // not a proxy protocol header + return -1; + } + memcpy(hdr, preread_bytes, NET_HEADER_SIZE); + pos= NET_HEADER_SIZE; + Vio *vio= net->vio; + memset(peer_info, 0, sizeof (*peer_info)); + + if (have_v1_header) + { + /* Read until end of header (newline character)*/ + while(pos < sizeof(hdr)) + { + long len= (long)vio_read(vio, hdr + pos, 1); + if (len < 0) + return -1; + pos++; + if (hdr[pos-1] == '\n') + break; + } + hdr[pos]= 0; + + if (parse_v1_header((char *)hdr, pos, peer_info)) + return -1; + } + else // if (have_v2_header) + { +#define PROXY_V2_HEADER_LEN 16 + /* read off 16 bytes of the header.*/ + long len= vio_read(vio, hdr + pos, PROXY_V2_HEADER_LEN - pos); + if (len < 0) + return -1; + // 2 last bytes are the length in network byte order of the part following header + ushort trail_len= ((ushort)hdr[PROXY_V2_HEADER_LEN-2] >> 8) + hdr[PROXY_V2_HEADER_LEN-1]; + if (trail_len > sizeof(hdr) - PROXY_V2_HEADER_LEN) + return -1; + len= vio_read(vio, hdr + PROXY_V2_HEADER_LEN, trail_len); + pos= PROXY_V2_HEADER_LEN + trail_len; + if (parse_v2_header(hdr, pos, peer_info)) + return -1; + } + + if (peer_info->peer_addr.ss_family == AF_INET6) + { + /* + Normalize IPv4 compatible or mapped IPv6 addresses. + They will be treated as IPv4. + */ + sockaddr_storage tmp; + int dst_len; + memset(&tmp, 0, sizeof(tmp)); + vio_get_normalized_ip((const struct sockaddr *)&peer_info->peer_addr, + sizeof(sockaddr_storage), (struct sockaddr *)&tmp, &dst_len); + memcpy(&peer_info->peer_addr, &tmp, (size_t)dst_len); + } + return 0; +} + + +/** + CIDR address matching etc (for the proxy_protocol_networks parameter) +*/ + +/** + Subnetwork address in CIDR format, e.g + 192.168.1.0/24 or 2001:db8::/32 +*/ +struct subnet +{ + char addr[16]; /* Binary representation of the address, big endian*/ + unsigned short family; /* Address family, AF_INET or AF_INET6 */ + unsigned short bits; /* subnetwork size */ +}; + +static subnet* proxy_protocol_subnets; +size_t proxy_protocol_subnet_count; + +#define MAX_MASK_BITS(family) (family == AF_INET ? 32 : 128) + + +/** Convert IPv4 that are compat or mapped IPv4 to "normal" IPv4 */ +static int normalize_subnet(struct subnet *subnet) +{ + unsigned char *addr= (unsigned char*)subnet->addr; + if (subnet->family == AF_INET6) + { + const struct in6_addr *src_ip6=(in6_addr *)addr; + if (IN6_IS_ADDR_V4MAPPED(src_ip6) || IN6_IS_ADDR_V4COMPAT(src_ip6)) + { + /* Copy the actual IPv4 address (4 last bytes) */ + if (subnet->bits < 96) + return -1; + subnet->family= AF_INET; + memcpy(addr, addr+12, 4); + subnet->bits -= 96; + } + } + return 0; +} + +/** + Convert string representation of a subnet to subnet struct. +*/ +static int parse_subnet(char *addr_str, struct subnet *subnet) +{ + if (strchr(addr_str, ':')) + subnet->family= AF_INET6; + else if (strchr(addr_str, '.')) + subnet->family= AF_INET; + else if (!strcmp(addr_str, "localhost")) + { + subnet->family= AF_UNIX; + subnet->bits= 0; + return 0; + } + + char *pmask= strchr(addr_str, '/'); + if (!pmask) + { + subnet->bits= MAX_MASK_BITS(subnet->family); + } + else + { + *pmask= 0; + pmask++; + int b= 0; + + do + { + if (*pmask < '0' || *pmask > '9') + return -1; + b= 10 * b + *pmask - '0'; + if (b > MAX_MASK_BITS(subnet->family)) + return -1; + pmask++; + } + while (*pmask); + + subnet->bits= (unsigned short)b; + } + + if (!inet_pton(subnet->family, addr_str, subnet->addr)) + return -1; + + if (normalize_subnet(subnet)) + return -1; + + return 0; +} + +/** + Parse comma separated string subnet list into subnets array, + which is stored in 'proxy_protocol_subnets' variable + + @param[in] subnets_str : networks in CIDR format, + separated by comma and/or space + + @return 0 if success, otherwise -1 +*/ +int set_proxy_protocol_networks(const char *subnets_str) +{ + if (!subnets_str || !*subnets_str) + return 0; + + size_t max_subnets= MY_MAX(3,strlen(subnets_str)/2); + proxy_protocol_subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL); + + /* Check for special case '*'. */ + if (strcmp(subnets_str, "*") == 0) + { + + proxy_protocol_subnets[0].family= AF_INET; + proxy_protocol_subnets[1].family= AF_INET6; + proxy_protocol_subnets[2].family= AF_UNIX; + proxy_protocol_subnet_count= 3; + return 0; + } + + char token[256]; + const char *p= subnets_str; + for(proxy_protocol_subnet_count= 0;; proxy_protocol_subnet_count++) + { + while(*p && (*p ==',' || *p == ' ')) + p++; + if (!*p) + break; + + size_t cnt= 0; + while(*p && *p != ',' && *p != ' ' && cnt < sizeof(token)-1) + token[cnt++]= *p++; + + token[cnt++]=0; + if (cnt == sizeof(token)) + return -1; + + if (parse_subnet(token, &proxy_protocol_subnets[proxy_protocol_subnet_count])) + { + sql_print_error("Error parsing proxy_protocol_networks parameter, near '%s'",token); + return -1; + } + } + return 0; +} + +/** + Compare memory areas, in memcmp().similar fashion. + The difference to memcmp() is that size parameter is the + bit count, not byte count. +*/ +static int compare_bits(const void *s1, const void *s2, int bit_count) +{ + int result= 0; + int byte_count= bit_count / 8; + if (byte_count && (result= memcmp(s1, s2, byte_count))) + return result; + int rem= byte_count % 8; + if (rem) + { + // compare remaining bits i.e partial bytes. + unsigned char s1_bits= (((char *)s1)[byte_count]) >> (8 - rem); + unsigned char s2_bits= (((char *)s2)[byte_count]) >> (8 - rem); + if (s1_bits > s2_bits) + return 1; + if (s1_bits < s2_bits) + return -1; + } + return 0; +} + +/** + Check whether networks address matches network. +*/ +bool addr_matches_subnet(const sockaddr *sock_addr, const subnet *subnet) +{ + DBUG_ASSERT(subnet->family == AF_UNIX || + subnet->family == AF_INET || + subnet->family == AF_INET6); + + if (sock_addr->sa_family != subnet->family) + return false; + + if (subnet->family == AF_UNIX) + return true; + + void *addr= (subnet->family == AF_INET) ? + (void *)&((struct sockaddr_in *)sock_addr)->sin_addr : + (void *)&((struct sockaddr_in6 *)sock_addr)->sin6_addr; + + return (compare_bits(subnet->addr, addr, subnet->bits) == 0); +} + + +/** + Check whether proxy header from client is allowed, as per + specification in 'proxy_protocol_networks' server variable. + + The non-TCP "localhost" clients (unix socket, shared memory, pipes) + are accepted whenever 127.0.0.1 accepted in 'proxy_protocol_networks' +*/ +bool is_proxy_protocol_allowed(const sockaddr *addr) +{ + if (proxy_protocol_subnet_count == 0) + return false; + + sockaddr_storage addr_storage; + struct sockaddr *normalized_addr= (struct sockaddr *)&addr_storage; + + /* + Non-TCP addresses (unix domain socket, windows pipe and shared memory + gets tranlated to TCP4 localhost address. + + Note, that vio remote addresses are initialized with binary zeros + for these protocols (which is AF_UNSPEC everywhere). + */ + switch(addr->sa_family) + { + case AF_UNSPEC: + case AF_UNIX: + normalized_addr->sa_family= AF_UNIX; + break; + case AF_INET: + case AF_INET6: + { + int len= + (addr->sa_family == AF_INET)?sizeof(sockaddr_in):sizeof (sockaddr_in6); + int dst_len; + vio_get_normalized_ip(addr, len,normalized_addr, &dst_len); + } + break; + default: + DBUG_ASSERT(0); + } + + for (size_t i= 0; i < proxy_protocol_subnet_count; i++) + if (addr_matches_subnet(normalized_addr, &proxy_protocol_subnets[i])) + return true; + + return false; +} + + +void cleanup_proxy_protocol_networks() +{ + my_free(proxy_protocol_subnets); + proxy_protocol_subnets= 0; + proxy_protocol_subnet_count= 0; +} + diff --git a/sql/proxy_protocol.h b/sql/proxy_protocol.h new file mode 100644 index 00000000000..6f9bcf73307 --- /dev/null +++ b/sql/proxy_protocol.h @@ -0,0 +1,15 @@ +#include "my_net.h" + +struct proxy_peer_info +{ + struct sockaddr_storage peer_addr; + int port; + bool is_local_command; +}; + +extern bool has_proxy_protocol_header(NET *net); +extern int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info); +extern bool is_proxy_protocol_allowed(const sockaddr *remote_addr); + +extern int set_proxy_protocol_networks(const char *spec); +extern void cleanup_proxy_protocol_networks(); diff --git a/sql/records.cc b/sql/records.cc index f16bdcff6e6..650a51f7f37 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -26,7 +26,7 @@ Functions for easy reading of records, possible through a cache */ -#include <my_global.h> +#include "mariadb.h" #include "records.h" #include "sql_priv.h" #include "records.h" @@ -89,8 +89,8 @@ bool init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, table->file->print_error(error, MYF(0)); } - /* read_record will be changed to rr_index in rr_index_first */ - info->read_record= reverse ? rr_index_last : rr_index_first; + /* read_record_func will be changed to rr_index in rr_index_first */ + info->read_record_func= reverse ? rr_index_last : rr_index_first; DBUG_RETURN(error != 0); } @@ -229,8 +229,8 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, if (tempfile && !(select && select->quick)) { DBUG_PRINT("info",("using rr_from_tempfile")); - info->read_record= (addon_field ? - rr_unpack_from_tempfile : rr_from_tempfile); + info->read_record_func= + addon_field ? rr_unpack_from_tempfile : rr_from_tempfile; info->io_cache= tempfile; reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0); info->ref_pos=table->file->ref; @@ -260,14 +260,14 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, if (! init_rr_cache(thd, info)) { DBUG_PRINT("info",("using rr_from_cache")); - info->read_record=rr_from_cache; + info->read_record_func= rr_from_cache; } } } else if (select && select->quick) { DBUG_PRINT("info",("using rr_quick")); - info->read_record=rr_quick; + info->read_record_func= rr_quick; } else if (filesort && filesort->record_pointers) { @@ -277,13 +277,13 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, info->cache_pos= filesort->record_pointers; info->cache_end= (info->cache_pos+ filesort->return_rows * info->ref_length); - info->read_record= (addon_field ? - rr_unpack_from_buffer : rr_from_pointers); + info->read_record_func= + addon_field ? rr_unpack_from_buffer : rr_from_pointers; } else if (table->file->keyread_enabled()) { int error; - info->read_record= rr_index_first; + info->read_record_func= rr_index_first; if (!table->file->inited && (error= table->file->ha_index_init(table->file->keyread, 1))) { @@ -295,7 +295,7 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, else { DBUG_PRINT("info",("using rr_sequential")); - info->read_record=rr_sequential; + info->read_record_func= rr_sequential; 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 */ @@ -331,7 +331,7 @@ void end_read_record(READ_RECORD *info) { if (info->table->is_created()) (void) info->table->file->extra(HA_EXTRA_NO_CACHE); - if (info->read_record != rr_quick) // otherwise quick_range does it + if (info->read_record_func != rr_quick) // otherwise quick_range does it (void) info->table->file->ha_index_or_rnd_end(); info->table=0; } @@ -399,7 +399,7 @@ static int rr_index_first(READ_RECORD *info) } tmp= info->table->file->ha_index_first(info->record); - info->read_record= rr_index; + info->read_record_func= rr_index; if (tmp) tmp= rr_handle_error(info, tmp); return tmp; @@ -422,7 +422,7 @@ static int rr_index_first(READ_RECORD *info) static int rr_index_last(READ_RECORD *info) { int tmp= info->table->file->ha_index_last(info->record); - info->read_record= rr_index_desc; + info->read_record_func= rr_index_desc; if (tmp) tmp= rr_handle_error(info, tmp); return tmp; diff --git a/sql/records.h b/sql/records.h index 473cb610be5..940c88ca0c7 100644 --- a/sql/records.h +++ b/sql/records.h @@ -55,7 +55,7 @@ struct READ_RECORD //handler *file; TABLE **forms; /* head and ref forms */ Unlock_row_func unlock_row; - Read_func read_record; + Read_func read_record_func; THD *thd; SQL_SELECT *select; uint cache_records; @@ -70,6 +70,8 @@ struct READ_RECORD bool print_error, ignore_not_found_rows; void (*unpack)(struct st_sort_addon_field *, uchar *, uchar *); + int read_record() { return read_record_func(this); } + /* SJ-Materialization runtime may need to read fields from the materialized table and unpack them into original table fields: diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 4cf7df5227f..20290e8bad8 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -24,7 +24,7 @@ functions like register_slave()) are working. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_parse.h" // check_access #ifdef HAVE_REPLICATION diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h index 2cc031a462d..c3584fb17f2 100644 --- a/sql/repl_failsafe.h +++ b/sql/repl_failsafe.h @@ -19,7 +19,7 @@ #ifdef HAVE_REPLICATION #include "mysql.h" -#include "my_sys.h" +#include <my_sys.h> #include "slave.h" typedef enum {RPL_AUTH_MASTER=0,RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE, diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index 0ab4c62235f..d09b7aee31c 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "mysqld.h" // system_charset_info #include "rpl_filter.h" diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index c385434e41e..d58a2ea4d3e 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -16,16 +16,16 @@ /* Definitions for MariaDB global transaction ID (GTID). */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" -#include "my_sys.h" #include "unireg.h" -#include "my_global.h" +#include "mariadb.h" #include "sql_base.h" #include "sql_parse.h" #include "key.h" #include "rpl_gtid.h" #include "rpl_rli.h" +#include "slave.h" const LEX_STRING rpl_gtid_slave_state_table_name= @@ -33,7 +33,7 @@ const LEX_STRING rpl_gtid_slave_state_table_name= void -rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid, +rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid, void *hton, rpl_group_info *rgi) { int err; @@ -45,7 +45,7 @@ rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid, it is even committed. */ mysql_mutex_lock(&LOCK_slave_state); - err= update(gtid->domain_id, gtid->server_id, sub_id, gtid->seq_no, rgi); + err= update(gtid->domain_id, gtid->server_id, sub_id, gtid->seq_no, hton, rgi); mysql_mutex_unlock(&LOCK_slave_state); if (err) { @@ -74,12 +74,14 @@ rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi) if (rgi->gtid_pending) { uint64 sub_id= rgi->gtid_sub_id; + void *hton= NULL; + rgi->gtid_pending= false; if (rgi->gtid_ignore_duplicate_state!=rpl_group_info::GTID_DUPLICATE_IGNORE) { - if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false)) + if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false, &hton)) DBUG_RETURN(1); - update_state_hash(sub_id, &rgi->current_gtid, rgi); + update_state_hash(sub_id, &rgi->current_gtid, hton, rgi); } rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL; } @@ -243,7 +245,7 @@ rpl_slave_state_free_element(void *arg) rpl_slave_state::rpl_slave_state() - : last_sub_id(0), loaded(false) + : last_sub_id(0), gtid_pos_tables(0), loaded(false) { mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state, MY_MUTEX_INIT_SLOW); @@ -255,6 +257,7 @@ rpl_slave_state::rpl_slave_state() rpl_slave_state::~rpl_slave_state() { + free_gtid_pos_tables((struct gtid_pos_table *)gtid_pos_tables); truncate_hash(); my_hash_free(&hash); delete_dynamic(>id_sort_array); @@ -286,11 +289,12 @@ rpl_slave_state::truncate_hash() int rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id, - uint64 seq_no, rpl_group_info *rgi) + uint64 seq_no, void *hton, rpl_group_info *rgi) { element *elem= NULL; list_element *list_elem= NULL; + DBUG_ASSERT(hton || !loaded); if (!(elem= get_element(domain_id))) return 1; @@ -313,7 +317,7 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id, { if (rgi->gtid_ignore_duplicate_state==rpl_group_info::GTID_DUPLICATE_OWNER) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS Relay_log_info *rli= rgi->rli; #endif uint32 count= elem->owner_count; @@ -335,6 +339,7 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id, list_elem->server_id= server_id; list_elem->sub_id= sub_id; list_elem->seq_no= seq_no; + list_elem->hton= hton; elem->add(list_elem); if (last_sub_id < sub_id) @@ -466,6 +471,94 @@ gtid_check_rpl_slave_state_table(TABLE *table) /* + Attempt to find a mysql.gtid_slave_posXXX table that has a storage engine + that is already in use by the current transaction, if any. +*/ +void +rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename) +{ + struct gtid_pos_table *list, *table_entry, *default_entry; + + /* + See comments on rpl_slave_state::gtid_pos_tables for rules around proper + access to the list. + */ + list= (struct gtid_pos_table *) + my_atomic_loadptr_explicit(>id_pos_tables, MY_MEMORY_ORDER_ACQUIRE); + + Ha_trx_info *ha_info; + uint count = 0; + for (ha_info= thd->transaction.all.ha_list; ha_info; ha_info= ha_info->next()) + { + void *trx_hton= ha_info->ht(); + table_entry= list; + + if (!ha_info->is_trx_read_write() || trx_hton == binlog_hton) + continue; + while (table_entry) + { + if (table_entry->table_hton == trx_hton) + { + if (likely(table_entry->state == GTID_POS_AVAILABLE)) + { + *out_tablename= table_entry->table_name; + /* + Check if this is a cross-engine transaction, so we can correctly + maintain the rpl_transactions_multi_engine status variable. + */ + if (count >= 1) + statistic_increment(rpl_transactions_multi_engine, LOCK_status); + else + { + for (;;) + { + ha_info= ha_info->next(); + if (!ha_info) + break; + if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) + { + statistic_increment(rpl_transactions_multi_engine, LOCK_status); + break; + } + } + } + return; + } + /* + This engine is marked to automatically create the table. + We cannot easily do this here (possibly in the middle of a + transaction). But we can request the slave background thread + to create it, and in a short while it should become available + for following transactions. + */ +#ifdef HAVE_REPLICATION + slave_background_gtid_pos_create_request(table_entry); +#endif + break; + } + table_entry= table_entry->next; + } + ++count; + } + /* + If we cannot find any table whose engine matches an engine that is + already active in the transaction, or if there is no current transaction + engines available, we return the default gtid_slave_pos table. + */ + default_entry= (struct gtid_pos_table *) + my_atomic_loadptr_explicit(&default_gtid_pos_table, MY_MEMORY_ORDER_ACQUIRE); + *out_tablename= default_entry->table_name; + /* Record in status that we failed to find a suitable gtid_pos table. */ + if (count > 0) + { + statistic_increment(transactions_gtid_foreign_engine, LOCK_status); + if (count > 1) + statistic_increment(rpl_transactions_multi_engine, LOCK_status); + } +} + + +/* Write a gtid to the replication slave state table. Do it as part of the transaction, to get slave crash safety, or as a separate @@ -481,19 +574,24 @@ gtid_check_rpl_slave_state_table(TABLE *table) */ int rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, - bool in_transaction, bool in_statement) + bool in_transaction, bool in_statement, + void **out_hton) { TABLE_LIST tlist; - int err= 0; + int err= 0, not_sql_thread; bool table_opened= false; TABLE *table; - list_element *elist= 0, *next; + list_element *delete_list= 0, *next, *cur, **next_ptr_ptr, **best_ptr_ptr; + uint64_t best_sub_id; element *elem; ulonglong thd_saved_option= thd->variables.option_bits; Query_tables_list lex_backup; wait_for_commit* suspended_wfc; + void *hton= NULL; + LEX_CSTRING gtid_pos_table_name; DBUG_ENTER("record_gtid"); + *out_hton= NULL; if (unlikely(!loaded)) { /* @@ -509,6 +607,25 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, if (!in_statement) thd->reset_for_next_command(); + /* + Only the SQL thread can call select_gtid_pos_table without a mutex + Other threads needs to use a mutex and take into account that the + result may change during execution, so we have to make a copy. + */ + + if ((not_sql_thread= (thd->system_thread != SYSTEM_THREAD_SLAVE_SQL))) + mysql_mutex_lock(&LOCK_slave_state); + select_gtid_pos_table(thd, >id_pos_table_name); + if (not_sql_thread) + { + LEX_CSTRING *tmp= thd->make_clex_string(gtid_pos_table_name.str, + gtid_pos_table_name.length); + mysql_mutex_unlock(&LOCK_slave_state); + if (!tmp) + DBUG_RETURN(1); + gtid_pos_table_name= *tmp; + } + DBUG_EXECUTE_IF("gtid_inject_record_gtid", { my_error(ER_CANNOT_UPDATE_GTID_STATE, MYF(0)); @@ -538,14 +655,13 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, */ suspended_wfc= thd->suspend_subsequent_commits(); thd->lex->reset_n_backup_query_tables_list(&lex_backup); - tlist.init_one_table(STRING_WITH_LEN("mysql"), - rpl_gtid_slave_state_table_name.str, - rpl_gtid_slave_state_table_name.length, - NULL, TL_WRITE); + tlist.init_one_table(STRING_WITH_LEN("mysql"), gtid_pos_table_name.str, + gtid_pos_table_name.length, NULL, TL_WRITE); if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0))) goto end; table_opened= true; table= tlist.table; + hton= table->s->db_type(); if ((err= gtid_check_rpl_slave_state_table(table))) goto end; @@ -581,6 +697,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, table->file->print_error(err, MYF(0)); goto end; } + *out_hton= hton; if(opt_bin_log && (err= mysql_bin_log.bump_seq_no_counter_if_needed(gtid->domain_id, @@ -598,36 +715,62 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, err= 1; goto end; } - if ((elist= elem->grab_list()) != NULL) + + /* Now pull out all GTIDs that were recorded in this engine. */ + delete_list = NULL; + next_ptr_ptr= &elem->list; + cur= elem->list; + best_sub_id= 0; + best_ptr_ptr= NULL; + while (cur) { - /* Delete any old stuff, but keep around the most recent one. */ - list_element *cur= elist; - uint64 best_sub_id= cur->sub_id; - list_element **best_ptr_ptr= &elist; - while ((next= cur->next)) + list_element *next= cur->next; + if (cur->hton == hton) { - if (next->sub_id > best_sub_id) + /* Belongs to same engine, so move it to the delete list. */ + cur->next= delete_list; + delete_list= cur; + if (cur->sub_id > best_sub_id) { - best_sub_id= next->sub_id; + best_sub_id= cur->sub_id; + best_ptr_ptr= &delete_list; + } + else if (best_ptr_ptr == &delete_list) best_ptr_ptr= &cur->next; + } + else + { + /* Another engine, leave it in the list. */ + if (cur->sub_id > best_sub_id) + { + best_sub_id= cur->sub_id; + /* Current best is not on the delete list. */ + best_ptr_ptr= NULL; } - cur= next; + *next_ptr_ptr= cur; + next_ptr_ptr= &cur->next; } - /* - Delete the highest sub_id element from the old list, and put it back as - the single-element new list. - */ + cur= next; + } + *next_ptr_ptr= NULL; + /* + If the highest sub_id element is on the delete list, put it back on the + original list, to preserve the highest sub_id element in the table for + GTID position recovery. + */ + if (best_ptr_ptr) + { cur= *best_ptr_ptr; *best_ptr_ptr= cur->next; - cur->next= NULL; + cur->next= elem->list; elem->list= cur; } mysql_mutex_unlock(&LOCK_slave_state); - if (!elist) + if (!delete_list) goto end; - /* Now delete any already committed rows. */ + /* Now delete any already committed GTIDs. */ bitmap_set_bit(table->read_set, table->field[0]->field_index); bitmap_set_bit(table->read_set, table->field[1]->field_index); @@ -636,7 +779,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, table->file->print_error(err, MYF(0)); goto end; } - while (elist) + while (delete_list) { uchar key_buffer[4+8]; @@ -646,9 +789,9 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, /* `break' does not work inside DBUG_EXECUTE_IF */ goto dbug_break; }); - next= elist->next; + next= delete_list->next; - table->field[1]->store(elist->sub_id, true); + table->field[1]->store(delete_list->sub_id, true); /* domain_id is already set in table->record[0] from write_row() above. */ key_copy(key_buffer, table->record[0], &table->key_info[0], 0, false); if (table->file->ha_index_read_map(table->record[1], key_buffer, @@ -662,8 +805,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, not want to endlessly error on the same element in case of table corruption or such. */ - my_free(elist); - elist= next; + my_free(delete_list); + delete_list= next; if (err) break; } @@ -681,13 +824,13 @@ end: if (err || (err= ha_commit_trans(thd, FALSE))) { /* - If error, we need to put any remaining elist back into the HASH so we - can do another delete attempt later. + If error, we need to put any remaining delete_list back into the HASH + so we can do another delete attempt later. */ - if (elist) + if (delete_list) { mysql_mutex_lock(&LOCK_slave_state); - put_back_list(gtid->domain_id, elist); + put_back_list(gtid->domain_id, delete_list); mysql_mutex_unlock(&LOCK_slave_state); } @@ -1077,11 +1220,12 @@ rpl_slave_state::load(THD *thd, const char *state_from_master, size_t len, { rpl_gtid gtid; uint64 sub_id; + void *hton= NULL; if (gtid_parser_helper(&state_from_master, end, >id) || !(sub_id= next_sub_id(gtid.domain_id)) || - record_gtid(thd, >id, sub_id, false, in_statement) || - update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no, NULL)) + record_gtid(thd, >id, sub_id, false, in_statement, &hton) || + update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no, hton, NULL)) return 1; if (state_from_master == end) break; @@ -1115,6 +1259,75 @@ rpl_slave_state::is_empty() } +void +rpl_slave_state::free_gtid_pos_tables(struct rpl_slave_state::gtid_pos_table *list) +{ + struct gtid_pos_table *cur, *next; + + cur= list; + while (cur) + { + next= cur->next; + my_free(cur); + cur= next; + } +} + + +/* + Replace the list of available mysql.gtid_slave_posXXX tables with a new list. + The caller must be holding LOCK_slave_state. Additionally, this function + must only be called while all SQL threads are stopped. +*/ +void +rpl_slave_state::set_gtid_pos_tables_list(rpl_slave_state::gtid_pos_table *new_list, + rpl_slave_state::gtid_pos_table *default_entry) +{ + gtid_pos_table *old_list; + + mysql_mutex_assert_owner(&LOCK_slave_state); + old_list= (struct gtid_pos_table *)gtid_pos_tables; + my_atomic_storeptr_explicit(>id_pos_tables, new_list, MY_MEMORY_ORDER_RELEASE); + my_atomic_storeptr_explicit(&default_gtid_pos_table, default_entry, + MY_MEMORY_ORDER_RELEASE); + free_gtid_pos_tables(old_list); +} + + +void +rpl_slave_state::add_gtid_pos_table(rpl_slave_state::gtid_pos_table *entry) +{ + mysql_mutex_assert_owner(&LOCK_slave_state); + entry->next= (struct gtid_pos_table *)gtid_pos_tables; + my_atomic_storeptr_explicit(>id_pos_tables, entry, MY_MEMORY_ORDER_RELEASE); +} + + +struct rpl_slave_state::gtid_pos_table * +rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton, + rpl_slave_state::gtid_pos_table_state state) +{ + struct gtid_pos_table *p; + char *allocated_str; + + if (!my_multi_malloc(MYF(MY_WME), + &p, sizeof(*p), + &allocated_str, table_name->length+1, + NULL)) + { + my_error(ER_OUTOFMEMORY, MYF(0), (int)(sizeof(*p) + table_name->length+1)); + return NULL; + } + memcpy(allocated_str, table_name->str, table_name->length+1); // Also copy '\0' + p->next = NULL; + p->table_hton= hton; + p->table_name.str= allocated_str; + p->table_name.length= table_name->length; + p->state= state; + return p; +} + + void rpl_binlog_state::init() { my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), @@ -1901,15 +2114,14 @@ void slave_connection_state::remove(const rpl_gtid *in_gtid) { uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id), 0); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS bool err; rpl_gtid *slave_gtid= &((entry *)rec)->gtid; DBUG_ASSERT(rec /* We should never try to remove not present domain_id. */); DBUG_ASSERT(slave_gtid->server_id == in_gtid->server_id); DBUG_ASSERT(slave_gtid->seq_no == in_gtid->seq_no); + err= #endif - - IF_DBUG(err=, ) my_hash_delete(&hash, rec); DBUG_ASSERT(!err); } diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index 5dfac7a3c6f..c473ff40ee9 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -112,6 +112,12 @@ struct rpl_slave_state uint64 sub_id; uint64 seq_no; uint32 server_id; + /* + hton of mysql.gtid_slave_pos* table used to record this GTID. + Can be NULL if the gtid table failed to load (eg. missing + mysql.gtid_slave_pos table following an upgrade). + */ + void *hton; }; /* Elements in the HASH that hold the state for one domain_id. */ @@ -155,6 +161,26 @@ struct rpl_slave_state } }; + /* Descriptor for mysql.gtid_slave_posXXX table in specific engine. */ + enum gtid_pos_table_state { + GTID_POS_AUTO_CREATE, + GTID_POS_CREATE_REQUESTED, + GTID_POS_CREATE_IN_PROGRESS, + GTID_POS_AVAILABLE + }; + struct gtid_pos_table { + struct gtid_pos_table *next; + /* + Use a void * here, rather than handlerton *, to make explicit that we + are not using the value to access any functionality in the engine. It + is just used as an opaque value to identify which engine we are using + for each GTID row. + */ + void *table_hton; + LEX_CSTRING table_name; + uint8 state; + }; + /* Mapping from domain_id to its element. */ HASH hash; /* Mutex protecting access to the state. */ @@ -163,6 +189,30 @@ struct rpl_slave_state DYNAMIC_ARRAY gtid_sort_array; uint64 last_sub_id; + /* + List of tables available for durably storing the slave GTID position. + + Accesses to this table is protected by LOCK_slave_state. However for + efficiency, there is also a provision for read access to it from a running + slave without lock. + + An element can be added at the head of a list by storing the new + gtid_pos_tables pointer atomically with release semantics, to ensure that + the next pointer of the new element is visible to readers of the new list. + Other changes (like deleting or replacing elements) must happen only while + all SQL driver threads are stopped. LOCK_slave_state must be held in any + case. + + The list can be read without lock by an SQL driver thread or worker thread + by reading the gtid_pos_tables pointer atomically with acquire semantics, + to ensure that it will see the correct next pointer of a new head element. + + The type is struct gtid_pos_table *, but needs to be void * to allow using + my_atomic operations without violating C strict aliasing semantics. + */ + void * volatile gtid_pos_tables; + /* The default entry in gtid_pos_tables, mysql.gtid_slave_pos. */ + void * volatile default_gtid_pos_table; bool loaded; rpl_slave_state(); @@ -171,10 +221,11 @@ struct rpl_slave_state void truncate_hash(); ulong count() const { return hash.records; } int update(uint32 domain_id, uint32 server_id, uint64 sub_id, - uint64 seq_no, rpl_group_info *rgi); + uint64 seq_no, void *hton, rpl_group_info *rgi); int truncate_state_table(THD *thd); + void select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename); int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, - bool in_transaction, bool in_statement); + bool in_transaction, bool in_statement, void **out_hton); uint64 next_sub_id(uint32 domain_id); int iterate(int (*cb)(rpl_gtid *, void *), void *data, rpl_gtid *extra_gtids, uint32 num_extra, @@ -188,10 +239,17 @@ struct rpl_slave_state element *get_element(uint32 domain_id); int put_back_list(uint32 domain_id, list_element *list); - void update_state_hash(uint64 sub_id, rpl_gtid *gtid, rpl_group_info *rgi); + void update_state_hash(uint64 sub_id, rpl_gtid *gtid, void *hton, + rpl_group_info *rgi); int record_and_update_gtid(THD *thd, struct rpl_group_info *rgi); int check_duplicate_gtid(rpl_gtid *gtid, rpl_group_info *rgi); void release_domain_owner(rpl_group_info *rgi); + void set_gtid_pos_tables_list(gtid_pos_table *new_list, + gtid_pos_table *default_entry); + void add_gtid_pos_table(gtid_pos_table *entry); + struct gtid_pos_table *alloc_gtid_pos_table(LEX_CSTRING *table_name, + void *hton, rpl_slave_state::gtid_pos_table_state state); + void free_gtid_pos_tables(struct gtid_pos_table *list); }; diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index 520fb61d8c4..e3ff2a17a6a 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index bff0da26862..d7081f766ec 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "rpl_injector.h" #include "transaction.h" diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h index 41e1fcf460c..dc7bfb6503a 100644 --- a/sql/rpl_injector.h +++ b/sql/rpl_injector.h @@ -17,7 +17,6 @@ #define INJECTOR_H /* Pull in 'byte', 'my_off_t', and 'uint32' */ -#include <my_global.h> #include <my_bitmap.h> #include "rpl_constants.h" diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 96d9ee4a1b4..9661e0b0353 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> // For HAVE_REPLICATION +#include "mariadb.h" // For HAVE_REPLICATION #include "sql_priv.h" #include <my_dir.h> #include "rpl_mi.h" @@ -1557,6 +1557,9 @@ bool give_error_if_slave_running(bool already_locked) /** any_slave_sql_running() + @param + already_locked 0 if we need to lock, 1 if we have LOCK_active_mi_locked + @return 0 No Slave SQL thread is running # Number of slave SQL thread running @@ -1567,26 +1570,28 @@ bool give_error_if_slave_running(bool already_locked) hash entries can't be accessed. */ -uint any_slave_sql_running() +uint any_slave_sql_running(bool already_locked) { uint count= 0; HASH *hash; DBUG_ENTER("any_slave_sql_running"); - mysql_mutex_lock(&LOCK_active_mi); + if (!already_locked) + mysql_mutex_lock(&LOCK_active_mi); if (unlikely(shutdown_in_progress || !master_info_index)) + count= 1; + else { - mysql_mutex_unlock(&LOCK_active_mi); - DBUG_RETURN(1); - } - hash= &master_info_index->master_info_hash; - for (uint i= 0; i< hash->records; ++i) - { - Master_info *mi= (Master_info *)my_hash_element(hash, i); - if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN) - count++; + hash= &master_info_index->master_info_hash; + for (uint i= 0; i< hash->records; ++i) + { + Master_info *mi= (Master_info *)my_hash_element(hash, i); + if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN) + count++; + } } - mysql_mutex_unlock(&LOCK_active_mi); + if (!already_locked) + mysql_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(count); } diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index ccc1be6e5ce..610bc77b683 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -20,7 +20,7 @@ #include "rpl_rli.h" #include "rpl_reporting.h" -#include "my_sys.h" +#include <my_sys.h> #include "rpl_filter.h" #include "keycaches.h" @@ -379,7 +379,7 @@ void create_logfile_name_with_suffix(char *res_file_name, size_t length, uchar *get_key_master_info(Master_info *mi, size_t *length, my_bool not_used __attribute__((unused))); void free_key_master_info(Master_info *mi); -uint any_slave_sql_running(); +uint any_slave_sql_running(bool already_locked); bool give_error_if_slave_running(bool already_lock); #endif /* HAVE_REPLICATION */ diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 973b9d899c1..4a6e813d73b 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -1,4 +1,4 @@ -#include "my_global.h" +#include "mariadb.h" #include "rpl_parallel.h" #include "slave.h" #include "rpl_mi.h" @@ -256,7 +256,9 @@ signal_error_to_sql_driver_thread(THD *thd, rpl_group_info *rgi, int err) rgi->rli->stop_for_until= false; mysql_mutex_lock(rgi->rli->relay_log.get_log_lock()); mysql_mutex_unlock(rgi->rli->relay_log.get_log_lock()); + rgi->rli->relay_log.lock_binlog_end_pos(); rgi->rli->relay_log.signal_update(); + rgi->rli->relay_log.unlock_binlog_end_pos(); } @@ -1002,8 +1004,7 @@ handle_rpl_parallel_thread(void *arg) thd->security_ctx->skip_grants(); thd->variables.max_allowed_packet= slave_max_allowed_packet; thd->slave_thread= 1; - thd->variables.sql_log_slow= opt_log_slow_slave_statements; - thd->variables.log_slow_filter= global_system_variables.log_slow_filter; + set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; thd->net.reading_or_writing= 0; @@ -1462,7 +1463,7 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool, */ if (!new_count && !force) { - if (any_slave_sql_running()) + if (any_slave_sql_running(false)) { DBUG_PRINT("warning", ("SQL threads running while trying to reset parallel pool")); @@ -1617,7 +1618,7 @@ err: int rpl_parallel_resize_pool_if_no_slaves(void) { /* master_info_index is set to NULL on shutdown */ - if (opt_slave_parallel_threads > 0 && !any_slave_sql_running()) + if (opt_slave_parallel_threads > 0 && !any_slave_sql_running(false)) return rpl_parallel_inactivate_pool(&global_rpl_thread_pool); return 0; } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 51e93003c56..9ff5004414c 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "rpl_rli.h" diff --git a/sql/rpl_record.h b/sql/rpl_record.h index be69716d9d5..8d565845c4b 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -18,7 +18,6 @@ #define RPL_RECORD_H #include <rpl_reporting.h> -#include "my_global.h" /* uchar */ struct rpl_group_info; struct TABLE; diff --git a/sql/rpl_record_old.cc b/sql/rpl_record_old.cc index a252bbff0f5..4180557f018 100644 --- a/sql/rpl_record_old.cc +++ b/sql/rpl_record_old.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "rpl_rli.h" #include "rpl_record_old.h" diff --git a/sql/rpl_reporting.cc b/sql/rpl_reporting.cc index ad949402511..800682fab91 100644 --- a/sql/rpl_reporting.cc +++ b/sql/rpl_reporting.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "rpl_reporting.h" #include "log.h" // sql_print_error, sql_print_warning, diff --git a/sql/rpl_reporting.h b/sql/rpl_reporting.h index d90b7ad6650..17748f587b1 100644 --- a/sql/rpl_reporting.h +++ b/sql/rpl_reporting.h @@ -16,7 +16,7 @@ #ifndef RPL_REPORTING_H #define RPL_REPORTING_H -#include "my_sys.h" /* loglevel */ +#include <my_sys.h> /* loglevel */ /** Maximum size of an error message from a slave thread. diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index ed9f0369f5d..efb256fbe11 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" // HAVE_* #include "rpl_mi.h" @@ -31,6 +31,8 @@ #include "slave.h" #include <mysql/plugin.h> #include <mysql/service_thd_wait.h> +#include "lock.h" +#include "sql_table.h" static int count_relay_log_space(Relay_log_info* rli); @@ -1509,41 +1511,22 @@ Relay_log_info::update_relay_log_state(rpl_gtid *gtid_list, uint32 count) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) -int -rpl_load_gtid_slave_state(THD *thd) +struct gtid_pos_element { uint64 sub_id; rpl_gtid gtid; void *hton; }; + +static int +scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array, + LEX_CSTRING *tablename, void **out_hton) { TABLE_LIST tlist; TABLE *table; bool table_opened= false; bool table_scanned= false; - bool array_inited= false; - struct local_element { uint64 sub_id; rpl_gtid gtid; }; - struct local_element tmp_entry, *entry; - HASH hash; - DYNAMIC_ARRAY array; + struct gtid_pos_element tmp_entry, *entry; int err= 0; - uint32 i; - DBUG_ENTER("rpl_load_gtid_slave_state"); - - mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); - bool loaded= rpl_global_gtid_slave_state->loaded; - mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); - if (loaded) - DBUG_RETURN(0); - - my_hash_init(&hash, &my_charset_bin, 32, - offsetof(local_element, gtid) + offsetof(rpl_gtid, domain_id), - sizeof(uint32), NULL, my_free, HASH_UNIQUE); - if ((err= my_init_dynamic_array(&array, sizeof(local_element), 0, 0, MYF(0)))) - goto end; - array_inited= true; thd->reset_for_next_command(); - - tlist.init_one_table(STRING_WITH_LEN("mysql"), - rpl_gtid_slave_state_table_name.str, - rpl_gtid_slave_state_table_name.length, - NULL, TL_READ); + tlist.init_one_table(STRING_WITH_LEN("mysql"), tablename->str, + tablename->length, NULL, TL_READ); if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0))) goto end; table_opened= true; @@ -1589,26 +1572,28 @@ rpl_load_gtid_slave_state(THD *thd) tmp_entry.gtid.domain_id= domain_id; tmp_entry.gtid.server_id= server_id; tmp_entry.gtid.seq_no= seq_no; - if ((err= insert_dynamic(&array, (uchar *)&tmp_entry))) + tmp_entry.hton= table->s->db_type(); + if ((err= insert_dynamic(array, (uchar *)&tmp_entry))) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); goto end; } - if ((rec= my_hash_search(&hash, (const uchar *)&domain_id, 0))) + if ((rec= my_hash_search(hash, (const uchar *)&domain_id, 0))) { - entry= (struct local_element *)rec; + entry= (struct gtid_pos_element *)rec; if (entry->sub_id >= sub_id) continue; entry->sub_id= sub_id; DBUG_ASSERT(entry->gtid.domain_id == domain_id); entry->gtid.server_id= server_id; entry->gtid.seq_no= seq_no; + entry->hton= table->s->db_type(); } else { - if (!(entry= (struct local_element *)my_malloc(sizeof(*entry), - MYF(MY_WME)))) + if (!(entry= (struct gtid_pos_element *)my_malloc(sizeof(*entry), + MYF(MY_WME)))) { my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*entry)); err= 1; @@ -1618,7 +1603,8 @@ rpl_load_gtid_slave_state(THD *thd) entry->gtid.domain_id= domain_id; entry->gtid.server_id= server_id; entry->gtid.seq_no= seq_no; - if ((err= my_hash_insert(&hash, (uchar *)entry))) + entry->hton= table->s->db_type(); + if ((err= my_hash_insert(hash, (uchar *)entry))) { my_free(entry); my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -1626,6 +1612,249 @@ rpl_load_gtid_slave_state(THD *thd) } } } + err= 0; /* Clear HA_ERR_END_OF_FILE */ + +end: + if (table_scanned) + { + table->file->ha_index_or_rnd_end(); + ha_commit_trans(thd, FALSE); + ha_commit_trans(thd, TRUE); + } + if (table_opened) + { + *out_hton= table->s->db_type(); + close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); + } + return err; +} + + +/* + Look for all tables mysql.gtid_slave_pos*. Read all rows from each such + table found into ARRAY. For each domain id, put the row with highest sub_id + into HASH. +*/ +static int +scan_all_gtid_slave_pos_table(THD *thd, int (*cb)(THD *, LEX_CSTRING *, void *), + void *cb_data) +{ + static LEX_CSTRING mysql_db_name= {C_STRING_WITH_LEN("mysql")}; + char path[FN_REFLEN]; + MY_DIR *dirp; + + thd->reset_for_next_command(); + if (lock_schema_name(thd, mysql_db_name.str)) + return 1; + + build_table_filename(path, sizeof(path) - 1, mysql_db_name.str, "", "", 0); + if (!(dirp= my_dir(path, MYF(MY_DONT_SORT)))) + { + my_error(ER_FILE_NOT_FOUND, MYF(0), path, my_errno); + close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); + return 1; + } + else + { + size_t i; + Dynamic_array<LEX_CSTRING*> files(dirp->number_of_files); + Discovered_table_list tl(thd, &files); + int err; + + err= ha_discover_table_names(thd, &mysql_db_name, dirp, &tl, false); + my_dirend(dirp); + close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); + if (err) + return err; + + for (i = 0; i < files.elements(); ++i) + { + if (strncmp(files.at(i)->str, + rpl_gtid_slave_state_table_name.str, + rpl_gtid_slave_state_table_name.length) == 0) + { + if ((err= (*cb)(thd, files.at(i), cb_data))) + return err; + } + } + } + + return 0; +} + + +struct load_gtid_state_cb_data { + HASH *hash; + DYNAMIC_ARRAY *array; + struct rpl_slave_state::gtid_pos_table *table_list; + struct rpl_slave_state::gtid_pos_table *default_entry; +}; + +static int +process_gtid_pos_table(THD *thd, LEX_CSTRING *table_name, void *hton, + struct load_gtid_state_cb_data *data) +{ + struct rpl_slave_state::gtid_pos_table *p, *entry, **next_ptr; + bool is_default= + (strcmp(table_name->str, rpl_gtid_slave_state_table_name.str) == 0); + + /* + Ignore tables with duplicate storage engine, with a warning. + Prefer the default mysql.gtid_slave_pos over another table + mysql.gtid_slave_posXXX with the same storage engine. + */ + next_ptr= &data->table_list; + entry= data->table_list; + while (entry) + { + if (entry->table_hton == hton) + { + static const char *warning_msg= "Ignoring redundant table mysql.%s " + "since mysql.%s has the same storage engine"; + if (!is_default) + { + /* Ignore the redundant table. */ + sql_print_warning(warning_msg, table_name->str, entry->table_name); + return 0; + } + else + { + sql_print_warning(warning_msg, entry->table_name, table_name->str); + /* Delete the redundant table, and proceed to add this one instead. */ + *next_ptr= entry->next; + my_free(entry); + break; + } + } + next_ptr= &entry->next; + entry= entry->next; + } + + p= rpl_global_gtid_slave_state->alloc_gtid_pos_table(table_name, + hton, rpl_slave_state::GTID_POS_AVAILABLE); + if (!p) + return 1; + p->next= data->table_list; + data->table_list= p; + if (is_default) + data->default_entry= p; + return 0; +} + + +/* + Put tables corresponding to @@gtid_pos_auto_engines at the end of the list, + marked to be auto-created if needed. +*/ +static int +gtid_pos_auto_create_tables(rpl_slave_state::gtid_pos_table **list_ptr) +{ + plugin_ref *auto_engines; + int err= 0; + mysql_mutex_lock(&LOCK_global_system_variables); + for (auto_engines= opt_gtid_pos_auto_plugins; + !err && auto_engines && *auto_engines; + ++auto_engines) + { + void *hton= plugin_hton(*auto_engines); + char buf[FN_REFLEN+1]; + LEX_CSTRING table_name; + char *p; + rpl_slave_state::gtid_pos_table *entry, **next_ptr; + + /* See if this engine is already in the list. */ + next_ptr= list_ptr; + entry= *list_ptr; + while (entry) + { + if (entry->table_hton == hton) + break; + next_ptr= &entry->next; + entry= entry->next; + } + if (entry) + continue; + + /* Add an auto-create entry for this engine at end of list. */ + p= strmake(buf, rpl_gtid_slave_state_table_name.str, FN_REFLEN); + p= strmake(p, "_", FN_REFLEN - (p - buf)); + p= strmake(p, plugin_name(*auto_engines)->str, FN_REFLEN - (p - buf)); + table_name.str= buf; + table_name.length= p - buf; + entry= rpl_global_gtid_slave_state->alloc_gtid_pos_table + (&table_name, hton, rpl_slave_state::GTID_POS_AUTO_CREATE); + if (!entry) + { + err= 1; + break; + } + *next_ptr= entry; + } + mysql_mutex_unlock(&LOCK_global_system_variables); + return err; +} + + +static int +load_gtid_state_cb(THD *thd, LEX_CSTRING *table_name, void *arg) +{ + int err; + load_gtid_state_cb_data *data= static_cast<load_gtid_state_cb_data *>(arg); + void *hton; + + if ((err= scan_one_gtid_slave_pos_table(thd, data->hash, data->array, + table_name, &hton))) + return err; + return process_gtid_pos_table(thd, table_name, hton, data); +} + + +int +rpl_load_gtid_slave_state(THD *thd) +{ + bool array_inited= false; + struct gtid_pos_element tmp_entry, *entry; + HASH hash; + DYNAMIC_ARRAY array; + int err= 0; + uint32 i; + load_gtid_state_cb_data cb_data; + DBUG_ENTER("rpl_load_gtid_slave_state"); + + mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); + bool loaded= rpl_global_gtid_slave_state->loaded; + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + if (loaded) + DBUG_RETURN(0); + + cb_data.table_list= NULL; + cb_data.default_entry= NULL; + my_hash_init(&hash, &my_charset_bin, 32, + offsetof(gtid_pos_element, gtid) + offsetof(rpl_gtid, domain_id), + sizeof(uint32), NULL, my_free, HASH_UNIQUE); + if ((err= my_init_dynamic_array(&array, sizeof(gtid_pos_element), 0, 0, MYF(0)))) + goto end; + array_inited= true; + + cb_data.hash = &hash; + cb_data.array = &array; + if ((err= scan_all_gtid_slave_pos_table(thd, load_gtid_state_cb, &cb_data))) + goto end; + + if (!cb_data.default_entry) + { + /* + If the mysql.gtid_slave_pos table does not exist, but at least one other + table is available, arbitrarily pick the first in the list to use as + default. + */ + cb_data.default_entry= cb_data.table_list; + } + if ((err= gtid_pos_auto_create_tables(&cb_data.table_list))) + goto end; mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); if (rpl_global_gtid_slave_state->loaded) @@ -1634,14 +1863,24 @@ rpl_load_gtid_slave_state(THD *thd) goto end; } + if (!cb_data.table_list) + { + my_error(ER_NO_SUCH_TABLE, MYF(0), "mysql", + rpl_gtid_slave_state_table_name.str); + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + err= 1; + goto end; + } + for (i= 0; i < array.elements; ++i) { get_dynamic(&array, (uchar *)&tmp_entry, i); if ((err= rpl_global_gtid_slave_state->update(tmp_entry.gtid.domain_id, - tmp_entry.gtid.server_id, - tmp_entry.sub_id, - tmp_entry.gtid.seq_no, - NULL))) + tmp_entry.gtid.server_id, + tmp_entry.sub_id, + tmp_entry.gtid.seq_no, + tmp_entry.hton, + NULL))) { mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -1651,7 +1890,7 @@ rpl_load_gtid_slave_state(THD *thd) for (i= 0; i < hash.records; ++i) { - entry= (struct local_element *)my_hash_element(&hash, i); + entry= (struct gtid_pos_element *)my_hash_element(&hash, i); if (opt_bin_log && mysql_bin_log.bump_seq_no_counter_if_needed(entry->gtid.domain_id, entry->gtid.seq_no)) @@ -1662,27 +1901,175 @@ rpl_load_gtid_slave_state(THD *thd) } } + rpl_global_gtid_slave_state->set_gtid_pos_tables_list(cb_data.table_list, + cb_data.default_entry); + cb_data.table_list= NULL; rpl_global_gtid_slave_state->loaded= true; mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); - err= 0; /* Clear HA_ERR_END_OF_FILE */ +end: + if (array_inited) + delete_dynamic(&array); + my_hash_free(&hash); + if (cb_data.table_list) + rpl_global_gtid_slave_state->free_gtid_pos_tables(cb_data.table_list); + DBUG_RETURN(err); +} + + +static int +find_gtid_pos_tables_cb(THD *thd, LEX_CSTRING *table_name, void *arg) +{ + load_gtid_state_cb_data *data= static_cast<load_gtid_state_cb_data *>(arg); + TABLE_LIST tlist; + TABLE *table= NULL; + int err; + + thd->reset_for_next_command(); + tlist.init_one_table(STRING_WITH_LEN("mysql"), table_name->str, + table_name->length, NULL, TL_READ); + if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0))) + goto end; + table= tlist.table; + + if ((err= gtid_check_rpl_slave_state_table(table))) + goto end; + err= process_gtid_pos_table(thd, table_name, table->s->db_type(), data); end: - if (table_scanned) + if (table) { - table->file->ha_index_or_rnd_end(); ha_commit_trans(thd, FALSE); ha_commit_trans(thd, TRUE); - } - if (table_opened) - { close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); } - if (array_inited) - delete_dynamic(&array); - my_hash_free(&hash); - DBUG_RETURN(err); + + return err; +} + + +/* + Re-compute the list of available mysql.gtid_slave_posXXX tables. + + This is done at START SLAVE to pick up any newly created tables without + requiring server restart. +*/ +int +find_gtid_slave_pos_tables(THD *thd) +{ + int err= 0; + load_gtid_state_cb_data cb_data; + uint num_running; + + mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); + bool loaded= rpl_global_gtid_slave_state->loaded; + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + if (!loaded) + return 0; + + cb_data.table_list= NULL; + cb_data.default_entry= NULL; + if ((err= scan_all_gtid_slave_pos_table(thd, find_gtid_pos_tables_cb, &cb_data))) + goto end; + + if (!cb_data.table_list) + { + my_error(ER_NO_SUCH_TABLE, MYF(0), "mysql", + rpl_gtid_slave_state_table_name.str); + err= 1; + goto end; + } + if (!cb_data.default_entry) + { + /* + If the mysql.gtid_slave_pos table does not exist, but at least one other + table is available, arbitrarily pick the first in the list to use as + default. + */ + cb_data.default_entry= cb_data.table_list; + } + if ((err= gtid_pos_auto_create_tables(&cb_data.table_list))) + goto end; + + mysql_mutex_lock(&LOCK_active_mi); + num_running= any_slave_sql_running(true); + mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); + if (num_running <= 1) + { + /* + If no slave is running now, the count will be 1, since this SQL thread + which is starting is included in the count. In this case, we can safely + replace the list, no-one can be trying to read it without lock. + */ + DBUG_ASSERT(num_running == 1); + rpl_global_gtid_slave_state->set_gtid_pos_tables_list(cb_data.table_list, + cb_data.default_entry); + cb_data.table_list= NULL; + } + else + { + /* + If there are SQL threads running, we cannot safely remove the old list. + However we can add new entries, and warn about any tables that + disappeared, but may still be visible to running SQL threads. + */ + rpl_slave_state::gtid_pos_table *old_entry, *new_entry, **next_ptr_ptr; + + old_entry= (rpl_slave_state::gtid_pos_table *) + rpl_global_gtid_slave_state->gtid_pos_tables; + while (old_entry) + { + new_entry= cb_data.table_list; + while (new_entry) + { + if (new_entry->table_hton == old_entry->table_hton) + break; + new_entry= new_entry->next; + } + if (!new_entry) + sql_print_warning("The table mysql.%s was removed. " + "This change will not take full effect " + "until all SQL threads have been restarted", + old_entry->table_name.str); + old_entry= old_entry->next; + } + next_ptr_ptr= &cb_data.table_list; + new_entry= cb_data.table_list; + while (new_entry) + { + /* Check if we already have a table with this storage engine. */ + old_entry= (rpl_slave_state::gtid_pos_table *) + rpl_global_gtid_slave_state->gtid_pos_tables; + while (old_entry) + { + if (new_entry->table_hton == old_entry->table_hton) + break; + old_entry= old_entry->next; + } + if (old_entry) + { + /* This new_entry is already available in the list. */ + next_ptr_ptr= &new_entry->next; + new_entry= new_entry->next; + } + else + { + /* Move this new_entry to the list. */ + rpl_slave_state::gtid_pos_table *next= new_entry->next; + rpl_global_gtid_slave_state->add_gtid_pos_table(new_entry); + *next_ptr_ptr= next; + new_entry= next; + } + } + } + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + mysql_mutex_unlock(&LOCK_active_mi); + +end: + if (cb_data.table_list) + rpl_global_gtid_slave_state->free_gtid_pos_tables(cb_data.table_list); + return err; } diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index d88bc9f6ecd..b8b153c34be 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -752,7 +752,7 @@ struct rpl_group_info Runtime state for printing a note when slave is taking too long while processing a row event. */ - time_t row_stmt_start_timestamp; + longlong row_stmt_start_timestamp; bool long_find_row_note_printed; /* Needs room for "Gtid D-S-N\x00". */ char gtid_info_buf[5+10+1+10+1+20+1]; @@ -898,17 +898,15 @@ struct rpl_group_info char *gtid_info(); void unmark_start_commit(); - time_t get_row_stmt_start_timestamp() + longlong get_row_stmt_start_timestamp() { return row_stmt_start_timestamp; } - time_t set_row_stmt_start_timestamp() + void set_row_stmt_start_timestamp() { if (row_stmt_start_timestamp == 0) - row_stmt_start_timestamp= my_time(0); - - return row_stmt_start_timestamp; + row_stmt_start_timestamp= microsecond_interval_timer(); } void reset_row_stmt_start_timestamp() @@ -967,6 +965,7 @@ extern struct rpl_slave_state *rpl_global_gtid_slave_state; extern gtid_waiting rpl_global_gtid_waiting; int rpl_load_gtid_slave_state(THD *thd); +int find_gtid_slave_pos_tables(THD *thd); int event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev); void delete_or_keep_event_post_apply(rpl_group_info *rgi, Log_event_type typ, Log_event *ev); diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index 48111bc5d0a..80d093722f7 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #ifdef HAVE_REPLICATION diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 9a984c5c953..774f582b4b9 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include <my_bit.h> #include "rpl_utility.h" #include "log_event.h" @@ -128,6 +128,8 @@ max_display_length_for_field(enum_field_types sql_type, unsigned int metadata) case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: return metadata; + case MYSQL_TYPE_VARCHAR_COMPRESSED: + return metadata - 1; /* The actual length for these types does not really matter since @@ -145,6 +147,7 @@ max_display_length_for_field(enum_field_types sql_type, unsigned int metadata) return my_set_bits(3 * 8); case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_BLOB_COMPRESSED: /* For the blob type, Field::real_type() lies and say that all blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look @@ -294,6 +297,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const break; } case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VARCHAR_COMPRESSED: { length= m_field_metadata[col] > 255 ? 2 : 1; // c&p of Field_varstring::data_length() length+= length == 1 ? (uint32) *master_data : uint2korr(master_data); @@ -303,6 +307,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_BLOB_COMPRESSED: case MYSQL_TYPE_GEOMETRY: { /* @@ -406,11 +411,14 @@ void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_ case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VARCHAR_COMPRESSED: { CHARSET_INFO *cs= str->charset(); uint32 length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "varchar(%u)", metadata); + "varchar(%u)%s", metadata, + type == MYSQL_TYPE_VARCHAR_COMPRESSED ? " compressed" + : ""); str->length(length); } break; @@ -455,6 +463,7 @@ void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_ break; case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_BLOB_COMPRESSED: /* Field::real_type() lies regarding the actual type of a BLOB, so it is necessary to check the pack length to figure out what kind @@ -482,6 +491,9 @@ void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_ DBUG_ASSERT(0); break; } + + if (type == MYSQL_TYPE_BLOB_COMPRESSED) + str->append(STRING_WITH_LEN(" compressed")); break; case MYSQL_TYPE_STRING: @@ -583,6 +595,7 @@ can_convert_field_to(Field *field, int *order_var) { DBUG_ENTER("can_convert_field_to"); + bool same_type; #ifndef DBUG_OFF char field_type_buf[MAX_FIELD_WIDTH]; String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1); @@ -590,11 +603,30 @@ can_convert_field_to(Field *field, DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x", field_type.c_ptr_safe(), field->real_type(), source_type, metadata)); #endif + /** + @todo + Implement Field_varstring_cmopressed::real_type() and + Field_blob_compressed::real_type() properly. All occurencies + of Field::real_type() have to be inspected and adjusted if needed. + + Until it is not ready we have to compare source_type against + binlog_type() when replicating from or to compressed data types. + + @sa Comment for Field::binlog_type() + */ + if (source_type == MYSQL_TYPE_VARCHAR_COMPRESSED || + source_type == MYSQL_TYPE_BLOB_COMPRESSED || + field->binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED || + field->binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED) + same_type= field->binlog_type() == source_type; + else + same_type= field->real_type() == source_type; + /* If the real type is the same, we need to check the metadata to decide if conversions are allowed. */ - if (field->real_type() == source_type) + if (same_type) { if (metadata == 0) // Metadata can only be zero if no metadata was provided { @@ -731,18 +763,22 @@ can_convert_field_to(Field *field, case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_BLOB_COMPRESSED: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VARCHAR_COMPRESSED: switch (field->real_type()) { case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_BLOB_COMPRESSED: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VARCHAR_COMPRESSED: *order_var= compare_lengths(field, source_type, metadata); /* Here we know that the types are different, so if the order @@ -1036,6 +1072,7 @@ table_def::table_def(unsigned char *types, ulong size, switch (binlog_type(i)) { case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_BLOB_COMPRESSED: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_DOUBLE: @@ -1066,6 +1103,7 @@ table_def::table_def(unsigned char *types, ulong size, break; } case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VARCHAR_COMPRESSED: { /* These types store two bytes. @@ -1127,7 +1165,7 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, enum enum_binlog_che if (event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS int8 fd_alg= event_buf[event_len - BINLOG_CHECKSUM_LEN - BINLOG_CHECKSUM_ALG_DESC_LEN]; #endif diff --git a/sql/scheduler.cc b/sql/scheduler.cc index de472ae2504..818bb3818f4 100644 --- a/sql/scheduler.cc +++ b/sql/scheduler.cc @@ -22,6 +22,7 @@ #pragma implementation #endif +#include "mariadb.h" #include "mysqld.h" #include "sql_connect.h" // init_new_connection_handler_thread #include "scheduler.h" diff --git a/sql/scheduler.h b/sql/scheduler.h index 71553372999..b067763d9b4 100644 --- a/sql/scheduler.h +++ b/sql/scheduler.h @@ -25,8 +25,6 @@ #pragma interface #endif -#include <my_global.h> - class THD; /* Functions used when manipulating threads */ diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 4b449f3991a..ff9780a9531 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -1216,7 +1216,7 @@ bool Transaction_state_tracker::store(THD *thd, String *buf) tx_isolation_typelib as it hyphenates its items. */ buf->append(STRING_WITH_LEN("SET TRANSACTION ISOLATION LEVEL ")); - buf->append(isol[tx_isol_level - 1].str, isol[tx_isol_level - 1].length); + buf->append(&isol[tx_isol_level - 1]); buf->append(STRING_WITH_LEN("; ")); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 15f6bbdafc5..311b33bc0dd 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -16,7 +16,7 @@ /* variable declarations are in sys_vars.cc now !!! */ -#include "sql_plugin.h" // Includes my_global.h +#include "sql_plugin.h" #include "sql_class.h" // set_var.h: session_var_ptr #include "set_var.h" #include "sql_priv.h" @@ -1162,6 +1162,7 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) { STRING_WITH_LEN("SET") }, // GET_SET 13 { STRING_WITH_LEN("DOUBLE") }, // GET_DOUBLE 14 { STRING_WITH_LEN("FLAGSET") }, // GET_FLAGSET 15 + { STRING_WITH_LEN("BOOLEAN") }, // GET_BIT 16 }; const ulong vartype= (var->option.var_type & GET_TYPE_MASK); const LEX_CSTRING *type= types + vartype; @@ -1293,3 +1294,222 @@ enum sys_var::where get_sys_var_value_origin(void *ptr) return sys_var::CONFIG; } + +/* + Find the next item in string of comma-separated items. + END_POS points at the end of the string. + ITEM_START and ITEM_END return the limits of the next item. + Returns true while items are available, false at the end. +*/ +static bool +engine_list_next_item(const char **pos, const char *end_pos, + const char **item_start, const char **item_end) +{ + if (*pos >= end_pos) + return false; + *item_start= *pos; + while (*pos < end_pos && **pos != ',') + ++*pos; + *item_end= *pos; + ++*pos; + return true; +} + + +static bool +resolve_engine_list_item(THD *thd, plugin_ref *list, uint32 *idx, + const char *pos, const char *pos_end, + bool error_on_unknown_engine, bool temp_copy) +{ + LEX_CSTRING item_str; + plugin_ref ref; + uint32_t i; + THD *thd_or_null = (temp_copy ? thd : NULL); + + item_str.str= pos; + item_str.length= pos_end-pos; + ref= ha_resolve_by_name(thd_or_null, &item_str, false); + if (!ref) + { + if (error_on_unknown_engine) + { + ErrConvString err(pos, pos_end-pos, system_charset_info); + my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr()); + return true; + } + return false; + } + /* Ignore duplicates, like --plugin-load does. */ + for (i= 0; i < *idx; ++i) + { + if (plugin_hton(list[i]) == plugin_hton(ref)) + { + if (!temp_copy) + plugin_unlock(NULL, ref); + return false; + } + } + list[*idx]= ref; + ++*idx; + return false; +} + + +/* + Helper for class Sys_var_pluginlist. + Resolve a comma-separated list of storage engine names to a null-terminated + array of plugin_ref. + + If TEMP_COPY is true, a THD must be given as well. In this case, the + allocated memory and locked plugins are registered in the THD and will + be freed / unlocked automatically. If TEMP_COPY is true, THD can be + passed as NULL, and resources must be freed explicitly later with + free_engine_list(). +*/ +plugin_ref * +resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len, + bool error_on_unknown_engine, bool temp_copy) +{ + uint32 count, idx; + const char *pos, *item_start, *item_end; + const char *str_arg_end= str_arg + str_arg_len; + plugin_ref *res; + + count= 0; + pos= str_arg; + for (;;) + { + if (!engine_list_next_item(&pos, str_arg_end, &item_start, &item_end)) + break; + ++count; + } + + if (temp_copy) + res= (plugin_ref *)thd->calloc((count+1)*sizeof(*res)); + else + res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME)); + if (!res) + { + my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*res))); + goto err; + } + + idx= 0; + pos= str_arg; + for (;;) + { + if (!engine_list_next_item(&pos, str_arg_end, &item_start, &item_end)) + break; + DBUG_ASSERT(idx < count); + if (idx >= count) + break; + if (resolve_engine_list_item(thd, res, &idx, item_start, item_end, + error_on_unknown_engine, temp_copy)) + goto err; + } + + return res; + +err: + if (!temp_copy) + free_engine_list(res); + return NULL; +} + + +void +free_engine_list(plugin_ref *list) +{ + plugin_ref *p; + + if (!list) + return; + for (p= list; *p; ++p) + plugin_unlock(NULL, *p); + my_free(list); +} + + +plugin_ref * +copy_engine_list(plugin_ref *list) +{ + plugin_ref *p; + uint32 count, i; + + for (p= list, count= 0; *p; ++p, ++count) + ; + p= (plugin_ref *)my_malloc((count+1)*sizeof(*p), MYF(0)); + if (!p) + { + my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p))); + return NULL; + } + for (i= 0; i < count; ++i) + p[i]= my_plugin_lock(NULL, list[i]); + p[i] = NULL; + return p; +} + + +/* + Create a temporary copy of an engine list. The memory will be freed + (and the plugins unlocked) automatically, on the passed THD. +*/ +plugin_ref * +temp_copy_engine_list(THD *thd, plugin_ref *list) +{ + plugin_ref *p; + uint32 count, i; + + for (p= list, count= 0; *p; ++p, ++count) + ; + p= (plugin_ref *)thd->alloc((count+1)*sizeof(*p)); + if (!p) + { + my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p))); + return NULL; + } + for (i= 0; i < count; ++i) + p[i]= my_plugin_lock(thd, list[i]); + p[i] = NULL; + return p; +} + + +char * +pretty_print_engine_list(THD *thd, plugin_ref *list) +{ + plugin_ref *p; + size_t size; + char *buf, *pos; + + if (!list || !*list) + return thd->strmake("", 0); + + size= 0; + for (p= list; *p; ++p) + size+= plugin_name(*p)->length + 1; + buf= static_cast<char *>(thd->alloc(size)); + if (!buf) + return NULL; + pos= buf; + for (p= list; *p; ++p) + { + LEX_CSTRING *name; + size_t remain; + + remain= buf + size - pos; + DBUG_ASSERT(remain > 0); + if (remain <= 1) + break; + if (pos != buf) + { + pos= strmake(pos, ",", remain-1); + --remain; + } + name= plugin_name(*p); + pos= strmake(pos, name->str, MY_MIN(name->length, remain-1)); + } + *pos= '\0'; + return buf; +} diff --git a/sql/set_var.h b/sql/set_var.h index 17d1ff93ebc..d0143e1e524 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -158,6 +158,7 @@ public: case GET_BOOL: case GET_SET: case GET_FLAGSET: + case GET_BIT: return type != STRING_RESULT && type != INT_RESULT; case GET_DOUBLE: return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT; @@ -286,6 +287,7 @@ public: longlong longlong_value; ///< for signed integer double double_value; ///< for Sys_var_double plugin_ref plugin; ///< for Sys_var_plugin + plugin_ref *plugins; ///< for Sys_var_pluginlist Time_zone *time_zone; ///< for Sys_var_tz LEX_STRING string_value; ///< for Sys_var_charptr and others const void *ptr; ///< for Sys_var_struct @@ -424,6 +426,12 @@ int sys_var_init(); uint sys_var_elements(); int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags); void sys_var_end(void); +plugin_ref *resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len, + bool error_on_unknown_engine, bool temp_copy); +void free_engine_list(plugin_ref *list); +plugin_ref *copy_engine_list(plugin_ref *list); +plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list); +char *pretty_print_engine_list(THD *thd, plugin_ref *list); #endif diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index a6462cbca9b..0204121c553 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7775,6 +7775,10 @@ ER_UNKNOWN_SEQUENCES 42S02 ER_UNKNOWN_VIEW 42S02 eng "Unknown VIEW: '%-.300s'" ER_WRONG_INSERT_INTO_SEQUENCE - eng "Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a squence object (like with mysqldump). If you want to change the SEQUENCE, use ALTER SEQUENCE instead." + eng "Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a sequence object (like with mysqldump). If you want to change the SEQUENCE, use ALTER SEQUENCE instead." ER_SP_STACK_TRACE eng "At line %u in %s" +ER_COMPRESSED_COLUMN_USED_AS_KEY + eng "Compressed column '%-.192s' can't be used in key specification" +ER_UNKNOWN_COMPRESSION_METHOD + eng "Unknown compression method: %s" diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 6e21d6249ab..c99ad088e9f 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "my_global.h" +#include "mariadb.h" #include <signal.h> //#include "sys_vars.h" @@ -163,7 +163,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) "where mysqld died. If you see no messages after this, something went\n" "terribly wrong...\n"); my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, - (ulong)my_thread_stack_size); + (ulong)my_thread_stack_size, 0); } if (thd) { diff --git a/sql/slave.cc b/sql/slave.cc index 86675b4f19c..46932e36e95 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -25,7 +25,7 @@ replication slave. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "slave.h" #include "sql_parse.h" // execute_init_command @@ -60,6 +60,7 @@ #include "rpl_tblmap.h" #include "debug_sync.h" #include "rpl_parallel.h" +#include "sql_show.h" #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -279,15 +280,180 @@ static void init_slave_psi_keys(void) #endif /* HAVE_PSI_INTERFACE */ +/* + Note: This definition needs to be kept in sync with the one in + mysql_system_tables.sql which is used by mysql_create_db. +*/ +static const char gtid_pos_table_definition1[]= + "CREATE TABLE "; +static const char gtid_pos_table_definition2[]= + " (domain_id INT UNSIGNED NOT NULL, " + "sub_id BIGINT UNSIGNED NOT NULL, " + "server_id INT UNSIGNED NOT NULL, " + "seq_no BIGINT UNSIGNED NOT NULL, " + "PRIMARY KEY (domain_id, sub_id)) CHARSET=latin1 " + "COMMENT='Replication slave GTID position' " + "ENGINE="; + +/* + Build a query string + CREATE TABLE mysql.gtid_slave_pos_<engine> ... ENGINE=<engine> +*/ +static bool +build_gtid_pos_create_query(THD *thd, String *query, + LEX_CSTRING *table_name, + LEX_CSTRING *engine_name) +{ + bool err= false; + err|= query->append(gtid_pos_table_definition1); + err|= append_identifier(thd, query, table_name->str, table_name->length); + err|= query->append(gtid_pos_table_definition2); + err|= append_identifier(thd, query, engine_name->str, engine_name->length); + return err; +} + + +static int +gtid_pos_table_creation(THD *thd, plugin_ref engine, LEX_CSTRING *table_name) +{ + int err; + StringBuffer<sizeof(gtid_pos_table_definition1) + + sizeof(gtid_pos_table_definition1) + + 2*FN_REFLEN> query; + + if (build_gtid_pos_create_query(thd, &query, table_name, plugin_name(engine))) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return 1; + } + + thd->set_db("mysql", 5); + thd->clear_error(); + ulonglong thd_saved_option= thd->variables.option_bits; + /* This query shuold not be binlogged. */ + thd->variables.option_bits&= ~(ulonglong)OPTION_BIN_LOG; + thd->set_query_and_id(query.c_ptr(), query.length(), thd->charset(), + next_query_id()); + Parser_state parser_state; + err= parser_state.init(thd, thd->query(), thd->query_length()); + if (err) + goto end; + mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, + FALSE, FALSE); + if (thd->is_error()) + err= 1; +end: + thd->variables.option_bits= thd_saved_option; + thd->reset_query(); + return err; +} + + +static void +handle_gtid_pos_auto_create_request(THD *thd, void *hton) +{ + int err; + plugin_ref engine= NULL, *auto_engines; + rpl_slave_state::gtid_pos_table *entry; + StringBuffer<FN_REFLEN> loc_table_name; + LEX_CSTRING table_name; + + /* + Check that the plugin is still in @@gtid_pos_auto_engines, and lock + it. + */ + mysql_mutex_lock(&LOCK_global_system_variables); + engine= NULL; + for (auto_engines= opt_gtid_pos_auto_plugins; + auto_engines && *auto_engines; + ++auto_engines) + { + if (plugin_hton(*auto_engines) == hton) + { + engine= my_plugin_lock(NULL, *auto_engines); + break; + } + } + mysql_mutex_unlock(&LOCK_global_system_variables); + if (!engine) + { + /* The engine is gone from @@gtid_pos_auto_engines, so no action. */ + goto end; + } + + /* Find the entry for the table to auto-create. */ + mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); + entry= (rpl_slave_state::gtid_pos_table *) + rpl_global_gtid_slave_state->gtid_pos_tables; + while (entry) + { + if (entry->table_hton == hton && + entry->state == rpl_slave_state::GTID_POS_CREATE_REQUESTED) + break; + entry= entry->next; + } + if (entry) + { + entry->state = rpl_slave_state::GTID_POS_CREATE_IN_PROGRESS; + err= loc_table_name.append(entry->table_name.str, entry->table_name.length); + } + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + if (!entry) + goto end; + if (err) + { + sql_print_error("Out of memory while trying to auto-create GTID position table"); + goto end; + } + table_name.str= loc_table_name.c_ptr_safe(); + table_name.length= loc_table_name.length(); + + err= gtid_pos_table_creation(thd, engine, &table_name); + if (err) + { + sql_print_error("Error auto-creating GTID position table `mysql.%s`: %s Error_code: %d", + table_name.str, thd->get_stmt_da()->message(), + thd->get_stmt_da()->sql_errno()); + thd->clear_error(); + goto end; + } + + /* Now enable the entry for the auto-created table. */ + mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); + entry= (rpl_slave_state::gtid_pos_table *) + rpl_global_gtid_slave_state->gtid_pos_tables; + while (entry) + { + if (entry->table_hton == hton && + entry->state == rpl_slave_state::GTID_POS_CREATE_IN_PROGRESS) + { + entry->state= rpl_slave_state::GTID_POS_AVAILABLE; + break; + } + entry= entry->next; + } + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + +end: + if (engine) + plugin_unlock(NULL, engine); +} + + static bool slave_background_thread_running; static bool slave_background_thread_stop; static bool slave_background_thread_gtid_loaded; -struct slave_background_kill_t { +static struct slave_background_kill_t { slave_background_kill_t *next; THD *to_kill; } *slave_background_kill_list; +static struct slave_background_gtid_pos_create_t { + slave_background_gtid_pos_create_t *next; + void *hton; +} *slave_background_gtid_pos_create_list; + pthread_handler_t handle_slave_background(void *arg __attribute__((unused))) @@ -321,6 +487,7 @@ handle_slave_background(void *arg __attribute__((unused))) do { slave_background_kill_t *kill_list; + slave_background_gtid_pos_create_t *create_list; thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background, &stage_slave_background_wait_request, @@ -329,12 +496,14 @@ handle_slave_background(void *arg __attribute__((unused))) { stop= abort_loop || thd->killed || slave_background_thread_stop; kill_list= slave_background_kill_list; - if (stop || kill_list) + create_list= slave_background_gtid_pos_create_list; + if (stop || kill_list || create_list) break; mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); } slave_background_kill_list= NULL; + slave_background_gtid_pos_create_list= NULL; thd->EXIT_COND(&old_stage); while (kill_list) @@ -353,6 +522,16 @@ handle_slave_background(void *arg __attribute__((unused))) mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready); my_free(p); } + + while (create_list) + { + slave_background_gtid_pos_create_t *next= create_list->next; + void *hton= create_list->hton; + handle_gtid_pos_auto_create_request(thd, hton); + my_free(create_list); + create_list= next; + } + mysql_mutex_lock(&LOCK_slave_background); } while (!stop); @@ -392,6 +571,41 @@ slave_background_kill_request(THD *to_kill) /* + This function must only be called from a slave SQL thread (or worker thread), + to ensure that the table_entry will not go away before we can lock the + LOCK_slave_state. +*/ +void +slave_background_gtid_pos_create_request( + rpl_slave_state::gtid_pos_table *table_entry) +{ + slave_background_gtid_pos_create_t *p; + + if (table_entry->state != rpl_slave_state::GTID_POS_AUTO_CREATE) + return; + p= (slave_background_gtid_pos_create_t *)my_malloc(sizeof(*p), MYF(MY_WME)); + if (!p) + return; + mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); + if (table_entry->state != rpl_slave_state::GTID_POS_AUTO_CREATE) + { + my_free(p); + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + return; + } + table_entry->state= rpl_slave_state::GTID_POS_CREATE_REQUESTED; + mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state); + + p->hton= table_entry->table_hton; + mysql_mutex_lock(&LOCK_slave_background); + p->next= slave_background_gtid_pos_create_list; + slave_background_gtid_pos_create_list= p; + mysql_cond_signal(&COND_slave_background); + mysql_mutex_unlock(&LOCK_slave_background); +} + + +/* Start the slave background thread. This thread is currently used for two purposes: @@ -3164,6 +3378,13 @@ void set_slave_thread_options(THD* thd) options&= ~OPTION_BIN_LOG; thd->variables.option_bits= options; thd->variables.completion_type= 0; + + /* For easier test in LOGGER::log_command */ + if (thd->variables.log_disabled_statements & LOG_DISABLE_SLAVE) + thd->variables.option_bits|= OPTION_LOG_OFF; + + thd->variables.sql_log_slow= !MY_TEST(thd->variables.log_slow_disabled_statements & + LOG_SLOW_DISABLE_SLAVE); DBUG_VOID_RETURN; } @@ -3210,8 +3431,7 @@ static int init_slave_thread(THD* thd, Master_info *mi, thd->security_ctx->skip_grants(); thd->slave_thread= 1; thd->connection_name= mi->connection_name; - thd->variables.sql_log_slow= opt_log_slow_slave_statements; - thd->variables.log_slow_filter= global_system_variables.log_slow_filter; + thd->variables.sql_log_slow= !MY_TEST(thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE); set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; @@ -5066,6 +5286,14 @@ pthread_handler_t handle_slave_sql(void *arg) if (mi->using_gtid != Master_info::USE_GTID_NO || opt_gtid_strict_mode) goto err; } + /* Re-load the set of mysql.gtid_slave_posXXX tables available. */ + if (find_gtid_slave_pos_tables(thd)) + { + rli->report(ERROR_LEVEL, thd->get_stmt_da()->sql_errno(), NULL, + "Error processing replication GTID position tables: %s", + thd->get_stmt_da()->message()); + goto err; + } /* execute init_slave variable */ if (opt_init_slave.length) diff --git a/sql/slave.h b/sql/slave.h index 431e6847abe..c856a6989ed 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -48,6 +48,7 @@ #include "my_list.h" #include "rpl_filter.h" #include "rpl_tblmap.h" +#include "rpl_gtid.h" #define SLAVE_NET_TIMEOUT 60 @@ -268,6 +269,8 @@ void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); void slave_background_kill_request(THD *to_kill); +void slave_background_gtid_pos_create_request + (rpl_slave_state::gtid_pos_table *table_entry); extern bool volatile abort_loop; extern Master_info *active_mi; /* active_mi for multi-master */ diff --git a/sql/sp.cc b/sql/sp.cc index c8b9e02076b..e2884f49d99 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sp.h" @@ -1558,7 +1558,7 @@ bool lock_db_routines(THD *thd, const char *db) uchar keybuf[MAX_KEY_LENGTH]; DBUG_ENTER("lock_db_routines"); - DBUG_ASSERT(ok_for_lower_case_names(db)); + DBUG_SLOW_ASSERT(ok_for_lower_case_names(db)); /* mysql.proc will be re-opened during deletion, so we can ignore diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 70ba5084914..342673bf619 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #ifdef USE_PRAGMA_IMPLEMENTATION diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 51886a61ee9..a045ff5d3c5 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -21,8 +21,6 @@ #pragma interface /* gcc class implementation */ #endif -#include "my_global.h" /* ulong */ - /* Stored procedures/functions cache. This is used as follows: * Each thread has its own cache. diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 645703d78a4..0bc269c414c 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_prepare.h" @@ -1590,9 +1590,8 @@ sp_head::execute_trigger(THD *thd, goto err_with_cleanup; } -#ifndef DBUG_OFF + /* Needed by slow log */ nctx->sp= this; -#endif thd->spcont= nctx; @@ -1714,9 +1713,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, */ thd->restore_active_arena(&call_arena, &backup_arena); -#ifndef DBUG_OFF + /* Needed by slow log */ nctx->sp= this; -#endif /* Pass arguments. */ for (arg_no= 0; arg_no < argcount; arg_no++) @@ -1920,9 +1918,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) DBUG_RETURN(TRUE); } -#ifndef DBUG_OFF octx->sp= 0; -#endif thd->spcont= octx; /* set callers_arena to thd, for upper-level function to work */ @@ -1935,9 +1931,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) thd->spcont= save_spcont; DBUG_RETURN(TRUE); } -#ifndef DBUG_OFF nctx->sp= this; -#endif if (params > 0) { @@ -2034,13 +2028,32 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length, m_name.str)); } + save_enable_slow_log= thd->enable_slow_log; - if (!(m_flags & LOG_SLOW_STATEMENTS) && save_enable_slow_log) + + /* + Disable slow log if: + - Slow logging is enabled (no change needed) + - This is a normal SP (not event log) + - If we have not explicitely disabled logging of SP + */ + if (save_enable_slow_log && + ((!(m_flags & LOG_SLOW_STATEMENTS) && + (thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SP)))) { DBUG_PRINT("info", ("Disabling slow log for the execution")); thd->enable_slow_log= FALSE; } - if (!(m_flags & LOG_GENERAL_LOG) && !(thd->variables.option_bits & OPTION_LOG_OFF)) + + /* + Disable general log if: + - If general log is enabled (no change needed) + - This is a normal SP (not event log) + - If we have not explicitely disabled logging of SP + */ + if (!(thd->variables.option_bits & OPTION_LOG_OFF) && + (!(m_flags & LOG_GENERAL_LOG) && + (thd->variables.log_disabled_statements & LOG_DISABLE_SP))) { DBUG_PRINT("info", ("Disabling general log for the execution")); save_log_general= true; @@ -2082,6 +2095,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) if (save_log_general) thd->variables.option_bits &= ~OPTION_LOG_OFF; thd->enable_slow_log= save_enable_slow_log; + /* In the case when we weren't able to employ reuse mechanism for OUT/INOUT paranmeters, we should reallocate memory. This @@ -2336,9 +2350,7 @@ sp_head::backpatch_goto(THD *thd, sp_label *lab,sp_label *lab_begin_block) */ continue; } - if (my_strcasecmp(system_charset_info, - bp->lab->name.str, - lab->name.str) == 0) + if (lex_string_cmp(system_charset_info, &bp->lab->name, &lab->name) == 0) { if (bp->instr_type == GOTO) { @@ -3243,14 +3255,29 @@ int sp_instr_stmt::execute(THD *thd, uint *nextp) { int res; + bool save_enable_slow_log; + const CSET_STRING query_backup= thd->query_string; + QUERY_START_TIME_INFO time_info; + Sub_statement_state backup_state; DBUG_ENTER("sp_instr_stmt::execute"); DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command())); - const CSET_STRING query_backup= thd->query_string; #if defined(ENABLED_PROFILING) /* This s-p instr is profilable and will be captured. */ thd->profiling.set_query_source(m_query.str, m_query.length); #endif + + if ((save_enable_slow_log= thd->enable_slow_log)) + { + /* + Save start time info for the CALL statement and overwrite it with the + current time for log_slow_statement() to log the individual query timing. + */ + thd->get_time(&time_info); + thd->set_time(); + } + thd->store_slow_query_state(&backup_state); + if (!(res= alloc_query(thd, m_query.str, m_query.length)) && !(res=subst_spvars(thd, this, &m_query))) { @@ -3263,6 +3290,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) if (query_cache_send_result_to_client(thd, thd->query(), thd->query_length()) <= 0) { + thd->reset_slow_query_state(); res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); bool log_slow= !res && thd->enable_slow_log; @@ -3282,6 +3310,15 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) if (log_slow) log_slow_statement(thd); + + /* + Restore enable_slow_log, that can be changed by a admin or call + command + */ + thd->enable_slow_log= save_enable_slow_log; + + /* Add the number of rows to thd for the 'call' statistics */ + thd->add_slow_query_state(&backup_state); } else { @@ -3302,6 +3339,10 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) thd->get_stmt_da()->reset_diagnostics_area(); } } + /* Restore the original query start time */ + if (thd->enable_slow_log) + thd->set_time(&time_info); + DBUG_RETURN(res || thd->is_error()); } @@ -3404,7 +3445,7 @@ sp_instr_set::print(String *str) str->qs_append(STRING_WITH_LEN("set ")); if (var) { - str->qs_append(var->name.str, var->name.length); + str->qs_append(&var->name); str->qs_append('@'); } str->qs_append(m_offset); @@ -3450,9 +3491,9 @@ sp_instr_set_row_field::print(String *str) if (str->reserve(rsrv)) return; str->qs_append(STRING_WITH_LEN("set ")); - str->qs_append(var->name.str, var->name.length); + str->qs_append(&var->name); str->qs_append('.'); - str->qs_append(def->field_name.str, def->field_name.length); + str->qs_append(&def->field_name); str->qs_append('@'); str->qs_append(m_offset); str->qs_append('['); @@ -3508,13 +3549,13 @@ sp_instr_set_row_field_by_name::print(String *str) if (str->reserve(rsrv)) return; str->qs_append(STRING_WITH_LEN("set ")); - str->qs_append(var->name.str, var->name.length); + str->qs_append(&var->name); str->qs_append('.'); - str->qs_append(m_field_name.str, m_field_name.length); + str->qs_append(&m_field_name); str->qs_append('@'); str->qs_append(m_offset); str->qs_append("[\"",2); - str->qs_append(m_field_name.str, m_field_name.length); + str->qs_append(&m_field_name); str->qs_append("\"]",2); str->qs_append(' '); m_value->print(str, enum_query_type(QT_ORDINARY | @@ -4167,7 +4208,7 @@ sp_instr_cfetch::print(String *str) if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) return; str->qs_append(' '); - str->qs_append(pv->name.str, pv->name.length); + str->qs_append(&pv->name); str->qs_append('@'); str->qs_append(pv->offset); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 272bc5d445c..c3ace46a789 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -27,7 +27,6 @@ are dependencies on include order for set_var.h and item.h. This will be resolved later. */ -#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_class.h" // THD, set_var.h: THD #include "set_var.h" // Item #include "sp_pcontext.h" // sp_pcontext diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index d98f8005945..1e2081e3479 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #ifdef USE_PRAGMA_IMPLEMENTATION @@ -132,8 +132,8 @@ sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope) bool cmp_labels(sp_label *a, sp_label *b) { - return (my_strcasecmp(system_charset_info, a->name.str, b->name.str) == 0 - && a->type == b->type); + return (lex_string_cmp(system_charset_info, &a->name, &b->name) == 0 && + a->type == b->type); } sp_pcontext *sp_pcontext::pop_context() @@ -304,7 +304,7 @@ sp_label *sp_pcontext::find_goto_label(const LEX_CSTRING *name, bool recusive) while ((lab= li++)) { - if (my_strcasecmp(system_charset_info, name->str, lab->name.str) == 0) + if (lex_string_cmp(system_charset_info, name, &lab->name) == 0) return lab; } @@ -341,7 +341,7 @@ sp_label *sp_pcontext::find_label(const LEX_CSTRING *name) while ((lab= li++)) { - if (my_strcasecmp(system_charset_info, name->str, lab->name.str) == 0) + if (lex_string_cmp(system_charset_info, name, &lab->name) == 0) return lab; } @@ -416,6 +416,7 @@ static sp_condition_value // Errors cond_invalid_cursor(ER_SP_CURSOR_NOT_OPEN, "24000"), cond_dup_val_on_index(ER_DUP_ENTRY, "23000"), + cond_dup_val_on_index2(ER_DUP_ENTRY_WITH_KEY_NAME, "23000"), cond_too_many_rows(ER_TOO_MANY_ROWS, "42000"); @@ -426,6 +427,7 @@ static sp_condition sp_predefined_conditions[]= // Errors sp_condition(C_STRING_WITH_LEN("INVALID_CURSOR"), &cond_invalid_cursor), sp_condition(C_STRING_WITH_LEN("DUP_VAL_ON_INDEX"), &cond_dup_val_on_index), + sp_condition(C_STRING_WITH_LEN("DUP_VAL_ON_INDEX"), &cond_dup_val_on_index2), sp_condition(C_STRING_WITH_LEN("TOO_MANY_ROWS"), &cond_too_many_rows) }; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 8290a927a77..70ab5a576b3 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #ifdef USE_PRAGMA_IMPLEMENTATION diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 9a4a8e27032..66df0359d28 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -177,11 +177,9 @@ public: /// of the client/server protocol. bool end_partial_result_set; -#ifndef DBUG_OFF /// The stored program for which this runtime context is created. Used for /// checking if correct runtime context is used for variable handling. sp_head *sp; -#endif ///////////////////////////////////////////////////////////////////////// // SP-variables. diff --git a/sql/spatial.cc b/sql/spatial.cc index 8817e82d6c4..8d595541eef 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "spatial.h" #include "gstream.h" // Gis_read_stream diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b0550fb5189..ae7dc336720 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -25,7 +25,7 @@ in the relevant fields. Empty strings comes last. */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_acl.h" // MYSQL_DB_FIELD_COUNT, ACL_ACCESS #include "sql_base.h" // close_mysql_tables @@ -1594,12 +1594,10 @@ static const char *fix_plugin_ptr(const char *name) */ static bool fix_user_plugin_ptr(ACL_USER *user) { - if (my_strcasecmp(system_charset_info, user->plugin.str, - native_password_plugin_name.str) == 0) + if (lex_string_eq(&user->plugin, &native_password_plugin_name) == 0) user->plugin= native_password_plugin_name; else - if (my_strcasecmp(system_charset_info, user->plugin.str, - old_password_plugin_name.str) == 0) + if (lex_string_eq(&user->plugin, &old_password_plugin_name) == 0) user->plugin= old_password_plugin_name; else return true; @@ -1639,12 +1637,10 @@ static bool fix_lex_user(THD *thd, LEX_USER *user) DBUG_ASSERT(user->plugin.length || !user->auth.length); DBUG_ASSERT(!(user->plugin.length && (user->pwtext.length || user->pwhash.length))); - if (my_strcasecmp(system_charset_info, user->plugin.str, - native_password_plugin_name.str) == 0) + if (lex_string_eq(&user->plugin, &native_password_plugin_name) == 0) check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; else - if (my_strcasecmp(system_charset_info, user->plugin.str, - old_password_plugin_name.str) == 0) + if (lex_string_eq(&user->plugin, &old_password_plugin_name) == 0) check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; else if (user->plugin.length) @@ -1832,7 +1828,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) { if (host_table.init_read_record(&read_record_info, thd)) DBUG_RETURN(true); - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { ACL_HOST host; update_hostname(&host.host, get_field(&acl_memroot, host_table.host())); @@ -1936,7 +1932,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) } allow_all_hosts=0; - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { ACL_USER user; bool is_role= FALSE; @@ -2148,7 +2144,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) const Db_table& db_table= tables.db_table(); if (db_table.init_read_record(&read_record_info, thd)) DBUG_RETURN(TRUE); - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { ACL_DB db; char *db_name; @@ -2215,7 +2211,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) { if (proxies_priv_table.init_read_record(&read_record_info, thd)) DBUG_RETURN(TRUE); - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { ACL_PROXY_USER proxy; proxy.init(proxies_priv_table, &acl_memroot); @@ -2244,7 +2240,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) MEM_ROOT temp_root; init_alloc_root(&temp_root, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { char *hostname= safe_str(get_field(&temp_root, roles_mapping_table.host())); char *username= safe_str(get_field(&temp_root, roles_mapping_table.user())); @@ -3175,7 +3171,7 @@ static void remove_ptr_from_dynarray(DYNAMIC_ARRAY *array, void *ptr) { DBUG_ASSERT(!found); delete_dynamic_element(array, i); - IF_DBUG(found= true, break); + IF_DBUG_ASSERT(found= true, break); } } DBUG_ASSERT(found); @@ -7584,10 +7580,18 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx; ulong orig_want_access= original_want_access; - if (t_ref->sequence) + /* + If sequence is used as part of NEXT VALUE, PREVIUS VALUE or SELECT, + we need to modify the requested access rights depending on how the + sequence is used. + */ + if (t_ref->sequence & + (orig_want_access & + (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL))) { - /* We want to have either SELECT or INSERT rights to sequences depending - on how they are accessed + /* + We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed */ orig_want_access= ((t_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? INSERT_ACL : SELECT_ACL); @@ -8381,18 +8385,18 @@ static void add_user_parameters(String *result, ACL_USER* acl_user, { DBUG_ASSERT(acl_user->salt_len); result->append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); - result->append(acl_user->auth_string.str, acl_user->auth_string.length); + result->append(&acl_user->auth_string); result->append('\''); } } else { result->append(STRING_WITH_LEN(" IDENTIFIED VIA ")); - result->append(acl_user->plugin.str, acl_user->plugin.length); + result->append(&acl_user->plugin); if (acl_user->auth_string.length) { result->append(STRING_WITH_LEN(" USING '")); - result->append(acl_user->auth_string.str, acl_user->auth_string.length); + result->append(&acl_user->auth_string); result->append('\''); } } @@ -11200,7 +11204,7 @@ applicable_roles_insert(ACL_USER_BASE *grantee, ACL_ROLE *role, void *ptr) if (!is_role) { if (data->user->default_rolename.length && - !strcmp(data->user->default_rolename.str, role->user.str)) + !lex_string_eq(&data->user->default_rolename, &role->user)) table->field[3]->store(STRING_WITH_LEN("YES"), cs); else table->field[3]->store(STRING_WITH_LEN("NO"), cs); @@ -12776,8 +12780,8 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, restarted and a server auth plugin will read the data that the client has just send. Cache them to return in the next server_mpvio_read_packet(). */ - if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str, - plugin_name(mpvio->plugin)->str) != 0) + if (lex_string_eq(&mpvio->acl_user->plugin, + plugin_name(mpvio->plugin)) != 0) { mpvio->cached_client_reply.pkt= passwd; mpvio->cached_client_reply.pkt_len= passwd_len; @@ -13207,8 +13211,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) { DBUG_ASSERT(mpvio.acl_user); DBUG_ASSERT(command == COM_CHANGE_USER || - my_strcasecmp(system_charset_info, auth_plugin_name->str, - mpvio.acl_user->plugin.str)); + lex_string_eq(auth_plugin_name, &mpvio.acl_user->plugin)); auth_plugin_name= &mpvio.acl_user->plugin; res= do_auth_once(thd, auth_plugin_name, &mpvio); } diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 6164c6fa57d..dacddd603dd 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "violite.h" /* SSL_type */ #include "sql_class.h" /* LEX_COLUMN */ diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 1e46fc44c5e..c81ca438bcc 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -14,7 +14,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "sql_class.h" // THD and my_global.h +#include "mariadb.h" +#include "sql_class.h" // THD #include "keycaches.h" // get_key_cache #include "sql_base.h" // Open_table_context #include "lock.h" // MYSQL_OPEN_* @@ -448,10 +449,11 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, int compl_result_code; bool need_repair_or_alter= 0; wait_for_commit* suspended_wfc; - DBUG_ENTER("mysql_admin_table"); DBUG_PRINT("enter", ("extra_open_options: %u", extra_open_options)); + thd->prepare_logs_for_admin_command(); + field_list.push_back(item= new (thd->mem_root) Item_empty_string(thd, "Table", NAME_CHAR_LEN * 2), thd->mem_root); @@ -809,7 +811,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Here we close and reopen table in read mode because operation of collecting statistics is long and it will be better do not block the table completely. - InnoDB/XtraDB will allow read/write and MyISAM read/insert. + InnoDB will allow read/write and MyISAM read/insert. */ trans_commit_stmt(thd); trans_commit(thd); @@ -1303,7 +1305,6 @@ bool Sql_cmd_analyze_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); - thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "analyze", lock_type, 1, 0, 0, 0, &handler::ha_analyze, 0); @@ -1334,7 +1335,6 @@ bool Sql_cmd_check_table::execute(THD *thd) if (check_table_access(thd, SELECT_ACL, first_table, TRUE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ - thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check", lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, @@ -1359,7 +1359,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); - thd->enable_slow_log= opt_log_slow_admin_statements; + res= (specialflag & SPECIAL_NO_NEW_FUNC) ? mysql_recreate_table(thd, first_table, true) : mysql_admin_table(thd, first_table, &m_lex->check_opt, @@ -1391,7 +1391,8 @@ bool Sql_cmd_repair_table::execute(THD *thd) if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ - thd->enable_slow_log= opt_log_slow_admin_statements; + thd->enable_slow_log&= !MY_TEST(thd->variables.log_slow_disabled_statements & + LOG_SLOW_DISABLE_ADMIN); WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair", TL_WRITE, 1, diff --git a/sql/sql_alloc.h b/sql/sql_alloc.h new file mode 100644 index 00000000000..4db12964f0a --- /dev/null +++ b/sql/sql_alloc.h @@ -0,0 +1,56 @@ +#ifndef SQL_ALLOC_INCLUDED +#define SQL_ALLOC_INCLUDED +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2017, MariaDB AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include <my_sys.h> /* alloc_root, MEM_ROOT, TRASH */ + +THD *thd_get_current_thd(); + +/* mysql standard class memory allocator */ + +class Sql_alloc +{ +public: + static void *operator new(size_t size) throw () + { + DBUG_ASSERT(size < UINT_MAX32); + return thd_alloc(thd_get_current_thd(), uint(size)); + } + static void *operator new[](size_t size) throw () + { + DBUG_ASSERT(size < UINT_MAX32); + return thd_alloc(thd_get_current_thd(), uint(size)); + } + static void *operator new[](size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } + static void operator delete(void *ptr, MEM_ROOT *mem_root) + { /* never called */ } + static void operator delete[](void *ptr, MEM_ROOT *mem_root) + { /* never called */ } + static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } +#ifdef HAVE_valgrind + bool dummy_for_valgrind; + inline Sql_alloc() :dummy_for_valgrind(0) {} +#else + inline Sql_alloc() {} +#endif + inline ~Sql_alloc() {} +}; +#endif /* SQL_ALLOC_INCLUDED */ diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 0194f26d217..3d1e4c0fa65 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mariadb.h" #include "sql_parse.h" // check_access #include "sql_table.h" // mysql_alter_table, // mysql_exchange_partition @@ -89,7 +90,7 @@ Alter_table_ctx::Alter_table_ctx() new_db(NULL), new_name(NULL), new_alias(NULL), fk_error_if_delete_row(false), fk_error_id(NULL), fk_error_table(NULL) -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS , tmp_table(false) #endif { @@ -109,7 +110,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list, new_db(new_db_arg), new_name(new_name_arg), fk_error_if_delete_row(false), fk_error_id(NULL), fk_error_table(NULL) -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS , tmp_table(false) #endif { @@ -186,7 +187,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list, this case. This fact is enforced with assert. */ build_tmptable_filename(thd, tmp_path, sizeof(tmp_path)); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS tmp_table= true; #endif } @@ -309,7 +310,7 @@ bool Sql_cmd_alter_table::execute(THD *thd) "INDEX DIRECTORY"); create_info.data_file_name= create_info.index_file_name= NULL; - thd->enable_slow_log= opt_log_slow_admin_statements; + thd->prepare_logs_for_admin_command(); #ifdef WITH_WSREP if ((!thd->is_current_stmt_binlog_format_row() || @@ -354,7 +355,7 @@ bool Sql_cmd_discard_import_tablespace::execute(THD *thd) if (check_grant(thd, ALTER_ACL, table_list, false, UINT_MAX, false)) return true; - thd->enable_slow_log= opt_log_slow_admin_statements; + thd->prepare_logs_for_admin_command(); /* Check if we attempt to alter mysql.slow_log or diff --git a/sql/sql_alter.h b/sql/sql_alter.h index c0232dd7358..a37d96934ea 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -331,7 +331,7 @@ private: char new_path[FN_REFLEN + 1]; char tmp_path[FN_REFLEN + 1]; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS /** Indicates that we are altering temporary table. Used only in asserts. */ bool tmp_table; #endif diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index d6af0410ad2..351ddb452d8 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -29,7 +29,7 @@ #define MYSQL_LEX 1 -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "procedure.h" #include "sql_analyse.h" @@ -298,9 +298,10 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num) } // get_ev_num_info -void free_string(String *s) +int free_string(String *s) { s->free(); + return 0; } @@ -374,7 +375,7 @@ void field_str::add() if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg)) { room_in_tree = 0; // Remove tree, out of RAM ? - delete_tree(&tree); + delete_tree(&tree, 0); } else { @@ -382,7 +383,7 @@ void field_str::add() if ((treemem += length) > pc->max_treemem) { room_in_tree = 0; // Remove tree, too big tree - delete_tree(&tree); + delete_tree(&tree, 0); } } } @@ -441,7 +442,7 @@ void field_real::add() if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? - delete_tree(&tree); + delete_tree(&tree, 0); } /* if element->count == 1, this element can be found only once from tree @@ -450,7 +451,7 @@ void field_real::add() else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements) { room_in_tree = 0; // Remove tree, too many elements - delete_tree(&tree); + delete_tree(&tree, 0); } } @@ -507,7 +508,7 @@ void field_decimal::add() if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? - delete_tree(&tree); + delete_tree(&tree, 0); } /* if element->count == 1, this element can be found only once from tree @@ -516,7 +517,7 @@ void field_decimal::add() else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements) { room_in_tree = 0; // Remove tree, too many elements - delete_tree(&tree); + delete_tree(&tree, 0); } } @@ -574,7 +575,7 @@ void field_longlong::add() if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? - delete_tree(&tree); + delete_tree(&tree, 0); } /* if element->count == 1, this element can be found only once from tree @@ -583,7 +584,7 @@ void field_longlong::add() else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements) { room_in_tree = 0; // Remove tree, too many elements - delete_tree(&tree); + delete_tree(&tree, 0); } } @@ -630,7 +631,7 @@ void field_ulonglong::add() if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? - delete_tree(&tree); + delete_tree(&tree, 0); } /* if element->count == 1, this element can be found only once from tree @@ -639,7 +640,7 @@ void field_ulonglong::add() else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements) { room_in_tree = 0; // Remove tree, too many elements - delete_tree(&tree); + delete_tree(&tree, 0); } } diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 820877f2a69..6704de4ed6d 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -68,7 +68,7 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)), int compare_decimal2(int* len, const char *s, const char *t); Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list); -void free_string(String*); +int free_string(String*); class analyse; class field_info :public Sql_alloc @@ -86,7 +86,7 @@ public: nulls(0), min_length(0), max_length(0), room_in_tree(1), found(0),item(a), pc(b) {}; - virtual ~field_info() { delete_tree(&tree); } + virtual ~field_info() { delete_tree(&tree, 0); } virtual void add() = 0; virtual void get_opt_type(String*, ha_rows) = 0; virtual String *get_min_arg(String *) = 0; diff --git a/sql/sql_analyze_stmt.cc b/sql/sql_analyze_stmt.cc index ac3797aae60..2c09772bd66 100644 --- a/sql/sql_analyze_stmt.cc +++ b/sql/sql_analyze_stmt.cc @@ -18,7 +18,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_select.h" #include "my_json_writer.h" diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index 8134adca13f..7c8b355b8d0 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_audit.h" diff --git a/sql/sql_audit.h b/sql/sql_audit.h index 96f9d0caece..7a11f5aa113 100644 --- a/sql/sql_audit.h +++ b/sql/sql_audit.h @@ -18,8 +18,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> - #include <mysql/plugin_audit.h> #include "sql_class.h" @@ -155,6 +153,7 @@ static inline void mysql_audit_general(THD *thd, uint event_subtype, int error_code, const char *msg) { + DBUG_ENTER("mysql_audit_general"); if (mysql_audit_general_enabled()) { char user_buff[MAX_USER_HOST_SIZE]; @@ -195,6 +194,7 @@ void mysql_audit_general(THD *thd, uint event_subtype, mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, &event); } + DBUG_VOID_RETURN; } static inline diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c0736130cfe..e59007d3e5a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -17,7 +17,7 @@ /* Basic functions needed by many modules */ -#include <my_global.h> +#include "mariadb.h" #include "sql_base.h" // setup_table_map #include "sql_priv.h" #include "unireg.h" @@ -1136,10 +1136,10 @@ void update_non_unique_table_error(TABLE_LIST *update, update->view == duplicate->view || update->view_name.length != duplicate->view_name.length || update->view_db.length != duplicate->view_db.length || - my_strcasecmp(table_alias_charset, - update->view_name.str, duplicate->view_name.str) != 0 || - my_strcasecmp(table_alias_charset, - update->view_db.str, duplicate->view_db.str) != 0) + lex_string_cmp(table_alias_charset, + &update->view_name, &duplicate->view_name) != 0 || + lex_string_cmp(table_alias_charset, + &update->view_db, &duplicate->view_db) != 0) { /* it is not the same view repeated (but it can be parts of the same copy @@ -6107,8 +6107,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, item is not fix_field()'ed yet. */ if (item_field->field_name.str && item_field->table_name && - !my_strcasecmp(system_charset_info, item_field->field_name.str, - field_name->str) && + !lex_string_cmp(system_charset_info, &item_field->field_name, + field_name) && !my_strcasecmp(table_alias_charset, item_field->table_name, table_name) && (!db_name || (item_field->db_name && @@ -6137,11 +6137,11 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, } else { - int fname_cmp= my_strcasecmp(system_charset_info, - item_field->field_name.str, - field_name->str); - if (!my_strcasecmp(system_charset_info, - item_field->name.str,field_name->str)) + bool fname_cmp= lex_string_cmp(system_charset_info, + &item_field->field_name, + field_name); + if (!lex_string_cmp(system_charset_info, + &item_field->name, field_name)) { /* If table name was not given we should scan through aliases @@ -6187,7 +6187,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, { if (is_ref_by_name && find->name.str && item->name.str && find->name.length == item->name.length && - !my_strcasecmp(system_charset_info,item->name.str, find->name.str)) + !lex_string_cmp(system_charset_info, &item->name, &find->name)) { found= li.ref(); *counter= i; @@ -6404,8 +6404,8 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, here. These columns must be checked only on unqualified reference by name (e.g. in SELECT list). */ - if (!my_strcasecmp(system_charset_info, field_name_1->str, - cur_field_name_2->str)) + if (!lex_string_cmp(system_charset_info, field_name_1, + cur_field_name_2)) { DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); if (cur_nj_col_2->is_common || @@ -8642,7 +8642,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_LOG); /* Make sure all columns get assigned to a default value */ table->use_all_columns(); - DBUG_ASSERT(table->no_replicate); + DBUG_ASSERT(table->s->no_replicate); } else thd->restore_backup_open_tables_state(backup); diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index f58bcf2e8fe..aa1a1cd6941 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_binlog.h" #include "sql_parse.h" diff --git a/sql/sql_bootstrap.cc b/sql/sql_bootstrap.cc index 4ef9885b34d..ce7d7a9fc93 100644 --- a/sql/sql_bootstrap.cc +++ b/sql/sql_bootstrap.cc @@ -14,7 +14,7 @@ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ -#include <my_global.h> +#include "mariadb.h" #include <ctype.h> #include <string.h> #include "sql_bootstrap.h" diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 7849e16a839..e09b1788441 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -328,7 +328,7 @@ TODO list: (This could be done with almost no speed penalty) */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_basic_types.h" #include "sql_cache.h" @@ -345,7 +345,6 @@ TODO list: #include "../storage/myisammrg/ha_myisammrg.h" #include "../storage/myisammrg/myrg_def.h" #include "probes_mysql.h" -#include "log_slow.h" #include "transaction.h" #include "strfunc.h" @@ -962,7 +961,7 @@ inline void Query_cache_query::unlock_reading() void Query_cache_query::init_n_lock() { DBUG_ENTER("Query_cache_query::init_n_lock"); - res=0; wri = 0; len = 0; ready= 0; + res=0; wri = 0; len = 0; ready= 0; hit_count = 0; mysql_rwlock_init(key_rwlock_query_cache_query_lock, &lock); lock_writing(); DBUG_PRINT("qcache", ("inited & locked query for block %p", @@ -2143,6 +2142,7 @@ lookup: } move_to_query_list_end(query_block); hits++; + query->increment_hits(); unlock(); /* @@ -2341,7 +2341,7 @@ void Query_cache::invalidate(THD *thd, const char *db) if (is_disabled()) DBUG_VOID_RETURN; - DBUG_ASSERT(ok_for_lower_case_names(db)); + DBUG_SLOW_ASSERT(ok_for_lower_case_names(db)); bool restart= FALSE; /* @@ -4049,41 +4049,35 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, tables_used->view_name.str, tables_used->view_db.str)); *tables_type|= HA_CACHE_TBL_NONTRANSACT; + continue; } - else + if (tables_used->derived) { - if (tables_used->derived) - { - DBUG_PRINT("qcache", ("table: %s", tables_used->alias)); - table_count--; - DBUG_PRINT("qcache", ("derived table skipped")); - continue; - } - DBUG_PRINT("qcache", ("table: %s db: %s type: %u", - tables_used->table->s->table_name.str, - tables_used->table->s->db.str, - tables_used->table->s->db_type()->db_type)); - *tables_type|= tables_used->table->file->table_cache_type(); + DBUG_PRINT("qcache", ("table: %s", tables_used->alias)); + table_count--; + DBUG_PRINT("qcache", ("derived table skipped")); + continue; + } - /* - table_alias_charset used here because it depends of - lower_case_table_names variable - */ - table_count+= tables_used->table->file-> - count_query_cache_dependant_tables(tables_type); - - if (tables_used->table->s->tmp_table != NO_TMP_TABLE || - (*tables_type & HA_CACHE_TBL_NOCACHE) || - (tables_used->db_length == 5 && - my_strnncoll(table_alias_charset, - (uchar*)tables_used->table->s->table_cache_key.str, 6, - (uchar*)"mysql",6) == 0)) - { - DBUG_PRINT("qcache", - ("select not cacheable: temporary, system or " - "other non-cacheable table(s)")); - DBUG_RETURN(0); - } + DBUG_PRINT("qcache", ("table: %s db: %s type: %u", + tables_used->table->s->table_name.str, + tables_used->table->s->db.str, + tables_used->table->s->db_type()->db_type)); + *tables_type|= tables_used->table->file->table_cache_type(); + + /* + table_alias_charset used here because it depends of + lower_case_table_names variable + */ + table_count+= tables_used->table->file-> + count_query_cache_dependant_tables(tables_type); + + if (tables_used->table->s->not_usable_by_query_cache) + { + DBUG_PRINT("qcache", + ("select not cacheable: temporary, system or " + "other non-cacheable table(s)")); + DBUG_RETURN(0); } } DBUG_RETURN(table_count); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 07a80f778b8..a6592e9b782 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -159,6 +159,7 @@ struct Query_cache_query unsigned int last_pkt_nr; uint8 tbls_type; uint8 ready; + ulonglong hit_count; Query_cache_query() {} /* Remove gcc warning */ inline void init_n_lock(); @@ -184,6 +185,8 @@ struct Query_cache_query */ inline void set_results_ready() { ready= 1; } inline bool is_results_ready() { return ready; } + inline void increment_hits() { hit_count++; } + inline ulong hits() { return hit_count; } void lock_writing(); void lock_reading(); bool try_lock_writing(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b40ee63fac6..5c8a378eacd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -28,7 +28,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" #include "sql_priv.h" #include "sql_class.h" #include "sql_cache.h" // query_cache_abort @@ -121,8 +121,8 @@ extern "C" void free_sequence_last(SEQUENCE_LAST_VALUE *entry) bool Key_part_spec::operator==(const Key_part_spec& other) const { return length == other.length && - !my_strcasecmp(system_charset_info, field_name.str, - other.field_name.str); + !lex_string_cmp(system_charset_info, &field_name, + &other.field_name); } /** @@ -249,9 +249,9 @@ bool Foreign_key::validate(List<Create_field> &table_fields) { it.rewind(); while ((sql_field= it++) && - my_strcasecmp(system_charset_info, - column->field_name.str, - sql_field->field_name.str)) {} + lex_string_cmp(system_charset_info, + &column->field_name, + &sql_field->field_name)) {} if (!sql_field) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str); @@ -839,7 +839,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) enable_slow_log= 0; durability_property= HA_REGULAR_DURABILITY; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS dbug_sentry=THD_SENTRY_MAGIC; #endif mysql_audit_init_thd(this); @@ -1647,7 +1647,7 @@ THD::~THD() mysql_mutex_destroy(&LOCK_wakeup_ready); mysql_mutex_destroy(&LOCK_thd_data); mysql_mutex_destroy(&LOCK_thd_kill); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS dbug_sentry= THD_SENTRY_GONE; #endif #ifndef EMBEDDED_LIBRARY @@ -2067,6 +2067,23 @@ int THD::killed_errno() } +void THD::reset_killed() +{ + /* + Resetting killed has to be done under a mutex to ensure + its not done during an awake() call. + */ + DBUG_ENTER("reset_killed"); + if (killed != NOT_KILLED) + { + mysql_mutex_lock(&LOCK_thd_kill); + killed= NOT_KILLED; + killed_err= 0; + mysql_mutex_unlock(&LOCK_thd_kill); + } + DBUG_VOID_RETURN; +} + /* Remember the location of thread info, the structure needed for the structure for the net buffer @@ -3717,7 +3734,7 @@ void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup) backup->set_query_arena(this); set_query_arena(set); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS backup->is_backup_arena= TRUE; #endif DBUG_VOID_RETURN; @@ -3736,7 +3753,7 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup) DBUG_ASSERT(backup->is_backup_arena); set->set_query_arena(this); set_query_arena(backup); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS backup->is_backup_arena= FALSE; #endif DBUG_VOID_RETURN; @@ -4630,7 +4647,6 @@ void destroy_thd(MYSQL_THD thd) thd->add_status_to_global(); unlink_not_visible_thd(thd); delete thd; - dec_thread_running(); } void reset_thd(MYSQL_THD thd) @@ -4741,7 +4757,7 @@ thd_need_wait_reports(const MYSQL_THD thd) } /* - Used by storage engines (currently TokuDB and InnoDB/XtraDB) to report that + Used by storage engines (currently TokuDB and InnoDB) to report that one transaction THD is about to go to wait for a transactional lock held by another transactions OTHER_THD. @@ -4763,7 +4779,7 @@ thd_need_wait_reports(const MYSQL_THD thd) transaction, and later re-try it, to resolve the deadlock. This call need only receive reports about waits for locks that will remain - until the holding transaction commits. InnoDB/XtraDB auto-increment locks, + until the holding transaction commits. InnoDB auto-increment locks, for example, are released earlier, and so need not be reported. (Such false positives are not harmful, but could lead to unnecessary kill and retry, so best avoided). @@ -4816,7 +4832,7 @@ thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd) } /* - This function is called from InnoDB/XtraDB to check if the commit order of + This function is called from InnoDB to check if the commit order of two transactions has already been decided by the upper layer. This happens in parallel replication, where the commit order is forced to be the same on the slave as it was originally on the master. @@ -4846,7 +4862,7 @@ thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd) If this function returns true, normal locking should be done as required by the binlogging and transaction isolation level in effect. But if it returns - false, the correct order will be enforced anyway, and InnoDB/XtraDB can + false, the correct order will be enforced anyway, and InnoDB can avoid taking the gap lock, preventing the lock conflict. Calling this function is just an optimisation to avoid unnecessary @@ -5128,10 +5144,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, backup->count_cuted_fields= count_cuted_fields; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; - backup->query_plan_flags= query_plan_flags; backup->limit_found_rows= limit_found_rows; - backup->examined_row_count= m_examined_row_count; - backup->sent_row_count= m_sent_row_count; backup->cuted_fields= cuted_fields; backup->client_capabilities= client_capabilities; backup->savepoints= transaction.savepoints; @@ -5139,6 +5152,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, first_successful_insert_id_in_prev_stmt; backup->first_successful_insert_id_in_cur_stmt= first_successful_insert_id_in_cur_stmt; + store_slow_query_state(backup); if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) && !is_current_stmt_binlog_format_row()) @@ -5154,14 +5168,12 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, /* Disable result sets */ client_capabilities &= ~CLIENT_MULTI_RESULTS; in_sub_stmt|= new_state; - m_examined_row_count= 0; - m_sent_row_count= 0; cuted_fields= 0; transaction.savepoints= 0; first_successful_insert_id_in_cur_stmt= 0; + reset_slow_query_state(); } - void THD::restore_sub_statement_state(Sub_statement_state *backup) { DBUG_ENTER("THD::restore_sub_statement_state"); @@ -5196,7 +5208,6 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) variables.option_bits= backup->option_bits; in_sub_stmt= backup->in_sub_stmt; enable_slow_log= backup->enable_slow_log; - query_plan_flags= backup->query_plan_flags; first_successful_insert_id_in_prev_stmt= backup->first_successful_insert_id_in_prev_stmt; first_successful_insert_id_in_cur_stmt= @@ -5204,6 +5215,10 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) limit_found_rows= backup->limit_found_rows; set_sent_row_count(backup->sent_row_count); client_capabilities= backup->client_capabilities; + + /* Restore statistic needed for slow log */ + add_slow_query_state(backup); + /* If we've left sub-statement mode, reset the fatal error flag. Otherwise keep the current value, to propagate it up the sub-statement @@ -5228,6 +5243,56 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) DBUG_VOID_RETURN; } +/* + Store slow query state at start of a stored procedure statment +*/ + +void THD::store_slow_query_state(Sub_statement_state *backup) +{ + backup->affected_rows= affected_rows; + backup->bytes_sent_old= bytes_sent_old; + backup->examined_row_count= m_examined_row_count; + backup->query_plan_flags= query_plan_flags; + backup->query_plan_fsort_passes= query_plan_fsort_passes; + backup->sent_row_count= m_sent_row_count; + backup->tmp_tables_disk_used= tmp_tables_disk_used; + backup->tmp_tables_size= tmp_tables_size; + backup->tmp_tables_used= tmp_tables_used; +} + +/* Reset variables related to slow query log */ + +void THD::reset_slow_query_state() +{ + affected_rows= 0; + bytes_sent_old= status_var.bytes_sent; + m_examined_row_count= 0; + m_sent_row_count= 0; + query_plan_flags= QPLAN_INIT; + query_plan_fsort_passes= 0; + tmp_tables_disk_used= 0; + tmp_tables_size= 0; + tmp_tables_used= 0; +} + +/* + Add back the stored values to the current counters to be able to get + right status for 'call procedure_name' +*/ + +void THD::add_slow_query_state(Sub_statement_state *backup) +{ + affected_rows+= backup->affected_rows; + bytes_sent_old= backup->bytes_sent_old; + m_examined_row_count+= backup->examined_row_count; + m_sent_row_count+= backup->sent_row_count; + query_plan_flags|= backup->query_plan_flags; + query_plan_fsort_passes+= backup->query_plan_fsort_passes; + tmp_tables_disk_used+= backup->tmp_tables_disk_used; + tmp_tables_size+= backup->tmp_tables_size; + tmp_tables_used+= backup->tmp_tables_used; +} + void THD::set_statement(Statement *stmt) { @@ -5262,6 +5327,8 @@ void THD::inc_examined_row_count(ha_rows count) void THD::inc_status_created_tmp_disk_tables() { + tmp_tables_disk_used++; + query_plan_flags|= QPLAN_TMP_DISK; status_var_increment(status_var.created_tmp_disk_tables_); #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_created_tmp_disk_tables)(m_statement_psi, 1); @@ -5270,6 +5337,8 @@ void THD::inc_status_created_tmp_disk_tables() void THD::inc_status_created_tmp_tables() { + tmp_tables_used++; + query_plan_flags|= QPLAN_TMP_TABLE; status_var_increment(status_var.created_tmp_tables_); #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_created_tmp_tables)(m_statement_psi, 1); @@ -5926,7 +5995,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx", table->table_name, flags)); - if (table->table->no_replicate) + if (table->table->s->no_replicate) { /* The statement uses a table that is not replicated. @@ -6440,7 +6509,7 @@ CPP_UNNAMED_NS_START { DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr)); DBUG_ASSERT(m_ptr[s] != 0); - DBUG_ASSERT(m_alloc_checked == TRUE); + DBUG_SLOW_ASSERT(m_alloc_checked == TRUE); return m_ptr[s]; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 96a3cc3522f..bc72fc25a18 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -20,7 +20,6 @@ /* Classes in mysql */ -#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "dur_prop.h" #include <waiting_threads.h> #include "sql_const.h" @@ -38,6 +37,7 @@ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, THR_LOCK_INFO */ #include "thr_timer.h" #include "thr_malloc.h" +#include "log_slow.h" /* LOG_SLOW_DISABLE_... */ #include "sql_digest_stream.h" // sql_digest_state @@ -536,6 +536,8 @@ typedef struct system_variables ulonglong join_buff_space_limit; ulonglong log_slow_filter; ulonglong log_slow_verbosity; + ulonglong log_slow_disabled_statements; + ulonglong log_disabled_statements; ulonglong bulk_insert_buff_size; ulonglong join_buff_size; ulonglong sortbuff_size; @@ -554,6 +556,7 @@ typedef struct system_variables ha_rows max_join_size; ha_rows expensive_subquery_limit; ulong auto_increment_increment, auto_increment_offset; + ulong column_compression_zlib_strategy; ulong lock_wait_timeout; ulong join_cache_level; ulong max_allowed_packet; @@ -641,6 +644,7 @@ typedef struct system_variables my_bool sql_log_bin_off; my_bool binlog_annotate_row_events; my_bool binlog_direct_non_trans_update; + my_bool column_compression_zlib_wrap; plugin_ref table_plugin; plugin_ref tmp_table_plugin; @@ -691,6 +695,12 @@ typedef struct system_variables my_bool sequence_read_skip_cache; ulong threadpool_priority; + + uint idle_transaction_timeout; + uint idle_readonly_transaction_timeout; + uint idle_write_transaction_timeout; + uint column_compression_threshold; + uint column_compression_zlib_level; } SV; /** @@ -701,6 +711,8 @@ typedef struct system_variables typedef struct system_status_var { + ulong column_compressions; + ulong column_decompressions; ulong com_stat[(uint) SQLCOM_END]; ulong com_create_tmp_table; ulong com_drop_tmp_table; @@ -891,7 +903,7 @@ void free_tmp_table(THD *thd, TABLE *entry); /* The following macro is to make init of Query_arena simpler */ -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS #define INIT_ARENA_DBUG_INFO is_backup_arena= 0; is_reprepared= FALSE; #else #define INIT_ARENA_DBUG_INFO @@ -906,7 +918,7 @@ public: */ Item *free_list; MEM_ROOT *mem_root; // Pointer to current memroot -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS bool is_backup_arena; /* True if this arena is used for backup. */ bool is_reprepared; #endif @@ -1513,19 +1525,25 @@ public: class Sub_statement_state { public: + Discrete_interval auto_inc_interval_for_cur_row; + Discrete_intervals_list auto_inc_intervals_forced; + SAVEPOINT *savepoints; ulonglong option_bits; ulonglong first_successful_insert_id_in_prev_stmt; ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row; - Discrete_interval auto_inc_interval_for_cur_row; - Discrete_intervals_list auto_inc_intervals_forced; ulonglong limit_found_rows; - ha_rows cuted_fields, sent_row_count, examined_row_count; + ulonglong tmp_tables_size; ulonglong client_capabilities; + ulonglong cuted_fields, sent_row_count, examined_row_count; + ulonglong affected_rows; + ulonglong bytes_sent_old; + ulong tmp_tables_used; + ulong tmp_tables_disk_used; + ulong query_plan_fsort_passes; ulong query_plan_flags; uint in_sub_stmt; /* 0, SUB_STMT_TRIGGER or SUB_STMT_FUNCTION */ bool enable_slow_log; bool last_insert_id_used; - SAVEPOINT *savepoints; enum enum_check_fields count_cuted_fields; }; @@ -2016,6 +2034,16 @@ struct wait_for_commit void reinit(); }; +/* + Structure to store the start time for a query +*/ + +typedef struct +{ + my_time_t start_time; + ulong start_time_sec_part; + ulonglong start_utime, utime_after_lock; +} QUERY_START_TIME_INFO; extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); @@ -2236,7 +2264,7 @@ public: HASH ull_hash; /* Hash of used seqeunces (for PREVIOUS value) */ HASH sequences; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS uint dbug_sentry; // watch out for memory corruption #endif struct st_my_thread_var *mysys_var; @@ -2717,6 +2745,14 @@ public: { m_row_count_func= row_count_func; } + inline void set_affected_rows(longlong row_count_func) + { + /* + We have to add to affected_rows (used by slow log), as otherwise + information for 'call' will be wrong + */ + affected_rows+= (row_count_func >= 0 ? row_count_func : 0); + } ha_rows cuted_fields; @@ -2746,6 +2782,9 @@ public: ha_rows get_examined_row_count() const { return m_examined_row_count; } + ulonglong get_affected_rows() const + { return affected_rows; } + void set_sent_row_count(ha_rows count); void set_examined_row_count(ha_rows count); @@ -2823,8 +2862,16 @@ public: /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; + + /* The following variables are used when printing to slow log */ ulong query_plan_flags; ulong query_plan_fsort_passes; + ulong tmp_tables_used; + ulong tmp_tables_disk_used; + ulonglong tmp_tables_size; + ulonglong bytes_sent_old; + ulonglong affected_rows; /* Number of changed rows */ + pthread_t real_id; /* For debugging */ my_thread_id thread_id, thread_dbug_id; uint32 os_thread_id; @@ -2914,7 +2961,6 @@ public: uint8 failed_com_change_user; bool slave_thread; bool extra_port; /* If extra connection */ - bool no_errors; /** @@ -2958,7 +3004,7 @@ public: */ bool charset_is_system_charset, charset_is_collation_connection; bool charset_is_character_set_filesystem; - bool enable_slow_log; /* enable slow log for current statement */ + bool enable_slow_log; /* Enable slow log for current statement */ bool abort_on_warning; bool got_warning; /* Set on call to push_warning() */ /* set during loop of derived table processing */ @@ -2990,6 +3036,7 @@ public: the query. 0 if no error on the master. */ int slave_expected_error; + enum_sql_command last_sql_command; // Last sql_command exceuted in mysql_execute_command() sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; @@ -3282,6 +3329,20 @@ public: MYSQL_SET_STATEMENT_LOCK_TIME(m_statement_psi, (utime_after_lock - start_utime)); } + void get_time(QUERY_START_TIME_INFO *time_info) + { + time_info->start_time= start_time; + time_info->start_time_sec_part= start_time_sec_part; + time_info->start_utime= start_utime; + time_info->utime_after_lock= utime_after_lock; + } + void set_time(QUERY_START_TIME_INFO *time_info) + { + start_time= time_info->start_time; + start_time_sec_part= time_info->start_time_sec_part; + start_utime= time_info->start_utime; + utime_after_lock= time_info->utime_after_lock; + } ulonglong current_utime() { return microsecond_interval_timer(); } /* Tell SHOW PROCESSLIST to show time from this point */ @@ -3300,7 +3361,7 @@ public: void update_server_status() { set_time_for_next_stage(); - if (utime_after_query > utime_after_lock + variables.long_query_time) + if (utime_after_query >= utime_after_lock + variables.long_query_time) server_status|= SERVER_QUERY_WAS_SLOW; } inline ulonglong found_rows(void) @@ -3408,17 +3469,31 @@ public: LEX_STRING *make_lex_string(const char* str, uint length) { LEX_STRING *lex_str; - if (!(lex_str= (LEX_STRING *)alloc_root(mem_root, sizeof(LEX_STRING)))) + char *tmp; + if (!(lex_str= (LEX_STRING *) alloc_root(mem_root, sizeof(LEX_STRING) + + length+1))) return 0; - return make_lex_string(lex_str, str, length); + tmp= (char*) (lex_str+1); + lex_str->str= tmp; + memcpy(tmp, str, length); + tmp[length]= 0; + lex_str->length= length; + return lex_str; } LEX_CSTRING *make_clex_string(const char* str, uint length) { LEX_CSTRING *lex_str; - if (!(lex_str= (LEX_CSTRING *)alloc_root(mem_root, sizeof(LEX_CSTRING)))) + char *tmp; + if (!(lex_str= (LEX_CSTRING *)alloc_root(mem_root, sizeof(LEX_CSTRING) + + length+1))) return 0; - return make_lex_string(lex_str, str, length); + tmp= (char*) (lex_str+1); + lex_str->str= tmp; + memcpy(tmp, str, length); + tmp[length]= 0; + lex_str->length= length; + return lex_str; } // Allocate LEX_STRING for character set conversion @@ -3689,20 +3764,7 @@ public: } } int killed_errno(); - inline void reset_killed() - { - /* - Resetting killed has to be done under a mutex to ensure - its not done during an awake() call. - */ - if (killed != NOT_KILLED) - { - mysql_mutex_lock(&LOCK_thd_kill); - killed= NOT_KILLED; - killed_err= 0; - mysql_mutex_unlock(&LOCK_thd_kill); - } - } + void reset_killed(); inline void reset_kill_query() { if (killed < KILL_CONNECTION) @@ -3732,6 +3794,9 @@ public: void restore_backup_open_tables_state(Open_tables_backup *backup); void reset_sub_statement_state(Sub_statement_state *backup, uint new_state); void restore_sub_statement_state(Sub_statement_state *backup); + void store_slow_query_state(Sub_statement_state *backup); + void reset_slow_query_state(); + void add_slow_query_state(Sub_statement_state *backup); void set_n_backup_active_arena(Query_arena *set, Query_arena *backup); void restore_active_arena(Query_arena *set, Query_arena *backup); @@ -4486,6 +4551,29 @@ public: mysql_mutex_unlock(&LOCK_thread_count); } + + uint get_net_wait_timeout() + { + if (in_active_multi_stmt_transaction()) + { + if (transaction.all.is_trx_read_write()) + { + if (variables.idle_write_transaction_timeout > 0) + return variables.idle_write_transaction_timeout; + } + else + { + if (variables.idle_readonly_transaction_timeout > 0) + return variables.idle_readonly_transaction_timeout; + } + + if (variables.idle_transaction_timeout > 0) + return variables.idle_transaction_timeout; + } + + return variables.net_wait_timeout; + } + /** Switch to a sublex, to parse a substatement or an expression. */ @@ -4510,6 +4598,12 @@ public: */ bool restore_from_local_lex_to_old_lex(LEX *oldlex); + inline void prepare_logs_for_admin_command() + { + enable_slow_log&= !MY_TEST(variables.log_slow_disabled_statements & + LOG_SLOW_DISABLE_ADMIN); + query_plan_flags|= QPLAN_ADMIN; + } }; inline void add_to_active_threads(THD *thd) @@ -4536,11 +4630,12 @@ inline void unlink_not_visible_thd(THD *thd) /** A short cut for thd->get_stmt_da()->set_ok_status(). */ inline void -my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0, +my_ok(THD *thd, ulonglong affected_rows_arg= 0, ulonglong id= 0, const char *message= NULL) { - thd->set_row_count_func(affected_rows); - thd->get_stmt_da()->set_ok_status(affected_rows, id, message); + thd->set_row_count_func(affected_rows_arg); + thd->set_affected_rows(affected_rows_arg); + thd->get_stmt_da()->set_ok_status(affected_rows_arg, id, message); } @@ -6090,7 +6185,7 @@ public: (int) m_db.length, (m_db.length ? m_db.str : ""), dot, ".", (int) m_name.length, m_name.str); - DBUG_ASSERT(ok_for_lower_case_names(m_db.str)); + DBUG_SLOW_ASSERT(ok_for_lower_case_names(m_db.str)); return false; } }; @@ -6110,6 +6205,25 @@ public: } }; +/* Functions to compare if two lex strings are equal */ +inline bool lex_string_cmp(CHARSET_INFO *charset, + const LEX_CSTRING *a, + const LEX_CSTRING *b) +{ + return my_strcasecmp(charset, a->str, b->str); +} + +/* + Compare if two LEX_CSTRING are equal. Assumption is that + character set is ASCII (like for plugin names) +*/ +inline bool lex_string_eq(const LEX_CSTRING *a, + const LEX_CSTRING *b) +{ + if (a->length != b->length) + return 1; /* Different */ + return strcasecmp(a->str, b->str) != 0; +} #endif /* MYSQL_SERVER */ diff --git a/sql/sql_client.cc b/sql/sql_client.cc index efac01f9894..0e17360915c 100644 --- a/sql/sql_client.cc +++ b/sql/sql_client.cc @@ -18,7 +18,7 @@ This files defines some MySQL C API functions that are server specific */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_class.h" // system_variables diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 0e5d8d43c0c..a100f38c02c 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -20,7 +20,7 @@ Functions to autenticate and handle reqests for a connection */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #ifndef __WIN__ #include <netdb.h> // getservbyname, servent @@ -37,6 +37,7 @@ #include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL #include "sql_callback.h" #include "wsrep_mysqld.h" +#include "proxy_protocol.h" HASH global_user_stats, global_client_stats, global_table_stats; HASH global_index_stats; @@ -836,6 +837,113 @@ bool init_new_connection_handler_thread() return 0; } +/** + Set client address during authentication. + + Initializes THD::main_security_ctx and THD::peer_port. + Optionally does ip to hostname translation. + + @param thd current THD handle + @param addr peer address (can be NULL, if 'ip' is set) + @param ip peer address as string (can be NULL if 'addr' is set) + @param port peer port + @param check_proxy_networks if true, and host is in + 'proxy_protocol_networks' list, skip + "host not privileged" check + @param[out] host_errors - number of connect + errors for this host + + @retval 0 ok, 1 error +*/ +int thd_set_peer_addr(THD *thd, + sockaddr_storage *addr, + const char *ip, + uint port, + bool check_proxy_networks, + uint *host_errors) +{ + *host_errors= 0; + + thd->peer_port= port; + + char ip_string[128]; + if (!ip) + { + void *addr_data; + if (addr->ss_family == AF_UNIX) + { + /* local connection */ + my_free((void *)thd->main_security_ctx.ip); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host = my_localhost; + thd->main_security_ctx.ip= 0; + return 0; + } + else if (addr->ss_family == AF_INET) + addr_data= &((struct sockaddr_in *)addr)->sin_addr; + else + addr_data= &((struct sockaddr_in6 *)addr)->sin6_addr; + if (!inet_ntop(addr->ss_family,addr_data, ip_string, sizeof(ip_string))) + { + DBUG_ASSERT(0); + return 1; + } + ip= ip_string; + } + + my_free((void *)thd->main_security_ctx.ip); + if (!(thd->main_security_ctx.ip = my_strdup(ip, MYF(MY_WME)))) + { + /* + No error accounting per IP in host_cache, + this is treated as a global server OOM error. + TODO: remove the need for my_strdup. + */ + statistic_increment(aborted_connects, &LOCK_status); + statistic_increment(connection_errors_internal, &LOCK_status); + return 1; /* The error is set by my_strdup(). */ + } + thd->main_security_ctx.host_or_ip = thd->main_security_ctx.ip; + if (!(specialflag & SPECIAL_NO_RESOLVE)) + { + int rc; + + rc = ip_to_hostname(addr, + thd->main_security_ctx.ip, + &thd->main_security_ctx.host, + host_errors); + + /* Cut very long hostnames to avoid possible overflows */ + if (thd->main_security_ctx.host) + { + if (thd->main_security_ctx.host != my_localhost) + ((char*)thd->main_security_ctx.host)[MY_MIN(strlen(thd->main_security_ctx.host), + HOSTNAME_LENGTH)] = 0; + thd->main_security_ctx.host_or_ip = thd->main_security_ctx.host; + } + + if (rc == RC_BLOCKED_HOST) + { + /* HOST_CACHE stats updated by ip_to_hostname(). */ + my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; + } + } + DBUG_PRINT("info", ("Host: %s ip: %s", + (thd->main_security_ctx.host ? + thd->main_security_ctx.host : "unknown host"), + (thd->main_security_ctx.ip ? + thd->main_security_ctx.ip : "unknown ip"))); + if ((!check_proxy_networks || !is_proxy_protocol_allowed((struct sockaddr *) addr)) + && acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) + { + /* HOST_CACHE stats updated by acl_check_host(). */ + my_error(ER_HOST_NOT_PRIVILEGED, MYF(0), + thd->main_security_ctx.host_or_ip); + return 1; + } + return 0; +} + /* Perform handshake, authorize client and update thd ACL variables. @@ -865,8 +973,9 @@ static int check_connection(THD *thd) { my_bool peer_rc; char ip[NI_MAXHOST]; + uint16 peer_port; - peer_rc= vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST); + peer_rc= vio_peer_addr(net->vio, ip, &peer_port, NI_MAXHOST); /* =========================================================================== @@ -941,55 +1050,10 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) - { - /* - No error accounting per IP in host_cache, - this is treated as a global server OOM error. - TODO: remove the need for my_strdup. - */ - statistic_increment(aborted_connects,&LOCK_status); - statistic_increment(connection_errors_internal, &LOCK_status); - return 1; /* The error is set by my_strdup(). */ - } - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; - if (!(specialflag & SPECIAL_NO_RESOLVE)) - { - int rc; - - rc= ip_to_hostname(&net->vio->remote, - thd->main_security_ctx.ip, - &thd->main_security_ctx.host, - &connect_errors); - - /* Cut very long hostnames to avoid possible overflows */ - if (thd->main_security_ctx.host) - { - if (thd->main_security_ctx.host != my_localhost) - ((char*) thd->main_security_ctx.host)[MY_MIN(strlen(thd->main_security_ctx.host), - HOSTNAME_LENGTH)]= 0; - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; - } - - if (rc == RC_BLOCKED_HOST) - { - /* HOST_CACHE stats updated by ip_to_hostname(). */ - my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip); - return 1; - } - } - DBUG_PRINT("info",("Host: %s ip: %s", - (thd->main_security_ctx.host ? - thd->main_security_ctx.host : "unknown host"), - (thd->main_security_ctx.ip ? - thd->main_security_ctx.ip : "unknown ip"))); - if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) - { - /* HOST_CACHE stats updated by acl_check_host(). */ - my_error(ER_HOST_NOT_PRIVILEGED, MYF(0), - thd->main_security_ctx.host_or_ip); + + if (thd_set_peer_addr(thd, &net->vio->remote, ip, peer_port, + true, &connect_errors)) return 1; - } } else /* Hostname given means that the connection was on a socket */ { diff --git a/sql/sql_connect.h b/sql/sql_connect.h index 364be401944..67950061da8 100644 --- a/sql/sql_connect.h +++ b/sql/sql_connect.h @@ -16,7 +16,7 @@ #ifndef SQL_CONNECT_INCLUDED #define SQL_CONNECT_INCLUDED -#include "my_sys.h" /* pthread_handler_t */ +#include <my_sys.h> /* pthread_handler_t */ #include "mysql_com.h" /* enum_server_command */ #include "structs.h" #include <mysql/psi/mysql_socket.h> @@ -85,6 +85,10 @@ bool thd_init_client_charset(THD *thd, uint cs_number); bool setup_connection_thread_globals(THD *thd); bool thd_prepare_connection(THD *thd); bool thd_is_connection_alive(THD *thd); +int thd_set_peer_addr(THD *thd, sockaddr_storage *addr, + const char *ip, uint port, + bool check_proxy_networks, + uint *host_errors); bool login_connection(THD *thd); void prepare_new_connection_state(THD* thd); diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc index 2460a16551d..19cd780e9c3 100644 --- a/sql/sql_crypt.cc +++ b/sql/sql_crypt.cc @@ -26,7 +26,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_crypt.h" #include "password.h" diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h index 3df554e9d31..e61776713b6 100644 --- a/sql/sql_crypt.h +++ b/sql/sql_crypt.h @@ -21,7 +21,7 @@ #pragma interface /* gcc class implementation */ #endif -#include "sql_list.h" /* Sql_alloc */ +#include "sql_alloc.h" /* Sql_alloc */ #include "my_rnd.h" /* rand_struct */ class SQL_CRYPT :public Sql_alloc diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index c163044547f..2047c7c8762 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -1,3 +1,20 @@ +/* + Copyright (c) 2016, 2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "mariadb.h" #include "sql_class.h" #include "sql_lex.h" #include "sql_cte.h" @@ -112,8 +129,8 @@ bool With_clause::check_dependencies() elem != with_elem; elem= elem->next) { - if (my_strcasecmp(system_charset_info, with_elem->query_name->str, - elem->query_name->str) == 0) + if (lex_string_cmp(system_charset_info, with_elem->query_name, + elem->query_name) == 0) { my_error(ER_DUP_QUERY_NAME, MYF(0), with_elem->query_name->str); return true; diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 85676df9d39..036f0335c10 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -1,3 +1,19 @@ +/* + Copyright (c) 2016, 2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + #ifndef SQL_CTE_INCLUDED #define SQL_CTE_INCLUDED #include "sql_list.h" diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 40eb7046108..864b64a9f28 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -17,7 +17,7 @@ #pragma implementation /* gcc class implementation */ #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_cursor.h" diff --git a/sql/sql_db.cc b/sql/sql_db.cc index f91b92b1d4f..4db216a3a41 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -18,7 +18,7 @@ /* create and drop of databases */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_db.h" diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 17e2404fdf1..32ff44d9343 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -21,7 +21,7 @@ Multi-table deletes were introduced by Monty and Sinisa */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_delete.h" @@ -588,7 +588,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, deltempfile= new (thd->mem_root) Unique (refpos_order_cmp, table->file, table->file->ref_length, MEM_STRIP_BUF_SIZE); - while (!(error=info.read_record(&info)) && !thd->killed && + while (!(error=info.read_record()) && !thd->killed && ! thd->is_error()) { if (record_should_be_deleted(thd, table, select, explain)) @@ -613,7 +613,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, delete_record= true; } - while (!(error=info.read_record(&info)) && !thd->killed && + while (!(error=info.read_record()) && !thd->killed && ! thd->is_error()) { if (delete_while_scanning) @@ -1286,7 +1286,7 @@ int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info, */ info.ignore_not_found_rows= 1; bool will_batch= !table->file->start_bulk_delete(); - while (!(local_error= info.read_record(&info)) && !thd->killed) + while (!(local_error= info.read_record()) && !thd->killed) { if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 8dff001d4d0..2df3af03af5 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -22,7 +22,7 @@ */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_derived.h" diff --git a/sql/sql_digest.cc b/sql/sql_digest.cc index 27c33f1c64b..65edcc122f1 100644 --- a/sql/sql_digest.cc +++ b/sql/sql_digest.cc @@ -18,7 +18,7 @@ This code needs extra visibility in the lexer structures */ -#include "my_global.h" +#include "mariadb.h" #include "my_md5.h" #include "mysqld_error.h" @@ -31,11 +31,6 @@ #include "sql_get_diagnostics.h" -#ifdef NEVER -#include "my_sys.h" -#include "sql_signal.h" -#endif - /* Generated code */ #include "sql_yacc.h" #define LEX_TOKEN_WITH_DEFINITION diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 6d86ece6a9f..a25bdef3d9d 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -16,7 +16,7 @@ /* Execute DO statement */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "transaction.h" #include "unireg.h" diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 144cf9d4a30..b1c7481bb8c 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -41,7 +41,7 @@ This file contains the implementation of error and warnings related ***********************************************************************/ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_error.h" diff --git a/sql/sql_error.h b/sql/sql_error.h index 263c5843a4a..f8b8adc805a 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -17,12 +17,12 @@ #ifndef SQL_ERROR_H #define SQL_ERROR_H -#include "sql_list.h" /* Sql_alloc, MEM_ROOT */ -#include "m_string.h" /* LEX_STRING */ -#include "sql_string.h" /* String */ -#include "sql_plist.h" /* I_P_List */ -#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ -#include "my_time.h" /* MYSQL_TIME */ +#include "sql_list.h" /* Sql_alloc, MEM_ROOT, list */ +#include "m_string.h" /* LEX_STRING */ +#include "sql_string.h" /* String */ +#include "sql_plist.h" /* I_P_List */ +#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ +#include "my_time.h" /* MYSQL_TIME */ #include "decimal.h" class THD; diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index ca276eb87ac..05df9a21572 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -18,7 +18,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_select.h" #include "my_json_writer.h" @@ -1145,7 +1145,7 @@ void Explain_table_access::fill_key_len_str(String *key_len_str) const void Explain_index_use::set(MEM_ROOT *mem_root, KEY *key, uint key_len_arg) { - set_pseudo_key(mem_root, key->name); + set_pseudo_key(mem_root, key->name.str); key_len= key_len_arg; uint len= 0; for (uint i= 0; i < key->usable_key_parts; i++) @@ -2450,7 +2450,8 @@ int Explain_range_checked_fer::append_possible_keys_stat(MEM_ROOT *alloc, for (j= 0; j < table->s->keys; j++) { if (possible_keys.is_set(j)) - keys_stat_names[j]= key_set.append_str(alloc, table->key_info[j].name); + keys_stat_names[j]= key_set.append_str(alloc, + table->key_info[j].name.str); else keys_stat_names[j]= NULL; } diff --git a/sql/sql_expression_cache.cc b/sql/sql_expression_cache.cc index c79783bf561..00f5bfd792f 100644 --- a/sql/sql_expression_cache.cc +++ b/sql/sql_expression_cache.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_base.h" #include "sql_select.h" #include "sql_expression_cache.h" diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc index 1713cb04ebc..76973b4daa2 100644 --- a/sql/sql_get_diagnostics.cc +++ b/sql/sql_get_diagnostics.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */ +#include "mariadb.h" #include "sql_list.h" // Sql_alloc, List, List_iterator #include "sql_cmd.h" // Sql_cmd #include "sql_class.h" // Diagnostics_area diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index babb09a1267..947c41e461e 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -52,7 +52,7 @@ cursor points at the first record). */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_handler.h" #include "sql_base.h" // close_thread_tables @@ -571,7 +571,7 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, if (handler->keyno < 0 || my_strcasecmp(&my_charset_latin1, keyname, - table->s->key_info[handler->keyno].name)) + table->s->key_info[handler->keyno].name.str)) { if ((handler->keyno= find_type(keyname, &table->s->keynames, FIND_TYPE_NO_PREFIX) - 1) < 0) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index bd11397e2aa..4ccaa6a055f 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_help.h" @@ -202,7 +202,7 @@ int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields, FALSE)) DBUG_RETURN(0); - while (!read_record_info.read_record(&read_record_info)) + while (!read_record_info.read_record()) { if (!select->cond->val_int()) // Doesn't match like continue; @@ -246,7 +246,7 @@ int search_keyword(THD *thd, TABLE *keywords, FALSE)) DBUG_RETURN(0); - while (!read_record_info.read_record(&read_record_info) && count<2) + while (!read_record_info.read_record() && count<2) { if (!select->cond->val_int()) // Dosn't match like continue; @@ -380,7 +380,7 @@ int search_categories(THD *thd, TABLE *categories, if (init_read_record(&read_record_info, thd, categories, select, NULL, 1, 0, FALSE)) DBUG_RETURN(0); - while (!read_record_info.read_record(&read_record_info)) + while (!read_record_info.read_record()) { if (select && !select->cond->val_int()) continue; @@ -418,7 +418,7 @@ void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname, FALSE)) DBUG_VOID_RETURN; - while (!read_record_info.read_record(&read_record_info)) + while (!read_record_info.read_record()) { if (!select->cond->val_int()) continue; diff --git a/sql/sql_hset.h b/sql/sql_hset.h index 4dfddf898f0..dfaf17cf55c 100644 --- a/sql/sql_hset.h +++ b/sql/sql_hset.h @@ -15,7 +15,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "my_global.h" #include "hash.h" diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 3d81ab35373..e592a873ef0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -56,7 +56,7 @@ */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_insert.h" #include "sql_update.h" // compare_record diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 41741f3dcc7..9a7b8f2af21 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -27,6 +27,7 @@ #pragma implementation // gcc: Class implementation #endif +#include "mariadb.h" #include "key.h" #include "sql_base.h" #include "sql_select.h" @@ -3372,7 +3373,7 @@ int JOIN_TAB_SCAN::next() if (is_first_record) is_first_record= FALSE; else - err= info->read_record(info); + err= info->read_record(); if (!err) { @@ -3387,7 +3388,7 @@ int JOIN_TAB_SCAN::next() Move to the next record if the last retrieved record does not meet the condition pushed to the table join_tab. */ - err= info->read_record(info); + err= info->read_record(); if (!err) { join_tab->tracker->r_rows++; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 169f33f81e2..b8d51a5783f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -18,7 +18,7 @@ /* A lexical scanner on a temporary buffer with a yacc interface */ #define MYSQL_LEX 1 -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_class.h" // sql_lex.h: SQLCOM_END #include "sql_lex.h" @@ -681,7 +681,6 @@ void LEX::start(THD *thd_arg) context_stack.empty(); unit.init_query(); - unit.init_select(); select_lex.linkage= UNSPECIFIED_TYPE; /* 'parent_lex' is used in init_query() so it must be before it. */ select_lex.parent_lex= this; @@ -2137,7 +2136,7 @@ void trim_whitespace(CHARSET_INFO *cs, LEX_CSTRING *str, uint *prefix_length) st_select_lex structures initialisations */ -void st_select_lex_node::init_query() +void st_select_lex_node::init_query_common() { options= 0; sql_cache= SQL_CACHE_UNSPECIFIED; @@ -2146,13 +2145,9 @@ void st_select_lex_node::init_query() uncacheable= 0; } -void st_select_lex_node::init_select() -{ -} - void st_select_lex_unit::init_query() { - st_select_lex_node::init_query(); + init_query_common(); linkage= GLOBAL_OPTIONS_TYPE; select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; @@ -2178,7 +2173,7 @@ void st_select_lex_unit::init_query() void st_select_lex::init_query() { - st_select_lex_node::init_query(); + init_query_common(); table_list.empty(); top_join_list.empty(); join_list= &top_join_list; @@ -2233,7 +2228,6 @@ void st_select_lex::init_query() void st_select_lex::init_select() { - st_select_lex_node::init_select(); sj_nests.empty(); sj_subselects.empty(); group_list.empty(); @@ -2556,26 +2550,6 @@ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, return FALSE; } -bool st_select_lex_node::inc_in_sum_expr() { return 1; } -uint st_select_lex_node::get_in_sum_expr() { return 0; } -TABLE_LIST* st_select_lex_node::get_table_list() { return 0; } -List<Item>* st_select_lex_node::get_item_list() { return 0; } -TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table, - LEX_CSTRING *alias, - ulong table_join_options, - thr_lock_type flags, - enum_mdl_type mdl_type, - List<Index_hint> *hints, - List<String> *partition_names, - LEX_STRING *option) -{ - return 0; -} -ulong st_select_lex_node::get_table_join_options() -{ - return 0; -} - /* prohibit using LIMIT clause */ @@ -5474,7 +5448,7 @@ bool LEX::sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop) Item_splocal(thd, &src->name, src->offset, src->sql_type()); if (args[i] == NULL) return true; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS args[i]->m_sp= sphead; #endif } @@ -5608,7 +5582,7 @@ bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop) loop.m_index->sql_type()); if (splocal == NULL) return true; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS splocal->m_sp= sphead; #endif Item_int *inc= new (thd->mem_root) Item_int(thd, loop.m_direction); @@ -5794,8 +5768,8 @@ bool LEX::sp_block_finalize(THD *thd, const Lex_spblock_st spblock, if (sp_block_finalize(thd, spblock, &splabel)) return true; if (end_label->str && - my_strcasecmp(system_charset_info, - end_label->str, splabel->name.str) != 0) + lex_string_cmp(system_charset_info, + end_label, &splabel->name) != 0) { my_error(ER_SP_LABEL_MISMATCH, MYF(0), end_label->str); return true; @@ -6202,8 +6176,8 @@ bool LEX::sp_pop_loop_label(THD *thd, const LEX_CSTRING *label_name) sp_label *lab= spcont->pop_label(); sphead->backpatch(lab); if (label_name->str && - my_strcasecmp(system_charset_info, label_name->str, - lab->name.str) != 0) + lex_string_cmp(system_charset_info, label_name, + &lab->name) != 0) { my_error(ER_SP_LABEL_MISMATCH, MYF(0), label_name->str); return true; @@ -6394,7 +6368,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd, pos.pos(), pos.length()))) return NULL; } -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS item->m_sp= sphead; #endif safe_to_cache_query=0; @@ -6562,7 +6536,7 @@ Item *LEX::create_item_limit(THD *thd, spv->offset, spv->sql_type(), pos.pos(), pos.length()))) return NULL; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS item->m_sp= sphead; #endif safe_to_cache_query= 0; @@ -6686,7 +6660,7 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name, pos.pos(), pos.length()); if (splocal == NULL) return NULL; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS splocal->m_sp= sphead; #endif safe_to_cache_query= 0; @@ -7077,6 +7051,36 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond, } +int set_statement_var_if_exists(THD *thd, const char *var_name, + size_t var_name_length, ulonglong value) +{ + sys_var *sysvar; + if (thd->lex->sql_command == SQLCOM_CREATE_VIEW) + { + my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "[NO]WAIT"); + return 1; + } + if (thd->lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "[NO]WAIT"); + return 1; + } + if ((sysvar= find_sys_var_ex(thd, var_name, var_name_length, true, false))) + { + Item *item= new (thd->mem_root) Item_uint(thd, value); + set_var *var= new (thd->mem_root) set_var(thd, OPT_SESSION, sysvar, + &null_clex_str, item); + + if (!item || !var || thd->lex->stmt_var_list.push_back(var, thd->mem_root)) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return 1; + } + } + return 0; +} + + bool LEX::sp_add_cfetch(THD *thd, const LEX_CSTRING *name) { uint offset; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7be918f2c0b..5f1f4a397d4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -23,7 +23,6 @@ #include "violite.h" /* SSL_type */ #include "sql_trigger.h" -#include "item.h" /* From item_subselect.h: subselect_union_engine */ #include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */ #include "mem_root_array.h" #include "sql_cmd.h" @@ -551,6 +550,8 @@ protected: st_select_lex_node *next, **prev, /* neighbor list */ *master, *slave, /* vertical links */ *link_next, **link_prev; /* list of whole SELECT_LEX */ + + void init_query_common(); public: ulonglong options; @@ -588,11 +589,8 @@ public: linkage(UNSPECIFIED_TYPE) { } - virtual ~st_select_lex_node() {} inline st_select_lex_node* get_master() { return master; } - virtual void init_query(); - virtual void init_select(); void include_down(st_select_lex_node *upper); void add_slave(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); @@ -601,23 +599,6 @@ public: void exclude(); void exclude_from_tree(); - virtual st_select_lex* outer_select()= 0; - virtual st_select_lex* return_after_parsing()= 0; - - virtual bool inc_in_sum_expr(); - virtual uint get_in_sum_expr(); - virtual TABLE_LIST* get_table_list(); - virtual List<Item>* get_item_list(); - virtual ulong get_table_join_options(); - virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, - LEX_CSTRING *alias, - ulong table_options, - thr_lock_type flags= TL_UNLOCK, - enum_mdl_type mdl_type= MDL_SHARED_READ, - List<Index_hint> *hints= 0, - List<String> *partition_names= 0, - LEX_STRING *option= 0); - virtual void set_lock_for_tables(thr_lock_type lock_type) {} void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; } void move_node(st_select_lex_node *where_to_move) { @@ -3946,6 +3927,8 @@ extern bool is_native_function_with_warn(THD *thd, const LEX_CSTRING *name); void my_missing_function_error(const LEX_CSTRING &token, const char *name); bool is_keyword(const char *name, uint len); +int set_statement_var_if_exists(THD *thd, const char *var_name, + size_t var_name_length, ulonglong value); Virtual_column_info *add_virtual_expression(THD *thd, Item *expr); Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, diff --git a/sql/sql_list.cc b/sql/sql_list.cc index 2c1b3c47d55..e938d5515c9 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -18,6 +18,7 @@ #pragma implementation // gcc: Class implementation #endif +#include "mariadb.h" #include "sql_list.h" list_node end_of_list; diff --git a/sql/sql_list.h b/sql/sql_list.h index 111826495f7..422b7943aa9 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -19,48 +19,7 @@ #pragma interface /* gcc class implementation */ #endif -#include "my_sys.h" /* alloc_root, TRASH, MY_WME, - MY_FAE, MY_ALLOW_ZERO_PTR */ -#include "m_string.h" /* bfill */ - -THD *thd_get_current_thd(); - -/* mysql standard class memory allocator */ - -class Sql_alloc -{ -public: - static void *operator new(size_t size) throw () - { - DBUG_ASSERT(size < UINT_MAX32); - return thd_alloc(thd_get_current_thd(), (uint) size); - } - static void *operator new[](size_t size) throw () - { - DBUG_ASSERT(size < UINT_MAX32); - return thd_alloc(thd_get_current_thd(), (uint) size); - } - static void *operator new[](size_t size, MEM_ROOT *mem_root) throw () - { return alloc_root(mem_root, size); } - static void *operator new(size_t size, MEM_ROOT *mem_root) throw () - { return alloc_root(mem_root, size); } - static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } - static void operator delete(void *ptr, MEM_ROOT *mem_root) - { /* never called */ } - static void operator delete[](void *ptr, MEM_ROOT *mem_root) - { /* never called */ } - static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } -#ifdef HAVE_valgrind - bool dummy_for_valgrind; - inline Sql_alloc() :dummy_for_valgrind(0) {} - inline ~Sql_alloc() {} -#else - inline Sql_alloc() {} - inline ~Sql_alloc() {} -#endif - -}; - +#include "sql_alloc.h" /** Simple intrusive linked list. @@ -69,6 +28,7 @@ public: 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 { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 4d5d1a4d943..6cd0b76c66d 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -19,7 +19,7 @@ /* Copy data from a textfile to table */ /* 2006-12 Erik Wetterberg : LOAD XML added */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_load.h" @@ -837,7 +837,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, if (n++) query_str.append(STRING_WITH_LEN(", ")); append_identifier(thd, &query_str, item->name.str, item->name.length); - query_str.append(val->name.str, val->name.length); + query_str.append(&val->name); } } diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index a2efa5e072c..f8b96279378 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -20,12 +20,11 @@ !! This file is built from my_locale.pl !! */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_locale.h" #include "sql_class.h" // THD -#include "my_sys.h" // MY_*, NullS, NULL enum err_msgs_index diff --git a/sql/sql_locale.h b/sql/sql_locale.h index ec2f3d29e15..d1009832e0c 100644 --- a/sql/sql_locale.h +++ b/sql/sql_locale.h @@ -22,7 +22,6 @@ typedef struct my_locale_errmsgs const char ***errmsgs; } MY_LOCALE_ERRMSGS; -#include "my_global.h" /* uint */ typedef struct st_typelib TYPELIB; diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index 8c8aee0cb03..f787d39b774 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -21,7 +21,7 @@ * o Berkeley DB: removing unneeded log files. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_manager.h" #include "sql_base.h" // flush_tables diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fc9a1eab758..0c68615f911 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -15,7 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define MYSQL_LEX 1 -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_parse.h" // sql_kill, *_precheck, *_prepare #include "lock.h" // try_transactional_lock, @@ -99,7 +99,6 @@ #include "debug_sync.h" #include "probes_mysql.h" #include "set_var.h" -#include "log_slow.h" #include "sql_bootstrap.h" #include "sql_sequence.h" @@ -601,7 +600,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | - CF_CAN_BE_EXPLAINED;; + CF_CAN_BE_EXPLAINED; sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -1222,8 +1221,8 @@ bool do_command(THD *thd) the client, the connection is closed or "net_wait_timeout" number of seconds has passed. */ - if(!thd->skip_wait_timeout) - my_net_set_read_timeout(net, thd->variables.net_wait_timeout); + if (!thd->skip_wait_timeout) + my_net_set_read_timeout(net, thd->get_net_wait_timeout()); /* Errors and diagnostics are cleared once here before query */ thd->clear_error(1); @@ -1286,7 +1285,8 @@ bool do_command(THD *thd) mysql_mutex_lock(&thd->LOCK_wsrep_thd); if (thd->wsrep_conflict_state == MUST_ABORT) { - DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id)); + DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", + (ulong) thd->real_id)); wsrep_client_rollback(thd); } mysql_mutex_unlock(&thd->LOCK_wsrep_thd); @@ -1590,17 +1590,24 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_EXECUTE_IF("crash_dispatch_command_before", { DBUG_PRINT("crash_dispatch_command_before", ("now")); - DBUG_ABORT(); }); + DBUG_SUICIDE(); }); /* Performance Schema Interface instrumentation, begin */ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, com_statement_info[command]. m_key); + /* + We should always call reset_for_next_command() before a query. + mysql_parse() will do this for queries. Ensure it's also done + for other commands. + */ + if (command != COM_QUERY) + thd->reset_for_next_command(); thd->set_command(command); /* - Commands which always take a long time are logged into - the slow log only if opt_log_slow_admin_statements is set. + thd->variables.log_slow_disabled_statements defines which statements + are logged to slow log */ thd->enable_slow_log= thd->variables.sql_log_slow; thd->query_plan_flags= QPLAN_INIT; @@ -1883,6 +1890,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_query_and_id(beginning_of_next_stmt, length, thd->charset(), next_query_id()); + /* Count each statement from the client. */ @@ -1892,7 +1900,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_time(); /* Reset the query start time. */ parser_state.reset(beginning_of_next_stmt, length); - /* TODO: set thd->lex->sql_command to SQLCOM_END here */ if (WSREP_ON) wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, @@ -1950,7 +1957,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } packet= arg_end + 1; - thd->reset_for_next_command(0); // Don't clear errors // thd->reset_for_next_command reset state => restore it if (is_next_command) { @@ -2045,8 +2051,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, status_var_increment(thd->status_var.com_other); - thd->enable_slow_log&= opt_log_slow_admin_statements; - thd->query_plan_flags|= QPLAN_ADMIN; + thd->prepare_logs_for_admin_command(); if (check_global_access(thd, REPL_SLAVE_ACL)) break; @@ -2426,9 +2431,12 @@ com_multi_end: /* + Log query to slow queries, if it passes filtering + @note This function must call delete_explain_query(). */ + void log_slow_statement(THD *thd) { DBUG_ENTER("log_slow_statement"); @@ -2440,19 +2448,26 @@ void log_slow_statement(THD *thd) */ if (unlikely(thd->in_sub_stmt)) goto end; // Don't set time for sub stmt + if (!thd->enable_slow_log || !global_system_variables.sql_log_slow) + goto end; + if ((thd->server_status & + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && + !(sql_command_flags[thd->last_sql_command] & CF_STATUS_COMMAND) && + (!thd->variables.log_slow_filter || + (thd->variables.log_slow_filter & QPLAN_NOT_USING_INDEX))) + { + thd->query_plan_flags|= QPLAN_NOT_USING_INDEX; + /* We are always logging no index queries if enabled in filter */ + thd->server_status|= SERVER_QUERY_WAS_SLOW; + } /* Follow the slow log filter configuration. */ - if (!thd->enable_slow_log || !global_system_variables.sql_log_slow || - (thd->variables.log_slow_filter - && !(thd->variables.log_slow_filter & thd->query_plan_flags))) + if (thd->variables.log_slow_filter && + !(thd->variables.log_slow_filter & thd->query_plan_flags)) goto end; - - if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || - ((thd->server_status & - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && - opt_log_queries_not_using_indexes && - !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && + + if ((thd->server_status & SERVER_QUERY_WAS_SLOW) && thd->get_examined_row_count() >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; @@ -2867,6 +2882,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp) { /* bits that should be cleared in thd->server_status */ uint bits_to_be_cleared= 0; + ulonglong affected_rows; if (sp->m_flags & sp_head::MULTI_RESULTS) { if (!(thd->client_capabilities & CLIENT_MULTI_RESULTS)) @@ -2906,7 +2922,9 @@ static bool do_execute_sp(THD *thd, sp_head *sp) return 1; // Substatement should already have sent error } - my_ok(thd, (thd->get_row_count_func() < 0) ? 0 : thd->get_row_count_func()); + affected_rows= thd->affected_rows; // Affected rows for all sub statements + thd->affected_rows= 0; // Reset total, as my_ok() adds to it + my_ok(thd, affected_rows); return 0; } @@ -3137,6 +3155,13 @@ bool Sql_cmd_call::execute(THD *thd) if (do_execute_sp(thd, sp)) return true; + + /* + Disable slow log for the above call(), if calls are disabled. + Instead we will log the executed statements to the slow log. + */ + if (thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_CALL) + thd->enable_slow_log= 0; } return false; } @@ -3218,6 +3243,12 @@ mysql_execute_command(THD *thd) table_list.first); /* + Remember last commmand executed, so that we can use it in functions called by + dispatch_command() + */ + thd->last_sql_command= lex->sql_command; + + /* Reset warning count for each query that uses tables A better approach would be to reset this for any commands that is not a SHOW command or a select that only access local @@ -4200,7 +4231,7 @@ mysql_execute_command(THD *thd) (!thd->is_current_stmt_binlog_format_row() || !create_info.tmp_table())) { - WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL) + WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL); } /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); @@ -4245,14 +4276,13 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ - WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); /* Currently CREATE INDEX or DROP INDEX cause a full table rebuild and thus classify as slow administrative statements just like ALTER TABLE. */ - thd->enable_slow_log&= opt_log_slow_admin_statements; - thd->query_plan_flags|= QPLAN_ADMIN; + thd->prepare_logs_for_admin_command(); bzero((char*) &create_info, sizeof(create_info)); create_info.db_type= 0; @@ -4371,7 +4401,7 @@ end_with_restore_list: if (check_rename_table(thd, first_table, all_tables)) goto error; - WSREP_TO_ISOLATION_BEGIN(0, 0, first_table) + WSREP_TO_ISOLATION_BEGIN(0, 0, first_table); if (mysql_rename_tables(thd, first_table, 0)) goto error; @@ -5152,7 +5182,7 @@ end_with_restore_list: (CREATE_ACL | DROP_ACL) : CREATE_ACL, &lex->name)) break; - WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); res= mysql_create_db(thd, lex->name.str, lex->create_info, &lex->create_info); break; @@ -5161,7 +5191,7 @@ end_with_restore_list: { if (prepare_db_action(thd, DROP_ACL, &lex->name)) break; - WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); res= mysql_rm_db(thd, lex->name.str, lex->if_exists()); break; } @@ -5193,7 +5223,7 @@ end_with_restore_list: res= 1; break; } - WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); res= mysql_upgrade_db(thd, db); if (!res) my_ok(thd); @@ -5204,7 +5234,7 @@ end_with_restore_list: LEX_CSTRING *db= &lex->name; if (prepare_db_action(thd, ALTER_ACL, db)) break; - WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); res= mysql_alter_db(thd, db->str, &lex->create_info); break; } @@ -5245,7 +5275,7 @@ end_with_restore_list: if (res) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); switch (lex->sql_command) { case SQLCOM_CREATE_EVENT: { @@ -5279,7 +5309,7 @@ end_with_restore_list: &lex->spname->m_name); break; case SQLCOM_DROP_EVENT: - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res= Events::drop_event(thd, &lex->spname->m_db, &lex->spname->m_name, lex->if_exists()))) @@ -5296,7 +5326,7 @@ end_with_restore_list: "mysql", NULL, NULL, 1, 0)) break; #ifdef HAVE_DLOPEN - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res = mysql_create_function(thd, &lex->udf))) my_ok(thd); #else @@ -5314,7 +5344,7 @@ end_with_restore_list: "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list, lex->sql_command == SQLCOM_CREATE_ROLE))) @@ -5328,7 +5358,7 @@ end_with_restore_list: check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res= mysql_drop_user(thd, lex->users_list, lex->sql_command == SQLCOM_DROP_ROLE))) my_ok(thd); @@ -5341,7 +5371,7 @@ end_with_restore_list: check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (lex->sql_command == SQLCOM_ALTER_USER) res= mysql_alter_user(thd, lex->users_list); else @@ -5357,7 +5387,7 @@ end_with_restore_list: break; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd); break; @@ -5418,7 +5448,7 @@ end_with_restore_list: if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0)) goto error; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_routine_grant(thd, all_tables, sph, lex->users_list, grants, lex->sql_command == SQLCOM_REVOKE, TRUE); @@ -5431,7 +5461,7 @@ end_with_restore_list: all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_table_grant(thd, all_tables, lex->users_list, lex->columns, lex->grant, lex->sql_command == SQLCOM_REVOKE); @@ -5447,7 +5477,7 @@ end_with_restore_list: } else { - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* Conditionally writes to binlog */ res= mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, lex->sql_command == SQLCOM_REVOKE, @@ -5473,7 +5503,7 @@ end_with_restore_list: case SQLCOM_REVOKE_ROLE: case SQLCOM_GRANT_ROLE: { - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res= mysql_grant_role(thd, lex->users_list, lex->sql_command != SQLCOM_GRANT_ROLE))) my_ok(thd); @@ -5531,7 +5561,7 @@ end_with_restore_list: REFRESH_STATUS | REFRESH_USER_RESOURCES)) { - WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); } #endif /* WITH_WSREP*/ @@ -5565,11 +5595,11 @@ end_with_restore_list: */ if (first_table) { - WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); + WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); } else { - WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); + WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); } } #endif /* WITH_WSREP */ @@ -5906,7 +5936,7 @@ end_with_restore_list: if (check_routine_access(thd, ALTER_PROC_ACL, db, name, Sp_handler::handler(lex->sql_command), 0)) goto error; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* Conditionally writes to binlog */ sp_result= sph->sp_drop_routine(thd, lex->spname); @@ -6019,7 +6049,7 @@ end_with_restore_list: Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands as specified through the thd->lex->create_view->mode flag. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_create_view(thd, first_table, thd->lex->create_view->mode); break; } @@ -6028,14 +6058,14 @@ end_with_restore_list: if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); break; } case SQLCOM_CREATE_TRIGGER: { /* Conditionally writes to binlog. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_create_or_drop_trigger(thd, all_tables, 1); break; @@ -6043,7 +6073,7 @@ end_with_restore_list: case SQLCOM_DROP_TRIGGER: { /* Conditionally writes to binlog. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_create_or_drop_trigger(thd, all_tables, 0); break; } @@ -6108,13 +6138,13 @@ end_with_restore_list: my_ok(thd); break; case SQLCOM_INSTALL_PLUGIN: - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (! (res= mysql_install_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); break; case SQLCOM_UNINSTALL_PLUGIN: - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); @@ -6135,7 +6165,7 @@ end_with_restore_list: if (check_global_access(thd, SUPER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= create_server(thd, &lex->server_options); break; @@ -6148,7 +6178,7 @@ end_with_restore_list: if (check_global_access(thd, SUPER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if ((error= alter_server(thd, &lex->server_options))) { @@ -6168,7 +6198,7 @@ end_with_restore_list: if (check_global_access(thd, SUPER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if ((err_code= drop_server(thd, &lex->server_options))) { @@ -7483,13 +7513,13 @@ void THD::reset_for_next_command(bool do_clear_error) reset_dynamic(&thd->user_var_events); thd->user_var_events_alloc= thd->mem_root; } + thd->enable_slow_log= thd->variables.sql_log_slow; thd->get_stmt_da()->reset_for_next_command(); thd->rand_used= 0; thd->m_sent_row_count= thd->m_examined_row_count= 0; thd->accessed_rows_and_keys= 0; - thd->query_plan_flags= QPLAN_INIT; - thd->query_plan_fsort_passes= 0; + reset_slow_query_state(); thd->reset_current_stmt_binlog_format_row(); thd->binlog_unsafe_warning_flags= 0; @@ -7571,7 +7601,6 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) DBUG_RETURN(1); unit->init_query(); - unit->init_select(); unit->thd= thd; unit->include_down(lex->current_select); unit->link_next= 0; @@ -7645,28 +7674,23 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) @param var_name Variable name */ -void create_select_for_variable(const char *var_name) +void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) { - THD *thd; LEX *lex; - LEX_CSTRING tmp; Item *var; char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end; DBUG_ENTER("create_select_for_variable"); - thd= current_thd; lex= thd->lex; mysql_init_select(lex); lex->sql_command= SQLCOM_SELECT; - tmp.str= var_name; - tmp.length=strlen(var_name); /* We set the name of Item to @@session.var_name because that then is used as the column name in the output. */ - if ((var= get_system_var(thd, OPT_SESSION, tmp, null_clex_str))) + if ((var= get_system_var(thd, OPT_SESSION, var_name, &null_clex_str))) { - end= strxmov(buff, "@@session.", var_name, NullS); + end= strxmov(buff, "@@session.", var_name->str, NullS); var->set_name(thd, buff, (uint)(end-buff), system_charset_info); add_item_to_list(thd, var); } diff --git a/sql/sql_parse.h b/sql/sql_parse.h index b8d7bb46e08..b0371a2cb81 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -16,7 +16,6 @@ #ifndef SQL_PARSE_INCLUDED #define SQL_PARSE_INCLUDED -#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_acl.h" /* GLOBAL_ACLS */ class Comp_creator; @@ -94,7 +93,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state, bool is_com_multi, bool is_next_command); bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); -void create_select_for_variable(const char *var_name); +void create_select_for_variable(THD *thd, LEX_CSTRING *var_name); void create_table_set_open_action_and_adjust_tables(LEX *lex); void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c9e78964e2a..3fc49dc42ca 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -47,7 +47,7 @@ /* Some general useful functions */ #define MYSQL_LEX 1 -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_partition.h" #include "key.h" // key_restore diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 61b026e5450..0c1c9fb02de 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -15,6 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mariadb.h" #include "sql_parse.h" // check_one_table_access // check_merge_table_access // check_one_table_access @@ -91,7 +92,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd) DBUG_ASSERT(!create_info.data_file_name && !create_info.index_file_name); WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); - thd->enable_slow_log= opt_log_slow_admin_statements; + thd->prepare_logs_for_admin_command(); DBUG_RETURN(exchange_partition(thd, first_table, &alter_info)); #ifdef WITH_WSREP error: diff --git a/sql/sql_plist.h b/sql/sql_plist.h index df50cccc874..14f6eb5e2aa 100644 --- a/sql/sql_plist.h +++ b/sql/sql_plist.h @@ -16,8 +16,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> - template <typename T, typename L> class I_P_List_iterator; class I_P_List_null_counter; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 4d25de0f299..a4e6546e38a 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -15,8 +15,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "sql_plugin.h" // Includes my_global.h -#include "sql_priv.h" // SHOW_MY_BOOL +#include "sql_plugin.h" // SHOW_MY_BOOL +#include "sql_priv.h" #include "unireg.h" #include "sql_class.h" // set_var.h: THD #include "sys_vars_shared.h" @@ -947,6 +947,10 @@ SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type) } +/* + If LEX is passed non-NULL, an automatic unlock of the plugin will happen + in the LEX destructor. +*/ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc) { st_plugin_int *pi= plugin_ref_to_int(rc); @@ -990,6 +994,16 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc) } +/* + Notes on lifetime: + + If THD is passed as non-NULL (and with a non-NULL thd->lex), an entry is made + in the thd->lex which will cause an automatic unlock of the plugin in the LEX + destructor. In this case, no manual unlock must be done. + + Otherwise, when passing a NULL THD, the caller must arrange that plugin + unlock happens later. +*/ plugin_ref plugin_lock(THD *thd, plugin_ref ptr) { LEX *lex= thd ? thd->lex : 0; @@ -1026,6 +1040,16 @@ plugin_ref plugin_lock(THD *thd, plugin_ref ptr) } +/* + Notes on lifetime: + + If THD is passed as non-NULL (and with a non-NULL thd->lex), an entry is made + in the thd->lex which will cause an automatic unlock of the plugin in the LEX + destructor. In this case, no manual unlock must be done. + + Otherwise, when passing a NULL THD, the caller must arrange that plugin + unlock happens later. +*/ plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name, int type) { LEX *lex= thd ? thd->lex : 0; @@ -1645,7 +1669,7 @@ int plugin_init(int *argc, char **argv, int flags) */ global_system_variables.table_plugin = intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); - DBUG_ASSERT(plugin_ptr->ref_count == 1); + DBUG_SLOW_ASSERT(plugin_ptr->ref_count == 1); } mysql_mutex_unlock(&LOCK_plugin); @@ -1816,7 +1840,7 @@ static void plugin_load(MEM_ROOT *tmp_root) goto end; } table->use_all_columns(); - while (!(error= read_record_info.read_record(&read_record_info))) + while (!(error= read_record_info.read_record())) { DBUG_PRINT("info", ("init plugin record")); String str_name, str_dl; @@ -1940,6 +1964,12 @@ void plugin_shutdown(void) if (initialized) { + if (opt_gtid_pos_auto_plugins) + { + free_engine_list(opt_gtid_pos_auto_plugins); + opt_gtid_pos_auto_plugins= NULL; + } + mysql_mutex_lock(&LOCK_plugin); reap_needed= true; @@ -2824,7 +2854,8 @@ sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length, mysql_mutex_unlock(&LOCK_plugin); if (!throw_error && !var) - my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (int)length, (char*) str); + my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), + (int) (length ? length : strlen(str)), (char*) str); DBUG_RETURN(var); } diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 469ae5c88a3..f100e8a232a 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -25,7 +25,7 @@ SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, \ SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, \ SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_LEX_STRING -#include <my_global.h> +#include "mariadb.h" #undef SHOW_always_last #include "m_string.h" /* LEX_STRING */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9de0a6d0e99..7fc6141bcea 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -84,7 +84,7 @@ When one supplies long data for a placeholder: at statement execute. */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_class.h" // set_var.h: THD @@ -2956,7 +2956,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) for (order= sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS bool res= #endif sl->handle_derived(lex, DT_REINIT); @@ -3786,7 +3786,7 @@ void Prepared_statement::cleanup_stmt() { DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: %p", this)); - thd->restore_set_statement_var(); + lex->restore_set_statement_var(); cleanup_items(free_list); thd->cleanup_after_query(); thd->rollback_item_tree_changes(); @@ -4257,7 +4257,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query, packet_end= packet_end_arg; iterations= TRUE; start_param= true; -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS Item *free_list_state= thd->free_list; #endif thd->select_number= select_number_after_prepare; @@ -4482,7 +4482,7 @@ Prepared_statement::reprepare() { swap_prepared_statement(©); swap_parameter_array(param_array, copy.param_array, param_count); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS is_reprepared= TRUE; #endif /* diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 7206162792a..c1a13ebd210 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -29,10 +29,9 @@ - "profiling_history_size", integer, session + global, "Num queries stored?" */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_profile.h" -#include <my_sys.h> #include "sql_show.h" // schema_table_store_record #include "sql_class.h" // THD diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index c01ad90f5d2..057d1a9f46c 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_reload.h" #include "sql_priv.h" #include "mysqld.h" // select_errors diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 2cba634e17c..61e312646da 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -19,7 +19,7 @@ Atomic rename of table; RENAME TABLE t1 to t2, tmp to t1 [,...] */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_rename.h" diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 1f802b7de83..49e3d60795d 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_base.h" diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e4ab9c0b405..394492f6a1d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -29,7 +29,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_select.h" @@ -50,7 +50,6 @@ #include "filesort.h" // filesort_free_buffers #include "sql_union.h" // mysql_union #include "opt_subselect.h" -#include "log_slow.h" #include "sql_derived.h" #include "sql_statistics.h" #include "sql_cte.h" @@ -81,6 +80,9 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "index_merge", "hash_ALL", "hash_range", "hash_index", "hash_index_merge" }; +LEX_CSTRING group_key= {STRING_WITH_LEN("group_key")}; +LEX_CSTRING distinct_key= {STRING_WITH_LEN("distinct_key")}; + struct st_sargable_param; static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); @@ -6284,7 +6286,7 @@ best_access_path(JOIN *join, loose_scan_opt.next_ref_key(); DBUG_PRINT("info", ("Considering ref access on key %s", - keyuse->table->key_info[keyuse->key].name)); + keyuse->table->key_info[keyuse->key].name.str)); do /* For each keypart */ { @@ -9394,7 +9396,8 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->flags= HA_GENERATED_KEY; keyinfo->is_statistics_from_stat_tables= FALSE; - keyinfo->name= (char *) "$hj"; + keyinfo->name.str= "$hj"; + keyinfo->name.length= 3; keyinfo->rec_per_key= (ulong*) thd->calloc(sizeof(ulong)*key_parts); if (!keyinfo->rec_per_key) DBUG_RETURN(TRUE); @@ -10973,32 +10976,32 @@ pick_table_access_method(JOIN_TAB *tab) { case JT_REF: tab->read_first_record= join_read_always_key; - tab->read_record.read_record= join_read_next_same; + tab->read_record.read_record_func= join_read_next_same; break; case JT_REF_OR_NULL: tab->read_first_record= join_read_always_key_or_null; - tab->read_record.read_record= join_read_next_same_or_null; + tab->read_record.read_record_func= join_read_next_same_or_null; break; case JT_CONST: tab->read_first_record= join_read_const; - tab->read_record.read_record= join_no_more_records; + tab->read_record.read_record_func= join_no_more_records; break; case JT_EQ_REF: tab->read_first_record= join_read_key; - tab->read_record.read_record= join_no_more_records; + tab->read_record.read_record_func= join_no_more_records; break; case JT_FT: tab->read_first_record= join_ft_read_first; - tab->read_record.read_record= join_ft_read_next; + tab->read_record.read_record_func= join_ft_read_next; break; case JT_SYSTEM: tab->read_first_record= join_read_system; - tab->read_record.read_record= join_no_more_records; + tab->read_record.read_record_func= join_no_more_records; break; /* keep gcc happy */ @@ -16722,8 +16725,6 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, (int) distinct, (int) save_sum_fields, (ulong) rows_limit, MY_TEST(group))); - thd->query_plan_flags|= QPLAN_TMP_TABLE; - if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES)) temp_pool_slot = bitmap_lock_set_next(&temp_pool); @@ -17286,7 +17287,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, keyinfo->collected_stats= NULL; keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->is_statistics_from_stat_tables= FALSE; - keyinfo->name= (char*) "group_key"; + keyinfo->name= group_key; ORDER *cur_group= group; for (; cur_group ; cur_group= cur_group->next, key_part_info++) { @@ -17397,7 +17398,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL | HA_BINARY_PACK_KEY | HA_PACK_KEY; keyinfo->ext_key_flags= keyinfo->flags; keyinfo->key_length= 0; // Will compute the sum of the parts below. - keyinfo->name= (char*) "distinct_key"; + keyinfo->name= distinct_key; keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->is_statistics_from_stat_tables= FALSE; keyinfo->read_stats= NULL; @@ -17851,7 +17852,6 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, table->in_use->inc_status_created_tmp_disk_tables(); table->in_use->inc_status_created_tmp_tables(); - table->in_use->query_plan_flags|= QPLAN_TMP_DISK; share->db_record_offset= 1; table->set_created(); DBUG_RETURN(0); @@ -18006,7 +18006,6 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, } table->in_use->inc_status_created_tmp_disk_tables(); table->in_use->inc_status_created_tmp_tables(); - table->in_use->query_plan_flags|= QPLAN_TMP_DISK; share->db_record_offset= 1; table->created= TRUE; DBUG_RETURN(0); @@ -18173,7 +18172,12 @@ free_tmp_table(THD *thd, TABLE *entry) { entry->file->ha_index_or_rnd_end(); if (entry->db_stat) + { + entry->file->info(HA_STATUS_VARIABLE); + thd->tmp_tables_size+= (entry->file->stats.data_file_length + + entry->file->stats.index_file_length); entry->file->ha_drop_table(entry->s->table_name.str); + } else entry->file->ha_delete_table(entry->s->table_name.str); delete entry->file; @@ -18514,6 +18518,10 @@ bool instantiate_tmp_table(TABLE *table, KEY *keyinfo, { if (table->s->db_type() == TMP_ENGINE_HTON) { + /* + If it is not heap (in-memory) table then convert index to unique + constrain. + */ if (create_internal_tmp_table(table, keyinfo, start_recinfo, recinfo, options)) return TRUE; @@ -18879,7 +18887,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) skip_over= TRUE; } - error= info->read_record(info); + error= info->read_record(); if (skip_over && !error) { @@ -19722,7 +19730,7 @@ int read_first_record_seq(JOIN_TAB *tab) { if (tab->read_record.table->file->ha_rnd_init_with_error(1)) return 1; - return (*tab->read_record.read_record)(&tab->read_record); + return tab->read_record.read_record(); } static int @@ -19782,7 +19790,7 @@ int join_init_read_record(JOIN_TAB *tab) if (init_read_record(&tab->read_record, tab->join->thd, tab->table, tab->select, tab->filesort_result, 1,1, FALSE)) return 1; - return (*tab->read_record.read_record)(&tab->read_record); + return tab->read_record.read_record(); } int @@ -19802,9 +19810,9 @@ join_read_record_no_init(JOIN_TAB *tab) tab->read_record.copy_field= save_copy; tab->read_record.copy_field_end= save_copy_end; - tab->read_record.read_record= rr_sequential_and_unpack; + tab->read_record.read_record_func= rr_sequential_and_unpack; - return (*tab->read_record.read_record)(&tab->read_record); + return tab->read_record.read_record(); } @@ -19837,7 +19845,7 @@ join_read_first(JOIN_TAB *tab) !table->covering_keys.is_set(tab->index) || table->file->keyread == tab->index); tab->table->status=0; - tab->read_record.read_record=join_read_next; + tab->read_record.read_record_func= join_read_next; tab->read_record.table=table; tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; @@ -19877,7 +19885,7 @@ join_read_last(JOIN_TAB *tab) !table->covering_keys.is_set(tab->index) || table->file->keyread == tab->index); tab->table->status=0; - tab->read_record.read_record=join_read_prev; + tab->read_record.read_record_func= join_read_prev; tab->read_record.table=table; tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; @@ -21843,7 +21851,7 @@ check_reverse_order: with key part (A) and then traverse the index backwards. */ tab->read_first_record= join_read_last_key; - tab->read_record.read_record= join_read_prev_same; + tab->read_record.read_record_func= join_read_prev_same; /* Cancel Pushed Index Condition, as it doesn't work for reverse scans. */ @@ -24456,7 +24464,7 @@ int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table, for (j=0 ; j < table->s->keys ; j++) { if (possible_keys.is_set(j)) - list.append_str(alloc, table->key_info[j].name); + list.append_str(alloc, table->key_info[j].name.str); } return 0; } @@ -26768,7 +26776,7 @@ AGGR_OP::end_send() error= join_init_read_record(join_tab); } else - error= join_tab->read_record.read_record(&join_tab->read_record); + error= join_tab->read_record.read_record(); if (error > 0 || (join->thd->is_error())) // Fatal error rc= NESTED_LOOP_ERROR; diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index eb9dfe012f7..53c9c160593 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -15,6 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mariadb.h" #include "sql_class.h" #include "sql_list.h" #include "sql_sequence.h" @@ -848,7 +849,7 @@ bool Sql_cmd_alter_sequence::execute(THD *thd) 0, 0)) DBUG_RETURN(TRUE); /* purecov: inspected */ - if (check_grant(thd, ALTER_ACL, first_table, FALSE, UINT_MAX, FALSE)) + if (check_grant(thd, ALTER_ACL, first_table, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); /* purecov: inspected */ if (lex->check_exists) diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 5e826dff2e0..30b2e11139b 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -33,7 +33,7 @@ currently running transactions etc will not be disrupted. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_servers.h" #include "unireg.h" @@ -208,7 +208,7 @@ static bool servers_load(THD *thd, TABLE_LIST *tables) if (init_read_record(&read_record_info,thd,table=tables[0].table, NULL, NULL, 1,0, FALSE)) DBUG_RETURN(1); - while (!(read_record_info.read_record(&read_record_info))) + while (!(read_record_info.read_record())) { /* return_val is already TRUE, so no need to set */ if ((get_server_from_table_to_cache(table))) diff --git a/sql/sql_servers.h b/sql/sql_servers.h index d5668f0dfcb..1cb05416c63 100644 --- a/sql/sql_servers.h +++ b/sql/sql_servers.h @@ -16,7 +16,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "my_global.h" /* uint */ #include "slave.h" // for tables_ok(), rpl_filter class THD; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4dcc519029c..de928fe9e85 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -17,7 +17,7 @@ /* Function with list databases, tables or fields */ -#include "sql_plugin.h" // Includes my_global.h +#include "sql_plugin.h" // SHOW_MY_BOOL #include "sql_priv.h" #include "unireg.h" #include "sql_acl.h" // fill_schema_*_privileges @@ -1773,7 +1773,7 @@ static void append_create_options(THD *thd, String *packet, if (opt->quoted_value) append_unescaped(packet, opt->value.str, opt->value.length); else - packet->append(opt->value.str, opt->value.length); + packet->append(&opt->value); } if (in_comment) packet->append(STRING_WITH_LEN(" */")); @@ -2169,7 +2169,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, bool found_primary=0; packet->append(STRING_WITH_LEN(",\n ")); - if (i == primary_key && !strcmp(key_info->name, primary_key_name)) + if (i == primary_key && !strcmp(key_info->name.str, primary_key_name)) { found_primary=1; /* @@ -2188,7 +2188,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN("KEY ")); if (!found_primary) - append_identifier(thd, packet, key_info->name, strlen(key_info->name)); + append_identifier(thd, packet, key_info->name.str, key_info->name.length); packet->append(STRING_WITH_LEN(" (")); @@ -6235,7 +6235,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, table->field[3]->store((longlong) ((key_info->flags & HA_NOSAME) ? 0 : 1), TRUE); table->field[4]->store(db_name->str, db_name->length, cs); - table->field[5]->store(key_info->name, strlen(key_info->name), cs); + table->field[5]->store(key_info->name.str, key_info->name.length, cs); table->field[6]->store((longlong) (j+1), TRUE); str= (key_part->field ? &key_part->field->field_name : &unknown); @@ -6483,17 +6483,17 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, if (i != primary_key && !(key_info->flags & HA_NOSAME)) continue; - if (i == primary_key && !strcmp(key_info->name, primary_key_name)) + if (i == primary_key && !strcmp(key_info->name.str, primary_key_name)) { - if (store_constraints(thd, table, db_name, table_name, key_info->name, - strlen(key_info->name), + if (store_constraints(thd, table, db_name, table_name, + key_info->name.str, key_info->name.length, STRING_WITH_LEN("PRIMARY KEY"))) DBUG_RETURN(1); } else if (key_info->flags & HA_NOSAME) { - if (store_constraints(thd, table, db_name, table_name, key_info->name, - strlen(key_info->name), + if (store_constraints(thd, table, db_name, table_name, + key_info->name.str, key_info->name.length, STRING_WITH_LEN("UNIQUE"))) DBUG_RETURN(1); } @@ -6689,8 +6689,7 @@ static int get_schema_key_column_usage_record(THD *thd, f_idx++; restore_record(table, s->default_values); store_key_column_usage(table, db_name, table_name, - key_info->name, - strlen(key_info->name), + key_info->name.str, key_info->name.length, key_part->field->field_name.str, key_part->field->field_name.length, (longlong) f_idx); @@ -7089,7 +7088,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, tmp_res.length(0); if (part_elem->has_null_value) { - tmp_str.append("NULL"); + tmp_str.append(STRING_WITH_LEN("NULL")); if (num_items > 0) tmp_str.append(","); } @@ -7098,7 +7097,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, if (part_info->column_list) { if (part_info->part_field_list.elements > 1U) - tmp_str.append("("); + tmp_str.append(STRING_WITH_LEN("(")); if (get_partition_column_description(thd, part_info, list_value, diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc index 6a57b8fc9ce..1e1c2c1d624 100644 --- a/sql/sql_signal.cc +++ b/sql/sql_signal.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sp_head.h" #include "sp_pcontext.h" diff --git a/sql/sql_sort.h b/sql/sql_sort.h index 6c97ad7e9ab..d57239671a8 100644 --- a/sql/sql_sort.h +++ b/sql/sql_sort.h @@ -17,7 +17,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "my_base.h" /* ha_rows */ -#include "my_sys.h" /* qsort2_cmp */ +#include <my_sys.h> /* qsort2_cmp */ #include "queues.h" typedef struct st_buffpek BUFFPEK; diff --git a/sql/sql_state.c b/sql/sql_state.c index 2bfd61d6696..046868a78a7 100644 --- a/sql/sql_state.c +++ b/sql/sql_state.c @@ -16,7 +16,7 @@ /* Functions to map mysqld errno to sql_state */ -#include <my_global.h> +#include "mariadb.h" #include <mysqld_error.h> #include <my_base.h> diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 224b7541dee..0048e525cad 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -23,7 +23,7 @@ @{ */ -#include <my_global.h> +#include "mariadb.h" #include "sql_base.h" #include "key.h" #include "sql_statistics.h" @@ -666,16 +666,22 @@ public: { if (find_stat()) { + bool res; store_record_for_update(); store_stat_fields(); - return update_record(); + res= update_record(); + DBUG_ASSERT(res == 0); + return res; } else { int err; store_stat_fields(); if ((err= stat_file->ha_write_row(record[0]))) + { + DBUG_ASSERT(0); return TRUE; + } /* Make change permanent and avoid 'table is marked as crashed' errors */ stat_file->extra(HA_EXTRA_FLUSH); } @@ -1319,8 +1325,8 @@ public: void set_index_prefix_key_fields(KEY *index_info) { set_full_table_name(); - const char *index_name= index_info->name; - index_name_field->store(index_name, strlen(index_name), + const char *index_name= index_info->name.str; + index_name_field->store(index_name, index_info->name.length, system_charset_info); table_key_info= index_info; } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index e07a1cd6820..70ddf7b1241 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -20,8 +20,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> -#include <my_sys.h> +#include "mariadb.h" #include <m_string.h> #include <m_ctype.h> #include <mysql_com.h> diff --git a/sql/sql_string.h b/sql/sql_string.h index 3908cdff252..c88c58b1b40 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -25,7 +25,7 @@ #endif #include "m_ctype.h" /* my_charset_bin */ -#include "my_sys.h" /* alloc_root, my_free, my_realloc */ +#include <my_sys.h> /* alloc_root, my_free, my_realloc */ #include "m_string.h" /* TRASH */ class String; @@ -589,6 +589,10 @@ public: { qs_append(str, (uint32)strlen(str)); } + void qs_append(const LEX_CSTRING *str) + { + qs_append(str->str, str->length); + } void qs_append(const char *str, uint32 len); void qs_append_hex(const char *str, uint32 len); void qs_append(double d); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cfc571b22ef..724389592e3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -18,7 +18,7 @@ /* drop and alter of tables */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "debug_sync.h" @@ -2777,9 +2777,9 @@ static int sort_keys(KEY *a, KEY *b) /* Sort NOT NULL keys before other keys */ return (a_flags & HA_NULL_PART_KEY) ? 1 : -1; } - if (a->name == primary_key_name) + if (a->name.str == primary_key_name) return -1; - if (b->name == primary_key_name) + if (b->name.str == primary_key_name) return 1; /* Sort keys don't containing partial segments before others */ if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG) @@ -3068,34 +3068,29 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info, */ List_iterator_fast<Key_part_spec> k_column_iterator(k->columns); - - bool all_columns_are_identical= true; - + uint i; key_column_iterator.rewind(); - for (uint i= 0; i < key->columns.elements; ++i) + for (i= 0; i < key->columns.elements; ++i) { Key_part_spec *c1= key_column_iterator++; Key_part_spec *c2= k_column_iterator++; DBUG_ASSERT(c1 && c2); - if (my_strcasecmp(system_charset_info, - c1->field_name.str, c2->field_name.str) || + if (lex_string_cmp(system_charset_info, + &c1->field_name, &c2->field_name) || (c1->length != c2->length)) - { - all_columns_are_identical= false; break; - } } // Report a warning if we have two identical keys. - if (all_columns_are_identical) + if (i == key->columns.elements) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_DUP_INDEX, ER_THD(thd, ER_DUP_INDEX), - key_info->name); + key_info->name.str); break; } } @@ -3356,9 +3351,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, /* Check if we have used the same field name before */ for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++) { - if (my_strcasecmp(system_charset_info, - sql_field->field_name.str, - dup_field->field_name.str) == 0) + if (lex_string_cmp(system_charset_info, + &sql_field->field_name, + &dup_field->field_name) == 0) { /* If this was a CREATE ... SELECT statement, accept a field @@ -3690,9 +3685,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, it.rewind(); field=0; while ((sql_field=it++) && - my_strcasecmp(system_charset_info, - column->field_name.str, - sql_field->field_name.str)) + lex_string_cmp(system_charset_info, + &column->field_name, + &sql_field->field_name)) field++; if (!sql_field) { @@ -3701,13 +3696,21 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } while ((dup_column= cols2++) != column) { - if (!my_strcasecmp(system_charset_info, - column->field_name.str, dup_column->field_name.str)) + if (!lex_string_cmp(system_charset_info, + &column->field_name, &dup_column->field_name)) { my_error(ER_DUP_FIELDNAME, MYF(0), column->field_name.str); DBUG_RETURN(TRUE); } } + + if (sql_field->compression_method()) + { + my_error(ER_COMPRESSED_COLUMN_USED_AS_KEY, MYF(0), + column->field_name.str); + DBUG_RETURN(TRUE); + } + cols2.rewind(); if (key->type == Key::FULLTEXT) { @@ -3951,12 +3954,13 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, my_error(ER_DUP_KEYNAME, MYF(0), key_name); DBUG_RETURN(TRUE); } - key_info->name=(char*) key_name; + key_info->name.str= (char*) key_name; + key_info->name.length= strlen(key_name); } } - if (!key_info->name || check_column_name(key_info->name)) + if (!key_info->name.str || check_column_name(key_info->name.str)) { - my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name); + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name.str); DBUG_RETURN(TRUE); } if (key->type == Key::UNIQUE && !(key_info->flags & HA_NULL_PART_KEY)) @@ -3971,7 +3975,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (validate_comment_length(thd, &key->key_create_info.comment, INDEX_COMMENT_MAXLEN, ER_TOO_LONG_INDEX_COMMENT, - key_info->name)) + key_info->name.str)) DBUG_RETURN(TRUE); key_info->comment.length= key->key_create_info.comment.length; @@ -4068,9 +4072,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Virtual_column_info *dup_check; while ((dup_check= dup_it++) && dup_check != check) { - if (check->name.length == dup_check->name.length && - my_strcasecmp(system_charset_info, - check->name.str, dup_check->name.str) == 0) + if (!lex_string_cmp(system_charset_info, + &check->name, &dup_check->name)) { my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "CHECK", check->name.str); DBUG_RETURN(TRUE); @@ -5004,7 +5007,7 @@ static bool check_if_keyname_exists(const char *name, KEY *start, KEY *end) { for (KEY *key=start ; key != end ; key++) - if (!my_strcasecmp(system_charset_info,name,key->name)) + if (!my_strcasecmp(system_charset_info, name, key->name.str)) return 1; return 0; } @@ -5667,8 +5670,9 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info) */ for (f_ptr=table->field; *f_ptr; f_ptr++) { - if (my_strcasecmp(system_charset_info, - sql_field->field_name.str, (*f_ptr)->field_name.str) == 0) + if (lex_string_cmp(system_charset_info, + &sql_field->field_name, + &(*f_ptr)->field_name) == 0) goto drop_create_field; } { @@ -5680,8 +5684,9 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info) Create_field *chk_field; while ((chk_field= chk_it++) && chk_field != sql_field) { - if (my_strcasecmp(system_charset_info, - sql_field->field_name.str, chk_field->field_name.str) == 0) + if (lex_string_cmp(system_charset_info, + &sql_field->field_name, + &chk_field->field_name) == 0) goto drop_create_field; } } @@ -5716,8 +5721,9 @@ drop_create_field: */ for (f_ptr=table->field; *f_ptr; f_ptr++) { - if (my_strcasecmp(system_charset_info, - sql_field->change.str, (*f_ptr)->field_name.str) == 0) + if (lex_string_cmp(system_charset_info, + &sql_field->change, + &(*f_ptr)->field_name) == 0) { break; } @@ -5786,7 +5792,8 @@ drop_create_field: for (n_key=0; n_key < table->s->keys; n_key++) { if (my_strcasecmp(system_charset_info, - drop->name, table->key_info[n_key].name) == 0) + drop->name, + table->key_info[n_key].name.str) == 0) { remove_drop= FALSE; break; @@ -5884,7 +5891,7 @@ drop_create_field: for (n_key=0; n_key < table->s->keys; n_key++) { if (my_strcasecmp(system_charset_info, - keyname, table->key_info[n_key].name) == 0) + keyname, table->key_info[n_key].name.str) == 0) { goto remove_key; } @@ -6035,8 +6042,8 @@ remove_key: { Virtual_column_info *dup= table->check_constraints[c]; if (dup->name.length == check->name.length && - my_strcasecmp(system_charset_info, - check->name.str, dup->name.str) == 0) + lex_string_cmp(system_charset_info, + &check->name, &dup->name) == 0) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_DUP_CONSTRAINT_NAME, ER_THD(thd, ER_DUP_CONSTRAINT_NAME), @@ -6343,8 +6350,8 @@ static bool fill_alter_inplace_info(THD *thd, } /* Check if field was renamed */ - if (my_strcasecmp(system_charset_info, field->field_name.str, - new_field->field_name.str)) + if (lex_string_cmp(system_charset_info, &field->field_name, + &new_field->field_name)) { field->flags|= FIELD_IS_RENAMED; ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_NAME; @@ -6475,7 +6482,8 @@ static bool fill_alter_inplace_info(THD *thd, new_key < new_key_end; new_key++) { - if (! strcmp(table_key->name, new_key->name)) + if (!lex_string_cmp(system_charset_info, &table_key->name, + &new_key->name)) break; } if (new_key >= new_key_end) @@ -6484,7 +6492,7 @@ static bool fill_alter_inplace_info(THD *thd, ha_alter_info->index_drop_buffer [ha_alter_info->index_drop_count++]= table_key; - DBUG_PRINT("info", ("index dropped: '%s'", table_key->name)); + DBUG_PRINT("info", ("index dropped: '%s'", table_key->name.str)); continue; } @@ -6552,7 +6560,7 @@ static bool fill_alter_inplace_info(THD *thd, [ha_alter_info->index_add_count++]= new_key - ha_alter_info->key_info_buffer; /* Mark all old fields which are used in newly created index. */ - DBUG_PRINT("info", ("index changed: '%s'", table_key->name)); + DBUG_PRINT("info", ("index changed: '%s'", table_key->name.str)); } /*end of for (; table_key < table_key_end;) */ @@ -6566,7 +6574,8 @@ static bool fill_alter_inplace_info(THD *thd, /* Search an old key with the same name. */ for (table_key= table->key_info; table_key < table_key_end; table_key++) { - if (! strcmp(table_key->name, new_key->name)) + if (!lex_string_cmp(system_charset_info, &table_key->name, + &new_key->name)) break; } if (table_key >= table_key_end) @@ -6575,7 +6584,7 @@ static bool fill_alter_inplace_info(THD *thd, ha_alter_info->index_add_buffer [ha_alter_info->index_add_count++]= new_key - ha_alter_info->key_info_buffer; - DBUG_PRINT("info", ("index added: '%s'", new_key->name)); + DBUG_PRINT("info", ("index added: '%s'", new_key->name.str)); } else ha_alter_info->create_info->indexes_option_struct[table_key - table->key_info]= @@ -6647,7 +6656,8 @@ static bool fill_alter_inplace_info(THD *thd, if (new_key->flags & HA_NOSAME) { - bool is_pk= !my_strcasecmp(system_charset_info, new_key->name, primary_key_name); + bool is_pk= !my_strcasecmp(system_charset_info, + new_key->name.str, primary_key_name); if ((!(new_key->flags & HA_KEY_HAS_PART_KEY_SEG) && !(new_key->flags & HA_NULL_PART_KEY)) || @@ -6799,9 +6809,9 @@ bool mysql_compare_tables(TABLE *table, create_info->table_options|= HA_OPTION_PACK_RECORD; /* Check if field was renamed */ - if (my_strcasecmp(system_charset_info, - field->field_name.str, - tmp_new_field->field_name.str)) + if (lex_string_cmp(system_charset_info, + &field->field_name, + &tmp_new_field->field_name)) DBUG_RETURN(false); /* Evaluate changes bitmap and send to check_if_incompatible_data() */ @@ -6828,7 +6838,8 @@ bool mysql_compare_tables(TABLE *table, /* Search a key with the same name. */ for (new_key= key_info_buffer; new_key < new_key_end; new_key++) { - if (! strcmp(table_key->name, new_key->name)) + if (!lex_string_cmp(system_charset_info, &table_key->name, + &new_key->name)) break; } if (new_key >= new_key_end) @@ -6867,7 +6878,8 @@ bool mysql_compare_tables(TABLE *table, /* Search a key with the same name. */ for (table_key= table->key_info; table_key < table_key_end; table_key++) { - if (! strcmp(table_key->name, new_key->name)) + if (!lex_string_cmp(system_charset_info, &table_key->name, + &new_key->name)) break; } if (table_key >= table_key_end) @@ -7518,8 +7530,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, while ((def=def_it++)) { if (def->change.str && - !my_strcasecmp(system_charset_info,field->field_name.str, - def->change.str)) + !lex_string_cmp(system_charset_info, &field->field_name, + &def->change)) break; } if (def) @@ -7653,8 +7665,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, find_it.rewind(); while ((find=find_it++)) { - if (!my_strcasecmp(system_charset_info, def->after.str, - find->field_name.str)) + if (!lex_string_cmp(system_charset_info, &def->after, + &find->field_name)) break; } if (!find) @@ -7712,7 +7724,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, for (uint i=0 ; i < table->s->keys ; i++,key_info++) { - const char *key_name= key_info->name; + const char *key_name= key_info->name.str; Alter_drop *drop; drop_it.rewind(); while ((drop=drop_it++)) @@ -8068,8 +8080,8 @@ fk_check_column_changes(THD *thd, Alter_info *alter_info, { Field *old_field= new_field->field; - if (my_strcasecmp(system_charset_info, old_field->field_name.str, - new_field->field_name.str)) + if (lex_string_cmp(system_charset_info, &old_field->field_name, + &new_field->field_name)) { /* Copy algorithm doesn't support proper renaming of columns in @@ -8182,10 +8194,10 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, if ((drop->type == Alter_drop::FOREIGN_KEY) && (my_strcasecmp(system_charset_info, f_key->foreign_id->str, drop->name) == 0) && - (my_strcasecmp(table_alias_charset, f_key->foreign_db->str, - table->s->db.str) == 0) && - (my_strcasecmp(table_alias_charset, f_key->foreign_table->str, - table->s->table_name.str) == 0)) + (lex_string_cmp(table_alias_charset, f_key->foreign_db, + &table->s->db) == 0) && + (lex_string_cmp(table_alias_charset, f_key->foreign_table, + &table->s->table_name) == 0)) fk_parent_key_it.remove(); } } @@ -9777,7 +9789,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, thd->progress.max_counter= from->file->records(); time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10; - while (!(error=info.read_record(&info))) + while (!(error= info.read_record())) { if (thd->killed) { @@ -9946,8 +9958,8 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy) HA_CREATE_INFO create_info; Alter_info alter_info; TABLE_LIST *next_table= table_list->next_global; - DBUG_ENTER("mysql_recreate_table"); + /* Set lock type which is appropriate for ALTER TABLE. */ table_list->lock_type= TL_READ_NO_INSERT; /* Same applies to MDL request. */ @@ -9965,6 +9977,8 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy) if (table_copy) alter_info.requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY; + thd->prepare_logs_for_admin_command(); + bool res= mysql_alter_table(thd, NullS, NullS, &create_info, table_list, &alter_info, 0, (ORDER *) 0, 0); diff --git a/sql/sql_table.h b/sql/sql_table.h index 2e080462deb..e45ddef6548 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -17,8 +17,7 @@ #ifndef SQL_TABLE_INCLUDED #define SQL_TABLE_INCLUDED -#include "my_global.h" /* my_bool */ -#include "my_sys.h" // pthread_mutex_t +#include <my_sys.h> // pthread_mutex_t #include "m_string.h" // LEX_CUSTRING class Alter_info; diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 8b9e14e5a18..93a3007d1ea 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -15,7 +15,7 @@ /* drop and alter of tablespaces */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_tablespace.h" diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 1baa5c3d983..ab12278ef8c 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -16,7 +16,7 @@ /* Write some debug info */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_test.h" diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c8ec1fc7f6a..a8a0ffa3cf2 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -17,7 +17,7 @@ /* Functions to handle date and time */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_time.h" #include "tztime.h" // struct Time_zone diff --git a/sql/sql_time.h b/sql/sql_time.h index 4e8f280514f..1832e4501ed 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -17,7 +17,6 @@ #ifndef SQL_TIME_INCLUDED #define SQL_TIME_INCLUDED -#include "my_global.h" /* ulong */ #include "my_time.h" #include "mysql_time.h" /* timestamp_type */ #include "sql_error.h" /* Sql_condition */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 291d55d61a2..dcce8ae3724 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -16,7 +16,7 @@ #define MYSQL_LEX 1 -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sp_head.h" @@ -688,7 +688,7 @@ static void build_trig_stmt_query(THD *thd, TABLE_LIST *tables, /* Create statement for storing trigger (without trigger order) */ if (lex->trg_chistics.ordering_clause == TRG_ORDER_NONE) - trigger_def->append(stmt_definition.str, stmt_definition.length); + trigger_def->append(&stmt_definition); else { /* Copy data before FOLLOWS/PRECEDES trigger_name */ @@ -750,8 +750,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, DBUG_RETURN(true); /* Trigger must be in the same schema as target table. */ - if (my_strcasecmp(table_alias_charset, table->s->db.str, - lex->spname->m_db.str)) + if (lex_string_cmp(table_alias_charset, &table->s->db, + &lex->spname->m_db)) { my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0)); DBUG_RETURN(true); @@ -923,8 +923,8 @@ err_without_cleanup: if (trigger_dropped) { String drop_trg_query; - drop_trg_query.append("DROP TRIGGER /* generated by failed CREATE TRIGGER */ "); - drop_trg_query.append(lex->spname->m_name.str); + drop_trg_query.append(STRING_WITH_LEN("DROP TRIGGER /* generated by failed CREATE TRIGGER */ ")); + drop_trg_query.append(&lex->spname->m_name); /* We dropped an existing trigger and was not able to recreate it because of an internal error. Ensure it's also dropped on the slave. @@ -1084,8 +1084,8 @@ Trigger *Table_triggers_list::find_trigger(const LEX_CSTRING *name, (trigger= *parent); parent= &trigger->next) { - if (my_strcasecmp(table_alias_charset, - trigger->name.str, name->str) == 0) + if (lex_string_cmp(table_alias_charset, + &trigger->name, name) == 0) { if (remove_from_list) { @@ -1633,8 +1633,8 @@ void Table_triggers_list::add_trigger(trg_event_type event, for ( ; *parent ; parent= &(*parent)->next, position++) { if (ordering_clause != TRG_ORDER_NONE && - !my_strcasecmp(table_alias_charset, anchor_trigger_name->str, - (*parent)->name.str)) + !lex_string_cmp(table_alias_charset, anchor_trigger_name, + &(*parent)->name)) { if (ordering_clause == TRG_ORDER_FOLLOWS) { diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index d4859efc7af..1d6edbc5fc9 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mariadb.h" #include "debug_sync.h" // DEBUG_SYNC #include "table.h" // TABLE, FOREIGN_KEY_INFO #include "sql_class.h" // THD @@ -150,18 +151,18 @@ fk_truncate_illegal_if_parent(THD *thd, TABLE *table) /* Loop over the set of foreign keys for which this table is a parent. */ while ((fk_info= it++)) { - DBUG_ASSERT(!my_strcasecmp(system_charset_info, - fk_info->referenced_db->str, - table->s->db.str)); - - DBUG_ASSERT(!my_strcasecmp(system_charset_info, - fk_info->referenced_table->str, - table->s->table_name.str)); - - if (my_strcasecmp(system_charset_info, fk_info->foreign_db->str, - table->s->db.str) || - my_strcasecmp(system_charset_info, fk_info->foreign_table->str, - table->s->table_name.str)) + DBUG_ASSERT(!lex_string_cmp(system_charset_info, + fk_info->referenced_db, + &table->s->db)); + + DBUG_ASSERT(!lex_string_cmp(system_charset_info, + fk_info->referenced_table, + &table->s->table_name)); + + if (lex_string_cmp(system_charset_info, fk_info->foreign_db, + &table->s->db) || + lex_string_cmp(system_charset_info, fk_info->foreign_table, + &table->s->table_name)) break; } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 737d01f7b89..3ea364f2fba 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mariadb.h" #include "sql_type.h" #include "sql_const.h" #include "sql_class.h" @@ -54,11 +55,13 @@ Type_handler_set type_handler_set; Type_handler_string type_handler_string; Type_handler_var_string type_handler_var_string; Type_handler_varchar type_handler_varchar; +static Type_handler_varchar_compressed type_handler_varchar_compressed; Type_handler_tiny_blob type_handler_tiny_blob; Type_handler_medium_blob type_handler_medium_blob; Type_handler_long_blob type_handler_long_blob; Type_handler_blob type_handler_blob; +static Type_handler_blob_compressed type_handler_blob_compressed; #ifdef HAVE_SPATIAL Type_handler_geometry type_handler_geometry; @@ -922,6 +925,9 @@ Type_handler::get_handler_by_field_type(enum_field_types type) in field_type() context and add DBUG_ASSERT(0) here. */ return &type_handler_newdate; + case MYSQL_TYPE_VARCHAR_COMPRESSED: + case MYSQL_TYPE_BLOB_COMPRESSED: + break; }; DBUG_ASSERT(0); return &type_handler_string; @@ -945,10 +951,12 @@ Type_handler::get_handler_by_real_type(enum_field_types type) case MYSQL_TYPE_DOUBLE: return &type_handler_double; case MYSQL_TYPE_NULL: return &type_handler_null; case MYSQL_TYPE_VARCHAR: return &type_handler_varchar; + case MYSQL_TYPE_VARCHAR_COMPRESSED: return &type_handler_varchar_compressed; case MYSQL_TYPE_TINY_BLOB: return &type_handler_tiny_blob; case MYSQL_TYPE_MEDIUM_BLOB: return &type_handler_medium_blob; case MYSQL_TYPE_LONG_BLOB: return &type_handler_long_blob; case MYSQL_TYPE_BLOB: return &type_handler_blob; + case MYSQL_TYPE_BLOB_COMPRESSED: return &type_handler_blob_compressed; case MYSQL_TYPE_VAR_STRING: /* VAR_STRING is actually a field_type(), not a real_type(), @@ -1304,6 +1312,21 @@ Field *Type_handler_varchar::make_conversion_table_field(TABLE *table, } +Field *Type_handler_varchar_compressed::make_conversion_table_field(TABLE *table, + uint metadata, + const Field *target) + const +{ + return new(table->in_use->mem_root) + Field_varstring_compressed(NULL, metadata, + HA_VARCHAR_PACKLENGTH(metadata), + (uchar *) "", 1, Field::NONE, + &empty_clex_str, + table->s, target->charset(), + zlib_compression_method); +} + + Field *Type_handler_tiny_blob::make_conversion_table_field(TABLE *table, uint metadata, const Field *target) @@ -1326,6 +1349,19 @@ Field *Type_handler_blob::make_conversion_table_field(TABLE *table, } +Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table, + uint metadata, + const Field *target) + const +{ + return new(table->in_use->mem_root) + Field_blob_compressed(NULL, (uchar *) "", 1, Field::NONE, + &empty_clex_str, + table->s, 2, target->charset(), + zlib_compression_method); +} + + Field *Type_handler_medium_blob::make_conversion_table_field(TABLE *table, uint metadata, const Field *target) @@ -1695,6 +1731,7 @@ bool Type_handler_string_result:: const { def->redefine_stage1_common(dup, file, schema); + def->set_compression_method(dup->compression_method()); def->create_length_to_internal_length_string(); return false; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 910172134fd..0354adfde1e 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -2542,6 +2542,14 @@ public: }; +class Type_handler_varchar_compressed: public Type_handler_varchar +{ +public: + Field *make_conversion_table_field(TABLE *, uint metadata, + const Field *target) const; +}; + + class Type_handler_blob_common: public Type_handler_longstr { public: @@ -2642,6 +2650,14 @@ public: }; +class Type_handler_blob_compressed: public Type_handler_blob +{ +public: + Field *make_conversion_table_field(TABLE *, uint metadata, + const Field *target) const; +}; + + #ifdef HAVE_SPATIAL class Type_handler_geometry: public Type_handler_string_result { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 612cc97f6a2..7b2d041a094 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -31,7 +31,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_base.h" // close_mysql_tables @@ -189,7 +189,7 @@ void udf_init() } table->use_all_columns(); - while (!(error= read_record_info.read_record(&read_record_info))) + while (!(error= read_record_info.read_record())) { DBUG_PRINT("info",("init udf record")); LEX_CSTRING name; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 6b5c328fd5d..362837834f2 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -20,7 +20,7 @@ UNION's were introduced by Monty and Sinisa <sinisa@mysql.com> */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_union.h" @@ -73,6 +73,7 @@ void select_unit::change_select() case INTERSECT_TYPE: intersect_mark->value= prev_step= curr_step; curr_step= current_select_number; + /* fall through */ case EXCEPT_TYPE: step= thd->lex->current_select->linkage; break; diff --git a/sql/sql_union.h b/sql/sql_union.h index 171f607fba7..d5659e5d947 100644 --- a/sql/sql_union.h +++ b/sql/sql_union.h @@ -16,8 +16,6 @@ #ifndef SQL_UNION_INCLUDED #define SQL_UNION_INCLUDED -#include "my_global.h" /* ulong */ - class THD; class select_result; struct LEX; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c6959509a08..d188be8bc97 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -20,7 +20,7 @@ Multi-table updates were introduced by Sinisa & Monty */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_update.h" #include "sql_cache.h" // query_cache_* @@ -619,7 +619,7 @@ int mysql_update(THD *thd, THD_STAGE_INFO(thd, stage_searching_rows_for_update); ha_rows tmp_limit= limit; - while (!(error=info.read_record(&info)) && !thd->killed) + while (!(error=info.read_record()) && !thd->killed) { explain->buf_tracker.on_record_read(); thd->inc_examined_row_count(1); @@ -735,7 +735,7 @@ int mysql_update(THD *thd, can_compare_record= records_are_comparable(table); explain->tracker.on_scan_init(); - while (!(error=info.read_record(&info)) && !thd->killed) + while (!(error=info.read_record()) && !thd->killed) { explain->tracker.on_record_read(); thd->inc_examined_row_count(1); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 75d8841d25c..fd6ecbbdec9 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -16,7 +16,7 @@ */ #define MYSQL_LEX 1 -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_view.h" @@ -140,7 +140,7 @@ bool check_duplicate_names(THD *thd, List<Item> &item_list, bool gen_unique_view itc.rewind(); while ((check= itc++) && check != item) { - if (my_strcasecmp(system_charset_info, item->name.str, check->name.str) == 0) + if (lex_string_cmp(system_charset_info, &item->name, &check->name) == 0) { if (!gen_unique_view_name) goto err; @@ -647,8 +647,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, { C_STRING_WITH_LEN("ALTER ") }, { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; - buff.append(command[thd->lex->create_view->mode].str, - command[thd->lex->create_view->mode].length); + buff.append(&command[thd->lex->create_view->mode]); view_store_options(thd, views, &buff); buff.append(STRING_WITH_LEN("VIEW ")); @@ -680,7 +679,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, buff.append(')'); } buff.append(STRING_WITH_LEN(" AS ")); - buff.append(views->source.str, views->source.length); + buff.append(&views->source); int errcode= query_error_code(thd, TRUE); /* diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 3869628dfea..d22fff9d486 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -1,3 +1,20 @@ +/* + Copyright (c) 2016, 2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "mariadb.h" #include "sql_parse.h" #include "sql_select.h" #include "sql_list.h" @@ -5,7 +22,6 @@ #include "filesort.h" #include "sql_base.h" #include "sql_window.h" -#include "my_dbug.h" bool @@ -723,7 +739,7 @@ public: void init(READ_RECORD *info) { ref_length= info->ref_length; - if (info->read_record == rr_from_pointers) + if (info->read_record_func == rr_from_pointers) { io_cache= NULL; cache_start= info->cache_pos; @@ -2683,7 +2699,7 @@ bool compute_window_func(THD *thd, while (true) { - if ((err= info.read_record(&info))) + if ((err= info.read_record())) break; // End of file. /* Remember current row so that we can restore it before computing @@ -3127,5 +3143,3 @@ Window_funcs_computation::save_explain_plan(MEM_ROOT *mem_root, } else #endif - - diff --git a/sql/sql_window.h b/sql/sql_window.h index ed1d9e36492..4cb9c1362f5 100644 --- a/sql/sql_window.h +++ b/sql/sql_window.h @@ -1,8 +1,22 @@ +/* + Copyright (c) 2016, 2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_WINDOW_INCLUDED #define SQL_WINDOW_INCLUDED -#include "my_global.h" #include "item.h" #include "filesort.h" #include "records.h" diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 17fcd83f681..277d67ca014 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -33,7 +33,7 @@ #define Lex (thd->lex) #define Select Lex->current_select -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_parse.h" /* comp_*_creator */ #include "sql_table.h" /* primary_key_name */ @@ -217,7 +217,7 @@ int LEX::case_stmt_action_when(Item *when, bool simple) var= new (thd->mem_root) Item_case_expr(thd, spcont->get_current_case_expr_id()); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS if (var) { var->m_sp= sphead; @@ -399,7 +399,7 @@ LEX::create_item_for_sp_var(LEX_CSTRING *name, sp_variable *spvar, Item_splocal(thd, name, spvar->offset, spvar->sql_type(), pos_in_q, len_in_q); -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS if (item) item->m_sp= sphead; #endif @@ -1285,6 +1285,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token NOMAXVALUE_SYM %token NOMINVALUE_SYM %token NO_WAIT_SYM +%token NOWAIT_SYM %token NO_WRITE_TO_BINLOG %token NTILE_SYM %token NULL_SYM /* SQL-2003-R */ @@ -1642,6 +1643,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <const_simple_string> field_length opt_field_length opt_field_length_default_1 + opt_compression_method %type <string> text_string hex_or_bin_String opt_gconcat_separator @@ -1902,7 +1904,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); parse_vcol_expr vcol_opt_specifier vcol_opt_attribute vcol_opt_attribute_list vcol_attribute opt_serial_attribute opt_serial_attribute_list serial_attribute - explainable_command + explainable_command opt_lock_wait_timeout END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -2548,7 +2550,7 @@ create: if (Lex->add_create_index($2, &$5, $6, $1 | $4)) MYSQL_YYABORT; } - '(' key_list ')' normal_key_options + '(' key_list ')' opt_lock_wait_timeout normal_key_options opt_index_lock_algorithm { } | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident ON table_ident @@ -2558,7 +2560,7 @@ create: if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4)) MYSQL_YYABORT; } - '(' key_list ')' fulltext_key_options + '(' key_list ')' opt_lock_wait_timeout fulltext_key_options opt_index_lock_algorithm { } | create_or_replace spatial INDEX_SYM opt_if_not_exists ident ON table_ident @@ -2568,7 +2570,7 @@ create: if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4)) MYSQL_YYABORT; } - '(' key_list ')' spatial_key_options + '(' key_list ')' opt_lock_wait_timeout spatial_key_options opt_index_lock_algorithm { } | create_or_replace DATABASE opt_if_not_exists ident { @@ -6644,9 +6646,19 @@ attribute: $2->name,Lex->charset->csname)); Lex->last_field->charset= $2; } + | COMPRESSED_SYM opt_compression_method + { + if (Lex->last_field->set_compressed($2)) + MYSQL_YYABORT; + } | serial_attribute ; +opt_compression_method: + /* empty */ { $$= NULL; } + | equal ident { $$= $2.str; } + ; + serial_attribute: not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; } | opt_primary KEY_SYM @@ -7161,7 +7173,7 @@ alter: Lex->create_info.storage_media= HA_SM_DEFAULT; DBUG_ASSERT(!Lex->m_sql_cmd); } - alter_options TABLE_SYM table_ident + alter_options TABLE_SYM table_ident opt_lock_wait_timeout { if (!Lex->select_lex.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, @@ -8276,7 +8288,7 @@ optimize: /* Will be overridden during execution. */ YYPS->m_lock_type= TL_UNLOCK; } - table_list + table_list opt_lock_wait_timeout { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); @@ -8326,13 +8338,13 @@ table_to_table_list: ; table_to_table: - table_ident TO_SYM table_ident + table_ident opt_lock_wait_timeout TO_SYM table_ident { LEX *lex=Lex; SELECT_LEX *sl= lex->current_select; if (!sl->add_table_to_list(thd, $1,NULL,TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE) || - !sl->add_table_to_list(thd, $3,NULL,TL_OPTION_UPDATING, + !sl->add_table_to_list(thd, $4, NULL, TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } @@ -8739,14 +8751,14 @@ select_option: opt_select_lock_type: /* empty */ - | FOR_SYM UPDATE_SYM + | FOR_SYM UPDATE_SYM opt_lock_wait_timeout { LEX *lex=Lex; lex->current_select->lock_type= TL_WRITE; lex->current_select->set_lock_for_tables(TL_WRITE); lex->safe_to_cache_query=0; } - | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM + | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout { LEX *lex=Lex; lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS; @@ -10739,7 +10751,7 @@ variable_aux: thd->parse_error(); MYSQL_YYABORT; } - if (!($$= get_system_var(thd, $2, $3, $4))) + if (!($$= get_system_var(thd, $2, &$3, &$4))) MYSQL_YYABORT; if (!((Item_func_get_system_var*) $$)->is_written_to_binlog()) Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_VARIABLE); @@ -12233,9 +12245,9 @@ drop: YYPS->m_lock_type= TL_UNLOCK; YYPS->m_mdl_type= MDL_EXCLUSIVE; } - table_list opt_restrict + table_list opt_lock_wait_timeout opt_restrict {} - | DROP INDEX_SYM opt_if_exists_table_element ident ON table_ident {} + | DROP INDEX_SYM opt_if_exists_table_element ident ON table_ident opt_lock_wait_timeout { LEX *lex=Lex; Alter_drop *ad= (new (thd->mem_root) @@ -12820,7 +12832,7 @@ truncate: YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } - table_name + table_name opt_lock_wait_timeout { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); @@ -13043,9 +13055,15 @@ show_param: lex->sql_command= SQLCOM_SHOW_PRIVILEGES; } | COUNT_SYM '(' '*' ')' WARNINGS - { (void) create_select_for_variable("warning_count"); } + { + LEX_CSTRING var= {STRING_WITH_LEN("warning_count")}; + (void) create_select_for_variable(thd, &var); + } | COUNT_SYM '(' '*' ')' ERRORS - { (void) create_select_for_variable("error_count"); } + { + LEX_CSTRING var= {STRING_WITH_LEN("error_count")}; + (void) create_select_for_variable(thd, &var); + } | WARNINGS opt_limit_clause { Lex->sql_command = SQLCOM_SHOW_WARNS;} | ERRORS opt_limit_clause @@ -14852,6 +14870,7 @@ keyword_sp_not_data_type: | NOMINVALUE_SYM {} | NOMAXVALUE_SYM {} | NO_WAIT_SYM {} + | NOWAIT_SYM {} | NODEGROUP_SYM {} | NONE_SYM {} | NOTFOUND_SYM {} @@ -15421,10 +15440,27 @@ lock: my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK")); lex->sql_command= SQLCOM_LOCK_TABLES; } - table_lock_list + table_lock_list opt_lock_wait_timeout {} ; +opt_lock_wait_timeout: + /* empty */ + {} + | WAIT_SYM ulong_num + { + if (set_statement_var_if_exists(thd, C_STRING_WITH_LEN("lock_wait_timeout"), $2) || + set_statement_var_if_exists(thd, C_STRING_WITH_LEN("innodb_lock_wait_timeout"), $2)) + MYSQL_YYABORT; + } + | NOWAIT_SYM + { + if (set_statement_var_if_exists(thd, C_STRING_WITH_LEN("lock_wait_timeout"), 0) || + set_statement_var_if_exists(thd, C_STRING_WITH_LEN("innodb_lock_wait_timeout"), 0)) + MYSQL_YYABORT; + } + ; + table_or_tables: TABLE_SYM { } | TABLES { } diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 3f531f07e54..ad8b6697ce7 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -33,7 +33,7 @@ #define Lex (thd->lex) #define Select Lex->current_select -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_parse.h" /* comp_*_creator */ #include "sql_table.h" /* primary_key_name */ @@ -694,6 +694,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token NOMAXVALUE_SYM %token NOMINVALUE_SYM %token NO_WAIT_SYM +%token NOWAIT_SYM %token NO_WRITE_TO_BINLOG %token NTILE_SYM %token NULL_SYM /* SQL-2003-R */ @@ -1327,7 +1328,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); parse_vcol_expr vcol_opt_specifier vcol_opt_attribute vcol_opt_attribute_list vcol_attribute opt_serial_attribute opt_serial_attribute_list serial_attribute - explainable_command + explainable_command opt_lock_wait_timeout set_assign sf_tail_standalone sp_tail_standalone @@ -1989,7 +1990,7 @@ create: if (Lex->add_create_index($2, &$5, $6, $1 | $4)) MYSQL_YYABORT; } - '(' key_list ')' normal_key_options + '(' key_list ')' opt_lock_wait_timeout normal_key_options opt_index_lock_algorithm { } | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident ON table_ident @@ -1999,7 +2000,7 @@ create: if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4)) MYSQL_YYABORT; } - '(' key_list ')' fulltext_key_options + '(' key_list ')' opt_lock_wait_timeout fulltext_key_options opt_index_lock_algorithm { } | create_or_replace spatial INDEX_SYM opt_if_not_exists ident ON table_ident @@ -2009,7 +2010,7 @@ create: if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4)) MYSQL_YYABORT; } - '(' key_list ')' spatial_key_options + '(' key_list ')' opt_lock_wait_timeout spatial_key_options opt_index_lock_algorithm { } | create_or_replace DATABASE opt_if_not_exists ident { @@ -3616,7 +3617,7 @@ opt_parenthesized_cursor_actual_parameters: sp_proc_stmt_open: OPEN_SYM ident opt_parenthesized_cursor_actual_parameters { - if (Lex->sp_open_cursor(thd, &$2, $3)) + if (Lex->sp_open_cursor(thd, &$2, $3)) MYSQL_YYABORT; } ; @@ -7142,7 +7143,7 @@ alter: Lex->create_info.storage_media= HA_SM_DEFAULT; DBUG_ASSERT(!Lex->m_sql_cmd); } - alter_options TABLE_SYM table_ident + alter_options TABLE_SYM table_ident opt_lock_wait_timeout { if (!Lex->select_lex.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, @@ -8257,7 +8258,7 @@ optimize: /* Will be overridden during execution. */ YYPS->m_lock_type= TL_UNLOCK; } - table_list + table_list opt_lock_wait_timeout { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); @@ -8307,13 +8308,13 @@ table_to_table_list: ; table_to_table: - table_ident TO_SYM table_ident + table_ident opt_lock_wait_timeout TO_SYM table_ident { LEX *lex=Lex; SELECT_LEX *sl= lex->current_select; if (!sl->add_table_to_list(thd, $1,NULL,TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE) || - !sl->add_table_to_list(thd, $3,NULL,TL_OPTION_UPDATING, + !sl->add_table_to_list(thd, $4, NULL, TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } @@ -8720,14 +8721,14 @@ select_option: opt_select_lock_type: /* empty */ - | FOR_SYM UPDATE_SYM + | FOR_SYM UPDATE_SYM opt_lock_wait_timeout { LEX *lex=Lex; lex->current_select->lock_type= TL_WRITE; lex->current_select->set_lock_for_tables(TL_WRITE); lex->safe_to_cache_query=0; } - | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM + | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout { LEX *lex=Lex; lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS; @@ -10769,7 +10770,7 @@ variable_aux: thd->parse_error(); MYSQL_YYABORT; } - if (!($$= get_system_var(thd, $2, $3, $4))) + if (!($$= get_system_var(thd, $2, &$3, &$4))) MYSQL_YYABORT; if (!((Item_func_get_system_var*) $$)->is_written_to_binlog()) Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_VARIABLE); @@ -12289,9 +12290,9 @@ drop: YYPS->m_lock_type= TL_UNLOCK; YYPS->m_mdl_type= MDL_EXCLUSIVE; } - table_list opt_restrict + table_list opt_lock_wait_timeout opt_restrict {} - | DROP INDEX_SYM opt_if_exists_table_element ident ON table_ident {} + | DROP INDEX_SYM opt_if_exists_table_element ident ON table_ident opt_lock_wait_timeout { LEX *lex=Lex; Alter_drop *ad= (new (thd->mem_root) @@ -12876,7 +12877,7 @@ truncate: YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } - table_name + table_name opt_lock_wait_timeout { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); @@ -13106,9 +13107,15 @@ show_param: lex->sql_command= SQLCOM_SHOW_PRIVILEGES; } | COUNT_SYM '(' '*' ')' WARNINGS - { (void) create_select_for_variable("warning_count"); } + { + LEX_CSTRING var= {STRING_WITH_LEN("warning_count")}; + (void) create_select_for_variable(thd, &var); + } | COUNT_SYM '(' '*' ')' ERRORS - { (void) create_select_for_variable("error_count"); } + { + LEX_CSTRING var= {STRING_WITH_LEN("error_count")}; + (void) create_select_for_variable(thd, &var); + } | WARNINGS opt_limit_clause { Lex->sql_command = SQLCOM_SHOW_WARNS;} | ERRORS opt_limit_clause @@ -15022,6 +15029,7 @@ keyword_sp_not_data_type: | NOMINVALUE_SYM {} | NOMAXVALUE_SYM {} | NO_WAIT_SYM {} + | NOWAIT_SYM {} | NODEGROUP_SYM {} | NONE_SYM {} | NOTFOUND_SYM {} @@ -15073,7 +15081,7 @@ keyword_sp_not_data_type: | RESUME_SYM {} | RETURNED_SQLSTATE_SYM {} | RETURNS_SYM {} - | REUSE_SYM {} /* Oracle-R */ + | REUSE_SYM {} | REVERSE_SYM {} | ROLE_SYM {} | ROLLUP_SYM {} @@ -15644,10 +15652,27 @@ lock: my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK")); lex->sql_command= SQLCOM_LOCK_TABLES; } - table_lock_list + table_lock_list opt_lock_wait_timeout {} ; +opt_lock_wait_timeout: + /* empty */ + {} + | WAIT_SYM ulong_num + { + if (set_statement_var_if_exists(thd, C_STRING_WITH_LEN("lock_wait_timeout"), $2) || + set_statement_var_if_exists(thd, C_STRING_WITH_LEN("innodb_lock_wait_timeout"), $2)) + MYSQL_YYABORT; + } + | NOWAIT_SYM + { + if (set_statement_var_if_exists(thd, C_STRING_WITH_LEN("lock_wait_timeout"), 0) || + set_statement_var_if_exists(thd, C_STRING_WITH_LEN("innodb_lock_wait_timeout"), 0)) + MYSQL_YYABORT; + } + ; + table_or_tables: TABLE_SYM { } | TABLES { } diff --git a/sql/strfunc.cc b/sql/strfunc.cc index b09eadb098e..f4c8fcd517f 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -15,7 +15,7 @@ /* Some useful string utility functions used by the MySQL server */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "strfunc.h" diff --git a/sql/strfunc.h b/sql/strfunc.h index 7f3021e1a6d..1aba0bff422 100644 --- a/sql/strfunc.h +++ b/sql/strfunc.h @@ -16,8 +16,6 @@ #ifndef STRFUNC_INCLUDED #define STRFUNC_INCLUDED -#include "my_global.h" /* ulonglong, uint */ - typedef struct st_typelib TYPELIB; ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs, diff --git a/sql/structs.h b/sql/structs.h index 97702e5727b..793be462b26 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -109,9 +109,9 @@ typedef struct st_key { pk2 is explicitly present in idx1, it is not in the extension, so ext_key_part_map.is_set(1) == false */ + LEX_CSTRING name; key_part_map ext_key_part_map; uint block_size; - uint name_length; enum ha_key_alg algorithm; /* The flag is on if statistical data for the index prefixes @@ -128,7 +128,6 @@ typedef struct st_key { LEX_CSTRING *parser_name; /* Fulltext [pre]parser name */ }; KEY_PART_INFO *key_part; - const char *name; /* Name of key */ /* Unique name for cache; db + \0 + table_name + \0 + key_name + \0 */ uchar *cache_name; /* diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index eb154d215d3..d16ae7f85a3 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -31,7 +31,7 @@ (for example in storage/myisam/ha_myisam.cc) ! */ -#include "sql_plugin.h" // Includes my_global.h +#include "sql_plugin.h" #include "sql_priv.h" #include "sql_class.h" // set_var.h: THD #include "sys_vars.ic" @@ -50,7 +50,6 @@ #include "sql_base.h" // close_cached_tables #include "hostname.h" // host_cache_size #include <myisam.h> -#include "log_slow.h" #include "debug_sync.h" // DEBUG_SYNC #include "sql_show.h" @@ -764,6 +763,53 @@ static Sys_var_struct Sys_collation_server( offsetof(CHARSET_INFO, name), DEFAULT(&default_charset_info), NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_collation_not_null)); +static Sys_var_uint Sys_column_compression_threshold( + "column_compression_threshold", + "Minimum column data length eligible for compression", + SESSION_VAR(column_compression_threshold), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, UINT_MAX), DEFAULT(100), BLOCK_SIZE(1)); + +static Sys_var_uint Sys_column_compression_zlib_level( + "column_compression_zlib_level", + "zlib compression level (1 gives best speed, 9 gives best compression)", + SESSION_VAR(column_compression_zlib_level), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 9), DEFAULT(6), BLOCK_SIZE(1)); + +/* + Note that names must correspond to zlib strategy definition. So that we can + pass column_compression_zlib_strategy directly to deflateInit2(). +*/ +static const char *column_compression_zlib_strategy_names[]= +{ "DEFAULT_STRATEGY", "FILTERED", "HUFFMAN_ONLY", "RLE", "FIXED", 0 }; + +static Sys_var_enum Sys_column_compression_zlib_strategy( + "column_compression_zlib_strategy", + "The strategy parameter is used to tune the compression algorithm. Use " + "the value DEFAULT_STRATEGY for normal data, FILTERED for data produced " + "by a filter (or predictor), HUFFMAN_ONLY to force Huffman encoding " + "only (no string match), or RLE to limit match distances to one " + "(run-length encoding). Filtered data consists mostly of small values " + "with a somewhat random distribution. In this case, the compression " + "algorithm is tuned to compress them better. The effect of FILTERED is " + "to force more Huffman coding and less string matching; it is somewhat " + "intermediate between DEFAULT_STRATEGY and HUFFMAN_ONLY. RLE is " + "designed to be almost as fast as HUFFMAN_ONLY, but give better " + "compression for PNG image data. The strategy parameter only affects " + "the compression ratio but not the correctness of the compressed output " + "even if it is not set appropriately. FIXED prevents the use of dynamic " + "Huffman codes, allowing for a simpler decoder for special " + "applications.", + SESSION_VAR(column_compression_zlib_strategy), CMD_LINE(REQUIRED_ARG), + column_compression_zlib_strategy_names, DEFAULT(0)); + +static Sys_var_mybool Sys_column_compression_zlib_wrap( + "column_compression_zlib_wrap", + "Generate zlib header and trailer and compute adler32 check value. " + "It can be used with storage engines that don't provide data integrity " + "verification to detect data corruption.", + SESSION_VAR(column_compression_zlib_wrap), CMD_LINE(OPT_ARG), + DEFAULT(FALSE)); + static const char *concurrent_insert_names[]= {"NEVER", "AUTO", "ALWAYS", 0}; static Sys_var_enum Sys_concurrent_insert( "concurrent_insert", "Use concurrent insert with MyISAM", @@ -1165,7 +1211,7 @@ static Sys_var_ulong Sys_lock_wait_timeout( "lock_wait_timeout", "Timeout in seconds to wait for a lock before returning an error.", SESSION_VAR(lock_wait_timeout), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(24 * 60 * 60), BLOCK_SIZE(1)); + VALID_RANGE(0, LONG_TIMEOUT), DEFAULT(24 * 60 * 60), BLOCK_SIZE(1)); #ifdef HAVE_MLOCKALL static Sys_var_mybool Sys_locked_in_memory( @@ -1212,25 +1258,28 @@ static Sys_var_charptr Sys_log_error( CMD_LINE(OPT_ARG, OPT_LOG_ERROR), IN_FS_CHARSET, DEFAULT(disabled_my_option)); -static Sys_var_mybool Sys_log_queries_not_using_indexes( +static Sys_var_bit Sys_log_queries_not_using_indexes( "log_queries_not_using_indexes", "Log queries that are executed without benefit of any index to the " - "slow log if it is open", - GLOBAL_VAR(opt_log_queries_not_using_indexes), - CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + "slow log if it is open. Same as log_slow_filter='not_using_index'", + SESSION_VAR(log_slow_filter), CMD_LINE(OPT_ARG), QPLAN_NOT_USING_INDEX, + DEFAULT(FALSE)); -static Sys_var_mybool Sys_log_slow_admin_statements( +static Sys_var_bit Sys_log_slow_admin_statements( "log_slow_admin_statements", - "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to " - "the slow log if it is open.", - GLOBAL_VAR(opt_log_slow_admin_statements), - CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements " + "to the slow log if it is open. Resets or sets the option 'admin' in " + "log_slow_disabled_statements", + SESSION_VAR(log_slow_disabled_statements), + CMD_LINE(OPT_ARG), REVERSE(LOG_SLOW_DISABLE_ADMIN), DEFAULT(TRUE)); -static Sys_var_mybool Sys_log_slow_slave_statements( +static Sys_var_bit Sys_log_slow_slave_statements( "log_slow_slave_statements", - "Log slow statements executed by slave thread to the slow log if it is open.", - GLOBAL_VAR(opt_log_slow_slave_statements), - CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + "Log slow statements executed by slave thread to the slow log if it is " + "open. Resets or sets the option 'slave' in " + "log_slow_disabled_statements", + SESSION_VAR(log_slow_disabled_statements), + CMD_LINE(OPT_ARG), REVERSE(LOG_SLOW_DISABLE_SLAVE), DEFAULT(TRUE)); static Sys_var_ulong Sys_log_warnings( "log_warnings", @@ -3552,6 +3601,27 @@ static Sys_var_ulong Sys_net_wait_timeout( VALID_RANGE(1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)), DEFAULT(NET_WAIT_TIMEOUT), BLOCK_SIZE(1)); +static Sys_var_uint Sys_idle_transaction_timeout( + "idle_transaction_timeout", + "The number of seconds the server waits for idle transaction", + SESSION_VAR(idle_transaction_timeout), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)), + DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_uint Sys_idle_readonly_transaction_timeout( + "idle_readonly_transaction_timeout", + "The number of seconds the server waits for read-only idle transaction", + SESSION_VAR(idle_readonly_transaction_timeout), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)), + DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_uint Sys_idle_write_transaction_timeout( + "idle_write_transaction_timeout", + "The number of seconds the server waits for write idle transaction", + SESSION_VAR(idle_write_transaction_timeout), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)), + DEFAULT(0), BLOCK_SIZE(1)); + static Sys_var_plugin Sys_default_storage_engine( "default_storage_engine", "The default storage engine for new tables", SESSION_VAR(table_plugin), NO_CMD_LINE, @@ -3576,6 +3646,45 @@ static Sys_var_plugin Sys_enforce_storage_engine( NO_CMD_LINE, MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); + +#ifdef HAVE_REPLICATION +/* + Check + 1. Value for gtid_pos_auto_engines is not NULL. + 2. No slave SQL thread is running. +*/ +static bool +check_gtid_pos_auto_engines(sys_var *self, THD *thd, set_var *var) +{ + bool running; + bool err= false; + + DBUG_ASSERT(var->type == OPT_GLOBAL); + if (var->value && var->value->is_null()) + err= true; + else + { + running= give_error_if_slave_running(false); + if (running) + err= true; + } + return err; +} + + +static Sys_var_pluginlist Sys_gtid_pos_auto_engines( + "gtid_pos_auto_engines", + "List of engines for which to automatically create a " + "mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine " + "is replicated. This can be used to avoid introducing cross-engine " + "transactions, if engines are used different from that used by table " + "mysql.gtid_slave_pos", + GLOBAL_VAR(opt_gtid_pos_auto_plugins), NO_CMD_LINE, + DEFAULT(>id_pos_auto_engines), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_gtid_pos_auto_engines)); +#endif + + #if defined(ENABLED_DEBUG_SYNC) /* Variable can be set for the session only. @@ -4131,6 +4240,17 @@ static Sys_var_charptr Sys_license( READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET, DEFAULT(STRINGIFY_ARG(LICENSE))); +char *my_proxy_protocol_networks; +static Sys_var_charptr Sys_proxy_protocol_networks( + "proxy_protocol_networks", "Enable proxy protocol for these source " + "networks. The syntax is a comma separated list of IPv4 and IPv6 " + "networks. If the network doesn't contain mask, it is considered to be " + "a single host. \"*\" represents all networks and must the only " + "directive on the line. String \"localhost\" represents non-TCP " + "local connections (Unix domain socket, Windows named pipe or shared memory).", + READ_ONLY GLOBAL_VAR(my_proxy_protocol_networks), + CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT("")); + static bool check_log_path(sys_var *self, THD *thd, set_var *var) { if (!var->value) @@ -4367,6 +4487,7 @@ static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type) return res; } + static bool check_not_empty_set(sys_var *self, THD *thd, set_var *var) { return var->save_result.ulonglong_value == 0; @@ -5257,15 +5378,42 @@ static Sys_var_keycache Sys_key_cache_segments( ON_UPDATE(repartition_keycache)); static const char *log_slow_filter_names[]= -{ "admin", "filesort", "filesort_on_disk", "full_join", "full_scan", - "query_cache", "query_cache_miss", "tmp_table", "tmp_table_on_disk", 0 +{ + "admin", "filesort", "filesort_on_disk", "filsort_priority_queue", + "full_join", "full_scan", "not_using_index", "query_cache", + "query_cache_miss", "tmp_table", "tmp_table_on_disk", 0 }; + + static Sys_var_set Sys_log_slow_filter( "log_slow_filter", - "Log only certain types of queries", + "Log only certain types of queries to the slow log. If variable empty alll kind of queries are logged. All types are bound by slow_query_time, except 'not_using_index' which is always logged if enabled", SESSION_VAR(log_slow_filter), CMD_LINE(REQUIRED_ARG), log_slow_filter_names, - DEFAULT(my_set_bits(array_elements(log_slow_filter_names)-1))); + /* by default we log all queries except 'not_using_index' */ + DEFAULT(my_set_bits(array_elements(log_slow_filter_names)-1) & + ~QPLAN_NOT_USING_INDEX)); + +static const char *log_slow_disabled_statements_names[]= +{ "admin", "call", "slave", "sp", 0 }; + +static const char *log_disabled_statements_names[]= +{ "slave", "sp", 0 }; + +static Sys_var_set Sys_log_slow_disabled_statements( + "log_slow_disabled_statements", + "Don't log certain types of statements to slow log", + SESSION_VAR(log_slow_disabled_statements), CMD_LINE(REQUIRED_ARG), + log_slow_disabled_statements_names, + DEFAULT(LOG_SLOW_DISABLE_SP)); + +static Sys_var_set Sys_log_disabled_statements( + "log_disabled_statements", + "Don't log certain types of statements to general log", + SESSION_VAR(log_disabled_statements), CMD_LINE(REQUIRED_ARG), + log_disabled_statements_names, + DEFAULT(LOG_DISABLE_SP), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); static const char *default_regex_flags_names[]= { @@ -5570,12 +5718,10 @@ static Sys_var_ulonglong Sys_max_thread_mem( static Sys_var_sesvartrack Sys_track_session_sys_vars( "session_track_system_variables", - "Track changes in registered system variables. " - "For compatibility with MySQL defaults this variable should be set to " - "\"autocommit, character_set_client, character_set_connection, " - "character_set_results, time_zone\"", + "Track changes in registered system variables. ", CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET, - DEFAULT(""), + DEFAULT("autocommit,character_set_client,character_set_connection," + "character_set_results,time_zone"), NO_MUTEX_GUARD); static bool update_session_track_schema(sys_var *self, THD *thd, diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index ba58315b449..da6d902a167 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -88,7 +88,7 @@ while(!(X)) \ { \ fprintf(stderr, "Sysvar '%s' failed '%s'\n", name_arg, #X); \ - DBUG_ABORT(); \ + DBUG_ASSERT(0); \ exit(255); \ } @@ -612,7 +612,7 @@ public: /* parse and feel list with default values */ if (thd) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS bool res= #endif sysvartrack_validate_value(thd, @@ -1535,6 +1535,116 @@ public: { return valptr(thd, get_default(thd)); } }; +/** + Class for variables that containg a list of plugins. + Currently this is used only for @@gtid_pos_auto_create_engines + + Backing store: plugin_ref + + @note + Currently this is only used for storage engine type plugins, and thus only + storage engine type plugin is implemented. It could be extended to other + plugin types later if needed, similar to Sys_var_plugin. + + These variables don't support command-line equivalents, any such + command-line options should be added manually to my_long_options in mysqld.cc + + Note on lifetimes of resources allocated: We allocate a zero-terminated array + of plugin_ref*, and lock the contained plugins. The list in the global + variable must be freed (with free_engine_list()). However, the way Sys_var + works, there is no place to explicitly free other lists, like the one + returned from get_default(). + + Therefore, the code needs to work with temporary lists, which are + registered in the THD to be automatically freed (and plugins similarly + automatically unlocked). This is why do_check() allocates a temporary + list, from which do_update() then makes a permanent copy. +*/ +class Sys_var_pluginlist: public sys_var +{ + int plugin_type; +public: + Sys_var_pluginlist(const char *name_arg, + const char *comment, int flag_args, ptrdiff_t off, size_t size, + CMD_LINE getopt, + char **def_val, PolyLock *lock=0, + enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, + on_check_function on_check_func=0, + on_update_function on_update_func=0, + const char *substitute=0) + : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, + getopt.arg_type, SHOW_CHAR, (intptr)def_val, + lock, binlog_status_arg, on_check_func, on_update_func, + substitute) + { + option.var_type|= GET_STR; + SYSVAR_ASSERT(size == sizeof(plugin_ref)); + SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE + } + bool do_check(THD *thd, set_var *var) + { + char buff[STRING_BUFFER_USUAL_SIZE]; + String str(buff,sizeof(buff), system_charset_info), *res; + plugin_ref *plugins; + + if (!(res=var->value->val_str(&str))) + plugins= resolve_engine_list(thd, "", 0, true, true); + else + plugins= resolve_engine_list(thd, res->ptr(), res->length(), true, true); + if (!plugins) + return true; + var->save_result.plugins= plugins; + return false; + } + void do_update(plugin_ref **valptr, plugin_ref* newval) + { + plugin_ref *oldval= *valptr; + *valptr= copy_engine_list(newval); + free_engine_list(oldval); + } + bool session_update(THD *thd, set_var *var) + { + do_update((plugin_ref**)session_var_ptr(thd), + var->save_result.plugins); + return false; + } + bool global_update(THD *thd, set_var *var) + { + do_update((plugin_ref**)global_var_ptr(), + var->save_result.plugins); + return false; + } + void session_save_default(THD *thd, set_var *var) + { + plugin_ref* plugins= global_var(plugin_ref *); + var->save_result.plugins= plugins ? temp_copy_engine_list(thd, plugins) : 0; + } + plugin_ref *get_default(THD *thd) + { + char *default_value= *reinterpret_cast<char**>(option.def_value); + if (!default_value) + return 0; + return resolve_engine_list(thd, default_value, strlen(default_value), + false, true); + } + + void global_save_default(THD *thd, set_var *var) + { + var->save_result.plugins= get_default(thd); + } + + uchar *valptr(THD *thd, plugin_ref *plugins) + { + return (uchar*)pretty_print_engine_list(thd, plugins); + } + uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) + { return valptr(thd, session_var(thd, plugin_ref*)); } + uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) + { return valptr(thd, global_var(plugin_ref*)); } + uchar *default_value_ptr(THD *thd) + { return valptr(thd, get_default(thd)); } +}; + #if defined(ENABLED_DEBUG_SYNC) #include "debug_sync.h" @@ -1654,12 +1764,12 @@ public: binlog_status_arg, on_check_func, on_update_func, substitute) { - option.var_type|= GET_BOOL; + option.var_type|= GET_BIT; reverse_semantics= my_count_bits(bitmask_arg) > 1; bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg; + option.block_size= reverse_semantics ? -(long) bitmask : bitmask; set(global_var_ptr(), def_val); SYSVAR_ASSERT(def_val < 2); - SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE SYSVAR_ASSERT(size == sizeof(ulonglong)); } bool session_update(THD *thd, set_var *var) diff --git a/sql/table.cc b/sql/table.cc index 7131e9d4a7d..70adb869e0a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -17,7 +17,7 @@ /* Some general useful functions */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "table.h" #include "key.h" // find_ref_key @@ -251,30 +251,18 @@ TABLE_CATEGORY get_table_category(const LEX_CSTRING *db, if (is_infoschema_db(db->str, db->length)) return TABLE_CATEGORY_INFORMATION; - if ((db->length == PERFORMANCE_SCHEMA_DB_NAME.length) && - (my_strcasecmp(system_charset_info, - PERFORMANCE_SCHEMA_DB_NAME.str, - db->str) == 0)) + if (lex_string_eq(&PERFORMANCE_SCHEMA_DB_NAME, db) == 0) return TABLE_CATEGORY_PERFORMANCE; - if ((db->length == MYSQL_SCHEMA_NAME.length) && - (my_strcasecmp(system_charset_info, - MYSQL_SCHEMA_NAME.str, - db->str) == 0)) + if (lex_string_eq(&MYSQL_SCHEMA_NAME, db) == 0) { if (is_system_table_name(name->str, name->length)) return TABLE_CATEGORY_SYSTEM; - if ((name->length == GENERAL_LOG_NAME.length) && - (my_strcasecmp(system_charset_info, - GENERAL_LOG_NAME.str, - name->str) == 0)) + if (lex_string_eq(&GENERAL_LOG_NAME, name) == 0) return TABLE_CATEGORY_LOG; - if ((name->length == SLOW_LOG_NAME.length) && - (my_strcasecmp(system_charset_info, - SLOW_LOG_NAME.str, - name->str) == 0)) + if (lex_string_eq(&SLOW_LOG_NAME, name) == 0) return TABLE_CATEGORY_LOG; } @@ -328,8 +316,13 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, share->normalized_path.length= path_length; share->table_category= get_table_category(& share->db, & share->table_name); share->open_errno= ENOENT; - /* The following will be fixed in open_table_from_share */ - share->cached_row_logging_check= 1; + /* The following will be updated in open_table_from_share */ + share->can_do_row_logging= 1; + if (share->table_category == TABLE_CATEGORY_LOG) + share->no_replicate= 1; + if (my_strnncoll(table_alias_charset, (uchar*) db, 6, + (const uchar*) "mysql", 6) == 0) + share->not_usable_by_query_cache= 1; init_sql_alloc(&share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); @@ -402,8 +395,8 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, share->normalized_path.str= (char*) path; share->path.length= share->normalized_path.length= strlen(path); share->frm_version= FRM_VER_CURRENT; - - share->cached_row_logging_check= 0; // No row logging + share->not_usable_by_query_cache= 1; + share->can_do_row_logging= 0; // No row logging /* table_map_id is also used for MERGE tables to suppress repeated @@ -2124,18 +2117,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, for (uint key=0 ; key < keys ; key++,keyinfo++) { uint usable_parts= 0; - keyinfo->name=(char*) share->keynames.type_names[key]; - keyinfo->name_length= strlen(keyinfo->name); + keyinfo->name.str= share->keynames.type_names[key]; + keyinfo->name.length= strlen(keyinfo->name.str); keyinfo->cache_name= (uchar*) alloc_root(&share->mem_root, share->table_cache_key.length+ - keyinfo->name_length + 1); + keyinfo->name.length + 1); if (keyinfo->cache_name) // If not out of memory { uchar *pos= keyinfo->cache_name; memcpy(pos, share->table_cache_key.str, share->table_cache_key.length); - memcpy(pos + share->table_cache_key.length, keyinfo->name, - keyinfo->name_length+1); + memcpy(pos + share->table_cache_key.length, keyinfo->name.str, + keyinfo->name.length+1); } if (!key) @@ -3379,24 +3372,20 @@ partititon_err: outparam->mark_columns_used_by_check_constraints(); - if (share->table_category == TABLE_CATEGORY_LOG) - { - outparam->no_replicate= TRUE; - } - else if (outparam->file) + if (db_stat) { + /* Set some flags in share on first open of the table */ handler::Table_flags flags= outparam->file->ha_table_flags(); - outparam->no_replicate= ! MY_TEST(flags & (HA_BINLOG_STMT_CAPABLE - | HA_BINLOG_ROW_CAPABLE)) - || MY_TEST(flags & HA_HAS_OWN_BINLOGGING); - } - else - { - outparam->no_replicate= FALSE; + if (! MY_TEST(flags & (HA_BINLOG_STMT_CAPABLE | + HA_BINLOG_ROW_CAPABLE)) || + MY_TEST(flags & HA_HAS_OWN_BINLOGGING)) + share->no_replicate= TRUE; + if (outparam->file->table_cache_type() & HA_CACHE_TBL_NOCACHE) + share->not_usable_by_query_cache= TRUE; } - if (outparam->no_replicate || !binlog_filter->db_ok(outparam->s->db.str)) - outparam->s->cached_row_logging_check= 0; // No row based replication + if (share->no_replicate || !binlog_filter->db_ok(share->db.str)) + share->can_do_row_logging= 0; // No row based replication /* Increment the opened_tables counter, only when open flags set. */ if (db_stat) @@ -6906,7 +6895,8 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, if (unique) keyinfo->flags|= HA_NOSAME; sprintf(buf, "key%i", key); - if (!(keyinfo->name= strdup_root(&mem_root, buf))) + keyinfo->name.length= strlen(buf); + if (!(keyinfo->name.str= strmake_root(&mem_root, buf, keyinfo->name.length))) return TRUE; keyinfo->rec_per_key= (ulong*) alloc_root(&mem_root, sizeof(ulong)*key_parts); @@ -8307,7 +8297,7 @@ Field *TABLE::find_field_by_name(LEX_CSTRING *str) const for (Field **tmp= field; *tmp; tmp++) { if ((*tmp)->field_name.length == length && - !my_strcasecmp(system_charset_info, (*tmp)->field_name.str, str->str)) + !lex_string_cmp(system_charset_info, &(*tmp)->field_name, str)) return *tmp; } return NULL; diff --git a/sql/table.h b/sql/table.h index 77a75335f75..9ecec6d636c 100644 --- a/sql/table.h +++ b/sql/table.h @@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_plist.h" #include "sql_list.h" /* Sql_alloc */ #include "mdl.h" @@ -694,6 +693,8 @@ struct TABLE_SHARE bool use_ext_keys; /* Extended keys can be used */ bool null_field_first; bool system; /* Set if system table (one record) */ + bool not_usable_by_query_cache; + bool no_replicate; bool crypted; /* If .frm file is crypted */ bool crashed; bool is_view; @@ -703,6 +704,8 @@ struct TABLE_SHARE bool vcols_need_refixing; bool check_set_initialized; bool has_update_default_function; + bool can_do_row_logging; /* 1 if table supports RBR */ + ulong table_map_id; /* for row-based replication */ /* @@ -721,14 +724,6 @@ struct TABLE_SHARE /* For sequence tables, the current sequence state */ SEQUENCE *sequence; - /* - Cache for row-based replication table share checks that does not - need to be repeated. Possible values are: -1 when cache value is - not calculated yet, 0 when table *shall not* be replicated, 1 when - table *may* be replicated. - */ - int cached_row_logging_check; - /* Name of the tablespace used for this table */ char *tablespace; @@ -1255,7 +1250,6 @@ public: If set, indicate that the table is not replicated by the server. */ bool locked_by_logger; - bool no_replicate; bool locked_by_name; bool fulltext_searched; bool no_cache; @@ -2083,9 +2077,6 @@ struct TABLE_LIST /* Don't associate a table share. */ OPEN_STUB } open_strategy; - /* For transactional locking. */ - int lock_timeout; /* NOWAIT or WAIT [X] */ - bool lock_transactional; /* If transactional lock requested. */ /** TRUE if an alias for this table was specified in the SQL. */ bool is_alias; /** TRUE if the table is referred to in the statement using a fully @@ -2614,7 +2605,7 @@ static inline void tmp_restore_column_map(MY_BITMAP *bitmap, static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table, MY_BITMAP *bitmap) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS return tmp_use_all_columns(table, bitmap); #else return 0; @@ -2624,7 +2615,7 @@ static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table, static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap, my_bitmap_map *old) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS tmp_restore_column_map(bitmap, old); #endif } @@ -2639,7 +2630,7 @@ static inline void dbug_tmp_use_all_columns(TABLE *table, MY_BITMAP *read_set, MY_BITMAP *write_set) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS save[0]= read_set->bitmap; save[1]= write_set->bitmap; (void) tmp_use_all_columns(table, read_set); @@ -2652,7 +2643,7 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set, MY_BITMAP *write_set, my_bitmap_map **old) { -#ifndef DBUG_OFF +#ifdef DBUG_ASSERT_EXISTS tmp_restore_column_map(read_set, old[0]); tmp_restore_column_map(write_set, old[1]); #endif diff --git a/sql/table_cache.cc b/sql/table_cache.cc index be990543757..6067ecb059d 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -46,7 +46,7 @@ TABLE_SHARE::tdc.flushed is true */ -#include "my_global.h" +#include "mariadb.h" #include "lf.h" #include "table.h" #include "sql_base.h" diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 5e5a05084b3..2c3cd0fe24e 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -19,6 +19,7 @@ All methods pertaining to temporary tables. */ +#include "mariadb.h" #include "sql_acl.h" /* TMP_TABLE_ACLS */ #include "sql_base.h" /* tdc_create_key */ #include "lock.h" /* mysql_lock_remove */ @@ -1118,6 +1119,7 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, table->grant.privilege= TMP_TABLE_ACLS; share->tmp_table= (table->file->has_transaction_manager() ? TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE); + share->not_usable_by_query_cache= 1; table->pos_in_table_list= 0; table->query_id= query_id; diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index cbed769a424..74763e81b15 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -17,7 +17,7 @@ /* Mallocs for used in threads */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "thr_malloc.h" diff --git a/sql/thr_malloc.h b/sql/thr_malloc.h index fc23c87c9fd..574dc7966b0 100644 --- a/sql/thr_malloc.h +++ b/sql/thr_malloc.h @@ -16,8 +16,6 @@ #ifndef THR_MALLOC_INCLUDED #define THR_MALLOC_INCLUDED -#include "my_global.h" // uint, size_t - typedef struct st_mem_root MEM_ROOT; void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size, diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index 598951da406..486a829c645 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include <violite.h> #include <sql_priv.h> #include <sql_class.h> @@ -199,7 +199,7 @@ void tp_callback(TP_connection *c) c->priority= get_priority(c); /* Read next command from client. */ - c->set_io_timeout(thd->variables.net_wait_timeout); + c->set_io_timeout(thd->get_net_wait_timeout()); c->state= TP_STATE_IDLE; if (c->start_io()) goto error; diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index e90f87fffc4..3fdaff0504f 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <my_global.h> +#include "mariadb.h" #include <violite.h> #include <sql_priv.h> #include <sql_class.h> diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc index 855b9b38d78..adaca08982f 100644 --- a/sql/threadpool_win.cc +++ b/sql/threadpool_win.cc @@ -19,7 +19,7 @@ #define _WIN32_WINNT 0x0601 -#include <my_global.h> +#include "mariadb.h" #include <violite.h> #include <sql_priv.h> #include <sql_class.h> diff --git a/sql/transaction.cc b/sql/transaction.cc index 78cd3047f82..cbd875e3114 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -18,7 +18,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "transaction.h" #include "rpl_handler.h" diff --git a/sql/transaction.h b/sql/transaction.h index b6b22053150..7e34693a2eb 100644 --- a/sql/transaction.h +++ b/sql/transaction.h @@ -20,7 +20,6 @@ #pragma interface /* gcc class implementation */ #endif -#include <my_global.h> #include <m_string.h> class THD; diff --git a/sql/tztime.cc b/sql/tztime.cc index a9db91668bb..4581461f8b3 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -29,22 +29,21 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #if !defined(TZINFO2SQL) && !defined(TESTTIME) #include "sql_priv.h" #include "unireg.h" -#include "tztime.h" #include "sql_time.h" // localtime_to_TIME #include "sql_base.h" // open_system_tables_for_read, // close_system_tables #else #include <my_time.h> -#include "tztime.h" #include <my_sys.h> #include <mysql_version.h> #include <my_getopt.h> #endif +#include "tztime.h" #include "tzfile.h" #include <m_string.h> #include <my_dir.h> diff --git a/sql/udf_example.c b/sql/udf_example.c index 98700953b2c..cc9a703373c 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -125,7 +125,7 @@ typedef unsigned long long ulonglong; typedef long long longlong; #endif /*__WIN__*/ #else -#include <my_global.h> +#include "mariadb.h" #include <my_sys.h> #if defined(MYSQL_SERVER) #include <m_string.h> /* To get strmov() */ diff --git a/sql/uniques.cc b/sql/uniques.cc index 7def2d79ad7..894e959cace 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -31,7 +31,7 @@ deletes in disk order. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_sort.h" @@ -367,7 +367,7 @@ double Unique::get_use_cost(uint *buffer, size_t nkeys, uint key_size, Unique::~Unique() { close_cached_file(&file); - delete_tree(&tree); + delete_tree(&tree, 0); delete_dynamic(&file_ptrs); } @@ -387,7 +387,7 @@ bool Unique::flush() (void*) this, left_root_right) || insert_dynamic(&file_ptrs, (uchar*) &file_ptr)) return 1; - delete_tree(&tree); + delete_tree(&tree, 0); return 0; } diff --git a/sql/unireg.cc b/sql/unireg.cc index 5d5b82ba015..49724a3f47e 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -25,7 +25,7 @@ str is a (long) to record position where 0 is the first position. */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "unireg.h" #include "sql_partition.h" // struct partition_info @@ -478,7 +478,7 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo, *pos++=(uchar) NAMES_SEP_CHAR; for (key=keyinfo ; key != end ; key++) { - uchar *tmp=(uchar*) strmov((char*) pos,key->name); + uchar *tmp=(uchar*) strmov((char*) pos,key->name.str); *tmp++= (uchar) NAMES_SEP_CHAR; *tmp=0; pos=tmp; @@ -539,7 +539,7 @@ static bool pack_expression(String *buf, Virtual_column_info *vcol, size_t len_off= buf->length(); buf->q_append2b(0); // to be added later buf->q_append((char)vcol->name.length); - buf->q_append(vcol->name.str, vcol->name.length); + buf->q_append(&vcol->name); size_t expr_start= buf->length(); vcol->print(buf); size_t expr_len= buf->length() - expr_start; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index a299ddf074f..465d1f25b5b 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -13,6 +13,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "mariadb.h" #include "wsrep_priv.h" #include "wsrep_binlog.h" // wsrep_dump_rbr_buf() #include "wsrep_xid.h" diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index ad5ef9c5c55..bddbbb95f4d 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -13,6 +13,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "mariadb.h" #include "wsrep_binlog.h" #include "wsrep_priv.h" #include "log.h" diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc index 8da791b3429..bf4ce7c9d90 100644 --- a/sql/wsrep_check_opts.cc +++ b/sql/wsrep_check_opts.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include "mysqld.h" #include "sys_vars_shared.h" #include "wsrep.h" diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 0aa7f9b0aad..c83f64e9cb4 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -13,7 +13,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include <my_global.h> +#include "mariadb.h" #include <sql_class.h> #include <mysql/service_wsrep.h> diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index d047c3580ef..e0d46159697 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include <mysqld.h> #include "sql_base.h" #include "rpl_filter.h" diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 02d0ee50e6b..63d153a7af4 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include <mysqld.h> #include <sql_class.h> #include <sql_parse.h> @@ -246,6 +247,17 @@ static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) { } } +void wsrep_log(void (*fun)(const char *, ...), const char *format, ...) +{ + va_list args; + char msg[1024]; + va_start(args, format); + vsnprintf(msg, sizeof(msg) - 1, format, args); + va_end(args); + (fun)("WSREP: %s", msg); +} + + static void wsrep_log_states (wsrep_log_level_t const level, const wsrep_uuid_t* const group_uuid, wsrep_seqno_t const group_seqno, @@ -1310,22 +1322,17 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len) SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *first_table= select_lex->table_list.first; TABLE_LIST *views = first_table; - + LEX_USER *definer; String buff; const LEX_STRING command[3]= {{ C_STRING_WITH_LEN("CREATE ") }, { C_STRING_WITH_LEN("ALTER ") }, { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; - buff.append(command[thd->lex->create_view->mode].str, - command[thd->lex->create_view->mode].length); - - LEX_USER *definer; + buff.append(&command[thd->lex->create_view->mode]); if (lex->definer) - { definer= get_current_user(thd, lex->definer); - } else { /* @@ -1928,7 +1935,6 @@ pthread_handler_t start_wsrep_THD(void *arg) close_connection(thd, ER_OUT_OF_RESOURCES); statistic_increment(aborted_connects,&LOCK_status); MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); - goto error; } @@ -1951,7 +1957,6 @@ pthread_handler_t start_wsrep_THD(void *arg) close_connection(thd, ER_OUT_OF_RESOURCES); statistic_increment(aborted_connects,&LOCK_status); MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); - delete thd; goto error; } @@ -1995,13 +2000,8 @@ pthread_handler_t start_wsrep_THD(void *arg) // at server shutdown } - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) - { - mysql_mutex_lock(&LOCK_thread_count); - thd->unlink(); - mysql_mutex_unlock(&LOCK_thread_count); - delete thd; - } + unlink_not_visible_thd(thd); + delete thd; my_thread_end(); return(NULL); @@ -2022,7 +2022,7 @@ static bool abort_replicated(THD *thd) bool ret_code= false; if (thd->wsrep_query_state== QUERY_COMMITTING) { - WSREP_DEBUG("aborting replicated trx: %lu", thd->real_id); + WSREP_DEBUG("aborting replicated trx: %lu", (ulong) thd->real_id); (void)wsrep_abort_thd(thd, thd, TRUE); ret_code= true; @@ -2726,6 +2726,7 @@ void wsrep_unlock_rollback() my_bool wsrep_aborting_thd_contains(THD *thd) { + mysql_mutex_assert_owner(&LOCK_wsrep_rollback); wsrep_aborting_thd_t abortees = wsrep_aborting_thd; while (abortees) { diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 0502a29527f..bed9b0dca48 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -193,13 +193,8 @@ extern wsrep_seqno_t wsrep_locked_seqno; ? wsrep_forced_binlog_format : (ulong)(my_format)) // prefix all messages with "WSREP" -#define WSREP_LOG(fun, ...) \ - do { \ - char msg[1024] = {'\0'}; \ - snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \ - fun("WSREP: %s", msg); \ - } while(0) - +void wsrep_log(void (*fun)(const char *, ...), const char *format, ...); +#define WSREP_LOG(fun, ...) wsrep_log(fun, ## __VA_ARGS__) #define WSREP_LOG_CONFLICT_THD(thd, role) \ WSREP_LOG(sql_print_information, \ "%s: \n " \ diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc index 92c685ba485..92bcc8eda43 100644 --- a/sql/wsrep_notify.cc +++ b/sql/wsrep_notify.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include <mysqld.h> #include "wsrep_priv.h" #include "wsrep_utils.h" diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 8626cb07196..9c00f9fdaf6 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -13,11 +13,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "mariadb.h" #include "wsrep_sst.h" - #include <mysqld.h> #include <m_ctype.h> -#include <my_sys.h> #include <strfunc.h> #include <sql_class.h> #include <set_var.h> diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 5f29d28b19f..04ecf0fcb59 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -13,8 +13,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "mariadb.h" #include "wsrep_thd.h" - #include "transaction.h" #include "rpl_rli.h" #include "log_event.h" diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index 1a358877a35..3c341e222b3 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -20,6 +20,7 @@ #define _GNU_SOURCE // POSIX_SPAWN_USEVFORK flag #endif +#include "mariadb.h" #include "wsrep_utils.h" #include "wsrep_mysqld.h" diff --git a/sql/wsrep_xid.cc b/sql/wsrep_xid.cc index 2ff6ea0b32e..5af39bfc230 100644 --- a/sql/wsrep_xid.cc +++ b/sql/wsrep_xid.cc @@ -16,6 +16,7 @@ //! @file some utility functions and classes not directly related to replication +#include "mariadb.h" #include "wsrep_xid.h" #include "sql_class.h" #include "wsrep_mysqld.h" // for logging macros |