diff options
Diffstat (limited to 'sql')
39 files changed, 644 insertions, 451 deletions
diff --git a/sql/derror.cc b/sql/derror.cc index baf7163790d..33835992258 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -177,8 +177,8 @@ bool read_texts(const char *file_name, const char *language, O_RDONLY | O_SHARE | O_BINARY, MYF(0))) < 0) goto err; - sql_print_error("An old style --language value with language specific part detected: %s", lc_messages_dir); - sql_print_error("Use --lc-messages-dir without language specific part instead."); + sql_print_warning("An old style --language or -lc-message-dir value with language specific part detected: %s", lc_messages_dir); + sql_print_warning("Use --lc-messages-dir without language specific part instead."); } funktpos=1; diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 55a3f6b36c4..b41c9e2cda0 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -42,7 +42,7 @@ cond_wait(mythd, abstime, msg, SCHED_FUNC, __LINE__) extern pthread_attr_t connection_attrib; - +extern ulong event_executed; Event_db_repository *Event_worker_thread::db_repository; @@ -557,7 +557,8 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) event_name))) goto error; - ++started_events; + started_events++; + executed_events++; // For SHOW STATUS DBUG_PRINT("info", ("Event is in THD: 0x%lx", (long) new_thd)); DBUG_RETURN(FALSE); diff --git a/sql/field.cc b/sql/field.cc index f20d9ba87fc..a3d3d951887 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5677,7 +5677,7 @@ bool Field_newdate::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) if (!tmp) return fuzzydate & TIME_NO_ZERO_DATE; if (!ltime->month || !ltime->day) - return !(fuzzydate & TIME_FUZZY_DATE); + return fuzzydate & TIME_NO_ZERO_IN_DATE; return 0; } @@ -9395,9 +9395,12 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, #ifdef HAVE_SPATIAL if (f_is_geom(pack_flag)) + { + status_var_increment(current_thd->status_var.feature_gis); return new Field_geom(ptr,null_pos,null_bit, unireg_check, field_name, share, pack_length, geom_type); + } #endif if (f_is_blob(pack_flag)) return new Field_blob(ptr,null_pos,null_bit, diff --git a/sql/handler.cc b/sql/handler.cc index 3f201b266f0..5b22712e595 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2552,6 +2552,8 @@ int handler::update_auto_increment() bool append= FALSE; THD *thd= table->in_use; struct system_variables *variables= &thd->variables; + int result=0, tmp; + enum enum_check_fields save_count_cuted_fields; DBUG_ENTER("handler::update_auto_increment"); /* @@ -2569,8 +2571,10 @@ int handler::update_auto_increment() statement (case of INSERT VALUES(null),(3763),(null): the last NULL needs to insert 3764, not the value of the first NULL plus 1). + Ignore negative values. */ - adjust_next_insert_id_after_explicit_value(nr); + if ((longlong) nr > 0 || (table->next_number_field->flags & UNSIGNED_FLAG)) + adjust_next_insert_id_after_explicit_value(nr); insert_id_for_cur_row= 0; // didn't generate anything DBUG_RETURN(0); } @@ -2629,7 +2633,6 @@ int handler::update_auto_increment() else nb_desired_values= AUTO_INC_DEFAULT_NB_MAX; } - /* This call ignores all its parameters but nr, currently */ get_auto_increment(variables->auto_increment_offset, variables->auto_increment_increment, nb_desired_values, &nr, @@ -2666,29 +2669,23 @@ int handler::update_auto_increment() } if (unlikely(nr == ULONGLONG_MAX)) - DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); - if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) - { - /* - first test if the query was aborted due to strict mode constraints - */ - if (killed_mask_hard(thd->killed) == KILL_BAD_DATA) - DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + /* Store field without warning (Warning will be printed by insert) */ + save_count_cuted_fields= thd->count_cuted_fields; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; + tmp= table->next_number_field->store((longlong) nr, TRUE); + thd->count_cuted_fields= save_count_cuted_fields; + if (unlikely(tmp)) // Out of range value in store + { /* - field refused this value (overflow) and truncated it, use the result of - the truncation (which is going to be inserted); however we try to - decrease it to honour auto_increment_* variables. - That will shift the left bound of the reserved interval, we don't - bother shifting the right bound (anyway any other value from this - interval will cause a duplicate key). + It's better to return an error here than getting a confusing + 'duplicate key error' later. */ - nr= prev_insert_id(table->next_number_field->val_int(), variables); - if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) - nr= table->next_number_field->val_int(); + result= HA_ERR_AUTOINC_ERANGE; } if (append) { @@ -2710,6 +2707,10 @@ int handler::update_auto_increment() already set. */ insert_id_for_cur_row= nr; + + if (result) // overflow + DBUG_RETURN(result); + /* Set next insert id to point to next auto-increment value to be able to handle multi-row statements. @@ -2833,7 +2834,7 @@ void handler::ha_release_auto_increment() } -void handler::print_keydup_error(uint key_nr, const char *msg) +void handler::print_keydup_error(uint key_nr, const char *msg, myf errflag) { /* Write the duplicated key in the error message */ char key[MAX_KEY_LENGTH]; @@ -2843,7 +2844,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) { /* Key is unknown */ str.copy("", 0, system_charset_info); - my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*"); + my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), "*UNKNOWN*"); } else { @@ -2856,7 +2857,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) str.append(STRING_WITH_LEN("...")); } my_printf_error(ER_DUP_ENTRY, msg, - MYF(0), str.c_ptr_safe(), table->key_info[key_nr].name); + errflag, str.c_ptr_safe(), table->key_info[key_nr].name); } } @@ -2924,7 +2925,7 @@ void handler::print_error(int error, myf errflag) uint key_nr=get_dup_key(error); if ((int) key_nr >= 0) { - print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME)); + print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME), errflag); DBUG_VOID_RETURN; } } @@ -3087,7 +3088,10 @@ void handler::print_error(int error, myf errflag) textno= ER_AUTOINC_READ_FAILED; break; case HA_ERR_AUTOINC_ERANGE: - textno= ER_WARN_DATA_OUT_OF_RANGE; + textno= error; + my_error(textno, errflag, table->next_number_field->field_name, + table->in_use->warning_info->current_row_for_warning()); + DBUG_VOID_RETURN; break; case HA_ERR_TOO_MANY_CONCURRENT_TRXS: textno= ER_TOO_MANY_CONCURRENT_TRXS; diff --git a/sql/handler.h b/sql/handler.h index b6052412069..874e0de210c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1997,7 +1997,7 @@ public: void adjust_next_insert_id_after_explicit_value(ulonglong nr); int update_auto_increment(); - void print_keydup_error(uint key_nr, const char *msg); + void print_keydup_error(uint key_nr, const char *msg, myf errflag); virtual void print_error(int error, myf errflag); virtual bool get_error_message(int error, String *buf); uint get_dup_key(int error); @@ -2046,7 +2046,8 @@ public: if (!error || ((flags & HA_CHECK_DUP_KEY) && (error == HA_ERR_FOUND_DUPP_KEY || - error == HA_ERR_FOUND_DUPP_UNIQUE))) + error == HA_ERR_FOUND_DUPP_UNIQUE)) || + error == HA_ERR_AUTOINC_ERANGE) return FALSE; return TRUE; } diff --git a/sql/item.cc b/sql/item.cc index ac54e1925b7..4d80a153785 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -503,8 +503,8 @@ Item::Item(THD *thd, Item *item): orig_name(item->orig_name), max_length(item->max_length), name_length(item->name_length), - marker(item->marker), decimals(item->decimals), + marker(item->marker), maybe_null(item->maybe_null), in_rollup(item->in_rollup), null_value(item->null_value), @@ -7759,6 +7759,13 @@ Item* Item_cache_wrapper::get_tmp_table_item(THD *thd_arg) } +bool Item_direct_view_ref::send(Protocol *protocol, String *buffer) +{ + if (check_null_ref()) + return protocol->store_null(); + return Item_direct_ref::send(protocol, buffer); +} + /** Prepare referenced field then call usual Item_direct_ref::fix_fields . @@ -7773,6 +7780,7 @@ Item* Item_cache_wrapper::get_tmp_table_item(THD *thd_arg) bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) { + DBUG_ASSERT(1); /* view fild reference must be defined */ DBUG_ASSERT(*ref); /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ @@ -9285,7 +9293,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) item->max_length, item->decimals)); fld_type= Field::field_type_merge(fld_type, get_real_type(item)); { - int item_decimals= item->decimals; + uint item_decimals= item->decimals; /* fix variable decimals which always is NOT_FIXED_DEC */ if (Field::result_merge_type(fld_type) == INT_RESULT) item_decimals= 0; diff --git a/sql/item.h b/sql/item.h index 8855996b76c..3136bb00394 100644 --- a/sql/item.h +++ b/sql/item.h @@ -618,8 +618,8 @@ public: calls. */ uint name_length; /* Length of name */ + uint decimals; int8 marker; - uint8 decimals; bool maybe_null; /* If item may be null */ bool in_rollup; /* If used in GROUP BY list of a query with ROLLUP */ @@ -3161,20 +3161,29 @@ class Item_direct_view_ref :public Item_direct_ref { Item_equal *item_equal; TABLE_LIST *view; + TABLE *null_ref_table; + + bool check_null_ref() + { + if (null_ref_table == NULL) + { + null_ref_table= view->get_real_join_table(); + } + if (null_ref_table->null_row) + { + null_value= 1; + return TRUE; + } + return FALSE; + } public: Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, TABLE_LIST *view_arg) :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg), - item_equal(0), view(view_arg) {} - /* Constructor need to process subselect with temporary tables (see Item) */ - Item_direct_view_ref(THD *thd, Item_direct_ref *item) - :Item_direct_ref(thd, item), item_equal(0) {} - Item_direct_view_ref(TABLE_LIST *view_arg, Item **item, - const char *field_name_arg) - :Item_direct_ref(view_arg, item, field_name_arg), item_equal(0) - {} + item_equal(0), view(view_arg), + null_ref_table(NULL) {} bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; @@ -3205,6 +3214,85 @@ public: view_arg->view_used_tables|= (*ref)->used_tables(); return 0; } + void save_val(Field *to) + { + if (check_null_ref()) + to->set_null(); + else + Item_direct_ref::save_val(to); + } + double val_real() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_real(); + } + longlong val_int() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_int(); + } + String *val_str(String* tmp) + { + if (check_null_ref()) + return NULL; + else + return Item_direct_ref::val_str(tmp); + } + my_decimal *val_decimal(my_decimal *tmp) + { + if (check_null_ref()) + return NULL; + else + return Item_direct_ref::val_decimal(tmp); + } + bool val_bool() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_bool(); + } + bool is_null() + { + if (check_null_ref()) + return 1; + else + return Item_direct_ref::is_null(); + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + if (check_null_ref()) + { + bzero((char*) ltime,sizeof(*ltime)); + return 1; + } + return Item_direct_ref::get_date(ltime, fuzzydate); + } + bool send(Protocol *protocol, String *buffer); + void save_org_in_field(Field *field) + { + if (check_null_ref()) + field->set_null(); + else + Item_direct_ref::save_val(field); + } + void save_in_result_field(bool no_conversions) + { + if (check_null_ref()) + result_field->set_null(); + else + Item_direct_ref::save_in_result_field(no_conversions); + } + + void cleanup() + { + null_ref_table= NULL; + Item_direct_ref::cleanup(); + } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 7a7cdd4ba02..441eb37d701 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6046,6 +6046,8 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) DBUG_ASSERT(fixed == 0); Item *UNINIT_VAR(item); // Safe as arg_count is > 1 + status_var_increment(thd->status_var.feature_fulltext); + maybe_null=1; join_key=0; @@ -6816,3 +6818,62 @@ longlong Item_func_uuid_short::val_int() mysql_mutex_unlock(&LOCK_short_uuid_generator); return (longlong) val; } + + +/** + Last_value - return last argument. +*/ + +void Item_func_last_value::evaluate_sideeffects() +{ + DBUG_ASSERT(fixed == 1 && arg_count > 0); + for (uint i= 0; i < arg_count-1 ; i++) + args[i]->val_int(); +} + +String *Item_func_last_value::val_str(String *str) +{ + String *tmp; + evaluate_sideeffects(); + tmp= last_value->val_str(str); + null_value= last_value->null_value; + return tmp; +} + +longlong Item_func_last_value::val_int() +{ + longlong tmp; + evaluate_sideeffects(); + tmp= last_value->val_int(); + null_value= last_value->null_value; + return tmp; +} + +double Item_func_last_value::val_real() +{ + double tmp; + evaluate_sideeffects(); + tmp= last_value->val_real(); + null_value= last_value->null_value; + return tmp; +} + +my_decimal *Item_func_last_value::val_decimal(my_decimal *decimal_value) +{ + my_decimal *tmp; + evaluate_sideeffects(); + tmp= last_value->val_decimal(decimal_value); + null_value= last_value->null_value; + return tmp; +} + + +void Item_func_last_value::fix_length_and_dec() +{ + last_value= args[arg_count -1]; + decimals= last_value->decimals; + max_length= last_value->max_length; + collation.set(last_value->collation.collation); + maybe_null= last_value->maybe_null; + unsigned_flag= last_value->unsigned_flag; +} diff --git a/sql/item_func.h b/sql/item_func.h index 111479c8e52..586444e0e4e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2003,6 +2003,27 @@ public: } }; + +class Item_func_last_value :public Item_func +{ +protected: + Item *last_value; +public: + Item_func_last_value(List<Item> &list) :Item_func(list) {} + double val_real(); + longlong val_int(); + String *val_str(String *); + my_decimal *val_decimal(my_decimal *); + void fix_length_and_dec(); + enum Item_result result_type () const { return last_value->result_type(); } + const char *func_name() const { return "last_value"; } + table_map not_null_tables() const { return 0; } + enum_field_types field_type() const { return last_value->field_type(); } + bool const_item() const { return 0; } + void evaluate_sideeffects(); +}; + + Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, LEX_STRING component); extern bool check_reserved_words(LEX_STRING *name); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 3648b10af3f..bc89a6c14b3 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1695,7 +1695,8 @@ count_distance: for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next()) { /* We only check vertices of object 2 */ - if (dist_point->shape < obj2_si) + if (dist_point->type != Gcalc_heap::nt_shape_node || + dist_point->shape < obj2_si) continue; /* if we have an edge to check */ diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c5d1edbe475..ebfca684ccb 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3774,6 +3774,7 @@ bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref) (arg_count / 2)); nums= (uint *) alloc_root(thd->mem_root, sizeof(uint) * (arg_count / 2)); + status_var_increment(thd->status_var.feature_dynamic_columns); return res || vals == 0 || nums == 0; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c10b75c154b..efc058763c0 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -220,6 +220,8 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) uint8 uncacheable; bool res; + status_var_increment(thd->status_var.feature_subquery); + DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); if (!done_first_fix_fields) @@ -733,6 +735,19 @@ bool Item_subselect::expr_cache_is_needed(THD *thd) /** + Check if the left IN argument contains NULL values. + + @retval TRUE there are NULLs + @retval FALSE otherwise +*/ + +inline bool Item_in_subselect::left_expr_has_null() +{ + return (*(optimizer->get_cache()))->null_value; +} + + +/** Check if an expression cache is needed for this subquery @param thd Thread handle @@ -3283,161 +3298,51 @@ int subselect_uniquesubquery_engine::scan_table() } -/* - Copy ref key and check for null parts in it - - SYNOPSIS - subselect_uniquesubquery_engine::copy_ref_key() - - DESCRIPTION - Copy ref key and check for null parts in it. - Depending on the nullability and conversion problems this function - recognizes and processes the following states : - 1. Partial match on top level. This means IN has a value of FALSE - regardless of the data in the subquery table. - Detected by finding a NULL in the left IN operand of a top level - expression. - We may actually skip reading the subquery, so return TRUE to skip - the table scan in subselect_uniquesubquery_engine::exec and make - the value of the IN predicate a NULL (that is equal to FALSE on - top level). - 2. No exact match when IN is nested inside another predicate. - Detected by finding a NULL in the left IN operand when IN is not - a top level predicate. - We cannot have an exact match. But we must proceed further with a - table scan to find out if it's a partial match (and IN has a value - of NULL) or no match (and IN has a value of FALSE). - So we return FALSE to continue with the scan and see if there are - any record that would constitute a partial match (as we cannot - determine that from the index). - 3. Error converting the left IN operand to the column type of the - right IN operand. This counts as no match (and IN has the value of - FALSE). We mark the subquery table cursor as having no more rows - (to ensure that the processing that follows will not find a match) - and return FALSE, so IN is not treated as returning NULL. +/** + Copy ref key for index access into the only subquery table. + @details + Copy ref key and check for conversion problems. + If there is an error converting the left IN operand to the column type of + the right IN operand count it as no match. In this case IN has the value of + FALSE. We mark the subquery table cursor as having no more rows (to ensure + that the processing that follows will not find a match) and return FALSE, + so IN is not treated as returning NULL. - RETURN - FALSE - The value of the IN predicate is not known. Proceed to find the - value of the IN predicate using the determined values of - null_keypart and table->status. - TRUE - IN predicate has a value of NULL. Stop the processing right there - and return NULL to the outer predicates. + @returns + @retval FALSE The outer ref was copied into an index lookup key. + @retval TRUE The outer ref cannot possibly match any row, IN is FALSE. */ -bool subselect_uniquesubquery_engine::copy_ref_key() +bool subselect_uniquesubquery_engine::copy_ref_key(bool skip_constants) { DBUG_ENTER("subselect_uniquesubquery_engine::copy_ref_key"); for (store_key **copy= tab->ref.key_copy ; *copy ; copy++) { - if ((*copy)->store_key_is_const()) - continue; - tab->ref.key_err= (*copy)->copy(); - - /* - When there is a NULL part in the key we don't need to make index - lookup for such key thus we don't need to copy whole key. - If we later should do a sequential scan return OK. Fail otherwise. - - See also the comment for the subselect_uniquesubquery_engine::exec() - function. - */ - null_keypart= (*copy)->null_key; - if (null_keypart) - { - bool top_level= ((Item_in_subselect *) item)->is_top_level_item(); - if (top_level) - { - /* Partial match on top level */ - DBUG_RETURN(1); - } - else - { - /* No exact match when IN is nested inside another predicate */ - break; - } - } - - /* - Check if the error is equal to STORE_KEY_FATAL. This is not expressed - using the store_key::store_key_result enum because ref.key_err is a - boolean and we want to detect both TRUE and STORE_KEY_FATAL from the - space of the union of the values of [TRUE, FALSE] and - store_key::store_key_result. - TODO: fix the variable an return types. - */ - if (tab->ref.key_err & 1) - { - /* - Error converting the left IN operand to the column type of the right - IN operand. - */ - tab->table->status= STATUS_NOT_FOUND; - break; - } - } - DBUG_RETURN(0); -} - - -/* - @retval 1 A NULL was found in the outer reference, index lookup is - not applicable, the outer ref is unsusable as a lookup key, - use some other method to find a match. - @retval 0 The outer ref was copied into an index lookup key. - @retval -1 The outer ref cannot possibly match any row, IN is FALSE. -*/ -/* TIMOUR: this method is a variant of copy_ref_key(), needs refactoring. */ - -int subselect_uniquesubquery_engine::copy_ref_key_simple() -{ - for (store_key **copy= tab->ref.key_copy ; *copy ; copy++) - { enum store_key::store_key_result store_res; + if (skip_constants && (*copy)->store_key_is_const()) + continue; store_res= (*copy)->copy(); tab->ref.key_err= store_res; - /* - When there is a NULL part in the key we don't need to make index - lookup for such key thus we don't need to copy whole key. - If we later should do a sequential scan return OK. Fail otherwise. - - See also the comment for the subselect_uniquesubquery_engine::exec() - function. - */ - null_keypart= (*copy)->null_key; - if (null_keypart) - return 1; - - /* - Check if the error is equal to STORE_KEY_FATAL. This is not expressed - using the store_key::store_key_result enum because ref.key_err is a - boolean and we want to detect both TRUE and STORE_KEY_FATAL from the - space of the union of the values of [TRUE, FALSE] and - store_key::store_key_result. - TODO: fix the variable an return types. - */ if (store_res == store_key::STORE_KEY_FATAL) { /* Error converting the left IN operand to the column type of the right IN operand. */ - return -1; + DBUG_RETURN(true); } } - return 0; + DBUG_RETURN(false); } -/* - Execute subselect - - SYNOPSIS - subselect_uniquesubquery_engine::exec() +/** + Execute subselect via unique index lookup - DESCRIPTION + @details Find rows corresponding to the ref key using index access. If some part of the lookup key is NULL, then we're evaluating NULL IN (SELECT ... ) @@ -3454,11 +3359,11 @@ int subselect_uniquesubquery_engine::copy_ref_key_simple() The result of this function (info about whether a row was found) is stored in this->empty_result_set. - NOTE - RETURN - FALSE - ok - TRUE - an error occured while scanning + @returns + @retval 0 OK + @retval 1 notify caller to call Item_subselect::reset(), + in most cases reset() sets the result to NULL */ int subselect_uniquesubquery_engine::exec() @@ -3468,32 +3373,30 @@ int subselect_uniquesubquery_engine::exec() TABLE *table= tab->table; empty_result_set= TRUE; table->status= 0; + Item_in_subselect *in_subs= (Item_in_subselect *) item; + + if (!tab->preread_init_done && tab->preread_init()) + DBUG_RETURN(1); - /* TODO: change to use of 'full_scan' here? */ - if (copy_ref_key()) + if (in_subs->left_expr_has_null()) { /* - TIMOUR: copy_ref_key() == 1 means NULL result, not error, why return 1? - Check who reiles on this result. + The case when all values in left_expr are NULL is handled by + Item_in_optimizer::val_int(). */ - DBUG_RETURN(1); + if (in_subs->is_top_level_item()) + DBUG_RETURN(1); /* notify caller to call reset() and set NULL value. */ + else + DBUG_RETURN(scan_table()); } - if (table->status) + + if (copy_ref_key(true)) { - /* - We know that there will be no rows even if we scan. - Can be set in copy_ref_key. - */ - ((Item_in_subselect *) item)->value= 0; + /* We know that there will be no rows even if we scan. */ + in_subs->value= 0; DBUG_RETURN(0); } - if (!tab->preread_init_done && tab->preread_init()) - DBUG_RETURN(1); - - if (null_keypart) - DBUG_RETURN(scan_table()); - if (!table->file->inited) table->file->ha_index_init(tab->ref.key, 0); error= table->file->ha_index_read_map(table->record[0], @@ -3569,14 +3472,10 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine() } -/* - Index-lookup subselect 'engine' - run the subquery - - SYNOPSIS - subselect_indexsubquery_engine:exec() - full_scan +/** + Execute subselect via unique index lookup - DESCRIPTION + @details The engine is used to resolve subqueries in form oe IN (SELECT key FROM tbl WHERE subq_where) @@ -3591,7 +3490,7 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine() row that satisfies subq_where. If found, return NULL, otherwise return FALSE. - TODO + @todo The step #1 can be optimized further when the index has several key parts. Consider a subquery: @@ -3616,9 +3515,10 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine() cheaper. We can use index statistics to quickly check whether "ref" scan will be cheaper than full table scan. - RETURN - 0 - 1 + @returns + @retval 0 OK + @retval 1 notify caller to call Item_subselect::reset(), + in most cases reset() sets the result to NULL */ int subselect_indexsubquery_engine::exec() @@ -3627,10 +3527,10 @@ int subselect_indexsubquery_engine::exec() int error; bool null_finding= 0; TABLE *table= tab->table; + Item_in_subselect *in_subs= (Item_in_subselect *) item; ((Item_in_subselect *) item)->value= 0; empty_result_set= TRUE; - null_keypart= 0; table->status= 0; if (check_null) @@ -3640,25 +3540,27 @@ int subselect_indexsubquery_engine::exec() ((Item_in_subselect *) item)->was_null= 0; } - /* Copy the ref key and check for nulls... */ - if (copy_ref_key()) + if (!tab->preread_init_done && tab->preread_init()) DBUG_RETURN(1); - if (table->status) + if (in_subs->left_expr_has_null()) { - /* - We know that there will be no rows even if we scan. - Can be set in copy_ref_key. + /* + The case when all values in left_expr are NULL is handled by + Item_in_optimizer::val_int(). */ - ((Item_in_subselect *) item)->value= 0; - DBUG_RETURN(0); + if (in_subs->is_top_level_item()) + DBUG_RETURN(1); /* notify caller to call reset() and set NULL value. */ + else + DBUG_RETURN(scan_table()); } - if (!tab->preread_init_done && tab->preread_init()) - DBUG_RETURN(1); - - if (null_keypart) - DBUG_RETURN(scan_table()); + if (copy_ref_key(true)) + { + /* We know that there will be no rows even if we scan. */ + in_subs->value= 0; + DBUG_RETURN(0); + } if (!table->file->inited) table->file->ha_index_init(tab->ref.key, 1); @@ -5429,37 +5331,42 @@ subselect_partial_match_engine::subselect_partial_match_engine( int subselect_partial_match_engine::exec() { Item_in_subselect *item_in= (Item_in_subselect *) item; - int copy_res, lookup_res; + int lookup_res; - /* Try to find a matching row by index lookup. */ - copy_res= lookup_engine->copy_ref_key_simple(); - if (copy_res == -1) - { - /* The result is FALSE based on the outer reference. */ - item_in->value= 0; - item_in->null_value= 0; - return 0; - } - else if (copy_res == 0) + DBUG_ASSERT(!(item_in->left_expr_has_null() && + item_in->is_top_level_item())); + + if (!item_in->left_expr_has_null()) { - /* Search for a complete match. */ - if ((lookup_res= lookup_engine->index_lookup())) + /* Try to find a matching row by index lookup. */ + if (lookup_engine->copy_ref_key(false)) { - /* An error occured during lookup(). */ + /* The result is FALSE based on the outer reference. */ item_in->value= 0; item_in->null_value= 0; - return lookup_res; + return 0; } - else if (item_in->value || !count_columns_with_nulls) + else { - /* - A complete match was found, the result of IN is TRUE. - If no match was found, and there are no NULLs in the materialized - subquery, then the result is guaranteed to be false because this - branch is executed when the outer reference has no NULLs as well. - Notice: (this->item == lookup_engine->item) - */ - return 0; + /* Search for a complete match. */ + if ((lookup_res= lookup_engine->index_lookup())) + { + /* An error occured during lookup(). */ + item_in->value= 0; + item_in->null_value= 0; + return lookup_res; + } + else if (item_in->value || !count_columns_with_nulls) + { + /* + A complete match was found, the result of IN is TRUE. + If no match was found, and there are no NULLs in the materialized + subquery, then the result is guaranteed to be false because this + branch is executed when the outer reference has no NULLs as well. + Notice: (this->item == lookup_engine->item) + */ + return 0; + } } } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 05c4528490f..2a64c63a1be 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -591,6 +591,7 @@ public: /* Inform 'this' that it was computed, and contains a valid result. */ void set_first_execution() { if (first_execution) first_execution= FALSE; } bool expr_cache_is_needed(THD *thd); + inline bool left_expr_has_null(); int optimize(double *out_rows, double *cost); /* @@ -869,7 +870,6 @@ protected: expression is NULL. */ bool empty_result_set; - bool null_keypart; /* TRUE <=> constructed search tuple has a NULL */ public: // constructor can assign THD because it will be called after JOIN::prepare @@ -893,8 +893,7 @@ public: bool no_tables(); int index_lookup(); /* TIMOUR: this method needs refactoring. */ int scan_table(); - bool copy_ref_key(); - int copy_ref_key_simple(); /* TIMOUR: this method needs refactoring. */ + bool copy_ref_key(bool skip_constants); bool no_rows() { return empty_result_set; } virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 857d9bc2080..117276e488b 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -361,9 +361,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, { uint days; days= calc_daynr(l_time->year,1,1) + yearday - 1; - if (days <= 0 || days > MAX_DAY_NUMBER) + if (get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day)) goto err; - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (week_number >= 0 && weekday) @@ -408,9 +407,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, (weekday - 1); } - if (days <= 0 || days > MAX_DAY_NUMBER) + if (get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day)) goto err; - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || @@ -768,7 +766,7 @@ longlong Item_func_to_days::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + if (get_arg0_date(<ime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) return 0; return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); } @@ -808,7 +806,7 @@ longlong Item_func_to_seconds::val_int() MYSQL_TIME ltime; longlong seconds; longlong days; - if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + if (get_arg0_date(<ime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) return 0; seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second; seconds=ltime.neg ? -seconds : seconds; @@ -1501,10 +1499,11 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) if ((fuzzy_date & TIME_NO_ZERO_DATE) && value == 0) return (null_value= 1); bzero(ltime, sizeof(MYSQL_TIME)); - get_date_from_daynr((long) value, <ime->year, <ime->month, <ime->day); + if (get_date_from_daynr((long) value, <ime->year, <ime->month, + <ime->day)) + return (null_value= 1); - if ((fuzzy_date & TIME_NO_ZERO_DATE) && - (ltime->year == 0 || ltime->month == 0 || ltime->day == 0)) + if ((fuzzy_date & TIME_NO_ZERO_DATE) && ltime->year == 0) return (null_value= 1); ltime->time_type= MYSQL_TIMESTAMP_DATE; @@ -2043,7 +2042,7 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { INTERVAL interval; - if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE | TIME_FUZZY_DATE) || + if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE | TIME_FUZZY_DATE | TIME_NO_ZERO_IN_DATE) || get_interval_value(args[1], int_type, &interval)) return (null_value=1); @@ -2514,14 +2513,12 @@ bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) year= year_2000_handling(year); days= calc_daynr(year,1,1) + daynr - 1; - /* Day number from year 0 to 9999-12-31 */ - if (days >= 0 && days <= MAX_DAY_NUMBER) - { - bzero(ltime, sizeof(*ltime)); - ltime->time_type= MYSQL_TIMESTAMP_DATE; - get_date_from_daynr(days, <ime->year, <ime->month, <ime->day); - return (null_value= 0); - } + if (get_date_from_daynr(days, <ime->year, <ime->month, <ime->day)) + goto err; + ltime->time_type= MYSQL_TIMESTAMP_DATE; + ltime->neg= 0; + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; + return (null_value= 0); err: return (null_value= 1); @@ -2615,8 +2612,8 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) if (!is_time) { - get_date_from_daynr(days,<ime->year,<ime->month,<ime->day); - if (!ltime->day) + if (get_date_from_daynr(days,<ime->year,<ime->month,<ime->day) || + !ltime->day) return (null_value= 1); return (null_value= 0); } diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 0fa2d39aea9..ae0a74c5ba6 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2601,6 +2601,8 @@ void Item_xml_str_func::fix_length_and_dec() MY_XPATH xpath; int rc; + status_var_increment(current_thd->status_var.feature_xml); + nodeset_func= 0; if (agg_arg_charsets_for_comparison(collation, args, arg_count)) diff --git a/sql/lex.h b/sql/lex.h index 9f4369630a0..9bf4c439cb6 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -302,6 +302,7 @@ static SYMBOL symbols[] = { { "KILL", SYM(KILL_SYM)}, { "LANGUAGE", SYM(LANGUAGE_SYM)}, { "LAST", SYM(LAST_SYM)}, + { "LAST_VALUE", SYM(LAST_VALUE)}, { "LEADING", SYM(LEADING)}, { "LEAVE", SYM(LEAVE_SYM)}, { "LEAVES", SYM(LEAVES)}, diff --git a/sql/log.cc b/sql/log.cc index 50c66135f24..e4db7b2eb0f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3277,7 +3277,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, bytes_written+= description_event_for_queue->data_written; } if (flush_io_cache(&log_file) || - mysql_file_sync(log_file.file, MYF(MY_WME))) + mysql_file_sync(log_file.file, MYF(MY_WME|MY_SYNC_FILESIZE))) goto err; mysql_mutex_lock(&LOCK_commit_ordered); strmake(last_commit_pos_file, log_file_name, @@ -3307,7 +3307,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, strlen(log_file_name)) || my_b_write(&index_file, (uchar*) "\n", 1) || flush_io_cache(&index_file) || - mysql_file_sync(index_file.file, MYF(MY_WME))) + mysql_file_sync(index_file.file, MYF(MY_WME|MY_SYNC_FILESIZE))) goto err; #ifdef HAVE_REPLICATION @@ -3416,7 +3416,7 @@ static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset) } /* The following will either truncate the file or fill the end with \n' */ if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) || - mysql_file_sync(file, MYF(MY_WME))) + mysql_file_sync(file, MYF(MY_WME|MY_SYNC_FILESIZE))) goto err; /* Reset data in old index cache */ @@ -4136,7 +4136,7 @@ int MYSQL_BIN_LOG::sync_purge_index_file() DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file"); if ((error= flush_io_cache(&purge_index_file)) || - (error= my_sync(purge_index_file.file, MYF(MY_WME)))) + (error= my_sync(purge_index_file.file, MYF(MY_WME|MY_SYNC_FILESIZE)))) DBUG_RETURN(error); DBUG_RETURN(error); @@ -4753,7 +4753,7 @@ bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) if (sync_period && ++sync_counter >= sync_period) { sync_counter= 0; - err= mysql_file_sync(fd, MYF(MY_WME)); + err= mysql_file_sync(fd, MYF(MY_WME|MY_SYNC_FILESIZE)); if (synced) *synced= 1; #ifndef DBUG_OFF diff --git a/sql/log_event.cc b/sql/log_event.cc index 25ab7b7c870..132f778ee08 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1087,6 +1087,9 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length) ulong now; bool ret; DBUG_ENTER("Log_event::write_header"); + DBUG_PRINT("enter", ("filepos: %lld length: %lu type: %d", + (longlong) my_b_tell(file), event_data_length, + (int) get_type_code())); /* Store number of bytes that will be written by this event */ data_written= event_data_length + sizeof(header); @@ -3625,6 +3628,34 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli) return do_apply_event(rli, query, q_len); } +/** + Compare if two errors should be regarded as equal. + This is to handle the case when you can get slightly different errors + on master and slave for the same thing. + @param + expected_error Error we got on master + actual_error Error we got on slave + + @return + 1 Errors are equal + 0 Errors are different +*/ + +bool test_if_equal_repl_errors(int expected_error, int actual_error) +{ + if (expected_error == actual_error) + return 1; + switch (expected_error) { + case ER_DUP_ENTRY: + case ER_AUTOINC_READ_FAILED: + return (actual_error == ER_AUTOINC_READ_FAILED || + actual_error == HA_ERR_AUTOINC_ERANGE); + default: + break; + } + return 0; +} + /** @todo @@ -3937,7 +3968,8 @@ compare_errors: DBUG_PRINT("info",("expected_error: %d sql_errno: %d", expected_error, actual_error)); - if ((expected_error && expected_error != actual_error && + if ((expected_error && + !test_if_equal_repl_errors(expected_error, actual_error) && !concurrency_error_code(expected_error)) && !ignored_error_code(actual_error) && !ignored_error_code(expected_error)) @@ -3959,7 +3991,7 @@ Default database: '%s'. Query: '%s'", If we get the same error code as expected and it is not a concurrency issue, or should be ignored. */ - else if ((expected_error == actual_error && + else if ((test_if_equal_repl_errors(expected_error, actual_error) && !concurrency_error_code(expected_error)) || ignored_error_code(actual_error)) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index fa6b085c3ad..96ea789edd7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -360,7 +360,7 @@ static DYNAMIC_ARRAY all_options; /* Global variables */ -bool opt_bin_log, opt_ignore_builtin_innodb= 0; +bool opt_bin_log, opt_bin_log_used=0, opt_ignore_builtin_innodb= 0; my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0, opt_abort; ulonglong log_output_options; my_bool opt_userstat_running; @@ -482,6 +482,7 @@ ulonglong binlog_stmt_cache_size=0; ulonglong max_binlog_stmt_cache_size=0; ulonglong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ +ulong executed_events=0; query_id_t global_query_id; my_atomic_rwlock_t global_query_id_lock; my_atomic_rwlock_t thread_running_lock; @@ -579,7 +580,7 @@ char mysql_real_data_home[FN_REFLEN], lc_messages_dir[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], *opt_init_file, *opt_tc_log_file; -char *lc_messages_dir_ptr, *log_error_file_ptr; +char *lc_messages_dir_ptr= lc_messages_dir, *log_error_file_ptr; char mysql_unpacked_real_data_home[FN_REFLEN]; int mysql_unpacked_real_data_home_len; uint mysql_real_data_home_len, mysql_data_home_len= 1; @@ -2028,13 +2029,19 @@ static struct passwd *check_user(const char *user) if (!(tmp_user_info= getpwuid(atoi(user)))) goto err; } + return tmp_user_info; /* purecov: end */ err: sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user); unireg_abort(1); +#endif + return NULL; +} +static inline void allow_coredumps() +{ #ifdef PR_SET_DUMPABLE if (test_flags & TEST_CORE_ON_SIGNAL) { @@ -2042,11 +2049,9 @@ err: (void) prctl(PR_SET_DUMPABLE, 1); } #endif - -#endif - return NULL; } + static void set_user(const char *user, struct passwd *user_info_arg) { /* purecov: begin tested */ @@ -2073,6 +2078,7 @@ static void set_user(const char *user, struct passwd *user_info_arg) sql_perror("setuid"); unireg_abort(1); } + allow_coredumps(); #endif /* purecov: end */ } @@ -2092,6 +2098,7 @@ static void set_effective_user(struct passwd *user_info_arg) sql_perror("setreuid"); unireg_abort(1); } + allow_coredumps(); #endif } @@ -4168,14 +4175,15 @@ static int init_server_components() unireg_abort(1); /* need to configure logging before initializing storage engines */ - if (opt_log_slave_updates && !opt_bin_log) + if (!opt_bin_log_used) { - sql_print_warning("You need to use --log-bin to make " - "--log-slave-updates work."); + if (opt_log_slave_updates) + sql_print_warning("You need to use --log-bin to make " + "--log-slave-updates work."); + if (binlog_format_used) + sql_print_warning("You need to use --log-bin to make " + "--binlog-format work."); } - if (!opt_bin_log && binlog_format_used) - sql_print_warning("You need to use --log-bin to make " - "--binlog-format work."); /* Check that we have not let the format to unspecified at this point */ DBUG_ASSERT((uint)global_system_variables.binlog_format <= @@ -6222,7 +6230,7 @@ struct my_option my_long_options[]= {"language", 'L', "Client error messages in given language. May be given as a full path. " "Deprecated. Use --lc-messages-dir instead.", - &lc_messages_dir_ptr, &lc_messages_dir_ptr, 0, + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lc-messages", 0, "Set the language used for the error messages.", @@ -6943,6 +6951,16 @@ SHOW_VAR status_vars[]= { {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, {"Empty_queries", (char*) offsetof(STATUS_VAR, empty_queries), SHOW_LONG_STATUS}, + {"Executed_events", (char*) &executed_events, SHOW_LONG_NOFLUSH }, + {"Executed_triggers", (char*) offsetof(STATUS_VAR, executed_triggers), SHOW_LONG_STATUS}, + {"Feature_dynamic_columns", (char*) offsetof(STATUS_VAR, feature_dynamic_columns), SHOW_LONG_STATUS}, + {"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS}, + {"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS}, + {"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS}, + {"Feature_subquery", (char*) offsetof(STATUS_VAR, feature_subquery), SHOW_LONG_STATUS}, + {"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS}, + {"Feature_trigger", (char*) offsetof(STATUS_VAR, feature_trigger), SHOW_LONG_STATUS}, + {"Feature_xml", (char*) offsetof(STATUS_VAR, feature_xml), SHOW_LONG_STATUS}, {"Flush_commands", (char*) &refresh_version, SHOW_LONG_NOFLUSH}, {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, @@ -6982,6 +7000,7 @@ SHOW_VAR status_vars[]= { {"Opened_files", (char*) &my_file_total_opened, SHOW_LONG_NOFLUSH}, {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS}, {"Opened_table_definitions", (char*) offsetof(STATUS_VAR, opened_shares), SHOW_LONG_STATUS}, + {"Opened_views", (char*) offsetof(STATUS_VAR, opened_views), SHOW_LONG_STATUS}, {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_FUNC}, {"Rows_sent", (char*) offsetof(STATUS_VAR, rows_sent), SHOW_LONGLONG_STATUS}, {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS}, @@ -7214,7 +7233,7 @@ static int mysql_init_variables(void) myisam_test_invalid_symlink= test_if_data_home_dir; #endif opt_log= opt_slow_log= 0; - opt_bin_log= 0; + opt_bin_log= opt_bin_log_used= 0; opt_disable_networking= opt_skip_show_db=0; opt_skip_name_resolve= 0; opt_ignore_builtin_innodb= 0; @@ -7266,10 +7285,10 @@ static int mysql_init_variables(void) mysql_home_ptr= mysql_home; pidfile_name_ptr= pidfile_name; log_error_file_ptr= log_error_file; - lc_messages_dir_ptr= lc_messages_dir; protocol_version= PROTOCOL_VERSION; what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= 1L; /* Increments on each reload */ + executed_events= 0; global_query_id= thread_id= 1L; my_atomic_rwlock_init(&global_query_id_lock); my_atomic_rwlock_init(&thread_running_lock); @@ -7455,7 +7474,6 @@ mysqld_get_one_option(int optid, break; case 'L': strmake(lc_messages_dir, argument, sizeof(lc_messages_dir)-1); - lc_messages_dir_ptr= lc_messages_dir; break; case OPT_BINLOG_FORMAT: binlog_format_used= true; @@ -7484,6 +7502,7 @@ mysqld_get_one_option(int optid, break; case (int) OPT_BIN_LOG: opt_bin_log= test(argument != disabled_my_option); + opt_bin_log_used= 1; break; case (int) OPT_LOG_BASENAME: { diff --git a/sql/mysqld.h b/sql/mysqld.h index 62d2426d692..7a24b56dcb7 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -175,6 +175,7 @@ extern ulong opt_binlog_rows_event_max_size; extern ulong rpl_recovery_rank, thread_cache_size; extern ulong stored_program_cache_size; extern ulong back_log; +extern ulong executed_events; extern char language[FN_REFLEN]; extern "C" MYSQL_PLUGIN_IMPORT ulong server_id; extern ulong concurrency; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index cbec039b3e4..fa3a07b72c5 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -791,7 +791,7 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, { /* Update endpoints for MAX/MIN, see function comment. */ Item *value= args[between && max_fl ? 2 : 1]; - store_val_in_field(part->field, value, CHECK_FIELD_IGNORE); + value->save_in_field_no_warnings(part->field, 1); if (part->null_bit) *key_ptr++= (uchar) test(part->field->is_null()); part->field->get_key_image(key_ptr, part->length, Field::itRAW); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 52569f193aa..85e9227c154 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3893,34 +3893,22 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry) { char query_buf[2*FN_REFLEN + 21]; String query(query_buf, sizeof(query_buf), system_charset_info); + query.length(0); - if (query.ptr()) - { - /* this DELETE FROM is needed even with row-based binlogging */ - query.append("DELETE FROM "); - append_identifier(thd, &query, share->db.str, share->db.length); - query.append("."); - append_identifier(thd, &query, share->table_name.str, + query.append("DELETE FROM "); + append_identifier(thd, &query, share->db.str, share->db.length); + query.append("."); + append_identifier(thd, &query, share->table_name.str, share->table_name.length); - int errcode= query_error_code(thd, TRUE); - if (thd->binlog_query(THD::STMT_QUERY_TYPE, - query.ptr(), query.length(), - FALSE, FALSE, FALSE, errcode)) - return TRUE; - } - else - { - /* - As replication is maybe going to be corrupted, we need to warn the - DBA on top of warning the client (which will automatically be done - because of MYF(MY_WME) in my_malloc() above). - */ - sql_print_error("When opening HEAP table, could not allocate memory " - "to write 'DELETE FROM %`s.%`s' to the binary log", - share->db.str, share->table_name.str); - delete entry->triggers; + + /* + we bypass thd->binlog_query() here, + as it does a lot of extra work, that is simply wrong in this case + */ + Query_log_event qinfo(thd, query.ptr(), query.length(), + FALSE, TRUE, TRUE, 0); + if (mysql_bin_log.write(&qinfo)) return TRUE; - } } } return FALSE; @@ -9433,6 +9421,7 @@ open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, if (mysql_make_view(thd, parser, table_desc, (prgflag & OPEN_VIEW_NO_PARSE))) goto err; + status_var_increment(thd->status_var.opened_views); } else { diff --git a/sql/sql_class.h b/sql/sql_class.h index 4943a39f491..3aa0c5ae9c7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -617,25 +617,17 @@ typedef struct system_status_var ulong ha_savepoint_count; ulong ha_savepoint_rollback_count; -#if 0 - /* KEY_CACHE parts. These are copies of the original */ - ulong key_blocks_changed; - ulong key_blocks_used; - ulong key_cache_r_requests; - ulong key_cache_read; - ulong key_cache_w_requests; - ulong key_cache_write; - /* END OF KEY_CACHE parts */ -#endif - ulong net_big_packet_count; ulong opened_tables; ulong opened_shares; + ulong opened_views; /* +1 opening a view */ + ulong select_full_join_count; ulong select_full_range_join_count; ulong select_range_count; ulong select_range_check_count; ulong select_scan_count; + ulong executed_triggers; ulong long_query_count; ulong filesort_merge_passes; ulong filesort_range_count; @@ -650,6 +642,16 @@ typedef struct system_status_var ulong com_stmt_reset; ulong com_stmt_close; + /* Features used */ + ulong feature_dynamic_columns; /* +1 when creating a dynamic column */ + ulong feature_fulltext; /* +1 when MATCH is used */ + ulong feature_gis; /* +1 opening a table with GIS features */ + ulong feature_locale; /* +1 when LOCALE is set */ + ulong feature_subquery; /* +1 when subqueries are used */ + ulong feature_timezone; /* +1 when XPATH is used */ + ulong feature_trigger; /* +1 opening a table with triggers */ + ulong feature_xml; /* +1 when XPATH is used */ + ulong empty_queries; ulong access_denied_errors; ulong lost_connections; @@ -1680,7 +1682,7 @@ public: my_hrtime_t user_time; // track down slow pthread_create ulonglong prior_thr_create_utime, thr_create_utime; - ulonglong start_utime, utime_after_lock; + ulonglong start_utime, utime_after_lock, utime_after_query; // Process indicator struct { @@ -2483,8 +2485,8 @@ public: */ void update_server_status() { - ulonglong end_utime_of_query= current_utime(); - if (end_utime_of_query > utime_after_lock + variables.long_query_time) + utime_after_query= current_utime(); + if (utime_after_query > utime_after_lock + variables.long_query_time) server_status|= SERVER_QUERY_WAS_SLOW; } inline ulonglong found_rows(void) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e0d0d4c4223..3c3b9f85727 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -329,7 +329,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, /* - Check update fields for the timestamp field. + Check update fields for the timestamp and auto_increment fields. SYNOPSIS check_update_fields() @@ -342,6 +342,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, If the update fields include the timestamp field, remove TIMESTAMP_AUTO_SET_ON_UPDATE from table->timestamp_field_type. + If the update fields include an autoinc field, set the + table->next_number_field_updated flag. + RETURN 0 OK -1 Error @@ -353,7 +356,9 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, { TABLE *table= insert_table_list->table; my_bool timestamp_mark; + my_bool autoinc_mark; LINT_INIT(timestamp_mark); + LINT_INIT(autoinc_mark); if (table->timestamp_field) { @@ -365,6 +370,19 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, table->timestamp_field->field_index); } + table->next_number_field_updated= FALSE; + + if (table->found_next_number_field) + { + /* + Unmark the auto_increment field so that we can check if this is modified + by update_fields + */ + autoinc_mark= bitmap_test_and_clear(table->write_set, + table->found_next_number_field-> + field_index); + } + /* Check the fields we are going to modify */ if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0)) return -1; @@ -386,6 +404,18 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, bitmap_set_bit(table->write_set, table->timestamp_field->field_index); } + + if (table->found_next_number_field) + { + if (bitmap_is_set(table->write_set, + table->found_next_number_field->field_index)) + table->next_number_field_updated= TRUE; + + if (autoinc_mark) + bitmap_set_bit(table->write_set, + table->found_next_number_field->field_index); + } + return 0; } @@ -1563,6 +1593,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) MY_BITMAP *save_read_set, *save_write_set; ulonglong prev_insert_id= table->file->next_insert_id; ulonglong insert_id_for_cur_row= 0; + ulonglong prev_insert_id_for_cur_row= 0; DBUG_ENTER("write_record"); info->records++; @@ -1598,7 +1629,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) report error as usual. We will not do any duplicate key processing. */ if (info->ignore) + { + table->file->print_error(error, MYF(ME_JUST_WARNING)); goto ok_or_after_trg_err; /* Ignoring a not fatal error, return 0 */ + } goto err; } if ((int) (key_nr = table->file->get_dup_key(error)) < 0) @@ -1688,6 +1722,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (info->ignore && !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) { + table->file->print_error(error, MYF(ME_JUST_WARNING)); goto ok_or_after_trg_err; } goto err; @@ -1705,6 +1740,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) INSERT query, which is handled separately by THD::arg_of_last_insert_id_function. */ + prev_insert_id_for_cur_row= table->file->insert_id_for_cur_row; insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; trg_error= (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, @@ -1712,9 +1748,22 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) info->copied++; } - if (table->next_number_field) - table->file->adjust_next_insert_id_after_explicit_value( - table->next_number_field->val_int()); + /* + Only update next_insert_id if the AUTO_INCREMENT value was explicitly + updated, so we don't update next_insert_id with the value from the + row being updated. Otherwise reset next_insert_id to what it was + before the duplicate key error, since that value is unused. + */ + if (table->next_number_field_updated) + { + DBUG_ASSERT(table->next_number_field != NULL); + + table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int()); + } + else + { + table->file->restore_auto_increment(prev_insert_id_for_cur_row); + } goto ok_or_after_trg_err; } else /* DUP_REPLACE */ @@ -1803,6 +1852,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (!info->ignore || table->file->is_fatal_error(error, HA_CHECK_DUP)) goto err; + table->file->print_error(error, MYF(ME_JUST_WARNING)); table->file->restore_auto_increment(prev_insert_id); goto ok_or_after_trg_err; } diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index f953cf4df57..91a98d8c6f1 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -3876,8 +3876,9 @@ int JOIN_TAB_SCAN_MRR::next() If a record in in an incremental cache contains no fields then the association for the last record in cache will be equal to cache->end_pos */ - DBUG_ASSERT(cache->buff <= (uchar *) (*ptr) && - (uchar *) (*ptr) <= cache->end_pos); + DBUG_ASSERT((!(mrr_mode & HA_MRR_NO_ASSOCIATION))? + (cache->buff <= (uchar *) (*ptr) && + (uchar *) (*ptr) <= cache->end_pos): TRUE); if (join_tab->table->vfield) update_virtual_fields(join->thd, join_tab->table); } @@ -4543,7 +4544,7 @@ bool JOIN_CACHE_BKAH::prepare_look_for_matches(bool skip_last) { last_matching_rec_ref_ptr= next_matching_rec_ref_ptr= 0; if (no_association && - (curr_matching_chain= get_matching_chain_by_join_key())) + !(curr_matching_chain= get_matching_chain_by_join_key())) return 1; last_matching_rec_ref_ptr= get_next_rec_ref(curr_matching_chain); return 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 91bdad3da62..175c2c1d672 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1438,6 +1438,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); + thd_proc_info(thd, "updating status"); /* Finalize server status flags after executing a command. */ thd->update_server_status(); thd->protocol->end_statement(); @@ -1495,38 +1496,30 @@ void log_slow_statement(THD *thd) DBUG_VOID_RETURN; // Don't set time for sub stmt /* Follow the slow log filter configuration. */ - if (!(thd->variables.log_slow_filter & thd->query_plan_flags)) + if (!thd->enable_slow_log || + !(thd->variables.log_slow_filter & thd->query_plan_flags)) DBUG_VOID_RETURN; - /* - If rate limiting of slow log writes is enabled, decide whether to log - this query to the log or not. - */ - if (thd->variables.log_slow_rate_limit > 1 && - (global_query_id % thd->variables.log_slow_rate_limit) != 0) - DBUG_VOID_RETURN; + if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || + ((thd->server_status & + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && + opt_log_queries_not_using_indexes && + !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && + thd->examined_row_count >= thd->variables.min_examined_row_limit) + { + thd->status_var.long_query_count++; + /* + If rate limiting of slow log writes is enabled, decide whether to log + this query to the log or not. + */ + if (thd->variables.log_slow_rate_limit > 1 && + (global_query_id % thd->variables.log_slow_rate_limit) != 0) + DBUG_VOID_RETURN; - /* - Do not log administrative statements unless the appropriate option is - set. - */ - if (thd->enable_slow_log) - { - ulonglong end_utime_of_query= thd->current_utime(); thd_proc_info(thd, "logging slow query"); - - if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || - ((thd->server_status & - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && - opt_log_queries_not_using_indexes && - !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && - thd->examined_row_count >= thd->variables.min_examined_row_limit) - { - thd_proc_info(thd, "logging slow query"); - thd->status_var.long_query_count++; - slow_log_print(thd, thd->query(), thd->query_length(), - end_utime_of_query); - } + slow_log_print(thd, thd->query(), thd->query_length(), + thd->utime_after_query); + thd_proc_info(thd, 0); } DBUG_VOID_RETURN; } @@ -2974,6 +2967,7 @@ end_with_restore_list: DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act2))); };); + DEBUG_SYNC(thd, "after_mysql_insert"); break; } case SQLCOM_REPLACE_SELECT: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 264ff6552db..f0c786dea86 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8072,37 +8072,6 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, } /** - This function is only called for const items on fields which are keys. - - @return - returns 1 if there was some conversion made when the field was stored. -*/ - -bool -store_val_in_field(Field *field, Item *item, enum_check_fields check_flag) -{ - bool error; - TABLE *table= field->table; - THD *thd= table->in_use; - ha_rows cuted_fields=thd->cuted_fields; - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, - table->write_set); - - /* - we should restore old value of count_cuted_fields because - store_val_in_field can be called from mysql_insert - with select_insert, which make count_cuted_fields= 1 - */ - enum_check_fields old_count_cuted_fields= thd->count_cuted_fields; - thd->count_cuted_fields= check_flag; - error= item->save_in_field(field, 1); - thd->count_cuted_fields= old_count_cuted_fields; - dbug_tmp_restore_column_map(table->write_set, old_map); - return error || cuted_fields != thd->cuted_fields; -} - - -/** @details Initialize a JOIN as a query execution plan that accesses a single table via a table scan. @@ -17760,7 +17729,7 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item) field->real_type() != MYSQL_TYPE_VARCHAR && (field->type() != MYSQL_TYPE_FLOAT || field->decimals() == 0)) { - return !store_val_in_field(field, right_item, CHECK_FIELD_WARN); + return !right_item->save_in_field_no_warnings(field, 1); } } } diff --git a/sql/sql_select.h b/sql/sql_select.h index be5f523a7e2..118a684ab62 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1430,7 +1430,6 @@ typedef struct st_select_check { extern const char *join_type_str[]; /* Extern functions in sql_select.cc */ -bool store_val_in_field(Field *field, Item *val, enum_check_fields check_flag); void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, List<Item> &fields, bool reset_with_sum_func); bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, @@ -1504,6 +1503,7 @@ public: enum_check_fields saved_count_cuted_fields= thd->count_cuted_fields; ulonglong sql_mode= thd->variables.sql_mode; thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); + thd->variables.sql_mode|= MODE_INVALID_DATES; thd->count_cuted_fields= CHECK_FIELD_IGNORE; diff --git a/sql/sql_state.c b/sql/sql_state.c index 511dc65917b..5acf97f16cc 100644 --- a/sql/sql_state.c +++ b/sql/sql_state.c @@ -17,6 +17,7 @@ #include <my_global.h> #include <mysqld_error.h> +#include <my_base.h> struct st_map_errno_to_sqlstate { @@ -27,6 +28,7 @@ struct st_map_errno_to_sqlstate struct st_map_errno_to_sqlstate sqlstate_map[]= { +#include <handler_state.h> #include <sql_state.h> }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 06ec9a733c6..5a6090e5d9a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1828,6 +1828,7 @@ int write_bin_log(THD *thd, bool clear_error, if (mysql_bin_log.is_open()) { int errcode= 0; + thd_proc_info(thd, "Writing to binlog"); if (clear_error) thd->clear_error(); else @@ -1835,6 +1836,7 @@ int write_bin_log(THD *thd, bool clear_error, error= thd->binlog_query(THD::STMT_QUERY_TYPE, query, query_length, is_trans, FALSE, FALSE, errcode); + thd_proc_info(thd, 0); } return error; } @@ -7476,7 +7478,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to, (to->key_info[0].key_part[0].field->flags & AUTO_INCREMENT_FLAG)) err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE); - to->file->print_keydup_error(key_nr, err_msg); + to->file->print_keydup_error(key_nr, err_msg, MYF(0)); break; } } diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 5972c8918ba..5c0471fdfaa 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -25,9 +25,9 @@ #include <m_ctype.h> - /* Some functions to calculate dates */ +#define MAX_DAY_NUMBER 3652424L -#ifndef TESTTIME + /* Some functions to calculate dates */ /* Name description of interval names used in statements. @@ -147,46 +147,42 @@ uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year) /* Change a daynr to year, month and day */ /* Daynr 0 is returned as date 00.00.00 */ -void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, +bool get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, uint *ret_day) { uint year,temp,leap_day,day_of_year,days_in_year; uchar *month_pos; DBUG_ENTER("get_date_from_daynr"); - if (daynr <= 365L || daynr >= 3652500) - { /* Fix if wrong daynr */ - *ret_year= *ret_month = *ret_day =0; + if (daynr < 365 || daynr > MAX_DAY_NUMBER) + DBUG_RETURN(1); + + year= (uint) (daynr*100 / 36525L); + temp=(((year-1)/100+1)*3)/4; + day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp; + while (day_of_year > (days_in_year= calc_days_in_year(year))) + { + day_of_year-=days_in_year; + (year)++; } - else + leap_day=0; + if (days_in_year == 366) { - year= (uint) (daynr*100 / 36525L); - temp=(((year-1)/100+1)*3)/4; - day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp; - while (day_of_year > (days_in_year= calc_days_in_year(year))) + if (day_of_year > 31+28) { - day_of_year-=days_in_year; - (year)++; + day_of_year--; + if (day_of_year == 31+28) + leap_day=1; /* Handle leapyears leapday */ } - leap_day=0; - if (days_in_year == 366) - { - if (day_of_year > 31+28) - { - day_of_year--; - if (day_of_year == 31+28) - leap_day=1; /* Handle leapyears leapday */ - } - } - *ret_month=1; - for (month_pos= days_in_month ; - day_of_year > (uint) *month_pos ; - day_of_year-= *(month_pos++), (*ret_month)++) - ; - *ret_year=year; - *ret_day=day_of_year+leap_day; } - DBUG_VOID_RETURN; + *ret_month=1; + for (month_pos= days_in_month ; + day_of_year > (uint) *month_pos ; + day_of_year-= *(month_pos++), (*ret_month)++) + ; + *ret_year=year; + *ret_day=day_of_year+leap_day; + DBUG_RETURN(0); } /* Functions to handle periods */ @@ -842,7 +838,6 @@ void make_truncated_value_warning(THD *thd, /* Daynumber from year 0 to 9999-12-31 */ -#define MAX_DAY_NUMBER 3652424L #define COMBINE(X) \ (((((X)->day * 24LL + (X)->hour) * 60LL + \ (X)->minute) * 60LL + (X)->second)*1000000LL + \ @@ -909,19 +904,18 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, daynr= usec; /* Day number from year 0 to 9999-12-31 */ - if ((ulonglong) daynr > MAX_DAY_NUMBER) + if (get_date_from_daynr((long) daynr, <ime->year, <ime->month, + <ime->day)) goto invalid_date; - get_date_from_daynr((long) daynr, <ime->year, <ime->month, - <ime->day); break; } case INTERVAL_WEEK: period= (calc_daynr(ltime->year,ltime->month,ltime->day) + sign * (long) interval.day); /* Daynumber from year 0 to 9999-12-31 */ - if ((ulong) period > MAX_DAY_NUMBER) + if (get_date_from_daynr((long) period,<ime->year,<ime->month, + <ime->day)) goto invalid_date; - get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day); break; case INTERVAL_YEAR: ltime->year+= sign * (long) interval.year; @@ -1071,4 +1065,3 @@ int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) return 0; } -#endif diff --git a/sql/sql_time.h b/sql/sql_time.h index 026a15cb796..c1a75bb2ad3 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -33,7 +33,7 @@ typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT; ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); -void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); +bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code); bool str_to_time_with_warn(CHARSET_INFO *cs, const char *str, uint length, MYSQL_TIME *l_time, ulonglong fuzzydate); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 1b942ecc93b..aff00f9fcf4 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1334,6 +1334,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, triggers->definitions_list.elements); table->triggers= triggers; + status_var_increment(thd->status_var.feature_trigger); /* TODO: This could be avoided if there is no triggers @@ -2116,6 +2117,8 @@ bool Table_triggers_list::process_triggers(THD *thd, if (sp_trigger == NULL) return FALSE; + status_var_increment(thd->status_var.executed_triggers); + if (old_row_is_record1) { old_field= record1_field; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index bf261bffec3..fb0951410a4 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -406,7 +406,7 @@ int mysql_update(THD *thd, table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); select= make_select(table, 0, 0, conds, 0, &error); - if (error || !limit || + if (error || !limit || thd->is_error() || (select && select->check_quick(thd, safe_update, limit))) { delete select; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8ef59fafb98..555efaf366d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1064,6 +1064,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token KILL_SYM %token LANGUAGE_SYM /* SQL-2003-R */ %token LAST_SYM /* SQL-2003-N */ +%token LAST_VALUE %token LE /* OPERATOR */ %token LEADING /* SQL-2003-R */ %token LEAVES @@ -5872,9 +5873,9 @@ attribute: NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; } | not NULL_SYM { Lex->type|= NOT_NULL_FLAG; } | DEFAULT now_or_signed_literal { Lex->default_value=$2; } - | ON UPDATE_SYM NOW_SYM opt_time_precision + | ON UPDATE_SYM NOW_SYM optional_braces { - Item *item= new (YYTHD->mem_root) Item_func_now_local($4); + Item *item= new (YYTHD->mem_root) Item_func_now_local(6); if (item == NULL) MYSQL_YYABORT; Lex->on_update_value= item; @@ -5966,9 +5967,9 @@ type_with_opt_collate: now_or_signed_literal: - NOW_SYM opt_time_precision + NOW_SYM optional_braces { - $$= new (YYTHD->mem_root) Item_func_now_local($2); + $$= new (YYTHD->mem_root) Item_func_now_local(6); if ($$ == NULL) MYSQL_YYABORT; } @@ -8890,6 +8891,12 @@ function_call_conflict: if ($$ == NULL) MYSQL_YYABORT; } + | LAST_VALUE '(' expr_list ')' + { + $$= new (YYTHD->mem_root) Item_func_last_value(* $3); + if ($$ == NULL) + MYSQL_YYABORT; + } | MICROSECOND_SYM '(' expr ')' { $$= new (YYTHD->mem_root) Item_func_microsecond($3); @@ -13088,6 +13095,7 @@ keyword_sp: | ISSUER_SYM {} | INSERT_METHOD {} | KEY_BLOCK_SIZE {} + | LAST_VALUE {} | LAST_SYM {} | LEAVES {} | LESS_SYM {} diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index fe48f953c28..4a003a89a7e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3578,22 +3578,25 @@ static bool check_locale(sys_var *self, THD *thd, set_var *var) if (!locale->errmsgs->errmsgs) { + bool res; mysql_mutex_lock(&LOCK_error_messages); - if (!locale->errmsgs->errmsgs && - read_texts(ERRMSG_FILE, locale->errmsgs->language, - &locale->errmsgs->errmsgs, - ER_ERROR_LAST - ER_ERROR_FIRST + 1)) + res= (!locale->errmsgs->errmsgs && + read_texts(ERRMSG_FILE, locale->errmsgs->language, + &locale->errmsgs->errmsgs, + ER_ERROR_LAST - ER_ERROR_FIRST + 1)); + mysql_mutex_unlock(&LOCK_error_messages); + if (res) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "Can't process error message file for locale '%s'", locale->name); - mysql_mutex_unlock(&LOCK_error_messages); return true; } - mysql_mutex_unlock(&LOCK_error_messages); } + status_var_increment(thd->status_var.feature_locale); return false; } + static Sys_var_struct Sys_lc_messages( "lc_messages", "Set the language used for the error messages", SESSION_VAR(lc_messages), NO_CMD_LINE, diff --git a/sql/table.cc b/sql/table.cc index d733c5ada62..47b2cae1a04 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4949,6 +4949,28 @@ void TABLE_LIST::set_check_materialized() } } +TABLE *TABLE_LIST::get_real_join_table() +{ + TABLE_LIST *tbl= this; + while (tbl->table == NULL || tbl->table->reginfo.join_tab == NULL) + { + if (tbl->view == NULL && tbl->derived == NULL) + break; + /* we do not support merging of union yet */ + DBUG_ASSERT(tbl->view == NULL || + tbl->view->select_lex.next_select() == NULL); + DBUG_ASSERT(tbl->derived == NULL || + tbl->derived->first_select()->next_select() == NULL); + + if (tbl->table) + table= tbl->table; + tbl= (tbl->view != NULL ? + tbl->view->select_lex.get_table_list() : + tbl->derived->first_select()->get_table_list()); + } + return tbl->table; +} + Natural_join_column::Natural_join_column(Field_translator *field_param, TABLE_LIST *tab) diff --git a/sql/table.h b/sql/table.h index fc451ff5050..9e26f907920 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1088,15 +1088,20 @@ public: uint db_stat; /* mode of file as in handler.h */ /* number of select if it is derived table */ uint derived_select_number; - int current_lock; /* Type of lock on table */ - bool copy_blobs; /* copy_blobs when storing */ - /* 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0. If maybe_null !=0, this table is inner w.r.t. some outer join operation, and null_row may be true. */ uint maybe_null; + int current_lock; /* Type of lock on table */ + bool copy_blobs; /* copy_blobs when storing */ + /* + Set if next_number_field is in the UPDATE fields of INSERT ... ON DUPLICATE + KEY UPDATE. + */ + bool next_number_field_updated; + /* If true, the current table row is considered to have all columns set to NULL, including columns declared as "not null" (see maybe_null). @@ -1964,6 +1969,7 @@ struct TABLE_LIST TABLE_LIST *find_underlying_table(TABLE *table); TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); + TABLE *get_real_join_table(); bool is_leaf_for_name_resolution(); inline TABLE_LIST *top_table() { return belong_to_view ? belong_to_view : this; } diff --git a/sql/tztime.cc b/sql/tztime.cc index 9fae9f3fedd..ba24cab9ca7 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2329,7 +2329,6 @@ my_tz_find(THD *thd, const String *name) if (!str_to_offset(name->ptr(), name->length(), &offset)) { - if (!(result_tz= (Time_zone_offset *)my_hash_search(&offset_tzs, (const uchar *)&offset, sizeof(long)))) @@ -2371,6 +2370,9 @@ my_tz_find(THD *thd, const String *name) mysql_mutex_unlock(&tz_LOCK); + if (result_tz && result_tz != my_tz_SYSTEM && result_tz != my_tz_UTC) + status_var_increment(thd->status_var.feature_timezone); + DBUG_RETURN(result_tz); } |