1
0
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:
Igor Babaev
2011-06-04 19:56:06 -07:00
99 changed files with 4331 additions and 1089 deletions

View File

@ -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
*****************************************************************************/