Surgical changes in sql_select and sql_union code in order to

accomodate EXPLAIN properly for all possible variant of UNION's
derived tables etc ...

This also fixes all reported (and unreported) bugs when EXPLAIN is
run on UNION's.

select_describe() now has a very dirty hack to avoid some problems
with transactional tables on table unlocking.

Code speedup is possible. For the moment all that was important was
that all tests are passed.
parent c630531b
...@@ -6963,13 +6963,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -6963,13 +6963,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{ {
List<Item> field_list; List<Item> field_list;
Item *item; Item *item;
List<Item> item_list;
THD *thd=join->thd; THD *thd=join->thd;
MYSQL_LOCK *save_lock;
SELECT_LEX *select_lex = &(join->thd->lex.select_lex); SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
select_result *result=join->result;
DBUG_ENTER("select_describe"); DBUG_ENTER("select_describe");
/* Don't log this into the slow query log */ /* Don't log this into the slow query log */
select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
if (join->thd->lex.select == select_lex) if (thd->lex.select == select_lex)
{ {
field_list.push_back(new Item_empty_string("table",NAME_LEN)); field_list.push_back(new Item_empty_string("table",NAME_LEN));
field_list.push_back(new Item_empty_string("type",10)); field_list.push_back(new Item_empty_string("type",10));
...@@ -6985,24 +6988,22 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -6985,24 +6988,22 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item->maybe_null=1; item->maybe_null=1;
field_list.push_back(new Item_real("rows",0.0,0,10)); field_list.push_back(new Item_real("rows",0.0,0,10));
field_list.push_back(new Item_empty_string("Extra",255)); field_list.push_back(new Item_empty_string("Extra",255));
if (send_fields(thd,field_list,1)) if (result->send_fields(field_list,1))
return; return;
} }
char buff[512],*buff_ptr;
String tmp(buff,sizeof(buff)),*packet= &thd->packet;
if (message) if (message)
{ {
packet->length(0); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_empty_string("",0));
net_store_null(packet); item_list.push_back(new Item_string(message,strlen(message)));
net_store_data(packet,message,strlen(message)); if (result->send_data(item_list))
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) result->send_error(0,NullS);
DBUG_VOID_RETURN;
} }
else else
{ {
...@@ -7011,69 +7012,70 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -7011,69 +7012,70 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{ {
JOIN_TAB *tab=join->join_tab+i; JOIN_TAB *tab=join->join_tab+i;
TABLE *table=tab->table; TABLE *table=tab->table;
char buff[512],*buff_ptr=buff;
char buff1[512], buff2[512], bufff[512];
String tmp1(buff1,sizeof(buff1));
String tmp2(buff2,sizeof(buff2));
item_list.empty();
if (tab->type == JT_ALL && tab->select && tab->select->quick) if (tab->type == JT_ALL && tab->select && tab->select->quick)
tab->type= JT_RANGE; tab->type= JT_RANGE;
packet->length(0); item_list.push_back(new Item_string(table->table_name,strlen(table->table_name)));
net_store_data(packet,table->table_name); item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type])));
net_store_data(packet,join_type_str[tab->type]); tmp1.length(0); tmp2.length(0);
tmp.length(0);
key_map bits; key_map bits;
uint j; uint j;
for (j=0,bits=tab->keys ; bits ; j++,bits>>=1) for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
{ {
if (bits & 1) if (bits & 1)
{ {
if (tmp.length()) if (tmp1.length())
tmp.append(','); tmp1.append(',');
tmp.append(table->key_info[j].name); tmp1.append(table->key_info[j].name);
} }
} }
if (tmp.length()) if (tmp1.length())
net_store_data(packet,tmp.ptr(),tmp.length()); item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length()));
else else
net_store_null(packet); item_list.push_back(new Item_null());
if (tab->ref.key_parts) if (tab->ref.key_parts)
{ {
net_store_data(packet,table->key_info[tab->ref.key].name); item_list.push_back(new Item_string(table->key_info[tab->ref.key].name,strlen(table->key_info[tab->ref.key].name)));
net_store_data(packet,(uint32) tab->ref.key_length); item_list.push_back(new Item_int((int) tab->ref.key_length));
tmp.length(0);
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++) for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
{ {
if (tmp.length()) if (tmp2.length())
tmp.append(','); tmp2.append(',');
tmp.append((*ref)->name()); tmp2.append((*ref)->name());
} }
net_store_data(packet,tmp.ptr(),tmp.length()); item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length()));
} }
else if (tab->type == JT_NEXT) else if (tab->type == JT_NEXT)
{ {
net_store_data(packet,table->key_info[tab->index].name); item_list.push_back(new Item_string(table->key_info[tab->index].name,strlen(table->key_info[tab->index].name)));
net_store_data(packet,(uint32) table->key_info[tab->index].key_length); item_list.push_back(new Item_int((int) table->key_info[tab->index].key_length));
net_store_null(packet); item_list.push_back(new Item_null());
} }
else if (tab->select && tab->select->quick) else if (tab->select && tab->select->quick)
{ {
net_store_data(packet,table->key_info[tab->select->quick->index].name);; item_list.push_back(new Item_string(table->key_info[tab->select->quick->index].name,strlen(table->key_info[tab->select->quick->index].name)));
net_store_data(packet,(uint32) tab->select->quick->max_used_key_length); item_list.push_back(new Item_int((int) tab->select->quick->max_used_key_length));
net_store_null(packet); item_list.push_back(new Item_null());
} }
else else
{ {
net_store_null(packet); item_list.push_back(new Item_null());
net_store_null(packet); item_list.push_back(new Item_null());
net_store_null(packet); item_list.push_back(new Item_null());
} }
sprintf(buff,"%.0f",join->best_positions[i].records_read); sprintf(bufff,"%.0f",join->best_positions[i].records_read);
net_store_data(packet,buff); item_list.push_back(new Item_string(bufff,strlen(bufff)));
my_bool key_read=table->key_read; my_bool key_read=table->key_read;
if (tab->type == JT_NEXT && if (tab->type == JT_NEXT &&
((table->used_keys & ((key_map) 1 << tab->index)))) ((table->used_keys & ((key_map) 1 << tab->index))))
key_read=1; key_read=1;
buff_ptr=buff;
if (tab->info) if (tab->info)
net_store_data(packet,tab->info); item_list.push_back(new Item_string(tab->info,strlen(tab->info)));
else if (tab->select) else if (tab->select)
{ {
if (tab->use_quick == 2) if (tab->use_quick == 2)
...@@ -7127,16 +7129,20 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -7127,16 +7129,20 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
} }
buff_ptr=strmov(buff_ptr,"Distinct"); buff_ptr=strmov(buff_ptr,"Distinct");
} }
net_store_data(packet,buff,(uint) (buff_ptr - buff)); item_list.push_back(new Item_string(buff,(uint) (buff_ptr - buff)));
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_VOID_RETURN; /* Purecov: Inspected */
// For next iteration // For next iteration
used_tables|=table->map; used_tables|=table->map;
if (result->send_data(item_list))
result->send_error(0,NullS);
} }
} }
if (!join->thd->lex.select->next) if (!join->thd->lex.select->next)
send_eof(&thd->net); {
save_lock=thd->lock;
thd->lock=(MYSQL_LOCK *)0;
result->send_eof();
thd->lock=save_lock;
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -31,10 +31,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -31,10 +31,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
ORDER *order; ORDER *order;
List<Item> item_list; List<Item> item_list;
TABLE *table; TABLE *table;
int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0;
int res;
TABLE_LIST result_table_list; TABLE_LIST result_table_list;
TMP_TABLE_PARAM tmp_table_param; TMP_TABLE_PARAM tmp_table_param;
select_union *union_result; select_union *union_result;
int res;
DBUG_ENTER("mysql_union"); DBUG_ENTER("mysql_union");
/* Fix tables 'to-be-unioned-from' list to point at opened tables */ /* Fix tables 'to-be-unioned-from' list to point at opened tables */
...@@ -71,32 +72,25 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -71,32 +72,25 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
order=0; order=0;
} }
if (lex->select_lex.options & SELECT_DESCRIBE) if (describe)
{
for (sl= &lex->select_lex; sl; sl=sl->next)
{ {
lex->select=sl; Item *item;
thd->offset_limit=sl->offset_limit; item_list.push_back(new Item_empty_string("table",NAME_LEN));
thd->select_limit=sl->select_limit+sl->offset_limit; item_list.push_back(new Item_empty_string("type",10));
if (thd->select_limit < sl->select_limit) item_list.push_back(item=new Item_empty_string("possible_keys",
thd->select_limit= HA_POS_ERROR; // no limit NAME_LEN*MAX_KEY));
if (thd->select_limit == HA_POS_ERROR) item->maybe_null=1;
sl->options&= ~OPTION_FOUND_ROWS; item_list.push_back(item=new Item_empty_string("key",NAME_LEN));
res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first, item->maybe_null=1;
sl->item_list, item_list.push_back(item=new Item_int("key_len",0,3));
sl->where, item->maybe_null=1;
((sl->braces) ? item_list.push_back(item=new Item_empty_string("ref",
(ORDER *) sl->order_list.first : (ORDER *) 0), NAME_LEN*MAX_REF_PARTS));
(ORDER*) sl->group_list.first, item->maybe_null=1;
sl->having, item_list.push_back(new Item_real("rows",0.0,0,10));
(ORDER*) NULL, item_list.push_back(new Item_empty_string("Extra",255));
(sl->options | thd->options | SELECT_NO_UNLOCK |
SELECT_DESCRIBE),
result);
}
DBUG_RETURN(0);
} }
else
{ {
Item *item; Item *item;
List_iterator<Item> it(lex->select_lex.item_list); List_iterator<Item> it(lex->select_lex.item_list);
...@@ -113,7 +107,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -113,7 +107,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements; tmp_table_param.field_count=item_list.elements;
if (!(table=create_tmp_table(thd, &tmp_table_param, item_list, if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
(ORDER*) 0, !lex->union_option, (ORDER*) 0, !describe & !lex->union_option,
1, 0, 1, 0,
(lex->select_lex.options | thd->options | (lex->select_lex.options | thd->options |
TMP_TABLE_ALL_COLUMNS)))) TMP_TABLE_ALL_COLUMNS))))
...@@ -130,7 +124,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -130,7 +124,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
res= -1; res= -1;
goto exit; goto exit;
} }
for (sl= &lex->select_lex; sl; sl=sl->next) union_result->save_time_stamp=!describe;
for (sl=&lex->select_lex;sl;sl=sl->next)
{ {
thd->offset_limit=sl->offset_limit; thd->offset_limit=sl->offset_limit;
thd->select_limit=sl->select_limit+sl->offset_limit; thd->select_limit=sl->select_limit+sl->offset_limit;
...@@ -146,7 +142,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -146,7 +142,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
(ORDER*) sl->group_list.first, (ORDER*) sl->group_list.first,
sl->having, sl->having,
(ORDER*) NULL, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK, sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
union_result); union_result);
if (res) if (res)
goto exit; goto exit;
...@@ -187,6 +183,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -187,6 +183,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
if (thd->select_limit == HA_POS_ERROR) if (thd->select_limit == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS; thd->options&= ~OPTION_FOUND_ROWS;
} }
if (describe)
thd->select_limit= HA_POS_ERROR; // no limit
res=mysql_select(thd,&result_table_list, res=mysql_select(thd,&result_table_list,
item_list, NULL, /*ftfunc_list,*/ order, item_list, NULL, /*ftfunc_list,*/ order,
(ORDER*) NULL, NULL, (ORDER*) NULL, (ORDER*) NULL, NULL, (ORDER*) NULL,
...@@ -222,7 +220,7 @@ select_union::~select_union() ...@@ -222,7 +220,7 @@ select_union::~select_union()
int select_union::prepare(List<Item> &list) int select_union::prepare(List<Item> &list)
{ {
if (list.elements != table->fields) if (save_time_stamp && list.elements != table->fields)
{ {
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
......
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