mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
new lock for multiupdate:
- open and create derived tables - detect which tables should be locked for write - lock and fill derived tables some unitialized variables fixed
This commit is contained in:
@ -25,15 +25,15 @@
|
||||
#include "sql_select.h"
|
||||
#include "sql_acl.h"
|
||||
|
||||
static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s,
|
||||
TABLE_LIST *t);
|
||||
|
||||
|
||||
/*
|
||||
Resolve derived tables in all queries
|
||||
call given derived table processor (preparing or filling tables)
|
||||
|
||||
SYNOPSIS
|
||||
mysql_handle_derived()
|
||||
lex LEX for this thread
|
||||
processor procedure of derived table processing
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
@ -42,7 +42,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s,
|
||||
*/
|
||||
|
||||
int
|
||||
mysql_handle_derived(LEX *lex)
|
||||
mysql_handle_derived(LEX *lex, int (*processor)(THD*, LEX*, TABLE_LIST*))
|
||||
{
|
||||
if (lex->derived_tables)
|
||||
{
|
||||
@ -55,14 +55,8 @@ mysql_handle_derived(LEX *lex)
|
||||
cursor= cursor->next_local)
|
||||
{
|
||||
int res;
|
||||
if (cursor->derived && (res= mysql_derived(lex->thd, lex,
|
||||
cursor->derived,
|
||||
cursor)))
|
||||
{
|
||||
if ((res= (*processor)(lex->thd, lex, cursor)))
|
||||
return res;
|
||||
}
|
||||
else if (cursor->ancestor)
|
||||
cursor->set_ancestor();
|
||||
}
|
||||
if (lex->describe)
|
||||
{
|
||||
@ -80,20 +74,16 @@ mysql_handle_derived(LEX *lex)
|
||||
|
||||
|
||||
/*
|
||||
Resolve derived tables in all queries
|
||||
Create temporary table structure (but do not fill it)
|
||||
|
||||
SYNOPSIS
|
||||
mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
|
||||
thd Thread handle
|
||||
lex LEX for this thread
|
||||
unit node that contains all SELECT's for derived tables
|
||||
t TABLE_LIST for the upper SELECT
|
||||
orig_table_list TABLE_LIST for the upper SELECT
|
||||
|
||||
IMPLEMENTATION
|
||||
Derived table is resolved with temporary table. It is created based on the
|
||||
queries defined. After temporary table is created, if this is not EXPLAIN,
|
||||
then the entire unit / node is deleted. unit is deleted if UNION is used
|
||||
for derived table and node is deleted is it is a simple SELECT.
|
||||
Derived table is resolved with temporary table.
|
||||
|
||||
After table creation, the above TABLE_LIST is updated with a new table.
|
||||
|
||||
@ -107,60 +97,126 @@ mysql_handle_derived(LEX *lex)
|
||||
0 ok
|
||||
1 Error
|
||||
-1 Error and error message given
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
|
||||
TABLE_LIST *org_table_list)
|
||||
int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
{
|
||||
SELECT_LEX *first_select= unit->first_select();
|
||||
TABLE *table;
|
||||
int res;
|
||||
select_union *derived_result;
|
||||
bool is_union= first_select->next_select() &&
|
||||
first_select->next_select()->linkage == UNION_TYPE;
|
||||
SELECT_LEX *save_current_select= lex->current_select;
|
||||
DBUG_ENTER("mysql_derived");
|
||||
|
||||
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;
|
||||
/*
|
||||
Temp table is created so that it hounours if UNION without ALL is to be
|
||||
processed
|
||||
*/
|
||||
if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
|
||||
unit->types, (ORDER*) 0,
|
||||
is_union && unit->union_distinct, 1,
|
||||
(first_select->options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS),
|
||||
HA_POS_ERROR,
|
||||
org_table_list->alias)))
|
||||
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
||||
int res= 0;
|
||||
if (unit)
|
||||
{
|
||||
res= -1;
|
||||
goto exit;
|
||||
SELECT_LEX *first_select= unit->first_select();
|
||||
TABLE *table= 0;
|
||||
select_union *derived_result;
|
||||
bool is_union= first_select->next_select() &&
|
||||
first_select->next_select()->linkage == UNION_TYPE;
|
||||
DBUG_ENTER("mysql_derived");
|
||||
|
||||
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;
|
||||
/*
|
||||
Temp table is created so that it hounours if UNION without ALL is to be
|
||||
processed
|
||||
*/
|
||||
if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
|
||||
unit->types, (ORDER*) 0,
|
||||
is_union && unit->union_distinct, 1,
|
||||
(first_select->options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS),
|
||||
HA_POS_ERROR,
|
||||
orig_table_list->alias)))
|
||||
{
|
||||
res= -1;
|
||||
goto exit;
|
||||
}
|
||||
derived_result->set_table(table);
|
||||
|
||||
exit:
|
||||
/*
|
||||
if it is preparation PS only or commands that need only VIEW structure
|
||||
then we do not need real data and we can skip execution (and parameters
|
||||
is not defined, too)
|
||||
*/
|
||||
if (res)
|
||||
{
|
||||
if (table)
|
||||
free_tmp_table(thd, table);
|
||||
delete derived_result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!thd->fill_derived_tables())
|
||||
delete derived_result;
|
||||
orig_table_list->derived_result= derived_result;
|
||||
orig_table_list->table= table;
|
||||
orig_table_list->real_name= table->real_name;
|
||||
table->derived_select_number= first_select->select_number;
|
||||
table->tmp_table= TMP_TABLE;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.privilege= SELECT_ACL;
|
||||
#endif
|
||||
orig_table_list->db= (char *)"";
|
||||
// Force read of table stats in the optimizer
|
||||
table->file->info(HA_STATUS_VARIABLE);
|
||||
/* Add new temporary table to list of open derived tables */
|
||||
table->next= thd->derived_tables;
|
||||
thd->derived_tables= table;
|
||||
}
|
||||
}
|
||||
derived_result->set_table(table);
|
||||
else if (orig_table_list->ancestor)
|
||||
orig_table_list->set_ancestor();
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
if it is preparation PS only or commands that need only VIEW structure
|
||||
then we do not need real data and we can skip execution (and parameters
|
||||
is not defined, too)
|
||||
|
||||
/*
|
||||
fill derived table
|
||||
|
||||
SYNOPSIS
|
||||
mysql_derived_filling()
|
||||
thd Thread handle
|
||||
lex LEX for this thread
|
||||
unit node that contains all SELECT's for derived tables
|
||||
orig_table_list TABLE_LIST for the upper SELECT
|
||||
|
||||
IMPLEMENTATION
|
||||
Derived table is resolved with temporary table. It is created based on the
|
||||
queries defined. After temporary table is filled, if this is not EXPLAIN,
|
||||
then the entire unit / node is deleted. unit is deleted if UNION is used
|
||||
for derived table and node is deleted is it is a simple SELECT.
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error
|
||||
-1 Error and error message given
|
||||
*/
|
||||
if (!thd->only_prepare() && !lex->only_view_structure())
|
||||
|
||||
int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
{
|
||||
TABLE *table= orig_table_list->table;
|
||||
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
||||
int res= 0;
|
||||
|
||||
/*check that table creation pass without problem and it is derived table */
|
||||
if (table && unit)
|
||||
{
|
||||
SELECT_LEX *first_select= unit->first_select();
|
||||
select_union *derived_result= orig_table_list->derived_result;
|
||||
SELECT_LEX *save_current_select= lex->current_select;
|
||||
bool is_union= first_select->next_select() &&
|
||||
first_select->next_select()->linkage == UNION_TYPE;
|
||||
if (is_union)
|
||||
{
|
||||
// execute union without clean up
|
||||
if (!(res= unit->prepare(thd, derived_result, SELECT_NO_UNLOCK)))
|
||||
res= unit->exec();
|
||||
res= unit->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -173,7 +229,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
|
||||
first_select->options&= ~OPTION_FOUND_ROWS;
|
||||
|
||||
lex->current_select= first_select;
|
||||
res= mysql_select(thd, &first_select->ref_pointer_array,
|
||||
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,
|
||||
@ -186,49 +242,27 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
|
||||
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;
|
||||
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;
|
||||
|
||||
if (!lex->describe)
|
||||
unit->cleanup();
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.privilege= SELECT_ACL;
|
||||
#endif
|
||||
org_table_list->db= (char *)"";
|
||||
// Force read of table stats in the optimizer
|
||||
table->file->info(HA_STATUS_VARIABLE);
|
||||
}
|
||||
|
||||
if (!lex->describe)
|
||||
free_tmp_table(thd, table);
|
||||
unit->cleanup();
|
||||
}
|
||||
lex->current_select= save_current_select;
|
||||
if (res)
|
||||
free_tmp_table(thd, table);
|
||||
else
|
||||
{
|
||||
/* Add new temporary table to list of open derived tables */
|
||||
table->next= thd->derived_tables;
|
||||
thd->derived_tables= table;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free_tmp_table(thd, table);
|
||||
unit->cleanup();
|
||||
}
|
||||
|
||||
exit:
|
||||
delete derived_result;
|
||||
lex->current_select= save_current_select;
|
||||
DBUG_RETURN(res);
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user