1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Merge mysqldev@production.mysql.com:my/mysql-5.0-release

into  mysql.com:/opt/local/work/mysql-5.0-root
This commit is contained in:
konstantin@mysql.com
2005-09-23 00:46:59 +04:00
58 changed files with 1789 additions and 986 deletions

View File

@ -23,6 +23,7 @@
#include "mysql_priv.h"
#include "sql_select.h"
#include "sql_cursor.h"
#include <m_ctype.h>
#include <hash.h>
@ -107,20 +108,15 @@ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
ulong options);
static Next_select_func setup_end_select_func(JOIN *join);
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
Procedure *proc);
static enum_nested_loop_state
sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static enum_nested_loop_state
evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
int error, my_bool *report_error);
static enum_nested_loop_state
evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
static enum_nested_loop_state
sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records);
static enum_nested_loop_state
flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last);
static enum_nested_loop_state
end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
@ -1716,262 +1712,6 @@ JOIN::destroy()
DBUG_RETURN(error);
}
/************************* Cursor ******************************************/
Cursor::Cursor(THD *thd)
:Query_arena(&main_mem_root, INITIALIZED),
join(0), unit(0),
protocol(thd),
close_at_commit(FALSE)
{
/* We will overwrite it at open anyway. */
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
thr_lock_owner_init(&lock_id, &thd->lock_info);
bzero((void*) ht_info, sizeof(ht_info));
}
void
Cursor::init_from_thd(THD *thd)
{
Engine_info *info;
/*
We need to save and reset thd->mem_root, otherwise it'll be freed
later in mysql_parse.
We can't just change the thd->mem_root here as we want to keep the
things that are already allocated in thd->mem_root for Cursor::fetch()
*/
main_mem_root= *thd->mem_root;
state= thd->stmt_arena->state;
/* Allocate new memory root for thd */
init_sql_alloc(thd->mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
/*
The same is true for open tables and lock: save tables and zero THD
pointers to prevent table close in close_thread_tables (This is a part
of the temporary solution to make cursors work with minimal changes to
the current source base).
*/
derived_tables= thd->derived_tables;
open_tables= thd->open_tables;
lock= thd->lock;
query_id= thd->query_id;
free_list= thd->free_list;
change_list= thd->change_list;
reset_thd(thd);
/* Now we have an active cursor and can cause a deadlock */
thd->lock_info.n_cursors++;
close_at_commit= FALSE; /* reset in case we're reusing the cursor */
info= &ht_info[0];
for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
{
const handlerton *ht= *pht;
close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
if (ht->create_cursor_read_view)
{
info->ht= ht;
info->read_view= (ht->create_cursor_read_view)();
++info;
}
}
/*
XXX: thd->locked_tables is not changed.
What problems can we have with it if cursor is open?
TODO: must be fixed because of the prelocked mode.
*/
}
void
Cursor::reset_thd(THD *thd)
{
thd->derived_tables= 0;
thd->open_tables= 0;
thd->lock= 0;
thd->free_list= 0;
thd->change_list.empty();
}
int
Cursor::open(JOIN *join_arg)
{
join= join_arg;
THD *thd= join->thd;
/* First non-constant table */
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
DBUG_ENTER("Cursor::open");
/*
Send fields description to the client; server_status is sent
in 'EOF' packet, which ends send_fields().
*/
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
join->result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
::send_eof(thd);
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
/* Prepare JOIN for reading rows. */
join->tmp_table= 0;
join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
join->send_records= 0;
join->fetch_limit= join->unit->offset_limit_cnt;
/* Disable JOIN CACHE as it is not working with cursors yet */
for (JOIN_TAB *tab= join_tab;
tab != join->join_tab + join->tables - 1;
tab++)
{
if (tab->next_select == sub_select_cache)
tab->next_select= sub_select;
}
DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
/*
null_row is set only if row not found and it's outer join: should never
happen for the first table in join_tab list
*/
DBUG_ASSERT(join_tab->table->null_row == 0);
DBUG_RETURN(0);
}
/*
DESCRIPTION
Fetch next num_rows rows from the cursor and sent them to the client
PRECONDITION:
Cursor is open
RETURN VALUES:
none, this function will send error or OK to network if necessary.
*/
void
Cursor::fetch(ulong num_rows)
{
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
enum_nested_loop_state error= NESTED_LOOP_OK;
Query_arena backup_arena;
Engine_info *info;
DBUG_ENTER("Cursor::fetch");
DBUG_PRINT("enter",("rows: %lu", num_rows));
DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
thd->lock == 0);
thd->derived_tables= derived_tables;
thd->open_tables= open_tables;
thd->lock= lock;
thd->query_id= query_id;
thd->change_list= change_list;
/* save references to memory, allocated during fetch */
thd->set_n_backup_active_arena(this, &backup_arena);
for (info= ht_info; info->read_view ; info++)
(info->ht->set_cursor_read_view)(info->read_view);
join->fetch_limit+= num_rows;
error= sub_select(join, join_tab, 0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
error= sub_select(join,join_tab,1);
if (error == NESTED_LOOP_QUERY_LIMIT)
error= NESTED_LOOP_OK; /* select_limit used */
if (error == NESTED_LOOP_CURSOR_LIMIT)
join->resume_nested_loop= TRUE;
#ifdef USING_TRANSACTIONS
ha_release_temporary_latches(thd);
#endif
/* Grab free_list here to correctly free it in close */
thd->restore_active_arena(this, &backup_arena);
for (info= ht_info; info->read_view; info++)
(info->ht->set_cursor_read_view)(0);
if (error == NESTED_LOOP_CURSOR_LIMIT)
{
/* Fetch limit worked, possibly more rows are there */
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
::send_eof(thd);
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
change_list= thd->change_list;
reset_thd(thd);
}
else
{
close(TRUE);
if (error == NESTED_LOOP_OK)
{
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
::send_eof(thd);
thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
}
else if (error != NESTED_LOOP_KILLED)
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
}
DBUG_VOID_RETURN;
}
void
Cursor::close(bool is_active)
{
THD *thd= join->thd;
DBUG_ENTER("Cursor::close");
/*
In case of UNIONs JOIN is freed inside of unit->cleanup(),
otherwise in select_lex->cleanup().
*/
if (unit)
(void) unit->cleanup();
else
(void) join->select_lex->cleanup();
for (Engine_info *info= ht_info; info->read_view; info++)
{
(info->ht->close_cursor_read_view)(info->read_view);
info->read_view= 0;
info->ht= 0;
}
if (is_active)
close_thread_tables(thd);
else
{
/* XXX: Another hack: closing tables used in the cursor */
DBUG_ASSERT(lock || open_tables || derived_tables);
TABLE *tmp_derived_tables= thd->derived_tables;
MYSQL_LOCK *tmp_lock= thd->lock;
thd->open_tables= open_tables;
thd->derived_tables= derived_tables;
thd->lock= lock;
close_thread_tables(thd);
thd->open_tables= tmp_derived_tables;
thd->derived_tables= tmp_derived_tables;
thd->lock= tmp_lock;
}
thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
join= 0;
unit= 0;
free_items();
change_list.empty();
DBUG_VOID_RETURN;
}
/*********************************************************************/
/*
An entry point to single-unit select (a select without UNION).
@ -2051,9 +1791,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
}
else
{
if (join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
select_lex, unit))
if (err= join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
select_lex, unit))
{
goto err;
}
@ -2068,9 +1808,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
DBUG_RETURN(TRUE);
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
if (join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
select_lex, unit))
if (err= join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
select_lex, unit))
{
goto err;
}
@ -2112,7 +1852,7 @@ err:
if (free_join)
{
thd->proc_info="end";
err= select_lex->cleanup();
err|= select_lex->cleanup();
DBUG_RETURN(err || thd->net.report_error);
}
DBUG_RETURN(join->error);
@ -5976,7 +5716,7 @@ void JOIN::join_free(bool full)
cleanup(full);
for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
for (sl= unit->first_select_in_union(); sl; sl= sl->next_select())
for (sl= unit->first_select(); sl; sl= sl->next_select())
{
JOIN *join= sl->join;
if (join)
@ -8077,18 +7817,24 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
if (field->maybe_null && !field->field->maybe_null())
{
result= create_tmp_field_from_item(thd, item, table, NULL,
modify_item, convert_blob_length);
modify_item, convert_blob_length);
*from_field= field->field;
if (result && modify_item)
((Item_field*)item)->result_field= result;
field->result_field= result;
}
else if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT)
else if (table_cant_handle_bit_fields && field->field->type() ==
FIELD_TYPE_BIT)
{
*from_field= field->field;
result= create_tmp_field_from_item(thd, item, table, copy_func,
modify_item, convert_blob_length);
if (result && modify_item)
field->result_field= result;
}
else
result= create_tmp_field_from_field(thd, (*from_field= field->field),
item->name, table,
modify_item ? (Item_field*) item :
modify_item ? field :
NULL,
convert_blob_length);
if (orig_type == Item::REF_ITEM && orig_modify)
@ -8122,9 +7868,31 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
/*
Create a temp table according to a field list.
Set distinct if duplicates could be removed
Given fields field pointers are changed to point at tmp_table
for send_fields
SYNOPSIS
create_tmp_table()
thd thread handle
param a description used as input to create the table
fields list of items that will be used to define
column types of the table (also see NOTES)
group TODO document
distinct should table rows be distinct
save_sum_fields see NOTES
select_options
rows_limit
table_alias possible name of the temporary table that can be used
for name resolving; can be "".
DESCRIPTION
Given field pointers are changed to point at tmp_table for
send_fields. The table object is self contained: it's
allocated in its own memory root, as well as Field objects
created for table columns.
This function will replace Item_sum items in 'fields' list with
corresponding Item_field items, pointing at the fields in the
temporary table, unless this was prohibited by TRUE
value of argument save_sum_fields. The Item_field objects
are created in THD memory root.
*/
#define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128
@ -8138,6 +7906,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ulonglong select_options, ha_rows rows_limit,
char *table_alias)
{
MEM_ROOT *mem_root_save, own_root;
TABLE *table;
uint i,field_count,null_count,null_pack_length;
uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
@ -8202,29 +7971,33 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
field_count=param->field_count+param->func_count+param->sum_func_count;
hidden_field_count=param->hidden_field_count;
if (!my_multi_malloc(MYF(MY_WME),
&table,sizeof(*table),
&reg_field, sizeof(Field*)*(field_count+1),
&blob_field, sizeof(uint)*(field_count+1),
&from_field, sizeof(Field*)*field_count,
&copy_func,sizeof(*copy_func)*(param->func_count+1),
&param->keyinfo,sizeof(*param->keyinfo),
&key_part_info,
sizeof(*key_part_info)*(param->group_parts+1),
&param->start_recinfo,
sizeof(*param->recinfo)*(field_count*2+4),
&tmpname,(uint) strlen(path)+1,
&group_buff,group && ! using_unique_constraint ?
param->group_length : 0,
NullS))
init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0);
if (!multi_alloc_root(&own_root,
&table, sizeof(*table),
&reg_field, sizeof(Field*) * (field_count+1),
&blob_field, sizeof(uint)*(field_count+1),
&from_field, sizeof(Field*)*field_count,
&copy_func, sizeof(*copy_func)*(param->func_count+1),
&param->keyinfo, sizeof(*param->keyinfo),
&key_part_info,
sizeof(*key_part_info)*(param->group_parts+1),
&param->start_recinfo,
sizeof(*param->recinfo)*(field_count*2+4),
&tmpname, (uint) strlen(path)+1,
&group_buff, group && ! using_unique_constraint ?
param->group_length : 0,
NullS))
{
bitmap_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
}
if (!(param->copy_field=copy=new Copy_field[field_count]))
/* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */
if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count]))
{
bitmap_clear_bit(&temp_pool, temp_pool_slot);
my_free((gptr) table,MYF(0)); /* purecov: inspected */
free_root(&own_root, MYF(0)); /* purecov: inspected */
DBUG_RETURN(NULL); /* purecov: inspected */
}
param->items_to_copy= copy_func;
@ -8234,6 +8007,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bzero((char*) table,sizeof(*table));
bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
bzero((char*) from_field,sizeof(Field*)*field_count);
table->mem_root= own_root;
mem_root_save= thd->mem_root;
thd->mem_root= &table->mem_root;
table->field=reg_field;
table->alias= table_alias;
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
@ -8299,7 +8077,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
Field *new_field=
create_tmp_field(thd, table, arg, arg->type(), &copy_func,
tmp_from_field, group != 0,not_all_columns,
group || distinct,
distinct,
param->convert_blob_length);
if (!new_field)
goto err; // Should be OOM
@ -8310,6 +8088,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field++= (uint) (reg_field - table->field);
blob_count++;
}
if (new_field->type() == FIELD_TYPE_BIT)
total_uneven_bit_length+= new_field->field_length & 7;
new_field->field_index= (uint) (reg_field - table->field);
*(reg_field++)= new_field;
if (new_field->real_type() == MYSQL_TYPE_STRING ||
@ -8318,7 +8098,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
string_count++;
string_total_length+= new_field->pack_length();
}
thd->mem_root= mem_root_save;
thd->change_item_tree(argp, new Item_field(new_field));
thd->mem_root= &table->mem_root;
if (!(new_field->flags & NOT_NULL_FLAG))
{
null_count++;
@ -8343,12 +8125,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
write rows to the temporary table.
We here distinguish between UNION and multi-table-updates by the fact
that in the later case group is set to the row pointer.
The test for item->marker == 4 is ensure we don't create a group-by
key over a bit field as heap tables can't handle that.
*/
Field *new_field= (param->schema_table) ?
create_tmp_field_for_schema(thd, item, table) :
create_tmp_field(thd, table, item, type, &copy_func,
tmp_from_field, group != 0,
not_all_columns || group != 0, 0,
not_all_columns || group != 0,
item->marker == 4,
param->convert_blob_length);
if (!new_field)
@ -8380,7 +8166,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*(reg_field++) =new_field;
}
if (!--hidden_field_count)
{
/*
This was the last hidden field; Remember how many hidden fields could
have null
*/
hidden_null_count=null_count;
null_count= 0;
}
}
DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
field_count= (uint) (reg_field - table->field);
@ -8415,8 +8208,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_count++;
}
hidden_null_pack_length=(hidden_null_count+7)/8;
null_pack_length= hidden_null_count +
(null_count + total_uneven_bit_length + 7) / 8;
null_pack_length= (hidden_null_pack_length +
(null_count + total_uneven_bit_length + 7) / 8);
reclength+=null_pack_length;
if (!reclength)
reclength=1; // Dummy select
@ -8432,7 +8225,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
table->s->rec_buff_length= alloc_length;
if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
if (!(table->record[0]= (byte*)
alloc_root(&table->mem_root, alloc_length*3)))
goto err;
table->record[1]= table->record[0]+alloc_length;
table->s->default_values= table->record[1]+alloc_length;
@ -8618,8 +8412,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->s->uniques= 1;
}
if (!(key_part_info= (KEY_PART_INFO*)
sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO))))
alloc_root(&table->mem_root,
keyinfo->key_parts * sizeof(KEY_PART_INFO))))
goto err;
bzero((void*) key_part_info, keyinfo->key_parts * sizeof(KEY_PART_INFO));
table->key_info=keyinfo;
keyinfo->key_part=key_part_info;
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
@ -8667,10 +8463,15 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (create_myisam_tmp_table(table,param,select_options))
goto err;
}
if (!open_tmp_table(table))
DBUG_RETURN(table);
if (open_tmp_table(table))
goto err;
err:
thd->mem_root= mem_root_save;
DBUG_RETURN(table);
err:
thd->mem_root= mem_root_save;
free_tmp_table(thd,table); /* purecov: inspected */
bitmap_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
@ -8815,11 +8616,12 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
if (table->s->keys)
{ // Get keys for ni_create
bool using_unique_constraint=0;
HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) *
keyinfo->key_parts);
HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root,
sizeof(*seg) * keyinfo->key_parts);
if (!seg)
goto err;
bzero(seg, sizeof(*seg) * keyinfo->key_parts);
if (keyinfo->key_length >= table->file->max_key_length() ||
keyinfo->key_parts > table->file->max_key_parts() ||
table->s->uniques)
@ -8916,13 +8718,14 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
void
free_tmp_table(THD *thd, TABLE *entry)
{
MEM_ROOT own_root= entry->mem_root;
const char *save_proc_info;
DBUG_ENTER("free_tmp_table");
DBUG_PRINT("enter",("table: %s",entry->alias));
save_proc_info=thd->proc_info;
thd->proc_info="removing tmp table";
free_blobs(entry);
if (entry->file)
{
if (entry->db_stat)
@ -8943,12 +8746,11 @@ free_tmp_table(THD *thd, TABLE *entry)
/* free blobs */
for (Field **ptr=entry->field ; *ptr ; ptr++)
(*ptr)->free();
my_free((gptr) entry->record[0],MYF(0));
free_io_cache(entry);
bitmap_clear_bit(&temp_pool, entry->temp_pool_slot);
my_free((gptr) entry,MYF(0));
free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
thd->proc_info=save_proc_info;
DBUG_VOID_RETURN;
@ -9063,7 +8865,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
end_select function to use. This function can't fail.
*/
static Next_select_func setup_end_select_func(JOIN *join)
Next_select_func setup_end_select_func(JOIN *join)
{
TABLE *table= join->tmp_table;
Next_select_func end_select;
@ -9218,7 +9020,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
}
static enum_nested_loop_state
enum_nested_loop_state
sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
enum_nested_loop_state rc;
@ -9359,7 +9161,7 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS.
*/
static enum_nested_loop_state
enum_nested_loop_state
sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
join_tab->table->null_row=0;
@ -12378,6 +12180,11 @@ calc_group_buffer(JOIN *join,ORDER *group)
key_length+=MAX_BLOB_WIDTH; // Can't be used as a key
else if (field->type() == MYSQL_TYPE_VARCHAR)
key_length+= field->field_length + HA_KEY_BLOB_LENGTH;
else if (field->type() == FIELD_TYPE_BIT)
{
/* Bit is usually stored as a longlong key for group fields */
key_length+= 8; // Big enough
}
else
key_length+= field->pack_length();
}
@ -13782,8 +13589,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
unit->fake_select_lex->type= "UNION RESULT";
unit->fake_select_lex->options|= SELECT_DESCRIBE;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE,
"")))
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
res= unit->exec();
res|= unit->cleanup();
}