mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merged the code of mwl 106 into the latest 5.3 with mwl 90 pushed.
Resolved all conflicts and failures.
This commit is contained in:
580
sql/table.cc
580
sql/table.cc
@ -3513,129 +3513,112 @@ void TABLE_LIST::calc_md5(char *buffer)
|
||||
|
||||
|
||||
/**
|
||||
@brief Set underlying table for table place holder of view.
|
||||
@brief
|
||||
Create field translation for mergeable derived table/view.
|
||||
|
||||
@details
|
||||
@param thd Thread handle
|
||||
|
||||
Replace all views that only use one table with the table itself. This
|
||||
allows us to treat the view as a simple table and even update it (it is a
|
||||
kind of optimization).
|
||||
@details
|
||||
Create field translation for mergeable derived table/view.
|
||||
|
||||
@note
|
||||
|
||||
This optimization is potentially dangerous as it makes views
|
||||
masquerade as base tables: Views don't have the pointer TABLE_LIST::table
|
||||
set to non-@c NULL.
|
||||
|
||||
We may have the case where a view accesses tables not normally accessible
|
||||
in the current Security_context (only in the definer's
|
||||
Security_context). According to the table's GRANT_INFO (TABLE::grant),
|
||||
access is fulfilled, but this is implicitly meant in the definer's security
|
||||
context. Hence we must never look at only a TABLE's GRANT_INFO without
|
||||
looking at the one of the referring TABLE_LIST.
|
||||
@return FALSE ok.
|
||||
@return TRUE an error occur.
|
||||
*/
|
||||
|
||||
void TABLE_LIST::set_underlying_merge()
|
||||
bool TABLE_LIST::create_field_translation(THD *thd)
|
||||
{
|
||||
TABLE_LIST *tbl;
|
||||
Item *item;
|
||||
Field_translator *transl;
|
||||
SELECT_LEX *select= get_single_select();
|
||||
List_iterator_fast<Item> it(select->item_list);
|
||||
uint field_count= 0;
|
||||
Query_arena *arena= thd->stmt_arena, backup;
|
||||
bool res= FALSE;
|
||||
|
||||
if ((tbl= merge_underlying_list))
|
||||
used_items.empty();
|
||||
|
||||
if (field_translation)
|
||||
{
|
||||
/* This is a view. Process all tables of view */
|
||||
DBUG_ASSERT(view && effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
do
|
||||
/*
|
||||
Update items in the field translation aftet view have been prepared.
|
||||
It's needed because some items in the select list, like IN subselects,
|
||||
might be substituted for optimized ones.
|
||||
*/
|
||||
if (is_view() && get_unit()->prepared && !field_translation_updated)
|
||||
{
|
||||
if (tbl->merge_underlying_list) // This is a view
|
||||
while ((item= it++))
|
||||
{
|
||||
DBUG_ASSERT(tbl->view &&
|
||||
tbl->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
/*
|
||||
This is the only case where set_ancestor is called on an object
|
||||
that may not be a view (in which case ancestor is 0)
|
||||
*/
|
||||
tbl->merge_underlying_list->set_underlying_merge();
|
||||
field_translation[field_count++].item= item;
|
||||
}
|
||||
} while ((tbl= tbl->next_local));
|
||||
|
||||
if (!multitable_view)
|
||||
{
|
||||
table= merge_underlying_list->table;
|
||||
schema_table= merge_underlying_list->schema_table;
|
||||
field_translation_updated= TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (arena->is_conventional())
|
||||
arena= 0; // For easier test
|
||||
else
|
||||
thd->set_n_backup_active_arena(arena, &backup);
|
||||
|
||||
/* Create view fields translation table */
|
||||
|
||||
if (!(transl=
|
||||
(Field_translator*)(thd->stmt_arena->
|
||||
alloc(select->item_list.elements *
|
||||
sizeof(Field_translator)))))
|
||||
{
|
||||
res= TRUE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while ((item= it++))
|
||||
{
|
||||
transl[field_count].name= item->name;
|
||||
transl[field_count++].item= item;
|
||||
}
|
||||
field_translation= transl;
|
||||
field_translation_end= transl + field_count;
|
||||
|
||||
exit:
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setup fields of placeholder of merged VIEW
|
||||
/**
|
||||
@brief
|
||||
Create field translation for mergeable derived table/view.
|
||||
|
||||
SYNOPSIS
|
||||
TABLE_LIST::setup_underlying()
|
||||
thd - thread handler
|
||||
@param thd Thread handle
|
||||
|
||||
DESCRIPTION
|
||||
It is:
|
||||
- preparing translation table for view columns
|
||||
If there are underlying view(s) procedure first will be called for them.
|
||||
@details
|
||||
Create field translation for mergeable derived table/view.
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
@return FALSE ok.
|
||||
@return TRUE an error occur.
|
||||
*/
|
||||
|
||||
bool TABLE_LIST::setup_underlying(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("TABLE_LIST::setup_underlying");
|
||||
|
||||
if (!field_translation && merge_underlying_list)
|
||||
if (!view || (!field_translation && merge_underlying_list))
|
||||
{
|
||||
Field_translator *transl;
|
||||
SELECT_LEX *select= &view->select_lex;
|
||||
Item *item;
|
||||
TABLE_LIST *tbl;
|
||||
List_iterator_fast<Item> it(select->item_list);
|
||||
uint field_count= 0;
|
||||
|
||||
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*) &field_count))
|
||||
{
|
||||
SELECT_LEX *select= get_single_select();
|
||||
|
||||
if (create_field_translation(thd))
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
for (tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->merge_underlying_list &&
|
||||
tbl->setup_underlying(thd))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create view fields translation table */
|
||||
|
||||
if (!(transl=
|
||||
(Field_translator*)(thd->stmt_arena->
|
||||
alloc(select->item_list.elements *
|
||||
sizeof(Field_translator)))))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
while ((item= it++))
|
||||
{
|
||||
transl[field_count].name= item->name;
|
||||
transl[field_count++].item= item;
|
||||
}
|
||||
field_translation= transl;
|
||||
field_translation_end= transl + field_count;
|
||||
/* TODO: use hash for big number of fields */
|
||||
|
||||
/* full text function moving to current select */
|
||||
if (view->select_lex.ftfunc_list->elements)
|
||||
if (select->ftfunc_list->elements)
|
||||
{
|
||||
Item_func_match *ifm;
|
||||
SELECT_LEX *current_select= thd->lex->current_select;
|
||||
List_iterator_fast<Item_func_match>
|
||||
li(*(view->select_lex.ftfunc_list));
|
||||
li(*(select_lex->ftfunc_list));
|
||||
while ((ifm= li++))
|
||||
current_select->ftfunc_list->push_front(ifm);
|
||||
}
|
||||
@ -3645,7 +3628,7 @@ bool TABLE_LIST::setup_underlying(THD *thd)
|
||||
|
||||
|
||||
/*
|
||||
Prepare where expression of view
|
||||
Prepare where expression of derived table/view
|
||||
|
||||
SYNOPSIS
|
||||
TABLE_LIST::prep_where()
|
||||
@ -3669,7 +3652,8 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds,
|
||||
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->view && tbl->prep_where(thd, conds, no_where_clause))
|
||||
if (tbl->is_view_or_derived() &&
|
||||
tbl->prep_where(thd, conds, no_where_clause))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
@ -3677,6 +3661,8 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds,
|
||||
|
||||
if (where)
|
||||
{
|
||||
if (where->fixed)
|
||||
where->update_used_tables();
|
||||
if (!where->fixed && where->fix_fields(thd, &where))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
@ -3709,7 +3695,13 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds,
|
||||
}
|
||||
}
|
||||
if (tbl == 0)
|
||||
{
|
||||
if (*conds && !(*conds)->fixed)
|
||||
(*conds)->fix_fields(thd, conds);
|
||||
*conds= and_conds(*conds, where->copy_andor_structure(thd));
|
||||
if (*conds && !(*conds)->fixed)
|
||||
(*conds)->fix_fields(thd, conds);
|
||||
}
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
where_processed= TRUE;
|
||||
@ -3748,10 +3740,11 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded)
|
||||
DBUG_PRINT("info", ("alias: %s", table->alias));
|
||||
if (table->on_expr)
|
||||
cond= table->on_expr->copy_andor_structure(thd);
|
||||
if (!table->nested_join)
|
||||
if (!table->view)
|
||||
DBUG_RETURN(cond);
|
||||
List_iterator<TABLE_LIST> li(table->nested_join->join_list);
|
||||
while (TABLE_LIST *tbl= li++)
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST*)table->view->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->view && !is_cascaded)
|
||||
continue;
|
||||
@ -3791,7 +3784,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
{
|
||||
DBUG_ENTER("TABLE_LIST::prep_check_option");
|
||||
bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED;
|
||||
|
||||
TABLE_LIST *merge_underlying_list= view->select_lex.get_table_list();
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
/* see comment of check_opt_type parameter */
|
||||
@ -3808,7 +3801,6 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
|
||||
if (where)
|
||||
{
|
||||
DBUG_ASSERT(where->fixed);
|
||||
check_option= where->copy_andor_structure(thd);
|
||||
}
|
||||
if (is_cascaded)
|
||||
@ -3904,10 +3896,14 @@ void TABLE_LIST::hide_view_error(THD *thd)
|
||||
TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find)
|
||||
{
|
||||
/* is this real table and table which we are looking for? */
|
||||
if (table == table_to_find && merge_underlying_list == 0)
|
||||
if (table == table_to_find && view == 0)
|
||||
return this;
|
||||
if (!view)
|
||||
return 0;
|
||||
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= view->select_lex.get_table_list();
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
TABLE_LIST *result;
|
||||
if ((result= tbl->find_underlying_table(table_to_find)))
|
||||
@ -3989,7 +3985,12 @@ bool TABLE_LIST::check_single_table(TABLE_LIST **table_arg,
|
||||
table_map map,
|
||||
TABLE_LIST *view_arg)
|
||||
{
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
if (!select_lex)
|
||||
return FALSE;
|
||||
DBUG_ASSERT(is_merged_derived());
|
||||
for (TABLE_LIST *tbl= get_single_select()->get_table_list();
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->table)
|
||||
{
|
||||
@ -4031,8 +4032,10 @@ bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root)
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(view && merge_underlying_list);
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
DBUG_ASSERT(is_view_or_derived() && is_merged_derived());
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST*)view->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
if (tbl->set_insert_values(mem_root))
|
||||
return TRUE;
|
||||
}
|
||||
@ -4058,7 +4061,7 @@ bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root)
|
||||
*/
|
||||
bool TABLE_LIST::is_leaf_for_name_resolution()
|
||||
{
|
||||
return (view || is_natural_join || is_join_columns_complete ||
|
||||
return (is_merged_derived() || is_natural_join || is_join_columns_complete ||
|
||||
!nested_join);
|
||||
}
|
||||
|
||||
@ -4196,7 +4199,11 @@ void TABLE_LIST::register_want_access(ulong want_access)
|
||||
if (table)
|
||||
table->grant.want_privilege= want_access;
|
||||
}
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
if (!view)
|
||||
return;
|
||||
for (TABLE_LIST *tbl= view->select_lex.get_table_list();
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
tbl->register_want_access(want_access);
|
||||
}
|
||||
|
||||
@ -4426,14 +4433,23 @@ const char *Natural_join_column::db_name()
|
||||
DBUG_ASSERT(!strcmp(table_ref->db,
|
||||
table_ref->table->s->db.str) ||
|
||||
(table_ref->schema_table &&
|
||||
table_ref->table->s->db.str[0] == 0));
|
||||
table_ref->table->s->db.str[0] == 0) ||
|
||||
table_ref->is_materialized_derived());
|
||||
return table_ref->db;
|
||||
}
|
||||
|
||||
|
||||
GRANT_INFO *Natural_join_column::grant()
|
||||
{
|
||||
if (view_field)
|
||||
/* if (view_field)
|
||||
return &(table_ref->grant);
|
||||
return &(table_ref->table->grant);*/
|
||||
/*
|
||||
Have to check algorithm because merged derived also has
|
||||
field_translation.
|
||||
*/
|
||||
//if (table_ref->effective_algorithm == DTYPE_ALGORITHM_MERGE)
|
||||
if (table_ref->is_merged_derived())
|
||||
return &(table_ref->grant);
|
||||
return &(table_ref->table->grant);
|
||||
}
|
||||
@ -4514,7 +4530,17 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
|
||||
{
|
||||
DBUG_RETURN(field);
|
||||
}
|
||||
Item *item= new Item_direct_view_ref(view, field_ref, name);
|
||||
Item *item= new Item_direct_view_ref(&view->view->select_lex.context,
|
||||
field_ref, view->alias,
|
||||
name, view);
|
||||
/*
|
||||
Force creation of nullable item for the result tmp table for outer joined
|
||||
views/derived tables.
|
||||
*/
|
||||
if (view->outer_join)
|
||||
item->maybe_null= TRUE;
|
||||
/* Save item in case we will need to fall back to materialization. */
|
||||
view->used_items.push_back(item);
|
||||
DBUG_RETURN(item);
|
||||
}
|
||||
|
||||
@ -4568,8 +4594,7 @@ void Field_iterator_table_ref::set_field_iterator()
|
||||
/* This is a merge view, so use field_translation. */
|
||||
else if (table_ref->field_translation)
|
||||
{
|
||||
DBUG_ASSERT(table_ref->view &&
|
||||
table_ref->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
DBUG_ASSERT(table_ref->is_merged_derived());
|
||||
field_it= &view_field_it;
|
||||
DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_view",
|
||||
table_ref->alias));
|
||||
@ -5193,15 +5218,16 @@ void st_table::mark_virtual_columns_for_write(bool insert_fl)
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Allocate space for keys
|
||||
|
||||
@param key_count number of keys to allocate.
|
||||
@param key_count number of keys to allocate
|
||||
|
||||
@details
|
||||
Allocates space enough to fit 'key_count' keys for this table.
|
||||
The function allocates memory to fit 'key_count' keys for this table.
|
||||
|
||||
@return FALSE space was successfully allocated.
|
||||
@return TRUE an error occur.
|
||||
@return FALSE space was successfully allocated
|
||||
@return TRUE an error occur
|
||||
*/
|
||||
|
||||
bool TABLE::alloc_keys(uint key_count)
|
||||
@ -5260,22 +5286,24 @@ void TABLE::create_key_part_by_field(KEY *keyinfo,
|
||||
|
||||
|
||||
/**
|
||||
Add a key to a temporary table
|
||||
@brief
|
||||
Add one key to a temporary table
|
||||
|
||||
@param key the number of the key
|
||||
@param key_parts number of components of the key
|
||||
@param next_field_no the call-back function that returns the number of
|
||||
the field used as the next component of the key
|
||||
@param arg the argument for the above function
|
||||
@param unique Is it unique index
|
||||
@param unique TRUE <=> it is a unique index
|
||||
|
||||
@details
|
||||
The function adds a new key to the table that is assumed to be
|
||||
temprary table. The call-back function must at each call must return
|
||||
the number of the field that used as next component of this key
|
||||
The function adds a new key to the table that is assumed to be a temporary
|
||||
table. At each its invocation the call-back function must return
|
||||
the number of the field that is used as the next component of this key.
|
||||
|
||||
@return FALSE is a success
|
||||
@return TRUE if a failure
|
||||
|
||||
*/
|
||||
|
||||
bool TABLE::add_tmp_key(uint key, uint key_parts,
|
||||
@ -5326,6 +5354,31 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
@brief
|
||||
Drop all indexes except specified one.
|
||||
|
||||
@param key_to_save the key to save
|
||||
|
||||
@details
|
||||
Drop all indexes on this table except 'key_to_save'. The saved key becomes
|
||||
key #0. Memory occupied by key parts of dropped keys are freed.
|
||||
If the 'key_to_save' is negative then all keys are freed.
|
||||
*/
|
||||
|
||||
void TABLE::use_index(int key_to_save)
|
||||
{
|
||||
uint i= 1;
|
||||
DBUG_ASSERT(!created && key_to_save < (int)s->keys);
|
||||
if (key_to_save >= 0)
|
||||
/* Save the given key. */
|
||||
memcpy(key_info, key_info + key_to_save, sizeof(KEY));
|
||||
else
|
||||
/* Drop all keys; */
|
||||
i= 0;
|
||||
|
||||
s->keys= (key_to_save < 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Check if this is part of a MERGE table with attached children.
|
||||
@ -5388,6 +5441,7 @@ void TABLE_LIST::reinit_before_use(THD *thd)
|
||||
parent_embedding->nested_join->join_list.head() == embedded);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return subselect that contains the FROM list this table is taken from
|
||||
|
||||
@ -5659,6 +5713,296 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
@brief Reset const_table flag
|
||||
|
||||
@detail
|
||||
Reset const_table flag for this table. If this table is a merged derived
|
||||
table/view the flag is recursively reseted for all tables of the underlying
|
||||
select.
|
||||
*/
|
||||
|
||||
void TABLE_LIST::reset_const_table()
|
||||
{
|
||||
table->const_table= 0;
|
||||
if (is_merged_derived())
|
||||
{
|
||||
SELECT_LEX *select_lex= get_unit()->first_select();
|
||||
TABLE_LIST *tl;
|
||||
List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
|
||||
while ((tl= ti++))
|
||||
tl->reset_const_table();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@brief Run derived tables/view handling phases on underlying select_lex.
|
||||
|
||||
@param lex LEX for this thread
|
||||
@param phases derived tables/views handling phases to run
|
||||
(set of DT_XXX constants)
|
||||
@details
|
||||
This function runs this derived table through specified 'phases'.
|
||||
Underlying tables of this select are handled prior to this derived.
|
||||
'lex' is passed as an argument to called functions.
|
||||
|
||||
@return TRUE on error
|
||||
@return FALSE ok
|
||||
*/
|
||||
|
||||
bool TABLE_LIST::handle_derived(struct st_lex *lex, uint phases)
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= get_unit();
|
||||
if (unit)
|
||||
{
|
||||
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
|
||||
if (sl->handle_derived(lex, phases))
|
||||
return TRUE;
|
||||
return mysql_handle_single_derived(lex, this, phases);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Return unit of this derived table/view
|
||||
|
||||
@return reference to a unit if it's a derived table/view.
|
||||
@return 0 when it's not a derived table/view.
|
||||
*/
|
||||
|
||||
st_select_lex_unit *TABLE_LIST::get_unit()
|
||||
{
|
||||
return (view ? &view->unit : derived);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Return select_lex of this derived table/view
|
||||
|
||||
@return select_lex of this derived table/view.
|
||||
@return 0 when it's not a derived table.
|
||||
*/
|
||||
|
||||
st_select_lex *TABLE_LIST::get_single_select()
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= get_unit();
|
||||
return (unit ? unit->first_select() : 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Attach a join table list as a nested join to this TABLE_LIST.
|
||||
|
||||
@param join_list join table list to attach
|
||||
|
||||
@details
|
||||
This function wraps 'join_list' into a nested_join of this table, thus
|
||||
turning it to a nested join leaf.
|
||||
*/
|
||||
|
||||
void TABLE_LIST::wrap_into_nested_join(List<TABLE_LIST> &join_list)
|
||||
{
|
||||
TABLE_LIST *tl;
|
||||
/*
|
||||
Walk through derived table top list and set 'embedding' to point to
|
||||
the nesting table.
|
||||
*/
|
||||
nested_join->join_list.empty();
|
||||
List_iterator_fast<TABLE_LIST> li(join_list);
|
||||
nested_join->join_list= join_list;
|
||||
while ((tl= li++))
|
||||
{
|
||||
tl->embedding= this;
|
||||
tl->join_list= &nested_join->join_list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Initialize this derived table/view
|
||||
|
||||
@param thd Thread handle
|
||||
|
||||
@details
|
||||
This function makes initial preparations of this derived table/view for
|
||||
further processing:
|
||||
if it's a derived table this function marks it either as mergeable or
|
||||
materializable
|
||||
creates temporary table for name resolution purposes
|
||||
creates field translation for mergeable derived table/view
|
||||
|
||||
@return TRUE an error occur
|
||||
@return FALSE ok
|
||||
*/
|
||||
|
||||
bool TABLE_LIST::init_derived(THD *thd, bool init_view)
|
||||
{
|
||||
SELECT_LEX *first_select= get_single_select();
|
||||
SELECT_LEX_UNIT *unit= get_unit();
|
||||
|
||||
if (!unit)
|
||||
return FALSE;
|
||||
/*
|
||||
Check whether we can merge this derived table into main select.
|
||||
Depending on the result field translation will or will not
|
||||
be created.
|
||||
*/
|
||||
TABLE_LIST *first_table= (TABLE_LIST *) first_select->table_list.first;
|
||||
if (first_select->table_list.elements > 1 ||
|
||||
(first_table && first_table->is_multitable()))
|
||||
set_multitable();
|
||||
|
||||
unit->derived= this;
|
||||
if (init_view && !view)
|
||||
{
|
||||
/* This is all what we can do for a derived table for now. */
|
||||
set_derived();
|
||||
}
|
||||
|
||||
if (!is_view())
|
||||
{
|
||||
/* A subquery might be forced to be materialized due to a side-effect. */
|
||||
if (!is_materialized_derived() && first_select->is_mergeable() &&
|
||||
!(thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
|
||||
thd->lex->sql_command == SQLCOM_UPDATE))
|
||||
set_merged_derived();
|
||||
else
|
||||
set_materialized_derived();
|
||||
}
|
||||
/*
|
||||
Derived tables/view are materialized prior to UPDATE, thus we can skip
|
||||
them from table uniqueness check
|
||||
*/
|
||||
if (is_materialized_derived())
|
||||
{
|
||||
unit->master_unit()->set_unique_exclude();
|
||||
}
|
||||
/*
|
||||
Create field translation for mergeable derived tables/views.
|
||||
For derived tables field translation can be created only after
|
||||
unit is prepared so all '*' are get unrolled.
|
||||
*/
|
||||
if (is_merged_derived())
|
||||
{
|
||||
if (is_view() || unit->prepared)
|
||||
create_field_translation(thd);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Retrieve number of rows in the table
|
||||
|
||||
@details
|
||||
Retrieve number of rows in the table referred by this TABLE_LIST and
|
||||
store it in the table's stats.records variable. If this TABLE_LIST refers
|
||||
to a materialized derived table/view then the estimated number of rows of
|
||||
the derived table/view is used instead.
|
||||
|
||||
@return 0 ok
|
||||
@return non zero error
|
||||
*/
|
||||
|
||||
int TABLE_LIST::fetch_number_of_rows()
|
||||
{
|
||||
int error= 0;
|
||||
if (is_materialized_derived() && !fill_me)
|
||||
|
||||
{
|
||||
table->file->stats.records= ((select_union*)derived->result)->records;
|
||||
set_if_bigger(table->file->stats.records, 2);
|
||||
}
|
||||
else
|
||||
error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
Procedure of keys generation for result tables of materialized derived
|
||||
tables/views.
|
||||
|
||||
A key is generated for each equi-join pair derived table-another table.
|
||||
Each generated key consists of fields of derived table used in equi-join.
|
||||
Example:
|
||||
|
||||
SELECT * FROM (SELECT * FROM t1 GROUP BY 1) tt JOIN
|
||||
t1 ON tt.f1=t1.f3 and tt.f2.=t1.f4;
|
||||
In this case for the derived table tt one key will be generated. It will
|
||||
consist of two parts f1 and f2.
|
||||
Example:
|
||||
|
||||
SELECT * FROM (SELECT * FROM t1 GROUP BY 1) tt JOIN
|
||||
t1 ON tt.f1=t1.f3 JOIN
|
||||
t2 ON tt.f2=t2.f4;
|
||||
In this case for the derived table tt two keys will be generated.
|
||||
One key over f1 field, and another key over f2 field.
|
||||
Currently optimizer may choose to use only one such key, thus the second
|
||||
one will be dropped after range optimizer is finished.
|
||||
See also JOIN::drop_unused_derived_keys function.
|
||||
Example:
|
||||
|
||||
SELECT * FROM (SELECT * FROM t1 GROUP BY 1) tt JOIN
|
||||
t1 ON tt.f1=a_function(t1.f3);
|
||||
In this case for the derived table tt one key will be generated. It will
|
||||
consist of one field - f1.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@brief
|
||||
Change references to underlying items of a merged derived table/view
|
||||
for fields in derived table's result table.
|
||||
|
||||
@return FALSE ok
|
||||
@return TRUE Out of memory
|
||||
*/
|
||||
bool TABLE_LIST::change_refs_to_fields()
|
||||
{
|
||||
List_iterator<Item> li(used_items);
|
||||
Item_direct_ref *ref;
|
||||
Field_iterator_view field_it;
|
||||
THD *thd= table->in_use;
|
||||
DBUG_ASSERT(is_merged_derived());
|
||||
|
||||
if (!used_items.elements)
|
||||
return FALSE;
|
||||
|
||||
materialized_items= (Item**)thd->calloc(sizeof(void*) * table->s->fields);
|
||||
|
||||
while ((ref= (Item_direct_ref*)li++))
|
||||
{
|
||||
uint idx;
|
||||
Item *orig_item= *ref->ref;
|
||||
field_it.set(this);
|
||||
for (idx= 0; !field_it.end_of_fields(); field_it.next(), idx++)
|
||||
{
|
||||
if (field_it.item() == orig_item)
|
||||
break;
|
||||
}
|
||||
DBUG_ASSERT(!field_it.end_of_fields());
|
||||
if (!materialized_items[idx])
|
||||
{
|
||||
materialized_items[idx]= new Item_field(table->field[idx]);
|
||||
if (!materialized_items[idx])
|
||||
return TRUE;
|
||||
}
|
||||
ref->ref= materialized_items + idx;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Instansiate templates
|
||||
*****************************************************************************/
|
||||
|
Reference in New Issue
Block a user