diff options
author | unknown <tsmith@ramayana.hindu.god> | 2007-12-07 03:56:03 -0700 |
---|---|---|
committer | unknown <tsmith@ramayana.hindu.god> | 2007-12-07 03:56:03 -0700 |
commit | 284cb0e560293187b9d2d7a38aa71de9d9637567 (patch) | |
tree | b719b75e443bf2787a2c520cc6e9955e4eb6a4a8 /sql | |
parent | b5f919ddfa3bfe6202302bb3e88e252c68550ed7 (diff) | |
parent | 6e776686d4cbaac919eee8300b2c85e2cf5825ec (diff) | |
download | mariadb-git-284cb0e560293187b9d2d7a38aa71de9d9637567.tar.gz |
Merge tsmith@bk-internal.mysql.com:/home/bk/mysql-5.1
into ramayana.hindu.god:/home/tsmith/m/bk/maint/51
sql/sql_acl.cc:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_table.cc:
Auto merged
mysql-test/r/grant.result:
Manual merge
mysql-test/t/grant.test:
Manual merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 80 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 38 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 4 | ||||
-rw-r--r-- | sql/item_strfunc.h | 7 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 48 | ||||
-rw-r--r-- | sql/opt_range.cc | 8 | ||||
-rw-r--r-- | sql/partition_info.cc | 4 | ||||
-rw-r--r-- | sql/records.cc | 3 | ||||
-rw-r--r-- | sql/set_var.cc | 51 | ||||
-rw-r--r-- | sql/set_var.h | 14 | ||||
-rw-r--r-- | sql/sql_acl.cc | 20 | ||||
-rw-r--r-- | sql/sql_array.h | 2 | ||||
-rw-r--r-- | sql/sql_help.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 9 | ||||
-rw-r--r-- | sql/sql_select.cc | 66 | ||||
-rw-r--r-- | sql/sql_table.cc | 74 | ||||
-rw-r--r-- | sql/structs.h | 2 | ||||
-rw-r--r-- | sql/unireg.cc | 2 |
18 files changed, 326 insertions, 108 deletions
diff --git a/sql/field.cc b/sql/field.cc index cd8228305e4..942c0538abb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6401,24 +6401,74 @@ int Field_str::store(double nr) ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; uint length; - bool use_scientific_notation= TRUE; uint local_char_length= field_length / charset()->mbmaxlen; - /* - Check fabs(nr) against longest value that can be stored in field, - which depends on whether the value is < 1 or not, and negative or not - */ double anr= fabs(nr); + bool fractional= (anr != floor(anr)); int neg= (nr < 0.0) ? 1 : 0; - if (local_char_length > 4 && local_char_length < 32 && - (anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */ - : anr < log_10[local_char_length-neg]-1)) - use_scientific_notation= FALSE; - - length= (uint) my_sprintf(buff, (buff, "%-.*g", - (use_scientific_notation ? - max(0, (int)local_char_length-neg-5) : - local_char_length), - nr)); + uint max_length; + int exp; + uint digits; + uint i; + + /* Calculate the exponent from the 'e'-format conversion */ + if (anr < 1.0 && anr > 0) + { + for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100); + for (; anr < 1e-10; exp-= 10, anr*= 1e10); + for (i= 1; anr < 1 / log_10[i]; exp--, i++); + exp--; + } + else + { + for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100); + for (; anr > 1e10; exp+= 10, anr/= 1e10); + for (i= 1; anr > log_10[i]; exp++, i++); + } + + max_length= local_char_length - neg; + + /* + Since in sprintf("%g") precision means the number of significant digits, + calculate the maximum number of significant digits if the 'f'-format + would be used (+1 for decimal point if the number has a fractional part). + */ + digits= max(0, (int) max_length - fractional); + /* + If the exponent is negative, decrease digits by the number of leading zeros + after the decimal point that do not count as significant digits. + */ + if (exp < 0) + digits= max(0, (int) digits + exp); + /* + 'e'-format is used only if the exponent is less than -4 or greater than or + equal to the precision. In this case we need to adjust the number of + significant digits to take "e+NN" + decimal point into account (hence -5). + We also have to reserve one additional character if abs(exp) >= 100. + */ + if (exp >= (int) digits || exp < -4) + digits= max(0, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); + + /* Limit precision to DBL_DIG to avoid garbage past significant digits */ + set_if_smaller(digits, DBL_DIG); + + length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr)); + +#ifdef __WIN__ + /* + Windows always zero-pads the exponent to 3 digits, we want to remove the + leading 0 to match the sprintf() output on other platforms. + */ + if ((exp >= (int) digits || exp < -4) && exp > -100 && exp < 100) + { + DBUG_ASSERT(length >= 6); /* 1e+NNN */ + uint tmp= length - 3; + buff[tmp]= buff[tmp + 1]; + tmp++; + buff[tmp]= buff[tmp + 1]; + length--; + } +#endif + /* +1 below is because "precision" in %g above means the max. number of significant digits, not the output width. diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 633db8367c1..3c738fe9ff1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2626,6 +2626,23 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref) } +void Item_func_case::agg_str_lengths(Item* arg) +{ + set_if_bigger(max_length, arg->max_length); + set_if_bigger(decimals, arg->decimals); + unsigned_flag= unsigned_flag && arg->unsigned_flag; +} + + +void Item_func_case::agg_num_lengths(Item *arg) +{ + uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals, + arg->unsigned_flag) - arg->decimals; + set_if_bigger(max_length, len); + set_if_bigger(decimals, arg->decimals); + unsigned_flag= unsigned_flag && arg->unsigned_flag; +} + void Item_func_case::fix_length_and_dec() { @@ -2689,15 +2706,22 @@ void Item_func_case::fix_length_and_dec() max_length=0; decimals=0; - for (uint i=0 ; i < ncases ; i+=2) + unsigned_flag= TRUE; + if (cached_result_type == STRING_RESULT) { - set_if_bigger(max_length,args[i+1]->max_length); - set_if_bigger(decimals,args[i+1]->decimals); + for (uint i= 0; i < ncases; i+= 2) + agg_str_lengths(args[i + 1]); + if (else_expr_num != -1) + agg_str_lengths(args[else_expr_num]); } - if (else_expr_num != -1) + else { - set_if_bigger(max_length,args[else_expr_num]->max_length); - set_if_bigger(decimals,args[else_expr_num]->decimals); + for (uint i= 0; i < ncases; i+= 2) + agg_num_lengths(args[i + 1]); + if (else_expr_num != -1) + agg_num_lengths(args[else_expr_num]); + max_length= my_decimal_precision_to_length(max_length + decimals, decimals, + unsigned_flag); } } @@ -2901,7 +2925,7 @@ static inline int cmp_ulongs (ulonglong a_val, ulonglong b_val) SYNOPSIS cmp_longlong() - cmp_arg an argument passed to the calling function (qsort2) + cmp_arg an argument passed to the calling function (my_qsort2) a left argument b right argument diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8df0e1af331..188d87a69ca 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -742,7 +742,7 @@ public: virtual uchar *get_value(Item *item)=0; void sort() { - qsort2(base,used_count,size,compare,collation); + my_qsort2(base,used_count,size,compare,collation); } int find(Item *item); @@ -1145,6 +1145,8 @@ public: Item *find_item(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } void cleanup(); + void agg_str_lengths(Item *arg); + void agg_num_lengths(Item *arg); }; /* diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 3608568bd5e..0d7cd66acff 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -657,7 +657,12 @@ public: } String* val_str(String* str); const char *func_name() const { return "inet_ntoa"; } - void fix_length_and_dec() { decimals = 0; max_length=3*8+7; maybe_null=1;} + void fix_length_and_dec() + { + decimals= 0; + max_length= 3 * 8 + 7; + maybe_null= 1; + } }; class Item_func_quote :public Item_str_func diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index e7d513e9d6a..3d4a6de83ac 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3241,38 +3241,42 @@ get_date_time_result_type(const char *format, uint length) void Item_func_str_to_date::fix_length_and_dec() { - char format_buff[64]; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; maybe_null= 1; decimals=0; cached_field_type= MYSQL_TYPE_DATETIME; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - format= args[1]->val_str(&format_str); - if (!args[1]->null_value && (const_item= args[1]->const_item())) + if ((const_item= args[1]->const_item())) { - cached_format_type= get_date_time_result_type(format->ptr(), - format->length()); - switch (cached_format_type) { - case DATE_ONLY: - cached_timestamp_type= MYSQL_TIMESTAMP_DATE; - cached_field_type= MYSQL_TYPE_DATE; - max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - case TIME_ONLY: - case TIME_MICROSECOND: - cached_timestamp_type= MYSQL_TIMESTAMP_TIME; - cached_field_type= MYSQL_TYPE_TIME; - max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - default: - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; - cached_field_type= MYSQL_TYPE_DATETIME; - break; + char format_buff[64]; + String format_str(format_buff, sizeof(format_buff), &my_charset_bin); + String *format= args[1]->val_str(&format_str); + if (!args[1]->null_value) + { + cached_format_type= get_date_time_result_type(format->ptr(), + format->length()); + switch (cached_format_type) { + case DATE_ONLY: + cached_timestamp_type= MYSQL_TIMESTAMP_DATE; + cached_field_type= MYSQL_TYPE_DATE; + max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + case TIME_ONLY: + case TIME_MICROSECOND: + cached_timestamp_type= MYSQL_TIMESTAMP_TIME; + cached_field_type= MYSQL_TYPE_TIME; + max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + default: + cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; + cached_field_type= MYSQL_TYPE_DATETIME; + break; + } } } } + bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { DATE_TIME_FORMAT date_time_format; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index c67687b2bde..761897f21b5 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4463,8 +4463,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, ROR_SCAN_INFO's. Step 2: Get best ROR-intersection using an approximate algorithm. */ - qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), - (qsort_cmp)cmp_ror_scan_info); + my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), + (qsort_cmp)cmp_ror_scan_info); DBUG_EXECUTE("info",print_ror_scans_arr(param->table, "ordered", tree->ror_scans, tree->ror_scans_end);); @@ -4656,8 +4656,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, bitmap_get_first(&(*scan)->covered_fields); } - qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), - (qsort_cmp)cmp_ror_scan_info_covering); + my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), + (qsort_cmp)cmp_ror_scan_info_covering); DBUG_EXECUTE("info", print_ror_scans_arr(param->table, "remaining scans", diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ab887d5dda0..86d50cdf524 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -666,8 +666,8 @@ bool partition_info::check_list_constants() if (fixed && no_list_values) { bool first= TRUE; - qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), - &list_part_cmp); + my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), + &list_part_cmp); i= 0; LINT_INIT(prev_value); diff --git a/sql/records.cc b/sql/records.cc index 0bf815e4073..349cc4a8329 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -567,7 +567,8 @@ static int rr_from_cache(READ_RECORD *info) int3store(ref_position,(long) i); ref_position+=3; } - qsort(info->read_positions,length,info->struct_length,(qsort_cmp) rr_cmp); + my_qsort(info->read_positions, length, info->struct_length, + (qsort_cmp) rr_cmp); position=info->read_positions; for (i=0 ; i < length ; i++) diff --git a/sql/set_var.cc b/sql/set_var.cc index d408b2de64e..de5f1fbcd0f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -164,7 +164,8 @@ static sys_var_character_set_sv sys_character_set_server(&vars, "character_set_s sys_var_const_str sys_charset_system(&vars, "character_set_system", (char *)my_charset_utf8_general_ci.name); static sys_var_character_set_database sys_character_set_database(&vars, "character_set_database"); -static sys_var_character_set_sv sys_character_set_client(&vars, "character_set_client", +static sys_var_character_set_client sys_character_set_client(&vars, + "character_set_client", &SV::character_set_client, &default_charset_info); static sys_var_character_set_sv sys_character_set_connection(&vars, "character_set_connection", @@ -1865,6 +1866,21 @@ CHARSET_INFO **sys_var_character_set_sv::ci_ptr(THD *thd, enum_var_type type) } +bool sys_var_character_set_client::check(THD *thd, set_var *var) +{ + if (sys_var_character_set_sv::check(thd, var)) + return 1; + /* Currently, UCS-2 cannot be used as a client character set */ + if (var->save_result.charset->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, + var->save_result.charset->csname); + return 1; + } + return 0; +} + + CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, enum_var_type type) { @@ -2106,18 +2122,24 @@ void sys_var_log_state::set_default(THD *thd, enum_var_type type) static int sys_check_log_path(THD *thd, set_var *var) { - char path[FN_REFLEN]; + char path[FN_REFLEN], buff[FN_REFLEN]; MY_STAT f_stat; - const char *var_path= var->value->str_value.ptr(); + String str(buff, sizeof(buff), system_charset_info), *res; + const char *log_file_str; + + if (!(res= var->value->val_str(&str))) + goto err; + + log_file_str= res->c_ptr(); bzero(&f_stat, sizeof(MY_STAT)); - (void) unpack_filename(path, var_path); + (void) unpack_filename(path, log_file_str); if (my_stat(path, &f_stat, MYF(0))) { /* Check if argument is a file and we have 'write' permission */ if (!MY_S_ISREG(f_stat.st_mode) || !(f_stat.st_mode & MY_S_IWRITE)) - return -1; + goto err; } else { @@ -2126,11 +2148,16 @@ static int sys_check_log_path(THD *thd, set_var *var) Check if directory exists and we have permission to create file & write to file */ - (void) dirname_part(path, var_path, &path_length); + (void) dirname_part(path, log_file_str, &path_length); if (my_access(path, (F_OK|W_OK))) - return -1; + goto err; } return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, + res ? log_file_str : "NULL"); + return 1; } @@ -2283,6 +2310,13 @@ uchar *sys_var_log_output::value_ptr(THD *thd, enum_var_type type, int set_var_collation_client::check(THD *thd) { + /* Currently, UCS-2 cannot be used as a client character set */ + if (character_set_client->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + character_set_client->csname); + return 1; + } return 0; } @@ -2904,7 +2938,8 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted) /* sort into order */ if (sorted) - qsort(result, count + fixed_count, sizeof(SHOW_VAR), (qsort_cmp)show_cmp); + my_qsort(result, count + fixed_count, sizeof(SHOW_VAR), + (qsort_cmp) show_cmp); /* make last element empty */ bzero(show, sizeof(SHOW_VAR)); diff --git a/sql/set_var.h b/sql/set_var.h index eb2c893c89e..0e282212a3f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -667,6 +667,20 @@ public: }; +class sys_var_character_set_client: public sys_var_character_set_sv +{ +public: + sys_var_character_set_client(sys_var_chain *chain, const char *name_arg, + CHARSET_INFO *SV::*offset_arg, + CHARSET_INFO **global_default_arg, + bool is_nullable= 0) + : sys_var_character_set_sv(chain, name_arg, offset_arg, global_default_arg, + is_nullable) + { } + bool check(THD *thd, set_var *var); +}; + + class sys_var_character_set_database :public sys_var_character_set { public: diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 519ca429aa6..58ba8c28fb7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -365,8 +365,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) #endif VOID(push_dynamic(&acl_hosts,(uchar*) &host)); } - qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, - sizeof(ACL_HOST),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, + sizeof(ACL_HOST),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_hosts); @@ -553,8 +553,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) allow_all_hosts=1; // Anyone can connect } } - qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, + sizeof(ACL_USER),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_users); @@ -612,8 +612,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) #endif VOID(push_dynamic(&acl_dbs,(uchar*) &db)); } - qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, + sizeof(ACL_DB),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_dbs); init_check_host(); @@ -1243,8 +1243,8 @@ static void acl_insert_user(const char *user, const char *host, if (!acl_user.host.hostname || (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1])) allow_all_hosts=1; // Anyone can connect /* purecov: tested */ - qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, + sizeof(ACL_USER),(qsort_cmp) acl_compare); /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ rebuild_check_host(); @@ -1306,8 +1306,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db, acl_db.access=privileges; acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user); VOID(push_dynamic(&acl_dbs,(uchar*) &acl_db)); - qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, + sizeof(ACL_DB),(qsort_cmp) acl_compare); } diff --git a/sql/sql_array.h b/sql/sql_array.h index ab6fdd0c5c0..e1b22921519 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -62,7 +62,7 @@ public: void sort(CMP_FUNC cmp_func) { - qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); + my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); } }; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index c1962c8c650..0d633ce86ac 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -528,7 +528,7 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, List_iterator<String> it(*names); for (pos= pointers; pos!=end; (*pos++= it++)); - qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); + my_qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); for (pos= pointers; pos!=end; pos++) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index df425557bdf..887cc10d828 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7025,8 +7025,15 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, bool error= TRUE; // Error message is given DBUG_ENTER("create_table_precheck"); + /* + Require CREATE [TEMPORARY] privilege on new table; for + CREATE TABLE ... SELECT, also require INSERT. + */ + want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? - CREATE_TMP_ACL : CREATE_ACL); + CREATE_TMP_ACL : CREATE_ACL) | + (select_lex->item_list.elements ? INSERT_ACL : 0); + if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, 0, 0, test(create_table->schema_table)) || diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 952b94e6b6d..312da4c8206 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3723,7 +3723,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, { KEYUSE key_end,*prev,*save_pos,*use; - qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), + my_qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), (qsort_cmp) sort_keyuse); bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */ @@ -4492,8 +4492,9 @@ choose_plan(JOIN *join, table_map join_tables) Apply heuristic: pre-sort all access plans with respect to the number of records accessed. */ - qsort(join->best_ref + join->const_tables, join->tables - join->const_tables, - sizeof(JOIN_TAB*), straight_join?join_tab_cmp_straight:join_tab_cmp); + my_qsort(join->best_ref + join->const_tables, + join->tables - join->const_tables, sizeof(JOIN_TAB*), + straight_join ? join_tab_cmp_straight : join_tab_cmp); if (straight_join) { @@ -4540,6 +4541,17 @@ choose_plan(JOIN *join, table_map join_tables) ptr1 pointer to first JOIN_TAB object ptr2 pointer to second JOIN_TAB object + NOTES + The order relation implemented by join_tab_cmp() is not transitive, + i.e. it is possible to choose such a, b and c that (a < b) && (b < c) + but (c < a). This implies that result of a sort using the relation + implemented by join_tab_cmp() depends on the order in which + elements are compared, i.e. the result is implementation-specific. + Example: + a: dependent = 0x0 table->map = 0x1 found_records = 3 ptr = 0x907e6b0 + b: dependent = 0x0 table->map = 0x2 found_records = 3 ptr = 0x907e838 + c: dependent = 0x6 table->map = 0x10 found_records = 2 ptr = 0x907ecd0 + RETURN 1 if first is bigger -1 if second is bigger @@ -6440,7 +6452,15 @@ make_join_readinfo(JOIN *join, ulonglong options) else if (!table->covering_keys.is_clear_all() && !(tab->select && tab->select->quick)) { // Only read index tree - tab->index=find_shortest_key(table, & table->covering_keys); + /* + See bug #26447: "Using the clustered index for a table scan + is always faster than using a secondary index". + */ + if (table->s->primary_key != MAX_KEY && + table->file->primary_key_is_clustered()) + tab->index= table->s->primary_key; + else + tab->index=find_shortest_key(table, & table->covering_keys); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next } @@ -9201,9 +9221,43 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - new_field= new Field_new_decimal(item->max_length, maybe_null, item->name, - item->decimals, item->unsigned_flag); + { + uint8 dec= item->decimals; + uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; + uint32 len= item->max_length; + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + overflow= my_decimal_precision_to_length(intg + dec, dec, + item->unsigned_flag) - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + len -= item->decimals - dec; // corrected value fits + } + + new_field= new Field_new_decimal(len, maybe_null, item->name, + dec, item->unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be choosen diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c618d170fb7..166a2800ea8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1798,7 +1798,8 @@ bool quick_rm_table(handlerton *base,const char *db, /* Sort keys in the following order: - PRIMARY KEY - - UNIQUE keyws where all column are NOT NULL + - UNIQUE keys where all column are NOT NULL + - UNIQUE keys that don't contain partial segments - Other UNIQUE keys - Normal keys - Fulltext keys @@ -1809,26 +1810,31 @@ bool quick_rm_table(handlerton *base,const char *db, static int sort_keys(KEY *a, KEY *b) { - if (a->flags & HA_NOSAME) + ulong a_flags= a->flags, b_flags= b->flags; + + if (a_flags & HA_NOSAME) { - if (!(b->flags & HA_NOSAME)) + if (!(b_flags & HA_NOSAME)) return -1; - if ((a->flags ^ b->flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) + if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) { /* Sort NOT NULL keys before other keys */ - return (a->flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; + return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; } if (a->name == primary_key_name) return -1; if (b->name == primary_key_name) return 1; + /* Sort keys don't containing partial segments before others */ + if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG) + return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1; } - else if (b->flags & HA_NOSAME) + else if (b_flags & HA_NOSAME) return 1; // Prefer b - if ((a->flags ^ b->flags) & HA_FULLTEXT) + if ((a_flags ^ b_flags) & HA_FULLTEXT) { - return (a->flags & HA_FULLTEXT) ? 1 : -1; + return (a_flags & HA_FULLTEXT) ? 1 : -1; } /* Prefer original key order. usable_key_parts contains here @@ -2892,6 +2898,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, else key_info->flags|= HA_PACK_KEY; } + /* Check if the key segment is partial, set the key flag accordingly */ + if (length != sql_field->key_length) + key_info->flags|= HA_KEY_HAS_PART_KEY_SEG; + key_length+=length; key_part_info++; @@ -2947,8 +2957,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(TRUE); } /* Sort keys in optimized order */ - qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY), - (qsort_cmp) sort_keys); + my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY), + (qsort_cmp) sort_keys); create_info->null_bits= null_fields; DBUG_RETURN(FALSE); @@ -6879,23 +6889,35 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (order) { - from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL)); - bzero((char*) &tables,sizeof(tables)); - tables.table= from; - tables.alias= tables.table_name= from->s->table_name.str; - tables.db= from->s->db.str; - error=1; + if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered()) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + my_snprintf(warn_buff, sizeof(warn_buff), + "ORDER BY ignored as there is a user-defined clustered index" + " in the table '%-.192s'", from->s->table_name.str); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + warn_buff); + } + else + { + from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + MYF(MY_FAE | MY_ZEROFILL)); + bzero((char *) &tables, sizeof(tables)); + tables.table= from; + tables.alias= tables.table_name= from->s->table_name.str; + tables.db= from->s->db.str; + error= 1; - if (thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, - &tables, fields, all_fields, order) || - !(sortorder=make_unireg_sortorder(order, &length, NULL)) || - (from->sort.found_records = filesort(thd, from, sortorder, length, - (SQL_SELECT *) 0, HA_POS_ERROR, 1, - &examined_rows)) == - HA_POS_ERROR) - goto err; + if (thd->lex->select_lex.setup_ref_array(thd, order_num) || + setup_order(thd, thd->lex->select_lex.ref_pointer_array, + &tables, fields, all_fields, order) || + !(sortorder= make_unireg_sortorder(order, &length, NULL)) || + (from->sort.found_records= filesort(thd, from, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, + 1, &examined_rows)) == + HA_POS_ERROR) + goto err; + } }; /* Tell handler that we have values for all columns in the to table */ diff --git a/sql/structs.h b/sql/structs.h index 09a3c4d7285..662d0a680b8 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -71,7 +71,7 @@ typedef struct st_key_part_info { /* Info about a key part */ typedef struct st_key { uint key_length; /* Tot length of key */ - uint flags; /* dupp key and pack flags */ + ulong flags; /* dupp key and pack flags */ uint key_parts; /* How many key_parts */ uint extra_length; uint usable_key_parts; /* Should normally be = key_parts */ diff --git a/sql/unireg.cc b/sql/unireg.cc index f2238d69973..dbdefd8d5b1 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -505,7 +505,7 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo, int2store(pos+6, key->block_size); pos+=8; key_parts+=key->key_parts; - DBUG_PRINT("loop", ("flags: %d key_parts: %d at 0x%lx", + DBUG_PRINT("loop", ("flags: %lu key_parts: %d at 0x%lx", key->flags, key->key_parts, (long) key->key_part)); for (key_part=key->key_part,key_part_end=key_part+key->key_parts ; |