Commit 621b5da8 authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

Fixed bug with GROUP BY on NULL fields.

(Merge of code from 4.0)
parent 8a38deea
......@@ -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],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment