diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 4 | ||||
-rw-r--r-- | sql/item.cc | 18 | ||||
-rw-r--r-- | sql/item_func.cc | 2 | ||||
-rw-r--r-- | sql/item_func.h | 4 | ||||
-rw-r--r-- | sql/log.cc | 6 | ||||
-rw-r--r-- | sql/log_event.cc | 386 | ||||
-rw-r--r-- | sql/log_event.h | 24 | ||||
-rw-r--r-- | sql/log_event_old.cc | 17 | ||||
-rw-r--r-- | sql/partition_info.cc | 2 | ||||
-rw-r--r-- | sql/rpl_tblmap.cc | 20 | ||||
-rw-r--r-- | sql/rpl_tblmap.h | 10 | ||||
-rw-r--r-- | sql/sql_binlog.cc | 91 | ||||
-rw-r--r-- | sql/sql_class.cc | 23 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 3 | ||||
-rw-r--r-- | sql/sql_lex.h | 4 | ||||
-rw-r--r-- | sql/sql_repl.cc | 6 | ||||
-rw-r--r-- | sql/sql_select.cc | 21 | ||||
-rw-r--r-- | sql/sql_table.cc | 150 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 19 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 19 | ||||
-rw-r--r-- | sql/sys_vars.cc | 13 | ||||
-rw-r--r-- | sql/table.cc | 2 | ||||
-rw-r--r-- | sql/table.h | 12 | ||||
-rw-r--r-- | sql/wsrep_mysqld.cc | 1 | ||||
-rw-r--r-- | sql/wsrep_mysqld.h | 1 | ||||
-rw-r--r-- | sql/wsrep_mysqld_c.h | 30 |
27 files changed, 680 insertions, 210 deletions
diff --git a/sql/field.cc b/sql/field.cc index bb4a0f06fc4..6fe6af2d303 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8975,7 +8975,7 @@ int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs) (uint32) geom_type != wkb_type) { const char *db= table->s->db.str; - const char *tab_name= table->s->error_table_name(); + const char *tab_name= table->s->table_name.str; if (!db) db= ""; @@ -11022,7 +11022,7 @@ void Field::set_warning_truncated_wrong_value(const char *type_arg, { THD *thd= get_thd(); const char *db_name= table->s->db.str; - const char *table_name= table->s->error_table_name(); + const char *table_name= table->s->table_name.str; if (!db_name) db_name= ""; diff --git a/sql/item.cc b/sql/item.cc index a6b4402b6ba..47e10ba4004 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1952,7 +1952,12 @@ bool Item_name_const::is_null() Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val): Item_fixed_hybrid(thd), value_item(val), name_item(name_arg) { + StringBuffer<128> name_buffer; + String *name_str; Item::maybe_null= TRUE; + if (name_item->basic_const_item() && + (name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name + set_name(thd, name_str->ptr(), name_str->length(), name_str->charset()); } @@ -1988,25 +1993,14 @@ Item::Type Item_name_const::type() const bool Item_name_const::fix_fields(THD *thd, Item **ref) { - char buf[128]; - String *item_name; - String s(buf, sizeof(buf), &my_charset_bin); - s.length(0); - if (value_item->fix_fields_if_needed(thd, &value_item) || name_item->fix_fields_if_needed(thd, &name_item) || !value_item->const_item() || - !name_item->const_item() || - !(item_name= name_item->val_str(&s))) // Can't have a NULL name + !name_item->const_item()) { my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST"); return TRUE; } - if (is_autogenerated_name) - { - set_name(thd, item_name->c_ptr(), (uint) item_name->length(), - system_charset_info); - } if (value_item->collation.derivation == DERIVATION_NUMERIC) collation.set_numeric(); else diff --git a/sql/item_func.cc b/sql/item_func.cc index ef0dc0ba34b..e6b57750ec7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4477,7 +4477,7 @@ bool Item_func_set_user_var::register_field_in_bitmap(void *arg) true failure */ -static bool +bool update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, Item_result type, CHARSET_INFO *cs, bool unsigned_arg) diff --git a/sql/item_func.h b/sql/item_func.h index 6408cf4dd55..e4dc1d80bf9 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -3436,4 +3436,8 @@ bool eval_const_cond(COND *cond); extern bool volatile mqh_used; +bool update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, + Item_result type, CHARSET_INFO *cs, + bool unsigned_arg); + #endif /* ITEM_FUNC_INCLUDED */ diff --git a/sql/log.cc b/sql/log.cc index a4a2b4b1e37..a89be15a0d7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2017, MariaDB Corporation. +/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. + Copyright (c) 2009, 2019, 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 @@ -3994,7 +3994,7 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, // if the log entry matches, null string matching anything if (!log_name || (log_name_len == fname_len && - !memcmp(full_fname, full_log_name, log_name_len))) + !strncmp(full_fname, full_log_name, log_name_len))) { DBUG_PRINT("info", ("Found log file entry")); linfo->index_file_start_offset= offset; diff --git a/sql/log_event.cc b/sql/log_event.cc index bbadda3167e..70f0e6c2623 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3685,9 +3685,23 @@ void free_table_map_log_event(Table_map_log_event *event) delete event; } +/** + Encode the event, optionally per 'do_print_encoded' arg store the + result into the argument cache; optionally per event_info's + 'verbose' print into the cache a verbose representation of the event. + Note, no extra wrapping is done to the being io-cached data, like + to producing a BINLOG query. It's left for a routine that extracts from + the cache. + + @param file pointer to IO_CACHE + @param print_event_info pointer to print_event_info specializing + what out of and how to print the event + @param do_print_encoded whether to store base64-encoded event + into @file. +*/ bool Log_event::print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, - bool more) + bool do_print_encoded) { uchar *ptr= (uchar *)temp_buf; uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET); @@ -3738,12 +3752,9 @@ bool Log_event::print_base64(IO_CACHE* file, delete ev; } - if (print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && - print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS && - ! print_event_info->short_form) + if (do_print_encoded) { size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size); - bool error= 0; char *tmp_str; if (!(tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME)))) goto err; @@ -3753,17 +3764,8 @@ bool Log_event::print_base64(IO_CACHE* file, DBUG_ASSERT(0); } - if (my_b_tell(file) == 0) - if (unlikely(my_b_write_string(file, "\nBINLOG '\n"))) - error= 1; - if (likely(!error) && unlikely(my_b_printf(file, "%s\n", tmp_str))) - error= 1; - if (!more && likely(!error)) - if (unlikely(my_b_printf(file, "'%s\n", print_event_info->delimiter))) - error= 1; + my_b_printf(file, "%s\n", tmp_str); my_free(tmp_str); - if (unlikely(error)) - goto err; } #ifdef WHEN_FLASHBACK_REVIEW_READY @@ -3877,9 +3879,22 @@ bool Log_event::print_base64(IO_CACHE* file, } #else if (print_event_info->verbose) + { + /* + Verbose event printout can't start before encoded data + got enquoted. This is done at this point though multi-row + statement remain vulnerable. + TODO: fix MDEV-10362 to remove this workaround. + */ + if (print_event_info->base64_output_mode != + BASE64_OUTPUT_DECODE_ROWS) + my_b_printf(file, "'%s\n", print_event_info->delimiter); error= ev->print_verbose(file, print_event_info); + } else + { ev->count_row_events(print_event_info); + } #endif delete ev; if (unlikely(error)) @@ -5585,6 +5600,22 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, else thd->variables.collation_database= thd->db_charset; + { + const CHARSET_INFO *cs= thd->charset(); + /* + We cannot ask for parsing a statement using a character set + without state_maps (parser internal data). + */ + if (!cs->state_map) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "character_set cannot be parsed"); + thd->is_slave_error= true; + goto end; + } + } + /* Record any GTID in the same transaction, so slave state is transactionally consistent. @@ -6023,11 +6054,18 @@ bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && !print_event_info->short_form) { - if (print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS) - if (my_b_printf(&cache, "BINLOG '\n")) - goto err; - if (print_base64(&cache, print_event_info, FALSE)) + /* BINLOG is matched with the delimiter below on the same level */ + bool do_print_encoded= + print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS; + if (do_print_encoded) + my_b_printf(&cache, "BINLOG '\n"); + + if (print_base64(&cache, print_event_info, do_print_encoded)) goto err; + + if (do_print_encoded) + my_b_printf(&cache, "'%s\n", print_event_info->delimiter); + print_event_info->printed_fd_event= TRUE; } DBUG_RETURN(cache.flush_data()); @@ -9189,12 +9227,6 @@ User_var_log_event(const char* buf, uint event_len, val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + UV_CHARSET_NUMBER_SIZE); - if (val + val_len > buf_end) - { - error= true; - goto err; - } - /** We need to check if this is from an old server that did not pack information for flags. @@ -10969,7 +11001,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, DBUG_VOID_RETURN; } size_t const data_size= event_len - read_size; - DBUG_PRINT("info",("m_table_id: %lu m_flags: %d m_width: %lu data_size: %lu", + DBUG_PRINT("info",("m_table_id: %llu m_flags: %d m_width: %lu data_size: %lu", m_table_id, m_flags, m_width, (ulong) data_size)); m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME)); @@ -11182,12 +11214,12 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)"); int error= 0; /* - If m_table_id == ~0UL, then we have a dummy event that does not + If m_table_id == ~0ULL, then we have a dummy event that does not contain any data. In that case, we just remove all tables in the tables_to_lock list, close the thread tables, and return with success. */ - if (m_table_id == ~0UL) + if (m_table_id == ~0ULL) { /* This one is supposed to be set: just an extra check so that @@ -11453,7 +11485,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) table= m_table= rgi->m_table_map.get_table(m_table_id); - DBUG_PRINT("debug", ("m_table:%p, m_table_id: %lu%s", + DBUG_PRINT("debug", ("m_table:%p, m_table_id: %llu%s", m_table, m_table_id, table && master_had_triggers ? " (master had triggers)" : "")); @@ -11819,14 +11851,14 @@ Rows_log_event::do_update_pos(rpl_group_info *rgi) bool Rows_log_event::write_data_header() { uchar buf[ROWS_HEADER_LEN_V2]; // No need to init the buffer - DBUG_ASSERT(m_table_id != ~0UL); + DBUG_ASSERT(m_table_id != ~0ULL); DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", { int4store(buf + 0, m_table_id); int2store(buf + 4, m_flags); return (write_data(buf, 6)); }); - int6store(buf + RW_MAPID_OFFSET, (ulonglong)m_table_id); + int6store(buf + RW_MAPID_OFFSET, m_table_id); int2store(buf + RW_FLAGS_OFFSET, m_flags); return write_data(buf, ROWS_HEADER_LEN); } @@ -11894,12 +11926,226 @@ void Rows_log_event::pack_info(Protocol *protocol) char const *const flagstr= get_flags(STMT_END_F) ? " flags: STMT_END_F" : ""; size_t bytes= my_snprintf(buf, sizeof(buf), - "table_id: %lu%s", m_table_id, flagstr); + "table_id: %llu%s", m_table_id, flagstr); protocol->store(buf, bytes, &my_charset_bin); } #endif #ifdef MYSQL_CLIENT + +const char str_binlog[]= "\nBINLOG '\n"; +const char fmt_delim[]= "'%s\n"; +const char fmt_n_delim[]= "\n'%s"; +const char fmt_frag[]= "\nSET @binlog_fragment_%d ='\n"; +const char fmt_binlog2[]= "BINLOG @binlog_fragment_0, @binlog_fragment_1%s\n"; + +/** + Print an event "body" cache to @c file possibly in two fragments. + Each fragement is optionally per @c do_wrap to produce an SQL statement. + + @param file a file to print to + @param body the "body" IO_CACHE of event + @param do_wrap whether to wrap base64-encoded strings with + SQL cover. + @param delimiter delimiter string + + @param is_verbose MDEV-10362 workraround parameter to pass + info on presence of verbose printout in cache encoded data + + The function signals on any error through setting @c body->error to -1. +*/ +bool copy_cache_to_file_wrapped(IO_CACHE *body, + FILE *file, + bool do_wrap, + const char *delimiter, + bool is_verbose) +{ + const my_off_t cache_size= my_b_tell(body); + + if (reinit_io_cache(body, READ_CACHE, 0L, FALSE, FALSE)) + goto err; + + if (!do_wrap) + { + my_b_copy_to_file(body, file, SIZE_T_MAX); + } + else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) > + opt_binlog_rows_event_max_encoded_size) + { + /* + 2 fragments can always represent near 1GB row-based + base64-encoded event as two strings each of size less than + max(max_allowed_packet). Greater number of fragments does not + save from potential need to tweak (increase) @@max_allowed_packet + before to process the fragments. So 2 is safe and enough. + + Split the big query when its packet size's estimation exceeds a + limit. The estimate includes the maximum packet header + contribution of non-compressed packet. + */ + my_fprintf(file, fmt_frag, 0); + if (my_b_copy_to_file(body, file, (size_t) cache_size/2 + 1)) + goto err; + my_fprintf(file, fmt_n_delim, delimiter); + + my_fprintf(file, fmt_frag, 1); + if (my_b_copy_to_file(body, file, SIZE_T_MAX)) + goto err; + if (!is_verbose) + my_fprintf(file, fmt_delim, delimiter); + + my_fprintf(file, fmt_binlog2, delimiter); + } + else + { + my_fprintf(file, str_binlog); + if (my_b_copy_to_file(body, file, SIZE_T_MAX)) + goto err; + if (!is_verbose) + my_fprintf(file, fmt_delim, delimiter); + } + reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE); + + return false; + +err: + body->error = -1; + return true; +} + + +/** + Print an event "body" cache to @c file possibly in two fragments. + Each fragement is optionally per @c do_wrap to produce an SQL statement. + + @param file a file to print to + @param body the "body" IO_CACHE of event + @param do_wrap whether to wrap base64-encoded strings with + SQL cover. + @param delimiter delimiter string + + The function signals on any error through setting @c body->error to -1. +*/ +bool copy_cache_to_string_wrapped(IO_CACHE *cache, + LEX_STRING *to, + bool do_wrap, + const char *delimiter, + bool is_verbose) +{ + const my_off_t cache_size= my_b_tell(cache); + // contribution to total size estimate of formating + const size_t fmt_size= + sizeof(str_binlog) + 2*(sizeof(fmt_frag) + 2 /* %d */) + + sizeof(fmt_delim) + sizeof(fmt_n_delim) + + sizeof(fmt_binlog2) + + 3*PRINT_EVENT_INFO::max_delimiter_size; + + if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE)) + goto err; + + if (!(to->str= (char*) my_malloc((size_t)cache->end_of_file + fmt_size, + MYF(0)))) + { + perror("Out of memory: can't allocate memory in " + "copy_cache_to_string_wrapped()."); + goto err; + } + + if (!do_wrap) + { + if (my_b_read(cache, (uchar*) to->str, + (to->length= (size_t)cache->end_of_file))) + goto err; + } + else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) > + opt_binlog_rows_event_max_encoded_size) + { + /* + 2 fragments can always represent near 1GB row-based + base64-encoded event as two strings each of size less than + max(max_allowed_packet). Greater number of fragments does not + save from potential need to tweak (increase) @@max_allowed_packet + before to process the fragments. So 2 is safe and enough. + + Split the big query when its packet size's estimation exceeds a + limit. The estimate includes the maximum packet header + contribution of non-compressed packet. + */ + char *str= to->str; + size_t add_to_len; + + str += (to->length= sprintf(str, fmt_frag, 0)); + if (my_b_read(cache, (uchar*) str, (uint32) (cache_size/2 + 1))) + goto err; + str += (add_to_len = (uint32) (cache_size/2 + 1)); + to->length += add_to_len; + str += (add_to_len= sprintf(str, fmt_n_delim, delimiter)); + to->length += add_to_len; + + str += (add_to_len= sprintf(str, fmt_frag, 1)); + to->length += add_to_len; + if (my_b_read(cache, (uchar*) str, uint32(cache->end_of_file - (cache_size/2 + 1)))) + goto err; + str += (add_to_len= uint32(cache->end_of_file - (cache_size/2 + 1))); + to->length += add_to_len; + if (!is_verbose) + { + str += (add_to_len= sprintf(str , fmt_delim, delimiter)); + to->length += add_to_len; + } + to->length += sprintf(str, fmt_binlog2, delimiter); + } + else + { + char *str= to->str; + + str += (to->length= sprintf(str, str_binlog)); + if (my_b_read(cache, (uchar*) str, (size_t)cache->end_of_file)) + goto err; + str += cache->end_of_file; + to->length += (size_t)cache->end_of_file; + if (!is_verbose) + to->length += sprintf(str , fmt_delim, delimiter); + } + + reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE); + + return false; + +err: + cache->error= -1; + return true; +} + +/** + The function invokes base64 encoder to run on the current + event string and store the result into two caches. + When the event ends the current statement the caches are is copied into + the argument file. + Copying is also concerned how to wrap the event, specifically to produce + a valid SQL syntax. + When the encoded data size is within max(MAX_ALLOWED_PACKET) + a regular BINLOG query is composed. Otherwise it is build as fragmented + + SET @binlog_fragment_0='...'; + SET @binlog_fragment_1='...'; + BINLOG @binlog_fragment_0, @binlog_fragment_1; + + where fragments are represented by a pair of indexed user + "one shot" variables. + + @note + If any changes made don't forget to duplicate them to + Old_rows_log_event as long as it's supported. + + @param file pointer to IO_CACHE + @param print_event_info pointer to print_event_info specializing + what out of and how to print the event + @param name the name of a table that the event operates on + + The function signals on any error of cache access through setting + that cache's @c error to -1. +*/ bool Rows_log_event::print_helper(FILE *file, PRINT_EVENT_INFO *print_event_info, char const *const name) @@ -11909,18 +12155,24 @@ bool Rows_log_event::print_helper(FILE *file, #ifdef WHEN_FLASHBACK_REVIEW_READY IO_CACHE *const sql= &print_event_info->review_sql_cache; #endif + bool do_print_encoded= + print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && + print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS && + !print_event_info->short_form; bool const last_stmt_event= get_flags(STMT_END_F); if (!print_event_info->short_form) { + char llbuff[22]; + print_header(head, print_event_info, !last_stmt_event); - if (my_b_printf(head, "\t%s: table id %lu%s\n", - name, m_table_id, + if (my_b_printf(head, "\t%s: table id %s%s\n", + name, ullstr(m_table_id, llbuff), last_stmt_event ? " flags: STMT_END_F" : "")) goto err; } if (!print_event_info->short_form || print_event_info->print_row_count) - if (print_base64(body, print_event_info, !last_stmt_event)) + if (print_base64(body, print_event_info, do_print_encoded)) goto err; if (last_stmt_event) @@ -11928,25 +12180,31 @@ bool Rows_log_event::print_helper(FILE *file, if (!is_flashback) { if (copy_event_cache_to_file_and_reinit(head, file) || - copy_event_cache_to_file_and_reinit(body, file)) + copy_cache_to_file_wrapped(body, file, do_print_encoded, + print_event_info->delimiter, + print_event_info->verbose)) goto err; } else { - LEX_STRING tmp_str; - if (copy_event_cache_to_string_and_reinit(head, &tmp_str)) - return 1; - output_buf.append(tmp_str.str, tmp_str.length); // Not \0 terminated - my_free(tmp_str.str); - if (copy_event_cache_to_string_and_reinit(body, &tmp_str)) - return 1; - output_buf.append(tmp_str.str, tmp_str.length); - my_free(tmp_str.str); + LEX_STRING tmp_str; + + if (copy_event_cache_to_string_and_reinit(head, &tmp_str)) + return 1; + output_buf.append(tmp_str.str, tmp_str.length); // Not \0 terminated); + my_free(tmp_str.str); + + if (copy_cache_to_string_wrapped(body, &tmp_str, do_print_encoded, + print_event_info->delimiter, + print_event_info->verbose)) + return 1; + output_buf.append(tmp_str.str, tmp_str.length); + my_free(tmp_str.str); #ifdef WHEN_FLASHBACK_REVIEW_READY - if (copy_event_cache_to_string_and_reinit(sql, &tmp_str)) - return 1; - output_buf.append(tmp_str.str, tmp_str.length); - my_free(tmp_str.str); + if (copy_event_cache_to_string_and_reinit(sql, &tmp_str)) + return 1; + output_buf.append(tmp_str.str, tmp_str.length); + my_free(tmp_str.str); #endif } } @@ -12217,7 +12475,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, uchar cbuf[MAX_INT_WIDTH]; uchar *cbuf_end; DBUG_ENTER("Table_map_log_event::Table_map_log_event(TABLE)"); - DBUG_ASSERT(m_table_id != ~0UL); + DBUG_ASSERT(m_table_id != ~0ULL); /* In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in table.cc / alloc_table_share(): @@ -12302,7 +12560,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, #endif m_dbnam(NULL), m_dblen(0), m_tblnam(NULL), m_tbllen(0), m_colcnt(0), m_coltype(0), - m_memory(NULL), m_table_id(ULONG_MAX), m_flags(0), + m_memory(NULL), m_table_id(ULONGLONG_MAX), m_flags(0), m_data_size(0), m_field_metadata(0), m_field_metadata_size(0), m_null_bits(0), m_meta_memory(NULL) { @@ -12339,7 +12597,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, post_start+= TM_FLAGS_OFFSET; } - DBUG_ASSERT(m_table_id != ~0UL); + DBUG_ASSERT(m_table_id != ~0ULL); m_flags= uint2korr(post_start); @@ -12659,7 +12917,7 @@ int Table_map_log_event::do_apply_event(rpl_group_info *rgi) table_list->updating= 1; table_list->required_type= TABLE_TYPE_NORMAL; - DBUG_PRINT("debug", ("table: %s is mapped to %lu", + DBUG_PRINT("debug", ("table: %s is mapped to %llu", table_list->table_name.str, table_list->table_id)); table_list->master_had_triggers= ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? 1 : 0); @@ -12761,7 +13019,7 @@ int Table_map_log_event::do_update_pos(rpl_group_info *rgi) #ifndef MYSQL_CLIENT bool Table_map_log_event::write_data_header() { - DBUG_ASSERT(m_table_id != ~0UL); + DBUG_ASSERT(m_table_id != ~0ULL); uchar buf[TABLE_MAP_HEADER_LEN]; DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", { @@ -12769,7 +13027,7 @@ bool Table_map_log_event::write_data_header() int2store(buf + 4, m_flags); return (write_data(buf, 6)); }); - int6store(buf + TM_MAPID_OFFSET, (ulonglong)m_table_id); + int6store(buf + TM_MAPID_OFFSET, m_table_id); int2store(buf + TM_FLAGS_OFFSET, m_flags); return write_data(buf, TABLE_MAP_HEADER_LEN); } @@ -12819,7 +13077,7 @@ void Table_map_log_event::pack_info(Protocol *protocol) { char buf[256]; size_t bytes= my_snprintf(buf, sizeof(buf), - "table_id: %lu (%s.%s)", + "table_id: %llu (%s.%s)", m_table_id, m_dbnam, m_tblnam); protocol->store(buf, bytes, &my_charset_bin); } @@ -12834,17 +13092,25 @@ bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info) { if (!print_event_info->short_form) { + char llbuff[22]; + print_header(&print_event_info->head_cache, print_event_info, TRUE); if (my_b_printf(&print_event_info->head_cache, - "\tTable_map: %`s.%`s mapped to number %lu%s\n", - m_dbnam, m_tblnam, m_table_id, + "\tTable_map: %`s.%`s mapped to number %s%s\n", + m_dbnam, m_tblnam, ullstr(m_table_id, llbuff), ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? " (has triggers)" : ""))) goto err; } if (!print_event_info->short_form || print_event_info->print_row_count) { - if (print_base64(&print_event_info->body_cache, print_event_info, TRUE) || + bool do_print_encoded= + print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && + print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS && + !print_event_info->short_form; + + if (print_base64(&print_event_info->body_cache, print_event_info, + do_print_encoded) || copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, file)) goto err; @@ -14768,7 +15034,7 @@ err: bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file) { - return (my_b_copy_to_file(cache, file) || + return (my_b_copy_all_to_file(cache, file) || reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE)); } diff --git a/sql/log_event.h b/sql/log_event.h index 38a40c90799..339db756aab 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -866,6 +866,7 @@ typedef struct st_print_event_info bool allow_parallel_printed; bool found_row_event; bool print_row_count; + static const uint max_delimiter_size= 16; /* Settings on how to print the events */ bool short_form; /* @@ -1264,7 +1265,7 @@ public: bool print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, bool is_more); bool print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, - bool is_more); + bool do_print_encoded); #endif /* MYSQL_SERVER */ /* The following code used for Flashback */ @@ -4333,7 +4334,7 @@ public: int rewrite_db(const char* new_name, size_t new_name_len, const Format_description_log_event*); #endif - ulong get_table_id() const { return m_table_id; } + ulonglong get_table_id() const { return m_table_id; } const char *get_table_name() const { return m_tblnam; } const char *get_db_name() const { return m_dbnam; } @@ -4377,7 +4378,7 @@ private: uchar *m_coltype; uchar *m_memory; - ulong m_table_id; + ulonglong m_table_id; flag_set m_flags; size_t m_data_size; @@ -4506,7 +4507,7 @@ public: MY_BITMAP const *get_cols() const { return &m_cols; } MY_BITMAP const *get_cols_ai() const { return &m_cols_ai; } size_t get_width() const { return m_width; } - ulong get_table_id() const { return m_table_id; } + ulonglong get_table_id() const { return m_table_id; } #if defined(MYSQL_SERVER) /* @@ -4607,7 +4608,7 @@ protected: #ifdef MYSQL_SERVER TABLE *m_table; /* The table the rows belong to */ #endif - ulong m_table_id; /* Table ID */ + ulonglong m_table_id; /* Table ID */ MY_BITMAP m_cols; /* Bitmap denoting columns available */ ulong m_width; /* The width of the columns bitmap */ /* @@ -5171,6 +5172,19 @@ public: virtual int get_data_size() { return IGNORABLE_HEADER_LEN; } }; +#ifdef MYSQL_CLIENT +bool copy_cache_to_string_wrapped(IO_CACHE *body, + LEX_STRING *to, + bool do_wrap, + const char *delimiter, + bool is_verbose); +bool copy_cache_to_file_wrapped(IO_CACHE *body, + FILE *file, + bool do_wrap, + const char *delimiter, + bool is_verbose); +#endif + #ifdef MYSQL_SERVER /***************************************************************************** diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 66c4c2bef42..b5381ec6d74 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1842,27 +1842,34 @@ void Old_rows_log_event::pack_info(Protocol *protocol) #ifdef MYSQL_CLIENT +/* Method duplicates Rows_log_event's one */ bool Old_rows_log_event::print_helper(FILE *file, PRINT_EVENT_INFO *print_event_info, char const *const name) { IO_CACHE *const head= &print_event_info->head_cache; IO_CACHE *const body= &print_event_info->body_cache; + bool do_print_encoded= + print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS && + print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && + !print_event_info->short_form; + if (!print_event_info->short_form) { - bool const last_stmt_event= get_flags(STMT_END_F); - if (print_header(head, print_event_info, !last_stmt_event) || + if (print_header(head, print_event_info, !do_print_encoded) || my_b_printf(head, "\t%s: table id %lu%s\n", name, m_table_id, - last_stmt_event ? " flags: STMT_END_F" : "") || - print_base64(body, print_event_info, !last_stmt_event)) + do_print_encoded ? " flags: STMT_END_F" : "") || + print_base64(body, print_event_info, do_print_encoded)) goto err; } if (get_flags(STMT_END_F)) { if (copy_event_cache_to_file_and_reinit(head, file) || - copy_event_cache_to_file_and_reinit(body, file)) + copy_cache_to_file_wrapped(body, file, do_print_encoded, + print_event_info->delimiter, + print_event_info->verbose)) goto err; } return 0; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 0ac4014a669..2f021d6118c 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -878,7 +878,7 @@ void partition_info::vers_set_hist_part(THD *thd) return; warn: my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG), - table->s->db.str, table->s->error_table_name(), + table->s->db.str, table->s->table_name.str, vers_info->hist_part->partition_name); } diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index 7284e4be15c..02543a429b8 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -43,7 +43,7 @@ table_mapping::table_mapping() constructor is called at startup only. */ (void) my_hash_init(&m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE, - offsetof(entry,table_id),sizeof(ulong), + offsetof(entry,table_id),sizeof(ulonglong), 0,0,0); /* We don't preallocate any block, this is consistent with m_free=0 above */ init_alloc_root(&m_mem_root, "table_mapping", @@ -60,20 +60,20 @@ table_mapping::~table_mapping() free_root(&m_mem_root, MYF(0)); } -TABLE* table_mapping::get_table(ulong table_id) +TABLE* table_mapping::get_table(ulonglong table_id) { DBUG_ENTER("table_mapping::get_table(ulong)"); - DBUG_PRINT("enter", ("table_id: %lu", table_id)); + DBUG_PRINT("enter", ("table_id: %llu", table_id)); entry *e= find_entry(table_id); if (e) { - DBUG_PRINT("info", ("tid %lu -> table %p (%s)", + DBUG_PRINT("info", ("tid %llu -> table %p (%s)", table_id, e->table, MAYBE_TABLE_NAME(e->table))); DBUG_RETURN(e->table); } - DBUG_PRINT("info", ("tid %lu is not mapped!", table_id)); + DBUG_PRINT("info", ("tid %llu is not mapped!", table_id)); DBUG_RETURN(NULL); } @@ -103,11 +103,11 @@ int table_mapping::expand() return 0; } -int table_mapping::set_table(ulong table_id, TABLE* table) +int table_mapping::set_table(ulonglong table_id, TABLE* table) { DBUG_ENTER("table_mapping::set_table(ulong,TABLE*)"); - DBUG_PRINT("enter", ("table_id: %lu table: %p (%s)", - table_id, + DBUG_PRINT("enter", ("table_id: %llu table: %p (%s)", + table_id, table, MAYBE_TABLE_NAME(table))); entry *e= find_entry(table_id); if (e == 0) @@ -134,13 +134,13 @@ int table_mapping::set_table(ulong table_id, TABLE* table) DBUG_RETURN(ERR_MEMORY_ALLOCATION); } - DBUG_PRINT("info", ("tid %lu -> table %p (%s)", + DBUG_PRINT("info", ("tid %llu -> table %p (%s)", table_id, e->table, MAYBE_TABLE_NAME(e->table))); DBUG_RETURN(0); // All OK } -int table_mapping::remove_table(ulong table_id) +int table_mapping::remove_table(ulonglong table_id) { entry *e= find_entry(table_id); if (e) diff --git a/sql/rpl_tblmap.h b/sql/rpl_tblmap.h index 9fb1c4afbd7..05b298e6053 100644 --- a/sql/rpl_tblmap.h +++ b/sql/rpl_tblmap.h @@ -70,10 +70,10 @@ public: table_mapping(); ~table_mapping(); - TABLE* get_table(ulong table_id); + TABLE* get_table(ulonglong table_id); - int set_table(ulong table_id, TABLE* table); - int remove_table(ulong table_id); + int set_table(ulonglong table_id, TABLE* table); + int remove_table(ulonglong table_id); void clear_tables(); ulong count() const { return m_table_ids.records; } @@ -83,14 +83,14 @@ private: it, which only works for PODs) */ struct entry { - ulong table_id; + ulonglong table_id; union { TABLE *table; entry *next; }; }; - entry *find_entry(ulong table_id) + entry *find_entry(ulonglong table_id) { return (entry *) my_hash_search(&m_table_ids, (uchar*)&table_id, diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 1fa3cca7c27..97b8e2e4f91 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -110,6 +110,64 @@ static int check_event_type(int type, Relay_log_info *rli) } /** + Copy fragments into the standard placeholder thd->lex->comment.str. + + Compute the size of the (still) encoded total, + allocate and then copy fragments one after another. + The size can exceed max(max_allowed_packet) which is not a + problem as no String instance is created off this char array. + + @param thd THD handle + @return + 0 at success, + -1 otherwise. +*/ +int binlog_defragment(THD *thd) +{ + user_var_entry *entry[2]; + LEX_CSTRING name[2]= { thd->lex->comment, thd->lex->ident }; + + /* compute the total size */ + thd->lex->comment.str= NULL; + thd->lex->comment.length= 0; + for (uint k= 0; k < 2; k++) + { + entry[k]= + (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name[k].str, + name[k].length); + if (!entry[k] || entry[k]->type != STRING_RESULT) + { + my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), name[k].str); + return -1; + } + thd->lex->comment.length += entry[k]->length; + } + + thd->lex->comment.str= // to be freed by the caller + (char *) my_malloc(thd->lex->comment.length, MYF(MY_WME)); + if (!thd->lex->comment.str) + { + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); + return -1; + } + + /* fragments are merged into allocated buf while the user var:s get reset */ + size_t gathered_length= 0; + for (uint k=0; k < 2; k++) + { + memcpy(const_cast<char*>(thd->lex->comment.str) + gathered_length, entry[k]->value, + entry[k]->length); + gathered_length += entry[k]->length; + update_hash(entry[k], true, NULL, 0, STRING_RESULT, &my_charset_bin, 0); + } + + DBUG_ASSERT(gathered_length == thd->lex->comment.length); + + return 0; +} + + +/** Execute a BINLOG statement. To execute the BINLOG command properly the server needs to know @@ -134,14 +192,6 @@ void mysql_client_binlog_statement(THD* thd) if (check_global_access(thd, SUPER_ACL)) DBUG_VOID_RETURN; - size_t coded_len= thd->lex->comment.length; - if (!coded_len) - { - my_error(ER_SYNTAX_ERROR, MYF(0)); - DBUG_VOID_RETURN; - } - size_t decoded_len= my_base64_needed_decoded_length((int)coded_len); - /* option_bits will be changed when applying the event. But we don't expect it be changed permanently after BINLOG statement, so backup it first. @@ -156,6 +206,8 @@ void mysql_client_binlog_statement(THD* thd) int err; Relay_log_info *rli; rpl_group_info *rgi; + char *buf= NULL; + size_t coded_len= 0, decoded_len= 0; rli= thd->rli_fake; if (!rli && (rli= thd->rli_fake= new Relay_log_info(FALSE))) @@ -165,13 +217,13 @@ void mysql_client_binlog_statement(THD* thd) rgi->thd= thd; const char *error= 0; - char *buf= (char *) my_malloc(decoded_len, MYF(MY_WME)); Log_event *ev = 0; + my_bool is_fragmented= FALSE; /* Out of memory check */ - if (!(rli && buf)) + if (!(rli)) { my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); /* needed 1 bytes */ goto end; @@ -179,6 +231,23 @@ void mysql_client_binlog_statement(THD* thd) DBUG_ASSERT(rli->belongs_to_client()); + if (unlikely(is_fragmented= thd->lex->comment.str && thd->lex->ident.str)) + if (binlog_defragment(thd)) + goto end; + + if (!(coded_len= thd->lex->comment.length)) + { + my_error(ER_SYNTAX_ERROR, MYF(0)); + goto end; + } + + decoded_len= my_base64_needed_decoded_length((int)coded_len); + if (!(buf= (char *) my_malloc(decoded_len, MYF(MY_WME)))) + { + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); + goto end; + } + for (char const *strptr= thd->lex->comment.str ; strptr < thd->lex->comment.str + thd->lex->comment.length ; ) { @@ -317,6 +386,8 @@ void mysql_client_binlog_statement(THD* thd) my_ok(thd); end: + if (unlikely(is_fragmented)) + my_free(const_cast<char*>(thd->lex->comment.str)); thd->variables.option_bits= thd_options; rgi->slave_close_thread_tables(thd); my_free(buf); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8c5cadcf5a6..7a623ce6697 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6726,6 +6726,22 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, DBUG_ASSERT(is_current_stmt_binlog_format_row() && ((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open())); + /** + Save a reference to the original read bitmaps + We will need this to restore the bitmaps at the end as + binlog_prepare_row_images() may change table->read_set. + table->read_set is used by pack_row and deep in + binlog_prepare_pending_events(). + */ + MY_BITMAP *old_read_set= table->read_set; + + /** + This will remove spurious fields required during execution but + not needed for binlogging. This is done according to the: + binlog-row-image option. + */ + binlog_prepare_row_images(table); + size_t const before_maxlen= max_row_length(table, table->read_set, before_record); size_t const after_maxlen= max_row_length(table, table->rpl_write_set, @@ -6739,9 +6755,9 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, uchar *after_row= row_data.slot(1); size_t const before_size= pack_row(table, table->read_set, before_row, - before_record); + before_record); size_t const after_size= pack_row(table, table->rpl_write_set, after_row, - after_record); + after_record); /* Ensure that all events in a GTID group are in the same cache */ if (variables.option_bits & OPTION_GTID_BEGIN) @@ -6776,6 +6792,9 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, int error= ev->add_row_data(before_row, before_size) || ev->add_row_data(after_row, after_size); + /* restore read set for the rest of execution */ + table->column_bitmaps_set_no_signal(old_read_set, + table->write_set); return error; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 88494f8c169..361340ee235 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4465,7 +4465,7 @@ public: char buff[MYSQL_ERRMSG_SIZE]; CHARSET_INFO *cs= &my_charset_latin1; const char *db_name= s ? s->db.str : NULL; - const char *table_name= s ? s->error_table_name() : NULL; + const char *table_name= s ? s->table_name.str : NULL; if (!db_name) db_name= ""; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c4c141900f1..d3f4793fb67 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4131,7 +4131,8 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only) inner_join->select_options|= SELECT_DESCRIBE; } res= inner_join->optimize(); - sl->update_used_tables(); + if (!inner_join->cleaned) + sl->update_used_tables(); sl->update_correlated_cache(); is_correlated_unit|= sl->is_correlated; inner_join->select_options= save_options; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ee4baba1134..4af0f919c91 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3038,6 +3038,10 @@ public: String *wild; /* Wildcard in SHOW {something} LIKE 'wild'*/ sql_exchange *exchange; select_result *result; + /** + @c the two may also hold BINLOG arguments: either comment holds a + base64-char string or both represent the BINLOG fragment user variables. + */ LEX_CSTRING comment, ident; LEX_USER *grant_user; XID *xid; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 59f6a45a52f..7fc3bb5926d 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB Corporation +/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. + Copyright (c) 2008, 2019, 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 @@ -558,7 +558,7 @@ static my_bool log_in_use_callback(THD *thd, const char *log_name) my_bool result= 0; mysql_mutex_lock(&thd->LOCK_thd_data); if (auto linfo= thd->current_linfo) - result= !memcmp(log_name, linfo->log_file_name, strlen(log_name) + 1); + result= !strcmp(log_name, linfo->log_file_name); mysql_mutex_unlock(&thd->LOCK_thd_data); return result; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ef712f76031..de38cbf778d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17864,7 +17864,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, table->no_rows_with_nulls= param->force_not_null_cols; table->s= share; - init_tmp_table_share(thd, share, "", 0, tmpname, tmpname); + init_tmp_table_share(thd, share, "", 0, "(temporary)", tmpname); share->blob_field= blob_field; share->table_charset= param->table_charset; share->primary_key= MAX_KEY; // Indicate no primary key @@ -18718,8 +18718,7 @@ bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value) bool open_tmp_table(TABLE *table) { int error; - if (unlikely((error= table->file->ha_open(table, table->s->table_name.str, - O_RDWR, + if (unlikely((error= table->file->ha_open(table, table->s->path.str, O_RDWR, HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))) { @@ -18915,7 +18914,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, } } - if (unlikely((error= maria_create(share->table_name.str, + if (unlikely((error= maria_create(share->path.str, file_type, share->keys, &keydef, (uint) (*recinfo-start_recinfo), @@ -19070,12 +19069,12 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, bzero((char*) &create_info,sizeof(create_info)); create_info.data_file_length= table->in_use->variables.tmp_disk_table_size; - if (unlikely((error= mi_create(share->table_name.str, share->keys, &keydef, - (uint) (*recinfo-start_recinfo), + if (unlikely((error= mi_create(share->path.str, share->keys, &keydef, + (uint) (*recinfo-start_recinfo), start_recinfo, - share->uniques, &uniquedef, + share->uniques, &uniquedef, &create_info, - HA_CREATE_TMP_TABLE | + HA_CREATE_TMP_TABLE | HA_CREATE_INTERNAL_TABLE | ((share->db_create_options & HA_OPTION_PACK_RECORD) ? @@ -19226,7 +19225,7 @@ err_killed: (void) table->file->ha_rnd_end(); (void) new_table.file->ha_close(); err1: - new_table.file->ha_delete_table(new_table.s->table_name.str); + new_table.file->ha_delete_table(new_table.s->path.str); err2: delete new_table.file; thd_proc_info(thd, save_proc_info); @@ -19255,10 +19254,10 @@ free_tmp_table(THD *thd, TABLE *entry) 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); + entry->file->ha_drop_table(entry->s->path.str); } else - entry->file->ha_delete_table(entry->s->table_name.str); + entry->file->ha_delete_table(entry->s->path.str); delete entry->file; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4dd9d43a7b9..a3f1f616edd 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5891,7 +5891,8 @@ static bool is_candidate_key(KEY *key) KEY_PART_INFO *key_part; KEY_PART_INFO *key_part_end= key->key_part + key->user_defined_key_parts; - if (!(key->flags & HA_NOSAME) || (key->flags & HA_NULL_PART_KEY)) + if (!(key->flags & HA_NOSAME) || (key->flags & HA_NULL_PART_KEY) || + (key->flags & HA_KEY_HAS_PART_KEY_SEG)) return false; for (key_part= key->key_part; key_part < key_part_end; key_part++) @@ -6459,9 +6460,7 @@ static int compare_uint(const uint *s, const uint *t) @retval false success */ -static bool fill_alter_inplace_info(THD *thd, - TABLE *table, - bool varchar, +static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar, Alter_inplace_info *ha_alter_info) { Field **f_ptr, *field, *old_field; @@ -6469,7 +6468,6 @@ static bool fill_alter_inplace_info(THD *thd, Create_field *new_field; KEY_PART_INFO *key_part, *new_part; KEY_PART_INFO *end; - uint candidate_key_count= 0; Alter_info *alter_info= ha_alter_info->alter_info; DBUG_ENTER("fill_alter_inplace_info"); DBUG_PRINT("info", ("alter_info->flags: %llu", alter_info->flags)); @@ -6773,8 +6771,13 @@ static bool fill_alter_inplace_info(THD *thd, Primary key index for the new table */ const KEY* const new_pk= (ha_alter_info->key_count > 0 && - is_candidate_key(ha_alter_info->key_info_buffer)) ? + (!my_strcasecmp(system_charset_info, + ha_alter_info->key_info_buffer->name.str, + primary_key_name) || + is_candidate_key(ha_alter_info->key_info_buffer))) ? ha_alter_info->key_info_buffer : NULL; + const KEY *const old_pk= table->s->primary_key == MAX_KEY ? NULL : + table->key_info + table->s->primary_key; DBUG_PRINT("info", ("index count old: %d new: %d", table->s->keys, ha_alter_info->key_count)); @@ -6874,8 +6877,7 @@ static bool fill_alter_inplace_info(THD *thd, (i) Old table doesn't have primary key, new table has it and vice-versa (ii) Primary key changed to another existing index */ - if ((new_key == new_pk) != - ((uint) (table_key - table->key_info) == table->s->primary_key)) + if ((new_key == new_pk) != (table_key == old_pk)) goto index_changed; /* Check that key comment is not changed. */ @@ -6937,22 +6939,6 @@ static bool fill_alter_inplace_info(THD *thd, /* Now let us calculate flags for storage engine API. */ - /* Count all existing candidate keys. */ - for (table_key= table->key_info; table_key < table_key_end; table_key++) - { - /* - Check if key is a candidate key, This key is either already primary key - or could be promoted to primary key if the original primary key is - dropped. - In MySQL one is allowed to create primary key with partial fields (i.e. - primary key which is not considered candidate). For simplicity we count - such key as a candidate key here. - */ - if (((uint) (table_key - table->key_info) == table->s->primary_key) || - is_candidate_key(table_key)) - candidate_key_count++; - } - /* Figure out what kind of indexes we are dropping. */ KEY **dropped_key; KEY **dropped_key_end= ha_alter_info->index_drop_buffer + @@ -6965,21 +6951,10 @@ static bool fill_alter_inplace_info(THD *thd, if (table_key->flags & HA_NOSAME) { - /* - Unique key. Check for PRIMARY KEY. Also see comment about primary - and candidate keys above. - */ - if ((uint) (table_key - table->key_info) == table->s->primary_key) - { + if (table_key == old_pk) ha_alter_info->handler_flags|= ALTER_DROP_PK_INDEX; - candidate_key_count--; - } else - { ha_alter_info->handler_flags|= ALTER_DROP_UNIQUE_INDEX; - if (is_candidate_key(table_key)) - candidate_key_count--; - } } else ha_alter_info->handler_flags|= ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX; @@ -6992,24 +6967,10 @@ 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.str, primary_key_name); - - if ((!(new_key->flags & HA_KEY_HAS_PART_KEY_SEG) && - !(new_key->flags & HA_NULL_PART_KEY)) || - is_pk) - { - /* Candidate key or primary key! */ - if (candidate_key_count == 0 || is_pk) - ha_alter_info->handler_flags|= ALTER_ADD_PK_INDEX; - else - ha_alter_info->handler_flags|= ALTER_ADD_UNIQUE_INDEX; - candidate_key_count++; - } + if (new_key == new_pk) + ha_alter_info->handler_flags|= ALTER_ADD_PK_INDEX; else - { ha_alter_info->handler_flags|= ALTER_ADD_UNIQUE_INDEX; - } } else ha_alter_info->handler_flags|= ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX; @@ -8432,7 +8393,12 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } if (!drop) { - check->expr->walk(&Item::rename_fields_processor, 1, &column_rename_param); + if (alter_info->flags & ALTER_RENAME_COLUMN) + { + check->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + table->m_needs_reopen= 1; // because new column name is on thd->mem_root + } new_constraint_list.push_back(check, thd->mem_root); } } @@ -9315,6 +9281,64 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, THD_STAGE_INFO(thd, stage_setup); + if (alter_info->flags & ALTER_DROP_CHECK_CONSTRAINT) + { + /* + ALTER TABLE DROP CONSTRAINT + should be replaced with ... DROP [FOREIGN] KEY + if the constraint is the FOREIGN KEY or UNIQUE one. + */ + + List_iterator<Alter_drop> drop_it(alter_info->drop_list); + Alter_drop *drop; + List <FOREIGN_KEY_INFO> fk_child_key_list; + table->file->get_foreign_key_list(thd, &fk_child_key_list); + + alter_info->flags&= ~ALTER_DROP_CHECK_CONSTRAINT; + + while ((drop= drop_it++)) + { + if (drop->type == Alter_drop::CHECK_CONSTRAINT) + { + { + /* Test if there is a FOREIGN KEY with this name. */ + FOREIGN_KEY_INFO *f_key; + List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list); + + while ((f_key= fk_key_it++)) + { + if (my_strcasecmp(system_charset_info, f_key->foreign_id->str, + drop->name) == 0) + { + drop->type= Alter_drop::FOREIGN_KEY; + alter_info->flags|= ALTER_DROP_FOREIGN_KEY; + goto do_continue; + } + } + } + + { + /* Test if there is an UNIQUE with this name. */ + uint n_key; + + for (n_key=0; n_key < table->s->keys; n_key++) + { + if ((table->key_info[n_key].flags & HA_NOSAME) && + my_strcasecmp(system_charset_info, + drop->name, table->key_info[n_key].name.str) == 0) // Merge todo: review '.str' + { + drop->type= Alter_drop::KEY; + alter_info->flags|= ALTER_DROP_INDEX; + goto do_continue; + } + } + } + } + alter_info->flags|= ALTER_DROP_CHECK_CONSTRAINT; +do_continue:; + } + } + handle_if_exists_options(thd, table, alter_info); /* @@ -9639,7 +9663,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), alter_ctx.new_db.str, - alter_ctx.tmp_name.str, + alter_ctx.new_name.str, false, true))) goto err_new_table_cleanup; @@ -9755,7 +9779,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, goto err_new_table_cleanup; if (ha_create_table(thd, alter_ctx.get_tmp_path(), - alter_ctx.new_db.str, alter_ctx.tmp_name.str, + alter_ctx.new_db.str, alter_ctx.new_name.str, create_info, &frm)) goto err_new_table_cleanup; @@ -9763,11 +9787,11 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, no_ha_table= false; /* Open the table since we need to copy the data. */ - new_table= thd->create_and_open_tmp_table(new_db_type, &frm, - alter_ctx.get_tmp_path(), - alter_ctx.new_db.str, - alter_ctx.tmp_name.str, - true, true); + new_table= + thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), + alter_ctx.new_db.str, + alter_ctx.new_name.str, + true, true); if (!new_table) goto err_new_table_cleanup; @@ -9827,7 +9851,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, goto err_new_table_cleanup; } } - new_table->s->orig_table_name= table->s->table_name.str; /* Note: In case of MERGE table, we do not attach children. We do not @@ -10687,7 +10710,10 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, { /* calculating table's checksum */ ha_checksum crc= 0; - uchar null_mask=256 - (1 << t->s->last_null_bit_pos); + DBUG_ASSERT(t->s->last_null_bit_pos < 8); + uchar null_mask= (t->s->last_null_bit_pos ? + (256 - (1 << t->s->last_null_bit_pos)): + 0); t->use_all_stored_columns(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 00566c463e8..bdc1893637d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2073,6 +2073,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_lock_wait_timeout opt_delete_gtid_domain asrow_attribute + opt_constraint_no_id END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -6659,6 +6660,11 @@ check_constraint: } ; +opt_constraint_no_id: + /* Empty */ {} + | CONSTRAINT {} + ; + opt_constraint: /* empty */ { $$= null_clex_str; } | constraint { $$= $1; } @@ -8374,7 +8380,7 @@ alter_list_item: lex->alter_info.drop_list.push_back(ad, thd->mem_root); lex->alter_info.flags|= ALTER_DROP_FOREIGN_KEY; } - | DROP PRIMARY_SYM KEY_SYM + | DROP opt_constraint_no_id PRIMARY_SYM KEY_SYM { LEX *lex=Lex; Alter_drop *ad= (new (thd->mem_root) @@ -8886,8 +8892,17 @@ binlog_base64_event: { Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; Lex->comment= $2; + Lex->ident.str= NULL; + Lex->ident.length= 0; } - ; + | + BINLOG_SYM '@' ident_or_text ',' '@' ident_or_text + { + Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; + Lex->comment= $3; + Lex->ident= $6; + } + ; check_view_or_table: table_or_tables table_list opt_mi_check_type diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 025241f8e93..6a6c901c197 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -1580,6 +1580,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); set_assign sf_tail_standalone sp_tail_standalone + opt_constraint_no_id END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -6597,6 +6598,11 @@ check_constraint: } ; +opt_constraint_no_id: + /* Empty */ {} + | CONSTRAINT {} + ; + opt_constraint: /* empty */ { $$= null_clex_str; } | constraint { $$= $1; } @@ -8401,7 +8407,7 @@ alter_list_item: lex->alter_info.drop_list.push_back(ad, thd->mem_root); lex->alter_info.flags|= ALTER_DROP_FOREIGN_KEY; } - | DROP PRIMARY_SYM KEY_SYM + | DROP opt_constraint_no_id PRIMARY_SYM KEY_SYM { LEX *lex=Lex; Alter_drop *ad= (new (thd->mem_root) @@ -8913,8 +8919,17 @@ binlog_base64_event: { Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; Lex->comment= $2; + Lex->ident.str= NULL; + Lex->ident.length= 0; } - ; + | + BINLOG_SYM '@' ident_or_text ',' '@' ident_or_text + { + Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; + Lex->comment= $3; + Lex->ident= $6; + } + ; check_view_or_table: table_or_tables table_list opt_mi_check_type diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 766e655b20a..64a8b0c17b5 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -5484,6 +5484,19 @@ static Sys_var_mybool Sys_wsrep_certify_nonPK( GLOBAL_VAR(wsrep_certify_nonPK), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); +static const char *wsrep_certification_rules_names[]= { "strict", "optimized", NullS }; +static Sys_var_enum Sys_wsrep_certification_rules( + "wsrep_certification_rules", + "Certification rules to use in the cluster. Possible values are: " + "\"strict\": stricter rules that could result in more certification " + "failures. " + "\"optimized\": relaxed rules that allow more concurrency and " + "cause less certification failures.", + GLOBAL_VAR(wsrep_certification_rules), CMD_LINE(REQUIRED_ARG), + wsrep_certification_rules_names, DEFAULT(WSREP_CERTIFICATION_RULES_STRICT), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(0)); + static Sys_var_mybool Sys_wsrep_causal_reads( "wsrep_causal_reads", "Setting this variable is equivalent " "to setting wsrep_sync_wait READ flag", diff --git a/sql/table.cc b/sql/table.cc index 7682119c241..75f5a464186 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5450,7 +5450,7 @@ int TABLE::verify_constraints(bool ignore_failure) field_error.append((*chk)->name.str); my_error(ER_CONSTRAINT_FAILED, MYF(ignore_failure ? ME_WARNING : 0), field_error.c_ptr(), - s->db.str, s->error_table_name()); + s->db.str, s->table_name.str); return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; } } diff --git a/sql/table.h b/sql/table.h index 914f4dc15c2..82fefe60e0b 100644 --- a/sql/table.h +++ b/sql/table.h @@ -646,16 +646,6 @@ struct TABLE_SHARE LEX_CSTRING normalized_path; /* unpack_filename(path) */ LEX_CSTRING connect_string; - const char* orig_table_name; /* Original table name for this tmp table */ - const char* error_table_name() const /* Get table name for error messages */ - { - return tmp_table ? ( - orig_table_name ? - orig_table_name : - "(temporary)") : - table_name.str; - } - /* Set of keys in use, implemented as a Bitmap. Excludes keys disabled by ALTER TABLE ... DISABLE KEYS. @@ -2100,7 +2090,7 @@ struct TABLE_LIST /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ List<Index_hint> *index_hints; TABLE *table; /* opened table */ - ulong table_id; /* table id (from binlog) for opened table */ + ulonglong table_id; /* table id (from binlog) for opened table */ /* select_result for derived table to pass it from table creation to table filling procedure diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 18c2e7072e2..0b31c361abc 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -90,6 +90,7 @@ my_bool wsrep_convert_LOCK_to_trx; // Convert locking sessions to t my_bool wsrep_auto_increment_control; // Control auto increment variables my_bool wsrep_drupal_282555_workaround; // Retry autoinc insert after dupkey my_bool wsrep_certify_nonPK; // Certify, even when no primary key +ulong wsrep_certification_rules = WSREP_CERTIFICATION_RULES_STRICT; my_bool wsrep_recovery; // Recovery my_bool wsrep_replicate_myisam; // Enable MyISAM replication my_bool wsrep_log_conflicts; diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index dc2793c384d..d12cc835136 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -32,6 +32,7 @@ typedef struct st_mysql_show_var SHOW_VAR; #include <sql_priv.h> #include "mdl.h" #include "sql_table.h" +#include "wsrep_mysqld_c.h" #include "wsrep/provider.hpp" #include "wsrep/streaming_context.hpp" diff --git a/sql/wsrep_mysqld_c.h b/sql/wsrep_mysqld_c.h new file mode 100644 index 00000000000..235a871c113 --- /dev/null +++ b/sql/wsrep_mysqld_c.h @@ -0,0 +1,30 @@ +/* Copyright 2018-2018 Codership Oy <http://www.codership.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef WSREP_MYSQLD_C_H +#define WSREP_MYSQLD_C_H + +enum enum_wsrep_certification_rules { + WSREP_CERTIFICATION_RULES_STRICT, + WSREP_CERTIFICATION_RULES_OPTIMIZED +}; + +/* This is intentionally declared as a weak global symbol, so that +the same ha_innodb.so can be used with the embedded server +(which does not link to the definition of this variable) +and with the regular server built WITH_WSREP. */ +extern ulong wsrep_certification_rules __attribute__((weak)); + +#endif /* WSREP_MYSQLD_C_H */ |