table lists management during VIEW processing code cleanup
sql/sql_lex.h: comments added new method of adding table to global query tables list sql/sql_parse.cc: used new method to add table to query tables list removed spaces at end of line in new code sql/sql_view.cc: layout fixed table lists management code cleanup
This commit is contained in:
parent
e4dc7e5a40
commit
ae70baf21c
@ -643,7 +643,11 @@ typedef struct st_lex
|
|||||||
THD *thd;
|
THD *thd;
|
||||||
CHARSET_INFO *charset;
|
CHARSET_INFO *charset;
|
||||||
TABLE_LIST *query_tables; /* global list of all tables in this query */
|
TABLE_LIST *query_tables; /* global list of all tables in this query */
|
||||||
/* last element next_global of previous list */
|
/*
|
||||||
|
last element next_global of previous list (used only for list building
|
||||||
|
during parsing and VIEW processing. This pointer is not valid in
|
||||||
|
mysql_execute_command
|
||||||
|
*/
|
||||||
TABLE_LIST **query_tables_last;
|
TABLE_LIST **query_tables_last;
|
||||||
TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
|
TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
|
||||||
|
|
||||||
@ -765,6 +769,11 @@ typedef struct st_lex
|
|||||||
TABLE_LIST *unlink_first_table(bool *link_to_local);
|
TABLE_LIST *unlink_first_table(bool *link_to_local);
|
||||||
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
|
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
|
||||||
void first_lists_tables_same();
|
void first_lists_tables_same();
|
||||||
|
inline void add_to_query_tables(TABLE_LIST *table)
|
||||||
|
{
|
||||||
|
*(table->prev_global= query_tables_last)= table;
|
||||||
|
query_tables_last= &table->next_global;
|
||||||
|
}
|
||||||
|
|
||||||
bool can_be_merged();
|
bool can_be_merged();
|
||||||
bool can_use_merged();
|
bool can_use_merged();
|
||||||
|
@ -5152,8 +5152,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
|||||||
/* Link table in local list (list for current select) */
|
/* Link table in local list (list for current select) */
|
||||||
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
|
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
|
||||||
/* Link table in global list (all used tables) */
|
/* Link table in global list (all used tables) */
|
||||||
*(ptr->prev_global= lex->query_tables_last)= ptr;
|
lex->add_to_query_tables(ptr);
|
||||||
lex->query_tables_last= &ptr->next_global;
|
|
||||||
DBUG_RETURN(ptr);
|
DBUG_RETURN(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5162,9 +5161,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
|||||||
Initialize a new table list for a nested join
|
Initialize a new table list for a nested join
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
init_table_list()
|
init_table_list()
|
||||||
thd current thread
|
thd current thread
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
The function initializes a structure of the TABLE_LIST type
|
The function initializes a structure of the TABLE_LIST type
|
||||||
for a nested join. It sets up its nested join list as empty.
|
for a nested join. It sets up its nested join list as empty.
|
||||||
@ -5184,7 +5183,7 @@ bool st_select_lex::init_nested_join(THD *thd)
|
|||||||
TABLE_LIST *ptr;
|
TABLE_LIST *ptr;
|
||||||
NESTED_JOIN *nested_join;
|
NESTED_JOIN *nested_join;
|
||||||
DBUG_ENTER("init_nested_join");
|
DBUG_ENTER("init_nested_join");
|
||||||
|
|
||||||
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
|
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
|
||||||
!(nested_join= ptr->nested_join=
|
!(nested_join= ptr->nested_join=
|
||||||
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
||||||
@ -5209,7 +5208,7 @@ bool st_select_lex::init_nested_join(THD *thd)
|
|||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
The function returns to the previous join nest level.
|
The function returns to the previous join nest level.
|
||||||
If the current level contains only one member, the function
|
If the current level contains only one member, the function
|
||||||
moves it one level up, eliminating the nest.
|
moves it one level up, eliminating the nest.
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
Pointer to TABLE_LIST element added to the total table list, if success
|
Pointer to TABLE_LIST element added to the total table list, if success
|
||||||
@ -5241,7 +5240,7 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
|
|||||||
Nest last join operation
|
Nest last join operation
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
nest_last_join()
|
nest_last_join()
|
||||||
thd current thread
|
thd current thread
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -5257,7 +5256,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
|
|||||||
TABLE_LIST *ptr;
|
TABLE_LIST *ptr;
|
||||||
NESTED_JOIN *nested_join;
|
NESTED_JOIN *nested_join;
|
||||||
DBUG_ENTER("nest_last_join");
|
DBUG_ENTER("nest_last_join");
|
||||||
|
|
||||||
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
|
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
|
||||||
!(nested_join= ptr->nested_join=
|
!(nested_join= ptr->nested_join=
|
||||||
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
||||||
@ -5281,7 +5280,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Save names for a join with using clase
|
Save names for a join with using clase
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
save_names_for_using_list
|
save_names_for_using_list
|
||||||
tab1 left table in join
|
tab1 left table in join
|
||||||
@ -5289,11 +5288,11 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
|
|||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
The function saves the full names of the tables in st_select_lex
|
The function saves the full names of the tables in st_select_lex
|
||||||
to be able to build later an on expression to replace the using clause.
|
to be able to build later an on expression to replace the using clause.
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
None
|
None
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
|
void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
|
||||||
TABLE_LIST *tab2)
|
TABLE_LIST *tab2)
|
||||||
@ -5315,7 +5314,7 @@ void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
|
|||||||
db2= tab2->db;
|
db2= tab2->db;
|
||||||
table2= tab2->alias;
|
table2= tab2->alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Add a table to the current join list
|
Add a table to the current join list
|
||||||
@ -5350,9 +5349,9 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
convert_right_join()
|
convert_right_join()
|
||||||
thd current thread
|
thd current thread
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
The function takes the current join list t[0],t[1] ... and
|
The function takes the current join list t[0],t[1] ... and
|
||||||
effectively converts it into the list t[1],t[0] ...
|
effectively converts it into the list t[1],t[0] ...
|
||||||
Although the outer_join flag for the new nested table contains
|
Although the outer_join flag for the new nested table contains
|
||||||
JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
|
JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
|
||||||
@ -5376,10 +5375,10 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
|
|||||||
0, otherwise
|
0, otherwise
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TABLE_LIST *st_select_lex::convert_right_join()
|
TABLE_LIST *st_select_lex::convert_right_join()
|
||||||
{
|
{
|
||||||
TABLE_LIST *tab2= join_list->pop();
|
TABLE_LIST *tab2= join_list->pop();
|
||||||
TABLE_LIST *tab1= join_list->pop();
|
TABLE_LIST *tab1= join_list->pop();
|
||||||
DBUG_ENTER("convert_right_join");
|
DBUG_ENTER("convert_right_join");
|
||||||
|
|
||||||
join_list->push_front(tab2);
|
join_list->push_front(tab2);
|
||||||
@ -5443,7 +5442,7 @@ void add_join_on(TABLE_LIST *b,Item *expr)
|
|||||||
add_join_natural()
|
add_join_natural()
|
||||||
a Table to do normal join with
|
a Table to do normal join with
|
||||||
b Do normal join with this table
|
b Do normal join with this table
|
||||||
|
|
||||||
IMPLEMENTATION
|
IMPLEMENTATION
|
||||||
This function just marks that table b should be joined with a.
|
This function just marks that table b should be joined with a.
|
||||||
The function setup_cond() will create in b->on_expr a list
|
The function setup_cond() will create in b->on_expr a list
|
||||||
|
100
sql/sql_view.cc
100
sql/sql_view.cc
@ -45,6 +45,7 @@ TYPELIB sql_updatable_view_key_typelib=
|
|||||||
-1 Error
|
-1 Error
|
||||||
1 Error and error message given
|
1 Error and error message given
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int mysql_create_view(THD *thd,
|
int mysql_create_view(THD *thd,
|
||||||
enum_view_create_mode mode)
|
enum_view_create_mode mode)
|
||||||
{
|
{
|
||||||
@ -356,6 +357,7 @@ static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}};
|
|||||||
-1 Error
|
-1 Error
|
||||||
1 Error and error message given
|
1 Error and error message given
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||||
enum_view_create_mode mode)
|
enum_view_create_mode mode)
|
||||||
{
|
{
|
||||||
@ -423,7 +425,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
read revision number
|
read revision number
|
||||||
|
|
||||||
TODO: read dependense list, too, to process cascade/restrict
|
TODO: read dependense list, too, to process cascade/restrict
|
||||||
TODO: special cascade/restrict procedure for alter?
|
TODO: special cascade/restrict procedure for alter?
|
||||||
*/
|
*/
|
||||||
@ -501,7 +503,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
|||||||
my_bool
|
my_bool
|
||||||
mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||||
{
|
{
|
||||||
bool include_proc_table= 0;
|
|
||||||
DBUG_ENTER("mysql_make_view");
|
DBUG_ENTER("mysql_make_view");
|
||||||
|
|
||||||
if (table->view)
|
if (table->view)
|
||||||
@ -512,7 +513,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TABLE_LIST *old_next, *tbl_end, *tbl_next;
|
|
||||||
SELECT_LEX *end;
|
SELECT_LEX *end;
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
LEX *old_lex= thd->lex, *lex;
|
LEX *old_lex= thd->lex, *lex;
|
||||||
@ -599,11 +599,14 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
TABLE_LIST *top_view= (table->belong_to_view ?
|
TABLE_LIST *top_view= (table->belong_to_view ?
|
||||||
table->belong_to_view :
|
table->belong_to_view :
|
||||||
table);
|
table);
|
||||||
|
TABLE_LIST *view_tables= lex->query_tables;
|
||||||
|
TABLE_LIST *view_tables_tail= 0;
|
||||||
|
|
||||||
if (lex->spfuns.records)
|
if (lex->spfuns.records)
|
||||||
{
|
{
|
||||||
/* move SP to main LEX */
|
/* move SP to main LEX */
|
||||||
sp_merge_funs(old_lex, lex);
|
sp_merge_funs(old_lex, lex);
|
||||||
|
/* open mysq.proc for functions which are not in cache */
|
||||||
if (old_lex->proc_table == 0 &&
|
if (old_lex->proc_table == 0 &&
|
||||||
(old_lex->proc_table=
|
(old_lex->proc_table=
|
||||||
(TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0)
|
(TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0)
|
||||||
@ -614,18 +617,20 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
table->real_name= table->alias= (char*)"proc";
|
table->real_name= table->alias= (char*)"proc";
|
||||||
table->real_name_length= 4;
|
table->real_name_length= 4;
|
||||||
table->cacheable_table= 1;
|
table->cacheable_table= 1;
|
||||||
include_proc_table= 1;
|
old_lex->add_to_query_tables(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* cleanup LEX */
|
||||||
if (lex->spfuns.array.buffer)
|
if (lex->spfuns.array.buffer)
|
||||||
hash_free(&lex->spfuns);
|
hash_free(&lex->spfuns);
|
||||||
|
|
||||||
old_next= table->old_next= table->next_global;
|
/*
|
||||||
if ((table->next_global= lex->query_tables))
|
mark to avoid temporary table using and put view reference and find
|
||||||
table->next_global->prev_global= &table->next_global;
|
last view table
|
||||||
|
*/
|
||||||
/* mark to avoid temporary table using and put view reference*/
|
for (TABLE_LIST *tbl= view_tables;
|
||||||
for (TABLE_LIST *tbl= table->next_global; tbl; tbl= tbl->next_global)
|
tbl;
|
||||||
|
tbl= (view_tables_tail= tbl)->next_global)
|
||||||
{
|
{
|
||||||
tbl->skip_temporary= 1;
|
tbl->skip_temporary= 1;
|
||||||
tbl->belong_to_view= top_view;
|
tbl->belong_to_view= top_view;
|
||||||
@ -638,8 +643,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
if ((old_lex->sql_command == SQLCOM_SELECT && old_lex->describe) ||
|
if ((old_lex->sql_command == SQLCOM_SELECT && old_lex->describe) ||
|
||||||
old_lex->sql_command == SQLCOM_SHOW_CREATE)
|
old_lex->sql_command == SQLCOM_SHOW_CREATE)
|
||||||
{
|
{
|
||||||
if (check_table_access(thd, SELECT_ACL, table->next_global, 1) &&
|
if (check_table_access(thd, SELECT_ACL, view_tables, 1) &&
|
||||||
check_table_access(thd, SHOW_VIEW_ACL, table->next_global, 1))
|
check_table_access(thd, SHOW_VIEW_ACL, view_tables, 1))
|
||||||
{
|
{
|
||||||
my_error(ER_VIEW_NO_EXPLAIN, MYF(0));
|
my_error(ER_VIEW_NO_EXPLAIN, MYF(0));
|
||||||
goto err;
|
goto err;
|
||||||
@ -653,6 +658,29 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
if (lex->select_lex.options & OPTION_TO_QUERY_CACHE)
|
if (lex->select_lex.options & OPTION_TO_QUERY_CACHE)
|
||||||
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Put tables of VIEW after VIEW TABLE_LIST
|
||||||
|
|
||||||
|
NOTE: It is important for UPDATE/INSERT/DELETE checks to have this
|
||||||
|
tables just after VIEW instead of tail of list, to be able check that
|
||||||
|
table is unique. Also we store old next table for the same purpose.
|
||||||
|
*/
|
||||||
|
table->old_next= table->next_global;
|
||||||
|
if (view_tables)
|
||||||
|
{
|
||||||
|
if (table->next_global)
|
||||||
|
{
|
||||||
|
table->next_global->prev_global= &view_tables_tail->next_global;
|
||||||
|
view_tables_tail->next_global= table->old_next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lex->query_tables_last= &view_tables_tail->next_global;
|
||||||
|
}
|
||||||
|
view_tables->prev_global= &table->next_global;
|
||||||
|
table->next_global= view_tables;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check MERGE algorithm ability
|
check MERGE algorithm ability
|
||||||
- algorithm is not explicit TEMPORARY TABLE
|
- algorithm is not explicit TEMPORARY TABLE
|
||||||
@ -667,31 +695,26 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
TODO: support multi tables substitutions
|
TODO: support multi tables substitutions
|
||||||
|
|
||||||
table->next_global should be the same as
|
|
||||||
(TABLE_LIST *)lex->select_lex.table_list.first;
|
|
||||||
*/
|
*/
|
||||||
TABLE_LIST *view_table= table->next_global;
|
|
||||||
/* lex should contain at least one table */
|
/* lex should contain at least one table */
|
||||||
DBUG_ASSERT(view_table != 0);
|
DBUG_ASSERT(view_tables != 0);
|
||||||
|
|
||||||
table->effective_algorithm= VIEW_ALGORITHM_MERGE;
|
table->effective_algorithm= VIEW_ALGORITHM_MERGE;
|
||||||
DBUG_PRINT("info", ("algorithm: MERGE"));
|
DBUG_PRINT("info", ("algorithm: MERGE"));
|
||||||
table->updatable= (table->updatable_view != 0);
|
table->updatable= (table->updatable_view != 0);
|
||||||
|
|
||||||
if (old_next)
|
table->ancestor= view_tables;
|
||||||
{
|
/*
|
||||||
if ((view_table->next_global= old_next))
|
next table should include SELECT_LEX under this table SELECT_LEX
|
||||||
old_next->prev_global= &view_table->next_global;
|
|
||||||
}
|
TODO: ehere should be loop for multi tables substitution
|
||||||
table->ancestor= view_table;
|
*/
|
||||||
// next table should include SELECT_LEX under this table SELECT_LEX
|
|
||||||
table->ancestor->select_lex= table->select_lex;
|
table->ancestor->select_lex= table->select_lex;
|
||||||
/*
|
/*
|
||||||
move lock type (TODO: should we issue error in case of TMPTABLE
|
move lock type (TODO: should we issue error in case of TMPTABLE
|
||||||
algorithm and non-read locking)?
|
algorithm and non-read locking)?
|
||||||
*/
|
*/
|
||||||
view_table->lock_type= table->lock_type;
|
view_tables->lock_type= table->lock_type;
|
||||||
|
|
||||||
/* Store WHERE clause for postprocessing in setup_ancestor */
|
/* Store WHERE clause for postprocessing in setup_ancestor */
|
||||||
table->where= lex->select_lex.where;
|
table->where= lex->select_lex.where;
|
||||||
@ -714,22 +737,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
lex->unit.include_down(table->select_lex);
|
lex->unit.include_down(table->select_lex);
|
||||||
lex->unit.slave= &lex->select_lex; // fix include_down initialisation
|
lex->unit.slave= &lex->select_lex; // fix include_down initialisation
|
||||||
|
|
||||||
if (old_next)
|
|
||||||
{
|
|
||||||
if ((tbl_end= table->next_global))
|
|
||||||
{
|
|
||||||
for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next)
|
|
||||||
;
|
|
||||||
if ((tbl_end->next_global= old_next))
|
|
||||||
tbl_end->next_global->prev_global= &tbl_end->next_global;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* VIEW do not contain tables */
|
|
||||||
table->next_global= old_next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table->derived= &lex->unit;
|
table->derived= &lex->unit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -746,17 +753,6 @@ ok:
|
|||||||
lex->all_selects_list->link_prev=
|
lex->all_selects_list->link_prev=
|
||||||
(st_select_lex_node**)&old_lex->all_selects_list;
|
(st_select_lex_node**)&old_lex->all_selects_list;
|
||||||
|
|
||||||
if (include_proc_table)
|
|
||||||
{
|
|
||||||
TABLE_LIST *proc= old_lex->proc_table;
|
|
||||||
if((proc->next_global= table->next_global))
|
|
||||||
{
|
|
||||||
table->next_global->prev_global= &proc->next_global;
|
|
||||||
}
|
|
||||||
proc->prev_global= &table->next_global;
|
|
||||||
table->next_global= proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user