Commit 68c0a299 authored by unknown's avatar unknown

now all tables of query are locked in one place (including derived tables)

fixed BUG#2120 and other problem with EXPLAINing derived tables


mysql-test/r/derived.result:
  correct tables names & Co in derived tables
  test case for BUG#2120
mysql-test/t/derived.test:
  test case for BUG#2120
sql/mysql_priv.h:
  derived tables processing moved after open/locking all tables (in open_and_lock_tables)
sql/repl_failsafe.cc:
  correct initialization of TABLE_LIST
sql/sql_acl.cc:
  used simple table opening without derived table processing to avoid unneeded initialization of SELECT_LEX
sql/sql_base.cc:
  derived tables processing moved after open/locking all tables (in open_and_lock_tables)
sql/sql_delete.cc:
  all tables processing is done during opening
sql/sql_derived.cc:
  derived tables processing moved after open/locking all tables (in open_and_lock_tables) to sutisfy "all query tables locking" at the moment
sql/sql_insert.cc:
  all tables processing is done during opening
  correct initialization of TABLE_LIST
sql/sql_lex.cc:
  now table list will be created for whole query
  layout fix
  correct check of updated table in subqueries
sql/sql_lex.h:
  now table list will be created for whole query
  correct check of updated table in subqueries
sql/sql_olap.cc:
  THIS FUNCTION IS USED NOWHERE
  it will be good to remove it at all (handle_olaps)
sql/sql_parse.cc:
  derived tables processing moved after open/locking all tables (in open_and_lock_tables)
sql/sql_prepare.cc:
  new creating list parameters
  all tables processing is done during opening
sql/sql_select.cc:
  all tables processing is done during opening
sql/sql_select.h:
  now it used only within file where is defined
sql/sql_udf.cc:
  used simple table opening without derived table processing to avoid unneeded initialization of SELECT_LEX
sql/sql_update.cc:
  all tables processing is done during opening
parent e7a336d8
......@@ -59,7 +59,7 @@ explain select * from t1 as x1, (select * from t1) as x2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY x1 ALL NULL NULL NULL NULL 4
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4
2 DERIVED x1 ALL NULL NULL NULL NULL 4
2 DERIVED t1 ALL NULL NULL NULL NULL 4
drop table if exists t2,t3;
select * from (select 1) as a;
1
......@@ -141,7 +141,7 @@ a t
explain select count(*) from t1 as tt1, (select * from t1) as tt2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
2 DERIVED tt1 ALL NULL NULL NULL NULL 10000
2 DERIVED t1 index NULL a 4 NULL 10000 Using index
drop table t1;
SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b;
(SELECT * FROM (SELECT 1 as a) as a )
......@@ -189,13 +189,13 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY m2 ALL NULL NULL NULL NULL 9
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 Using where
2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort
2 DERIVED m2 index NULL PRIMARY 3 NULL 9 Using index
2 DERIVED m1 index NULL PRIMARY 3 NULL 9 Using index
explain SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY m2 ALL NULL NULL NULL NULL 9
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 Using where
2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort
2 DERIVED m2 index NULL PRIMARY 3 NULL 9 Using index
2 DERIVED m1 index NULL PRIMARY 3 NULL 9 Using index
drop table t1,t2;
SELECT a.x FROM (SELECT 1 AS x) AS a HAVING a.x = 1;
x
......@@ -229,8 +229,8 @@ explain select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 THEMAX.E2 1 Using where
2 DERIVED t1 ALL NULL NULL NULL NULL 2 Using where
3 DEPENDENT SUBQUERY B ALL NULL NULL NULL NULL 2 Using where
2 DERIVED A index NULL PRIMARY 4 NULL 2 Using where; Using index
3 DEPENDENT SUBQUERY B index NULL PRIMARY 4 NULL 2 Using where; Using index
drop table t1;
create table t1 (a int);
insert into t1 values (1),(2);
......@@ -298,3 +298,14 @@ INSERT INTO t3 VALUES (1000,0.00),(1001,0.25),(1002,0.50),(1003,0.75),(1008,1.00
select 497, TMP.ID, NULL from (select 497 as ID, MAX(t3.DATA) as DATA from t1 join t2 on (t1.ObjectID = t2.ID) join t3 on (t1.ObjectID = t3.ID) group by t2.ParID order by DATA DESC) as TMP;
497 ID NULL
drop table t1, t2, t3;
CREATE TABLE t1 (name char(1) default NULL, val int(5) default NULL);
INSERT INTO t1 VALUES ('a',1), ('a',2), ('a',2), ('a',2), ('a',3), ('a',6), ('a',7), ('a',11), ('a',11), ('a',12), ('a',13), ('a',13), ('a',20), ('b',2), ('b',3), ('b',4), ('b',5);
SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name;
name median
a 7.0000
b 3.5000
explain SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 Using temporary; Using filesort
2 DERIVED x ALL NULL NULL NULL NULL 17 Using temporary; Using filesort
2 DERIVED y ALL NULL NULL NULL NULL 17 Using where
......@@ -183,3 +183,12 @@ CREATE TABLE t3 (
INSERT INTO t3 VALUES (1000,0.00),(1001,0.25),(1002,0.50),(1003,0.75),(1008,1.00),(1009,1.25),(1010,1.50),(1011,1.75);
select 497, TMP.ID, NULL from (select 497 as ID, MAX(t3.DATA) as DATA from t1 join t2 on (t1.ObjectID = t2.ID) join t3 on (t1.ObjectID = t3.ID) group by t2.ParID order by DATA DESC) as TMP;
drop table t1, t2, t3;
#
# explain derived
#
CREATE TABLE t1 (name char(1) default NULL, val int(5) default NULL);
INSERT INTO t1 VALUES ('a',1), ('a',2), ('a',2), ('a',2), ('a',3), ('a',6), ('a',7), ('a',11), ('a',11), ('a',12), ('a',13), ('a',13), ('a',20), ('b',2), ('b',3), ('b',4), ('b',5);
SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name;
explain SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name;
......@@ -481,14 +481,13 @@ int mysql_select(THD *thd, Item ***rref_pointer_array,
SELECT_LEX *select_lex);
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
void fix_tables_pointers(SELECT_LEX *select_lex);
void fix_tables_pointers(SELECT_LEX_UNIT *select_lex);
int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
select_result *result);
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
int mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit);
int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
int mysql_handle_derived(LEX *lex);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
bool group,bool modify_item);
......@@ -676,6 +675,7 @@ int setup_ftfuncs(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
void wait_for_refresh(THD *thd);
int open_tables(THD *thd,TABLE_LIST *tables);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
int open_and_lock_tables(THD *thd,TABLE_LIST *tables);
int lock_tables(THD *thd,TABLE_LIST *tables);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
......
......@@ -732,7 +732,7 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
int error;
if (table_rules_on)
{
table.next= 0;
bzero((char*) &table, sizeof(table)); //just for safe
table.db= (char*) db;
table.real_name= (char*) table_name;
table.updating= 1;
......
......@@ -2247,7 +2247,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
#endif
if (open_and_lock_tables(thd,tables))
if (simple_open_n_lock_tables(thd,tables))
{ // Should never happen
close_thread_tables(thd); /* purecov: deadcode */
DBUG_RETURN(-1); /* purecov: deadcode */
......@@ -2395,7 +2395,7 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
}
/* open the mysql.user and mysql.db tables */
bzero((char*) &tables,sizeof(tables));
tables[0].alias=tables[0].real_name=(char*) "user";
tables[1].alias=tables[1].real_name=(char*) "db";
tables[0].next=tables+1;
......@@ -2421,7 +2421,7 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
}
#endif
if (open_and_lock_tables(thd,tables))
if (simple_open_n_lock_tables(thd,tables))
{ // This should never happen
close_thread_tables(thd); /* purecov: deadcode */
DBUG_RETURN(-1); /* purecov: deadcode */
......@@ -2517,7 +2517,7 @@ my_bool grant_init(THD *org_thd)
thd->store_globals();
thd->db= my_strdup("mysql",MYF(0));
thd->db_length=5; // Safety
bzero((char*) &tables,sizeof(tables));
bzero((char*) &tables, sizeof(tables));
tables[0].alias=tables[0].real_name= (char*) "tables_priv";
tables[1].alias=tables[1].real_name= (char*) "columns_priv";
tables[0].next=tables+1;
......@@ -3376,7 +3376,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
}
#endif
if (open_and_lock_tables(thd, tables))
if (simple_open_n_lock_tables(thd, tables))
{ // This should never happen
close_thread_tables(thd);
DBUG_RETURN(-1);
......
......@@ -1305,6 +1305,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
goto err; // Can't repair the table
TABLE_LIST table_list;
bzero((char*) &table_list, sizeof(table_list)); // just for safe
table_list.db=(char*) db;
table_list.real_name=(char*) name;
table_list.next=0;
......@@ -1372,11 +1373,13 @@ int open_tables(THD *thd,TABLE_LIST *start)
thd->proc_info="Opening tables";
for (tables=start ; tables ; tables=tables->next)
{
if (tables->derived)
continue;
if (!tables->table &&
!(tables->table=open_table(thd,
tables->db,
tables->real_name,
tables->alias, &refresh)))
!(tables->table= open_table(thd,
tables->db,
tables->real_name,
tables->alias, &refresh)))
{
if (refresh) // Refresh in progress
{
......@@ -1522,15 +1525,47 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
/*
Open all tables in list and locks them for read.
The lock will automaticly be freed by close_thread_tables()
Open all tables in list and locks them for read without derived
tables processing.
SYNOPSIS
simple_open_n_lock_tables()
thd - thread handler
tables - list of tables for open&locking
NOTE
The lock will automaticly be freed by close_thread_tables()
*/
int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
{
if (open_tables(thd,tables) || lock_tables(thd,tables))
return -1; /* purecov: inspected */
return 0;
DBUG_ENTER("open_n_lock_tables");
if (open_tables(thd, tables) || lock_tables(thd, tables))
DBUG_RETURN(-1); /* purecov: inspected */
DBUG_RETURN(0);
}
/*
Open all tables in list, locks them and process derived tables
tables processing.
SYNOPSIS
simple_open_n_lock_tables()
thd - thread handler
tables - list of tables for open&locking
NOTE
The lock will automaticly be freed by close_thread_tables()
*/
int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("open_and_lock_tables");
if (open_tables(thd, tables) || lock_tables(thd, tables))
DBUG_RETURN(-1); /* purecov: inspected */
fix_tables_pointers(thd->lex->all_selects_list);
DBUG_RETURN(mysql_handle_derived(thd->lex));
}
......@@ -1563,12 +1598,18 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
uint count=0;
for (table = tables ; table ; table=table->next)
count++;
{
if (!table->derived)
count++;
}
TABLE **start,**ptr;
if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*)*count)))
return -1;
for (table = tables ; table ; table=table->next)
*(ptr++)= table->table;
{
if (!table->derived)
*(ptr++)= table->table;
}
if (!(thd->lock=mysql_lock_tables(thd,start,count)))
return -1; /* purecov: inspected */
}
......@@ -1576,7 +1617,8 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
{
for (table = tables ; table ; table=table->next)
{
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
if (!table->derived &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
return -1;
......@@ -2165,6 +2207,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access right to all columns */
if (!(table->grant.privilege & SELECT_ACL) &&
!tables->derived &&
check_grant_all_columns(thd,SELECT_ACL,table))
DBUG_RETURN(-1);
#endif
......
......@@ -43,7 +43,6 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
if ((open_and_lock_tables(thd, table_list)))
DBUG_RETURN(-1);
fix_tables_pointers(thd->lex->all_selects_list);
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
......
......@@ -25,6 +25,49 @@
#include "sql_select.h"
#include "sql_acl.h"
int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
/*
Resolve derived tables in all queries
SYNOPSIS
mysql_handle_derived()
lex LEX for this thread
RETURN
0 ok
-1 Error
1 Error and error message given
*/
int
mysql_handle_derived(LEX *lex)
{
int res= 0;
if (lex->derived_tables)
{
for (SELECT_LEX *sl= lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
{
for (TABLE_LIST *cursor= sl->get_table_list();
cursor;
cursor= cursor->next)
{
if (cursor->derived && (res=mysql_derived(lex->thd, lex,
cursor->derived,
cursor)))
{
if (res < 0 || lex->thd->net.report_error)
send_error(lex->thd, lex->thd->killed ? ER_SERVER_SHUTDOWN : 0);
return 1;
}
}
}
}
return 0;
}
/*
Resolve derived tables in all queries
......@@ -49,9 +92,6 @@
Derived tables is stored in thd->derived_tables and freed in
close_thread_tables()
TODO
Move creation of derived tables in open_and_lock_tables()
RETURN
0 ok
1 Error
......@@ -72,143 +112,87 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
bool is_subsel= first_select->first_inner_unit() ? 1: 0;
SELECT_LEX *save_current_select= lex->current_select;
DBUG_ENTER("mysql_derived");
/*
In create_total_list, derived tables have to be treated in case of
EXPLAIN, This is because unit/node is not deleted in that
case. Current code in this function has to be improved to
recognize better when this function is called from derived tables
and when from other functions.
*/
if ((is_union || is_subsel) && unit->create_total_list(thd, lex, &tables, 1))
DBUG_RETURN(-1);
if (!(derived_result= new select_union(0)))
DBUG_RETURN(1); // out of memory
// st_select_lex_unit::prepare correctly work for single select
if ((res= unit->prepare(thd, derived_result, 0)))
goto exit;
derived_result->tmp_table_param.init();
derived_result->tmp_table_param.field_count= unit->types.elements;
/*
We have to do access checks here as this code is executed before any
sql command is started to execute.
Temp table is created so that it hounours if UNION without ALL is to be
processed
*/
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (tables)
res= check_table_access(thd,SELECT_ACL, tables,0);
else
res= check_access(thd, SELECT_ACL, any_db,0,0,0);
if (res)
DBUG_RETURN(1);
#endif
if (!(res=open_and_lock_tables(thd,tables)))
if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
unit->types, (ORDER*) 0,
is_union && !unit->union_option, 1,
(first_select->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR,
org_table_list->alias)))
{
if (is_union || is_subsel)
{
/*
The following code is a re-do of fix_tables_pointers() found
in sql_select.cc for UNION's within derived tables. The only
difference is in navigation, as in derived tables we care for
this level only.
*/
fix_tables_pointers(unit);
}
res= -1;
goto exit;
}
derived_result->set_table(table);
if (!(derived_result= new select_union(0)))
DBUG_RETURN(1); // out of memory
// st_select_lex_unit::prepare correctly work for single select
if ((res= unit->prepare(thd, derived_result, 0)))
goto exit;
if (is_union)
res= mysql_union(thd, lex, derived_result, unit);
else
{
unit->offset_limit_cnt= first_select->offset_limit;
unit->select_limit_cnt= first_select->select_limit+
first_select->offset_limit;
if (unit->select_limit_cnt < first_select->select_limit)
unit->select_limit_cnt= HA_POS_ERROR;
if (unit->select_limit_cnt == HA_POS_ERROR)
first_select->options&= ~OPTION_FOUND_ROWS;
lex->current_select= first_select;
res= mysql_select(thd, &first_select->ref_pointer_array,
(TABLE_LIST*) first_select->table_list.first,
first_select->with_wild,
first_select->item_list, first_select->where,
(first_select->order_list.elements+
first_select->group_list.elements),
(ORDER *) first_select->order_list.first,
(ORDER *) first_select->group_list.first,
first_select->having, (ORDER*) NULL,
(first_select->options | thd->options |
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
}
/*
This is done in order to redo all field optimisations when any of the
involved tables is used in the outer query
*/
if (tables)
{
for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
cursor->table->clear_query_id= 1;
}
derived_result->tmp_table_param.init();
derived_result->tmp_table_param.field_count= unit->types.elements;
if (!res)
{
/*
Temp table is created so that it hounours if UNION without ALL is to be
processed
Here we entirely fix both TABLE_LIST and list of SELECT's as
there were no derived tables
*/
if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
unit->types, (ORDER*) 0,
is_union && !unit->union_option, 1,
(first_select->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR,
org_table_list->alias)))
{
res= -1;
goto exit;
}
derived_result->set_table(table);
if (is_union)
res= mysql_union(thd, lex, derived_result, unit);
if (derived_result->flush())
res= 1;
else
{
unit->offset_limit_cnt= first_select->offset_limit;
unit->select_limit_cnt= first_select->select_limit+
first_select->offset_limit;
if (unit->select_limit_cnt < first_select->select_limit)
unit->select_limit_cnt= HA_POS_ERROR;
if (unit->select_limit_cnt == HA_POS_ERROR)
first_select->options&= ~OPTION_FOUND_ROWS;
lex->current_select= first_select;
res= mysql_select(thd, &first_select->ref_pointer_array,
(TABLE_LIST*) first_select->table_list.first,
first_select->with_wild,
first_select->item_list, first_select->where,
(first_select->order_list.elements+
first_select->group_list.elements),
(ORDER *) first_select->order_list.first,
(ORDER *) first_select->group_list.first,
first_select->having, (ORDER*) NULL,
(first_select->options | thd->options |
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
}
if (!res)
{
/*
Here we entirely fix both TABLE_LIST and list of SELECT's as
there were no derived tables
*/
if (derived_result->flush())
res= 1;
else
org_table_list->real_name= table->real_name;
org_table_list->table= table;
if (org_table_list->table_list)
{
org_table_list->real_name=table->real_name;
org_table_list->table=table;
table->derived_select_number= first_select->select_number;
table->tmp_table= TMP_TABLE;
org_table_list->table_list->real_name= table->real_name;
org_table_list->table_list->table= table;
}
table->derived_select_number= first_select->select_number;
table->tmp_table= TMP_TABLE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
org_table_list->grant.privilege= SELECT_ACL;
org_table_list->grant.privilege= SELECT_ACL;
#endif
if (lex->describe)
{
// to fix a problem in EXPLAIN
if (tables)
{
for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
if (cursor->table_list)
cursor->table_list->table=cursor->table;
}
}
else
{
unit->exclude_tree();
unit->cleanup();
}
org_table_list->db= (char *)"";
// Force read of table stats in the optimizer
table->file->info(HA_STATUS_VARIABLE);
}
org_table_list->db= (char *)"";
// Force read of table stats in the optimizer
table->file->info(HA_STATUS_VARIABLE);
}
if (res)
......@@ -223,7 +207,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
exit:
delete derived_result;
lex->current_select= save_current_select;
close_thread_tables(thd, 0, 1);
}
DBUG_RETURN(res);
}
......@@ -188,7 +188,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
res= open_and_lock_tables(thd, table_list);
if (res)
DBUG_RETURN(-1);
fix_tables_pointers(thd->lex->all_selects_list);
table= table_list->table;
thd->proc_info="init";
......@@ -646,7 +645,8 @@ class delayed_insert :public ilink {
thd.command=COM_DELAYED_INSERT;
thd.lex->current_select= 0; /* for my_message_sql */
bzero((char*) &thd.net,sizeof(thd.net)); // Safety
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety
thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT;
thd.host_or_ip= "";
bzero((char*) &info,sizeof(info));
......
......@@ -1286,12 +1286,10 @@ bool st_select_lex::test_limit()
!0 - error
*/
bool st_select_lex_unit::create_total_list(THD *thd_arg, st_lex *lex,
TABLE_LIST **result_arg,
bool check_derived)
TABLE_LIST **result_arg)
{
*result_arg= 0;
res= create_total_list_n_last_return(thd_arg, lex, &result_arg,
check_derived);
res= create_total_list_n_last_return(thd_arg, lex, &result_arg);
return res;
}
......@@ -1303,8 +1301,7 @@ bool st_select_lex_unit::create_total_list(THD *thd_arg, st_lex *lex,
thd THD pointer
lex pointer on LEX stricture
result pointer on pointer on result list of tables pointer
check_derived force derived table chacking (used for creating
table list for derived query)
DESCRIPTION
This is used for UNION & subselect to create a new table list of all used
tables.
......@@ -1318,8 +1315,7 @@ bool st_select_lex_unit::create_total_list(THD *thd_arg, st_lex *lex,
bool st_select_lex_unit::
create_total_list_n_last_return(THD *thd_arg,
st_lex *lex,
TABLE_LIST ***result_arg,
bool check_derived)
TABLE_LIST ***result_arg)
{
TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first;
TABLE_LIST **new_table_list= *result_arg, *aux;
......@@ -1345,15 +1341,12 @@ create_total_list_n_last_return(THD *thd_arg,
return 1;
}
if (sl->linkage == DERIVED_TABLE_TYPE && !check_derived)
goto end;
for (SELECT_LEX_UNIT *inner= sl->first_inner_unit();
inner;
inner= inner->next_unit())
{
if (inner->create_total_list_n_last_return(thd, lex,
&slave_list_last, 0))
&slave_list_last))
return 1;
}
......@@ -1400,63 +1393,75 @@ create_total_list_n_last_return(THD *thd_arg,
return 0;
}
st_select_lex_unit* st_select_lex_unit::master_unit()
{
return this;
}
st_select_lex* st_select_lex_unit::outer_select()
{
return (st_select_lex*) master;
}
bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc)
{
return add_to_list(thd, order_list, item, asc);
}
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
{
return item_list.push_back(item);
}
bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc)
{
return add_to_list(thd, group_list, item, asc);
}
bool st_select_lex::add_ftfunc_to_list(Item_func_match *func)
{
return !func || ftfunc_list->push_back(func); // end of memory?
}
st_select_lex_unit* st_select_lex::master_unit()
{
return (st_select_lex_unit*) master;
}
st_select_lex* st_select_lex::outer_select()
{
return (st_select_lex*) master->get_master();
}
bool st_select_lex::set_braces(bool value)
{
braces= value;
return 0;
}
bool st_select_lex::inc_in_sum_expr()
{
in_sum_expr++;
return 0;
}
uint st_select_lex::get_in_sum_expr()
{
return in_sum_expr;
}
TABLE_LIST* st_select_lex::get_table_list()
{
return (TABLE_LIST*) table_list.first;
......@@ -1467,21 +1472,25 @@ List<Item>* st_select_lex::get_item_list()
return &item_list;
}
List<String>* st_select_lex::get_use_index()
{
return use_index_ptr;
}
List<String>* st_select_lex::get_ignore_index()
{
return ignore_index_ptr;
}
ulong st_select_lex::get_table_join_options()
{
return table_join_options;
}
bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
{
if (ref_pointer_array)
......@@ -1493,6 +1502,58 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
order_group_num)* 5)) == 0;
}
/*
Find db.table which will be updated in this unit
SYNOPSIS
st_select_lex_unit::check_updateable()
db - data base name
table - real table name
RETURN
1 - found
0 - OK (table did not found)
*/
bool st_select_lex_unit::check_updateable(char *db, char *table)
{
for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
if (sl->check_updateable(db, table))
return 1;
return 0;
}
/*
Find db.table which will be updated in this select and
underlayed ones (except derived tables)
SYNOPSIS
st_select_lex::check_updateable()
db - data base name
table - real table name
RETURN
1 - found
0 - OK (table did not found)
*/
bool st_select_lex::check_updateable(char *db, char *table)
{
if (find_real_table_in_list(get_table_list(), db, table))
return 1;
for (SELECT_LEX_UNIT *un= first_inner_unit();
un;
un= un->next_unit())
{
if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
un->check_updateable(db, table))
return 1;
}
return 0;
}
void st_select_lex_unit::print(String *str)
{
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
......@@ -1535,6 +1596,7 @@ void st_select_lex::print_order(String *str, ORDER *order)
}
}
void st_select_lex::print_limit(THD *thd, String *str)
{
if (!thd)
......
......@@ -336,8 +336,7 @@ class st_select_lex_unit: public st_select_lex_node {
uint union_option;
void init_query();
bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result,
bool check_current_derived);
bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result);
st_select_lex_unit* master_unit();
st_select_lex* outer_select();
st_select_lex* first_select() { return (st_select_lex*) slave; }
......@@ -355,14 +354,15 @@ class st_select_lex_unit: public st_select_lex_node {
int exec();
int cleanup();
bool check_updateable(char *db, char *table);
void print(String *str);
friend void mysql_init_query(THD *thd);
friend int subselect_union_engine::exec();
private:
bool create_total_list_n_last_return(THD *thd, st_lex *lex,
TABLE_LIST ***result,
bool check_current_derived);
TABLE_LIST ***result);
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
......@@ -497,6 +497,7 @@ class st_select_lex: public st_select_lex_node
init_select();
}
bool setup_ref_array(THD *thd, uint order_group_num);
bool check_updateable(char *db, char *table);
void print(THD *thd, String *str);
static void print_order(String *str, ORDER *order);
void print_limit(THD *thd, String *str);
......
......@@ -143,18 +143,6 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
int count=select_lex->group_list.elements;
int sl_return=0;
// a fix for UNION's
for (TABLE_LIST *cursor= (TABLE_LIST *)select_lex->table_list.first;
cursor;
cursor=cursor->next)
{
if (cursor->do_redirect)
{
//Sinisa TODO: there are function for this purpose: fix_tables_pointers
cursor->table= cursor->table_list->table;
cursor->do_redirect= 0;
}
}
lex->last_selects=select_lex;
......
......@@ -1789,34 +1789,9 @@ mysql_execute_command(THD *thd)
#endif
}
#endif /* !HAVE_REPLICATION */
/*
TODO: make derived tables processing 'inside' SELECT processing.
TODO: solve problem with depended derived tables in subselects
*/
if (lex->derived_tables)
{
for (SELECT_LEX *sl= lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
{
for (TABLE_LIST *cursor= sl->get_table_list();
cursor;
cursor= cursor->next)
{
if (cursor->derived && (res=mysql_derived(thd, lex,
cursor->derived,
cursor)))
{
if (res < 0 || thd->net.report_error)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
DBUG_VOID_RETURN;
}
}
}
}
if (&lex->select_lex != lex->all_selects_list &&
lex->sql_command != SQLCOM_CREATE_TABLE &&
lex->unit.create_total_list(thd, lex, &tables, 0))
lex->unit.create_total_list(thd, lex, &tables))
DBUG_VOID_RETURN;
/*
......@@ -1875,7 +1850,6 @@ mysql_execute_command(THD *thd)
}
else
thd->send_explain_fields(result);
fix_tables_pointers(lex->all_selects_list);
res= mysql_explain_union(thd, &thd->lex->unit, result);
MYSQL_LOCK *save_lock= thd->lock;
thd->lock= (MYSQL_LOCK *)0;
......@@ -1918,7 +1892,6 @@ mysql_execute_command(THD *thd)
(res= open_and_lock_tables(thd,tables))))
break;
fix_tables_pointers(lex->all_selects_list);
res= mysql_do(thd, *lex->insert_list);
if (thd->net.report_error)
res= -1;
......@@ -2127,7 +2100,7 @@ mysql_execute_command(THD *thd)
lex->select_lex.table_list.first= (byte*) (tables);
create_table->next= 0;
if (&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables, 0))
lex->unit.create_total_list(thd, lex, &tables))
DBUG_VOID_RETURN;
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
......@@ -2342,6 +2315,8 @@ mysql_execute_command(THD *thd)
if (grant_option)
{
TABLE_LIST old_list,new_list;
bzero((char*) &old_list, sizeof(old_list));
bzero((char*) &new_list, sizeof(new_list)); // Safety
old_list=table[0];
new_list=table->next[0];
old_list.next=new_list.next=0;
......@@ -2673,23 +2648,15 @@ mysql_execute_command(THD *thd)
}
if (!walk)
{
if (lex->derived_tables)
{
// are we trying to delete derived table?
for (walk= (TABLE_LIST*) tables; walk; walk= walk->next)
{
if (!strcmp(auxi->real_name,walk->alias) &&
walk->derived)
{
net_printf(thd, ER_NON_UPDATABLE_TABLE,
auxi->real_name, "DELETE");
goto error;
}
}
}
net_printf(thd, ER_NONUNIQ_TABLE, auxi->real_name);
goto error;
}
if (walk->derived)
{
net_printf(thd, ER_NON_UPDATABLE_TABLE,
auxi->real_name, "DELETE");
goto error;
}
walk->lock_type= auxi->lock_type;
auxi->table_list= walk; // Remember corresponding table
}
......@@ -2703,21 +2670,27 @@ mysql_execute_command(THD *thd)
break;
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
auxi->table= auxi->table_list->table;
if (&lex->select_lex != lex->all_selects_list)
{
for (TABLE_LIST *t= select_lex->get_table_list();
t; t= t->next)
auxi->table= auxi->table_list->table;
/*
Multi-delete can't be constucted over-union => we always have
single SELECT on top and have to check underlayed SELECTs of it
*/
for (SELECT_LEX_UNIT *un= lex->select_lex.first_inner_unit();
un;
un= un->next_unit())
{
if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
un->check_updateable(auxi->table_list->db,
auxi->table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
my_error(ER_UPDATE_TABLE_USED, MYF(0), auxi->table_list->real_name);
res= -1;
break;
}
}
}
fix_tables_pointers(lex->all_selects_list);
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
table_count)))
{
......@@ -2962,7 +2935,6 @@ mysql_execute_command(THD *thd)
if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
(res= open_and_lock_tables(thd,tables))))
break;
fix_tables_pointers(lex->all_selects_list);
if (!(res= sql_set_variables(thd, &lex->var_list)))
send_ok(thd);
if (thd->net.report_error)
......
......@@ -733,7 +733,7 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
DBUG_RETURN(1);
#endif
if ((&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables, 0)))
lex->unit.create_total_list(thd, lex, &tables)))
DBUG_RETURN(1);
if (open_and_lock_tables(thd, tables))
......@@ -746,7 +746,6 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
}
else
{
fix_tables_pointers(lex->all_selects_list);
if (!result && !(result= new select_send()))
{
send_error(thd, ER_OUT_OF_RESOURCES);
......
......@@ -175,7 +175,6 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select");
fix_tables_pointers(lex->all_selects_list);
if (select_lex->next_select())
res=mysql_union(thd, lex, result, &lex->unit);
else
......
......@@ -427,7 +427,6 @@ class store_key_const_item :public store_key_item
bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
void relink_tables(SELECT_LEX *select_lex);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
COND *eliminate_not_funcs(COND *cond);
......@@ -149,7 +149,7 @@ void udf_init()
tables.lock_type = TL_READ;
tables.db=new_thd->db;
if (open_and_lock_tables(new_thd, &tables))
if (simple_open_n_lock_tables(new_thd, &tables))
{
DBUG_PRINT("error",("Can't open udf table"));
sql_print_error("Can't open mysql/func table");
......
......@@ -79,7 +79,6 @@ int mysql_update(THD *thd,
if ((open_and_lock_tables(thd, table_list)))
DBUG_RETURN(-1);
thd->proc_info="init";
fix_tables_pointers(thd->lex->all_selects_list);
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
......@@ -431,7 +430,6 @@ int mysql_multi_update(THD *thd,
#endif
if ((res=open_and_lock_tables(thd,table_list)))
DBUG_RETURN(res);
fix_tables_pointers(thd->lex->all_selects_list);
select_lex->select_limit= HA_POS_ERROR;
......
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