From 1f07c0b7a528fc96ea5e1ce66030c945430876d4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Jun 2001 13:36:53 +0300 Subject: [PATCH] Second phase of UNIONS (please do not test it yet) and some other changes. This is mostly a merge between my repository and central one, so that I can take a test for multi table delete and fix it. sql/mysql_priv.h: Added new functions needed for UNIONS, EXCEPT's etc sql/sql_class.h: A little change in multi_delete class sql/sql_lex.h: Added command for UNION's sql/sql_parse.cc: One new function and SQLCOM_UNION_SELECT. Please do not test UNION's. This is just a start of the work on them sql/sql_yacc.yy: Parsing stuff for the UNION's --- sql/mysql_priv.h | 2 ++ sql/sql_class.h | 2 +- sql/sql_lex.h | 2 +- sql/sql_parse.cc | 67 +++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_unions.cc | 33 +++++++++++++++++++++++ sql/sql_yacc.yy | 26 +++++++++++++++--- 6 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 sql/sql_unions.cc diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 45249b96125..66a68b52b7f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -232,6 +232,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_change_db(THD *thd,const char *name); void mysql_parse(THD *thd,char *inBuf,uint length); void mysql_init_select(LEX *lex); +void mysql_new_select(LEX *lex); void init_max_user_conn(void); void free_max_user_conn(void); pthread_handler_decl(handle_one_connection,arg); @@ -304,6 +305,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List &list,COND *conds, List &ftfuncs, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, uint select_type,select_result *result); +int mysql_union(THD *thd,LEX *lex, uint no); 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_class.h b/sql/sql_class.h index 3b83558ebdb..efaf6eb02a3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -608,7 +608,7 @@ public: bool do_delete; public: multi_delete(TABLE_LIST *dt, thr_lock_type o, uint n) - : delete_tables (dt), lock_option(o), deleted(0), num_of_tables(n), error(0) + : delete_tables(dt), deleted(0), num_of_tables(n), error(0), lock_option(o) { thd = current_thd; do_delete = false; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d4483361961..be4a7d1273f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -55,7 +55,7 @@ enum enum_sql_command { SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS, 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_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_UNION_SELECT }; enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cfb22bcb685..20e33516225 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -47,6 +47,7 @@ static void mysql_init_query(THD *thd); static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(char **filename_ptr, char *table_name); +static inline int link_in_large_list_and_check_acl(THD *thd,LEX *lex,SQL_LIST *tables); const char *any_db="*any*"; // Special symbol for check_access @@ -1719,6 +1720,30 @@ mysql_execute_command(void) close_thread_tables(thd); break; } + case SQLCOM_UNION_SELECT: + { + uint total_selects = select_lex->select_number; total_selects++; + SQL_LIST *total=(SQL_LIST *) thd->calloc(sizeof(SQL_LIST)); + if (select_lex->options & SELECT_DESCRIBE) + lex->exchange=0; + res = link_in_large_list_and_check_acl(thd,lex,total); + if (res == -1) + { + res=0; + break; + } + if (res && (res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, any_db))) + { + res=0; + break; + } + if (!(res=open_and_lock_tables(thd,(TABLE_LIST *)total->first))) + { + res=mysql_union(thd,lex,total_selects); + if (res==-1) res=0; + } + break; + } case SQLCOM_DROP_TABLE: { if (check_table_access(thd,DROP_ACL,tables)) @@ -2405,6 +2430,14 @@ mysql_init_select(LEX *lex) select_lex->next = (SELECT_LEX *)NULL; } +void +mysql_new_select(LEX *lex) +{ + uint select_no=lex->select->select_number; + SELECT_LEX *select_lex = (SELECT_LEX *)sql_calloc(sizeof(SELECT_LEX)); + lex->select->next=select_lex; + lex->select=select_lex; lex->select->select_number = ++select_no; +} void mysql_parse(THD *thd,char *inBuf,uint length) @@ -2838,6 +2871,40 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, DBUG_RETURN(ptr); } +static inline int link_in_large_list_and_check_acl(THD *thd,LEX *lex,SQL_LIST *tables) +{ + SELECT_LEX *sl; const char *current_db=thd->db ? thd->db : ""; + for (sl=&lex->select_lex;sl;sl=sl->next) + { + if ((lex->sql_command == SQLCOM_UNION_SELECT) && (sl->order_list.first != (byte *)NULL) && (sl->next != (st_select_lex *)NULL)) + { + net_printf(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); // correct error message will come here; only last SELECt can have ORDER BY + return -1; + } + if (sl->table_list.first == (byte *)NULL) continue; + TABLE_LIST *cursor,*aux=(TABLE_LIST*) sl->table_list.first; + if (aux) + { + if (check_table_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL , aux)) + return -1; + for (;aux;aux=aux->next) + { + if (!aux->db) + aux->db=(char *)current_db; + for (cursor=(TABLE_LIST *)tables->first;cursor;cursor=cursor->next) + if (!strcmp(cursor->db,aux->db) && (!strcmp(cursor->real_name,aux->real_name))) + break; + if (!cursor || !tables->first) + { + aux->lock_type= lex->lock_option; + link_in_list(tables,(byte*)aux,(byte**) &aux->next); + } + } + } + } + return (tables->first) ? 0 : 1; +} + void add_join_on(TABLE_LIST *b,Item *expr) { if (!b->on_expr) diff --git a/sql/sql_unions.cc b/sql/sql_unions.cc new file mode 100644 index 00000000000..06612265f81 --- /dev/null +++ b/sql/sql_unions.cc @@ -0,0 +1,33 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & Monty & Sinisa + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* Union of selects */ + +#include "mysql_priv.h" + +/* + Do a union of selects +*/ + + +int mysql_union(THD *thd,LEX *lex,uint no_of_selects) +{ + SELECT_LEX *sl; + for (sl=&lex->select_lex;sl;sl=sl->next) + { + } +} diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a58186e50ac..60292d5a515 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -543,7 +543,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); opt_mi_check_type opt_to mi_check_types normal_join table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_rkey_mode handler_read_or_scan - single_multi table_multi_delete table_sini_wild + single_multi table_multi_delete table_sini_wild union union_list END_OF_INPUT %type @@ -1260,11 +1260,11 @@ select: SELECT_SYM { LEX *lex=Lex; - lex->sql_command= SQLCOM_SELECT; + if (lex->sql_command!=SQLCOM_UNION_SELECT) lex->sql_command= SQLCOM_SELECT; lex->lock_option=TL_READ; mysql_init_select(lex); } - select_options select_item_list select_into select_lock_type + select_options select_item_list select_into select_lock_type union select_into: limit_clause {} @@ -3155,3 +3155,23 @@ commit: rollback: ROLLBACK_SYM { Lex->sql_command = SQLCOM_ROLLBACK;} + + +/* +** UNIONS : glue selects together +*/ + + +union: + /* empty */ {} + | union_list + +union_list: + UNION_SYM + { + LEX *lex=Lex; + if (lex->exchange) YYABORT; /* Only the last SELECT can have INTO...... */ + lex->sql_command=SQLCOM_UNION_SELECT; + mysql_new_select(lex); lex->select->linkage=UNION_TYPE; + } + select