mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
Changes so that CREATE and INSERT work from UNION's
This commit is contained in:
parent
31f269f1dd
commit
2252f945d0
6 changed files with 145 additions and 75 deletions
|
@ -376,3 +376,6 @@ support-files/mysql.spec
|
||||||
tags
|
tags
|
||||||
tmp/*
|
tmp/*
|
||||||
vio/viotest-ssl
|
vio/viotest-ssl
|
||||||
|
innobase/conftest.s1
|
||||||
|
innobase/conftest.subs
|
||||||
|
sql/sql_select.cc.orig
|
||||||
|
|
|
@ -309,7 +309,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
|
||||||
List<Item_func_match> &ftfuncs,
|
List<Item_func_match> &ftfuncs,
|
||||||
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
|
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
|
||||||
ulong select_type,select_result *result);
|
ulong select_type,select_result *result);
|
||||||
int mysql_union(THD *thd,LEX *lex);
|
int mysql_union(THD *thd,LEX *lex,select_result *create_insert=(select_result *)NULL);
|
||||||
Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
|
Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
|
||||||
Item_result_field ***copy_func, Field **from_field,
|
Item_result_field ***copy_func, Field **from_field,
|
||||||
bool group,bool modify_item);
|
bool group,bool modify_item);
|
||||||
|
|
|
@ -56,7 +56,7 @@ enum enum_sql_command {
|
||||||
SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
|
SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
|
||||||
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
|
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
|
||||||
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_UNION_SELECT,
|
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_UNION_SELECT,
|
||||||
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER
|
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
|
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
|
||||||
|
|
115
sql/sql_parse.cc
115
sql/sql_parse.cc
|
@ -48,7 +48,8 @@ static void remove_escape(char *name);
|
||||||
static void refresh_status(void);
|
static void refresh_status(void);
|
||||||
static bool append_file_to_dir(char **filename_ptr, char *table_name);
|
static bool append_file_to_dir(char **filename_ptr, char *table_name);
|
||||||
static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
||||||
TABLE_LIST **result);
|
TABLE_LIST **result, bool skip_first = false);
|
||||||
|
static int handle_create_select(THD *thd, LEX *lex, select_result *c_i);
|
||||||
|
|
||||||
const char *any_db="*any*"; // Special symbol for check_access
|
const char *any_db="*any*"; // Special symbol for check_access
|
||||||
|
|
||||||
|
@ -1068,7 +1069,7 @@ mysql_execute_command(void)
|
||||||
int res=0;
|
int res=0;
|
||||||
THD *thd=current_thd;
|
THD *thd=current_thd;
|
||||||
LEX *lex= &thd->lex;
|
LEX *lex= &thd->lex;
|
||||||
TABLE_LIST *tables=(TABLE_LIST*) lex->select->table_list.first;
|
TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
|
||||||
SELECT_LEX *select_lex = lex->select;
|
SELECT_LEX *select_lex = lex->select;
|
||||||
DBUG_ENTER("mysql_execute_command");
|
DBUG_ENTER("mysql_execute_command");
|
||||||
|
|
||||||
|
@ -1322,32 +1323,15 @@ mysql_execute_command(void)
|
||||||
thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
|
thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
|
||||||
if (thd->select_limit < select_lex->select_limit)
|
if (thd->select_limit < select_lex->select_limit)
|
||||||
thd->select_limit= HA_POS_ERROR; // No limit
|
thd->select_limit= HA_POS_ERROR; // No limit
|
||||||
|
|
||||||
if (!(res=open_and_lock_tables(thd,tables->next)))
|
|
||||||
{
|
|
||||||
if ((result=new select_create(tables->db ? tables->db : thd->db,
|
if ((result=new select_create(tables->db ? tables->db : thd->db,
|
||||||
tables->real_name, &lex->create_info,
|
tables->real_name, &lex->create_info,
|
||||||
lex->create_list,
|
lex->create_list,
|
||||||
lex->key_list,
|
lex->key_list,
|
||||||
select_lex->item_list,lex->duplicates)))
|
select_lex->item_list,lex->duplicates)))
|
||||||
{
|
res=handle_create_select(thd,lex,result);
|
||||||
res=mysql_select(thd,tables->next,select_lex->item_list,
|
|
||||||
select_lex->where,
|
|
||||||
select_lex->ftfunc_list,
|
|
||||||
(ORDER*) select_lex->order_list.first,
|
|
||||||
(ORDER*) select_lex->group_list.first,
|
|
||||||
select_lex->having,
|
|
||||||
(ORDER*) lex->proc_list.first,
|
|
||||||
select_lex->options | thd->options,
|
|
||||||
result);
|
|
||||||
if (res)
|
|
||||||
result->abort();
|
|
||||||
delete result;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
res= -1;
|
res= -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else // regular create
|
else // regular create
|
||||||
{
|
{
|
||||||
res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
|
res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
|
||||||
|
@ -1612,6 +1596,45 @@ mysql_execute_command(void)
|
||||||
if (thd->select_limit < select_lex->select_limit)
|
if (thd->select_limit < select_lex->select_limit)
|
||||||
thd->select_limit= HA_POS_ERROR; // No limit
|
thd->select_limit= HA_POS_ERROR; // No limit
|
||||||
|
|
||||||
|
if (lex->select_lex.next)
|
||||||
|
{
|
||||||
|
TABLE_LIST *total;
|
||||||
|
if ((res = create_total_list_and_check_acl(thd,lex,&total)))
|
||||||
|
goto error;
|
||||||
|
if (check_dup(thd,total->db,total->real_name,total->next))
|
||||||
|
{
|
||||||
|
net_printf(&thd->net,ER_INSERT_TABLE_USED,total->real_name);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
total->lock_type=TL_WRITE; // update first table
|
||||||
|
{
|
||||||
|
TABLE_LIST *table;
|
||||||
|
for (table = total->next ; table ; table=table->next)
|
||||||
|
table->lock_type= lex->lock_option;
|
||||||
|
}
|
||||||
|
if (!(res=open_and_lock_tables(thd, total)))
|
||||||
|
{
|
||||||
|
if ((result=new select_insert(total->table,&lex->field_list,
|
||||||
|
lex->sql_command == SQLCOM_REPLACE_SELECT ?
|
||||||
|
DUP_REPLACE : DUP_IGNORE)))
|
||||||
|
{
|
||||||
|
|
||||||
|
for (SELECT_LEX *sl=&lex->select_lex; sl; sl=sl->next)
|
||||||
|
{
|
||||||
|
TABLE_LIST *help=(TABLE_LIST *)sl->table_list.first;
|
||||||
|
if (sl==&lex->select_lex) help=help->next;
|
||||||
|
for (TABLE_LIST *cursor= help;
|
||||||
|
cursor;
|
||||||
|
cursor=cursor->next)
|
||||||
|
cursor->table= ((TABLE_LIST*) cursor->table)->table;
|
||||||
|
}
|
||||||
|
res=mysql_union(thd,lex,result);
|
||||||
|
}
|
||||||
|
close_thread_tables(thd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (check_dup(thd,tables->db,tables->real_name,tables->next))
|
if (check_dup(thd,tables->db,tables->real_name,tables->next))
|
||||||
{
|
{
|
||||||
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
|
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
|
||||||
|
@ -1643,6 +1666,7 @@ mysql_execute_command(void)
|
||||||
else
|
else
|
||||||
res= -1;
|
res= -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#ifdef DELETE_ITEMS
|
#ifdef DELETE_ITEMS
|
||||||
delete select_lex->having;
|
delete select_lex->having;
|
||||||
delete select_lex->where;
|
delete select_lex->where;
|
||||||
|
@ -2434,6 +2458,7 @@ mysql_init_query(THD *thd)
|
||||||
thd->fatal_error=0; // Safety
|
thd->fatal_error=0; // Safety
|
||||||
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
|
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
|
||||||
thd->sent_row_count=thd->examined_row_count=0;
|
thd->sent_row_count=thd->examined_row_count=0;
|
||||||
|
thd->lex.sql_command=SQLCOM_NONE;
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2910,14 +2935,14 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
||||||
TABLE_LIST **result)
|
TABLE_LIST **result, bool skip_first = false)
|
||||||
{
|
{
|
||||||
SELECT_LEX *sl;
|
SELECT_LEX *sl;
|
||||||
TABLE_LIST **new_table_list= result, *aux;
|
TABLE_LIST **new_table_list= result, *aux;
|
||||||
const char *current_db=thd->db ? thd->db : ""; // QQ; To be removed
|
const char *current_db=thd->db ? thd->db : ""; // QQ; To be removed
|
||||||
|
|
||||||
*new_table_list=0; // end result list
|
*new_table_list=0; // end result list
|
||||||
for (sl=&lex->select_lex; sl; sl=sl->next)
|
for (sl= &lex->select_lex; sl; sl=sl->next)
|
||||||
{
|
{
|
||||||
if ((lex->sql_command == SQLCOM_UNION_SELECT) &&
|
if ((lex->sql_command == SQLCOM_UNION_SELECT) &&
|
||||||
sl->order_list.first && sl->next)
|
sl->order_list.first && sl->next)
|
||||||
|
@ -2926,6 +2951,7 @@ static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
aux= (TABLE_LIST*) sl->table_list.first;
|
aux= (TABLE_LIST*) sl->table_list.first;
|
||||||
|
if (skip_first && sl == &lex->select_lex) aux=aux->next;
|
||||||
if (aux)
|
if (aux)
|
||||||
{
|
{
|
||||||
TABLE_LIST *next;
|
TABLE_LIST *next;
|
||||||
|
@ -2961,6 +2987,51 @@ static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_create_select(THD *thd, LEX *lex, select_result *c_i)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
if (lex->select_lex.next)
|
||||||
|
{
|
||||||
|
TABLE_LIST *total;
|
||||||
|
if ((res = create_total_list_and_check_acl(thd,lex,&total,true)))
|
||||||
|
return res;
|
||||||
|
if (!(res=open_and_lock_tables(thd, total)))
|
||||||
|
{
|
||||||
|
for (SELECT_LEX *sl=&lex->select_lex; sl; sl=sl->next)
|
||||||
|
{
|
||||||
|
TABLE_LIST *help=(TABLE_LIST *)sl->table_list.first;
|
||||||
|
if (sl==&lex->select_lex) help=help->next;
|
||||||
|
for (TABLE_LIST *cursor= help;
|
||||||
|
cursor;
|
||||||
|
cursor=cursor->next)
|
||||||
|
cursor->table= ((TABLE_LIST*) cursor->table)->table;
|
||||||
|
}
|
||||||
|
res=mysql_union(thd,lex,c_i);
|
||||||
|
}
|
||||||
|
close_thread_tables(thd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
|
||||||
|
SELECT_LEX *select_lex=&lex->select_lex;
|
||||||
|
if (!(res=open_and_lock_tables(thd,tables->next)))
|
||||||
|
{
|
||||||
|
res=mysql_select(thd,tables->next,select_lex->item_list,
|
||||||
|
select_lex->where,
|
||||||
|
select_lex->ftfunc_list,
|
||||||
|
(ORDER*) select_lex->order_list.first,
|
||||||
|
(ORDER*) select_lex->group_list.first,
|
||||||
|
select_lex->having,
|
||||||
|
(ORDER*) lex->proc_list.first,
|
||||||
|
select_lex->options | thd->options,
|
||||||
|
c_i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res)
|
||||||
|
c_i->abort();
|
||||||
|
delete c_i;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void add_join_on(TABLE_LIST *b,Item *expr)
|
void add_join_on(TABLE_LIST *b,Item *expr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "sql_select.h"
|
#include "sql_select.h"
|
||||||
|
|
||||||
|
|
||||||
int mysql_union(THD *thd, LEX *lex)
|
int mysql_union(THD *thd, LEX *lex,select_result *create_insert=(select_result *)NULL)
|
||||||
{
|
{
|
||||||
SELECT_LEX *sl, *last_sl;
|
SELECT_LEX *sl, *last_sl;
|
||||||
ORDER *order;
|
ORDER *order;
|
||||||
|
@ -60,6 +60,7 @@ int mysql_union(THD *thd, LEX *lex)
|
||||||
|
|
||||||
/* Create a list of items that will be in the result set */
|
/* Create a list of items that will be in the result set */
|
||||||
first_table= (TABLE_LIST*) lex->select_lex.table_list.first;
|
first_table= (TABLE_LIST*) lex->select_lex.table_list.first;
|
||||||
|
if (create_insert) first_table=first_table->next;
|
||||||
while ((item= it++))
|
while ((item= it++))
|
||||||
if (item_list.push_back(item))
|
if (item_list.push_back(item))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
@ -95,7 +96,8 @@ int mysql_union(THD *thd, LEX *lex)
|
||||||
if (thd->select_limit == HA_POS_ERROR)
|
if (thd->select_limit == HA_POS_ERROR)
|
||||||
sl->options&= ~OPTION_FOUND_ROWS;
|
sl->options&= ~OPTION_FOUND_ROWS;
|
||||||
|
|
||||||
res=mysql_select(thd,(TABLE_LIST*) sl->table_list.first,
|
res=mysql_select(thd,(sl == &lex->select_lex) ? first_table :
|
||||||
|
(TABLE_LIST*) sl->table_list.first,
|
||||||
sl->item_list,
|
sl->item_list,
|
||||||
sl->where,
|
sl->where,
|
||||||
sl->ftfunc_list,
|
sl->ftfunc_list,
|
||||||
|
@ -114,17 +116,9 @@ int mysql_union(THD *thd, LEX *lex)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
delete union_result;
|
delete union_result;
|
||||||
|
if (create_insert)
|
||||||
/*
|
result=create_insert;
|
||||||
Sinisa, we must also be able to handle
|
else if (lex->exchange)
|
||||||
CREATE TABLE ... and INSERT ... SELECT with unions
|
|
||||||
|
|
||||||
To do this, it's probably best that we add a new handle_select() function
|
|
||||||
which takes 'select_result' as parameter and let this internally handle
|
|
||||||
SELECT with and without unions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (lex->exchange)
|
|
||||||
{
|
{
|
||||||
if (lex->exchange->dumpfile)
|
if (lex->exchange->dumpfile)
|
||||||
result=new select_dump(lex->exchange);
|
result=new select_dump(lex->exchange);
|
||||||
|
|
|
@ -730,7 +730,7 @@ create3:
|
||||||
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
|
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
|
||||||
mysql_init_select(lex);
|
mysql_init_select(lex);
|
||||||
}
|
}
|
||||||
select_options select_item_list opt_select_from {}
|
select_options select_item_list opt_select_from union {}
|
||||||
|
|
||||||
opt_as:
|
opt_as:
|
||||||
/* empty */ {}
|
/* empty */ {}
|
||||||
|
@ -1319,7 +1319,7 @@ select:
|
||||||
SELECT_SYM
|
SELECT_SYM
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
lex->sql_command= SQLCOM_SELECT;
|
if (lex->sql_command == SQLCOM_NONE) lex->sql_command= SQLCOM_SELECT;
|
||||||
lex->lock_option=TL_READ;
|
lex->lock_option=TL_READ;
|
||||||
mysql_init_select(lex);
|
mysql_init_select(lex);
|
||||||
}
|
}
|
||||||
|
@ -2207,7 +2207,7 @@ insert_values:
|
||||||
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
|
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
|
||||||
mysql_init_select(lex);
|
mysql_init_select(lex);
|
||||||
}
|
}
|
||||||
select_options select_item_list select_from select_lock_type {}
|
select_options select_item_list select_from select_lock_type union {}
|
||||||
|
|
||||||
values_list:
|
values_list:
|
||||||
values_list ',' no_braces
|
values_list ',' no_braces
|
||||||
|
@ -3418,7 +3418,9 @@ union_list:
|
||||||
}
|
}
|
||||||
select
|
select
|
||||||
{
|
{
|
||||||
Lex->sql_command=SQLCOM_UNION_SELECT;
|
LEX *lex=Lex;
|
||||||
|
if (lex->sql_command == SQLCOM_SELECT)
|
||||||
|
lex->sql_command=SQLCOM_UNION_SELECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue