===== File: include/mysql/plugin_audit.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/plugin_auth.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/plugin_data_type.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/plugin_encryption.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/plugin_ftparser.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/plugin_function.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/plugin_password_validation.h.pp ===== 314 : : }; 315 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 316 : : extern struct thd_alloc_service_st { 317 : : + void *(*thd_alloc_func)(const THD*, size_t); 318 : : + void *(*thd_calloc_func)(const THD*, size_t); 319 : : + char *(*thd_strdup_func)(const THD*, const char *); 320 : : + char *(*thd_strmake_func)(const THD*, const char *, size_t); 321 : : + void *(*thd_memdup_func)(const THD*, const void*, size_t); 322 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const THD*, 323 : : MYSQL_CONST_LEX_STRING *, 324 : : const char *, size_t, int); 325 : : } *thd_alloc_service; 326 : : +void *thd_alloc(const THD* thd, size_t size); 327 : : +void *thd_calloc(const THD* thd, size_t size); 328 : : +char *thd_strdup(const THD* thd, const char *str); 329 : : +char *thd_strmake(const THD* thd, const char *str, size_t size); 330 : : +void *thd_memdup(const THD* thd, const void* str, size_t size); 331 : : MYSQL_CONST_LEX_STRING 332 : : +*thd_make_lex_string(const THD* thd, MYSQL_CONST_LEX_STRING *lex_str, 333 : : const char *str, size_t size, 334 : : int allocate_lex_string); 335 : : } ===== File: include/mysql/service_thd_alloc.h ===== 50 : : typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; 51 : : 52 : : extern struct thd_alloc_service_st { 53 : : + void *(*thd_alloc_func)(const MYSQL_THD, size_t); 54 : : + void *(*thd_calloc_func)(const MYSQL_THD, size_t); 55 : : + char *(*thd_strdup_func)(const MYSQL_THD, const char *); 56 : : + char *(*thd_strmake_func)(const MYSQL_THD, const char *, size_t); 57 : : + void *(*thd_memdup_func)(const MYSQL_THD, const void*, size_t); 58 : : + MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(const MYSQL_THD, 59 : : MYSQL_CONST_LEX_STRING *, 60 : : const char *, size_t, int); 61 : : } *thd_alloc_service; 92 : : 93 : : @see alloc_root() 94 : : */ 95 : : +void *thd_alloc(const MYSQL_THD thd, size_t size); 96 : : /** 97 : : @see thd_alloc() 98 : : */ 99 : : +void *thd_calloc(const MYSQL_THD thd, size_t size); 100 : : /** 101 : : @see thd_alloc() 102 : : */ 103 : : +char *thd_strdup(const MYSQL_THD thd, const char *str); 104 : : /** 105 : : @see thd_alloc() 106 : : */ 107 : : +char *thd_strmake(const MYSQL_THD thd, const char *str, size_t size); 108 : : /** 109 : : @see thd_alloc() 110 : : */ 111 : : +void *thd_memdup(const MYSQL_THD thd, const void* str, size_t size); 112 : : 113 : : /** 114 : : Create a LEX_STRING in this connection's local memory pool 124 : : @see thd_alloc() 125 : : */ 126 : : MYSQL_CONST_LEX_STRING 127 : : +*thd_make_lex_string(const MYSQL_THD thd, MYSQL_CONST_LEX_STRING *lex_str, 128 : : const char *str, size_t size, 129 : : int allocate_lex_string); 130 : : ===== File: include/thr_lock.h ===== 173 : : my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, 174 : : enum thr_lock_type new_lock_type, 175 : : ulong lock_wait_timeout); 176 : : my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data, 177 : : ulong lock_wait_timeout); 178 : : void thr_set_lock_wait_callback(void (*before_wait)(void), ===== File: mysys/my_bitmap.c ===== 576 : 1497037 : void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2) 577 : : { 578 : 1497037 : my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end; 579 : 1497037 : + uint len= no_words_in_map(map), len2 = no_words_in_map(map2); 580 : : 581 : 1497037 : DBUG_ASSERT(map->bitmap); 582 : 1497037 : DBUG_ASSERT(map2->bitmap); 583 : : 584 : 1497037 : + end= to + MY_MIN(len, len2 - 1); 585 : 1497375 : + while (to < end) 586 : 338 : *to++ = *from++; 587 : : + 588 : 1497037 : + if (len2 <= len) 589 : 1497024 : + *to= (*from & ~map2->last_word_mask) | (*to & map2->last_word_mask); 590 : 1497037 : } 591 : : 592 : : ===== File: mysys/thr_lock.c ===== 1386 : : } 1387 : : 1388 : : 1389 : : /* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */ 1390 : : 1391 : 2931 : my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, ===== File: sql/field.cc ===== 10508 : : 10509 : 166027 : bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name, 10510 : : enum_vcol_info_type type, Alter_info *alter_info) 10511 : : { 10512 : : bool ret; 10513 : 166027 : Item::vcol_func_processor_result res; ===== File: sql/field.h ===== 1192 : : { 1193 : 99718420 : bitmap_set_bit(&table->has_value_set, field_index); 1194 : 99718267 : } 1195 : 4255268 : + bool has_explicit_value() const 1196 : : { 1197 : 4255268 : return bitmap_is_set(&table->has_value_set, field_index); 1198 : : } ===== File: sql/ha_sequence.cc ===== 287 : 29 : sequence->copy(&tmp_seq); 288 : 5409 : rows_changed++; 289 : : /* We have to do the logging while we hold the sequence mutex */ 290 : 5409 : + error= binlog_log_row(0, buf, log_func); 291 : : } 292 : : 293 : : /* Row is already logged, don't log it again in ha_write_row() */ ===== File: sql/handler.cc ===== 7243 : 350639 : mysql_bin_log.is_open())); 7244 : : } 7245 : : 7246 : 4193497 : +static int binlog_log_row_to_binlog(TABLE* table, 7247 : : + const uchar *before_record, 7248 : : + const uchar *after_record, 7249 : : + Log_func *log_func, 7250 : : + bool has_trans) 7251 : : { 7252 : 4193497 : + bool error= 0; 7253 : 4193497 : + THD *const thd= table->in_use; 7254 : : + 7255 : : + DBUG_ENTER("binlog_log_row_to_binlog"); 7256 : : 7257 : 4456269 : if (!thd->binlog_table_maps && 7258 : 262773 : thd->binlog_write_table_maps()) 7259 : 10 : DBUG_RETURN(HA_ERR_RBR_LOGGING_FAILED); 7260 : : 7261 : 4193486 : + DBUG_ASSERT(thd->is_current_stmt_binlog_format_row()); 7262 : 4193486 : + DBUG_ASSERT((WSREP_NNULL(thd) && wsrep_emulate_bin_log) 7263 : : + || mysql_bin_log.is_open()); 7264 : : + 7265 : 4193491 : + auto *cache_mngr= thd->binlog_setup_trx_data(); 7266 : 4193500 : + if (cache_mngr == NULL) 7267 : 0 : + DBUG_RETURN(HA_ERR_OUT_OF_MEM); 7268 : : + 7269 : : + /* Ensure that all events in a GTID group are in the same cache */ 7270 : 4193500 : + if (thd->variables.option_bits & OPTION_GTID_BEGIN) 7271 : 1032593 : + has_trans= 1; 7272 : : + 7273 : 8387000 : + auto *cache= binlog_get_cache_data(cache_mngr, 7274 : 4193500 : + use_trans_cache(thd, has_trans)); 7275 : : + 7276 : 4193501 : + error= (*log_func)(thd, table, mysql_bin_log.as_event_log(), cache, 7277 : : + has_trans, thd->variables.binlog_row_image, 7278 : : + before_record, after_record); 7279 : 4193501 : DBUG_RETURN(error ? HA_ERR_RBR_LOGGING_FAILED : 0); 7280 : : } 7281 : : 7282 : 61101425 : +int handler::binlog_log_row(const uchar *before_record, 7283 : : + const uchar *after_record, 7284 : : + Log_func *log_func) 7285 : : +{ 7286 : : + DBUG_ENTER("handler::binlog_log_row"); 7287 : : + 7288 : 61101425 : + int error = 0; 7289 : 61101425 : + if (row_logging) 7290 : 4193513 : + error= binlog_log_row_to_binlog(table, before_record, after_record, 7291 : 4193494 : + log_func, row_logging_has_trans); 7292 : : + 7293 : : +#ifdef HAVE_REPLICATION 7294 : 61101444 : + if (unlikely(!error && table->s->online_alter_binlog && is_root_handler())) 7295 : 1357 : + error= binlog_log_row_online_alter(table, before_record, after_record, 7296 : : + log_func); 7297 : : +#endif // HAVE_REPLICATION 7298 : : + 7299 : 61101444 : + DBUG_RETURN(error); 7300 : : +} 7301 : : + 7302 : : 7303 : 27867440 : int handler::ha_external_lock(THD *thd, int lock_type) 7304 : : { 7816 : 54653997 : if ((error= ha_check_overlaps(NULL, buf))) 7817 : 34 : DBUG_RETURN(error); 7818 : : 7819 : 54653614 : + if (table->s->long_unique_table && is_root_handler()) 7820 : : { 7821 : 944 : DBUG_ASSERT(inited == NONE || lookup_handler != this); 7822 : 944 : if ((error= check_duplicate_long_entries(buf))) 7834 : 54653219 : if (likely(!error)) 7835 : : { 7836 : 54616757 : rows_changed++; 7837 : 54616757 : + Log_func *log_func= Write_rows_log_event::binlog_row_logging_function; 7838 : 54616757 : + error= binlog_log_row(0, buf, log_func); 7839 : : + 7840 : : #ifdef WITH_WSREP 7841 : 3573146 : if (WSREP_NNULL(ha_thd()) && table_share->tmp_table == NO_TMP_TABLE && 7842 : 3122178 : ht->flags & HTON_WSREP_REPLICATION && 7867 : 4984596 : uint saved_status= table->status; 7868 : 4984596 : error= ha_check_overlaps(old_data, new_data); 7869 : : 7870 : 4984594 : + if (!error && table->s->long_unique_table && is_root_handler()) 7871 : 136 : error= check_duplicate_long_entries_update(new_data); 7872 : 4984594 : table->status= saved_status; 7873 : : 7885 : 4984468 : if (likely(!error)) 7886 : : { 7887 : 4980823 : rows_changed++; 7888 : 4980823 : + Log_func *log_func= Update_rows_log_event::binlog_row_logging_function; 7889 : 4980823 : + error= binlog_log_row(old_data, new_data, log_func); 7890 : : + 7891 : : #ifdef WITH_WSREP 7892 : 4980825 : THD *thd= ha_thd(); 7893 : 4980818 : if (WSREP_NNULL(thd)) 7961 : 1498534 : if (likely(!error)) 7962 : : { 7963 : 1498449 : rows_changed++; 7964 : 1498449 : + Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function; 7965 : 1498449 : + error= binlog_log_row(buf, 0, log_func); 7966 : : + 7967 : : #ifdef WITH_WSREP 7968 : 1498447 : THD *thd= ha_thd(); 7969 : 1498447 : if (WSREP_NNULL(thd)) ===== File: sql/handler.h ===== 371 : : /* Implements SELECT ... FOR UPDATE SKIP LOCKED */ 372 : : #define HA_CAN_SKIP_LOCKED (1ULL << 61) 373 : : 374 : : +/* This engine is not compatible with Online ALTER TABLE */ 375 : : +#define HA_NO_ONLINE_ALTER (1ULL << 62) 376 : : + 377 : : +#define HA_LAST_TABLE_FLAG HA_NO_ONLINE_ALTER 378 : : 379 : : 380 : : /* bits in index_flags(index_number) for what you can do with index */ 657 : : #define HA_CREATE_PRINT_ALL_OPTIONS (1UL << 26) 658 : : 659 : : typedef ulonglong alter_table_operations; 660 : : + 661 : : +class Event_log; 662 : : +class Cache_flip_event_log; 663 : : +class binlog_cache_data; 664 : : +class online_alter_cache_data; 665 : : +typedef bool Log_func(THD*, TABLE*, Event_log *, binlog_cache_data *, bool, 666 : : + ulong, const uchar*, const uchar*); 667 : : 668 : : /* 669 : : These flags are set by the parser and describes the type of 3560 : 197 : if (org_keyread != MAX_KEY) 3561 : 0 : ha_start_keyread(org_keyread); 3562 : 197 : } 3563 : : + 3564 : : +protected: 3565 : : + bool is_root_handler() const; 3566 : : + 3567 : : +public: 3568 : : int check_collation_compatibility(); 3569 : : int check_long_hash_compatibility() const; 3570 : : int ha_check_for_upgrade(HA_CHECK_OPT *check_opt); 4434 : : @return The handler error code or zero for success. 4435 : : */ 4436 : : virtual int 4437 : 144478 : + get_foreign_key_list(const THD *thd, List *f_key_list) 4438 : 144478 : { return 0; } 4439 : : /** 4440 : : Get the list of foreign keys referencing this table. 4448 : : @return The handler error code or zero for success. 4449 : : */ 4450 : : virtual int 4451 : 71699 : + get_parent_foreign_key_list(const THD *thd, List *f_key_list) 4452 : 71699 : { return 0; } 4453 : 2355436 : virtual uint referenced_by_foreign_key() { return 0;} 4454 : 1031 : virtual void init_table_handle_for_HANDLER() 4520 : : than lock_count() claimed. This can happen when the MERGE children 4521 : : are not attached when this is called from another thread. 4522 : : */ 4523 : : + virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, 4524 : : enum thr_lock_type lock_type)=0; 4525 : : 4526 : : /** Type of table for caching query */ 5062 : : bool check_table_binlog_row_based(); 5063 : : bool prepare_for_row_logging(); 5064 : : int prepare_for_insert(bool do_create); 5065 : : + int binlog_log_row(const uchar *before_record, 5066 : : const uchar *after_record, 5067 : : Log_func *log_func); 5068 : : 5635 : 573603 : return ((lower_case_table_names == 2 && info->alias.str) ? &info->alias : name); 5636 : : } 5637 : : 5638 : : 5639 : : /** 5640 : : @def MYSQL_TABLE_IO_WAIT ===== File: sql/item.cc ===== 1560 : : { 1561 : 51640 : context= 0; 1562 : 51640 : vcol_func_processor_result *res= (vcol_func_processor_result *) arg; 1563 : 51640 : + if (res->alter_info) 1564 : : { 1565 : 1689 : for (Key &k: res->alter_info->key_list) 1566 : : { ===== File: sql/lock.cc ===== 816 : : enum thr_lock_type lock_type; 817 : : THR_LOCK_DATA **locks_start; 818 : : 819 : 6728059 : + if ((table->s->tmp_table && table->s->tmp_table != TRANSACTIONAL_TMP_TABLE) 820 : 6675157 : + || (flags & GET_LOCK_SKIP_SEQUENCES && table->s->sequence != NULL)) 821 : 53246 : continue; 822 : 6674813 : lock_type= table->reginfo.lock_type; 823 : 6674813 : DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT); ===== File: sql/log.cc ===== 45 : : #include // For test_if_number 46 : : 47 : : #include // for Sys_last_gtid_ptr 48 : : +#include 49 : : 50 : : #ifdef _WIN32 51 : : #include "message.h" 104 : : Log_event *end_ev, bool all, bool using_stmt, 105 : : bool using_trx, bool is_ro_1pc); 106 : : 107 : : +static int binlog_online_alter_end_trans(THD *thd, bool all, bool commit); 108 : : + 109 : : static const LEX_CSTRING write_error_msg= 110 : : { STRING_WITH_LEN("error writing to the binary log") }; 111 : : 278 : : class binlog_cache_data 279 : : { 280 : : public: 281 : 46723 : + binlog_cache_data(): before_stmt_pos(MY_OFF_T_UNDEF), m_pending(0), status(0), 282 : 46723 : + incident(FALSE), saved_max_binlog_cache_size(0), ptr_binlog_cache_use(0), 283 : 46723 : ptr_binlog_cache_disk_use(0) 284 : 46723 : { } 285 : : 411 : : */ 412 : : IO_CACHE cache_log; 413 : : 414 : : +protected: 415 : : + /* 416 : : + Binlog position before the start of the current statement. 417 : : + */ 418 : : + my_off_t before_stmt_pos; 419 : : + 420 : : private: 421 : : /* 422 : : Pending binrows event. This event is the event where the rows are currently 431 : : */ 432 : : uint32 status; 433 : : 434 : : /* 435 : : This indicates that some events did not get into the cache and most likely 436 : : it is corrupted. 489 : 3 : delete pending(); 490 : 3 : set_pending(0); 491 : : } 492 : 420587 : + my_bool res= reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, reset_cache); 493 : 420588 : + DBUG_ASSERT(res == 0); 494 : 420588 : cache_log.end_of_file= saved_max_binlog_cache_size; 495 : 420588 : } 496 : : 499 : : }; 500 : : 501 : : 502 : : +class online_alter_cache_data: public Sql_alloc, public ilist_node<>, 503 : : + public binlog_cache_data 504 : : +{ 505 : : +public: 506 : 1609 : + void store_prev_position() 507 : : + { 508 : 1609 : + before_stmt_pos= my_b_write_tell(&cache_log); 509 : 1609 : + } 510 : : + 511 : : + handlerton *hton; 512 : : + Cache_flip_event_log *sink_log; 513 : : + SAVEPOINT *sv_list; 514 : : +}; 515 : : + 516 : 1702764 : void Log_event_writer::add_status(enum_logged_status status) 517 : : { 518 : 1702764 : if (likely(cache_data)) 595 : : ulong binlog_id; 596 : : /* Set if we get an error during commit that must be returned from unlog(). */ 597 : : bool delayed_error; 598 : : + 599 : : //Will be reset when gtid is written into binlog 600 : : uchar gtid_flags3; 601 : : decltype (rpl_gtid::seq_no) sa_seq_no; 1781 : : DBUG_ENTER("binlog_trans_log_truncate"); 1782 : : DBUG_PRINT("enter", ("pos: %lu", (ulong) pos)); 1783 : : 1784 : 71 : + DBUG_ASSERT(thd->binlog_get_cache_mngr() != NULL); 1785 : : /* Only true if binlog_trans_log_savepos() wasn't called before */ 1786 : 71 : DBUG_ASSERT(pos != ~(my_off_t) 0); 1787 : : 1788 : 71 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 1789 : 71 : cache_mngr->trx_cache.restore_savepoint(pos); 1790 : 71 : DBUG_VOID_RETURN; 1791 : : } 1825 : 22290 : static int binlog_close_connection(handlerton *hton, THD *thd) 1826 : : { 1827 : : DBUG_ENTER("binlog_close_connection"); 1828 : 22290 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 1829 : : #ifdef WITH_WSREP 1830 : 22262 : if (WSREP(thd) && cache_mngr && !cache_mngr->trx_cache.empty()) { 1831 : 0 : IO_CACHE* cache= cache_mngr->get_binlog_cache_log(true); 2073 : 2554 : binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all) 2074 : : { 2075 : : DBUG_ENTER("binlog_truncate_trx_cache"); 2076 : : + 2077 : 2554 : + if(!WSREP_EMULATE_BINLOG_NNULL(thd) && !mysql_bin_log.is_open()) 2078 : 0 : + DBUG_RETURN(0); 2079 : : + 2080 : 2554 : int error=0; 2081 : : 2082 : : DBUG_PRINT("info", ("thd->options={ %s %s}, transaction: %s", 2083 : : FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT), 2084 : : FLAGSTR(thd->variables.option_bits, OPTION_BEGIN), 2085 : : all ? "all" : "stmt")); 2086 : : 2087 : 2554 : + auto &trx_cache= cache_mngr->trx_cache; 2088 : 2554 : + MYSQL_BIN_LOG::remove_pending_rows_event(thd, &trx_cache); 2089 : 2554 : + thd->reset_binlog_for_next_statement(); 2090 : : + 2091 : : /* 2092 : : If rolling back an entire transaction or a single statement not 2093 : : inside a transaction, we reset the transaction cache. 2094 : : */ 2095 : 2554 : if (ending_trans(thd, all)) 2096 : : { 2097 : 1954 : + if (trx_cache.has_incident()) 2098 : 7 : error= mysql_bin_log.write_incident(thd); 2099 : : 2100 : 1954 : + DBUG_ASSERT(thd->binlog_table_maps == 0); 2101 : : 2102 : 1954 : cache_mngr->reset(false, true); 2103 : : } 2106 : : transaction cache to remove the statement. 2107 : : */ 2108 : : else 2109 : 600 : + trx_cache.restore_prev_position(); 2110 : : 2111 : 2554 : + DBUG_ASSERT(trx_cache.pending() == NULL); 2112 : 2554 : DBUG_RETURN(error); 2113 : : } 2114 : : 2267 : 7020 : return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE)); 2268 : 7020 : } 2269 : : 2270 : : +#ifdef HAVE_REPLICATION 2271 : 1357 : +int binlog_log_row_online_alter(TABLE* table, const uchar *before_record, 2272 : : + const uchar *after_record, Log_func *log_func) 2273 : : +{ 2274 : 1357 : + THD *thd= table->in_use; 2275 : : + 2276 : 1357 : + if (!table->online_alter_cache) 2277 : : + { 2278 : 225 : + table->online_alter_cache= online_alter_binlog_get_cache_data(thd, table); 2279 : 225 : + trans_register_ha(thd, false, binlog_hton, 0); 2280 : 225 : + if (thd->in_multi_stmt_transaction_mode()) 2281 : 48 : + trans_register_ha(thd, true, binlog_hton, 0); 2282 : : + } 2283 : : + 2284 : : + // We need to log all columns for the case if alter table changes primary key 2285 : 1357 : + DBUG_ASSERT(!before_record || bitmap_is_set_all(table->read_set)); 2286 : 1357 : + MY_BITMAP *old_rpl_write_set= table->rpl_write_set; 2287 : 1357 : + table->rpl_write_set= &table->s->all_set; 2288 : : + 2289 : 1357 : + table->online_alter_cache->store_prev_position(); 2290 : 1357 : + int error= (*log_func)(thd, table, table->s->online_alter_binlog, 2291 : 1357 : + table->online_alter_cache, 2292 : 1357 : + table->file->has_transactions_and_rollback(), 2293 : : + BINLOG_ROW_IMAGE_FULL, 2294 : 1357 : + before_record, after_record); 2295 : : + 2296 : 1357 : + table->rpl_write_set= old_rpl_write_set; 2297 : : + 2298 : 1357 : + if (unlikely(error)) 2299 : : + { 2300 : 2 : + table->online_alter_cache->restore_prev_position(); 2301 : 2 : + return HA_ERR_RBR_LOGGING_FAILED; 2302 : : + } 2303 : : + 2304 : 1355 : + return 0; 2305 : : +} 2306 : : + 2307 : : +static void 2308 : 261 : +binlog_online_alter_cleanup(ilist &list, bool ending_trans) 2309 : : +{ 2310 : 261 : + if (ending_trans) 2311 : : + { 2312 : 209 : + auto it= list.begin(); 2313 : 627 : + while (it != list.end()) 2314 : : + { 2315 : 209 : + auto &cache= *it++; 2316 : 209 : + cache.sink_log->release(); 2317 : 209 : + cache.reset(); 2318 : 209 : + delete &cache; 2319 : : + } 2320 : 209 : + list.clear(); 2321 : 209 : + DBUG_ASSERT(list.empty()); 2322 : : + } 2323 : 261 : +} 2324 : : +#endif // HAVE_REPLICATION 2325 : : + 2326 : : /** 2327 : : This function is called once after each statement. 2328 : : 2339 : 513625 : PSI_stage_info org_stage; 2340 : : DBUG_ENTER("binlog_commit"); 2341 : : 2342 : 513625 : + IF_DBUG(bool commit_online= !thd->online_alter_cache_list.empty(),); 2343 : : + 2344 : 513623 : + bool is_ending_transaction= ending_trans(thd, all); 2345 : 513623 : + error= binlog_online_alter_end_trans(thd, all, true); 2346 : 513624 : + if (error) 2347 : 0 : + DBUG_RETURN(error); 2348 : : 2349 : 513624 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 2350 : : + /* 2351 : : + cache_mngr can be NULL in case if binlog logging is disabled. 2352 : : + */ 2353 : 513624 : if (!cache_mngr) 2354 : : { 2355 : 110 : + DBUG_ASSERT(WSREP(thd) || commit_online || 2356 : : (thd->lex->sql_command != SQLCOM_XA_PREPARE && 2357 : : !(thd->lex->sql_command == SQLCOM_XA_COMMIT && 2358 : : thd->lex->xa_opt == XA_ONE_PHASE))); 2409 : : - We are in a transaction and a full transaction is committed. 2410 : : Otherwise, we accumulate the changes. 2411 : : */ 2412 : 388104 : + if (likely(!error) && is_ending_transaction) 2413 : : { 2414 : 57452 : bool is_xa_prepare= is_preparing_xa(thd); 2415 : : 2449 : : { 2450 : : DBUG_ENTER("binlog_rollback"); 2451 : : 2452 : 7925 : + bool is_ending_trans= ending_trans(thd, all); 2453 : : + 2454 : 7925 : + bool rollback_online= !thd->online_alter_cache_list.empty(); 2455 : 7925 : + if (rollback_online) 2456 : 15 : + binlog_online_alter_end_trans(thd, all, 0); 2457 : 7925 : int error= 0; 2458 : 7925 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 2459 : : 2460 : 7925 : if (!cache_mngr) 2461 : : { 2462 : 8 : + DBUG_ASSERT(WSREP(thd) || rollback_online); 2463 : 8 : + DBUG_ASSERT(thd->lex->sql_command != SQLCOM_XA_ROLLBACK || rollback_online); 2464 : : 2465 : 8 : DBUG_RETURN(0); 2466 : : } 2496 : 975 : thd->reset_binlog_for_next_statement(); 2497 : 975 : DBUG_RETURN(error); 2498 : : } 2499 : 6942 : + if (!wsrep_emulate_bin_log && Event_log::check_write_error(thd)) 2500 : : { 2501 : : /* 2502 : : "all == true" means that a "rollback statement" triggered the error and 2513 : : } 2514 : 6858 : else if (likely(!error)) 2515 : : { 2516 : 6858 : + if (is_ending_trans && trans_cannot_safely_rollback(thd, all)) 2517 : 4103 : error= binlog_rollback_flush_trx_cache(thd, all, cache_mngr); 2518 : : /* 2519 : : Truncate the cache if: 2525 : : . the format is not MIXED or no temporary non-trans table 2526 : : was updated. 2527 : : */ 2528 : 3565 : + else if (is_ending_trans || 2529 : 810 : (!(thd->transaction->stmt.has_created_dropped_temp_table() && 2530 : 24 : !thd->is_current_stmt_binlog_format_row()) && 2531 : 1292 : (!stmt_has_updated_non_trans_table(thd) || 2548 : : 2549 : 6 : void binlog_reset_cache(THD *thd) 2550 : : { 2551 : 6 : + binlog_cache_mngr *const cache_mngr= opt_bin_log ? 2552 : 6 : + thd->binlog_get_cache_mngr() : 0; 2553 : : DBUG_ENTER("binlog_reset_cache"); 2554 : 6 : if (cache_mngr) 2555 : : { 2556 : 6 : + MYSQL_BIN_LOG::remove_pending_rows_event(thd, &cache_mngr->trx_cache); 2557 : 6 : + thd->reset_binlog_for_next_statement(); 2558 : 6 : cache_mngr->reset(true, true); 2559 : : } 2560 : 6 : DBUG_VOID_RETURN; 2561 : : } 2562 : : 2563 : : 2564 : 148 : +void Event_log::set_write_error(THD *thd, bool is_transactional) 2565 : : { 2566 : : DBUG_ENTER("MYSQL_BIN_LOG::set_write_error"); 2567 : : 2601 : 148 : DBUG_VOID_RETURN; 2602 : : } 2603 : : 2604 : 7235 : +bool Event_log::check_write_error(THD *thd) 2605 : : { 2606 : : DBUG_ENTER("MYSQL_BIN_LOG::check_write_error"); 2607 : : 2653 : 221 : int error= 1; 2654 : : DBUG_ENTER("binlog_savepoint_set"); 2655 : : 2656 : 221 : + if (!mysql_bin_log.is_open() && !thd->online_alter_cache_list.empty()) 2657 : 2 : + DBUG_RETURN(0); 2658 : : + 2659 : 219 : char buf[1024]; 2660 : : 2661 : 219 : String log_query(buf, sizeof(buf), &my_charset_bin); 2688 : : { 2689 : : DBUG_ENTER("binlog_savepoint_rollback"); 2690 : : 2691 : 122 : + if (!mysql_bin_log.is_open() && !thd->online_alter_cache_list.empty()) 2692 : 1 : + DBUG_RETURN(0); 2693 : : + 2694 : : /* 2695 : : Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some 2696 : : non-transactional table. Otherwise, truncate the binlog cache starting 2697 : : from the SAVEPOINT command. 2698 : : + 2699 : : + For streaming replication, we must replicate savepoint rollback so that 2700 : : + slaves can maintain SR transactions 2701 : : */ 2702 : 121 : + if (IF_WSREP(thd->wsrep_trx().is_streaming(),0) || 2703 : 202 : + trans_has_updated_non_trans_table(thd) || 2704 : 81 : + (thd->variables.option_bits & OPTION_BINLOG_THIS_TRX)) 2705 : : { 2706 : 50 : char buf[1024]; 2707 : 50 : String log_query(buf, sizeof(buf), &my_charset_bin); 3160 : : { 3161 : 89382 : end_io_cache(&log_file); 3162 : : 3163 : 33857 : + if (log_type == LOG_BIN && log_file.file >= 0 && 3164 : 123239 : + mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error) 3165 : : { 3166 : 0 : write_error= 1; 3167 : 0 : sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); 3168 : : } 3169 : : 3170 : 86074 : + if (!(exiting & LOG_CLOSE_DELAYED_CLOSE) && log_file.file >= 0 && 3171 : 175455 : mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error) 3172 : : { 3173 : 0 : write_error= 1; 3664 : : We don't want to initialize locks here as such initialization depends on 3665 : : safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is 3666 : : called only in main(). Doing initialization here would make it happen 3667 : : + before main(). init_pthread_objects() can be called for that purpose. 3668 : : */ 3669 : 52593 : index_file_name[0] = 0; 3670 : 52593 : bzero((char*) &index_file, sizeof(index_file)); 3756 : : 3757 : 51887 : void MYSQL_BIN_LOG::init_pthread_objects() 3758 : : { 3759 : 51887 : + Event_log::init_pthread_objects(); 3760 : 51885 : mysql_mutex_init(m_key_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW); 3761 : 51885 : mysql_mutex_setflags(&LOCK_index, MYF_NO_DEADLOCK_DETECTION); 3762 : 51885 : mysql_mutex_init(key_BINLOG_LOCK_xid_list, 3772 : : &COND_binlog_background_thread, 0); 3773 : 51883 : mysql_cond_init(key_BINLOG_COND_binlog_background_thread_end, 3774 : : &COND_binlog_background_thread_end, 0); 3775 : 51880 : } 3776 : : 3777 : : 3842 : : } 3843 : : 3844 : : 3845 : 42081 : +bool Event_log::open(enum cache_type io_cache_type_arg) 3846 : : +{ 3847 : 42081 : + bool error= init_io_cache(&log_file, -1, LOG_BIN_IO_SIZE, io_cache_type_arg, 3848 : 42080 : + 0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)); 3849 : : + 3850 : 42080 : + log_state= LOG_OPENED; 3851 : 42080 : + inited= true; 3852 : 42080 : + if (error) 3853 : 0 : + return error; 3854 : : + 3855 : 42080 : + longlong bytes_written= write_description_event(BINLOG_CHECKSUM_ALG_OFF, 3856 : : + false, true, false); 3857 : 42072 : + status_var_add(current_thd->status_var.binlog_bytes_written, bytes_written); 3858 : 42076 : + return bytes_written < 0; 3859 : : +} 3860 : : + 3861 : : +longlong 3862 : 76917 : +Event_log::write_description_event(enum_binlog_checksum_alg checksum_alg, 3863 : : + bool encrypt, bool dont_set_created, 3864 : : + bool is_relay_log) 3865 : : +{ 3866 : 76917 : + Format_description_log_event s(BINLOG_VERSION); 3867 : : + /* 3868 : : + don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache 3869 : : + as we won't be able to reset it later 3870 : : + */ 3871 : 76912 : + if (io_cache_type == WRITE_CACHE) 3872 : 12190 : + s.flags |= LOG_EVENT_BINLOG_IN_USE_F; 3873 : 76912 : + s.checksum_alg= checksum_alg; 3874 : 76912 : + if (is_relay_log) 3875 : 22646 : + s.set_relay_log_event(); 3876 : : + 3877 : 76914 : + crypto.scheme = 0; 3878 : 76914 : + DBUG_ASSERT(s.checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF); 3879 : 76914 : + if (!s.is_valid()) 3880 : 0 : + return -1; 3881 : 76911 : + s.dont_set_created= dont_set_created; 3882 : 76911 : + if (write_event(&s, 0, &log_file)) 3883 : 0 : + return -1; 3884 : : + 3885 : 76911 : + if (encrypt) 3886 : : + { 3887 : 1381 : + uint key_version= encryption_key_get_latest_version(ENCRYPTION_KEY_SYSTEM_DATA); 3888 : 1381 : + if (key_version == ENCRYPTION_KEY_VERSION_INVALID) 3889 : : + { 3890 : 0 : + sql_print_error("Failed to enable encryption of binary logs"); 3891 : 0 : + return -1; 3892 : : + } 3893 : : + 3894 : 1381 : + if (key_version != ENCRYPTION_KEY_NOT_ENCRYPTED) 3895 : : + { 3896 : 1381 : + if (my_random_bytes(crypto.nonce, sizeof(crypto.nonce))) 3897 : 0 : + return -1; 3898 : : + 3899 : 1381 : + Start_encryption_log_event sele(1, key_version, crypto.nonce); 3900 : 1381 : + sele.checksum_alg= s.checksum_alg; 3901 : 1381 : + if (write_event(&sele, 0, &log_file)) 3902 : 0 : + return -1; 3903 : : + 3904 : : + // Start_encryption_log_event is written, enable the encryption 3905 : 1381 : + if (crypto.init(sele.crypto_scheme, key_version)) 3906 : 0 : + return -1; 3907 : 1381 : + } 3908 : : + } 3909 : 76913 : + return (longlong)s.data_written; 3910 : 76911 : +} 3911 : : + 3912 : : + 3913 : : /** 3914 : : Open a (new) binlog file. 3915 : : 4036 : : } 4037 : : 4038 : : { 4039 : : + enum_binlog_checksum_alg alg; 4040 : : 4041 : 34836 : if (is_relay_log) 4042 : : { 4044 : 1648 : relay_log_checksum_alg= 4045 : 1648 : opt_slave_sql_verify_checksum ? (enum_binlog_checksum_alg) binlog_checksum_options 4046 : : : BINLOG_CHECKSUM_ALG_OFF; 4047 : 22646 : + alg= relay_log_checksum_alg; 4048 : : } 4049 : : else 4050 : 12190 : + alg= (enum_binlog_checksum_alg)binlog_checksum_options; 4051 : : 4052 : 69672 : + longlong written= write_description_event(alg, encrypt_binlog, 4053 : 34836 : + null_created_arg, is_relay_log); 4054 : 34836 : + if (written == -1) 4055 : 0 : goto err; 4056 : 34836 : + bytes_written+= written; 4057 : : 4058 : 34836 : if (!is_relay_log) 4059 : : { 4423 : : log_name ? log_name : "NULL", full_log_name)); 4424 : : 4425 : : /* As the file is flushed, we can't get an error here */ 4426 : 178419 : + error= reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0); 4427 : 178419 : + DBUG_ASSERT(!error); 4428 : : 4429 : : for (;;) 4430 : : { 5743 : 11804 : DBUG_RETURN(error); 5744 : : } 5745 : : 5746 : 936862 : +bool Event_log::write_event(Log_event *ev, binlog_cache_data *cache_data, 5747 : : IO_CACHE *file) 5748 : : { 5749 : 936862 : Log_event_writer writer(file, 0, &crypto); 5907 : : bool 5908 : 1178224 : trans_has_updated_trans_table(const THD* thd) 5909 : : { 5910 : 1178224 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 5911 : : 5912 : 1178196 : return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0); 5913 : : } 5956 : : { 5957 : 7494585 : if (is_transactional) 5958 : 5383168 : return 1; 5959 : 2111417 : + auto *const cache_mngr= thd->binlog_get_cache_mngr(); 5960 : : 5961 : 2111387 : return ((thd->is_current_stmt_binlog_format_row() || 5962 : 2111395 : thd->variables.binlog_direct_non_trans_update) ? 0 : 6027 : : binlog_hton, which has internal linkage. 6028 : : */ 6029 : : 6030 : 23250 : +binlog_cache_mngr *binlog_setup_cache_mngr() 6031 : : { 6032 : 23250 : + auto *cache_mngr= (binlog_cache_mngr*) my_malloc(key_memory_binlog_cache_mngr, 6033 : : + sizeof(binlog_cache_mngr), 6034 : : + MYF(MY_ZEROFILL)); 6035 : 46515 : if (!cache_mngr || 6036 : 23257 : open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir, 6037 : 46515 : LOG_PREFIX, (size_t)binlog_stmt_cache_size, MYF(MY_WME)) || 6039 : : LOG_PREFIX, (size_t)binlog_cache_size, MYF(MY_WME))) 6040 : : { 6041 : 0 : my_free(cache_mngr); 6042 : 0 : + return NULL; 6043 : : } 6044 : : 6045 : 0 : cache_mngr= new (cache_mngr) 6046 : : + binlog_cache_mngr(max_binlog_stmt_cache_size, 6047 : : + max_binlog_cache_size, 6048 : : + &binlog_stmt_cache_use, 6049 : : + &binlog_stmt_cache_disk_use, 6050 : : + &binlog_cache_use, 6051 : 23258 : + &binlog_cache_disk_use); 6052 : : + 6053 : 23258 : + return cache_mngr; 6054 : : +} 6055 : : + 6056 : 6056975 : +binlog_cache_mngr *THD::binlog_setup_trx_data() 6057 : : +{ 6058 : : + DBUG_ENTER("THD::binlog_setup_trx_data"); 6059 : : + binlog_cache_mngr *cache_mngr= 6060 : 6056975 : + (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); 6061 : : + 6062 : 6056977 : + if (!cache_mngr) 6063 : : + { 6064 : 23249 : + cache_mngr= binlog_setup_cache_mngr(); 6065 : 23258 : + thd_set_ha_data(this, binlog_hton, cache_mngr); 6066 : : + } 6067 : : + 6068 : : + 6069 : 6056995 : DBUG_RETURN(cache_mngr); 6070 : : } 6071 : : 6132 : : void 6133 : 474288 : THD::binlog_start_trans_and_stmt() 6134 : : { 6135 : 474288 : + binlog_cache_mngr *cache_mngr= binlog_get_cache_mngr(); 6136 : : DBUG_ENTER("binlog_start_trans_and_stmt"); 6137 : : DBUG_PRINT("enter", ("cache_mngr: %p cache_mngr->trx_cache.get_prev_position(): %lu", 6138 : : cache_mngr, 6219 : : } 6220 : : 6221 : 426085 : void THD::binlog_set_stmt_begin() { 6222 : 426085 : + binlog_cache_mngr *cache_mngr= binlog_get_cache_mngr(); 6223 : : 6224 : : /* 6225 : : The call to binlog_trans_log_savepos() might create the cache_mngr 6229 : : */ 6230 : 426084 : my_off_t pos= 0; 6231 : 426084 : binlog_trans_log_savepos(this, &pos); 6232 : 426085 : + cache_mngr= binlog_get_cache_mngr(); 6233 : 426086 : cache_mngr->trx_cache.set_prev_position(pos); 6234 : 426083 : } 6235 : : 6336 : : } 6337 : 433306 : if (table->file->row_logging) 6338 : : { 6339 : 268013 : + if (mysql_bin_log.write_table_map(this, table, with_annotate)) 6340 : 10 : DBUG_RETURN(1); 6341 : 268003 : with_annotate= 0; 6342 : : } 6369 : : nonzero if an error pops up when writing the table map event. 6370 : : */ 6371 : : 6372 : 268012 : +bool MYSQL_BIN_LOG::write_table_map(THD *thd, TABLE *table, bool with_annotate) 6373 : : { 6374 : 268012 : int error= 1; 6375 : 268012 : bool is_transactional= table->file->row_logging_has_trans; 6382 : 268012 : DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); 6383 : : 6384 : : /* Ensure that all events in a GTID group are in the same cache */ 6385 : 268012 : + if (thd->variables.option_bits & OPTION_GTID_BEGIN) 6386 : 100428 : is_transactional= 1; 6387 : : 6388 : : Table_map_log_event 6389 : 268012 : + the_event(thd, table, table->s->table_map_id, is_transactional); 6390 : : 6391 : 268012 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 6392 : : binlog_cache_data *cache_data= (cache_mngr-> 6393 : 268013 : get_binlog_cache_data(is_transactional)); 6394 : 268013 : IO_CACHE *file= &cache_data->cache_log; 6395 : 268013 : Log_event_writer writer(file, cache_data); 6396 : : 6397 : 268012 : if (with_annotate) 6398 : 262772 : + if (thd->binlog_write_annotated_row(&writer)) 6399 : 3 : goto write_err; 6400 : : 6401 : 268010 : DBUG_EXECUTE_IF("table_map_write_error", 6413 : 268002 : DBUG_RETURN(0); 6414 : : 6415 : 10 : write_err: 6416 : 10 : + set_write_error(thd, is_transactional); 6417 : : /* 6418 : : For non-transactional engine or multi statement transaction with mixed 6419 : : engines, data is written to table but writing to binary log failed. In 6420 : : these scenarios rollback is not possible. Hence report an incident. 6421 : : */ 6422 : 20 : + if (check_write_error(thd) && cache_data && 6423 : 26 : + thd->lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE) && 6424 : 6 : table->current_lock == F_WRLCK) 6425 : 6 : cache_data->set_incident(); 6426 : 10 : DBUG_RETURN(error); 6427 : 268012 : } 6428 : : 6429 : : 6430 : : +#ifdef HAVE_REPLICATION 6431 : : +static online_alter_cache_data * 6432 : 209 : +online_alter_binlog_setup_cache_data(MEM_ROOT *root, TABLE_SHARE *share) 6433 : : +{ 6434 : : + static ulong online_alter_cache_use= 0, online_alter_cache_disk_use= 0; 6435 : : + 6436 : 209 : + auto cache= new (root) online_alter_cache_data(); 6437 : 209 : + if (!cache || open_cached_file(&cache->cache_log, mysql_tmpdir, 6438 : : + LOG_PREFIX, (size_t)binlog_cache_size, MYF(MY_WME))) 6439 : : + { 6440 : 0 : + delete cache; 6441 : 0 : + return NULL; 6442 : : + } 6443 : : + 6444 : 209 : + share->online_alter_binlog->acquire(); 6445 : 209 : + cache->hton= share->db_type(); 6446 : 209 : + cache->sink_log= share->online_alter_binlog; 6447 : : + 6448 : 209 : + my_off_t binlog_max_size= SIZE_T_MAX; // maximum possible cache size 6449 : 209 : + DBUG_EXECUTE_IF("online_alter_small_cache", binlog_max_size= 4096;); 6450 : : + 6451 : 209 : + cache->set_binlog_cache_info(binlog_max_size, 6452 : : + &online_alter_cache_use, 6453 : : + &online_alter_cache_disk_use); 6454 : 209 : + cache->store_prev_position(); 6455 : 209 : + return cache; 6456 : : +} 6457 : : + 6458 : : + 6459 : 225 : +online_alter_cache_data *online_alter_binlog_get_cache_data(THD *thd, TABLE *table) 6460 : : +{ 6461 : 225 : + ilist &list= thd->online_alter_cache_list; 6462 : : + 6463 : : + /* we assume it's very rare to have more than one online ALTER running */ 6464 : 225 : + for (auto &cache: list) 6465 : : + { 6466 : 16 : + if (cache.sink_log == table->s->online_alter_binlog) 6467 : 16 : + return &cache; 6468 : : + } 6469 : : + 6470 : 209 : + MEM_ROOT *root= &thd->transaction->mem_root; 6471 : 209 : + auto *new_cache_data= online_alter_binlog_setup_cache_data(root, table->s); 6472 : 209 : + list.push_back(*new_cache_data); 6473 : : + 6474 : 209 : + return new_cache_data; 6475 : : +} 6476 : : +#endif 6477 : : + 6478 : 11405616 : +binlog_cache_mngr *THD::binlog_get_cache_mngr() const 6479 : : +{ 6480 : 11405616 : + return (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); 6481 : : +} 6482 : : + 6483 : : + 6484 : : /** 6485 : : This function retrieves a pending row event from a cache which is 6486 : : specified through the parameter @c is_transactional. Respectively, when it 6487 : : is @c true, the pending event is returned from the transactional cache. 6488 : : Otherwise from the non-transactional cache. 6489 : : 6490 : : + @param cache_mngr cache manager to return pending row from 6491 : : + @param use_trans_cache @c true indicates a transactional cache, 6492 : : otherwise @c false a non-transactional. 6493 : : @return 6494 : : The row event if any. 6495 : : */ 6496 : 750134 : +Rows_log_event* binlog_get_pending_rows_event(binlog_cache_mngr *cache_mngr, 6497 : : + bool use_trans_cache) 6498 : : { 6499 : 750134 : + DBUG_ASSERT(cache_mngr); 6500 : 750134 : + return cache_mngr->get_binlog_cache_data(use_trans_cache)->pending(); 6501 : : } 6502 : : 6503 : 7283031 : +binlog_cache_data* binlog_get_cache_data(binlog_cache_mngr *cache_mngr, 6504 : : + bool use_trans_cache) 6505 : : { 6506 : 7283031 : + return cache_mngr->get_binlog_cache_data(use_trans_cache); 6507 : : +} 6508 : : 6509 : 3089777 : +int binlog_flush_pending_rows_event(THD *thd, bool stmt_end, 6510 : : + bool is_transactional, 6511 : : + Event_log *bin_log, 6512 : : + binlog_cache_data *cache_data) 6513 : : +{ 6514 : 3089777 : + int error= 0; 6515 : 3089777 : + auto *pending= cache_data->pending(); 6516 : 3089795 : + if (pending) 6517 : : + { 6518 : : + /* 6519 : : + Mark the event as the last event of a statement if the stmt_end 6520 : : + flag is set. 6521 : : + */ 6522 : 262935 : + if (stmt_end) 6523 : : + { 6524 : 262712 : + pending->set_flags(Rows_log_event::STMT_END_F); 6525 : 262712 : + thd->reset_binlog_for_next_statement(); 6526 : : + } 6527 : : 6528 : 262933 : + error= bin_log->flush_and_set_pending_rows_event(thd, 0, cache_data, 6529 : : + is_transactional); 6530 : : + } 6531 : 3089794 : + return error; 6532 : : } 6533 : : 6534 : : /** 6535 : : This function removes the pending rows event, discarding any outstanding 6536 : : rows. If there is no pending rows event available, this is effectively a 6541 : : otherwise @c false a non-transactional. 6542 : : */ 6543 : : int 6544 : 2628 : +MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd, binlog_cache_data *cache_data) 6545 : : { 6546 : : DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event"); 6547 : : 6548 : 2628 : if (Rows_log_event* pending= cache_data->pending()) 6549 : : { 6550 : 464 : delete pending; 6558 : : Moves the last bunch of rows from the pending Rows event to a cache (either 6559 : : transactional cache if is_transaction is @c true, or the non-transactional 6560 : : cache otherwise. Sets a new pending event. 6561 : : + In case of error during flushing, sets write_error=1 to itself. 6562 : : 6563 : : @param thd a pointer to the user thread. 6564 : : @param evt a pointer to the row event. 6566 : : otherwise @c false a non-transactional. 6567 : : */ 6568 : : int 6569 : 542605 : +Event_log::flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event, 6570 : : + binlog_cache_data *cache_data, 6571 : : + bool is_transactional) 6572 : : { 6573 : : DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); 6574 : 542605 : + DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || is_open()); 6575 : : DBUG_PRINT("enter", ("event: %p", event)); 6576 : : 6577 : : DBUG_PRINT("info", ("cache_mngr->pending(): %p", cache_data->pending())); 6578 : : 6579 : 542606 : if (Rows_log_event* pending= cache_data->pending()) 6601 : 279192 : delete pending; 6602 : : } 6603 : : 6604 : 542602 : + cache_data->set_pending(event); 6605 : : 6606 : 542600 : DBUG_RETURN(0); 6607 : : } 6608 : : 6609 : : +/* 6610 : : + Member function for ensuring that there is an rows log 6611 : : + event of the apropriate type before proceeding. 6612 : : + 6613 : : + POST CONDITION: 6614 : : + If a non-NULL pointer is returned, the pending event for thread 'thd' will 6615 : : + be an event created by callback hold by event_factory, and 6616 : : + will be either empty or have enough space to hold 'needed' bytes. 6617 : : + In addition, the columns bitmap will be correct for the row, meaning that 6618 : : + the pending event will be flushed if the columns in the event differ from 6619 : : + the columns suppled to the function. 6620 : : + 6621 : : + RETURNS 6622 : : + If no error, a non-NULL pending event (either one which already existed or 6623 : : + the newly created one). 6624 : : + If error, NULL. 6625 : : + */ 6626 : : + 6627 : : +Rows_log_event* 6628 : 4194855 : +Event_log::prepare_pending_rows_event(THD *thd, TABLE* table, 6629 : : + binlog_cache_data *cache_data, 6630 : : + uint32 serv_id, size_t needed, 6631 : : + bool is_transactional, 6632 : : + Rows_event_factory event_factory) 6633 : : +{ 6634 : : + DBUG_ENTER("MYSQL_BIN_LOG::prepare_pending_rows_event"); 6635 : : + /* Pre-conditions */ 6636 : 4194855 : + DBUG_ASSERT(table->s->table_map_id != ~0UL); 6637 : : + 6638 : : + /* 6639 : : + There is no good place to set up the transactional data, so we 6640 : : + have to do it here. 6641 : : + */ 6642 : 4194855 : + Rows_log_event* pending= cache_data->pending(); 6643 : : + 6644 : 4194853 : + if (unlikely(pending && !pending->is_valid())) 6645 : 0 : + DBUG_RETURN(NULL); 6646 : : + 6647 : : + /* 6648 : : + Check if the current event is non-NULL and a write-rows 6649 : : + event. Also check if the table provided is mapped: if it is not, 6650 : : + then we have switched to writing to a new table. 6651 : : + If there is no pending event, we need to create one. If there is a pending 6652 : : + event, but it's not about the same table id, or not of the same type 6653 : : + (between Write, Update and Delete), or not the same affected columns, or 6654 : : + going to be too big, flush this event to disk and create a new pending 6655 : : + event. 6656 : : + */ 6657 : 8126295 : + if (!pending || 6658 : 3931438 : + pending->server_id != serv_id || 6659 : 3931437 : + pending->get_table_id() != table->s->table_map_id || 6660 : 3927174 : + pending->get_general_type_code() != event_factory.type_code || 6661 : 12041472 : + pending->get_data_size() + needed > opt_binlog_rows_event_max_size || 6662 : 3915186 : + pending->read_write_bitmaps_cmp(table) == FALSE) 6663 : : + { 6664 : : + /* Create a new RowsEventT... */ 6665 : : + Rows_log_event* const 6666 : 279673 : + ev= event_factory.create(thd, table, table->s->table_map_id, 6667 : : + is_transactional); 6668 : 279673 : + if (unlikely(!ev)) 6669 : 0 : + DBUG_RETURN(NULL); 6670 : 279673 : + ev->server_id= serv_id; // I don't like this, it's too easy to forget. 6671 : : + /* 6672 : : + flush the pending event and replace it with the newly created 6673 : : + event... 6674 : : + */ 6675 : 279673 : + if (unlikely(flush_and_set_pending_rows_event(thd, ev, cache_data, 6676 : : + is_transactional))) 6677 : : + { 6678 : 3 : + delete ev; 6679 : 4 : + DBUG_RETURN(NULL); 6680 : : + } 6681 : : + 6682 : 279668 : + DBUG_RETURN(ev); /* This is the new pending event */ 6683 : : + } 6684 : 3915184 : + DBUG_RETURN(pending); /* This is the current pending event */ 6685 : : +} 6686 : : + 6687 : : 6688 : : /* Generate a new global transaction ID, and write it to the binlog */ 6689 : : 7731 : : bool first; 7732 : : }; 7733 : : 7734 : 513639 : +static int binlog_online_alter_end_trans(THD *thd, bool all, bool commit) 7735 : : +{ 7736 : : + DBUG_ENTER("binlog_online_alter_end_trans"); 7737 : 513639 : + int error= 0; 7738 : : +#ifdef HAVE_REPLICATION 7739 : 513639 : + if (thd->online_alter_cache_list.empty()) 7740 : 513376 : + DBUG_RETURN(0); 7741 : : + 7742 : 261 : + bool is_ending_transaction= ending_trans(thd, all); 7743 : : + 7744 : 522 : + for (auto &cache: thd->online_alter_cache_list) 7745 : : + { 7746 : 261 : + auto *binlog= cache.sink_log; 7747 : 261 : + DBUG_ASSERT(binlog); 7748 : 522 : + bool non_trans= cache.hton->flags & HTON_NO_ROLLBACK // Aria 7749 : 261 : + || !cache.hton->rollback; 7750 : 261 : + bool do_commit= (commit && is_ending_transaction) || non_trans; 7751 : : + 7752 : 261 : + if (commit || non_trans) 7753 : : + { 7754 : : + // Do not set STMT_END for last event to leave table open in altering thd 7755 : 252 : + error= binlog_flush_pending_rows_event(thd, false, true, binlog, &cache); 7756 : : + } 7757 : : + 7758 : 261 : + if (do_commit) 7759 : : + { 7760 : : + /* 7761 : : + If the cache wasn't reinited to write, then it remains empty after 7762 : : + the last write. 7763 : : + */ 7764 : 209 : + if (my_b_bytes_in_cache(&cache.cache_log) && likely(!error)) 7765 : : + { 7766 : 202 : + DBUG_ASSERT(cache.cache_log.type != READ_CACHE); 7767 : 202 : + mysql_mutex_lock(binlog->get_log_lock()); 7768 : 202 : + error= binlog->write_cache_raw(thd, &cache.cache_log); 7769 : 202 : + mysql_mutex_unlock(binlog->get_log_lock()); 7770 : : + } 7771 : : + } 7772 : 52 : + else if (!commit) // rollback 7773 : : + { 7774 : 9 : + DBUG_ASSERT(!non_trans); 7775 : 9 : + cache.restore_prev_position(); 7776 : : + } 7777 : : + else 7778 : : + { 7779 : 43 : + DBUG_ASSERT(!is_ending_transaction); 7780 : 43 : + cache.store_prev_position(); 7781 : : + } 7782 : : + 7783 : : + 7784 : 261 : + if (error) 7785 : : + { 7786 : 0 : + my_error(ER_ERROR_ON_WRITE, MYF(ME_ERROR_LOG), 7787 : 0 : + binlog->get_name(), errno); 7788 : 0 : + binlog_online_alter_cleanup(thd->online_alter_cache_list, 7789 : : + is_ending_transaction); 7790 : 0 : + DBUG_RETURN(error); 7791 : : + } 7792 : : + } 7793 : : + 7794 : 261 : + binlog_online_alter_cleanup(thd->online_alter_cache_list, 7795 : : + is_ending_transaction); 7796 : : + 7797 : 499 : + for (TABLE *table= thd->open_tables; table; table= table->next) 7798 : 238 : + table->online_alter_cache= NULL; 7799 : : +#endif // HAVE_REPLICATION 7800 : 261 : + DBUG_RETURN(error); 7801 : : +} 7802 : : + 7803 : : +SAVEPOINT** find_savepoint_in_list(THD *thd, LEX_CSTRING name, 7804 : : + SAVEPOINT ** const list); 7805 : : + 7806 : : +SAVEPOINT* savepoint_add(THD *thd, LEX_CSTRING name, SAVEPOINT **list, 7807 : : + int (*release_old)(THD*, SAVEPOINT*)); 7808 : : + 7809 : 934 : +int online_alter_savepoint_set(THD *thd, LEX_CSTRING name) 7810 : : +{ 7811 : : + 7812 : : + DBUG_ENTER("binlog_online_alter_savepoint"); 7813 : : +#ifdef HAVE_REPLICATION 7814 : 934 : + if (thd->online_alter_cache_list.empty()) 7815 : 930 : + DBUG_RETURN(0); 7816 : : + 7817 : 4 : + if (savepoint_alloc_size < sizeof (SAVEPOINT) + sizeof(my_off_t)) 7818 : 0 : + savepoint_alloc_size= sizeof (SAVEPOINT) + sizeof(my_off_t); 7819 : : + 7820 : 8 : + for (auto &cache: thd->online_alter_cache_list) 7821 : : + { 7822 : 4 : + if (cache.hton->savepoint_set == NULL) 7823 : 0 : + continue; 7824 : : + 7825 : 4 : + SAVEPOINT *sv= savepoint_add(thd, name, &cache.sv_list, NULL); 7826 : 4 : + if(unlikely(sv == NULL)) 7827 : 0 : + DBUG_RETURN(1); 7828 : 4 : + my_off_t *pos= (my_off_t*)(sv+1); 7829 : 4 : + *pos= cache.get_byte_position(); 7830 : : + 7831 : 4 : + sv->prev= cache.sv_list; 7832 : 4 : + cache.sv_list= sv; 7833 : : + } 7834 : : +#endif 7835 : 4 : + DBUG_RETURN(0); 7836 : : +} 7837 : : + 7838 : 408 : +int online_alter_savepoint_rollback(THD *thd, LEX_CSTRING name) 7839 : : +{ 7840 : : + DBUG_ENTER("online_alter_savepoint_rollback"); 7841 : : +#ifdef HAVE_REPLICATION 7842 : 411 : + for (auto &cache: thd->online_alter_cache_list) 7843 : : + { 7844 : 3 : + if (cache.hton->savepoint_set == NULL) 7845 : 0 : + continue; 7846 : : + 7847 : 3 : + SAVEPOINT **sv= find_savepoint_in_list(thd, name, &cache.sv_list); 7848 : : + // sv is null if savepoint was set up before online table was modified 7849 : 3 : + my_off_t pos= *sv ? *(my_off_t*)(*sv+1) : 0; 7850 : : + 7851 : 3 : + cache.restore_savepoint(pos); 7852 : : + } 7853 : : + 7854 : : +#endif 7855 : 408 : + DBUG_RETURN(0); 7856 : : +} 7857 : : + 7858 : 202 : +int Event_log::write_cache_raw(THD *thd, IO_CACHE *cache) 7859 : : +{ 7860 : : + DBUG_ENTER("Event_log::write_cache_raw"); 7861 : 202 : + mysql_mutex_assert_owner(&LOCK_log); 7862 : 202 : + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) 7863 : 0 : + DBUG_RETURN(ER_ERROR_ON_WRITE); 7864 : : + 7865 : 202 : + IO_CACHE *file= get_log_file(); 7866 : 202 : + IF_DBUG(size_t total= cache->end_of_file,); 7867 : : + do 7868 : : + { 7869 : 226 : + size_t read_len= cache->read_end - cache->read_pos; 7870 : 226 : + int res= my_b_safe_write(file, cache->read_pos, read_len); 7871 : 226 : + if (unlikely(res)) 7872 : 0 : + DBUG_RETURN(res); 7873 : 226 : + IF_DBUG(total-= read_len,); 7874 : 226 : + } while (my_b_fill(cache)); 7875 : 202 : + DBUG_ASSERT(total == 0); 7876 : 202 : + DBUG_RETURN(0); 7877 : : +} 7878 : : + 7879 : : /* 7880 : : Write the contents of a cache to the binary log. 7881 : : 7893 : : events prior to fill in the binlog cache. 7894 : : */ 7895 : : 7896 : 178871 : +int Event_log::write_cache(THD *thd, IO_CACHE *cache) 7897 : : { 7898 : : + DBUG_ENTER("Event_log::write_cache"); 7899 : : 7900 : 178871 : mysql_mutex_assert_owner(&LOCK_log); 7901 : 178871 : if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) 7904 : : size_t val; 7905 : 178871 : size_t end_log_pos_inc= 0; // each event processed adds BINLOG_CHECKSUM_LEN 2 t 7906 : 178871 : uchar header[LOG_EVENT_HEADER_LEN]; 7907 : 178871 : + CacheWriter writer(thd, get_log_file(), binlog_checksum_options, &crypto); 7908 : : 7909 : 178871 : if (crypto.scheme) 7910 : : { 7929 : : split. 7930 : : */ 7931 : : 7932 : 178871 : + group= (size_t)my_b_tell(get_log_file()); 7933 : 178871 : hdr_offs= carry= 0; 7934 : : 7935 : : do 12194 : : { 12195 : : binlog_cache_mngr *cache_mngr; 12196 : 390851 : if (opt_bin_log && 12197 : 91656 : + (cache_mngr= thd->binlog_get_cache_mngr())) 12198 : : { 12199 : 84337 : *out_file= cache_mngr->last_commit_pos_file; 12200 : 84337 : *out_pos= (ulonglong)(cache_mngr->last_commit_pos_offset); 12307 : : binlog_cache_mngr *cache_mngr; 12308 : : 12309 : 37665 : if (thd && opt_bin_log) 12310 : 11168 : + cache_mngr= thd->binlog_get_cache_mngr(); 12311 : : else 12312 : 26497 : cache_mngr= 0; 12313 : : 12432 : 812458 : IO_CACHE *wsrep_get_cache(THD * thd, bool is_transactional) 12433 : : { 12434 : 812458 : DBUG_ASSERT(binlog_hton->slot != HA_SLOT_UNDEF); 12435 : 812458 : + binlog_cache_mngr *cache_mngr = thd->binlog_get_cache_mngr(); 12436 : 812458 : if (cache_mngr) 12437 : 812452 : return cache_mngr->get_binlog_cache_log(is_transactional); 12438 : : 12448 : : /* 12449 : : todo: fix autocommit select to not call the caller 12450 : : */ 12451 : 202384 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 12452 : 202384 : if (cache_mngr) 12453 : : { 12454 : 34716 : cache_mngr->reset(false, true); 12466 : : { 12467 : : DBUG_ENTER("wsrep_thd_binlog_stmt_rollback"); 12468 : 72 : WSREP_DEBUG("wsrep_thd_binlog_stmt_rollback"); 12469 : 72 : + binlog_cache_mngr *const cache_mngr= thd->binlog_get_cache_mngr(); 12470 : 72 : if (cache_mngr) 12471 : : { 12472 : 68 : + MYSQL_BIN_LOG::remove_pending_rows_event(thd, &cache_mngr->trx_cache); 12473 : 68 : + thd->reset_binlog_for_next_statement(); 12474 : 68 : cache_mngr->stmt_cache.reset(); 12475 : : } 12476 : 72 : DBUG_VOID_RETURN; 12492 : : back a statement or a transaction. However, notifications do not happen 12493 : : if the binary log is set as read/write. 12494 : : */ 12495 : 37 : + binlog_cache_mngr *cache_mngr= thd->binlog_get_cache_mngr(); 12496 : : /* cache_mngr may be missing e.g. in mtr test ev51914.test */ 12497 : 37 : if (cache_mngr) 12498 : : { ===== File: sql/log.h ===== 326 : : bool strip_ext, char *buff); 327 : : virtual int generate_new_name(char *new_name, const char *log_name, 328 : : ulong next_log_number); 329 : 18990801 : + inline mysql_mutex_t* get_log_lock() { return &LOCK_log; } 330 : : protected: 331 : : /* LOCK_log is inited by init_pthread_objects() */ 332 : : mysql_mutex_t LOCK_log; 351 : : enum cache_type io_cache_type_arg); 352 : : }; 353 : : 354 : : +/** 355 : : + @struct Rows_event_factory 356 : : + 357 : : + Holds an event type code and a callback function to create it. 358 : : + Should be created by Rows_event_factory::get. 359 : : +*/ 360 : : +struct Rows_event_factory 361 : : +{ 362 : : + int type_code; 363 : : + 364 : : + Rows_log_event *(*create)(THD*, TABLE*, ulong, bool is_transactional); 365 : : + 366 : : + template 367 : 4194857 : + static Rows_event_factory get() 368 : : + { 369 : : + return { RowsEventT::TYPE_CODE, 370 : 4474530 : + [](THD* thd, TABLE* table, ulong flags, bool is_transactional) 371 : : + -> Rows_log_event* 372 : : + { 373 : 279673 : + return new RowsEventT(thd, table, flags, is_transactional); 374 : : + } 375 : 8389712 : + }; 376 : : + } 377 : : +}; 378 : : + 379 : : +class Event_log: public MYSQL_LOG 380 : : +{ 381 : : +protected: 382 : : + /* binlog encryption data */ 383 : : + struct Binlog_crypt_data crypto; 384 : : + 385 : : + mysql_mutex_t LOCK_binlog_end_pos; 386 : : + 387 : : + /** The instrumentation key to use for LOCK_binlog_end_pos. */ 388 : : + PSI_mutex_key m_key_LOCK_binlog_end_pos; 389 : : + /** The instrumentation key to use for opening the log file. */ 390 : : + PSI_file_key m_key_file_log, m_key_file_log_cache; 391 : : +public: 392 : : +#if !defined(MYSQL_CLIENT) 393 : : + Rows_log_event* 394 : : + prepare_pending_rows_event(THD *thd, TABLE* table, 395 : : + binlog_cache_data *cache_data, 396 : : + uint32 serv_id, size_t needed, 397 : : + bool is_transactional, 398 : : + Rows_event_factory event_factory); 399 : : +#endif 400 : : + int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event, 401 : : + binlog_cache_data *cache_data, 402 : : + bool is_transactional); 403 : : + void set_write_error(THD *thd, bool is_transactional); 404 : : + static bool check_write_error(THD *thd); 405 : : + int write_cache(THD *thd, IO_CACHE *cache); 406 : : + int write_cache_raw(THD *thd, IO_CACHE *cache); 407 : 0 : + char* get_name() { return name; } 408 : 42011 : + void cleanup() 409 : : + { 410 : 42011 : + if (inited) 411 : 42011 : + mysql_mutex_destroy(&LOCK_binlog_end_pos); 412 : : + 413 : 42011 : + MYSQL_LOG::cleanup(); 414 : 42011 : + } 415 : 93961 : + void init_pthread_objects() 416 : : + { 417 : 93961 : + MYSQL_LOG::init_pthread_objects(); 418 : : + 419 : 93967 : + mysql_mutex_init(m_key_LOCK_binlog_end_pos, &LOCK_binlog_end_pos, 420 : : + MY_MUTEX_INIT_SLOW); 421 : 93967 : + } 422 : : + 423 : : + bool open(enum cache_type io_cache_type_arg); 424 : 0 : + virtual IO_CACHE *get_log_file() { return &log_file; } 425 : : + 426 : : + longlong write_description_event(enum_binlog_checksum_alg checksum_alg, 427 : : + bool encrypt, bool dont_set_created, 428 : : + bool is_relay_log); 429 : : + 430 : : + bool write_event(Log_event *ev, binlog_cache_data *data, IO_CACHE *file); 431 : : +}; 432 : : + 433 : : +/** 434 : : + A single-reader, single-writer non-blocking layer for Event_log. 435 : : + Provides IO_CACHE for writing and IO_CACHE for reading. 436 : : + 437 : : + Writers use an overrided get_log_file version for their writes, while readers 438 : : + should use flip() to initiate reading. 439 : : + flip() swaps pointers to allow non-blocking reads. 440 : : + 441 : : + Writers can block other writers and a reader with a mutex, but a reader only 442 : : + swaps two pointers under a lock, so it won't block writers. 443 : : + 444 : : + TODO should be unnecessary after MDEV-24676 is done 445 : : + */ 446 : : +class Cache_flip_event_log: public Event_log { 447 : : + IO_CACHE alt_buf; 448 : : + IO_CACHE *current, *alt; 449 : : + std::atomic ref_count; 450 : : +public: 451 : : + 452 : 84161 : + Cache_flip_event_log() : Event_log(), alt_buf{}, 453 : 42081 : + current(&log_file), alt(&alt_buf), ref_count(1) {} 454 : 42081 : + bool open(enum cache_type io_cache_type_arg) 455 : : + { 456 : 42081 : + log_file.dir= mysql_tmpdir; 457 : 42074 : + alt_buf.dir= log_file.dir; 458 : 42074 : + bool res= Event_log::open(io_cache_type_arg); 459 : 42075 : + if (res) 460 : 0 : + return res; 461 : : + 462 : 42075 : + name= my_strdup(key_memory_MYSQL_LOG_name, "online-alter-binlog", 463 : : + MYF(MY_WME)); 464 : 42080 : + if (!name) 465 : 0 : + return false; 466 : : + 467 : 42080 : + res= init_io_cache(&alt_buf, -1, LOG_BIN_IO_SIZE, io_cache_type_arg, 0, 0, 468 : : + MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0; 469 : 42081 : + return res; 470 : : + } 471 : : + 472 : : + /** 473 : : + Swaps current and alt_log. Can be called only from the reader thread. 474 : : + @return a new IO_CACHE pointer to read from. 475 : : + */ 476 : 71570 : + IO_CACHE *flip() 477 : : + { 478 : 71570 : + IO_CACHE *tmp= current; 479 : 71570 : + reinit_io_cache(alt, WRITE_CACHE, 0, 0, 0); 480 : 71557 : + mysql_mutex_lock(get_log_lock()); 481 : 71564 : + reinit_io_cache(current, READ_CACHE, 0, 0, 0); 482 : 71569 : + current= alt; 483 : 71569 : + mysql_mutex_unlock(get_log_lock()); 484 : 71571 : + alt= tmp; 485 : : + 486 : 71571 : + return alt; 487 : : + } 488 : : + 489 : 202 : + IO_CACHE *get_log_file() override 490 : : + { 491 : 202 : + mysql_mutex_assert_owner(get_log_lock()); 492 : 202 : + return current; 493 : : + } 494 : : + 495 : 209 : + void acquire() 496 : : + { 497 : : + IF_DBUG(auto prev= ,) 498 : 209 : + ref_count.fetch_add(1); 499 : 209 : + DBUG_ASSERT(prev != 0); 500 : 209 : + } 501 : : + 502 : 42220 : + void release() 503 : : + { 504 : 42220 : + auto prev= ref_count.fetch_add(-1); 505 : : + 506 : 42220 : + if (prev == 1) 507 : : + { 508 : 42011 : + cleanup(); 509 : 42011 : + delete this; 510 : : + } 511 : 42217 : + } 512 : : + 513 : : +private: 514 : 42011 : + void cleanup() 515 : : + { 516 : 42011 : + close_cached_file(&log_file); 517 : 42010 : + close_cached_file(&alt_buf); 518 : 42011 : + Event_log::cleanup(); 519 : 42011 : + } 520 : : +}; 521 : : + 522 : : /* Tell the io thread if we can delay the master info sync. */ 523 : : #define SEMI_SYNC_SLAVE_DELAY_SYNC 1 524 : : /* Tell the io thread if the current event needs a ack. */ 588 : : #define BINLOG_COOKIE_IS_DUMMY(c) \ 589 : : ( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID ) 590 : : 591 : : + 592 : : class binlog_cache_mngr; 593 : : class binlog_cache_data; 594 : : struct rpl_gtid; 595 : : struct wait_for_commit; 596 : : 597 : : +class MYSQL_BIN_LOG: public TC_LOG, private Event_log 598 : : { 599 : : /** The instrumentation key to use for @ LOCK_index. */ 600 : : PSI_mutex_key m_key_LOCK_index; 602 : : PSI_cond_key m_key_relay_log_update; 603 : : /** The instrumentation key to use for @ COND_bin_log_updated */ 604 : : PSI_cond_key m_key_bin_log_update; 605 : : /** The instrumentation key to use for opening the log index file. */ 606 : : PSI_file_key m_key_file_log_index, m_key_file_log_index_cache; 607 : : 608 : : PSI_cond_key m_key_COND_queue_busy; 609 : : 610 : : struct group_commit_entry 611 : : { 658 : : 659 : : /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ 660 : : mysql_mutex_t LOCK_index; 661 : : mysql_mutex_t LOCK_xid_list; 662 : : mysql_cond_t COND_xid_list; 663 : : mysql_cond_t COND_relay_log_updated, COND_bin_log_updated; 707 : : ulonglong group_commit_trigger_count, group_commit_trigger_timeout; 708 : : ulonglong group_commit_trigger_lock_wait; 709 : : 710 : : /* pointer to the sync period variable, for binlog this will be 711 : : sync_binlog_period, for relay log this will be 712 : : sync_relay_log_period 727 : : new_file() is locking. new_file_without_locking() does not acquire 728 : : LOCK_log. 729 : : */ 730 : : int new_file_impl(); 731 : : void do_checkpoint_request(ulong binlog_id); 732 : : void purge(); 736 : : void trx_group_commit_leader(group_commit_entry *leader); 737 : : bool is_xidlist_idle_nolock(); 738 : : public: 739 : : + int new_file_without_locking(); 740 : : /* 741 : : A list of struct xid_count_per_binlog is used to keep track of how many 742 : : XIDs are in prepared, but not committed, state in each binlog. And how 872 : 51881 : } 873 : : #endif 874 : : 875 : 7283038 : + Event_log *as_event_log() 876 : : + { 877 : 7283038 : + return this; 878 : : + } 879 : : + 880 : : int open(const char *opt_name); 881 : : void close(); 882 : : virtual int generate_new_name(char *new_name, const char *log_name, 890 : : Format_description_log_event *fdle, bool do_xa); 891 : : int do_binlog_recovery(const char *opt_name, bool do_xa_recovery); 892 : : #if !defined(MYSQL_CLIENT) 893 : : + static int remove_pending_rows_event(THD *thd, binlog_cache_data *cache_data); 894 : : 895 : : #endif /* !defined(MYSQL_CLIENT) */ 896 : 14222 : void reset_bytes_written() 985 : : bool write_incident_already_locked(THD *thd); 986 : : bool write_incident(THD *thd); 987 : : void write_binlog_checkpoint_event_already_locked(const char *name, uint len); 988 : : + bool write_table_map(THD *thd, TABLE *table, bool with_annotate); 989 : : void start_union_events(THD *thd, query_id_t query_id_param); 990 : : void stop_union_events(THD *thd); 991 : : bool is_query_in_union(THD *thd, query_id_t query_id_param); 992 : : 993 : : + using Event_log::write_event; 994 : : + 995 : 500672 : bool write_event(Log_event *ev) { return write_event(ev, 0, &log_file); } 996 : : 997 : : bool write_event_buffer(uchar* buf,uint len); 1055 : : uint next_file_id(); 1056 : 0 : inline char* get_index_fname() { return index_file_name;} 1057 : 20598 : inline char* get_log_fname() { return log_file_name; } 1058 : : + using MYSQL_LOG::get_log_lock; 1059 : 106298 : inline mysql_cond_t* get_bin_log_cond() { return &COND_bin_log_updated; } 1060 : 436068 : inline IO_CACHE* get_log_file() { return &log_file; } 1061 : 1669 : inline uint64 get_reset_master_count() { return reset_master_count; } 1336 : : void make_default_log_name(char **out, const char* log_ext, bool once); 1337 : : void binlog_reset_cache(THD *thd); 1338 : : bool write_annotated_row(THD *thd); 1339 : : +int binlog_flush_pending_rows_event(THD *thd, bool stmt_end, 1340 : : + bool is_transactional, 1341 : : + Event_log *bin_log, 1342 : : + binlog_cache_data *cache_data); 1343 : : +Rows_log_event* binlog_get_pending_rows_event(binlog_cache_mngr *cache_mngr, 1344 : : + bool use_trans_cache); 1345 : : +int binlog_log_row_online_alter(TABLE* table, const uchar *before_record, 1346 : : + const uchar *after_record, Log_func *log_func); 1347 : : +online_alter_cache_data *online_alter_binlog_get_cache_data(THD *thd, TABLE *table); 1348 : : +binlog_cache_data* binlog_get_cache_data(binlog_cache_mngr *cache_mngr, 1349 : : + bool use_trans_cache); 1350 : : 1351 : : extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; 1352 : : extern handlerton *binlog_hton; 1439 : : bool write_bin_log_start_alter(THD *thd, bool& partial_alter, 1440 : : uint64 start_alter_id, bool log_if_exists); 1441 : : 1442 : : +int online_alter_savepoint_set(THD *thd, LEX_CSTRING name); 1443 : : +int online_alter_savepoint_rollback(THD *thd, LEX_CSTRING name); 1444 : : 1445 : : #endif /* LOG_H */ ===== File: sql/log_event.cc ===== 719 : 1217619 : Log_event::Log_event(const uchar *buf, 720 : 1217619 : const Format_description_log_event* description_event) 721 : 1217619 : :temp_buf(0), exec_time(0), cache_type(Log_event::EVENT_INVALID_CACHE), 722 : : +#ifndef MYSQL_CLIENT 723 : 1167827 : + slave_exec_mode(SLAVE_EXEC_MODE_STRICT), 724 : : +#endif 725 : 1217619 : checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF) 726 : : { 727 : : #ifndef MYSQL_CLIENT 764 : : 765 : 2364012 : int Log_event::read_log_event(IO_CACHE* file, String* packet, 766 : : const Format_description_log_event *fdle, 767 : : + enum enum_binlog_checksum_alg checksum_alg_arg, 768 : : + size_t max_allowed_packet) 769 : : { 770 : : ulong data_len; 771 : 2364012 : char buf[LOG_EVENT_MINIMAL_HEADER_LEN]; 772 : 2364016 : uchar ev_offset= packet->length(); 773 : : + 774 : : DBUG_ENTER("Log_event::read_log_event(IO_CACHE*,String*...)"); 775 : : 776 : 2363994 : if (my_b_read(file, (uchar*) buf, sizeof(buf))) 881 : : 882 : 1265894 : Log_event* Log_event::read_log_event(IO_CACHE* file, 883 : : const Format_description_log_event *fdle, 884 : : + my_bool crc_check, 885 : : + size_t max_allowed_packet) 886 : : { 887 : : DBUG_ENTER("Log_event::read_log_event(IO_CACHE*,Format_description_log_event*...)"); 888 : 1265894 : DBUG_ASSERT(fdle != 0); 890 : 1265889 : const char *error= 0; 891 : 1265890 : Log_event *res= 0; 892 : : 893 : 1265890 : + switch (read_log_event(file, &event, fdle, BINLOG_CHECKSUM_ALG_OFF, 894 : : + max_allowed_packet)) 895 : : { 896 : 1089200 : case 0: 897 : 1089200 : break; 2957 : : const Format_description_log_event 2958 : 165514 : *description_event) 2959 : : : Log_event(buf, description_event), 2960 : : #ifndef MYSQL_CLIENT 2961 : 156925 : m_table(NULL), 2962 : : #endif 2963 : 165514 : m_table_id(0), m_rows_buf(0), m_rows_cur(0), m_rows_end(0), 2964 : 165514 : + m_row_count(0), m_extra_row_data(0) 2965 : : #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) 2966 : 156925 : , m_curr_row(NULL), m_curr_row_end(NULL), 2967 : 156925 : m_key(NULL), m_key_info(NULL), m_key_nr(0), 2968 : 156925 : + m_usable_key_parts(0), master_had_triggers(0) 2969 : : #endif 2970 : : { 2971 : : DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)"); 2972 : 165514 : uint8 const common_header_len= description_event->common_header_len; 2973 : 165514 : Log_event_type event_type= (Log_event_type)(uchar)buf[EVENT_TYPE_OFFSET]; 2974 : 165514 : m_type= event_type; 2975 : 165514 : + m_cols_ai.bitmap= 0; // Set to invalid, so it can be processed in is_valid(). 2976 : : 2977 : 165514 : uint8 const post_header_len= description_event->post_header_len[event_type-1]; 2978 : : 2979 : 165514 : if (event_len < (uint)(common_header_len + post_header_len)) 2980 : 0 : DBUG_VOID_RETURN; 2981 : : 2982 : : DBUG_PRINT("enter",("event_len: %u common_header_len: %d " 2983 : : "post_header_len: %d", 3086 : 0 : DBUG_VOID_RETURN; 3087 : : } 3088 : : 3089 : 165513 : if (LOG_EVENT_IS_UPDATE_ROW(event_type)) 3090 : : { 3091 : : DBUG_PRINT("debug", ("Reading from %p", ptr_after_width)); 3104 : : } 3105 : : else 3106 : : { 3107 : 0 : + DBUG_ASSERT(m_cols_ai.bitmap == NULL); 3108 : 0 : DBUG_VOID_RETURN; 3109 : : } 3110 : : } 3111 : : + else 3112 : : + { 3113 : 149928 : + m_cols_ai= m_cols; /* Safety */ 3114 : : +#ifdef DBUG_OFF 3115 : : + /* 3116 : : + m_cols_ai should only be usable for update events. Make sure nobody 3117 : : + successfully manipulates it in debug builds. 3118 : : + */ 3119 : : + m_cols_ai.bitmap= (my_bitmap_map*)1; 3120 : : +#endif 3121 : : + } 3122 : : 3123 : 165511 : const uchar* const ptr_rows_data= (const uchar*) ptr_after_width; 3124 : : ===== File: sql/log_event.h ===== 54 : : #include "rpl_record.h" 55 : : #include "rpl_reporting.h" 56 : : #include "sql_class.h" /* THD */ 57 : : +#else 58 : : +typedef ulong enum_slave_exec_mode; 59 : : #endif 60 : : 61 : : #include "rpl_gtid.h" 1251 : : event's type, and its content is distributed in the event-specific fields. 1252 : : */ 1253 : : uchar *temp_buf; 1254 : : 1255 : : /* 1256 : : Timestamp on the master(for debugging and replication of 1280 : : */ 1281 : : uint16 flags; 1282 : : 1283 : : + /** 1284 : : + true <=> this event 'owns' temp_buf and should call my_free() when done 1285 : : + with it 1286 : : + */ 1287 : : + bool event_owns_temp_buf; 1288 : : + 1289 : : enum_event_cache_type cache_type; 1290 : : 1291 : : /** 1292 : : A storage to cache the global system variable's value. 1293 : : Handling of a separate event will be governed its member. 1294 : : */ 1295 : : + enum_slave_exec_mode slave_exec_mode; 1296 : : + 1297 : : + /** 1298 : : + The value is set by caller of FD constructor and 1299 : : + Log_event::write_header() for the rest. 1300 : : + In the FD case it's propagated into the last byte 1301 : : + of post_header_len[] at FD::write(). 1302 : : + On the slave side the value is assigned from post_header_len[last] 1303 : : + of the last seen FD event. 1304 : : + */ 1305 : : + enum enum_binlog_checksum_alg checksum_alg; 1306 : : 1307 : : Log_event_writer *writer; 1308 : : 1375 : : #endif 1376 : : #endif 1377 : : 1378 : : +private: 1379 : 2256413 : + static size_t get_max_packet() 1380 : : + { 1381 : 2256413 : + size_t max_packet= ~0UL; 1382 : : + #if !defined(MYSQL_CLIENT) 1383 : 2221689 : + THD *thd=current_thd; 1384 : 2221665 : + if (thd) 1385 : 2195184 : + max_packet= thd->slave_thread ? slave_max_allowed_packet 1386 : : + : thd->variables.max_allowed_packet; 1387 : : + #endif 1388 : 2256389 : + return max_packet; 1389 : : + } 1390 : : +public: 1391 : : + 1392 : : /* 1393 : : read_log_event() functions read an event from a binlog or relay 1394 : : log; used by SHOW BINLOG EVENTS, the binlog_dump thread on the 1403 : : static Log_event* read_log_event(IO_CACHE* file, 1404 : : const Format_description_log_event 1405 : : *description_event, 1406 : : + my_bool crc_check, 1407 : : + size_t max_allowed_packet); 1408 : 1158299 : + static Log_event* read_log_event(IO_CACHE* file, 1409 : : + const Format_description_log_event 1410 : : + *description_event, 1411 : : + my_bool crc_check) 1412 : : + { 1413 : 1158299 : + return read_log_event(file, description_event, crc_check, get_max_packet()); 1414 : : + } 1415 : : 1416 : : /** 1417 : : Reads an event from a binlog or relay log. Used by the dump thread 1438 : : */ 1439 : : static int read_log_event(IO_CACHE* file, String* packet, 1440 : : const Format_description_log_event *fdle, 1441 : : + enum enum_binlog_checksum_alg checksum_alg_arg, 1442 : : + size_t max_allowed_packet); 1443 : : + 1444 : 1098121 : + static int read_log_event(IO_CACHE* file, String* packet, 1445 : : + const Format_description_log_event *fdle, 1446 : : + enum enum_binlog_checksum_alg checksum_alg) 1447 : : + { 1448 : 1098121 : + return read_log_event(file, packet, fdle, checksum_alg, get_max_packet()); 1449 : : + } 1450 : : 1451 : 1632476 : static void *operator new(size_t size) 1452 : : { 1566 : : 1567 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 1568 : : 1569 : : + /** 1570 : : + Increase or decrease the rows inserted during ALTER TABLE based on the event 1571 : : + type. 1572 : : + */ 1573 : 35944 : + virtual void online_alter_update_row_count(ha_rows *) const {} 1574 : : + 1575 : : /** 1576 : : Apply the event to the database. 1577 : : 3790 : : bool m_used_query_txt; 3791 : : }; 3792 : : 3793 : : +class table_def; 3794 : : + 3795 : : /** 3796 : : @class Table_map_log_event 3797 : : 4443 : : virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info); 4444 : : #endif 4445 : : 4446 : : + table_def get_table_def(); 4447 : : 4448 : : private: 4449 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 4587 : : typedef uint16 flag_set; 4588 : : 4589 : : /* Special constants representing sets of flags */ 4590 : : + enum 4591 : : { 4592 : : RLE_NO_FLAGS = 0U 4593 : : }; 4601 : : 4602 : 6754612 : Log_event_type get_type_code() { return m_type; } /* Specific type (_V1 etc) */ 4603 : 279198 : enum_logged_status logged_status() { return LOGGED_ROW_EVENT; } 4604 : : + virtual Log_event_type get_general_type_code() const = 0; /* General rows op type, no version */ 4605 : : 4606 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 4607 : : virtual void pack_info(Protocol *protocol); 4629 : : #ifdef MYSQL_SERVER 4630 : 4791728 : int add_row_data(uchar *data, size_t length) 4631 : : { 4632 : 4791728 : + return do_add_row_data(data,length); 4633 : : } 4634 : : #endif 4635 : : 4707 : : } 4708 : 110980 : bool is_part_of_group() { return get_flags(STMT_END_F) != 0; } 4709 : : 4710 : : const uchar* get_extra_row_data() const { return m_extra_row_data; } 4711 : : 4712 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 4713 : : + virtual uint8 get_trg_event_map() const = 0; 4714 : : 4715 : 32801 : inline bool do_invoke_trigger() 4716 : : { 4746 : : #endif 4747 : : ulonglong m_table_id; /* Table ID */ 4748 : : MY_BITMAP m_cols; /* Bitmap denoting columns available */ 4749 : : + uint m_width; /* The width of the columns bitmap */ 4750 : : /* 4751 : : Bitmap for columns available in the after image, if present. These 4752 : : fields are only available for Update_rows events. Observe that the 4773 : : 4774 : : Log_event_type m_type; /* Actual event type */ 4775 : : 4776 : : + bool m_vers_from_plain; 4777 : : + 4778 : : + uint m_row_count; /* The number of rows added to the event */ 4779 : : + 4780 : : uchar *m_extra_row_data; /* Pointer to extra row data if any */ 4781 : : /* If non null, first byte is length */ 4782 : : 4783 : : 4784 : : /* helper functions */ 4785 : : 4786 : : + 4787 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 4788 : : const uchar *m_curr_row; /* Start of the row being processed */ 4789 : : const uchar *m_curr_row_end; /* One-after the end of the current row */ 4790 : : uchar *m_key; /* Buffer to keep key value during searches */ 4791 : : KEY *m_key_info; /* Pointer to KEY info for m_key_nr */ 4792 : : uint m_key_nr; /* Key number */ 4793 : : + uint m_usable_key_parts; /* A number of key_parts suited to lookup */ 4794 : : bool master_had_triggers; /* set after tables opening */ 4795 : : 4796 : : /* 4838 : : friend class Rows_log_event; 4839 : : }; 4840 : : 4841 : : + int find_key(const rpl_group_info *); // Find a best key to use in find_row() 4842 : : + uint find_key_parts(const KEY *key) const; 4843 : : + bool use_pk_position() const; 4844 : : int find_row(rpl_group_info *); 4845 : : int write_row(rpl_group_info *, const bool); 4846 : : int update_sequence(); 4853 : : 4854 : 301799 : ASSERT_OR_RETURN_ERROR(m_curr_row <= m_rows_end, HA_ERR_CORRUPT_EVENT); 4855 : 603598 : return ::unpack_row(rgi, m_table, m_width, m_curr_row, cols, 4856 : 301799 : + &m_curr_row_end, &m_master_reclength, m_rows_end); 4857 : : } 4858 : : 4859 : : // Unpack the current row into m_table->record[0] 4863 : : 4864 : 2388582 : ASSERT_OR_RETURN_ERROR(m_curr_row <= m_rows_end, HA_ERR_CORRUPT_EVENT); 4865 : 4777142 : return ::unpack_row(rgi, m_table, m_width, m_curr_row, &m_cols, 4866 : 2388582 : + &m_curr_row_end, &m_master_reclength, m_rows_end); 4867 : : } 4868 : : + bool process_triggers(trg_event_type event, trg_action_time_type time_type, 4869 : : bool old_row_is_record1); 4870 : : 4871 : : /** 4890 : : virtual int do_update_pos(rpl_group_info *rgi); 4891 : : virtual enum_skip_reason do_shall_skip(rpl_group_info *rgi); 4892 : : 4893 : : + /** 4894 : : + @brief Primitive to prepare for a sequence of row executions. 4895 : : 4896 : : DESCRIPTION 4897 : : 4901 : : space for any buffers that are needed for the two member 4902 : : functions mentioned above. 4903 : : 4904 : : + @return 4905 : : The member function will return 0 if all went OK, or a non-zero 4906 : : error code otherwise. 4907 : : */ 4908 : : + virtual 4909 : : + int do_before_row_operations(const rpl_group_info *) = 0; 4910 : : 4911 : : + /** 4912 : : + @brief Primitive to clean up after a sequence of row executions. 4913 : : 4914 : : DESCRIPTION 4915 : : 4922 : : function is successful, it should return the error code given in the argument. 4923 : : */ 4924 : : virtual 4925 : : + int do_after_row_operations(int error) = 0; 4926 : : 4927 : : + /** 4928 : : + @brief Primitive to do the actual execution necessary for a row. 4929 : : 4930 : : DESCRIPTION 4931 : : The member function will do the actual execution needed to handle a row. 4933 : : m_curr_row_end should point at the next row (one byte after the end 4934 : : of the current row). 4935 : : 4936 : : + @return 4937 : : 0 if execution succeeded, 1 if execution failed. 4938 : : 4939 : : */ 4953 : : class Write_rows_log_event : public Rows_log_event 4954 : : { 4955 : : public: 4956 : : + /* Support interface to THD::binlog_prepare_pending_rows_event */ 4957 : : + static constexpr Log_event_type TYPE_CODE = WRITE_ROWS_EVENT; 4958 : : 4959 : : #if defined(MYSQL_SERVER) 4960 : : Write_rows_log_event(THD*, TABLE*, ulong table_id, 4966 : : #endif 4967 : : #if defined(MYSQL_SERVER) 4968 : 3490654 : static bool binlog_row_logging_function(THD *thd, TABLE *table, 4969 : : + Event_log *bin_log, 4970 : : + binlog_cache_data *cache_data, 4971 : : + bool is_transactional, ulong, 4972 : : const uchar *before_record 4973 : : __attribute__((unused)), 4974 : : const uchar *after_record) 4975 : : { 4976 : 3490654 : DBUG_ASSERT(!table->versioned(VERS_TRX_ID)); 4977 : 3490655 : + return thd->binlog_write_row(table, bin_log, cache_data, is_transactional, 4978 : 3490654 : + after_record); 4979 : : } 4980 : : #endif 4981 : : 4982 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 4983 : : + uint8 get_trg_event_map() const override; 4984 : : + 4985 : 47 : + void online_alter_update_row_count(ha_rows *rows) const override 4986 : : + { 4987 : 47 : + *rows += m_row_count; 4988 : 47 : + } 4989 : : #endif 4990 : : 4991 : : private: 4992 : 11226228 : + Log_event_type get_general_type_code() const override { return TYPE_CODE; } 4993 : : 4994 : : #ifdef MYSQL_CLIENT 4995 : : + bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; 4996 : : #endif 4997 : : 4998 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 4999 : : + int do_before_row_operations(const rpl_group_info *) override; 5000 : : + int do_after_row_operations(int) override; 5001 : : + int do_exec_row(rpl_group_info *) override; 5002 : : #endif 5003 : : }; 5004 : : 5016 : : #endif 5017 : : private: 5018 : : #if defined(MYSQL_CLIENT) 5019 : : + bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; 5020 : : #endif 5021 : : }; 5022 : : 5035 : : class Update_rows_log_event : public Rows_log_event 5036 : : { 5037 : : public: 5038 : : + /* Support interface to THD::binlog_prepare_pending_rows_event */ 5039 : : + static constexpr Log_event_type TYPE_CODE = UPDATE_ROWS_EVENT; 5040 : : 5041 : : #ifdef MYSQL_SERVER 5042 : : Update_rows_log_event(THD*, TABLE*, ulong table_id, 5045 : : void init(MY_BITMAP const *cols); 5046 : : #endif 5047 : : 5048 : : + ~Update_rows_log_event() override; 5049 : : 5050 : : #ifdef HAVE_REPLICATION 5051 : : Update_rows_log_event(const uchar *buf, uint event_len, 5054 : : 5055 : : #ifdef MYSQL_SERVER 5056 : 596874 : static bool binlog_row_logging_function(THD *thd, TABLE *table, 5057 : : + Event_log *bin_log, 5058 : : + binlog_cache_data *cache_data, 5059 : : bool is_transactional, 5060 : : + ulong row_image, 5061 : : const uchar *before_record, 5062 : : const uchar *after_record) 5063 : : { 5064 : 596874 : DBUG_ASSERT(!table->versioned(VERS_TRX_ID)); 5065 : 596874 : + return thd->binlog_update_row(table, bin_log, cache_data, is_transactional, 5066 : : + (enum_binlog_row_image)row_image, 5067 : 596874 : before_record, after_record); 5068 : : } 5069 : : #endif 5070 : : 5071 : 597852 : + bool is_valid() const override 5072 : : { 5073 : 597852 : return Rows_log_event::is_valid() && m_cols_ai.bitmap; 5074 : : } 5075 : : 5076 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 5077 : : + uint8 get_trg_event_map() const override; 5078 : : #endif 5079 : : 5080 : : protected: 5081 : 1838838 : + Log_event_type get_general_type_code() const override { return TYPE_CODE; } 5082 : : 5083 : : #ifdef MYSQL_CLIENT 5084 : : + bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; 5085 : : #endif 5086 : : 5087 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 5088 : : + int do_before_row_operations(const rpl_group_info *) override; 5089 : : + int do_after_row_operations(int) override; 5090 : : + int do_exec_row(rpl_group_info *) override; 5091 : : #endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */ 5092 : : }; 5093 : : 5105 : : #endif 5106 : : private: 5107 : : #if defined(MYSQL_CLIENT) 5108 : : + bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; 5109 : : #endif 5110 : : }; 5111 : : 5132 : : class Delete_rows_log_event : public Rows_log_event 5133 : : { 5134 : : public: 5135 : : + /* Support interface to THD::binlog_prepare_pending_rows_event */ 5136 : : + static constexpr Log_event_type TYPE_CODE = DELETE_ROWS_EVENT; 5137 : : 5138 : : #ifdef MYSQL_SERVER 5139 : : Delete_rows_log_event(THD*, TABLE*, ulong, bool is_transactional); 5144 : : #endif 5145 : : #ifdef MYSQL_SERVER 5146 : 107330 : static bool binlog_row_logging_function(THD *thd, TABLE *table, 5147 : : + Event_log *bin_log, 5148 : : + binlog_cache_data *cache_data, 5149 : : bool is_transactional, 5150 : : + ulong row_image, 5151 : : const uchar *before_record, 5152 : : const uchar *after_record 5153 : : __attribute__((unused))) 5154 : : { 5155 : 107330 : DBUG_ASSERT(!table->versioned(VERS_TRX_ID)); 5156 : 107330 : + return thd->binlog_delete_row(table, bin_log, cache_data, is_transactional, 5157 : : + (enum_binlog_row_image)row_image, 5158 : 107330 : before_record); 5159 : : } 5160 : : #endif 5161 : : 5162 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 5163 : : + uint8 get_trg_event_map() const override; 5164 : : + 5165 : 34 : + void online_alter_update_row_count(ha_rows *rows) const override 5166 : : + { 5167 : 34 : + *rows -= m_row_count; 5168 : 34 : + } 5169 : : #endif 5170 : : 5171 : : protected: 5172 : 343219 : + Log_event_type get_general_type_code() const override { return TYPE_CODE; } 5173 : : 5174 : : #ifdef MYSQL_CLIENT 5175 : : + bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; 5176 : : #endif 5177 : : 5178 : : #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) 5179 : : + int do_before_row_operations(const rpl_group_info *const) override; 5180 : : + int do_after_row_operations(int) override; 5181 : : + int do_exec_row(rpl_group_info *) override; 5182 : : #endif 5183 : : }; 5184 : : 5195 : : #endif 5196 : : private: 5197 : : #if defined(MYSQL_CLIENT) 5198 : : + bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; 5199 : : #endif 5200 : : }; 5201 : : ===== File: sql/log_event_server.cc ===== 53 : : #include "wsrep_mysqld.h" 54 : : #include "sql_insert.h" 55 : : #include "sql_table.h" 56 : : +#include 57 : : 58 : : #include 59 : : #include "rpl_utility.h" 544 : : **************************************************************************/ 545 : : 546 : 1707759 : Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) 547 : 1707759 : + :log_pos(0), temp_buf(0), exec_time(0), 548 : 1707759 : + slave_exec_mode(SLAVE_EXEC_MODE_STRICT), 549 : 1707759 : + checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF), thd(thd_arg) 550 : : { 551 : 1707759 : server_id= thd->variables.server_id; 552 : 1707759 : when= thd->start_time; 570 : : 571 : 274398 : Log_event::Log_event() 572 : 274398 : :temp_buf(0), exec_time(0), flags(0), cache_type(EVENT_INVALID_CACHE), 573 : 274398 : + slave_exec_mode(SLAVE_EXEC_MODE_STRICT), 574 : 274398 : + checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF), thd(0) 575 : : { 576 : 274398 : server_id= global_system_variables.server_id; 577 : : /* 4585 : : MY_BITMAP const *cols, bool is_transactional, 4586 : 279672 : Log_event_type event_type) 4587 : : : Log_event(thd_arg, 0, is_transactional), 4588 : 279673 : m_table(tbl_arg), 4589 : 279673 : m_table_id(tid), 4590 : 279673 : m_width(tbl_arg ? tbl_arg->s->fields : 1), 4591 : 279673 : m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0), 4592 : 279673 : + m_type(event_type), m_row_count(0), m_extra_row_data(0) 4593 : : #ifdef HAVE_REPLICATION 4594 : 279673 : , m_curr_row(NULL), m_curr_row_end(NULL), 4595 : 279673 : m_key(NULL), m_key_info(NULL), m_key_nr(0), 4743 : : 4744 : 142460 : int Rows_log_event::do_apply_event(rpl_group_info *rgi) 4745 : : { 4746 : 142460 : + DBUG_ASSERT(rgi); 4747 : 142460 : Relay_log_info const *rli= rgi->rli; 4748 : : TABLE* table; 4749 : : DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)"); 4784 : 142456 : thd->set_query_timer(); 4785 : : 4786 : : /* 4787 : : + If there are no tables open, this must be the first row event seen 4788 : : + after the table map events. We should then open and lock all tables 4789 : : + used in the transaction and proceed with execution of the actual event. 4790 : : */ 4791 : 142458 : + if (!thd->open_tables) 4792 : : { 4793 : : /* 4794 : : Lock_tables() reads the contents of thd->lex, so they must be 5029 : : } 5030 : : } 5031 : : 5032 : : /* 5033 : : Moved invalidation right before the call to rows_event_stmt_cleanup(), 5034 : : to avoid query cache being polluted with stale entries, 5035 : : + Query cache is not invalidated on wsrep applier here 5036 : : */ 5037 : 132919 : if (!(WSREP(thd) && wsrep_thd_is_applying(thd))) 5038 : 107101 : query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock); 5039 : : } 5040 : : 5041 : 141702 : table= m_table= rgi->m_table_map.get_table(m_table_id); 5060 : 141696 : if (m_width == table->s->fields && bitmap_is_set_all(&m_cols)) 5061 : 139599 : set_flags(COMPLETE_ROWS_F); 5062 : : 5063 : 141692 : + Rpl_table_data rpl_data= *(RPL_TABLE_LIST*)table->pos_in_table_list; 5064 : : + 5065 : : /* 5066 : : Set tables write and read sets. 5067 : : 5075 : 556165 : DBUG_PRINT_BITSET("debug", "Setting table's read_set from: %s", &m_cols); 5076 : : 5077 : 141697 : bitmap_set_all(table->read_set); 5078 : 141697 : + bitmap_set_all(table->write_set); 5079 : 141697 : + table->rpl_write_set= table->write_set; 5080 : : + 5081 : 141697 : + if (rpl_data.copy_fields) 5082 : : + /* always full rows, all bits set */; 5083 : : + else 5084 : 141457 : + if (get_general_type_code() == WRITE_ROWS_EVENT) 5085 : 114209 : + bitmap_copy(table->write_set, &m_cols); // for sequences 5086 : : + else // If online alter, leave all columns set (i.e. skip intersects) 5087 : 27251 : + if (!thd->slave_thread || !table->s->online_alter_binlog) 5088 : : { 5089 : 27248 : bitmap_intersect(table->read_set,&m_cols); 5090 : 27250 : + if (get_general_type_code() == UPDATE_ROWS_EVENT) 5091 : 13322 : + bitmap_intersect(table->write_set, &m_cols_ai); 5092 : 27252 : table->mark_columns_per_binlog_row_image(); 5093 : 27249 : if (table->vfield) 5094 : 1368 : table->mark_virtual_columns_for_write(0); 5095 : : } 5096 : : 5097 : 141690 : if (table->versioned()) 5098 : : { 5099 : 281 : bitmap_set_bit(table->write_set, table->s->vers.start_fieldno); 5100 : 281 : bitmap_set_bit(table->write_set, table->s->vers.end_fieldno); 5101 : : } 5102 : : 5103 : 141699 : + if (!rpl_data.is_online_alter()) 5104 : 141458 : + this->slave_exec_mode= (enum_slave_exec_mode)slave_exec_mode_options; 5105 : : 5106 : : // Do event specific preparations 5107 : 141698 : + error= do_before_row_operations(rgi); 5108 : : 5109 : : /* 5110 : : Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc 5116 : : */ 5117 : 141701 : sql_mode_t saved_sql_mode= thd->variables.sql_mode; 5118 : 141701 : if (!is_auto_inc_in_extra_columns()) 5119 : 141705 : + thd->variables.sql_mode= (rpl_data.copy_fields ? saved_sql_mode : 0) 5120 : 141705 : + | MODE_NO_AUTO_VALUE_ON_ZERO; 5121 : : 5122 : : // row processing loop 5123 : : 5130 : 141708 : THD_STAGE_INFO(thd, stage_executing); 5131 : : do 5132 : : { 5133 : 2388578 : + DBUG_ASSERT(table->in_use); 5134 : : 5135 : 2388578 : error= do_exec_row(rgi); 5136 : : 5138 : : DBUG_PRINT("info", ("error: %s", HA_ERR(error))); 5139 : 2388587 : DBUG_ASSERT(error != HA_ERR_RECORD_DELETED); 5140 : : 5141 : 2388587 : if (unlikely(error)) 5142 : : { 5143 : 335 : int actual_error= convert_handler_error(error, thd, table); 5147 : 314 : ignored_error_code(actual_error) : 0); 5148 : : 5149 : : #ifdef WITH_WSREP 5150 : 338 : + if (WSREP(thd) && wsrep_thd_is_applying(thd) && 5151 : 4 : + wsrep_ignored_error_code(this, actual_error)) 5152 : : { 5153 : 1 : idempotent_error= true; 5154 : 1 : thd->wsrep_has_ignored_error= true; 5187 : 815141 : thd->transaction->stmt.modified_non_trans_table= TRUE; 5188 : 2388582 : if (likely(error == 0)) 5189 : : { 5190 : 2388273 : + m_row_count++; 5191 : 2388273 : error= thd->killed_errno(); 5192 : 2388272 : if (error && !thd->is_error()) 5193 : 188 : my_error(error, MYF(0)); 5211 : : const_cast(rli)->abort_slave= 1;); 5212 : : } 5213 : : 5214 : 142205 : + if (unlikely(error= do_after_row_operations(error)) && 5215 : 496 : ignored_error_code(convert_handler_error(error, thd, table))) 5216 : : { 5217 : : 5222 : 0 : thd->clear_error(1); 5223 : 0 : error= 0; 5224 : : } 5225 : : 5226 : 141707 : + if (unlikely(error)) 5227 : : + { 5228 : 497 : + if (rpl_data.is_online_alter()) 5229 : 12 : + goto err; 5230 : 485 : + slave_rows_error_report(ERROR_LEVEL, error, rgi, thd, table, 5231 : : + get_type_str(), 5232 : 485 : + RPL_LOG_NAME, log_pos); 5233 : : + /* 5234 : : + @todo We should probably not call 5235 : : + reset_current_stmt_binlog_format_row() from here. 5236 : : 5237 : : + Note: this applies to log_event_old.cc too. 5238 : : + /Sven 5239 : : + */ 5240 : 485 : + thd->reset_current_stmt_binlog_format_row(); 5241 : 485 : + thd->is_slave_error= 1; 5242 : : + /* remove trigger's tables */ 5243 : 485 : + goto err; 5244 : : + } 5245 : 141707 : + } // if (table) 5246 : : 5247 : 141262 : + DBUG_ASSERT(error == 0); 5248 : : 5249 : : + /* 5250 : : + Remove trigger's tables. In case of ONLINE ALTER TABLE, event doesn't own 5251 : : + the table (hence, no tables are locked), and therefore no cleanup should be 5252 : : + done after each event. 5253 : : + */ 5254 : 141262 : + if (rgi->tables_to_lock_count) 5255 : 140986 : + restore_empty_query_table_list(thd->lex); 5256 : : 5257 : 141262 : if (WSREP(thd) && wsrep_thd_is_applying(thd)) 5258 : 28570 : + query_cache_invalidate_locked_for_write(thd, rgi->tables_to_lock); 5259 : : 5260 : 141262 : if (get_flags(STMT_END_F)) 5261 : : { 5271 : 141262 : DBUG_RETURN(error); 5272 : : 5273 : 1191 : err: 5274 : 1191 : + if (rgi->tables_to_lock_count) 5275 : : + { 5276 : 1188 : + restore_empty_query_table_list(thd->lex); 5277 : 1188 : + rgi->slave_close_thread_tables(thd); 5278 : : + } 5279 : 1191 : thd->reset_query_timer(); 5280 : 1200 : DBUG_RETURN(error); 5281 : : } 5843 : 134783 : DBUG_RETURN(res); 5844 : : } 5845 : : 5846 : 170585 : +table_def Table_map_log_event::get_table_def() 5847 : : +{ 5848 : : + return table_def(m_coltype, m_colcnt, 5849 : 170585 : + m_field_metadata, m_field_metadata_size, 5850 : 170585 : + m_null_bits, m_flags); 5851 : : +} 5852 : : + 5853 : 134787 : int Table_map_log_event::do_apply_event(rpl_group_info *rgi) 5854 : : { 5855 : 134787 : RPL_TABLE_LIST *table_list; 5888 : 134783 : LEX_CSTRING tmp_db_name= {db_mem, db_mem_length }; 5889 : 134786 : LEX_CSTRING tmp_tbl_name= {tname_mem, tname_mem_length }; 5890 : : 5891 : : + /* 5892 : : + The memory allocated by the table_def structure (i.e., not the 5893 : : + memory allocated *for* the table_def structure) is released 5894 : : + inside rpl_group_info::clear_tables_to_lock() by calling the 5895 : : + table_def destructor explicitly. 5896 : : + */ 5897 : 0 : + new(table_list) RPL_TABLE_LIST(&tmp_db_name, &tmp_tbl_name, TL_WRITE, 5898 : 269574 : + get_table_def(), 5899 : 269573 : + m_flags & TM_BIT_HAS_TRIGGERS_F); 5900 : : + 5901 : 134784 : + table_list->table_id= DBUG_IF("inject_tblmap_same_id_maps_diff_table") ? 5902 : : + 0: m_table_id; 5903 : 134785 : table_list->required_type= TABLE_TYPE_NORMAL; 5904 : 134785 : + table_list->open_type= OT_BASE_ONLY; 5905 : 134785 : + DBUG_ASSERT(table_list->updating); 5906 : : 5907 : : DBUG_PRINT("debug", ("table: %s is mapped to %llu", 5908 : : table_list->table_name.str, 5909 : : table_list->table_id)); 5910 : : + DBUG_PRINT("debug", ("table->master_had_triggers=%d", 5911 : : (int)table_list->master_had_triggers)); 5912 : : 5913 : 134785 : enum_tbl_map_status tblmap_status= check_table_map(rgi, table_list); 5915 : : { 5916 : 134651 : DBUG_ASSERT(thd->lex->query_tables != table_list); 5917 : : 5918 : : /* 5919 : : We record in the slave's information that the table should be 5920 : : locked by linking the table into the list of tables to lock. 5959 : : execute in a user session 5960 : : */ 5961 : 1 : my_error(ER_SLAVE_FATAL_ERROR, MYF(0), buf); 5962 : : + } 5963 : : + 5964 : 130 : + table_list->~RPL_TABLE_LIST(); 5965 : 129 : my_free(memory); 5966 : : } 5967 : : 6468 : : 6469 : : #if defined(HAVE_REPLICATION) 6470 : : int 6471 : 114261 : +Write_rows_log_event::do_before_row_operations(const rpl_group_info *) 6472 : : { 6473 : 114261 : int error= 0; 6474 : : 6546 : : } 6547 : : 6548 : : int 6549 : 114264 : +Write_rows_log_event::do_after_row_operations(int error) 6550 : : { 6551 : 114264 : int local_error= 0; 6552 : : 6677 : : @c ha_update_row() or first deleted and then new record written. 6678 : : */ 6679 : : 6680 : 2034971 : +int Rows_log_event::write_row(rpl_group_info *rgi, const bool overwrite) 6681 : : { 6682 : : DBUG_ENTER("write_row"); 6683 : 2034971 : + DBUG_ASSERT(m_table != NULL); 6684 : 2034971 : + DBUG_ASSERT(thd != NULL); 6685 : : 6686 : 2034971 : TABLE *table= m_table; // pointer to event's table 6687 : : int error; 6754 : : TODO: Add safety measures against infinite looping. 6755 : : */ 6756 : : 6757 : 2034963 : + if (unlikely(table->s->sequence)) 6758 : 2624 : error= update_sequence(); 6759 : 2032346 : else while (unlikely(error= table->file->ha_write_row(table->record[0]))) 6760 : : { 6761 : 71 : + if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT || 6762 : 146 : + (keynum= table->file->get_dup_key(error)) < 0 || !overwrite) 6763 : : { 6764 : : DBUG_PRINT("info",("get_dup_key returns %d)", keynum)); 6765 : : /* 7023 : : 7024 : : 7025 : : #if defined(HAVE_REPLICATION) 7026 : 114992 : +uint8 Write_rows_log_event::get_trg_event_map() const 7027 : : { 7028 : 114992 : return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_UPDATE) | 7029 : 114991 : trg2bit(TRG_EVENT_DELETE); 7035 : : **************************************************************************/ 7036 : : 7037 : : #if defined(HAVE_REPLICATION) 7038 : : +/** 7039 : : + @brief Compares table->record[0] and table->record[1] 7040 : : 7041 : : + @returns true if different. 7042 : : */ 7043 : 1133506 : static bool record_compare(TABLE *table, bool vers_from_plain= false) 7044 : : { 7045 : 1133506 : + bool result= false; 7046 : 1133506 : + bool all_values_set= bitmap_is_set_all(&table->has_value_set); 7047 : : + 7048 : : /** 7049 : : Compare full record only if: 7050 : : + - all fields were given values 7051 : : - there are no blob fields (otherwise we would also need 7052 : : to compare blobs contents as well); 7053 : : - there are no varchar fields (otherwise we would also need 7058 : : */ 7059 : 1133506 : if ((table->s->blob_fields + 7060 : 1133506 : table->s->varchar_fields + 7061 : 1133506 : + table->s->null_fields) == 0 7062 : 13 : + && all_values_set) 7063 : : { 7064 : 0 : + result= cmp_record(table, record[1]); 7065 : 0 : goto record_compare_exit; 7066 : : } 7067 : : 7068 : : /* Compare null bits */ 7069 : 1133506 : + if (all_values_set && memcmp(table->null_flags, 7070 : 1133324 : + table->null_flags + table->s->rec_buff_length, 7071 : 1133324 : + table->s->null_bytes)) 7072 : 1434 : + goto record_compare_differ; // Diff in NULL value 7073 : : 7074 : : /* Compare fields */ 7075 : 2169308 : for (Field **ptr=table->field ; *ptr ; ptr++) 7076 : : { 7077 : 2153183 : + Field *f= *ptr; 7078 : : /* 7079 : : If the table is versioned, don't compare using the version if there is a 7080 : : primary key. If there isn't a primary key, we need the version to 7084 : : because the implicit row_end value will be set to the maximum value for 7085 : : the latest row update (which is what we care about). 7086 : : */ 7087 : 2153411 : + if (table->versioned() && f->vers_sys_field() && 7088 : 228 : (table->s->primary_key < MAX_KEY || 7089 : 50 : + (vers_from_plain && table->vers_start_field() == f))) 7090 : 45 : continue; 7091 : : + 7092 : : + /* 7093 : : + We only compare fields that exist on the master (or in ONLINE 7094 : : + ALTER case, that were in the original table). 7095 : : */ 7096 : 2153138 : + if (!all_values_set) 7097 : : { 7098 : 489 : + if (!f->has_explicit_value() && 7099 : : + /* Don't skip row_end if replicating unversioned -> versioned */ 7100 : 132 : + !(vers_from_plain && table->vers_end_field() == f)) 7101 : 107 : + continue; 7102 : 250 : + if (f->is_null() != f->is_null(table->s->rec_buff_length)) 7103 : 0 : + goto record_compare_differ; 7104 : : } 7105 : : + 7106 : 4305856 : + if (!f->is_null() && !f->vcol_info && 7107 : 2152825 : + f->cmp_binary_offset(table->s->rec_buff_length)) 7108 : 1115947 : + goto record_compare_differ; 7109 : : } 7110 : : 7111 : 16125 : record_compare_exit: 7112 : 16125 : return result; 7113 : 1117381 : +record_compare_differ: 7114 : 1117381 : + return true; 7115 : : +} 7116 : : +/** 7117 : : + Traverses default item expr of a field, and underlying field's default values. 7118 : : + If it is an extra field and has no value replicated, then its default expr 7119 : : + should be also checked. 7120 : : + */ 7121 : : +class Rpl_key_part_checker: public Field_enumerator 7122 : : +{ 7123 : : + bool online_alter; 7124 : : + Field *next_number_field; 7125 : : + bool field_usable; 7126 : : +public: 7127 : : + 7128 : : + 7129 : 17 : + void visit_field(Item_field *item) override 7130 : : + { 7131 : 17 : + if (!field_usable) 7132 : 0 : + return; 7133 : 17 : + field_usable= check_field(item->field); 7134 : : + } 7135 : : + 7136 : 102 : + bool check_field(Field *f) 7137 : : + { 7138 : 102 : + if (f->has_explicit_value()) 7139 : 75 : + return true; 7140 : : + 7141 : 27 : + if ((!f->vcol_info && !online_alter) || f == next_number_field) 7142 : 0 : + return false; 7143 : : + 7144 : 27 : + Virtual_column_info *computed= f->vcol_info ? f->vcol_info 7145 : : + : f->default_value; 7146 : : + 7147 : 27 : + if (computed == NULL) 7148 : 2 : + return true; // No DEFAULT, or constant DEFAULT 7149 : : + 7150 : : + // Deterministic DEFAULT or vcol expression 7151 : 25 : + return !(computed->flags & VCOL_NOT_STRICTLY_DETERMINISTIC) 7152 : 17 : + && !computed->expr->walk(&Item::enumerate_field_refs_processor, 7153 : : + false, this) 7154 : 42 : + && field_usable; 7155 : : + } 7156 : : + 7157 : 79 : + Rpl_key_part_checker(bool online_alter, Field *next_number_field): 7158 : 79 : + online_alter(online_alter), next_number_field(next_number_field), 7159 : 79 : + field_usable(true) {} 7160 : : +}; 7161 : : + 7162 : : + 7163 : : +/** 7164 : : + Newly added fields with non-deterministic defaults (i.e. DEFAULT(RANDOM()), 7165 : : + CURRENT_TIMESTAMP, AUTO_INCREMENT) should be excluded from key search. 7166 : : + Basically we exclude all the default-filled fields based on 7167 : : + has_explicit_value bitmap. 7168 : : +*/ 7169 : 23023 : +uint Rows_log_event::find_key_parts(const KEY *key) const 7170 : : +{ 7171 : 23023 : + RPL_TABLE_LIST *tl= (RPL_TABLE_LIST*)m_table->pos_in_table_list; 7172 : 23023 : + const bool online_alter= tl->m_online_alter_copy_fields; 7173 : : + uint p; 7174 : : + 7175 : 23023 : + if (!m_table->s->keys_in_use.is_set(uint(key - m_table->key_info))) 7176 : 1 : + return 0; 7177 : : + 7178 : 23021 : + if (!online_alter) 7179 : : + { 7180 : 22961 : + if (m_cols.n_bits >= m_table->s->fields) // replicated more than slave has // deleted columns 7181 : 22903 : + return key->user_defined_key_parts; 7182 : 58 : + if (m_table->s->virtual_fields == 0) 7183 : : + { 7184 : 75 : + for (p= 0; p < key->user_defined_key_parts; p++) 7185 : 56 : + if (key->key_part[p].fieldnr > m_cols.n_bits) // extra 7186 : 20 : + break; 7187 : 39 : + return p; 7188 : : + } 7189 : : + } 7190 : : + 7191 : 79 : + Rpl_key_part_checker key_part_checker(online_alter, 7192 : 79 : + m_table->found_next_number_field); 7193 : 156 : + for (p= 0; p < key->user_defined_key_parts; p++) 7194 : : + { 7195 : 85 : + if (!key_part_checker.check_field(key->key_part[p].field)) 7196 : 8 : + break; 7197 : : + } 7198 : 79 : + return p; 7199 : 79 : } 7200 : : 7201 : : 7205 : : A primary key is preferred if it exists; otherwise a unique index is 7206 : : preferred. Else we pick the index with the smalles rec_per_key value. 7207 : : 7208 : : + If a suitable key is found, set @c m_key, @c m_key_nr, @c m_key_info, 7209 : : + and @c m_usable_key_parts member fields appropriately. 7210 : : 7211 : : @returns Error code on failure, 0 on success. 7212 : : */ 7213 : 27445 : +int Rows_log_event::find_key(const rpl_group_info *rgi) 7214 : : { 7215 : 27445 : + DBUG_ASSERT(m_table); 7216 : 27445 : + RPL_TABLE_LIST *tl= (RPL_TABLE_LIST*)m_table->pos_in_table_list; 7217 : 27445 : + uint i, best_key_nr= 0, best_usable_key_parts= 0; 7218 : : + KEY *key; 7219 : 27445 : ulong UNINIT_VAR(best_rec_per_key), tmp; 7220 : : DBUG_ENTER("Rows_log_event::find_key"); 7221 : : 7222 : 27445 : + if ((best_key_nr= tl->cached_key_nr) != ~0U) 7223 : : { 7224 : 2701 : + DBUG_ASSERT(best_key_nr <= MAX_KEY); // use the cached value 7225 : 2701 : + best_usable_key_parts= tl->cached_usable_key_parts; 7226 : : + } 7227 : : + else 7228 : : + { 7229 : 24744 : + best_key_nr= MAX_KEY; 7230 : : + 7231 : : /* 7232 : : + if the source (in the row event) and destination (in m_table) records 7233 : : + don't have the same structure, some keys below might be unusable 7234 : : + for find_row(). 7235 : : + 7236 : : + If it's a replication and slave table (m_table) has less columns 7237 : : + than the master's - easy, all keys are usable. 7238 : : + 7239 : : + If slave's table has more columns, but none of them are generated - 7240 : : + then any column beyond m_cols.n_bits makes an index unusable. 7241 : : + 7242 : : + If slave's table has generated columns or it's the online alter table 7243 : : + where arbitrary structure conversion is possible (in the replication case 7244 : : + one table must be a prefix of the other, see table_def::compatible_with) 7245 : : + we cannot deduce what destination columns will be affected by m_cols, 7246 : : + we have to actually unpack one row and examine has_explicit_value() 7247 : : */ 7248 : : + 7249 : 24744 : + if (tl->m_online_alter_copy_fields || 7250 : 24656 : + (m_cols.n_bits < m_table->s->fields && 7251 : 68 : + m_table->s->virtual_fields)) 7252 : : { 7253 : 107 : + const uchar *curr_row_end= m_curr_row_end; 7254 : 107 : + Check_level_instant_set clis(m_table->in_use, CHECK_FIELD_IGNORE); 7255 : 107 : + if (int err= unpack_row(rgi, m_table, m_width, m_curr_row, &m_cols, 7256 : 107 : + &curr_row_end, &m_master_reclength, m_rows_end)) 7257 : 0 : + DBUG_RETURN(err); 7258 : 107 : } 7259 : : + 7260 : : /* 7261 : : + Keys are sorted so that any primary key is first, followed by unique keys, 7262 : : + followed by any other. So we will automatically pick the primary key if 7263 : : + it exists. 7264 : : */ 7265 : 27592 : + for (i= 0, key= m_table->key_info; i < m_table->s->keys; i++, key++) 7266 : : { 7267 : 23020 : + uint usable_key_parts= find_key_parts(key); 7268 : 23022 : + if (usable_key_parts == 0) 7269 : 15 : + continue; 7270 : : + /* 7271 : : + We cannot use a unique key with NULL-able columns to uniquely identify 7272 : : + a row (but we can still select it for range scan below if nothing better 7273 : : + is available). 7274 : : + */ 7275 : 23007 : + if ((key->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME && 7276 : 20184 : + usable_key_parts == key->user_defined_key_parts) 7277 : : + { 7278 : 20175 : + best_key_nr= i; 7279 : 20175 : + best_usable_key_parts= usable_key_parts; 7280 : 20175 : + break; 7281 : : + } 7282 : : + /* 7283 : : + We can only use a non-unique key if it allows range scans (ie. skip 7284 : : + FULLTEXT indexes and such). 7285 : : + */ 7286 : 2832 : + uint last_part= usable_key_parts - 1; 7287 : : + DBUG_PRINT("info", ("Index %s rec_per_key[%u]= %lu", 7288 : : + key->name.str, last_part, key->rec_per_key[last_part])); 7289 : 2832 : + if (!(m_table->file->index_flags(i, last_part, 1) & HA_READ_NEXT)) 7290 : 4 : + continue; 7291 : : + 7292 : 2829 : + tmp= key->rec_per_key[last_part]; 7293 : 2829 : + if (best_key_nr == MAX_KEY || (tmp > 0 && tmp < best_rec_per_key)) 7294 : : + { 7295 : 2825 : + best_key_nr= i; 7296 : 2825 : + best_usable_key_parts= usable_key_parts; 7297 : 2825 : + best_rec_per_key= tmp; 7298 : : + } 7299 : : } 7300 : 24747 : + tl->cached_key_nr= best_key_nr; 7301 : 24747 : + tl->cached_usable_key_parts= best_usable_key_parts; 7302 : : } 7303 : : 7304 : 27448 : + m_key_nr= best_key_nr; 7305 : 27448 : + m_usable_key_parts= best_usable_key_parts; 7306 : 27448 : if (best_key_nr == MAX_KEY) 7307 : 1783 : m_key_info= NULL; 7308 : : + else 7309 : : + { 7310 : 25665 : + m_key_info= m_table->key_info + best_key_nr; 7311 : : + 7312 : 25665 : + if (!use_pk_position()) 7313 : : + { 7314 : : + // Allocate buffer for key searches 7315 : 5126 : + m_key= (uchar *) my_malloc(PSI_INSTRUMENT_ME, m_key_info->key_length, MYF(MY_WME)); 7316 : 5126 : + if (m_key == NULL) 7317 : 0 : + DBUG_RETURN(HA_ERR_OUT_OF_MEM); 7318 : : + } 7319 : : } 7320 : : 7321 : 27443 : + DBUG_EXECUTE_IF("rpl_report_chosen_key", 7322 : : + push_warning_printf(m_table->in_use, 7323 : : + Sql_condition::WARN_LEVEL_NOTE, 7324 : : + ER_UNKNOWN_ERROR, "Key chosen: %d", 7325 : : + m_key_nr == MAX_KEY ? 7326 : : + -1 : m_key_nr);); 7327 : : 7328 : 27445 : + DBUG_RETURN(0); 7329 : : } 7330 : : 7331 : : 7386 : 130 : ? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED; 7387 : : } 7388 : : 7389 : 379276 : +bool Rows_log_event::use_pk_position() const 7390 : : +{ 7391 : 379276 : + return m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION 7392 : 185259 : + && m_table->s->primary_key < MAX_KEY 7393 : 168356 : + && m_key_nr == m_table->s->primary_key 7394 : 564534 : + && m_usable_key_parts == m_table->key_info->user_defined_key_parts; 7395 : : +} 7396 : : + 7397 : : /** 7398 : : Locate the current row in event's table. 7399 : : 7429 : : { 7430 : : DBUG_ENTER("Rows_log_event::find_row"); 7431 : : 7432 : 353614 : + DBUG_ASSERT(m_table); 7433 : 353614 : + DBUG_ASSERT(m_table->in_use != NULL); 7434 : : 7435 : 353614 : TABLE *table= m_table; 7436 : 353614 : int error= 0; 7437 : 353614 : bool is_table_scan= false, is_index_scan= false; 7438 : 353614 : + Check_level_instant_set clis(table->in_use, CHECK_FIELD_IGNORE); 7439 : : 7440 : : /* 7441 : : rpl_row_tabledefs.test specifies that 7466 : : DBUG_PRINT("info",("looking for the following record")); 7467 : 353615 : DBUG_DUMP("record[0]", table->record[0], table->s->reclength); 7468 : : 7469 : 353614 : + if (use_pk_position()) 7470 : : { 7471 : : /* 7472 : : Use a more efficient method to fetch the record given by 7487 : : table->s->reclength) == 0); 7488 : : 7489 : : */ 7490 : : DBUG_PRINT("info",("locating record using primary key (position)")); 7491 : : 7492 : 147814 : error= table->file->ha_rnd_pos_by_record(table->record[0]); 7548 : 191977 : table->record[0][table->s->null_bytes - 1]|= 7549 : 191977 : 256U - (1U << table->s->last_null_bit_pos); 7550 : : 7551 : 192058 : + const enum ha_rkey_function find_flag= 7552 : 192058 : + m_usable_key_parts == m_key_info->user_defined_key_parts 7553 : 192058 : + ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT; 7554 : 384116 : + error= table->file->ha_index_read_map(table->record[0], m_key, 7555 : 192058 : + make_keypart_map(m_usable_key_parts), 7556 : : + find_flag); 7557 : 192058 : + if (unlikely(error)) 7558 : : { 7559 : : DBUG_PRINT("info",("no record matching the key found in the table")); 7560 : 16 : if (error == HA_ERR_KEY_NOT_FOUND) 7586 : : found. I can see no scenario where it would be incorrect to 7587 : : chose the row to change only using a PK or an UNNI. 7588 : : */ 7589 : 192042 : + if (find_flag == HA_READ_KEY_EXACT && table->key_info->flags & HA_NOSAME) 7590 : : { 7591 : : /* Unique does not have non nullable part */ 7592 : 189646 : + if (!(table->key_info->flags & HA_NULL_PART_KEY)) 7593 : : { 7594 : 187714 : error= 0; 7595 : 187714 : goto end; 7660 : : /* Continue until we find the right record or have made a full loop */ 7661 : : do 7662 : : { 7663 : 1131111 : + if (unlikely((error= table->file->ha_rnd_next(table->record[0])))) 7664 : : DBUG_PRINT("info", ("error: %s", HA_ERR(error))); 7665 : 1131111 : switch (error) { 7666 : : 7729 : : #if defined(HAVE_REPLICATION) 7730 : : 7731 : : int 7732 : 13964 : +Delete_rows_log_event::do_before_row_operations(const rpl_group_info *rgi) 7733 : : { 7734 : : /* 7735 : : Increment the global status delete count variable 7737 : 13964 : if (get_flags(STMT_END_F)) 7738 : 12997 : status_var_increment(thd->status_var.com_stat[SQLCOM_DELETE]); 7739 : : 7740 : 13964 : if (do_invoke_trigger()) 7741 : 5 : m_table->prepare_triggers_for_delete_stmt_or_event(); 7742 : : 7743 : 13964 : + return find_key(rgi); 7744 : : } 7745 : : 7746 : : int 7747 : 13964 : +Delete_rows_log_event::do_after_row_operations(int error) 7748 : : { 7749 : 13964 : m_table->file->ha_index_or_rnd_end(); 7750 : 13964 : my_free(m_key); 7815 : : { 7816 : 51661 : error= m_table->file->ha_delete_row(m_table->record[0]); 7817 : : } 7818 : : } 7819 : 51684 : if (invoke_triggers && likely(!error) && 7820 : 3 : unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE))) 7828 : : #endif /* defined(HAVE_REPLICATION) */ 7829 : : 7830 : : #if defined(HAVE_REPLICATION) 7831 : 13984 : +uint8 Delete_rows_log_event::get_trg_event_map() const 7832 : : { 7833 : 13984 : return trg2bit(TRG_EVENT_DELETE); 7834 : : } 7883 : : #if defined(HAVE_REPLICATION) 7884 : : 7885 : : int 7886 : 13481 : +Update_rows_log_event::do_before_row_operations(const rpl_group_info *rgi) 7887 : : { 7888 : : /* 7889 : : Increment the global status update count variable 7892 : 11567 : status_var_increment(thd->status_var.com_stat[SQLCOM_UPDATE]); 7893 : : 7894 : : int err; 7895 : 13481 : + if ((err= find_key(rgi))) 7896 : 0 : return err; 7897 : : 7898 : 13481 : if (do_invoke_trigger()) 7902 : : } 7903 : : 7904 : : int 7905 : 13481 : +Update_rows_log_event::do_after_row_operations(int error) 7906 : : { 7907 : : /*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/ 7908 : 13481 : m_table->file->ha_index_or_rnd_end(); 8044 : : 8045 : : 8046 : : #if defined(HAVE_REPLICATION) 8047 : 13486 : +uint8 Update_rows_log_event::get_trg_event_map() const 8048 : : { 8049 : 13486 : return trg2bit(TRG_EVENT_UPDATE); 8050 : : } ===== File: sql/records.cc ===== 197 : 1259367 : info->table=table; 198 : 1259367 : info->sort_info= filesort; 199 : : 200 : 1259367 : + if ((table->s->tmp_table == INTERNAL_TMP_TABLE) && !using_addon_fields) 201 : 182640 : (void) table->file->extra(HA_EXTRA_MMAP); 202 : : 203 : 1259372 : if (using_addon_fields) ===== File: sql/rpl_record.cc ===== 144 : : #endif 145 : : 146 : : #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) 147 : : + 148 : : +struct Unpack_record_state 149 : : +{ 150 : : + uchar const *const row_data; 151 : : + uchar const *const row_end; 152 : : + size_t const master_null_byte_count; 153 : : + uchar const *null_ptr; 154 : : + uchar const *pack_ptr; 155 : : + /** Mask to mask out the correct bit among the null bits */ 156 : : + unsigned int null_mask; 157 : : + /** The "current" null bits */ 158 : : + unsigned int null_bits; 159 : 2690487 : + Unpack_record_state(uchar const *const row_data, 160 : : + uchar const *const row_end, 161 : : + size_t const master_null_byte_count) 162 : 2690487 : + : row_data(row_data), row_end(row_end), 163 : 2690487 : + master_null_byte_count(master_null_byte_count), 164 : 2690487 : + null_ptr(row_data), pack_ptr(row_data + master_null_byte_count) 165 : 2690487 : + {} 166 : 2691634 : + void next_null_byte() 167 : : + { 168 : 2691634 : + DBUG_ASSERT(null_ptr < row_data + master_null_byte_count); 169 : 2691634 : + null_mask= 1U; 170 : 2691634 : + null_bits= *null_ptr++; 171 : 2691634 : + } 172 : : +}; 173 : : + 174 : : + 175 : 5923772 : +static bool unpack_field(const table_def *tabledef, Field *f, 176 : : + Unpack_record_state *st, uint field_idx) 177 : : +{ 178 : 5923772 : + if ((st->null_mask & 0xFF) == 0) 179 : 723 : + st->next_null_byte(); 180 : : + 181 : 5923776 : + DBUG_ASSERT(st->null_mask & 0xFF); // One of the 8 LSB should be set 182 : : + 183 : 5923776 : + if (st->null_bits & st->null_mask) 184 : : + { 185 : 1183198 : + if (f->maybe_null()) 186 : : + { 187 : : + DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x", 188 : : + st->null_mask, st->null_bits)); 189 : : + /** 190 : : + Calling reset just in case one is unpacking on top a 191 : : + record with data. 192 : : + 193 : : + This could probably go into set_null() but doing so, 194 : : + (i) triggers assertion in other parts of the code at 195 : : + the moment; (ii) it would make us reset the field, 196 : : + always when setting null, which right now doesn't seem 197 : : + needed anywhere else except here. 198 : : + 199 : : + TODO: maybe in the future we should consider moving 200 : : + the reset to make it part of set_null. But then 201 : : + the assertions triggered need to be 202 : : + addressed/revisited. 203 : : + */ 204 : 1183180 : + f->reset(); 205 : 1183180 : + f->set_null(); 206 : : + } 207 : : + else 208 : : + { 209 : 18 : + THD *thd= f->table->in_use; 210 : : + 211 : 18 : + f->set_default(); 212 : 18 : + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 213 : : + ER_BAD_NULL_ERROR, 214 : 18 : + ER_THD(thd, ER_BAD_NULL_ERROR), 215 : : + f->field_name.str); 216 : : + } 217 : : + } 218 : : + else 219 : : + { 220 : 4740578 : + f->set_notnull(); 221 : : + 222 : : + /* 223 : : + We only unpack the field if it was non-null. 224 : : + Use the master's size information if available else call 225 : : + normal unpack operation. 226 : : + */ 227 : 4740573 : + uint16 const metadata = tabledef->field_metadata(field_idx); 228 : : +#ifdef DBUG_TRACE 229 : : + uchar const *const old_pack_ptr= st->pack_ptr; 230 : : +#endif 231 : : + 232 : 4740564 : + st->pack_ptr= f->unpack(f->ptr, st->pack_ptr, st->row_end, metadata); 233 : : + DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" 234 : : + " pack_ptr: %p; pack_ptr': %p; bytes: %d", 235 : : + f->field_name.str, metadata, 236 : : + old_pack_ptr, st->pack_ptr, 237 : : + (int) (st->pack_ptr - old_pack_ptr))); 238 : 4740561 : + if (!st->pack_ptr) 239 : 0 : + return false; 240 : : + } 241 : 5923759 : + st->null_mask <<= 1; 242 : 5923759 : + return true; 243 : : +} 244 : : + 245 : 885 : +static void convert_field(Field *f, Field *result_field, Field *conv_field) 246 : : +{ 247 : : +#ifndef DBUG_OFF 248 : 885 : + char type_buf[MAX_FIELD_WIDTH]; 249 : 885 : + char value_buf[MAX_FIELD_WIDTH]; 250 : 885 : + String source_type(type_buf, sizeof(type_buf), system_charset_info); 251 : 885 : + String value_string(value_buf, sizeof(value_buf), system_charset_info); 252 : 885 : + conv_field->sql_type(source_type); 253 : 885 : + conv_field->val_str(&value_string); 254 : : + DBUG_PRINT("debug", ("Copying field '%s' of type '%s' with value '%s'", 255 : : + result_field->field_name.str, 256 : : + source_type.c_ptr_safe(), value_string.c_ptr_safe())); 257 : : +#endif 258 : : + 259 : 885 : + Copy_field copy; 260 : 885 : + copy.set(result_field, f, TRUE); 261 : 885 : + (*copy.do_copy)(©); 262 : : + 263 : : +#ifndef DBUG_OFF 264 : 885 : + String target_type(type_buf, sizeof(type_buf), system_charset_info); 265 : 885 : + result_field->sql_type(target_type); 266 : 885 : + result_field->val_str(&value_string); 267 : : + DBUG_PRINT("debug", ("Value of field '%s' of type '%s' is now '%s'", 268 : : + result_field->field_name.str, 269 : : + target_type.c_ptr_safe(), value_string.c_ptr_safe())); 270 : : +#endif 271 : 1770 : +} 272 : : + 273 : : 274 : : /** 275 : : Unpack a row into @c table->record[0]. 292 : : unpack a row from from the backup image, but can be used for other 293 : : purposes as well. 294 : : 295 : : + @param rgi Relay group info 296 : : @param table Table to unpack into 297 : : @param colcnt Number of columns to read from record 298 : : @param row_data 299 : : + Packed row datanull_ptr 300 : : @param cols Pointer to bitset describing columns to fill in 301 : : @param curr_row_end 302 : : Pointer to variable that will hold the value of the 315 : : @retval HA_ERR_CORRUPT_EVENT 316 : : Found error when trying to unpack fields. 317 : : */ 318 : 2690488 : +int unpack_row(const rpl_group_info *rgi, TABLE *table, uint const colcnt, 319 : : + uchar const *const row_data, MY_BITMAP const *cols, 320 : : + uchar const **const current_row_end, 321 : : + ulong *const master_reclength, uchar const *const row_end) 322 : : { 323 : : int error; 324 : : DBUG_ENTER("unpack_row"); 325 : 2690488 : DBUG_ASSERT(row_data); 326 : 2690488 : DBUG_ASSERT(table); 327 : 2690488 : + DBUG_ASSERT(rgi); 328 : : 329 : 2690488 : + Unpack_record_state st(row_data, row_end, (bitmap_bits_set(cols) + 7) / 8); 330 : : 331 : 2690470 : if (bitmap_is_clear_all(cols)) 332 : : { 334 : : There was no data sent from the master, so there is 335 : : nothing to unpack. 336 : : */ 337 : 0 : + *current_row_end= st.pack_ptr; 338 : 0 : *master_reclength= 0; 339 : 0 : DBUG_RETURN(0); 340 : : } 341 : : 342 : 2690492 : + Rpl_table_data rpl_data= *(RPL_TABLE_LIST*)table->pos_in_table_list; 343 : 2690476 : + const table_def *tabledef= rpl_data.tabledef; 344 : 2690476 : + const TABLE *conv_table= rpl_data.conv_table; 345 : : + DBUG_PRINT("debug", ("Table data: tabldef: %p, conv_table: %p", 346 : : + tabledef, conv_table)); 347 : 2690476 : uint i= 0; 348 : : 349 : 2690476 : + st.next_null_byte(); 350 : 2690489 : + if (!rpl_data.is_online_alter()) 351 : : { 352 : : + Field *result_field; 353 : 8908742 : + for (; i < colcnt && (result_field= table->field[i]); i++) 354 : : { 355 : : + /* 356 : : + If there is a conversion table, we pick up the field pointer to 357 : : + the conversion table. If the conversion table or the field 358 : : + pointer is NULL, no conversions are necessary. 359 : : + */ 360 : 6220835 : + Field *conv_field= conv_table ? conv_table->field[i] : NULL; 361 : 6220835 : + Field *const f= conv_field ? conv_field : result_field; 362 : : + 363 : : + DBUG_PRINT("debug", ("Conversion %srequired for field '%s' (#%u)", 364 : : + conv_field ? "" : "not ", 365 : : + result_field->field_name.str, i)); 366 : 6220835 : + DBUG_ASSERT(f != NULL); 367 : : 368 : : + /* 369 : : + No need to bother about columns that does not exist: they have 370 : : + gotten default values when being emptied above. 371 : : + */ 372 : 6220835 : + if (!bitmap_is_set(cols, i)) 373 : 302060 : + continue; 374 : : 375 : 5918760 : + result_field->set_has_explicit_value(); 376 : : 377 : 5918768 : + bool unpack_result= unpack_field(tabledef, f, &st, i); 378 : 5918786 : + if (!unpack_result) 379 : : + { 380 : 0 : + rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, 381 : 0 : + rgi->gtid_info(), 382 : : + "Could not read field '%s' of table '%s.%s'", 383 : 0 : + f->field_name.str, table->s->db.str, 384 : 0 : + table->s->table_name.str); 385 : 0 : + DBUG_RETURN(HA_ERR_CORRUPT_EVENT); 386 : : } 387 : : 388 : : /* 390 : : case, we have unpacked the master data to the conversion 391 : : table, so we need to copy the value stored in the conversion 392 : : table into the final table and do the conversion at the same time. 393 : : 394 : : + If copy_fields is set, it means we are doing an online alter table, 395 : : + and will use copy_fields set up in copy_data_between_tables 396 : : + */ 397 : 5918786 : + if (conv_field) 398 : 885 : + convert_field(f, result_field, conv_field); 399 : : } 400 : : 401 : : + /* 402 : : + Throw away master's extra fields 403 : : + */ 404 : 2687907 : + uint max_cols= MY_MIN(tabledef->size(), cols->n_bits); 405 : 2691048 : + for (; i < max_cols; i++) 406 : : { 407 : 3153 : + if (bitmap_is_set(cols, i)) 408 : : { 409 : 3153 : + if ((st.null_mask & 0xFF) == 0) 410 : 420 : + st.next_null_byte(); 411 : 3153 : + DBUG_ASSERT(st.null_mask & 0xFF); // One of the 8 LSB should be set 412 : : + 413 : 3153 : + if (!((st.null_bits & st.null_mask) && tabledef->maybe_null(i))) { 414 : 2688 : + uint32 len= tabledef->calc_field_size(i, (uchar *) st.pack_ptr); 415 : 2688 : + DBUG_DUMP("field_data", st.pack_ptr, len); 416 : 2688 : + st.pack_ptr+= len; 417 : : + } 418 : 3153 : + st.null_mask <<= 1; 419 : : } 420 : : + } 421 : : 422 : 2687895 : + if (master_reclength) 423 : : + { 424 : 2687869 : + if (result_field) 425 : 2687541 : + *master_reclength = (ulong)(result_field->ptr - table->record[0]); 426 : : + else 427 : 328 : + *master_reclength = table->s->reclength; 428 : : } 429 : : } 430 : : + else 431 : : + { 432 : : + /* 433 : : + For Online Alter, iterate through old table fields to unpack, 434 : : + then iterate through copy_field array to copy to the new table's record. 435 : : + */ 436 : : 437 : 2595 : + DBUG_ASSERT(colcnt == conv_table->s->fields); 438 : 7578 : + for (;i < colcnt; i++) 439 : : + { 440 : 4983 : + DBUG_ASSERT(bitmap_is_set(cols, i)); 441 : 4983 : + Field *f= conv_table->field[i]; 442 : 4983 : + bool result= unpack_field(tabledef, f, &st, i); 443 : 4983 : + DBUG_ASSERT(result); 444 : : + } 445 : : + 446 : 7526 : + for (const auto *copy=rpl_data.copy_fields; 447 : 7526 : + copy != rpl_data.copy_fields_end; copy++) 448 : : + { 449 : 4931 : + copy->to_field->set_has_explicit_value(); 450 : 4931 : + copy->do_copy(copy); 451 : : + } 452 : 2595 : + if (master_reclength) 453 : 2595 : + *master_reclength = conv_table->s->reclength; 454 : : + } // if (rpl_data.is_online_alter()) 455 : : 456 : : /* 457 : : We should now have read all the null bytes, otherwise something is 458 : : really wrong. 459 : : */ 460 : 2690490 : + DBUG_ASSERT(st.null_ptr == row_data + st.master_null_byte_count); 461 : 2690490 : + DBUG_DUMP("row_data", row_data, st.pack_ptr - row_data); 462 : : 463 : 2690478 : + *current_row_end = st.pack_ptr; 464 : : 465 : 2946386 : + if (table->default_field && (rpl_data.is_online_alter() || 466 : 255905 : + LOG_EVENT_IS_WRITE_ROW(rgi->current_event->get_type_code()))) 467 : : { 468 : 89054 : + error= table->update_default_fields(table->in_use->lex->ignore); 469 : 89054 : + if (unlikely(error)) 470 : 0 : + DBUG_RETURN(error); 471 : : + } 472 : 2690481 : + if (table->vfield) 473 : : + { 474 : 246002 : + error= table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE); 475 : 246002 : + if (unlikely(error)) 476 : 2 : + DBUG_RETURN(error); 477 : : } 478 : : + 479 : 2690479 : + if (rpl_data.is_online_alter()) 480 : : + { 481 : : + /* we only check constraints for ALTER TABLE */ 482 : 2593 : + DBUG_ASSERT(table->in_use->lex->ignore == FALSE); 483 : 2593 : + error = table->verify_constraints(false); 484 : 2593 : + DBUG_ASSERT(error != VIEW_CHECK_SKIP); 485 : 2593 : + if (error) 486 : 6 : + DBUG_RETURN(HA_ERR_GENERIC); 487 : : + } 488 : : + 489 : 2690471 : DBUG_RETURN(0); 490 : : } 491 : : 542 : : 543 : 213 : DBUG_RETURN(0); 544 : : } 545 : : #endif // HAVE_REPLICATION ===== File: sql/rpl_record.h ===== 29 : : #endif 30 : : 31 : : #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) 32 : : +int unpack_row(const rpl_group_info *rgi, 33 : : TABLE *table, uint const colcnt, 34 : : uchar const *const row_data, MY_BITMAP const *cols, 35 : : uchar const **const curr_row_end, ulong *const master_reclength, ===== File: sql/rpl_rli.cc ===== 2473 : : If no GTID is available, then NULL is returned. 2474 : : */ 2475 : : char * 2476 : 1895 : +rpl_group_info::gtid_info() const 2477 : : { 2478 : 1895 : if (!gtid_sub_id || !current_gtid.seq_no) 2479 : 927 : return NULL; ===== File: sql/rpl_rli.h ===== 669 : : mysql_cond_t start_alter_cond; 670 : : }; 671 : : 672 : : +struct Rpl_table_data 673 : : +{ 674 : : + const table_def *tabledef; 675 : : + TABLE *conv_table; 676 : : + const Copy_field *copy_fields; 677 : : + const Copy_field *copy_fields_end; 678 : 2832183 : + Rpl_table_data(const RPL_TABLE_LIST &rpl_table_list) 679 : 2832183 : + { 680 : 2832183 : + tabledef= &rpl_table_list.m_tabledef; 681 : 2832183 : + conv_table= rpl_table_list.m_conv_table; 682 : 2832183 : + copy_fields= rpl_table_list.m_online_alter_copy_fields; 683 : 2832183 : + copy_fields_end= rpl_table_list.m_online_alter_copy_fields_end; 684 : 2832183 : + } 685 : 5779194 : + bool is_online_alter() const { return copy_fields != NULL; } 686 : : +}; 687 : : + 688 : : /* 689 : : This is data for various state needed to be kept for the processing of 690 : : one event group (transaction) during replication. 830 : : longlong row_stmt_start_timestamp; 831 : : bool long_find_row_note_printed; 832 : : /* Needs room for "Gtid D-S-N\x00". */ 833 : : + mutable char gtid_info_buf[5+10+1+10+1+20+1]; 834 : : 835 : : /* 836 : : The timestamp, from the master, of the commit event. 957 : : } 958 : 326619 : } 959 : : 960 : : void clear_tables_to_lock(); 961 : : void cleanup_context(THD *, bool); 962 : : void slave_close_thread_tables(THD *); 963 : : void mark_start_commit_no_lock(); 964 : : void mark_start_commit(); 965 : : + char *gtid_info() const; 966 : : void unmark_start_commit(); 967 : : 968 : 16139 : longlong get_row_stmt_start_timestamp() ===== File: sql/rpl_utility.h ===== 43 : : 44 : : class table_def 45 : : { 46 : : + table_def(const table_def&) = default; 47 : : public: 48 : : /** 49 : : Constructor. 57 : : table_def(unsigned char *types, ulong size, uchar *field_metadata, 58 : : int metadata_size, uchar *null_bitmap, uint16 flags); 59 : : 60 : : + 61 : : + /** 62 : : + Move constructor 63 : : + Since it deallocates a memory during destruction, we can't safely copy it. 64 : : + We should instead move it to zero m_memory in an old object 65 : : + */ 66 : 170583 : + table_def(table_def &&tabledef) 67 : 170583 : + : table_def(tabledef) 68 : : + { 69 : 170583 : + tabledef.m_memory= NULL; 70 : 170583 : + } 71 : : + 72 : : ~table_def(); 73 : : 74 : : /** 249 : : Extend the normal table list with a few new fields needed by the 250 : : slave thread, but nowhere else. 251 : : */ 252 : : +struct RPL_TABLE_LIST : public TABLE_LIST 253 : : { 254 : : table_def m_tabledef; 255 : : TABLE *m_conv_table; 256 : : + const Copy_field *m_online_alter_copy_fields; 257 : : + const Copy_field *m_online_alter_copy_fields_end; 258 : : + uint cached_key_nr; // [0..MAX_KEY] if set, ~0U if unset 259 : : + uint cached_usable_key_parts; 260 : : + bool m_tabledef_valid; 261 : : bool master_had_triggers; 262 : : + 263 : 134788 : + RPL_TABLE_LIST(const LEX_CSTRING *db_arg, const LEX_CSTRING *table_name_arg, 264 : : + thr_lock_type thr_lock_type, 265 : : + table_def &&tabledef, bool master_had_trigers) 266 : 134788 : + : TABLE_LIST(db_arg, table_name_arg, NULL, thr_lock_type), 267 : 134787 : + m_tabledef(std::move(tabledef)), m_conv_table(NULL), 268 : 134784 : + m_online_alter_copy_fields(NULL), m_online_alter_copy_fields_end(NULL), 269 : 134784 : + cached_key_nr(~0U), m_tabledef_valid(true), 270 : 134788 : + master_had_triggers(master_had_trigers) 271 : 134784 : + {} 272 : : + 273 : 35797 : + RPL_TABLE_LIST(TABLE *table, thr_lock_type lock_type, TABLE *conv_table, 274 : : + table_def &&tabledef, 275 : : + const Copy_field online_alter_copy_fields[], 276 : : + const Copy_field *online_alter_copy_fields_end) 277 : 35797 : + : TABLE_LIST(table, lock_type), 278 : 35795 : + m_tabledef(std::move(tabledef)), m_conv_table(conv_table), 279 : 35791 : + m_online_alter_copy_fields(online_alter_copy_fields), 280 : 35791 : + m_online_alter_copy_fields_end(online_alter_copy_fields_end), 281 : 35797 : + cached_key_nr(~0U), m_tabledef_valid(true), master_had_triggers(false) 282 : 35791 : + {} 283 : : }; 284 : : 285 : : ===== File: sql/sql_alter.cc ===== 177 : : } 178 : : 179 : : 180 : 90957 : +bool Alter_info::supports_lock(THD *thd, bool online, 181 : : + Alter_inplace_info *ha_alter_info) 182 : : { 183 : 90957 : switch (ha_alter_info->inplace_supported) { 184 : 142 : case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: 207 : : case HA_ALTER_INPLACE_SHARED_LOCK: 208 : 67032 : if (requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) 209 : : { 210 : 45 : + if (online) 211 : 21 : + ha_alter_info->inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED; 212 : : + else 213 : : + { 214 : 24 : + ha_alter_info->report_unsupported_error("LOCK=NONE", "LOCK=SHARED"); 215 : 24 : + return true; 216 : : + } 217 : : } 218 : 67008 : return false; 219 : 0 : case HA_ALTER_ERROR: 260 : 29157 : return requested_algorithm; 261 : : } 262 : : 263 : 4497 : +bool Alter_info::algorithm_is_nocopy(const THD *thd) const 264 : : +{ 265 : 4497 : + auto alg= algorithm(thd); 266 : : + return alg == ALTER_TABLE_ALGORITHM_INPLACE 267 : 4486 : + || alg == ALTER_TABLE_ALGORITHM_INSTANT 268 : 8983 : + || alg == ALTER_TABLE_ALGORITHM_NOCOPY; 269 : : +} 270 : : + 271 : : 272 : 6599 : Alter_table_ctx::Alter_table_ctx() 273 : 6599 : : db(null_clex_str), table_name(null_clex_str), alias(null_clex_str), ===== File: sql/sql_alter.h ===== 226 : : @retval false Supported lock type 227 : : @retval true Not supported value 228 : : */ 229 : : + bool supports_lock(THD *thd, bool, Alter_inplace_info *ha_alter_info); 230 : : 231 : : /** 232 : : Return user requested algorithm. If user does not specify 233 : : algorithm then return alter_algorithm variable value. 234 : : */ 235 : : enum_alter_table_algorithm algorithm(const THD *thd) const; 236 : : + bool algorithm_is_nocopy(const THD *thd) const; 237 : : 238 : : private: 239 : : Alter_info &operator=(const Alter_info &rhs); // not implemented ===== File: sql/sql_cache.h ===== 584 : : query_cache.send_result_to_client(A, B, C) 585 : : #define query_cache_invalidate_by_MyISAM_filename_ref \ 586 : : &query_cache_invalidate_by_MyISAM_filename 587 : : +#define query_cache_invalidate_locked_for_write(A, B) \ 588 : : + query_cache.invalidate_locked_for_write(A, B) 589 : : /* note the "maybe": it's a read without mutex */ 590 : : #define query_cache_maybe_disabled(T) \ 591 : : (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0) 603 : : #define query_cache_invalidate1(A,B) do { } while(0) 604 : : #define query_cache_send_result_to_client(A, B, C) 0 605 : : #define query_cache_invalidate_by_MyISAM_filename_ref NULL 606 : : +#define query_cache_invalidate_locked_for_write(A, B) do { } while(0) 607 : : 608 : : #define query_cache_abort(A,B) do { } while(0) 609 : : #define query_cache_end_of_result(A) do { } while(0) ===== File: sql/sql_class.cc ===== 1138 : : } 1139 : : 1140 : : extern "C" 1141 : 15893751 : +void *thd_alloc(const MYSQL_THD thd, size_t size) 1142 : : { 1143 : 15893751 : return thd->alloc(size); 1144 : : } 1145 : : 1146 : : extern "C" 1147 : 126471 : +void *thd_calloc(const MYSQL_THD thd, size_t size) 1148 : : { 1149 : 126471 : return thd->calloc(size); 1150 : : } 1151 : : 1152 : : extern "C" 1153 : 65 : +char *thd_strdup(const MYSQL_THD thd, const char *str) 1154 : : { 1155 : 65 : return thd->strdup(str); 1156 : : } 1157 : : 1158 : : extern "C" 1159 : 4 : +char *thd_strmake(const MYSQL_THD thd, const char *str, size_t size) 1160 : : { 1161 : 4 : return thd->strmake(str, size); 1162 : : } 1163 : : 1164 : : extern "C" 1165 : 36929 : +LEX_CSTRING *thd_make_lex_string(const THD *thd, LEX_CSTRING *lex_str, 1166 : : const char *str, size_t size, 1167 : : int allocate_lex_string) 1168 : : { 1171 : : } 1172 : : 1173 : : extern "C" 1174 : 4595 : +void *thd_memdup(const MYSQL_THD thd, const void* str, size_t size) 1175 : : { 1176 : 4595 : return thd->memdup(str, size); 1177 : : } 2345 : : 2346 : 1247992 : bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs, 2347 : : const char *from, size_t from_length, 2348 : : + CHARSET_INFO *from_cs) const 2349 : : { 2350 : : DBUG_ENTER("THD::convert_string"); 2351 : 1247992 : size_t new_length= to_cs->mbmaxlen * from_length; 2382 : : */ 2383 : : 2384 : 316 : bool THD::reinterpret_string_from_binary(LEX_CSTRING *to, CHARSET_INFO *cs, 2385 : : + const char *str, size_t length) const 2386 : : { 2387 : : /* 2388 : : When reinterpreting from binary to tricky character sets like 2424 : : */ 2425 : 5849005 : bool THD::convert_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, 2426 : : CHARSET_INFO *srccs, const char *src, size_t src_length, 2427 : : + String_copier *status) const 2428 : : { 2429 : : DBUG_ENTER("THD::convert_fix"); 2430 : 5849005 : size_t dst_length= dstcs->mbmaxlen * src_length; 2442 : : */ 2443 : 118927 : bool THD::copy_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, 2444 : : CHARSET_INFO *srccs, const char *src, size_t src_length, 2445 : : + String_copier *status) const 2446 : : { 2447 : : DBUG_ENTER("THD::copy_fix"); 2448 : 118927 : size_t dst_length= dstcs->mbmaxlen * src_length; 2474 : : 2475 : 5849009 : bool THD::convert_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, 2476 : : CHARSET_INFO *srccs, 2477 : : + const char *src, size_t src_length) const 2478 : : { 2479 : 5849009 : String_copier_with_error status; 2480 : 11697912 : return convert_fix(dstcs, dst, srccs, src, src_length, &status) || 2484 : : 2485 : 118924 : bool THD::copy_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, 2486 : : CHARSET_INFO *srccs, 2487 : : + const char *src, size_t src_length) const 2488 : : { 2489 : 118924 : String_copier_with_error status; 2490 : 237797 : return copy_fix(dstcs, dst, srccs, src, src_length, &status) || 2507 : : !0 out of memory 2508 : : */ 2509 : : 2510 : 34 : +bool THD::convert_string(String *s, CHARSET_INFO *from_cs, 2511 : : + CHARSET_INFO *to_cs) 2512 : : { 2513 : 34 : uint dummy_errors; 2514 : 34 : if (unlikely(convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, 2540 : : } 2541 : : 2542 : : 2543 : 30890779 : +bool THD::to_ident_sys_alloc(Lex_ident_sys_st *to, 2544 : : + const Lex_ident_cli_st *ident) const 2545 : : { 2546 : 30890779 : if (ident->is_quoted()) 2547 : : { 6901 : 5641345 : binlog_filter->db_ok(db->str))); 6902 : : } 6903 : : 6904 : : /* Declare in unnamed namespace. */ 6905 : : CPP_UNNAMED_NS_START 6906 : : /** 7025 : : 7026 : : CPP_UNNAMED_NS_END 7027 : : 7028 : 3490652 : +int THD::binlog_write_row(TABLE* table, Event_log *bin_log, 7029 : : + binlog_cache_data *cache_data, bool is_trans, 7030 : : uchar const *record) 7031 : : { 7032 : : /* 7033 : : Pack records into format for transfer. We are allocating more 7034 : : memory than needed, but that doesn't matter. 7042 : : 7043 : 3490651 : size_t const len= pack_row(table, table->rpl_write_set, row_data, record); 7044 : : 7045 : 3490647 : + auto creator= binlog_should_compress(len) ? 7046 : 49 : + Rows_event_factory::get() : 7047 : 3490601 : + Rows_event_factory::get(); 7048 : : 7049 : 6981307 : + auto *ev= bin_log->prepare_pending_rows_event(this, table, cache_data, 7050 : 3490649 : + variables.server_id, 7051 : : + len, is_trans, creator); 7052 : : 7053 : 3490658 : if (unlikely(ev == 0)) 7054 : 1 : return HA_ERR_OUT_OF_MEM; 7056 : 3490657 : return ev->add_row_data(row_data, len); 7057 : 3490660 : } 7058 : : 7059 : 596874 : +int THD::binlog_update_row(TABLE* table, Event_log *bin_log, 7060 : : + binlog_cache_data *cache_data, bool is_trans, 7061 : : + enum_binlog_row_image row_image, 7062 : : const uchar *before_record, 7063 : : const uchar *after_record) 7064 : : { 7065 : : /** 7066 : : Save a reference to the original read bitmaps 7067 : : We will need this to restore the bitmaps at the end as 7073 : : 7074 : : /** 7075 : : This will remove spurious fields required during execution but 7076 : : + not needed for binlogging, according to the row_image argument. 7077 : : */ 7078 : 596874 : + binlog_prepare_row_images(table, row_image); 7079 : : 7080 : 596874 : size_t const before_maxlen= max_row_length(table, table->read_set, 7081 : : before_record); 7093 : : before_record); 7094 : 596874 : size_t const after_size= pack_row(table, table->rpl_write_set, after_row, 7095 : : after_record); 7096 : : /* 7097 : : Don't print debug messages when running valgrind since they can 7098 : : trigger false warnings. 7104 : 596874 : DBUG_DUMP("after_row", after_row, after_size); 7105 : : #endif 7106 : : 7107 : 596874 : + auto creator= binlog_should_compress(before_size + after_size) ? 7108 : 41 : + Rows_event_factory::get() : 7109 : 596833 : + Rows_event_factory::get(); 7110 : 1193748 : + auto *ev= bin_log->prepare_pending_rows_event(this, table, cache_data, 7111 : 596874 : + variables.server_id, 7112 : : + before_size + after_size, 7113 : : + is_trans, creator); 7114 : : 7115 : 596874 : if (unlikely(ev == 0)) 7116 : 3 : return HA_ERR_OUT_OF_MEM; 7125 : : 7126 : 596874 : } 7127 : : 7128 : 107330 : +int THD::binlog_delete_row(TABLE* table, Event_log *bin_log, 7129 : : + binlog_cache_data *cache_data, bool is_trans, 7130 : : + enum_binlog_row_image row_image, 7131 : : uchar const *record) 7132 : : { 7133 : : /** 7134 : : Save a reference to the original read bitmaps 7135 : : We will need this to restore the bitmaps at the end as 7144 : : not needed for binlogging. This is done according to the: 7145 : : binlog-row-image option. 7146 : : */ 7147 : 107330 : + binlog_prepare_row_images(table, row_image); 7148 : : 7149 : : /* 7150 : : Pack records into format for transfer. We are allocating more 7160 : 107330 : DBUG_DUMP("table->read_set", (uchar*) table->read_set->bitmap, (table->s->fields + 7) / 8); 7161 : 107330 : size_t const len= pack_row(table, table->read_set, row_data, record); 7162 : : 7163 : 107330 : + auto creator= binlog_should_compress(len) ? 7164 : 14 : + Rows_event_factory::get() : 7165 : 107316 : + Rows_event_factory::get(); 7166 : 214660 : + auto *ev= bin_log->prepare_pending_rows_event(this, table, cache_data, 7167 : 107330 : + variables.server_id, 7168 : : + len, is_trans, creator); 7169 : : 7170 : 107330 : if (unlikely(ev == 0)) 7171 : 0 : return HA_ERR_OUT_OF_MEM; 7185 : : Remove from read_set spurious columns. The write_set has been 7186 : : handled before in table->mark_columns_needed_for_update. 7187 : : */ 7188 : 704204 : +void binlog_prepare_row_images(TABLE *table, enum_binlog_row_image row_image) 7189 : : { 7190 : : DBUG_ENTER("THD::binlog_prepare_row_images"); 7191 : : 7192 : 2734450 : DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s", 7193 : : table->read_set); 7194 : : 7195 : : /** 7196 : : if there is a primary key in the table (ie, user declared PK or a 7198 : : and the handler involved supports this. 7199 : : */ 7200 : 2075948 : if (table->s->primary_key < MAX_KEY && 7201 : 725522 : + row_image < BINLOG_ROW_IMAGE_FULL && 7202 : 21318 : !ha_check_storage_engine_flag(table->s->db_type(), 7203 : : HTON_NO_BINLOG_ROW_OPT)) 7204 : : { 7208 : : */ 7209 : 21318 : DBUG_ASSERT(table->read_set != &table->tmp_set); 7210 : : 7211 : 21318 : + switch (row_image) 7212 : : { 7213 : 18906 : case BINLOG_ROW_IMAGE_MINIMAL: 7214 : : /* MINIMAL: Mark only PK */ 7243 : 704204 : DBUG_VOID_RETURN; 7244 : : } 7245 : : 7246 : 11675749 : int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) 7247 : : { 7248 : : DBUG_ENTER("THD::binlog_flush_pending_rows_event"); 7258 : 4109653 : if (variables.option_bits & OPTION_GTID_BEGIN) 7259 : 947461 : is_transactional= 1; 7260 : : 7261 : 4109653 : + auto *cache_mngr= binlog_get_cache_mngr(); 7262 : 4109665 : + if (!cache_mngr) 7263 : 1020134 : + DBUG_RETURN(0); 7264 : 6179051 : + auto *cache= binlog_get_cache_data(cache_mngr, 7265 : 3089531 : + use_trans_cache(this, is_transactional)); 7266 : : 7267 : : + int error= 7268 : 3089530 : + ::binlog_flush_pending_rows_event(this, stmt_end, is_transactional, 7269 : : + mysql_bin_log.as_event_log(), cache); 7270 : 3089523 : DBUG_RETURN(error); 7271 : : } 7272 : : ===== File: sql/sql_class.h ===== 72 : : #include "wsrep_on.h" 73 : : #ifdef WITH_WSREP 74 : : #include 75 : : +#include 76 : : /* wsrep-lib */ 77 : : #include "wsrep_client_service.h" 78 : : #include "wsrep_client_state.h" 202 : : #define OLD_MODE_UTF8_IS_UTF8MB3 (1 << 3) 203 : : #define OLD_MODE_IGNORE_INDEX_ONLY_FOR_JOIN (1 << 4) 204 : : #define OLD_MODE_COMPAT_5_1_CHECKSUM (1 << 5) 205 : : +#define OLD_MODE_LOCK_ALTER_TABLE_COPY (1 << 6) 206 : : 207 : : extern char internal_table_name[2]; 208 : : extern char empty_c_string[1]; 1221 : 34795717 : inline bool is_conventional() const 1222 : 34795717 : { return state == STMT_CONVENTIONAL_EXECUTION; } 1223 : : 1224 : 110117555 : + inline void* alloc(size_t size) const { return alloc_root(mem_root,size); } 1225 : 13552117 : + inline void* calloc(size_t size) const 1226 : : { 1227 : : void *ptr; 1228 : 13552117 : if (likely((ptr=alloc_root(mem_root,size)))) 1229 : 13552044 : bzero(ptr, size); 1230 : 13552201 : return ptr; 1231 : : } 1232 : 93344 : + inline char *strdup(const char *str) const 1233 : 93344 : { return strdup_root(mem_root,str); } 1234 : 23337992 : + inline char *strmake(const char *str, size_t size) const 1235 : 23337992 : { return strmake_root(mem_root,str,size); } 1236 : 6 : + inline LEX_CSTRING strcat(const LEX_CSTRING &a, const LEX_CSTRING &b) const 1237 : : + { 1238 : 6 : + char *buf= (char*)alloc(a.length + b.length + 1); 1239 : 6 : + if (unlikely(!buf)) 1240 : 0 : + return null_clex_str; 1241 : 6 : + memcpy(buf, a.str, a.length); 1242 : 6 : + memcpy(buf + a.length, b.str, b.length); 1243 : 6 : + buf[a.length + b.length] = 0; 1244 : 6 : + return {buf, a.length + b.length}; 1245 : : + } 1246 : 7895367 : + inline void *memdup(const void *str, size_t size) const 1247 : 7895367 : { return memdup_root(mem_root,str,size); } 1248 : 8984733 : + inline void *memdup_w_gap(const void *str, size_t size, size_t gap) const 1249 : : { 1250 : : void *ptr; 1251 : 8984733 : if (likely((ptr= alloc_root(mem_root,size+gap)))) 2705 : : Protocol_binary protocol_binary; // Binary protocol 2706 : : HASH user_vars; // hash for user variables 2707 : : String packet; // dynamic buffer for network I/O 2708 : : + String convert_buffer; // buffer for charset conversions 2709 : : struct my_rnd_struct rand; // used for authentication 2710 : : struct system_variables variables; // Changeable local variables 2711 : : struct system_status_var status_var; // Per thread statistic vars 2957 : : */ 2958 : : void binlog_start_trans_and_stmt(); 2959 : : void binlog_set_stmt_begin(); 2960 : : + int binlog_write_row(TABLE* table, Event_log *bin_log, 2961 : : + binlog_cache_data *cache_data, bool is_transactional, 2962 : : const uchar *buf); 2963 : : + int binlog_delete_row(TABLE* table, Event_log *bin_log, 2964 : : + binlog_cache_data *cache_data, bool is_transactional, 2965 : : + enum_binlog_row_image row_image, const uchar *buf); 2966 : : + int binlog_update_row(TABLE* table, Event_log *bin_log, 2967 : : + binlog_cache_data *cache_data, bool is_transactional, 2968 : : + enum_binlog_row_image row_image, 2969 : : const uchar *old_data, const uchar *new_data); 2970 : : bool prepare_handlers_for_update(uint flag); 2971 : : bool binlog_write_annotated_row(Log_event_writer *writer); 2972 : : void binlog_prepare_for_row_logging(); 2973 : : bool binlog_write_table_maps(); 2974 : : 2975 : 70749 : void set_server_id(uint32 sid) { variables.server_id = sid; } 2976 : : 2977 : : /* 2978 : : Member functions to handle pending event for row-level logging. 2979 : : */ 2980 : : + binlog_cache_mngr *binlog_get_cache_mngr() const; 2981 : 5263740 : inline int binlog_flush_pending_rows_event(bool stmt_end) 2982 : : { 2983 : 10527486 : return (binlog_flush_pending_rows_event(stmt_end, FALSE) || 2984 : 10527486 : binlog_flush_pending_rows_event(stmt_end, TRUE)); 2985 : : } 2986 : : int binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional); 2987 : : 2988 : 421523 : bool binlog_need_stmt_format(bool is_transactional) const 2989 : : { 2990 : 421734 : return log_current_statement() && 2991 : 212 : + !binlog_get_pending_rows_event(binlog_get_cache_mngr(), 2992 : 421732 : + use_trans_cache(this, is_transactional)); 2993 : : } 2994 : : 2995 : : bool binlog_for_noop_dml(bool transactional_table); 4158 : : { 4159 : 1158066 : return !stmt_arena->is_stmt_prepare(); 4160 : : } 4161 : 0 : + inline void* trans_alloc(size_t size) const 4162 : : { 4163 : 0 : return alloc_root(&transaction->mem_root,size); 4164 : : } 4165 : : 4166 : 8180862 : + LEX_CSTRING strmake_lex_cstring(const char *str, size_t length) const 4167 : : { 4168 : 8180862 : const char *tmp= strmake_root(mem_root, str, length); 4169 : 8180856 : if (!tmp) 4170 : 0 : return {0,0}; 4171 : 8180856 : return {tmp, length}; 4172 : : } 4173 : 8180866 : + LEX_CSTRING strmake_lex_cstring(const LEX_CSTRING &from) const 4174 : : { 4175 : 8180866 : return strmake_lex_cstring(from.str, from.length); 4176 : : } 4177 : : 4178 : 61978 : + LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, 4179 : : + size_t length) const 4180 : : { 4181 : 61978 : if (!(lex_str->str= strmake_root(mem_root, str, length))) 4182 : : { 4186 : 61976 : lex_str->length= length; 4187 : 61976 : return lex_str; 4188 : : } 4189 : 26746624 : + LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str, const char* str, 4190 : : + size_t length) const 4191 : : { 4192 : 26746624 : if (!(lex_str->str= strmake_root(mem_root, str, length))) 4193 : : { 4198 : 26746756 : return lex_str; 4199 : : } 4200 : : // Remove double quotes: aaa""bbb -> aaa"bbb 4201 : 9585902 : + bool quote_unescape(LEX_CSTRING *dst, const LEX_CSTRING *src, 4202 : : + char quote) const 4203 : : { 4204 : 9585902 : const char *tmp= src->str; 4205 : 9585902 : const char *tmpend= src->str + src->length; 4219 : 9585936 : return false; 4220 : : } 4221 : : 4222 : 7556018 : + LEX_CSTRING *make_clex_string(const char* str, size_t length) const 4223 : : { 4224 : : LEX_CSTRING *lex_str; 4225 : : char *tmp; 4234 : 7556018 : lex_str->length= length; 4235 : 7556018 : return lex_str; 4236 : : } 4237 : 11 : + LEX_CSTRING *make_clex_string(const LEX_CSTRING from) const 4238 : : { 4239 : 11 : return make_clex_string(from.str, from.length); 4240 : : } 4241 : : 4242 : : // Allocate LEX_STRING for character set conversion 4243 : 7215882 : + bool alloc_lex_string(LEX_STRING *dst, size_t length) const 4244 : : { 4245 : 7215882 : if (likely((dst->str= (char*) alloc(length)))) 4246 : 7215906 : return false; 4249 : : } 4250 : : bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs, 4251 : : const char *from, size_t from_length, 4252 : : + CHARSET_INFO *from_cs) const; 4253 : : bool reinterpret_string_from_binary(LEX_CSTRING *to, CHARSET_INFO *to_cs, 4254 : : + const char *from, size_t from_length) 4255 : : + const; 4256 : 1247723 : bool convert_string(LEX_CSTRING *to, CHARSET_INFO *to_cs, 4257 : : const char *from, size_t from_length, 4258 : : + CHARSET_INFO *from_cs) const 4259 : : { 4260 : 1247723 : LEX_STRING tmp; 4261 : 1247723 : bool rc= convert_string(&tmp, to_cs, from, from_length, from_cs); 4265 : : } 4266 : 6933838 : bool convert_string(LEX_CSTRING *to, CHARSET_INFO *tocs, 4267 : : const LEX_CSTRING *from, CHARSET_INFO *fromcs, 4268 : : + bool simple_copy_is_possible) const 4269 : : { 4270 : 6933838 : if (!simple_copy_is_possible) 4271 : 1247724 : return unlikely(convert_string(to, tocs, from->str, from->length, fromcs)); 4281 : : */ 4282 : : bool convert_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, 4283 : : CHARSET_INFO *srccs, const char *src, size_t src_length, 4284 : : + String_copier *status) const; 4285 : : 4286 : : /* 4287 : : Same as above, but additionally sends ER_INVALID_CHARACTER_STRING 4289 : : */ 4290 : : bool convert_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, 4291 : : CHARSET_INFO *srccs, 4292 : : + const char *src, size_t src_length) const; 4293 : : /* 4294 : : If either "dstcs" or "srccs" is &my_charset_bin, 4295 : : then performs native copying using copy_fix(). 4297 : : */ 4298 : : bool copy_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, 4299 : : CHARSET_INFO *srccs, const char *src, size_t src_length, 4300 : : + String_copier *status) const; 4301 : : 4302 : : /* 4303 : : Same as above, but additionally sends ER_INVALID_CHARACTER_STRING 4304 : : in case of bad byte sequences or Unicode conversion problems. 4305 : : */ 4306 : : bool copy_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, 4307 : : + CHARSET_INFO *srccs, const char *src, size_t src_length) 4308 : : + const; 4309 : : 4310 : : + bool convert_string(String *s, CHARSET_INFO *from_cs, 4311 : : + CHARSET_INFO *to_cs); 4312 : : 4313 : : /* 4314 : : Check if the string is wellformed, raise an error if not wellformed. 4319 : : size_t length, 4320 : : CHARSET_INFO *cs) const; 4321 : : 4322 : : + bool to_ident_sys_alloc(Lex_ident_sys_st *to, 4323 : : + const Lex_ident_cli_st *from) const; 4324 : : 4325 : : /* 4326 : : Create a string literal with optional client->connection conversion. 4330 : : */ 4331 : : Item_basic_constant *make_string_literal(const char *str, size_t length, 4332 : : my_repertoire_t repertoire); 4333 : : + Item_basic_constant * 4334 : 12017458 : + make_string_literal(const Lex_string_with_metadata_st &str) 4335 : : { 4336 : 12017458 : my_repertoire_t repertoire= str.repertoire(variables.character_set_client); 4337 : 12017137 : return make_string_literal(str.str, str.length, repertoire); 5574 : : Item *sp_prepare_func_item(Item **it_addr, uint cols); 5575 : : bool sp_eval_expr(Field *result_field, Item **expr_item_ptr); 5576 : : 5577 : : + ilist online_alter_cache_list; 5578 : : + 5579 : : bool sql_parser(LEX *old_lex, LEX *lex, 5580 : : char *str, uint str_len, bool stmt_prepare_mode); 5581 : : 7579 : 106541 : return table->s->long_unique_table; 7580 : : } 7581 : : 7582 : : +/** 7583 : : + Return whether the handler is root. 7584 : : + @return false if table is maintained by different handlerton, true otherwise. 7585 : : + @note The implementation supposes that the same handler can't be found as both 7586 : : + root and non-root. 7587 : : + 7588 : : + There are two known cases when it's non-root: 7589 : : + 1. under partition's ha_write_row() (also true for copy_partitions()) 7590 : : + 2. under ha_mroonga::wrapper_write_row(); 7591 : : + same applies for ha_delete_row/ha_update_row. 7592 : : +*/ 7593 : 2464 : +inline bool handler::is_root_handler() const 7594 : : +{ 7595 : 2464 : + return ht == table->file->ht; 7596 : : +} 7597 : : + 7598 : : extern pthread_attr_t *get_connection_attrib(void); 7599 : : 7600 : : /** 7648 : 4580158 : len >= opt_bin_log_compress_min_len; 7649 : : } 7650 : : 7651 : : +void binlog_prepare_row_images(TABLE* table, 7652 : : + enum_binlog_row_image row_image); 7653 : : 7654 : : /** 7655 : : Save thd sql_mode on instantiation. ===== File: sql/sql_lex.cc ===== 9683 : : } 9684 : : 9685 : : 9686 : 10980555 : +bool Lex_ident_sys_st::copy_ident_cli(const THD *thd, const Lex_ident_cli_st *str) 9687 : : { 9688 : 10980555 : return thd->to_ident_sys_alloc(this, str); 9689 : : } 9690 : : 9691 : 10825630 : +bool Lex_ident_sys_st::copy_keyword(const THD *thd, const Lex_ident_cli_st *str) 9692 : : { 9693 : 21651394 : return thd->make_lex_string(static_cast(this), 9694 : 10825630 : str->str, str->length) == NULL; 9695 : : } 9696 : : 9697 : 10721512 : +bool Lex_ident_sys_st::copy_or_convert(const THD *thd, 9698 : : const Lex_ident_cli_st *src, 9699 : : CHARSET_INFO *cs) 9700 : : { 9704 : : } 9705 : : 9706 : : 9707 : 14913388 : +bool Lex_ident_sys_st::copy_sys(const THD *thd, const LEX_CSTRING *src) 9708 : : { 9709 : 14913388 : if (thd->check_string_for_wellformedness(src->str, src->length, 9710 : : system_charset_info)) 9713 : : } 9714 : : 9715 : : 9716 : 5849011 : +bool Lex_ident_sys_st::convert(const THD *thd, 9717 : : const LEX_CSTRING *src, CHARSET_INFO *cs) 9718 : : { 9719 : 5849011 : LEX_STRING tmp; ===== File: sql/sql_lex.h ===== 148 : : struct Lex_ident_sys_st: public LEX_CSTRING 149 : : { 150 : : public: 151 : : + bool copy_ident_cli(const THD *thd, const Lex_ident_cli_st *str); 152 : : + bool copy_keyword(const THD *thd, const Lex_ident_cli_st *str); 153 : : + bool copy_sys(const THD *thd, const LEX_CSTRING *str); 154 : : + bool convert(const THD *thd, const LEX_CSTRING *str, CHARSET_INFO *cs); 155 : : + bool copy_or_convert(const THD *thd, const Lex_ident_cli_st *str, 156 : : + CHARSET_INFO *cs); 157 : 10656023 : bool is_null() const { return str == NULL; } 158 : : bool to_size_number(ulonglong *to) const; 159 : 137 : void set_valid_utf8(const LEX_CSTRING *name) 168 : : class Lex_ident_sys: public Lex_ident_sys_st 169 : : { 170 : : public: 171 : 10979285 : + Lex_ident_sys(const THD *thd, const Lex_ident_cli_st *str) 172 : 10979285 : { 173 : 10979285 : if (copy_ident_cli(thd, str)) 174 : 0 : ((LEX_CSTRING &) *this)= null_clex_str; ===== File: sql/sql_parse.cc ===== 4898 : : } 4899 : : else 4900 : : { 4901 : 2492 : if (thd->variables.query_cache_wlock_invalidate) 4902 : 5 : + query_cache_invalidate_locked_for_write(thd, first_table); 4903 : 2492 : my_ok(thd); 4904 : : } 4905 : 2544 : break; ===== File: sql/sql_table.cc ===== 55 : : #include "sql_audit.h" 56 : : #include "sql_sequence.h" 57 : : #include "tztime.h" 58 : : +#include "rpl_rli.h" 59 : : #include "sql_insert.h" // binlog_drop_table 60 : : #include "ddl_log.h" 61 : : #include "debug.h" // debug_crash_here() 86 : : List &, bool, uint, ORDER *, 87 : : ha_rows *, ha_rows *, 88 : : Alter_info::enum_enable_or_disable, 89 : : + Alter_table_ctx *, bool, uint64); 90 : : static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, 91 : : Key *key); 92 : : static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *, 4325 : : { 4326 : 3245 : if (key->type == Key::FOREIGN_KEY) 4327 : : { 4328 : 2 : + my_error(ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING, MYF(0), 4329 : : "FOREIGN KEY"); 4330 : 2 : goto err; 4331 : : } 9847 : : } 9848 : : 9849 : : 9850 : : +static 9851 : 72056 : +bool online_alter_check_autoinc(const THD *thd, const Alter_info *alter_info, 9852 : : + const TABLE *table) 9853 : : +{ 9854 : : + /* 9855 : : + We can't go online, if all of the following is presented: 9856 : : + * Autoinc is added to existing field 9857 : : + * Disabled NO_AUTO_VALUE_ON_ZERO 9858 : : + * No non-nullable unique key in the old table, that has all the key parts 9859 : : + remaining unchanged. 9860 : : + */ 9861 : : + 9862 : : + // Exit earlier when possible 9863 : 72056 : + if (thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) 9864 : 4 : + return true; 9865 : 72052 : + if ((alter_info->flags | ALTER_CHANGE_COLUMN) != alter_info->flags) 9866 : 65545 : + return true; 9867 : : + 9868 : : + /* 9869 : : + Find at least one unique index (without NULLs), all columns of which 9870 : : + remain in the table unchanged to presume it's a safe ALTER TABLE. 9871 : : + */ 9872 : 7355 : + for (uint k= 0; k < table->s->keys; k++) 9873 : : + { 9874 : 5572 : + const KEY &key= table->key_info[k]; 9875 : 5572 : + if ((key.flags & HA_NOSAME) == 0 || key.flags & HA_NULL_PART_KEY) 9876 : 586 : + continue; 9877 : 4986 : + bool key_parts_good= true; 9878 : 14290 : + for (uint kp= 0; kp < key.user_defined_key_parts && key_parts_good; kp++) 9879 : : + { 9880 : 9304 : + const Field *f= key.key_part[kp].field; 9881 : : + // tmp_set contains dropped fields after mysql_prepare_alter_table 9882 : 9304 : + key_parts_good= !bitmap_is_set(&table->tmp_set, f->field_index); 9883 : : + 9884 : 9304 : + if (key_parts_good) 9885 : 24520 : + for (const auto &c: alter_info->create_list) 9886 : 16906 : + if (c.field == f) 9887 : : + { 9888 : 9295 : + key_parts_good= f->is_equal(c); 9889 : 9295 : + break; 9890 : : + } 9891 : : + } 9892 : 4986 : + if (key_parts_good) 9893 : 4724 : + return true; 9894 : : + } 9895 : : + 9896 : 14549 : + for (const auto &c: alter_info->create_list) 9897 : : + { 9898 : 6425 : + if (c.flags & AUTO_INCREMENT_FLAG) 9899 : : + { 9900 : 42 : + if (c.field && !(c.field->flags & AUTO_INCREMENT_FLAG)) 9901 : 34 : + return false; 9902 : 8 : + break; 9903 : : + } 9904 : : + } 9905 : 1749 : + return true; 9906 : : +} 9907 : : + 9908 : : +static 9909 : 72784 : +const char *online_alter_check_supported(const THD *thd, 9910 : : + const Alter_info *alter_info, 9911 : : + const TABLE *table, 9912 : : + const TABLE *new_table, bool *online) 9913 : : +{ 9914 : 72784 : + DBUG_ASSERT(*online); 9915 : : + 9916 : 72784 : + *online= thd->locked_tables_mode != LTM_LOCK_TABLES && !table->s->tmp_table; 9917 : 72784 : + if (!*online) 9918 : 458 : + return NULL; 9919 : : + 9920 : 72326 : + *online= (new_table->file->ha_table_flags() & HA_NO_ONLINE_ALTER) == 0; 9921 : 72328 : + if (!*online) 9922 : 15 : + return new_table->file->engine_name()->str; 9923 : : + 9924 : 72313 : + *online= table->s->sequence == NULL; 9925 : 72313 : + if (!*online) 9926 : 9 : + return "SEQUENCE"; 9927 : : + 9928 : 72304 : + *online= (alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING) == 0; 9929 : 72304 : + if (!*online) 9930 : 35 : + return "DROP SYSTEM VERSIONING"; 9931 : : + 9932 : 72269 : + *online= !thd->lex->ignore; 9933 : 72269 : + if (!*online) 9934 : 132 : + return "ALTER IGNORE TABLE"; 9935 : : + 9936 : 72137 : + *online= !table->versioned(VERS_TRX_ID); 9937 : 72136 : + if (!*online) 9938 : 12 : + return "BIGINT GENERATED ALWAYS AS ROW_START"; 9939 : : + 9940 : 72124 : + List fk_list; 9941 : 72124 : + table->file->get_foreign_key_list(thd, &fk_list); 9942 : 72147 : + for (auto &fk: fk_list) 9943 : : + { 9944 : 72 : + if (fk_modifies_child(fk.delete_method) || 9945 : 29 : + fk_modifies_child(fk.update_method)) 9946 : : + { 9947 : 21 : + *online= false; 9948 : : + // Don't fall to a common unsupported case to avoid heavy string ops. 9949 : 21 : + if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) 9950 : : + { 9951 : 6 : + return fk_modifies_child(fk.delete_method) 9952 : 20 : + ? thd->strcat({STRING_WITH_LEN("ON DELETE ")}, 9953 : 2 : + *fk_option_name(fk.delete_method)).str 9954 : 8 : + : thd->strcat({STRING_WITH_LEN("ON UPDATE ")}, 9955 : 10 : + *fk_option_name(fk.update_method)).str; 9956 : : + } 9957 : 15 : + return NULL; 9958 : : + } 9959 : : + } 9960 : : + 9961 : 310012 : + for (auto &c: alter_info->create_list) 9962 : : + { 9963 : 237956 : + *online= c.field || !(c.flags & AUTO_INCREMENT_FLAG); 9964 : 237956 : + if (!*online) 9965 : 43 : + return "ADD COLUMN ... AUTO_INCREMENT"; 9966 : : + 9967 : 237913 : + auto *def= c.default_value; 9968 : 237924 : + *online= !(def && def->flags & VCOL_NEXTVAL 9969 : : + // either it's a new field, or a NULL -> NOT NULL change 9970 : 11 : + && (!c.field || (!(c.field->flags & NOT_NULL_FLAG) 9971 : 8 : + && (c.flags & NOT_NULL_FLAG)))); 9972 : 237913 : + if (!*online) 9973 : : + { 9974 : 5 : + if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_NONE) 9975 : 1 : + return NULL; // Avoid heavy string op 9976 : 4 : + const char *fmt= ER_THD(thd, ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED); 9977 : : + 9978 : 4 : + LEX_CSTRING dflt{STRING_WITH_LEN("DEFAULT")}; 9979 : 4 : + LEX_CSTRING nxvl{STRING_WITH_LEN("NEXTVAL()")}; 9980 : 4 : + size_t len= strlen(fmt) + nxvl.length + c.field_name.length + dflt.length; 9981 : 4 : + char *resp= (char*)thd->alloc(len); 9982 : : + // expression %s cannot be used in the %s clause of %`s 9983 : 4 : + my_snprintf(resp, len, fmt, nxvl.str, dflt.str, c.field_name.str); 9984 : 4 : + return resp; 9985 : : + } 9986 : : + } 9987 : : + 9988 : 72056 : + *online= online_alter_check_autoinc(thd, alter_info, table); 9989 : 72056 : + if (!*online) 9990 : 34 : + return "CHANGE COLUMN ... AUTO_INCREMENT"; 9991 : : + 9992 : 72022 : + return NULL; 9993 : : +} 9994 : : + 9995 : : + 9996 : : /** 9997 : : Alter table 9998 : : 10085 : 124912 : MDL_request target_mdl_request; 10086 : 124860 : MDL_ticket *mdl_ticket= 0; 10087 : 124860 : Alter_table_prelocking_strategy alter_prelocking_strategy; 10088 : : +#ifdef HAVE_REPLICATION 10089 : 124862 : + bool online= order == NULL && !opt_bootstrap; 10090 : : +#else 10091 : : + bool online= false; 10092 : : +#endif 10093 : 124890 : TRIGGER_RENAME_PARAM trigger_param; 10094 : : 10095 : : /* 10172 : : */ 10173 : 124907 : table_list->required_type= TABLE_TYPE_NORMAL; 10174 : : 10175 : 249746 : + if ((alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_DEFAULT 10176 : 122043 : + && (thd->variables.old_behavior & OLD_MODE_LOCK_ALTER_TABLE_COPY)) 10177 : 124929 : + || alter_info->requested_lock > Alter_info::ALTER_TABLE_LOCK_NONE 10178 : 122422 : + || thd->lex->sql_command == SQLCOM_OPTIMIZE 10179 : 249814 : + || alter_info->algorithm(thd) > Alter_info::ALTER_TABLE_ALGORITHM_COPY) 10180 : 8101 : + online= false; 10181 : : + 10182 : 124839 : + if (online) 10183 : : + { 10184 : 116276 : + table_list->lock_type= TL_READ; 10185 : : + } 10186 : : + 10187 : 124839 : DEBUG_SYNC(thd, "alter_table_before_open_tables"); 10188 : : 10189 : 124836 : thd->open_options|= HA_OPEN_FOR_ALTER; 10214 : : 10215 : 122334 : table= table_list->table; 10216 : 122334 : bool is_reg_table= table->s->tmp_table == NO_TMP_TABLE; 10217 : : + 10218 : : #ifdef WITH_WSREP 10219 : 122330 : if (WSREP(thd) && 10220 : 230 : (thd->lex->sql_command == SQLCOM_ALTER_TABLE || 10275 : : a new one if needed. 10276 : : */ 10277 : 0 : table->s->tdc->flushed= 1; // Force close of all instances 10278 : 0 : + if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_EXCLUSIVE, 10279 : 0 : thd->variables.lock_wait_timeout)) 10280 : 0 : DBUG_RETURN(1); 10281 : 0 : quick_rm_table(thd, table->file->ht, &table_list->db, 10284 : 0 : goto end_inplace; 10285 : : } 10286 : 244574 : if (!if_exists && 10287 : 122284 : + (table->file->partition_ht()->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)) 10288 : : { 10289 : : /* 10290 : : Table is a shared table that may not exist on the slave. 10714 : : #endif 10715 : : 10716 : : /* 10717 : : + We can use only copy algorithm if one of the following is true: 10718 : : + - In-place is impossible for given operation. 10719 : : - Changes to partitioning which were not handled by fast_alter_part_table() 10720 : : needs to be handled using table copying algorithm unless the engine 10721 : : supports auto-partitioning as such engines can do some changes 10722 : : using in-place API. 10723 : : */ 10724 : 110911 : + if (is_inplace_alter_impossible(table, create_info, alter_info) 10725 : 110895 : || IF_PARTITIONING((partition_changed && 10726 : : + !(old_db_type->partition_flags() & HA_USE_AUTO_PARTITION)), 0)) 10727 : : { 10728 : 4497 : + if (alter_info->algorithm_is_nocopy(thd)) 10729 : : { 10730 : 16 : my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), 10731 : : + alter_info->algorithm_clause(thd), "ALGORITHM=COPY"); 10732 : 16 : DBUG_RETURN(true); 10733 : : } 10734 : : + 10735 : 4481 : + alter_info->set_requested_algorithm(Alter_info::ALTER_TABLE_ALGORITHM_COPY); 10736 : : } 10737 : : 10738 : : /* 10974 : : } 10975 : : 10976 : 182813 : if (alter_info->supports_algorithm(thd, &ha_alter_info) || 10977 : 90955 : + alter_info->supports_lock(thd, online, &ha_alter_info)) 10978 : : { 10979 : 927 : cleanup_table_after_inplace_alter(&altered_table); 10980 : 927 : goto err_new_table_cleanup; 11032 : : 11033 : 75915 : if (!table->s->tmp_table) 11034 : : { 11035 : : // If EXCLUSIVE lock is requested, upgrade already. 11036 : 75485 : if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE && 11037 : 9 : wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) 11089 : 75736 : DEBUG_SYNC(thd, "alter_table_intermediate_table_created"); 11090 : : 11091 : : /* Open the table since we need to copy the data. */ 11092 : 75736 : + new_table= thd->create_and_open_tmp_table(&frm, alter_ctx.get_tmp_path(), 11093 : : alter_ctx.new_db.str, 11094 : : + alter_ctx.new_name.str, true); 11095 : 75735 : if (!new_table) 11096 : 0 : goto err_new_table_cleanup; 11097 : : 11101 : 422 : thd->session_tracker.state_change.mark_as_changed(thd); 11102 : : } 11103 : : 11104 : 75735 : + if (online) 11105 : : + { 11106 : 72786 : + const char *reason= online_alter_check_supported(thd, alter_info, table, 11107 : : + new_table, 11108 : : + &online); 11109 : 72786 : + if (reason && 11110 : 290 : + alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) 11111 : : + { 11112 : 37 : + DBUG_ASSERT(!online); 11113 : 37 : + my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), 11114 : : + "LOCK=NONE", reason, "LOCK=SHARED"); 11115 : 37 : + goto err_new_table_cleanup; 11116 : : + } 11117 : : + } 11118 : : + 11119 : : /* 11120 : : Note: In case of MERGE table, we do not attach children. We do not 11121 : : copy data for MERGE tables. Only the children have data. 11173 : 0 : binlog_as_create_select= 1; 11174 : 0 : DBUG_ASSERT(new_table->file->row_logging); 11175 : 0 : new_table->mark_columns_needed_for_insert(); 11176 : 0 : + mysql_bin_log.write_table_map(thd, new_table, 1); 11177 : : } 11178 : 75600 : if (copy_data_between_tables(thd, table, new_table, 11179 : 75604 : alter_info->create_list, ignore, 11180 : : order_num, order, &copied, &deleted, 11181 : : alter_info->keys_onoff, 11182 : : + &alter_ctx, online, start_alter_id)) 11183 : 6368 : goto err_new_table_cleanup; 11184 : : } 11185 : : else 11673 : 76121 : DBUG_RETURN(error); 11674 : : } 11675 : : 11676 : : +#ifdef HAVE_REPLICATION 11677 : : +/* 11678 : : + locking ALTER TABLE doesn't issue ER_NO_DEFAULT_FOR_FIELD, so online 11679 : : + ALTER shouldn't either 11680 : : +*/ 11681 : : +class Has_default_error_handler : public Internal_error_handler 11682 : : +{ 11683 : : +public: 11684 : 62 : + bool handle_condition(THD *, uint sql_errno, const char *, 11685 : : + Sql_condition::enum_warning_level *, 11686 : : + const char *, Sql_condition **) 11687 : : + { 11688 : 62 : + return sql_errno == ER_NO_DEFAULT_FOR_FIELD; 11689 : : + } 11690 : : +}; 11691 : : + 11692 : : + 11693 : 71571 : +static int online_alter_read_from_binlog(THD *thd, rpl_group_info *rgi, 11694 : : + Cache_flip_event_log *log, 11695 : : + ha_rows *found_rows) 11696 : : +{ 11697 : 71571 : + int error= 0; 11698 : : + 11699 : 71571 : + IO_CACHE *log_file= log->flip(); 11700 : : + 11701 : 71573 : + thd_progress_report(thd, 0, my_b_write_tell(log_file)); 11702 : : + 11703 : 71570 : + Has_default_error_handler hdeh; 11704 : 71567 : + thd->push_internal_handler(&hdeh); 11705 : : + do 11706 : : + { 11707 : 107589 : + const auto *descr_event= rgi->rli->relay_log.description_event_for_exec; 11708 : 107589 : + auto *ev= Log_event::read_log_event(log_file, descr_event, false, ~0UL); 11709 : 107588 : + error= log_file->error; 11710 : 107588 : + if (unlikely(!ev)) 11711 : : + { 11712 : 71555 : + if (error) 11713 : 0 : + my_error(ER_IO_READ_ERROR,MYF(0), (ulong)EIO, strerror(EIO), ""); 11714 : 71556 : + break; 11715 : : + } 11716 : 36033 : + DBUG_ASSERT(!error); 11717 : : + 11718 : 36033 : + ev->thd= thd; 11719 : 36033 : + error= ev->apply_event(rgi); 11720 : : + 11721 : 36035 : + error= error || thd->is_error(); 11722 : 36037 : + if(likely(!error)) 11723 : 36025 : + ev->online_alter_update_row_count(found_rows); 11724 : : + 11725 : 36036 : + if (ev != rgi->rli->relay_log.description_event_for_exec) 11726 : 243 : + delete ev; 11727 : 36036 : + thd_progress_report(thd, my_b_tell(log_file), thd->progress.max_counter); 11728 : 36036 : + DEBUG_SYNC(thd, "alter_table_online_progress"); 11729 : 36034 : + } while(!error); 11730 : 71568 : + thd->pop_internal_handler(); 11731 : : + 11732 : 143117 : + return MY_TEST(error); 11733 : 71557 : +} 11734 : : +#endif 11735 : : 11736 : : static int 11737 : 75603 : copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, 11738 : : + List &create, bool ignore, 11739 : : + uint order_num, ORDER *order, 11740 : : + ha_rows *copied, ha_rows *deleted, 11741 : : Alter_info::enum_enable_or_disable keys_onoff, 11742 : : + Alter_table_ctx *alter_ctx, bool online, 11743 : : + uint64 start_alter_id) 11744 : : { 11745 : 75603 : int error= 1; 11746 : 75603 : Copy_field *copy= NULL, *copy_end; 11765 : 75604 : MYSQL_TIME query_start; 11766 : : DBUG_ENTER("copy_data_between_tables"); 11767 : : 11768 : : + /* 11769 : : + if ORDER BY: sorting 11770 : : + always: copying, building indexes. 11771 : : + if online: reading up the binlog (second binlog is being written) 11772 : : + reading up the second binlog under exclusive lock 11773 : : + */ 11774 : 75604 : + thd_progress_init(thd, MY_TEST(order) + 2 + 2 * MY_TEST(online)); 11775 : : 11776 : 322523 : if (!(copy= new (thd->mem_root) Copy_field[to->s->fields])) 11777 : 0 : DBUG_RETURN(-1); 11811 : : Create_field *def; 11812 : 75600 : copy_end=copy; 11813 : 75600 : to->s->default_fields= 0; 11814 : 75600 : + error= 1; 11815 : 322435 : for (Field **ptr=to->field ; *ptr ; ptr++) 11816 : : { 11817 : 246874 : def=it++; 11930 : 75553 : if (!ignore) /* for now, InnoDB needs the undo log for ALTER IGNORE */ 11931 : 75397 : to->file->extra(HA_EXTRA_BEGIN_ALTER_COPY); 11932 : : 11933 : 75549 : + if (!(error= info.read_record())) 11934 : : { 11935 : : +#ifdef HAVE_REPLICATION 11936 : 44815 : + if (online) 11937 : : { 11938 : 42080 : + from->s->online_alter_binlog= new Cache_flip_event_log(); 11939 : 42080 : + if (!from->s->online_alter_binlog) 11940 : 0 : + goto err; 11941 : 42080 : + from->s->online_alter_binlog->init_pthread_objects(); 11942 : 42081 : + error= from->s->online_alter_binlog->open(WRITE_CACHE); 11943 : : 11944 : 42081 : + if (error) 11945 : : + { 11946 : 0 : + from->s->online_alter_binlog->release(); 11947 : 0 : + from->s->online_alter_binlog= NULL; 11948 : 0 : + goto err; 11949 : : + } 11950 : : 11951 : 42081 : + from->mdl_ticket->downgrade_lock(MDL_SHARED_UPGRADABLE); 11952 : 42080 : + DEBUG_SYNC(thd, "alter_table_online_downgraded"); 11953 : : } 11954 : : +#else 11955 : : + DBUG_ASSERT(!online); 11956 : : +#endif // HAVE_REPLICATION 11957 : : 11958 : : + do 11959 : : { 11960 : 10382380 : + if (unlikely(thd->killed)) 11961 : : + { 11962 : 0 : + thd->send_kill_message(); 11963 : 0 : + error= 1; 11964 : 0 : + break; 11965 : : + } 11966 : : 11967 : 10382380 : + if (make_unversioned) 11968 : : + { 11969 : 76 : + if (!from_row_end->is_max()) 11970 : 3 : + continue; // Drop history rows. 11971 : : + } 11972 : : 11973 : 10382377 : + if (unlikely(++thd->progress.counter >= time_to_report_progress)) 11974 : : + { 11975 : 10062 : + time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10; 11976 : 10062 : + thd_progress_report(thd, thd->progress.counter, 11977 : : + thd->progress.max_counter); 11978 : : + } 11979 : : 11980 : : + /* Return error if source table isn't empty. */ 11981 : 10382375 : + if (unlikely(alter_ctx->error_if_not_empty)) 11982 : : + { 11983 : 5 : + error= 1; 11984 : 5 : + break; 11985 : : + } 11986 : : 11987 : 33987659 : + for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++) 11988 : : + { 11989 : 23605294 : + copy_ptr->do_copy(copy_ptr); 11990 : : + } 11991 : : 11992 : 10382365 : + if (make_versioned) 11993 : : + { 11994 : 20527 : + to_row_start->set_notnull(); 11995 : 20527 : + to_row_start->store_time(&query_start); 11996 : 20527 : + to_row_end->set_max(); 11997 : : + } 11998 : : + 11999 : 10382365 : + prev_insert_id= to->file->next_insert_id; 12000 : 10382365 : + if (to->default_field) 12001 : 25907 : + to->update_default_fields(ignore); 12002 : 10382365 : + if (to->vfield) 12003 : 4185 : + to->update_virtual_fields(to->file, VCOL_UPDATE_FOR_WRITE); 12004 : : + 12005 : : + /* This will set thd->is_error() if fatal failure */ 12006 : 10382365 : + if (to->verify_constraints(ignore) == VIEW_CHECK_SKIP) 12007 : 1 : + continue; 12008 : 10382361 : + if (unlikely(thd->is_error())) 12009 : : { 12010 : 113 : error= 1; 12011 : 113 : + break; 12012 : : } 12013 : 10382243 : + if (keep_versioned && to->versioned(VERS_TRX_ID)) 12014 : 8 : + to->vers_write= false; 12015 : : + 12016 : 10382243 : + if (to->next_number_field) 12017 : : + { 12018 : 549957 : + if (auto_increment_field_copied) 12019 : 255342 : + to->auto_increment_field_not_null= TRUE; 12020 : : + else 12021 : 294615 : + to->next_number_field->reset(); 12022 : : + } 12023 : 10382243 : + error= to->file->ha_write_row(to->record[0]); 12024 : 10382250 : + to->auto_increment_field_not_null= FALSE; 12025 : 10382250 : + if (unlikely(error)) 12026 : : { 12027 : 6188 : + if (to->file->is_fatal_error(error, HA_CHECK_DUP)) 12028 : : { 12029 : : + /* Not a duplicate key error. */ 12030 : 2 : + to->file->print_error(error, MYF(0)); 12031 : 2 : + error= 1; 12032 : 2 : break; 12033 : : } 12034 : : else 12035 : : { 12036 : : + /* Duplicate key error. */ 12037 : 6183 : + if (unlikely(alter_ctx->fk_error_if_delete_row)) 12038 : : { 12039 : : + /* 12040 : : + We are trying to omit a row from the table which serves as parent 12041 : : + in a foreign key. This might have broken referential integrity so 12042 : : + emit an error. Note that we can't ignore this error even if we are 12043 : : + executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but 12044 : : + doesn't allow to break unique or foreign key constraints, 12045 : : + */ 12046 : 0 : + my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0), 12047 : : + alter_ctx->fk_error_id, 12048 : : + alter_ctx->fk_error_table); 12049 : 0 : + break; 12050 : : + } 12051 : : + 12052 : 6183 : + if (ignore) 12053 : : + { 12054 : : + /* This ALTER IGNORE TABLE. Simply skip row and continue. */ 12055 : 16 : + to->file->restore_auto_increment(prev_insert_id); 12056 : 16 : + delete_count++; 12057 : : } 12058 : : else 12059 : : + { 12060 : : + /* Ordinary ALTER TABLE. Report duplicate key error. */ 12061 : 6167 : + uint key_nr= to->file->get_dup_key(error); 12062 : 6171 : + if ((int) key_nr >= 0) 12063 : : + { 12064 : 6167 : + const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME); 12065 : 6167 : + if (key_nr == 0 && to->s->keys > 0 && 12066 : 135 : + (to->key_info[0].key_part[0].field->flags & 12067 : : + AUTO_INCREMENT_FLAG)) 12068 : 1 : + err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE); 12069 : 6167 : + print_keydup_error(to, 12070 : 6167 : + key_nr >= to->s->keys ? NULL : 12071 : 6168 : + &to->key_info[key_nr], 12072 : : + err_msg, MYF(0)); 12073 : : + } 12074 : : + else 12075 : 4 : + to->file->print_error(error, MYF(0)); 12076 : 6172 : + break; 12077 : : + } 12078 : : } 12079 : : } 12080 : : + else 12081 : : + { 12082 : : + /* In case of alter ignore, notify the engine about it. */ 12083 : 10376062 : + if (ignore) 12084 : 808 : + to->file->extra(HA_EXTRA_IGNORE_INSERT); 12085 : 10376062 : + DEBUG_SYNC(thd, "copy_data_between_tables_before"); 12086 : 10376054 : + found_count++; 12087 : 10376054 : + mysql_stage_set_work_completed(thd->m_stage_progress_psi, found_count); 12088 : : + } 12089 : 10376076 : + thd->get_stmt_da()->inc_current_row_for_warning(); 12090 : 10376078 : + } while (!(error= info.read_record())); 12091 : : } 12092 : : + else 12093 : 30747 : + online= false; 12094 : : + 12095 : 75558 : + DEBUG_SYNC(thd, "alter_table_copy_end"); 12096 : : 12097 : 75555 : THD_STAGE_INFO(thd, stage_enabling_keys); 12098 : 75557 : thd_progress_next_stage(thd); 12099 : : 12100 : 75558 : if (unlikely(to->file->ha_end_bulk_insert()) && error <= 0) 12101 : : { 12102 : : /* Give error, if not already given */ 12104 : 0 : to->file->print_error(my_errno,MYF(0)); 12105 : 10 : error= 1; 12106 : : } 12107 : : + 12108 : 75558 : bulk_insert_started= 0; 12109 : 75558 : if (!ignore) 12110 : 75403 : to->file->extra(HA_EXTRA_END_ALTER_COPY); 12112 : 75561 : cleanup_done= 1; 12113 : 75561 : to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); 12114 : : 12115 : : +#ifdef HAVE_REPLICATION 12116 : 75561 : + if (online && error < 0) 12117 : : + { 12118 : : + MEM_UNDEFINED(from->record[0], from->s->rec_buff_length * 2); 12119 : : + MEM_UNDEFINED(to->record[0], to->s->rec_buff_length * 2); 12120 : 35796 : + thd_progress_next_stage(thd); 12121 : 35797 : + enum_sql_command saved_sql_command= thd->lex->sql_command; 12122 : 35797 : + Table_map_log_event table_event(thd, from, from->s->table_map_id, 12123 : 35795 : + from->file->has_transactions()); 12124 : 35793 : + Relay_log_info rli(false); 12125 : 35794 : + rpl_group_info rgi(&rli); 12126 : 107385 : + RPL_TABLE_LIST rpl_table(to, TL_WRITE, from, table_event.get_table_def(), 12127 : 71589 : + copy, copy_end); 12128 : 35787 : + DBUG_ASSERT(to->pos_in_table_list == NULL); 12129 : 35787 : + to->pos_in_table_list= &rpl_table; 12130 : 35787 : + rgi.thd= thd; 12131 : 35787 : + rgi.tables_to_lock= &rpl_table; 12132 : : + 12133 : 35787 : + rgi.m_table_map.set_table(from->s->table_map_id, to); 12134 : : + 12135 : 35796 : + Cache_flip_event_log *binlog= from->s->online_alter_binlog; 12136 : 35796 : + DBUG_ASSERT(binlog->is_open()); 12137 : : + 12138 : 0 : + rli.relay_log.description_event_for_exec= 12139 : 35794 : + new Format_description_log_event(4); 12140 : : + 12141 : : + // We'll be filling from->record[0] from row events 12142 : 35796 : + bitmap_set_all(from->write_set); 12143 : : + // We restore bitmaps, because update event is going to mess up with them. 12144 : 35796 : + to->default_column_bitmaps(); 12145 : : + 12146 : 35795 : + end_read_record(&info); 12147 : 35789 : + init_read_record_done= false; 12148 : 35789 : + mysql_unlock_tables(thd, thd->lock); 12149 : 35796 : + thd->lock= NULL; 12150 : : + 12151 : 35796 : + error= online_alter_read_from_binlog(thd, &rgi, binlog, &found_count); 12152 : 35788 : + if (start_alter_id) 12153 : : + { 12154 : 879 : + DBUG_ASSERT(thd->slave_thread); 12155 : : + 12156 : 879 : + int rpl_error= wait_for_master(thd); 12157 : 879 : + if (rpl_error) 12158 : 0 : + error= 1; 12159 : : + } 12160 : : + 12161 : 35788 : + DEBUG_SYNC(thd, "alter_table_online_before_lock"); 12162 : : + 12163 : : + int lock_error= 12164 : 71582 : + thd->mdl_context.upgrade_shared_lock(from->mdl_ticket, MDL_EXCLUSIVE, 12165 : 35793 : + (double)thd->variables.lock_wait_timeout); 12166 : 35789 : + if (!error) 12167 : 35777 : + error= lock_error; 12168 : : + 12169 : 35789 : + if (!error) 12170 : : + { 12171 : 35767 : + thd_progress_next_stage(thd); 12172 : 35776 : + error= online_alter_read_from_binlog(thd, &rgi, binlog, &found_count); 12173 : : + } 12174 : 35796 : + if (error) 12175 : 21 : + from->s->tdc->flush_unused(1); // to free the binlog 12176 : 35795 : + to->pos_in_table_list= NULL; // Safety 12177 : 35795 : + DBUG_ASSERT(thd->lex->sql_command == saved_sql_command); 12178 : 35795 : + thd->lex->sql_command= saved_sql_command; // Just in case 12179 : 35795 : + } 12180 : 39765 : + else if (online) // error was on copy stage 12181 : : + { 12182 : : + /* 12183 : : + We can't free the resources properly now, as we can still be in 12184 : : + non-exclusive state. So this s->online_alter_binlog will be used 12185 : : + until all transactions will release it. 12186 : : + Once the transaction commits, it can release online_alter_binlog 12187 : : + by decreasing ref_count. 12188 : : + 12189 : : + online_alter_binlog->ref_count can be reached 0 only once. 12190 : : + Proof: 12191 : : + If share exists, we'll always have ref_count >= 1. 12192 : : + Once it reaches destroy(), nobody can acquire it again, 12193 : : + therefore, only release() is possible at this moment. 12194 : : + */ 12195 : 6285 : + from->s->tdc->flush_unused(1); // to free the binlog 12196 : : + } 12197 : : +#endif 12198 : : + 12199 : 75554 : + if (error > 0 && !from->s->tmp_table) 12200 : : + { 12201 : : + /* We are going to drop the temporary table */ 12202 : 6322 : + to->file->extra(HA_EXTRA_PREPARE_FOR_DROP); 12203 : : + } 12204 : : + 12205 : 75554 : DEBUG_SYNC(thd, "copy_data_between_tables_before_reset_backup_lock"); 12206 : 75551 : if (backup_reset_alter_copy_lock(thd)) 12207 : 1 : error= 1; 12213 : 75594 : if (bulk_insert_started) 12214 : 42 : (void) to->file->ha_end_bulk_insert(); 12215 : : 12216 : 75594 : if (init_read_record_done) 12217 : 39763 : end_read_record(&info); 12218 : 398083 : delete [] copy; ===== File: sql/sys_vars.cc ===== 3899 : : "UTF8_IS_UTF8MB3", 3900 : : "IGNORE_INDEX_ONLY_FOR_JOIN", 3901 : : "COMPAT_5_1_CHECKSUM", 3902 : : + "LOCK_ALTER_TABLE_COPY", 3903 : : 0 3904 : : }; 3905 : : ===== File: sql/table.cc ===== 505 : : } 506 : : } 507 : : 508 : : +#ifdef HAVE_REPLICATION 509 : 1606533 : + if (online_alter_binlog) 510 : : + { 511 : 42011 : + online_alter_binlog->release(); 512 : 42008 : + online_alter_binlog= NULL; 513 : : + } 514 : : +#endif 515 : : + 516 : : #ifdef WITH_PARTITION_STORAGE_ENGINE 517 : 1606530 : plugin_unlock(NULL, default_part_plugin); 518 : : #endif /* WITH_PARTITION_STORAGE_ENGINE */ 7689 : 907 : bitmap_set_bit(write_set, s->vers.end_fieldno); 7690 : 907 : need_signal= true; 7691 : : } 7692 : : +#ifdef HAVE_REPLICATION 7693 : 69044 : + if (s->online_alter_binlog) 7694 : : + { 7695 : : + /* 7696 : : + For online alter we have to read all columns, because we need PK columns 7697 : : + in the row event, and we don't know what columns will be in PK after ALTER 7698 : : + */ 7699 : 34 : + bitmap_set_all(read_set); 7700 : 34 : + need_signal= true; 7701 : : + } 7702 : : +#endif 7703 : : 7704 : 69044 : if (need_signal) 7705 : 46609 : file->column_bitmaps_signal(); 7786 : : For System Versioning we have to read all columns since we store 7787 : : a copy of previous row with modified row_end back to a table. 7788 : : */ 7789 : 1620 : + bitmap_set_all(read_set); 7790 : 1620 : need_signal= true; 7791 : : } 7792 : : +#ifdef HAVE_REPLICATION 7793 : 148110 : + if (s->online_alter_binlog) 7794 : : + { 7795 : : + /* 7796 : : + For online alter we have to read all columns, because we need PK columns 7797 : : + in the row event, and we don't know what columns will be in PK after ALTER 7798 : : + */ 7799 : 129 : + bitmap_set_all(read_set); 7800 : 129 : + need_signal= true; 7801 : : + } 7802 : : +#endif 7803 : 148110 : if (check_constraints) 7804 : : { 7805 : 112 : mark_check_constraint_columns_for_read(); 10616 : 122 : item->print(str, query_type); 10617 : 122 : } 10618 : : 10619 : 7938591 : +Field *TABLE::find_field_by_name(const LEX_CSTRING *str) const 10620 : : { 10621 : : Field **tmp; 10622 : 7938591 : size_t length= str->length; ===== File: sql/table.h ===== 66 : : class ACL_internal_schema_access; 67 : : class ACL_internal_table_access; 68 : : class Field; 69 : : +class Copy_field; 70 : : class Table_statistics; 71 : : class With_element; 72 : : struct TDC_element; 80 : : struct Name_resolution_context; 81 : : class Table_function_json_table; 82 : : class Open_table_context; 83 : : +class MYSQL_LOG; 84 : : 85 : : /* 86 : : Used to identify NESTED_JOIN structures within a join (applicable only to 934 : : plugin_ref default_part_plugin; 935 : : #endif 936 : : 937 : : +#ifdef HAVE_REPLICATION 938 : : + Cache_flip_event_log *online_alter_binlog; 939 : : +#endif 940 : : + 941 : : /** 942 : : System versioning and application-time periods support. 943 : : */ 1630 : : */ 1631 : : Item *notnull_cond; 1632 : : 1633 : : + online_alter_cache_data *online_alter_cache; 1634 : : + 1635 : 1167494 : inline void reset() { bzero((void*)this, sizeof(*this)); } 1636 : : void init(THD *thd, TABLE_LIST *tl); 1637 : : bool fill_item_list(List *item_list) const; 1817 : : bool with_cleanup); 1818 : : bool vcol_fix_expr(THD *thd); 1819 : : bool vcol_cleanup_expr(THD *thd); 1820 : : + Field *find_field_by_name(const LEX_CSTRING *str) const; 1821 : : bool export_structure(THD *thd, class Row_definition_list *defs); 1822 : 5674684 : bool is_splittable() { return spl_opt_info != NULL; } 1823 : : void set_spl_opt_info(SplM_opt_info *spl_info); 2360 : : mdl_type, MDL_TRANSACTION); 2361 : 1174099 : } 2362 : : 2363 : 170587 : + TABLE_LIST(const LEX_CSTRING *db_arg, 2364 : : + const LEX_CSTRING *table_name_arg, 2365 : : + const LEX_CSTRING *alias_arg, 2366 : : + enum thr_lock_type lock_type_arg) 2367 : 170587 : + { 2368 : 170578 : + init_one_table(db_arg, table_name_arg, alias_arg, lock_type_arg); 2369 : 170579 : + } 2370 : : + 2371 : 35797 : TABLE_LIST(TABLE *table_arg, thr_lock_type lock_type) 2372 : 35797 : + : TABLE_LIST(&table_arg->s->db, &table_arg->s->table_name, NULL, lock_type) 2373 : : { 2374 : 35793 : DBUG_ASSERT(table_arg->s); 2375 : 35794 : table= table_arg; 2376 : 35794 : vers_conditions.name= table->s->vers.name; 2377 : 35794 : } ===== File: sql/temporary_tables.cc ===== 627 : : table->s->db.str, table->s->table_name.str)); 628 : : 629 : : // close all handlers in case it is statement abort and some can be left 630 : 95259 : + table->file->ha_reset(); 631 : : 632 : 95265 : locked= lock_temporary_tables(); 633 : : ===== File: sql/transaction.cc ===== 550 : 870111 : DBUG_RETURN(FALSE); 551 : : } 552 : : 553 : : +/** Find a savepoint by name in a savepoint list */ 554 : 1394 : +SAVEPOINT** find_savepoint_in_list(THD *thd, LEX_CSTRING name, 555 : : + SAVEPOINT ** const list) 556 : : { 557 : 1394 : + SAVEPOINT **sv= list; 558 : : 559 : 2087 : while (*sv) 560 : : { 561 : 2269 : if (system_charset_info->strnncoll( 562 : 1135 : + (uchar *) name.str, name.length, 563 : 1135 : + (uchar *) (*sv)->name, (*sv)->length) == 0) 564 : 441 : break; 565 : 693 : sv= &(*sv)->prev; 566 : : } 568 : 1393 : return sv; 569 : : } 570 : : 571 : : +/* Find a named savepoint in the current transaction. */ 572 : : +static SAVEPOINT ** 573 : 453 : +find_savepoint(THD *thd, LEX_CSTRING name) 574 : : +{ 575 : 453 : + return find_savepoint_in_list(thd, name, &thd->transaction->savepoints); 576 : : +} 577 : : + 578 : 938 : +SAVEPOINT* savepoint_add(THD *thd, LEX_CSTRING name, SAVEPOINT **list, 579 : : + int (*release_old)(THD*, SAVEPOINT*)) 580 : : +{ 581 : : + DBUG_ENTER("savepoint_add"); 582 : : + 583 : 938 : + SAVEPOINT **sv= find_savepoint_in_list(thd, name, list); 584 : : + 585 : : + SAVEPOINT *newsv; 586 : : + 587 : 937 : + if (*sv) /* old savepoint of the same name exists */ 588 : : + { 589 : 9 : + newsv= *sv; 590 : 9 : + if (release_old){ 591 : 9 : + int error= release_old(thd, *sv); 592 : 9 : + if (error) 593 : 0 : + DBUG_RETURN(NULL); 594 : : + } 595 : 9 : + *sv= (*sv)->prev; 596 : : + } 597 : 928 : + else if ((newsv= (SAVEPOINT *) alloc_root(&thd->transaction->mem_root, 598 : 929 : + savepoint_alloc_size)) == NULL) 599 : : + { 600 : 0 : + my_error(ER_OUT_OF_RESOURCES, MYF(0)); 601 : 0 : + DBUG_RETURN(NULL); 602 : : + } 603 : : + 604 : 938 : + newsv->name= strmake_root(&thd->transaction->mem_root, name.str, name.length); 605 : 937 : + newsv->length= (uint)name.length; 606 : 937 : + DBUG_RETURN(newsv); 607 : : +} 608 : : 609 : : /** 610 : : Set a named transaction savepoint. 618 : : 619 : 936 : bool trans_savepoint(THD *thd, LEX_CSTRING name) 620 : : { 621 : : DBUG_ENTER("trans_savepoint"); 622 : : 623 : 1872 : if (!(thd->in_multi_stmt_transaction_mode() || thd->in_sub_stmt) || 627 : 936 : if (thd->transaction->xid_state.check_has_uncommitted_xa()) 628 : 2 : DBUG_RETURN(TRUE); 629 : : 630 : 934 : + SAVEPOINT *newsv= savepoint_add(thd, name, &thd->transaction->savepoints, 631 : : + ha_release_savepoint); 632 : : 633 : 933 : + if (newsv == NULL) 634 : 0 : DBUG_RETURN(TRUE); 635 : : 636 : : /* 637 : : if we'll get an error here, don't add new savepoint to the list. 641 : 933 : if (unlikely(ha_savepoint(thd, newsv))) 642 : 0 : DBUG_RETURN(TRUE); 643 : : 644 : 934 : + int error= online_alter_savepoint_set(thd, name); 645 : 934 : + if (unlikely(error)) 646 : 0 : + DBUG_RETURN(error); 647 : : + 648 : 934 : newsv->prev= thd->transaction->savepoints; 649 : 934 : thd->transaction->savepoints= newsv; 650 : : 704 : : ER_WARNING_NOT_COMPLETE_ROLLBACK, 705 : 41 : ER_THD(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK)); 706 : : 707 : 413 : + res= res || online_alter_savepoint_rollback(thd, name); 708 : : + 709 : 413 : thd->transaction->savepoints= sv; 710 : : 711 : 413 : if (res) ===== File: sql/wsrep_client_service.cc ===== 243 : 749928 : if (cache) 244 : : { 245 : 749922 : size_t pending_rows_event_length= 0; 246 : 749922 : + auto *cache_mngr= m_thd->binlog_get_cache_mngr(); 247 : 749922 : + if (auto* ev= binlog_get_pending_rows_event(cache_mngr, true)) 248 : : { 249 : 749898 : pending_rows_event_length= ev->get_data_size(); 250 : : } ===== File: sql/wsrep_mysqld.cc ===== 3463 : 4 : const THD* thd= ev->thd; 3464 : : 3465 : 4 : DBUG_ASSERT(error); 3466 : 4 : + DBUG_ASSERT(wsrep_thd_is_applying(thd)); 3467 : 4 : + DBUG_ASSERT(!wsrep_thd_is_local_toi(thd)); 3468 : : 3469 : 4 : if ((wsrep_ignore_apply_errors & WSREP_IGNORE_ERRORS_ON_RECONCILING_DML)) 3470 : : { ===== File: storage/connect/ha_connect.cc ===== 1174 : : // HA_FAST_KEY_READ | causes error when sorting (???) 1175 : : HA_NO_TRANSACTIONS | HA_DUPLICATE_KEY_NOT_IN_ORDER | 1176 : : HA_NO_BLOBS | HA_MUST_USE_TABLE_CONDITION_PUSHDOWN | 1177 : : + HA_REUSES_FILE_NAMES | HA_NO_ONLINE_ALTER; 1178 : 5802 : ha_connect *hp= (ha_connect*)this; 1179 : 5802 : PTOS pos= hp->GetTableOptionStruct(); 1180 : : ===== File: storage/innobase/handler/ha_innodb.cc ===== 15365 : : FOREIGN_KEY_INFO* 15366 : 4591 : get_foreign_key_info( 15367 : : /*=================*/ 15368 : : + const THD* thd, /*!< in: user thread handle */ 15369 : : dict_foreign_t* foreign)/*!< in: foreign key constraint */ 15370 : : { 15371 : 4591 : FOREIGN_KEY_INFO f_key_info; 15501 : : int 15502 : 7956 : ha_innobase::get_foreign_key_list( 15503 : : /*==============================*/ 15504 : : + const THD* thd, /*!< in: user thread handle */ 15505 : : List* f_key_list) /*!< out: foreign key list */ 15506 : : { 15507 : 7956 : update_thd(ha_thd()); 15539 : : int 15540 : 7616 : ha_innobase::get_parent_foreign_key_list( 15541 : : /*=====================================*/ 15542 : : + const THD* thd, /*!< in: user thread handle */ 15543 : : List* f_key_list) /*!< out: foreign key list */ 15544 : : { 15545 : 7616 : update_thd(ha_thd()); 16436 : 2761 : || sql_command == SQLCOM_REPLACE_SELECT 16437 : 2760 : || sql_command == SQLCOM_UPDATE 16438 : 2758 : || sql_command == SQLCOM_CREATE_SEQUENCE 16439 : 2758 : + || sql_command == SQLCOM_CREATE_TABLE)) 16440 : 2405374 : + || (trx->isolation_level == TRX_ISO_REPEATABLE_READ 16441 : 2354492 : + && sql_command == SQLCOM_ALTER_TABLE 16442 : 23326 : + && lock_type == TL_READ)) { 16443 : : 16444 : : /* If the transaction isolation level is 16445 : : READ UNCOMMITTED or READ COMMITTED and we are executing ===== File: storage/innobase/handler/ha_innodb.h ===== 213 : : 214 : : char* get_foreign_key_create_info() override; 215 : : 216 : : + int get_foreign_key_list(const THD *thd, 217 : : List *f_key_list) override; 218 : : 219 : : int get_parent_foreign_key_list( 220 : : + const THD* thd, 221 : : List* f_key_list) override; 222 : : 223 : : bool can_switch_engines() override; ===== File: storage/maria/ha_maria.cc ===== 2959 : : tons of archived logs to roll-forward, we could then not disable 2960 : : REDOs/UNDOs in this case. 2961 : : */ 2962 : 8127 : + if (likely(file->s->now_transactional)) 2963 : : + { 2964 : : + DBUG_PRINT("info", ("Disabling logging for table")); 2965 : 8127 : + _ma_tmp_disable_logging_for_table(file, TRUE); 2966 : : + } 2967 : 8127 : file->autocommit= 0; 2968 : : } 2969 : : else ===== File: storage/maria/ha_maria.h ===== 67 : 1657457 : ~ha_maria() = default; 68 : : handler *clone(const char *name, MEM_ROOT *mem_root) override final; 69 : : const char *index_type(uint key_number) override final; 70 : 6800029 : + ulonglong table_flags() const override 71 : 6800029 : { return int_table_flags; } 72 : : ulong index_flags(uint inx, uint part, bool all_parts) const override final; 73 : 58558 : uint max_supported_keys() const override final ===== File: storage/maria/ha_s3.cc ===== 238 : : /* Remove things that S3 doesn't support */ 239 : 0 : int_table_flags&= ~(HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | 240 : : HA_CAN_EXPORT); 241 : 0 : + int_table_flags|= HA_NO_ONLINE_ALTER; 242 : 0 : can_enable_indexes= 0; 243 : 0 : } 244 : : ===== File: storage/mroonga/ha_mroonga.cpp ===== 16676 : 0 : DBUG_RETURN(res); 16677 : : } 16678 : : 16679 : 8 : +int ha_mroonga::wrapper_get_foreign_key_list(const THD *thd, 16680 : : List *f_key_list) 16681 : : { 16682 : 8 : MRN_DBUG_ENTER_METHOD(); 16690 : : } 16691 : : 16692 : : #ifdef MRN_SUPPORT_FOREIGN_KEYS 16693 : 24 : +int ha_mroonga::storage_get_foreign_key_list(const THD *thd, 16694 : : List *f_key_list) 16695 : : { 16696 : 24 : int error; 16800 : : } 16801 : : #endif 16802 : : 16803 : 32 : +int ha_mroonga::get_foreign_key_list(const THD *thd, 16804 : : List *f_key_list) 16805 : : { 16806 : 32 : MRN_DBUG_ENTER_METHOD(); 16814 : 32 : DBUG_RETURN(res); 16815 : : } 16816 : : 16817 : 4 : +int ha_mroonga::wrapper_get_parent_foreign_key_list(const THD *thd, 16818 : : List *f_key_list) 16819 : : { 16820 : 4 : MRN_DBUG_ENTER_METHOD(); 16827 : 4 : DBUG_RETURN(res); 16828 : : } 16829 : : 16830 : 9 : +int ha_mroonga::storage_get_parent_foreign_key_list(const THD *thd, 16831 : : List *f_key_list) 16832 : : { 16833 : 9 : MRN_DBUG_ENTER_METHOD(); 16835 : 9 : DBUG_RETURN(res); 16836 : : } 16837 : : 16838 : 13 : +int ha_mroonga::get_parent_foreign_key_list(const THD *thd, 16839 : : List *f_key_list) 16840 : : { 16841 : 13 : MRN_DBUG_ENTER_METHOD(); ===== File: storage/mroonga/ha_mroonga.hpp ===== 621 : : char *get_tablespace_name(THD *thd, char *name, uint name_len); 622 : : #endif 623 : : bool can_switch_engines() mrn_override; 624 : : + int get_foreign_key_list(const THD *thd, List *f_key_list) mrn_override; 625 : : + int get_parent_foreign_key_list(const THD *thd, List *f_key_list) mrn_override; 626 : : uint referenced_by_foreign_key() mrn_override; 627 : : void init_table_handle_for_HANDLER() mrn_override; 628 : : void free_foreign_key_create_info(char* str) mrn_override; 1273 : : #endif 1274 : : bool wrapper_can_switch_engines(); 1275 : : bool storage_can_switch_engines(); 1276 : : + int wrapper_get_foreign_key_list(const THD *thd, List *f_key_list); 1277 : : + int storage_get_foreign_key_list(const THD *thd, List *f_key_list); 1278 : : + int wrapper_get_parent_foreign_key_list(const THD *thd, List *f_key_list); 1279 : : + int storage_get_parent_foreign_key_list(const THD *thd, List *f_key_list); 1280 : : uint wrapper_referenced_by_foreign_key(); 1281 : : uint storage_referenced_by_foreign_key(); 1282 : : void wrapper_init_table_handle_for_HANDLER();