diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_partition.cc | 17 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 2 | ||||
-rw-r--r-- | sql/opt_range.cc | 38 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 10 | ||||
-rw-r--r-- | sql/sql_class.cc | 48 | ||||
-rw-r--r-- | sql/sql_class.h | 40 | ||||
-rw-r--r-- | sql/sql_insert.cc | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 305 | ||||
-rw-r--r-- | sql/sql_table.cc | 30 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 6 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 6 | ||||
-rw-r--r-- | sql/wsrep_mysqld.cc | 15 | ||||
-rw-r--r-- | sql/wsrep_mysqld.h | 9 | ||||
-rw-r--r-- | sql/wsrep_sst.cc | 8 | ||||
-rw-r--r-- | sql/wsrep_thd.cc | 21 |
16 files changed, 342 insertions, 216 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 75f6585f847..090b26a036b 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4095,8 +4095,21 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type) /* Add partition to be called in reset(). */ bitmap_set_bit(&m_partitions_to_reset, i); } - if (lock_type == F_WRLCK && m_part_info->part_expr) - m_part_info->part_expr->walk(&Item::register_field_in_read_map, 1, 0); + switch (lock_type) + { + case TL_WRITE_ALLOW_WRITE: + case TL_WRITE_CONCURRENT_INSERT: + case TL_WRITE_DELAYED: + case TL_WRITE_DEFAULT: + case TL_WRITE_LOW_PRIORITY: + case TL_WRITE: + case TL_WRITE_ONLY: + if (m_part_info->part_expr) + m_part_info->part_expr->walk(&Item::register_field_in_read_map, 1, 0); + if (m_part_info->part_type == VERSIONING_PARTITION) + m_part_info->vers_set_hist_part(thd); + default:; + } DBUG_RETURN(error); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7151e8966ee..98da93ae699 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3176,7 +3176,7 @@ bool Item_func_pad::fix_length_and_dec() DBUG_ASSERT(collation.collation->mbmaxlen > 0); if (args[1]->const_item() && !args[1]->is_expensive()) { - fix_char_length(Repeat_count(args[1]).count()); + fix_char_length_ulonglong(Repeat_count(args[1]).count()); return false; } max_length= MAX_BLOB_WIDTH; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d0c4ed2ffbc..536dc0383a9 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2692,6 +2692,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, KEY_PART *key_parts; KEY *key_info; PARAM param; + bool force_group_by = false; if (check_stack_overrun(thd, 2*STACK_MIN_SIZE + sizeof(PARAM), buff)) DBUG_RETURN(0); // Fatal error flag is set @@ -2856,6 +2857,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, Try to construct a QUICK_GROUP_MIN_MAX_SELECT. Notice that it can be constructed no matter if there is a range tree. */ + DBUG_EXECUTE_IF("force_group_by", force_group_by = true; ); if (!only_single_index_range_scan) group_trp= get_best_group_min_max(¶m, tree, best_read_time); if (group_trp) @@ -2867,11 +2869,15 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, if (unlikely(thd->trace_started())) group_trp->trace_basic_info(¶m, &grp_summary); - if (group_trp->read_cost < best_read_time) + if (group_trp->read_cost < best_read_time || force_group_by) { grp_summary.add("chosen", true); best_trp= group_trp; best_read_time= best_trp->read_cost; + if (force_group_by) + { + goto force_plan; + } } else grp_summary.add("chosen", false).add("cause", "cost"); @@ -2977,6 +2983,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, } } +force_plan: thd->mem_root= param.old_root; /* If we got a read plan, create a quick select from it. */ @@ -12189,13 +12196,28 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, DBUG_ASSERT(cur_prefix != NULL); result= file->ha_index_read_map(record, cur_prefix, keypart_map, HA_READ_AFTER_KEY); - if (result || last_range->max_keypart_map == 0) - DBUG_RETURN(result); - - key_range previous_endpoint; - last_range->make_max_endpoint(&previous_endpoint, prefix_length, keypart_map); - if (file->compare_key(&previous_endpoint) <= 0) - DBUG_RETURN(0); + if (result || last_range->max_keypart_map == 0) { + /* + Only return if actual failure occurred. For HA_ERR_KEY_NOT_FOUND + or HA_ERR_END_OF_FILE, we just want to continue to reach the next + set of ranges. It is possible for the storage engine to return + HA_ERR_KEY_NOT_FOUND/HA_ERR_END_OF_FILE even when there are more + keys if it respects the end range set by the read_range_first call + below. + */ + if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE) + DBUG_RETURN(result); + } else { + /* + For storage engines that don't respect end range, check if we've + moved past the current range. + */ + key_range previous_endpoint; + last_range->make_max_endpoint(&previous_endpoint, prefix_length, + keypart_map); + if (file->compare_key(&previous_endpoint) <= 0) + DBUG_RETURN(0); + } } uint count= ranges.elements - (uint)(cur_range - (QUICK_RANGE**) ranges.buffer); diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c64f60f3562..13d2b0b0cff 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7931,3 +7931,5 @@ ER_PERIOD_CONSTRAINT_DROP eng "Can't DROP CONSTRAINT `%s`. Use DROP PERIOD `%s` for this" ER_TOO_LONG_KEYPART 42000 S1009 eng "Specified key part was too long; max key part length is %u bytes" +ER_VERS_NO_PERIOD + eng "No 'PERIOD FOR SYSTEM_TIME' in system-versioned %`s"
\ No newline at end of file diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 881f2662345..4cf9b152940 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2608,6 +2608,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) DBUG_ASSERT(thd->open_tables == m_reopen_array[reopen_count]); thd->open_tables->pos_in_locked_tables->table= NULL; + thd->open_tables->pos_in_locked_tables= NULL; close_thread_table(thd, &thd->open_tables); } @@ -8463,8 +8464,8 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values, rfield->field_index == table->next_number_field->field_index) table->auto_increment_field_not_null= TRUE; Item::Type type= value->type(); - bool vers_sys_field= table->versioned() && rfield->vers_sys_field(); - if ((rfield->vcol_info || vers_sys_field) && + const bool skip_sys_field= rfield->vers_sys_field(); // TODO: && !thd->vers_modify_history() [MDEV-16546] + if ((rfield->vcol_info || skip_sys_field) && type != Item::DEFAULT_VALUE_ITEM && type != Item::NULL_ITEM && table->s->table_category != TABLE_CATEGORY_TEMPORARY) @@ -8473,15 +8474,14 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN, ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN), rfield->field_name.str, table->s->table_name.str); - if (vers_sys_field) - continue; } if (only_unvers_fields && !rfield->vers_update_unversioned()) only_unvers_fields= false; if (rfield->stored_in_db()) { - if (unlikely(value->save_in_field(rfield, 0) < 0) && !ignore_errors) + if (!skip_sys_field && + unlikely(value->save_in_field(rfield, 0) < 0) && !ignore_errors) { my_message(ER_UNKNOWN_ERROR, ER_THD(thd, ER_UNKNOWN_ERROR), MYF(0)); goto err; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 64cfcb89ac6..363c5d35499 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4881,12 +4881,6 @@ extern "C" int thd_slave_thread(const MYSQL_THD thd) } -extern "C" int thd_rpl_stmt_based(const MYSQL_THD thd) -{ - return thd && - !thd->is_current_stmt_binlog_format_row() && - !thd->is_current_stmt_binlog_disabled(); -} /* Returns high resolution timestamp for the start @@ -6226,6 +6220,48 @@ int THD::decide_logging_format(TABLE_LIST *tables) DBUG_RETURN(0); } +int THD::decide_logging_format_low(TABLE *table) +{ + /* + INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys + can be unsafe. + */ + if(wsrep_binlog_format() <= BINLOG_FORMAT_STMT && + !is_current_stmt_binlog_format_row() && + !lex->is_stmt_unsafe() && + lex->sql_command == SQLCOM_INSERT && + lex->duplicates == DUP_UPDATE) + { + uint unique_keys= 0; + uint keys= table->s->keys, i= 0; + Field *field; + for (KEY* keyinfo= table->s->key_info; + i < keys && unique_keys <= 1; i++, keyinfo++) + if (keyinfo->flags & HA_NOSAME && + !(keyinfo->key_part->field->flags & AUTO_INCREMENT_FLAG && + //User given auto inc can be unsafe + !keyinfo->key_part->field->val_int())) + { + for (uint j= 0; j < keyinfo->user_defined_key_parts; j++) + { + field= keyinfo->key_part[j].field; + if(!bitmap_is_set(table->write_set,field->field_index)) + goto exit; + } + unique_keys++; +exit:; + } + + if (unique_keys > 1) + { + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS); + binlog_unsafe_warning_flags|= lex->get_stmt_unsafe_flags(); + set_current_stmt_binlog_format_row_if_mixed(); + return 1; + } + } + return 0; +} /* Implementation of interface to write rows to the binary log through the diff --git a/sql/sql_class.h b/sql/sql_class.h index 5fac4369623..2b46fc69365 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2437,6 +2437,20 @@ public: /* container for handler's private per-connection data */ Ha_data ha_data[MAX_HA]; + /** + Bit field for the state of binlog warnings. + + The first Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types of + unsafeness that the current statement has. + + This must be a member of THD and not of LEX, because warnings are + detected and issued in different places (@c + decide_logging_format() and @c binlog_query(), respectively). + Between these calls, the THD->lex object may change; e.g., if a + stored routine is invoked. Only THD persists between the calls. + */ + uint32 binlog_unsafe_warning_flags; + #ifndef MYSQL_CLIENT binlog_cache_mngr * binlog_setup_trx_data(); @@ -2546,20 +2560,6 @@ private: */ enum_binlog_format current_stmt_binlog_format; - /** - Bit field for the state of binlog warnings. - - The first Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types of - unsafeness that the current statement has. - - This must be a member of THD and not of LEX, because warnings are - detected and issued in different places (@c - decide_logging_format() and @c binlog_query(), respectively). - Between these calls, the THD->lex object may change; e.g., if a - stored routine is invoked. Only THD persists between the calls. - */ - uint32 binlog_unsafe_warning_flags; - /* Number of outstanding table maps, i.e., table maps in the transaction cache. @@ -4536,6 +4536,18 @@ public: } void leave_locked_tables_mode(); int decide_logging_format(TABLE_LIST *tables); + /* + In Some cases when decide_logging_format is called it does not have all + information to decide the logging format. So that cases we call decide_logging_format_2 + at later stages in execution. + One example would be binlog format for IODKU but column with unique key is not inserted. + We dont have inserted columns info when we call decide_logging_format so on later stage we call + decide_logging_format_low + + @returns 0 if no format is changed + 1 if there is change in binlog format + */ + int decide_logging_format_low(TABLE *table); enum need_invoker { INVOKER_NONE=0, INVOKER_USER, INVOKER_ROLE}; void binlog_invoker(bool role) { m_binlog_invoker= role ? INVOKER_ROLE : INVOKER_USER; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8db6aac6846..7825a7742ef 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1061,6 +1061,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, break; } + thd->decide_logging_format_low(table); #ifndef EMBEDDED_LIBRARY if (lock_type == TL_WRITE_DELAYED) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6e2b10b907e..b1336681ac4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -760,173 +760,39 @@ void vers_select_conds_t::print(String *str, enum_query_type query_type) const } } -static -Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select, - vers_select_conds_t *conds, bool timestamp) -{ - DBUG_ASSERT(table); - DBUG_ASSERT(table->table); -#define newx new (thd->mem_root) - TABLE_SHARE *share= table->table->s; - const TABLE_SHARE::period_info_t *period= conds->period; - - const LEX_CSTRING &fstart= period->start_field(share)->field_name; - const LEX_CSTRING &fend= period->end_field(share)->field_name; - - conds->field_start= newx Item_field(thd, &select->context, - table->db.str, table->alias.str, - thd->make_clex_string(fstart)); - conds->field_end= newx Item_field(thd, &select->context, - table->db.str, table->alias.str, - thd->make_clex_string(fend)); - - Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL; - if (timestamp) - { - MYSQL_TIME max_time; - switch (conds->type) - { - case SYSTEM_TIME_UNSPECIFIED: - thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); - max_time.second_part= TIME_MAX_SECOND_PART; - curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS); - cond1= newx Item_func_eq(thd, conds->field_end, curr); - break; - case SYSTEM_TIME_AS_OF: - cond1= newx Item_func_le(thd, conds->field_start, conds->start.item); - cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item); - break; - case SYSTEM_TIME_FROM_TO: - cond1= newx Item_func_lt(thd, conds->field_start, conds->end.item); - cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item); - cond3= newx Item_func_lt(thd, conds->start.item, conds->end.item); - break; - case SYSTEM_TIME_BETWEEN: - cond1= newx Item_func_le(thd, conds->field_start, conds->end.item); - cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item); - cond3= newx Item_func_le(thd, conds->start.item, conds->end.item); - break; - case SYSTEM_TIME_BEFORE: - cond1= newx Item_func_lt(thd, conds->field_end, conds->start.item); - break; - default: - DBUG_ASSERT(0); - } - } - else - { - DBUG_ASSERT(table->table->s && table->table->s->db_plugin); - - Item *trx_id0= conds->start.item; - Item *trx_id1= conds->end.item; - if (conds->start.item && conds->start.unit == VERS_TIMESTAMP) - { - bool backwards= conds->type != SYSTEM_TIME_AS_OF; - trx_id0= newx Item_func_trt_id(thd, conds->start.item, - TR_table::FLD_TRX_ID, backwards); - } - if (conds->end.item && conds->end.unit == VERS_TIMESTAMP) - { - trx_id1= newx Item_func_trt_id(thd, conds->end.item, - TR_table::FLD_TRX_ID, false); - } - - switch (conds->type) - { - case SYSTEM_TIME_UNSPECIFIED: - curr= newx Item_int(thd, ULONGLONG_MAX); - cond1= newx Item_func_eq(thd, conds->field_end, curr); - DBUG_ASSERT(!conds->start.item); - DBUG_ASSERT(!conds->end.item); - break; - case SYSTEM_TIME_AS_OF: - cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id0, conds->field_start); - cond2= newx Item_func_trt_trx_sees(thd, conds->field_end, trx_id0); - DBUG_ASSERT(!conds->end.item); - break; - case SYSTEM_TIME_FROM_TO: - cond1= newx Item_func_trt_trx_sees(thd, trx_id1, conds->field_start); - cond2= newx Item_func_trt_trx_sees_eq(thd, conds->field_end, trx_id0); - cond3= newx Item_func_lt(thd, conds->start.item, conds->end.item); - break; - case SYSTEM_TIME_BETWEEN: - cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id1, conds->field_start); - cond2= newx Item_func_trt_trx_sees_eq(thd, conds->field_end, trx_id0); - cond3= newx Item_func_le(thd, conds->start.item, conds->end.item); - break; - case SYSTEM_TIME_BEFORE: - cond1= newx Item_func_trt_trx_sees(thd, trx_id0, conds->field_end); - break; - default: - DBUG_ASSERT(0); - } - } +/** + Setup System Versioning conditions - if (cond1) - { - cond1= and_items(thd, cond2, cond1); - cond1= and_items(thd, cond3, cond1); - } - return cond1; -#undef newx -} + Add WHERE condition according to FOR SYSTEM_TIME clause. -static -bool skip_setup_conds(THD *thd) -{ - return (!thd->stmt_arena->is_conventional() - && !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) - || thd->lex->is_view_context_analysis(); -} + If the table is partitioned by SYSTEM_TIME and there is no FOR SYSTEM_TIME + clause, then select now-partition instead of modifying WHERE condition. -Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where) + @retval + -1 on error + @retval + 0 on success +*/ +int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) { - DBUG_ENTER("SELECT_LEX::period_setup_conds"); - - if (skip_setup_conds(thd)) - DBUG_RETURN(where); - - Query_arena backup; - Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup); + DBUG_ENTER("SELECT_LEX::vers_setup_cond"); +#define newx new (thd->mem_root) - DBUG_ASSERT(!tables->next_local && tables->table); + TABLE_LIST *table; - Item *result= NULL; - for (TABLE_LIST *table= tables; table; table= table->next_local) + if (!thd->stmt_arena->is_conventional() && + !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { - if (!table->table) - continue; - vers_select_conds_t &conds= table->period_conditions; - if (!table->table->s->period.name.streq(conds.name)) - { - my_error(ER_PERIOD_NOT_FOUND, MYF(0), conds.name.str); - if (arena) - thd->restore_active_arena(arena, &backup); - DBUG_RETURN(NULL); - } - - conds.period= &table->table->s->period; - result= and_items(thd, result, - period_get_condition(thd, table, this, &conds, true)); + // statement is already prepared + DBUG_RETURN(0); } - result= and_items(thd, where, result); - if (arena) - thd->restore_active_arena(arena, &backup); - - DBUG_RETURN(result); -} - -int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) -{ - DBUG_ENTER("SELECT_LEX::vers_setup_conds"); - - if (skip_setup_conds(thd)) + if (thd->lex->is_view_context_analysis()) DBUG_RETURN(0); if (!versioned_tables) { - for (TABLE_LIST *table= tables; table; table= table->next_local) + for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) versioned_tables++; @@ -966,7 +832,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) } } - for (TABLE_LIST *table= tables; table; table= table->next_local) + for (table= tables; table; table= table->next_local) { if (!table->table || !table->table->versioned()) continue; @@ -974,12 +840,13 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) vers_select_conds_t &vers_conditions= table->vers_conditions; #ifdef WITH_PARTITION_STORAGE_ENGINE - /* - if the history is stored in partitions, then partitions - themselves are not versioned - */ - if (table->partition_names && table->table->part_info->vers_info) + Vers_part_info *vers_info; + if (table->table->part_info && (vers_info= table->table->part_info->vers_info)) + { + if (table->partition_names) { + /* If the history is stored in partitions, then partitions + themselves are not versioned. */ if (vers_conditions.is_set()) { my_error(ER_VERS_QUERY_IN_PARTITION, MYF(0), table->alias.str); @@ -988,6 +855,16 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) else vers_conditions.init(SYSTEM_TIME_ALL); } + else if (!vers_conditions.is_set()) + { + table->partition_names= newx List<String>; + String *s= newx String(vers_info->now_part->partition_name, + system_charset_info); + table->partition_names->push_back(s); + table->table->file->change_partitions_to_open(table->partition_names); + vers_conditions.init(SYSTEM_TIME_ALL); + } + } #endif if (outer_table && !vers_conditions.is_set()) @@ -1012,6 +889,16 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) lock_type= TL_READ; // ignore TL_WRITE, history is immutable anyway } + const LEX_CSTRING *fstart= + thd->make_clex_string(table->table->vers_start_field()->field_name); + const LEX_CSTRING *fend= + thd->make_clex_string(table->table->vers_end_field()->field_name); + + Item *row_start= + newx Item_field(thd, &this->context, table->db.str, table->alias.str, fstart); + Item *row_end= + newx Item_field(thd, &this->context, table->db.str, table->alias.str, fend); + bool timestamps_only= table->table->versioned(VERS_TIMESTAMP); if (vers_conditions.is_set()) @@ -1031,17 +918,103 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) } } - vers_conditions.period = &table->table->s->vers; - Item *cond= period_get_condition(thd, table, this, &vers_conditions, - timestamps_only); - if (cond) - table->on_expr= and_items(thd, table->on_expr, cond); - table->vers_conditions.type= SYSTEM_TIME_ALL; + Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL; + Item *point_in_time1= vers_conditions.start.item; + Item *point_in_time2= vers_conditions.end.item; + TABLE *t= table->table; + if (t->versioned(VERS_TIMESTAMP)) + { + MYSQL_TIME max_time; + switch (vers_conditions.type) + { + case SYSTEM_TIME_UNSPECIFIED: + thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); + max_time.second_part= TIME_MAX_SECOND_PART; + curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS); + cond1= newx Item_func_eq(thd, row_end, curr); + break; + case SYSTEM_TIME_AS_OF: + cond1= newx Item_func_le(thd, row_start, point_in_time1); + cond2= newx Item_func_gt(thd, row_end, point_in_time1); + break; + case SYSTEM_TIME_FROM_TO: + cond1= newx Item_func_lt(thd, row_start, point_in_time2); + cond2= newx Item_func_gt(thd, row_end, point_in_time1); + cond3= newx Item_func_lt(thd, point_in_time1, point_in_time2); + break; + case SYSTEM_TIME_BETWEEN: + cond1= newx Item_func_le(thd, row_start, point_in_time2); + cond2= newx Item_func_gt(thd, row_end, point_in_time1); + cond3= newx Item_func_le(thd, point_in_time1, point_in_time2); + break; + case SYSTEM_TIME_BEFORE: + cond1= newx Item_func_lt(thd, row_end, point_in_time1); + break; + default: + DBUG_ASSERT(0); + } + } + else + { + DBUG_ASSERT(table->table->s && table->table->s->db_plugin); + + Item *trx_id0, *trx_id1; + + switch (vers_conditions.type) + { + case SYSTEM_TIME_UNSPECIFIED: + curr= newx Item_int(thd, ULONGLONG_MAX); + cond1= newx Item_func_eq(thd, row_end, curr); + break; + case SYSTEM_TIME_AS_OF: + trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP + ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID) + : point_in_time1; + cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id0, row_start); + cond2= newx Item_func_trt_trx_sees(thd, row_end, trx_id0); + break; + case SYSTEM_TIME_FROM_TO: + cond3= newx Item_func_lt(thd, point_in_time1, point_in_time2); + /* fall through */ + case SYSTEM_TIME_BETWEEN: + trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP + ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true) + : point_in_time1; + trx_id1= vers_conditions.end.unit == VERS_TIMESTAMP + ? newx Item_func_trt_id(thd, point_in_time2, TR_table::FLD_TRX_ID, false) + : point_in_time2; + cond1= vers_conditions.type == SYSTEM_TIME_FROM_TO + ? newx Item_func_trt_trx_sees(thd, trx_id1, row_start) + : newx Item_func_trt_trx_sees_eq(thd, trx_id1, row_start); + cond2= newx Item_func_trt_trx_sees_eq(thd, row_end, trx_id0); + if (!cond3) + cond3= newx Item_func_le(thd, point_in_time1, point_in_time2); + break; + case SYSTEM_TIME_BEFORE: + trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP + ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true) + : point_in_time1; + cond1= newx Item_func_trt_trx_sees(thd, trx_id0, row_end); + break; + default: + DBUG_ASSERT(0); + } + } + if (cond1) + { + cond1= and_items(thd, cond2, cond1); + cond1= and_items(thd, cond3, cond1); + table->on_expr= and_items(thd, table->on_expr, cond1); + } + + table->vers_conditions.type= SYSTEM_TIME_ALL; } // for (table= tables; ...) DBUG_RETURN(0); +#undef newx } +#undef newx /***************************************************************************** Check fields, find best join, do the select and output fields. diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c8cd423a84c..a16e47b902c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5278,7 +5278,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, err: /* In RBR we don't need to log CREATE TEMPORARY TABLE */ - if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) + if (!result && thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) DBUG_RETURN(result); if (create_info->tmp_table()) @@ -7943,10 +7943,12 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, KEY *key_info=table->key_info; bool rc= TRUE; bool modified_primary_key= FALSE; + bool vers_system_invisible= false; Create_field *def; Field **f_ptr,*field; MY_BITMAP *dropped_fields= NULL; // if it's NULL - no dropped fields bool drop_period= false; + bool save_reopen= table->m_needs_reopen; DBUG_ENTER("mysql_prepare_alter_table"); /* @@ -8052,7 +8054,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, bitmap_set_bit(dropped_fields, field->field_index); continue; } - + if (field->invisible == INVISIBLE_SYSTEM && + field->flags & VERS_SYSTEM_FIELD) + { + vers_system_invisible= true; + } /* invisible versioning column is dropped automatically on DROP SYSTEM VERSIONING */ if (!drop && field->invisible >= INVISIBLE_SYSTEM && field->flags & VERS_SYSTEM_FIELD && @@ -8170,7 +8176,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, dropped_sys_vers_fields &= VERS_SYSTEM_FIELD; if ((dropped_sys_vers_fields || alter_info->flags & ALTER_DROP_PERIOD) && - dropped_sys_vers_fields != VERS_SYSTEM_FIELD) + dropped_sys_vers_fields != VERS_SYSTEM_FIELD && + !vers_system_invisible) { StringBuffer<NAME_LEN*3> tmp; append_drop_column(thd, dropped_sys_vers_fields & VERS_SYS_START_FLAG, @@ -8180,6 +8187,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, my_error(ER_MISSING, MYF(0), table->s->table_name.str, tmp.c_ptr()); goto err; } + else if (alter_info->flags & ALTER_DROP_PERIOD && vers_system_invisible) + { + my_error(ER_VERS_NO_PERIOD, MYF(0), table->s->table_name.str); + goto err; + } alter_info->flags &= ~(ALTER_DROP_PERIOD | ALTER_ADD_PERIOD); def_it.rewind(); while ((def=def_it++)) // Add new columns @@ -8687,7 +8699,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, alter_info->create_list.swap(new_create_list); alter_info->key_list.swap(new_key_list); alter_info->check_constraint_list.swap(new_constraint_list); + DBUG_RETURN(rc); err: + table->m_needs_reopen= save_reopen; DBUG_RETURN(rc); } @@ -10345,6 +10359,7 @@ end_temporary: (ulong) (copied + deleted), (ulong) deleted, (ulong) thd->get_stmt_da()->current_statement_warn_count()); my_ok(thd, copied + deleted, 0L, alter_ctx.tmp_buff); + DEBUG_SYNC(thd, "alter_table_inplace_trans_commit"); DBUG_RETURN(false); err_new_table_cleanup: @@ -10411,7 +10426,8 @@ err_with_mdl: tables and release the exclusive metadata lock. */ thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); - thd->mdl_context.release_all_locks_for_name(mdl_ticket); + if (!table_list->table) + thd->mdl_context.release_all_locks_for_name(mdl_ticket); DBUG_RETURN(true); } @@ -10444,12 +10460,14 @@ bool mysql_trans_commit_alter_copy_data(THD *thd) uint save_unsafe_rollback_flags; DBUG_ENTER("mysql_trans_commit_alter_copy_data"); - /* Save flags as transcommit_implicit_are_deleting_them */ + /* Save flags as trans_commit_implicit are deleting them */ save_unsafe_rollback_flags= thd->transaction.stmt.m_unsafe_rollback_flags; + DEBUG_SYNC(thd, "alter_table_copy_trans_commit"); + if (ha_enable_transaction(thd, TRUE)) DBUG_RETURN(TRUE); - + /* Ensure that the new table is saved properly to disk before installing the new .frm. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bd4277e7fea..9cf1bdd5e3e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7269,6 +7269,11 @@ serial_attribute: { Lex->last_field->versioning= $1; Lex->create_info.options|= HA_VERSIONED_TABLE; + if (Lex->alter_info.flags & ALTER_DROP_SYSTEM_VERSIONING) + { + my_yyabort_error((ER_VERS_NOT_VERSIONED, MYF(0), + Lex->create_last_non_select_table->table_name.str)); + } } ; @@ -8462,6 +8467,7 @@ alter_list_item: | DROP SYSTEM VERSIONING_SYM { Lex->alter_info.flags|= ALTER_DROP_SYSTEM_VERSIONING; + Lex->create_info.options&= ~HA_VERSIONED_TABLE; } | DROP PERIOD_SYM FOR_SYSTEM_TIME_SYM { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index a19f8d85a9e..e04554d4e88 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -7357,6 +7357,11 @@ serial_attribute: { Lex->last_field->versioning= $1; Lex->create_info.options|= HA_VERSIONED_TABLE; + if (Lex->alter_info.flags & ALTER_DROP_SYSTEM_VERSIONING) + { + my_yyabort_error((ER_VERS_NOT_VERSIONED, MYF(0), + Lex->create_last_non_select_table->table_name.str)); + } } ; @@ -8563,6 +8568,7 @@ alter_list_item: | DROP SYSTEM VERSIONING_SYM { Lex->alter_info.flags|= ALTER_DROP_SYSTEM_VERSIONING; + Lex->create_info.options&= ~HA_VERSIONED_TABLE; } | DROP PERIOD_SYM FOR_SYSTEM_TIME_SYM { diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 0637b4db7df..74a28c4724f 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -212,7 +212,19 @@ static PSI_file_info wsrep_files[]= { { &key_file_wsrep_gra_log, "wsrep_gra_log", 0} }; -#endif + +PSI_thread_key key_wsrep_sst_joiner, key_wsrep_sst_donor, + key_wsrep_rollbacker, key_wsrep_applier; + +static PSI_thread_info wsrep_threads[]= +{ + {&key_wsrep_sst_joiner, "wsrep_sst_joiner_thread", PSI_FLAG_GLOBAL}, + {&key_wsrep_sst_donor, "wsrep_sst_donor_thread", PSI_FLAG_GLOBAL}, + {&key_wsrep_rollbacker, "wsrep_rollbacker_thread", PSI_FLAG_GLOBAL}, + {&key_wsrep_applier, "wsrep_applier_thread", PSI_FLAG_GLOBAL} +}; + +#endif /* HAVE_PSI_INTERFACE */ my_bool wsrep_inited= 0; // initialized ? @@ -759,6 +771,7 @@ void wsrep_thr_init() mysql_mutex_register("sql", wsrep_mutexes, array_elements(wsrep_mutexes)); mysql_cond_register("sql", wsrep_conds, array_elements(wsrep_conds)); mysql_file_register("sql", wsrep_files, array_elements(wsrep_files)); + mysql_thread_register("sql", wsrep_threads, array_elements(wsrep_threads)); #endif mysql_mutex_init(key_LOCK_wsrep_ready, &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 844437bab95..a7a71307fdb 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -341,7 +341,14 @@ extern PSI_mutex_key key_LOCK_wsrep_thd_queue; extern PSI_cond_key key_COND_wsrep_thd_queue; extern PSI_file_key key_file_wsrep_gra_log; + +extern PSI_thread_key key_wsrep_sst_joiner; +extern PSI_thread_key key_wsrep_sst_donor; +extern PSI_thread_key key_wsrep_rollbacker; +extern PSI_thread_key key_wsrep_applier; #endif /* HAVE_PSI_INTERFACE */ + + struct TABLE_LIST; class Alter_info; int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, @@ -418,6 +425,8 @@ class Wsrep_thd_args enum wsrep_thread_type thread_type() {return thread_type_;} + pthread_t thread_id; + private: Wsrep_thd_args(const Wsrep_thd_args&); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 3181415dad1..85d5aca342d 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -663,10 +663,10 @@ static ssize_t sst_prepare_other (const char* method, pthread_t tmp; sst_thread_arg arg(cmd_str(), env()); mysql_mutex_lock (&arg.lock); - ret= pthread_create (&tmp, NULL, sst_joiner_thread, &arg); + ret = mysql_thread_create (key_wsrep_sst_joiner, &tmp, NULL, sst_joiner_thread, &arg); if (ret) { - WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)", + WSREP_ERROR("sst_prepare_other(): mysql_thread_create() failed: %d (%s)", ret, strerror(ret)); return -ret; } @@ -1350,10 +1350,10 @@ static int sst_donate_other (const char* method, pthread_t tmp; sst_thread_arg arg(cmd_str(), env); mysql_mutex_lock (&arg.lock); - ret= pthread_create (&tmp, NULL, sst_donor_thread, &arg); + ret = mysql_thread_create (key_wsrep_sst_donor, &tmp, NULL, sst_donor_thread, &arg); if (ret) { - WSREP_ERROR("sst_donate_other(): pthread_create() failed: %d (%s)", + WSREP_ERROR("sst_donate_other(): mysql_thread_create() failed: %d (%s)", ret, strerror(ret)); return ret; } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index c62132b16a2..80ffe67b405 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -86,10 +86,25 @@ static void wsrep_replication_process(THD *thd, static bool create_wsrep_THD(Wsrep_thd_args* args) { ulong old_wsrep_running_threads= wsrep_running_threads; - pthread_t unused; +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_thread_key key; - bool res= pthread_create(&unused, &connection_attrib, start_wsrep_THD, - args); + switch (args->thread_type()) + { + case WSREP_APPLIER_THREAD: + key= key_wsrep_applier; + break; + case WSREP_ROLLBACKER_THREAD: + key= key_wsrep_rollbacker; + break; + default: + assert(0); + break; + } +#endif + + bool res= mysql_thread_create(key, &args->thread_id, &connection_attrib, start_wsrep_THD, + (void*)args); /* if starting a thread on server startup, wait until the this thread's THD is fully initialized (otherwise a THD initialization code might |