1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00
This commit is contained in:
bell@sanja.is.com.ua
2003-06-25 23:52:15 +03:00
350 changed files with 14454 additions and 15810 deletions

View File

@ -138,7 +138,6 @@ static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool alloc_group_fields(JOIN *join,ORDER *group);
static bool make_sum_func_list(JOIN *join,List<Item> &fields);
// Create list for using with tempory table
static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
List<Item> &new_list1,
@ -153,7 +152,7 @@ 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 bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static void init_sum_functions(Item_sum **func);
static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct, const char *message=NullS);
@ -290,7 +289,7 @@ JOIN::prepare(Item ***rref_pointer_array,
fields_list,
&all_fields, wild_num))) ||
setup_ref_array(thd, rref_pointer_array, (fields_list.elements +
select_lex->with_sum_func +
select_lex->select_items +
og_num)) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
&all_fields, 1) ||
@ -314,7 +313,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having->with_sum_func)
having->split_sum_func(ref_pointer_array, all_fields);
}
// Is it subselect
{
Item_subselect *subselect;
@ -330,6 +329,8 @@ JOIN::prepare(Item ***rref_pointer_array,
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
/*
Check if one one uses a not constant column with group functions
and no GROUP BY.
@ -359,45 +360,47 @@ JOIN::prepare(Item ***rref_pointer_array,
for (table=tables_list ; table ; table=table->next)
tables++;
}
{
/* Caclulate the number of groups */
send_group_parts= 0;
for (ORDER *group= group_list ; group ; group= group->next)
send_group_parts++;
}
procedure= setup_procedure(thd, proc_param, result, fields_list, &error);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
goto err; /* purecov: inspected */
if (procedure)
{
if (setup_new_fields(thd, tables_list, fields_list, all_fields,
procedure->param_fields))
{ /* purecov: inspected */
delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
goto err; /* purecov: inspected */
if (procedure->group)
{
if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */
delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
goto err; /* purecov: inspected */
}
}
#ifdef NOT_NEEDED
else if (!group_list && procedure->flags & PROC_GROUP)
{
my_message(0,"Select must have a group with this procedure",MYF(0));
delete procedure;
DBUG_RETURN(-1);
goto err;
}
#endif
if (order && (procedure->flags & PROC_NO_SORT))
{ /* purecov: inspected */
{ /* purecov: inspected */
my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */
delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
goto err; /* purecov: inspected */
}
}
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
this->group= group_list != 0;
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
@ -412,15 +415,23 @@ JOIN::prepare(Item ***rref_pointer_array,
if (sum_func_count && !group_list && (func_count || field_count))
{
my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
delete procedure;
DBUG_RETURN(-1);
goto err;
}
#endif
if (!procedure && result->prepare(fields_list, unit))
{ /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
goto err; /* purecov: inspected */
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
goto err;
if (alloc_func_list())
goto err;
DBUG_RETURN(0); // All OK
err:
delete procedure; /* purecov: inspected */
procedure= 0;
DBUG_RETURN(-1); /* purecov: inspected */
}
/*
@ -652,7 +663,9 @@ JOIN::optimize()
else if (thd->is_fatal_error) // End of memory
DBUG_RETURN(1);
}
group_list= remove_const(this, group_list, conds, &simple_group);
simple_group= 0;
if (rollup.state == ROLLUP::STATE_NONE)
group_list= remove_const(this, group_list, conds, &simple_group);
if (!group_list && group)
{
order=0; // The output has only one row
@ -802,14 +815,14 @@ JOIN::optimize()
thd->proc_info="Sorting for group";
if (create_sort_index(thd, &join_tab[const_tables], group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
make_sum_func_list(this, all_fields) ||
alloc_group_fields(this, group_list))
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1))
DBUG_RETURN(1);
group_list=0;
}
else
{
if (make_sum_func_list(this, all_fields))
if (make_sum_func_list(all_fields, fields_list, 0))
DBUG_RETURN(1);
if (!group_list && ! exec_tmp_table1->distinct && order && simple_order)
{
@ -876,7 +889,7 @@ int
JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
//TODO move to unit reinit
/* TODO move to unit reinit */
unit->offset_limit_cnt =select_lex->offset_limit;
unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
if (unit->select_limit_cnt < select_lex->select_limit)
@ -887,7 +900,7 @@ JOIN::reinit()
if (setup_tables(tables_list))
DBUG_RETURN(1);
// Reset of sum functions
/* Reset of sum functions */
first_record= 0;
if (sum_funcs)
{
@ -911,7 +924,7 @@ JOIN::reinit()
filesort_free_buffers(exec_tmp_table2);
}
if (items0)
memcpy(ref_pointer_array, items0, ref_pointer_array_size);
set_items_ref_array(items0);
if (tmp_join)
restore_tmp();
@ -991,9 +1004,6 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
/* Perform FULLTEXT search before all regular searches */
//init_ftfuncs(thd, select_lex, test(order));
JOIN *curr_join= this;
List<Item> *curr_all_fields= &all_fields;
List<Item> *curr_fields_list= &fields_list;
@ -1044,7 +1054,7 @@ JOIN::exec()
}
curr_all_fields= &tmp_all_fields1;
curr_fields_list= &tmp_fields_list1;
memcpy(ref_pointer_array, items1, ref_pointer_array_size);
set_items_ref_array(items1);
if (sort_and_group || curr_tmp_table->group)
{
@ -1093,7 +1103,8 @@ JOIN::exec()
if (make_simple_join(curr_join, curr_tmp_table))
DBUG_VOID_RETURN;
calc_group_buffer(curr_join, group_list);
count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1,
count_field_types(&curr_join->tmp_table_param,
curr_join->tmp_all_fields1,
curr_join->select_distinct && !curr_join->group_list);
curr_join->tmp_table_param.hidden_field_count=
(curr_join->tmp_all_fields1.elements-
@ -1131,7 +1142,8 @@ JOIN::exec()
thd->proc_info="Copying to group table";
tmp_error= -1;
if (make_sum_func_list(curr_join, *curr_all_fields) ||
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1) ||
(tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
0)))
{
@ -1155,7 +1167,7 @@ JOIN::exec()
}
curr_fields_list= &curr_join->tmp_fields_list2;
curr_all_fields= &curr_join->tmp_all_fields2;
memcpy(ref_pointer_array, items2, ref_pointer_array_size);
set_items_ref_array(items2);
curr_join->tmp_table_param.field_count+=
curr_join->tmp_table_param.sum_func_count;
curr_join->tmp_table_param.sum_func_count= 0;
@ -1183,9 +1195,7 @@ JOIN::exec()
}
if (procedure)
{
count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0);
}
if (curr_join->group || curr_join->tmp_table_param.sum_func_count ||
(procedure && (procedure->flags & PROC_GROUP)))
@ -1215,10 +1225,10 @@ JOIN::exec()
}
curr_fields_list= &tmp_fields_list3;
curr_all_fields= &tmp_all_fields3;
memcpy(ref_pointer_array, items3, ref_pointer_array_size);
set_items_ref_array(items3);
if (make_sum_func_list(curr_join, *curr_all_fields) ||
thd->is_fatal_error)
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1) || thd->is_fatal_error)
DBUG_VOID_RETURN;
}
if (curr_join->group_list || curr_join->order)
@ -1231,7 +1241,7 @@ JOIN::exec()
{
// Some tables may have been const
curr_join->tmp_having->update_used_tables();
JOIN_TAB *table= &curr_join->join_tab[const_tables];
JOIN_TAB *table= &curr_join->join_tab[curr_join->const_tables];
table_map used_tables= curr_join->const_table_map | table->table->map;
Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having,
@ -1267,7 +1277,7 @@ JOIN::exec()
We can abort sorting after thd->select_limit rows if we there is no
WHERE clause for any tables after the sorted one.
*/
JOIN_TAB *table= &curr_join->join_tab[const_tables+1];
JOIN_TAB *table= &curr_join->join_tab[curr_join->const_tables+1];
JOIN_TAB *end_table= &curr_join->join_tab[tables];
for (; table < end_table ; table++)
{
@ -1305,7 +1315,7 @@ JOIN::exec()
*/
int
JOIN::cleanup(THD *thd)
JOIN::cleanup()
{
DBUG_ENTER("JOIN::cleanup");
select_lex->join= 0;
@ -1326,7 +1336,7 @@ JOIN::cleanup(THD *thd)
}
}
tmp_join->tmp_join= 0;
DBUG_RETURN(tmp_join->cleanup(thd));
DBUG_RETURN(tmp_join->cleanup());
}
lock=0; // It's faster to unlock later
@ -1410,7 +1420,7 @@ err:
thd->limit_found_rows= curr_join->send_records;
thd->examined_row_count= curr_join->examined_rows;
thd->proc_info="end";
err= join->cleanup(thd);
err= join->cleanup();
if (thd->net.report_error)
err= -1;
delete join;
@ -2930,7 +2940,6 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->tmp_table_param.func_count=0;
join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0;
join->first_record=join->sort_and_group=0;
join->sum_funcs=0;
join->send_records=(ha_rows) 0;
join->group=0;
join->row_limit=join->unit->select_limit_cnt;
@ -4147,10 +4156,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case STRING_RESULT:
if (item->max_length > 255)
new_field= new Field_blob(item->max_length,maybe_null,
item->name,table,item->str_value.charset());
item->name,table,item->charset());
else
new_field= new Field_string(item->max_length,maybe_null,
item->name,table,item->str_value.charset());
item->name,table,item->charset());
break;
case ROW_RESULT:
default:
@ -4796,7 +4805,7 @@ free_tmp_table(THD *thd, TABLE *entry)
(void) ha_delete_table(entry->db_type,entry->real_name);
/* free blobs */
for (Field **ptr=entry->field ; *ptr ; ptr++)
delete *ptr;
(*ptr)->free();
my_free((gptr) entry->record[0],MYF(0));
free_io_cache(entry);
@ -5729,8 +5738,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
else if (join->do_send_rows)
error=join->procedure->send_row(*join->fields) ? 1 : 0;
else
{
if (join->do_send_rows)
error=join->procedure->send_row(*join->fields) ? 1 : 0;
join->send_records++;
}
if (end_of_records && join->procedure->end_of_records())
error= 1; // Fatal error
}
@ -5744,17 +5757,23 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
else if (join->do_send_rows)
error=join->result->send_data(*join->fields) ? 1 : 0;
else
{
if (join->do_send_rows)
error=join->result->send_data(*join->fields) ? 1 : 0;
join->send_records++;
}
if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0)
{
if (join->rollup_send_data((uint) (idx+1)))
error= 1;
}
}
if (error > 0)
DBUG_RETURN(-1); /* purecov: inspected */
if (end_of_records)
{
join->send_records++;
DBUG_RETURN(0);
}
if (!error && ++join->send_records >= join->unit->select_limit_cnt &&
if (join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
@ -5774,7 +5793,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (idx < (int) join->send_group_parts)
{
copy_fields(&join->tmp_table_param);
init_sum_functions(join->sum_funcs);
if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
DBUG_RETURN(-1);
if (join->procedure)
join->procedure->add();
DBUG_RETURN(0);
@ -6030,7 +6050,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.items_to_copy);
init_sum_functions(join->sum_funcs);
if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
DBUG_RETURN(-1);
if (join->procedure)
join->procedure->add();
DBUG_RETURN(0);
@ -6289,14 +6310,14 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
*/
static uint
test_if_subkey(ORDER *order, TABLE *table, uint ref, key_map usable_keys)
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
key_map usable_keys)
{
uint nr;
uint min_length= (uint) ~0;
uint best= MAX_KEY;
uint not_used;
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
uint ref_key_parts= table->key_info[ref].key_parts;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
@ -6331,10 +6352,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
bool no_changes)
{
int ref_key;
uint ref_key_parts;
TABLE *table=tab->table;
SQL_SELECT *select=tab->select;
key_map usable_keys;
DBUG_ENTER("test_if_skip_sort_order");
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY */
usable_keys= ~(key_map) 0;
@ -6350,9 +6373,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
ref_key= -1;
if (tab->ref.key >= 0) // Constant range in WHERE
ref_key=tab->ref.key;
{
ref_key= tab->ref.key;
ref_key_parts= tab->ref.key_parts;
}
else if (select && select->quick) // Range found by opt_range
ref_key=select->quick->index;
{
ref_key= select->quick->index;
ref_key_parts= select->quick->used_key_parts;
}
if (ref_key >= 0)
{
@ -6366,20 +6395,28 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/*
We come here when ref_key is not among usable_keys
*/
uint a;
if ((a= test_if_subkey(order, table, ref_key, usable_keys)) < MAX_KEY)
uint new_ref_key;
/*
If using index only read, only consider other possible index only
keys
*/
if (table->used_keys & (((key_map) 1 << ref_key)))
usable_keys|= table->used_keys;
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
usable_keys)) < MAX_KEY)
{
/* Found key that can be used to retrieve data in sorted order */
if (tab->ref.key >= 0)
{
tab->ref.key= a;
table->file->index_init(a);
tab->ref.key= new_ref_key;
table->file->index_init(new_ref_key);
}
else
{
select->quick->index= a;
select->quick->index= new_ref_key;
select->quick->init();
}
ref_key= a;
ref_key= new_ref_key;
}
}
/* Check if we get the rows in requested sorted order by using the key */
@ -7672,7 +7709,10 @@ err2:
/*
Copy fields and null values between two tables
Make a copy of all simple SELECT'ed items
This is done at the start of a new group so that we can retrieve
these later when the group changes.
*/
void
@ -7692,33 +7732,76 @@ copy_fields(TMP_TABLE_PARAM *param)
}
/*****************************************************************************
Make an array of pointer to sum_functions to speed up sum_func calculation
*****************************************************************************/
/*
Make an array of pointers to sum_functions to speed up sum_func calculation
static bool
make_sum_func_list(JOIN *join,List<Item> &fields)
SYNOPSIS
alloc_func_list()
RETURN
0 ok
1 Error
*/
bool JOIN::alloc_func_list()
{
DBUG_ENTER("make_sum_func_list");
Item_sum **func =
(Item_sum**) sql_alloc(sizeof(Item_sum*)*
(join->tmp_table_param.sum_func_count+1));
if (!func)
DBUG_RETURN(TRUE);
List_iterator<Item> it(fields);
join->sum_funcs=func;
uint func_count, group_parts;
DBUG_ENTER("alloc_func_list");
Item *field;
while ((field=it++))
func_count= tmp_table_param.sum_func_count;
/*
If we are using rollup, we need a copy of the summary functions for
each level
*/
if (rollup.state != ROLLUP::STATE_NONE)
func_count*= (send_group_parts+1);
group_parts= send_group_parts;
/*
If distinct, reserve memory for possible
disctinct->group_by optimization
*/
if (select_distinct)
group_parts+= fields_list.elements;
/* This must use calloc() as rollup_make_fields depends on this */
sum_funcs= (Item_sum**) thd->calloc(sizeof(Item_sum**) * (func_count+1) +
sizeof(Item_sum***) * (group_parts+1));
sum_funcs_end= (Item_sum***) (sum_funcs+func_count+1);
DBUG_RETURN(sum_funcs == 0);
}
bool JOIN::make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
bool before_group_by)
{
List_iterator_fast<Item> it(all_fields);
Item_sum **func;
Item *item;
DBUG_ENTER("make_sum_func_list");
func= sum_funcs;
while ((item=it++))
{
if (field->type() == Item::SUM_FUNC_ITEM && !field->const_item())
if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
{
*func++=(Item_sum*) field;
*func++= (Item_sum*) item;
/* let COUNT(DISTINCT) create the temporary table */
if (((Item_sum*) field)->setup(join->thd))
if (((Item_sum*) item)->setup(thd))
DBUG_RETURN(TRUE);
}
}
if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
{
rollup.state= ROLLUP::STATE_READY;
if (rollup_make_fields(all_fields, send_fields, &func))
DBUG_RETURN(TRUE); // Should never happen
}
else if (rollup.state == ROLLUP::STATE_NONE)
{
for (uint i=0 ; i <= send_group_parts ;i++)
sum_funcs_end[i]= func;
}
*func=0; // End marker
DBUG_RETURN(FALSE);
}
@ -7814,8 +7897,8 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
all_fields - all fields list
RETURN
0 - ok
!=0 - error
0 ok
1 error
*/
static bool
@ -7884,12 +7967,21 @@ copy_sum_funcs(Item_sum **func_ptr)
}
static void
init_sum_functions(Item_sum **func_ptr)
static bool
init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
{
Item_sum *func;
for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
func->reset();
for (; func_ptr != end_ptr ;func_ptr++)
{
if ((*func_ptr)->reset())
return 1;
}
/* If rollup, calculate the upper sum levels */
for ( ; *func_ptr ; func_ptr++)
{
if ((*func_ptr)->add())
return 1;
}
return 0;
}
@ -7914,10 +8006,10 @@ copy_funcs(Item **func_ptr)
}
/*****************************************************************************
/*
Create a condition for a const reference and add this to the
currenct select for the table
*****************************************************************************/
*/
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
{
@ -7933,7 +8025,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
for (uint i=0 ; i < join_tab->ref.key_parts ; i++)
{
Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].fieldnr-1];
Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].
fieldnr-1];
Item *value=join_tab->ref.items[i];
cond->add(new Item_func_equal(new Item_field(field),value));
}
@ -7956,7 +8049,240 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
DBUG_RETURN(error ? TRUE : FALSE);
}
/*
Free joins of subselect of this select.
free_underlaid_joins()
thd - THD pointer
select - pointer to st_select_lex which subselects joins we will free
*/
void free_underlaid_joins(THD *thd, SELECT_LEX *select)
{
for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
unit;
unit= unit->next_unit())
unit->cleanup();
}
/****************************************************************************
ROLLUP handling
****************************************************************************/
/* Allocate memory needed for other rollup functions */
bool JOIN::rollup_init()
{
uint i,j;
Item **ref_array;
tmp_table_param.quick_group= 0; // Can't create groups in tmp table
rollup.state= ROLLUP::STATE_INITED;
/*
Create pointers to the different sum function groups
These are updated by rollup_make_fields()
*/
tmp_table_param.group_parts= send_group_parts;
if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) +
sizeof(List<Item>) +
ref_pointer_array_size)
* send_group_parts)))
return 1;
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
These will be filled up in rollup_make_fields()
*/
for (i= 0 ; i < send_group_parts ; i++)
{
List<Item> *fields= &rollup.fields[i];
fields->empty();
rollup.ref_pointer_arrays[i]= ref_array;
ref_array+= all_fields.elements;
for (j=0 ; j < fields_list.elements ; j++)
fields->push_back(rollup.item_null);
}
return 0;
}
/*
Fill up rollup structures with pointers to fields to use
SYNOPSIS
rollup_make_fields()
all_fields List of all fields (hidden and real ones)
fields Pointer to selected fields
func Store here a pointer to all fields
IMPLEMENTATION:
Creates copies of item_sum items for each sum level
RETURN
0 if ok
In this case func is pointing to next not used element.
1 on error
*/
bool JOIN::rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
Item_sum ***func)
{
List_iterator_fast<Item> it(all_fields);
Item *first_field= fields.head();
uint level;
/*
Create field lists for the different levels
The idea here is to have a separate field list for each rollup level to
avoid all runtime checks of which columns should be NULL.
The list is stored in reverse order to get sum function in such an order
in func that it makes it easy to reset them with init_sum_functions()
Assuming: SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP
rollup.fields[0] will contain list where a,b,c is NULL
rollup.fields[1] will contain list where b,c is NULL
...
rollup.ref_pointer_array[#] points to fields for rollup.fields[#]
...
sum_funcs_end[0] points to all sum functions
sum_funcs_end[1] points to all sum functions, except grand totals
...
*/
for (level=0 ; level < send_group_parts ; level++)
{
uint i;
uint pos= send_group_parts - level -1;
bool real_fields= 0;
Item *item;
List_iterator<Item> new_it(rollup.fields[pos]);
Item **ref_array_start= rollup.ref_pointer_arrays[pos];
ORDER *start_group;
/* Point to first hidden field */
Item **ref_array= ref_array_start + all_fields.elements-1;
/* Remember where the sum functions ends for the previous level */
sum_funcs_end[pos+1]= *func;
/* Find the start of the group for this level */
for (i= 0, start_group= group_list ;
i++ < pos ;
start_group= start_group->next)
;
it.rewind();
while ((item= it++))
{
if (item == first_field)
{
real_fields= 1; // End of hidden fields
ref_array= ref_array_start;
}
if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
{
/*
This is a top level summary function that must be replaced with
a sum function that is reset for this level.
NOTE: This code creates an object which is not that nice in a
sub select. Fortunately it's not common to have rollup in
sub selects.
*/
item= item->copy_or_same(thd);
((Item_sum*) item)->make_unique();
if (((Item_sum*) item)->setup(thd))
return 1;
*(*func)= (Item_sum*) item;
(*func)++;
}
else if (real_fields)
{
/* Check if this is something that is part of this group by */
ORDER *group;
for (group= start_group ; group ; group= group->next)
{
if (*group->item == item)
{
/*
This is an element that is used by the GROUP BY and should be
set to NULL in this level
*/
item->maybe_null= 1; // Value will be null sometimes
item= rollup.item_null;
break;
}
}
}
*ref_array= item;
if (real_fields)
{
(void) new_it++; // Point to next item
new_it.replace(item); // Replace previous
ref_array++;
}
else
ref_array--;
}
}
sum_funcs_end[0]= *func; // Point to last function
return 0;
}
/*
Send all rollup levels higher than the current one to the client
SYNOPSIS:
rollup_send_data()
idx Level we are on:
0 = Total sum level
1 = First group changed (a)
2 = Second group changed (a,b)
SAMPLE
SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP
RETURN
0 ok
1 If send_data_failed()
*/
int JOIN::rollup_send_data(uint idx)
{
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()))
{
if (send_records < unit->select_limit_cnt &&
result->send_data(rollup.fields[i]))
return 1;
send_records++;
}
}
/* Restore ref_pointer_array */
set_items_ref_array(current_ref_pointer_array);
return 0;
}
/****************************************************************************
EXPLAIN handling
Send a description about what how the select will be done to stdout
****************************************************************************/
@ -8196,19 +8522,3 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
result, unit, select_lex, 0);
DBUG_RETURN(res);
}
/*
Free joins of subselect of this select.
free_underlaid_joins()
thd - THD pointer
select - pointer to st_select_lex which subselects joins we will free
*/
void free_underlaid_joins(THD *thd, SELECT_LEX *select)
{
for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
unit;
unit= unit->next_unit())
unit->cleanup();
}