Commit e16535ce authored by unknown's avatar unknown
Browse files

olap.result, olap.test:

  Added a test case for bug #8616.
item.h:
  Fixed bug #8616.
  Added class Item_null_result used in rollup processing.
sql_select.h, sql_select.cc:
  Fixed bug #8616.
  Added JOIN::rollup_write_data to cover rollup queries
  with DISTINCT. Modified other rollup methods.


sql/sql_select.cc:
  Fixed bug #8616.
  Added JOIN::rollup_write_data to cover rollup queries
  with DISTINCT. Modified other rollup methods.
sql/sql_select.h:
  Fixed bug #8616.
  Added JOIN::rollup_write_data to cover rollup queries
  with DISTINCT. Modified other rollup methods.
sql/item.h:
  Fixed bug #8616.
  Added class Item_null_result used in rollup processing.
mysql-test/t/olap.test:
  Added a test case for bug #8616.
mysql-test/r/olap.result:
  Added a test case for bug #8616.
parent 32e027ea
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
@@ -307,3 +307,57 @@ day sample not_cancelled
2004-06-07	1	0
NULL	3	1
DROP TABLE user_day;
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES
(1,4),
(2,2), (2,2),
(4,1), (4,1), (4,1), (4,1),
(2,1), (2,1);
SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)
4
6
4
14
SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)
4
6
14
SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)	COUNT(DISTINCT b)
4	1
6	2
4	1
14	3
SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)	COUNT(DISTINCT b)
4	1
6	2
14	3
SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)	COUNT(*)
4	1
6	4
4	4
14	9
SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)	COUNT(*)
4	1
6	4
4	4
14	9
SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
SUM(b)	COUNT(DISTINCT b)	COUNT(*)
4	1	1
6	2	4
4	1	4
14	3	9
SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1
GROUP BY a WITH ROLLUP;
SUM(b)	COUNT(DISTINCT b)	COUNT(*)
4	1	1
6	2	4
4	1	4
14	3	9
DROP TABLE t1;
+27 −0
Original line number Diff line number Diff line
@@ -125,3 +125,30 @@ SELECT

DROP TABLE user_day;

#
# Test for bug #8616: distinct sum with rollup
#

CREATE TABLE t1 (a int, b int);

INSERT INTO t1 VALUES
  (1,4),
  (2,2), (2,2),
  (4,1), (4,1), (4,1), (4,1),
  (2,1), (2,1);

SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP;
SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP;

SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP;
SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP;

SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;

SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1
  GROUP BY a WITH ROLLUP;

DROP TABLE t1;
+11 −0
Original line number Diff line number Diff line
@@ -470,6 +470,17 @@ class Item_null :public Item
  Item *safe_charset_converter(CHARSET_INFO *tocs);
};

class Item_null_result :public Item_null
{
public:
  Field *result_field;
  Item_null_result() : Item_null(), result_field(0) {}
  bool is_result_field() { return result_field != 0; }
  void save_in_result_field(bool no_conversions)
  {
    save_in_field(result_field, no_conversions);
  }
};  

/* Item represents one placeholder ('?') of prepared statement */

+92 −26
Original line number Diff line number Diff line
@@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
				      uint elements, List<Item> &items);
static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr);
static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
@@ -1328,7 +1328,7 @@ JOIN::exec()
      if (curr_join->tmp_having)
	curr_join->tmp_having->update_used_tables();
      if (remove_duplicates(curr_join, curr_tmp_table,
			    curr_join->fields_list, curr_join->tmp_having))
			    *curr_fields_list, curr_join->tmp_having))
	DBUG_VOID_RETURN;
      curr_join->tmp_having=0;
      curr_join->select_distinct=0;
@@ -6740,26 +6740,32 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
    {
      if (join->procedure)
	join->procedure->end_group();
      if (idx < (int) join->send_group_parts)
      int send_group_parts= join->send_group_parts;
      if (idx < send_group_parts)
      {
	if (!join->first_record)
	{
	  /* No matching rows for group function */
	  join->clear();
	}
	copy_sum_funcs(join->sum_funcs);
	if (!join->having || join->having->val_int())
	{
	  if ((error=table->file->write_row(table->record[0])))
        copy_sum_funcs(join->sum_funcs,
                       join->sum_funcs_end[send_group_parts]);
	if (join->having && join->having->val_int() == 0)
          error= -1;
        else if ((error=table->file->write_row(table->record[0])))
	{
	  if (create_myisam_from_heap(join->thd, table,
				      &join->tmp_table_param,
				      error, 0))
	      DBUG_RETURN(-1);			// Not a table_is_full error
	    DBUG_RETURN(-1);		       
        }
	  else
	    join->send_records++;
        if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0)
	{
	  if (join->rollup_write_data((uint) (idx+1), table))
	    error= 1;
	}
	if (error > 0)
	  DBUG_RETURN(-1);	  
	if (end_of_records)
	  DBUG_RETURN(0);
      }
@@ -8888,11 +8894,10 @@ update_tmptable_sum_func(Item_sum **func_ptr,
	/* Copy result of sum functions to record in tmp_table */

static void
copy_sum_funcs(Item_sum **func_ptr)
copy_sum_funcs(Item_sum **func_ptr, Item_sum **end_ptr)
{
  Item_sum *func;
  for (; (func = *func_ptr) ; func_ptr++)
    (void) func->save_in_result_field(1);
  for (; func_ptr != end_ptr ; func_ptr++)
    (void) (*func_ptr)->save_in_result_field(1);
  return;
}

@@ -9013,14 +9018,16 @@ bool JOIN::rollup_init()
  */
  tmp_table_param.group_parts= send_group_parts;

  if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) +
  if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) +
                                                sizeof(Item**) +
                                                sizeof(List<Item>) +
				                ref_pointer_array_size)
				                * send_group_parts )))
    return 1;
  
  rollup.fields= (List<Item>*) (rollup.null_items + send_group_parts);
  rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts);
  ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);
  rollup.item_null= new (thd->mem_root) Item_null();

  /*
    Prepare space for field list for the different levels
@@ -9028,12 +9035,16 @@ bool JOIN::rollup_init()
  */
  for (i= 0 ; i < send_group_parts ; i++)
  {
    rollup.null_items[i]= new (thd->mem_root) Item_null_result();
    List<Item> *rollup_fields= &rollup.fields[i];
    rollup_fields->empty();
    rollup.ref_pointer_arrays[i]= ref_array;
    ref_array+= all_fields.elements;
  }
  for (i= 0 ; i < send_group_parts; i++)
  {
    for (j=0 ; j < fields_list.elements ; j++)
      rollup_fields->push_back(rollup.item_null);
      rollup.fields[i].push_back(rollup.null_items[i]);
  }
  return 0;
}
@@ -9137,7 +9148,8 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields,
      {
	/* Check if this is something that is part of this group by */
	ORDER *group_tmp;
	for (group_tmp= start_group ; group_tmp ; group_tmp= group_tmp->next)
	for (group_tmp= start_group, i-- ;
             group_tmp ; group_tmp= group_tmp->next, i++)
	{
	  if (*group_tmp->item == item)
	  {
@@ -9146,7 +9158,9 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields,
	      set to NULL in this level
	    */
	    item->maybe_null= 1;		// Value will be null sometimes
	    item= rollup.item_null;
            Item_null_result *null_item= rollup.null_items[i];
            null_item->result_field= ((Item_field *) item)->result_field;
            item= null_item;
	    break;
	  }
	}
@@ -9206,6 +9220,58 @@ int JOIN::rollup_send_data(uint idx)
  return 0;
}

/*
  Write all rollup levels higher than the current one to a temp table

  SYNOPSIS:
    rollup_write_data()
    idx                 Level we are on:
                        0 = Total sum level
                        1 = First group changed  (a)
                        2 = Second group changed (a,b)
    table               reference to temp table

  SAMPLE
    SELECT a, b, SUM(c) FROM t1 GROUP BY a,b WITH ROLLUP

  RETURN
    0	ok
    1   if write_data_failed()
*/

int JOIN::rollup_write_data(uint idx, TABLE *table)
{
  uint i;
  for (i= send_group_parts ; i-- > idx ; )
  {
    /* Get reference pointers to sum functions in place */
    memcpy((char*) ref_pointer_array,
	   (char*) rollup.ref_pointer_arrays[i],
	   ref_pointer_array_size);
    if ((!having || having->val_int()))
    {
      int error;
      Item *item;
      List_iterator_fast<Item> it(rollup.fields[i]);
      while ((item= it++))
      {
        if (item->type() == Item::NULL_ITEM && item->is_result_field())
          item->save_in_result_field(1);
      }
      copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]);
      if ((error= table->file->write_row(table->record[0])))
      {
	if (create_myisam_from_heap(thd, table, &tmp_table_param,
				      error, 0))
	  return 1;		     
      }
    }
  }
  /* Restore ref_pointer_array */
  set_items_ref_array(current_ref_pointer_array);
  return 0;
}

/*
  clear results if there are not rows found for group
  (end_send_group/end_write_group)
+2 −1
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ typedef struct st_rollup
{
  enum State { STATE_NONE, STATE_INITED, STATE_READY };
  State state;
  Item *item_null;
  Item_null_result **null_items;
  Item ***ref_pointer_arrays;
  List<Item> *fields;
} ROLLUP;
@@ -295,6 +295,7 @@ class JOIN :public Sql_alloc
  bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
			  Item_sum ***func);
  int rollup_send_data(uint idx);
  int rollup_write_data(uint idx, TABLE *table);
  bool test_in_subselect(Item **where);
  void join_free(bool full);
  void clear();