summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <tsmith@ramayana.hindu.god>2007-12-07 03:56:03 -0700
committerunknown <tsmith@ramayana.hindu.god>2007-12-07 03:56:03 -0700
commit284cb0e560293187b9d2d7a38aa71de9d9637567 (patch)
treeb719b75e443bf2787a2c520cc6e9955e4eb6a4a8 /sql
parentb5f919ddfa3bfe6202302bb3e88e252c68550ed7 (diff)
parent6e776686d4cbaac919eee8300b2c85e2cf5825ec (diff)
downloadmariadb-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.cc80
-rw-r--r--sql/item_cmpfunc.cc38
-rw-r--r--sql/item_cmpfunc.h4
-rw-r--r--sql/item_strfunc.h7
-rw-r--r--sql/item_timefunc.cc48
-rw-r--r--sql/opt_range.cc8
-rw-r--r--sql/partition_info.cc4
-rw-r--r--sql/records.cc3
-rw-r--r--sql/set_var.cc51
-rw-r--r--sql/set_var.h14
-rw-r--r--sql/sql_acl.cc20
-rw-r--r--sql/sql_array.h2
-rw-r--r--sql/sql_help.cc2
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_select.cc66
-rw-r--r--sql/sql_table.cc74
-rw-r--r--sql/structs.h2
-rw-r--r--sql/unireg.cc2
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 ;