mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
Fixed bug with GROUP BY on NULL fields.
(Merge of code from 4.0)
This commit is contained in:
@@ -46928,6 +46928,9 @@ not yet 100% confident in this code.
|
||||
@appendixsubsec Changes in release 3.23.52
|
||||
@itemize @bullet
|
||||
@item
|
||||
Fixed problem with @code{GROUP BY} on result with expression that created a
|
||||
@code{BLOB} field.
|
||||
@item
|
||||
Fixed problem with privilege tables when downgrading from 4.0.2 to 3.23.
|
||||
@item
|
||||
Fixed thread bug in @code{SLAVE START} and @code{SLAVE STOP}.
|
||||
|
||||
@@ -134,6 +134,7 @@ enum ha_base_keytype {
|
||||
#define HA_BINARY_PACK_KEY 32 /* Packing of all keys to prev key */
|
||||
#define HA_FULLTEXT 128 /* SerG: for full-text search */
|
||||
#define HA_UNIQUE_CHECK 256 /* Check the key for uniqueness */
|
||||
#define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */
|
||||
|
||||
/* Automatic bits in key-flag */
|
||||
|
||||
@@ -235,6 +236,7 @@ enum ha_base_keytype {
|
||||
#define SEARCH_UPDATE 64
|
||||
#define SEARCH_PREFIX 128
|
||||
#define SEARCH_LAST 256
|
||||
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
|
||||
|
||||
/* bits in opt_flag */
|
||||
#define QUICK_USED 1
|
||||
|
||||
@@ -110,6 +110,9 @@ typedef struct st_vio Vio;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */
|
||||
#define MAX_BLOB_WIDTH 8192 /* Default width for blob */
|
||||
|
||||
typedef struct st_net {
|
||||
Vio* vio;
|
||||
my_socket fd; /* For Perl DBI/dbd */
|
||||
|
||||
@@ -107,8 +107,9 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME)
|
||||
|| key_len) && nod_flag)
|
||||
if ((nextflag & SEARCH_FIND) && nod_flag &&
|
||||
((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
|
||||
key_len))
|
||||
{
|
||||
if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND,
|
||||
_mi_kpos(nod_flag,keypos))) >= 0 ||
|
||||
|
||||
@@ -263,7 +263,11 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
|
||||
if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
|
||||
comp_flag=SEARCH_BIGGER; /* Put after same key */
|
||||
else if (keyinfo->flag & HA_NOSAME)
|
||||
{
|
||||
comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */
|
||||
if (keyinfo->flag & HA_NULL_ARE_EQUAL)
|
||||
comp_flag|= SEARCH_NULL_ARE_EQUAL;
|
||||
}
|
||||
else
|
||||
comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
|
||||
|
||||
|
||||
@@ -68,3 +68,19 @@ One Two sum(Four)
|
||||
1 1 16
|
||||
1 2 16
|
||||
1 3 16
|
||||
xID xID1
|
||||
1 1
|
||||
2 2
|
||||
2 2
|
||||
3 134
|
||||
3 134
|
||||
3 134
|
||||
4 185
|
||||
4 185
|
||||
4 185
|
||||
4 185
|
||||
xID xID1 Level
|
||||
1 1 *
|
||||
2 2 **
|
||||
3 134 ***
|
||||
4 185 ****
|
||||
|
||||
@@ -259,3 +259,14 @@ insert into t1 values (1,3,3,4);
|
||||
insert into t1 values (1,3,4,4);
|
||||
select One, Two, sum(Four) from t1 group by One,Two;
|
||||
drop table if exists t1;
|
||||
|
||||
#
|
||||
# The GROUP BY returned rows in wrong order in 3.23.51
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID
|
||||
));
|
||||
insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL);
|
||||
select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2;
|
||||
select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1;
|
||||
drop table t1;
|
||||
|
||||
@@ -2222,18 +2222,18 @@ int setup_ftfuncs(THD *thd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int init_ftfuncs(THD *thd, bool no_order)
|
||||
{
|
||||
List_iterator<Item_func_match> li(thd->lex.ftfunc_list);
|
||||
Item_func_match *ifm;
|
||||
DBUG_PRINT("info",("Performing FULLTEXT search"));
|
||||
thd->proc_info="FULLTEXT initialization";
|
||||
|
||||
while ((ifm=li++))
|
||||
if (thd->lex.ftfunc_list.elements)
|
||||
{
|
||||
ifm->init_search(no_order);
|
||||
}
|
||||
List_iterator<Item_func_match> li(thd->lex.ftfunc_list);
|
||||
Item_func_match *ifm;
|
||||
DBUG_PRINT("info",("Performing FULLTEXT search"));
|
||||
thd->proc_info="FULLTEXT initialization";
|
||||
|
||||
while ((ifm=li++))
|
||||
ifm->init_search(no_order);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
uint select_options,select_result *result)
|
||||
{
|
||||
TABLE *tmp_table;
|
||||
int error,tmp;
|
||||
int error, tmp_error;
|
||||
bool need_tmp,hidden_group_fields;
|
||||
bool simple_order,simple_group,no_order;
|
||||
Item::cond_result cond_value;
|
||||
@@ -380,9 +380,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
thd->fatal_error)
|
||||
goto err;
|
||||
thd->proc_info="preparing";
|
||||
if ((tmp=join_read_const_tables(&join)) > 0)
|
||||
if ((tmp_error=join_read_const_tables(&join)) > 0)
|
||||
goto err;
|
||||
if (tmp && !(select_options & SELECT_DESCRIBE))
|
||||
if (tmp_error && !(select_options & SELECT_DESCRIBE))
|
||||
{
|
||||
error=return_zero_rows(result,tables,fields,
|
||||
join.tmp_table_param.sum_func_count != 0 &&
|
||||
@@ -701,9 +701,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
group=0;
|
||||
}
|
||||
thd->proc_info="Copying to group table";
|
||||
tmp_error= -1;
|
||||
if (make_sum_func_list(&join,all_fields) ||
|
||||
do_select(&join,(List<Item> *) 0,tmp_table2,0))
|
||||
(tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
|
||||
{
|
||||
error=tmp_error;
|
||||
free_tmp_table(thd,tmp_table2);
|
||||
goto err; /* purecov: inspected */
|
||||
}
|
||||
@@ -3347,7 +3349,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
if (!param->quick_group)
|
||||
group=0; // Can't use group key
|
||||
else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
|
||||
{
|
||||
(*tmp->item)->marker=4; // Store null in key
|
||||
if ((*tmp->item)->max_length >= MAX_CHAR_WIDTH)
|
||||
using_unique_constraint=1;
|
||||
}
|
||||
if (param->group_length >= MAX_BLOB_WIDTH)
|
||||
using_unique_constraint=1;
|
||||
if (group)
|
||||
@@ -3477,7 +3483,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
field_count= (uint) (reg_field - table->field);
|
||||
|
||||
/* If result table is small; use a heap */
|
||||
if (blob_count || using_unique_constraint ||
|
||||
if (blob_count || using_unique_constraint || group_null_items ||
|
||||
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
|
||||
OPTION_BIG_TABLES)
|
||||
{
|
||||
@@ -3499,7 +3505,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
if (blob_count == 0)
|
||||
{
|
||||
/* We need to ensure that first byte is not 0 for the delete link */
|
||||
if (hidden_null_count)
|
||||
if (param->hidden_field_count)
|
||||
hidden_null_count++;
|
||||
else
|
||||
null_count++;
|
||||
@@ -3633,14 +3639,17 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
if (maybe_null)
|
||||
{
|
||||
/*
|
||||
To be able to group on NULL, we move the null bit to be
|
||||
just before the column and extend the key to cover the null bit
|
||||
To be able to group on NULL, we reserve place in group_buff
|
||||
for the NULL flag just before the column.
|
||||
The field data is after this flag.
|
||||
The NULL flag is updated by 'end_update()' and 'end_write()'
|
||||
*/
|
||||
*group_buff= 0; // Init null byte
|
||||
key_part_info->offset--;
|
||||
key_part_info->length++;
|
||||
group->field->move_field((char*) group_buff+1, (uchar*) group_buff,
|
||||
1);
|
||||
keyinfo->flags|= HA_NULL_ARE_EQUAL; // def. that NULL == NULL
|
||||
key_part_info->null_bit=field->null_bit;
|
||||
key_part_info->null_offset= (uint) (field->null_ptr -
|
||||
(uchar*) table->record[0]);
|
||||
group->field->move_field((char*) ++group->buff);
|
||||
group_buff++;
|
||||
}
|
||||
else
|
||||
group->field->move_field((char*) group_buff);
|
||||
@@ -3820,11 +3829,17 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
|
||||
keyinfo->key_part[i].length > 4)
|
||||
seg->flag|=HA_SPACE_PACK;
|
||||
}
|
||||
if (using_unique_constraint &&
|
||||
!(field->flags & NOT_NULL_FLAG))
|
||||
if (!(field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
seg->null_bit= field->null_bit;
|
||||
seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
|
||||
/*
|
||||
We are using a GROUP BY on something that contains NULL
|
||||
In this case we have to tell MyISAM that two NULL should
|
||||
on INSERT be compared as equal
|
||||
*/
|
||||
if (!using_unique_constraint)
|
||||
keydef.flag|= HA_NULL_ARE_EQUAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4797,8 +4812,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
||||
{
|
||||
Item *item= *group->item;
|
||||
item->save_org_in_field(group->field);
|
||||
/* Store in the used key if the field was 0 */
|
||||
if (item->maybe_null)
|
||||
group->buff[0]=item->null_value ? 0: 1; // Save reversed value
|
||||
group->buff[-1]=item->null_value ? 1 : 0;
|
||||
}
|
||||
// table->file->index_init(0);
|
||||
if (!table->file->index_read(table->record[1],
|
||||
|
||||
Reference in New Issue
Block a user