From 2252f945d0404340813cfbd37a185a8f166dcf6b Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Sun, 12 Aug 2001 16:01:32 +0300 Subject: [PATCH] Changes so that CREATE and INSERT work from UNION's --- .bzrignore | 3 + sql/mysql_priv.h | 2 +- sql/sql_lex.h | 2 +- sql/sql_parse.cc | 183 ++++++++++++++++++++++++++++++++--------------- sql/sql_union.cc | 20 ++---- sql/sql_yacc.yy | 10 +-- 6 files changed, 145 insertions(+), 75 deletions(-) diff --git a/.bzrignore b/.bzrignore index c2ccdcb83f6..eb7463aee60 100644 --- a/.bzrignore +++ b/.bzrignore @@ -376,3 +376,6 @@ support-files/mysql.spec tags tmp/* vio/viotest-ssl +innobase/conftest.s1 +innobase/conftest.subs +sql/sql_select.cc.orig diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d02a2eb729e..9cdebb7ee98 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -309,7 +309,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List &list,COND *conds, List &ftfuncs, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, 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, Item_result_field ***copy_func, Field **from_field, bool group,bool modify_item); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index dadabe999c4..ef32dca6fc8 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -56,7 +56,7 @@ enum enum_sql_command { SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, 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, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6c3205c2feb..ca969cec120 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -48,7 +48,8 @@ static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(char **filename_ptr, char *table_name); 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 @@ -1068,7 +1069,7 @@ mysql_execute_command(void) int res=0; THD *thd=current_thd; 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; DBUG_ENTER("mysql_execute_command"); @@ -1322,32 +1323,15 @@ mysql_execute_command(void) thd->select_limit=select_lex->select_limit+select_lex->offset_limit; if (thd->select_limit < select_lex->select_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, lex->create_list, lex->key_list, select_lex->item_list,lex->duplicates))) - { - 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 - res= -1; - } - } + res=handle_create_select(thd,lex,result); + else + res= -1; + } else // regular create { res = mysql_create_table(thd,tables->db ? tables->db : thd->db, @@ -1612,36 +1596,76 @@ mysql_execute_command(void) if (thd->select_limit < select_lex->select_limit) thd->select_limit= HA_POS_ERROR; // No limit - if (check_dup(thd,tables->db,tables->real_name,tables->next)) - { - net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); - DBUG_VOID_RETURN; - } - tables->lock_type=TL_WRITE; // update first table - { - TABLE_LIST *table; - for (table = tables->next ; table ; table=table->next) - table->lock_type= lex->lock_option; - } - if (!(res=open_and_lock_tables(thd,tables))) - { - if ((result=new select_insert(tables->table,&lex->field_list, - lex->sql_command == SQLCOM_REPLACE_SELECT ? - DUP_REPLACE : DUP_IGNORE))) - { - 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); - delete result; - } - else - res= -1; + 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)) + { + net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); + DBUG_VOID_RETURN; + } + tables->lock_type=TL_WRITE; // update first table + { + TABLE_LIST *table; + for (table = tables->next ; table ; table=table->next) + table->lock_type= lex->lock_option; + } + if (!(res=open_and_lock_tables(thd,tables))) + { + if ((result=new select_insert(tables->table,&lex->field_list, + lex->sql_command == SQLCOM_REPLACE_SELECT ? + DUP_REPLACE : DUP_IGNORE))) + { + 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); + delete result; + } + else + res= -1; + } } #ifdef DELETE_ITEMS delete select_lex->having; @@ -2434,6 +2458,7 @@ mysql_init_query(THD *thd) thd->fatal_error=0; // Safety thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0; thd->sent_row_count=thd->examined_row_count=0; + thd->lex.sql_command=SQLCOM_NONE; 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, - TABLE_LIST **result) + TABLE_LIST **result, bool skip_first = false) { SELECT_LEX *sl; TABLE_LIST **new_table_list= result, *aux; const char *current_db=thd->db ? thd->db : ""; // QQ; To be removed *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) && sl->order_list.first && sl->next) @@ -2926,6 +2951,7 @@ static int create_total_list_and_check_acl(THD *thd, LEX *lex, return -1; } aux= (TABLE_LIST*) sl->table_list.first; + if (skip_first && sl == &lex->select_lex) aux=aux->next; if (aux) { TABLE_LIST *next; @@ -2961,6 +2987,51 @@ static int create_total_list_and_check_acl(THD *thd, LEX *lex, 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) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index a06c8f87cf0..072e867b569 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -25,7 +25,7 @@ #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; 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 */ first_table= (TABLE_LIST*) lex->select_lex.table_list.first; + if (create_insert) first_table=first_table->next; while ((item= it++)) if (item_list.push_back(item)) DBUG_RETURN(-1); @@ -95,7 +96,8 @@ int mysql_union(THD *thd, LEX *lex) if (thd->select_limit == HA_POS_ERROR) 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->where, sl->ftfunc_list, @@ -114,17 +116,9 @@ int mysql_union(THD *thd, LEX *lex) goto exit; } delete union_result; - - /* - Sinisa, we must also be able to handle - 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 (create_insert) + result=create_insert; + else if (lex->exchange) { if (lex->exchange->dumpfile) result=new select_dump(lex->exchange); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c6ae2241603..2cc233cf351 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -730,7 +730,7 @@ create3: lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; mysql_init_select(lex); } - select_options select_item_list opt_select_from {} + select_options select_item_list opt_select_from union {} opt_as: /* empty */ {} @@ -1319,7 +1319,7 @@ select: SELECT_SYM { LEX *lex=Lex; - lex->sql_command= SQLCOM_SELECT; + if (lex->sql_command == SQLCOM_NONE) lex->sql_command= SQLCOM_SELECT; lex->lock_option=TL_READ; mysql_init_select(lex); } @@ -2207,7 +2207,7 @@ insert_values: lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; 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 ',' no_braces @@ -3418,7 +3418,9 @@ union_list: } select { - Lex->sql_command=SQLCOM_UNION_SELECT; + LEX *lex=Lex; + if (lex->sql_command == SQLCOM_SELECT) + lex->sql_command=SQLCOM_UNION_SELECT; }