Fix for bug #31207: Test "join_nested" shows different strategy on IA64
CPUs / Intel's ICC compile The bug is a combination of two problems: 1. IA64/ICC MySQL binaries use glibc's qsort(), not the one in mysys. 2. 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. Since choose_plan() uses qsort() to pre-sort the join tables using join_tab_cmp() as a compare function, the results of the sorting may vary depending on qsort() implementation. It is neither possible nor important to implement a better ordering algorithm in join_tab_cmp(). Therefore the only way to fix it is to force our own qsort() to be used by renaming it to my_qsort(), so we don't depend on linker to decide that. This patch also "fixes" bug #20530: qsort redefinition violates the standard.
This commit is contained in:
parent
80a2d47b22
commit
6d1f3e8de5
@ -709,8 +709,10 @@ extern sig_handler my_set_alarm_variable(int signo);
|
||||
extern void my_string_ptr_sort(void *base,uint items,size_s size);
|
||||
extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements,
|
||||
size_s size_of_element,uchar *buffer[]);
|
||||
extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size,
|
||||
qsort2_cmp cmp, void *cmp_argument);
|
||||
extern qsort_t my_qsort(void *base_ptr, size_t total_elems, size_t size,
|
||||
qsort_cmp cmp);
|
||||
extern qsort_t my_qsort2(void *base_ptr, size_t total_elems, size_t size,
|
||||
qsort2_cmp cmp, void *cmp_argument);
|
||||
extern qsort2_cmp get_ptr_compare(uint);
|
||||
void my_store_ptr(byte *buff, uint pack_length, my_off_t pos);
|
||||
my_off_t my_get_ptr(byte *ptr, uint pack_length);
|
||||
|
@ -73,7 +73,7 @@ sqlobjects = net.lo
|
||||
sql_cmn_objects = pack.lo client.lo my_time.lo
|
||||
|
||||
# Not needed in the minimum library
|
||||
mysysobjects2 = my_lib.lo
|
||||
mysysobjects2 = my_lib.lo mf_qsort.lo
|
||||
mysysobjects = $(mysysobjects1) $(mysysobjects2)
|
||||
target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \
|
||||
$(sql_cmn_objects) $(vio_objects) $(sqlobjects)
|
||||
|
@ -430,8 +430,8 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
|
||||
ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
|
||||
sizeof(FTB_WORD *)*ftb->queue.elements);
|
||||
memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements);
|
||||
qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *),
|
||||
(qsort2_cmp)FTB_WORD_cmp_list, ftb->charset);
|
||||
my_qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *),
|
||||
(qsort2_cmp)FTB_WORD_cmp_list, ftb->charset);
|
||||
if (ftb->queue.elements<2) ftb->with_scan &= ~FTB_FLAG_TRUNC;
|
||||
ftb->state=READY;
|
||||
return ftb;
|
||||
|
@ -281,7 +281,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
|
||||
&dptr, left_root_right);
|
||||
|
||||
if (flags & FT_SORTED)
|
||||
qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, 0);
|
||||
my_qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp,
|
||||
0);
|
||||
|
||||
err:
|
||||
delete_tree(&aio.dtree);
|
||||
|
@ -3148,7 +3148,7 @@ static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count)
|
||||
cur_sort_p= sort_counts;
|
||||
while (cur_count_p < end_count_p)
|
||||
*(cur_sort_p++)= cur_count_p++;
|
||||
(void) qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp);
|
||||
(void) my_qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp);
|
||||
|
||||
/*
|
||||
Assign faked counts.
|
||||
|
@ -649,8 +649,8 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
|
||||
uint sort_length=info->key_length;
|
||||
DBUG_ENTER("write_keys");
|
||||
|
||||
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
|
||||
info);
|
||||
my_qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
|
||||
info);
|
||||
if (!my_b_inited(tempfile) &&
|
||||
open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST",
|
||||
DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
|
||||
@ -692,8 +692,8 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info,
|
||||
int err;
|
||||
DBUG_ENTER("write_keys_varlen");
|
||||
|
||||
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
|
||||
info);
|
||||
my_qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
|
||||
info);
|
||||
if (!my_b_inited(tempfile) &&
|
||||
open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST",
|
||||
DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
|
||||
@ -735,8 +735,8 @@ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys,
|
||||
{
|
||||
DBUG_ENTER("write_index");
|
||||
|
||||
qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*),
|
||||
(qsort2_cmp) info->key_cmp,info);
|
||||
my_qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*),
|
||||
(qsort2_cmp) info->key_cmp,info);
|
||||
while (count--)
|
||||
{
|
||||
if ((*info->key_write)(info,*sort_keys++))
|
||||
|
@ -2268,7 +2268,7 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
|
||||
As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
|
||||
we are guarunteed no thread will change them
|
||||
*/
|
||||
qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
|
||||
my_qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
|
||||
|
||||
keycache_pthread_mutex_lock(&keycache->cache_lock);
|
||||
for ( ; cache != end ; cache++)
|
||||
|
@ -91,10 +91,10 @@ typedef struct st_stack
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef QSORT_EXTRA_CMP_ARGUMENT
|
||||
qsort_t qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp,
|
||||
qsort_t my_qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp,
|
||||
void *cmp_argument)
|
||||
#else
|
||||
qsort_t qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp)
|
||||
qsort_t my_qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp)
|
||||
#endif
|
||||
{
|
||||
char *low, *high, *pivot;
|
||||
|
@ -35,7 +35,7 @@ void my_string_ptr_sort(void *base, uint items, size_s size)
|
||||
if (size && items)
|
||||
{
|
||||
uint size_arg=size;
|
||||
qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg);
|
||||
my_qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
result->number_off_files= dir_entries_storage->elements;
|
||||
|
||||
if (!(MyFlags & MY_DONT_SORT))
|
||||
qsort((void *) result->dir_entry, result->number_off_files,
|
||||
my_qsort((void *) result->dir_entry, result->number_off_files,
|
||||
sizeof(FILEINFO), (qsort_cmp) comp_names);
|
||||
DBUG_RETURN(result);
|
||||
|
||||
@ -498,7 +498,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
result->number_off_files= dir_entries_storage->elements;
|
||||
|
||||
if (!(MyFlags & MY_DONT_SORT))
|
||||
qsort((void *) result->dir_entry, result->number_off_files,
|
||||
my_qsort((void *) result->dir_entry, result->number_off_files,
|
||||
sizeof(FILEINFO), (qsort_cmp) comp_names);
|
||||
DBUG_PRINT("exit", ("found %d files", result->number_off_files));
|
||||
DBUG_RETURN(result);
|
||||
@ -605,7 +605,7 @@ MY_DIR *my_dir(const char* path, myf MyFlags)
|
||||
result->number_off_files= dir_entries_storage->elements;
|
||||
|
||||
if (!(MyFlags & MY_DONT_SORT))
|
||||
qsort((void *) result->dir_entry, result->number_off_files,
|
||||
my_qsort((void *) result->dir_entry, result->number_off_files,
|
||||
sizeof(FILEINFO), (qsort_cmp) comp_names);
|
||||
DBUG_RETURN(result);
|
||||
|
||||
|
@ -250,6 +250,6 @@ static int queue_fix_cmp(QUEUE *queue, void **a, void **b)
|
||||
|
||||
void queue_fix(QUEUE *queue)
|
||||
{
|
||||
qsort2(queue->root+1,queue->elements, sizeof(void *),
|
||||
(qsort2_cmp)queue_fix_cmp, queue);
|
||||
my_qsort2(queue->root+1,queue->elements, sizeof(void *),
|
||||
(qsort2_cmp)queue_fix_cmp, queue);
|
||||
}
|
||||
|
@ -852,7 +852,7 @@ int ha_tina::rnd_end()
|
||||
It also sorts so that we move the final blocks to the
|
||||
beginning so that we move the smallest amount of data possible.
|
||||
*/
|
||||
qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set);
|
||||
my_qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set);
|
||||
for (ptr= chain; ptr < chain_ptr; ptr++)
|
||||
{
|
||||
memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
|
||||
|
@ -2775,7 +2775,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
|
||||
|
||||
|
@ -781,7 +781,7 @@ public:
|
||||
virtual byte *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);
|
||||
|
||||
|
@ -3159,8 +3159,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););
|
||||
@ -3349,8 +3349,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",
|
||||
|
@ -497,7 +497,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++)
|
||||
|
@ -248,8 +248,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
|
||||
#endif
|
||||
VOID(push_dynamic(&acl_hosts,(gptr) &host));
|
||||
}
|
||||
qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
|
||||
sizeof(ACL_HOST),(qsort_cmp) acl_compare);
|
||||
my_qsort((gptr) 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);
|
||||
|
||||
@ -421,8 +421,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
|
||||
allow_all_hosts=1; // Anyone can connect
|
||||
}
|
||||
}
|
||||
qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
|
||||
sizeof(ACL_USER),(qsort_cmp) acl_compare);
|
||||
my_qsort((gptr) 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);
|
||||
|
||||
@ -479,8 +479,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
|
||||
#endif
|
||||
VOID(push_dynamic(&acl_dbs,(gptr) &db));
|
||||
}
|
||||
qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
|
||||
sizeof(ACL_DB),(qsort_cmp) acl_compare);
|
||||
my_qsort((gptr) 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();
|
||||
@ -1110,8 +1110,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((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
|
||||
sizeof(ACL_USER),(qsort_cmp) acl_compare);
|
||||
my_qsort((gptr) 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();
|
||||
@ -1173,8 +1173,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,(gptr) &acl_db));
|
||||
qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
|
||||
sizeof(ACL_DB),(qsort_cmp) acl_compare);
|
||||
my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
|
||||
sizeof(ACL_DB),(qsort_cmp) acl_compare);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -524,7 +524,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++)
|
||||
{
|
||||
|
@ -3658,7 +3658,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 */
|
||||
@ -4371,8 +4371,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)
|
||||
{
|
||||
@ -4421,6 +4422,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
|
||||
|
@ -1476,7 +1476,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
/* Sort keys in optimized order */
|
||||
qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY),
|
||||
my_qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY),
|
||||
(qsort_cmp) sort_keys);
|
||||
create_info->null_bits= null_fields;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user