summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <Sinisa@sinisa.nasamreza.org>2001-08-12 16:01:32 +0300
committerunknown <Sinisa@sinisa.nasamreza.org>2001-08-12 16:01:32 +0300
commit02e0db5a51c8218ce1cb2ecd29d1001d92e914a7 (patch)
tree10165e52923d9a0f715cfe8aae6421411900d377
parentad5100da0f7041cf7a0dbf3cf2860c0f82fc4c7a (diff)
downloadmariadb-git-02e0db5a51c8218ce1cb2ecd29d1001d92e914a7.tar.gz
Changes so that CREATE and INSERT work from UNION's
BitKeeper/etc/ignore: Added innobase/conftest.s1 innobase/conftest.subs sql/sql_select.cc.orig to the ignore list
-rw-r--r--.bzrignore3
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc183
-rw-r--r--sql/sql_union.cc20
-rw-r--r--sql/sql_yacc.yy10
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<Item> &list,COND *conds,
List<Item_func_match> &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;
}