diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 479 |
1 files changed, 229 insertions, 250 deletions
diff --git a/sql/table.cc b/sql/table.cc index 4ddaeeea248..bbf34ae2c25 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -595,6 +595,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, } reg_field->fieldnr= i+1; //Set field number + reg_field->field_index= i; reg_field->comment=comment; if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) { @@ -746,8 +747,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, error. */ keyinfo->key_length-= (key_part->length - field->key_length()); - key_part->store_length-= (key_part->length - field->key_length()); - key_part->length= field->key_length(); + key_part->store_length-= (uint16)(key_part->length - + field->key_length()); + key_part->length= (uint16)field->key_length(); sql_print_error("Found wrong key definition in %s; Please do \"ALTER TABLE '%s' FORCE \" to fix it!", name, share->table_name); push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_CRASHED_ON_USAGE, @@ -1716,8 +1718,6 @@ void st_table_list::set_ancestor() } if (tbl->multitable_view) multitable_view= TRUE; - if (tbl->table) - tbl->table->grant= grant; } while ((tbl= tbl->next_local)); if (!multitable_view) @@ -1730,68 +1730,18 @@ void st_table_list::set_ancestor() /* - Save old want_privilege and clear want_privilege - - SYNOPSIS - save_and_clear_want_privilege() -*/ - -void st_table_list::save_and_clear_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - { - privilege_backup= tbl->table->grant.want_privilege; - tbl->table->grant.want_privilege= 0; - } - else - { - tbl->save_and_clear_want_privilege(); - } - } -} - - -/* - restore want_privilege saved by save_and_clear_want_privilege - - SYNOPSIS - restore_want_privilege() -*/ - -void st_table_list::restore_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - tbl->table->grant.want_privilege= privilege_backup; - else - { - tbl->restore_want_privilege(); - } - } -} - - -/* setup fields of placeholder of merged VIEW SYNOPSIS st_table_list::setup_ancestor() thd - thread handler - conds - condition of this JOIN - check_opt_type - WHITH CHECK OPTION type (VIEW_CHECK_NONE, - VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + NOTES ancestor is list of tables and views used by view (underlying tables/views) DESCRIPTION It is: - - preparing translation table for view columns (fix_fields() for every - call and creation for first call) - - preparing WHERE, ON and CHECK OPTION condition (fix_fields() for every - call and merging for first call). + - preparing translation table for view columns If there are underlying view(s) procedure first will be called for them. RETURN @@ -1799,163 +1749,114 @@ void st_table_list::restore_want_privilege() TRUE - error */ -bool st_table_list::setup_ancestor(THD *thd, Item **conds, - uint8 check_opt_type) +bool st_table_list::setup_ancestor(THD *thd) { - Field_translator *transl; - SELECT_LEX *select= &view->select_lex; - SELECT_LEX *current_select_save= thd->lex->current_select; - byte *main_table_list_save= select_lex->table_list.first; - Item *item; - TABLE_LIST *tbl; - List_iterator_fast<Item> it(select->item_list); - uint i= 0; - enum sub_select_type linkage_save= - select_lex->master_unit()->first_select()->linkage; - bool save_set_query_id= thd->set_query_id; - bool save_wrapper= select_lex->no_wrap_view_item; - bool save_allow_sum_func= thd->allow_sum_func; - bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - - if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&res)) - return TRUE; - - for (tbl= ancestor; tbl; tbl= tbl->next_local) + if (!field_translation) { - if (tbl->ancestor && - tbl->setup_ancestor(thd, conds, - (check_opt_type == VIEW_CHECK_CASCADED ? - VIEW_CHECK_CASCADED : - VIEW_CHECK_NONE))) + 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, (char *)&field_count)) + { DBUG_RETURN(TRUE); - } + } - /* - We have to ensure that inside the view we are not referring to any - table outside of the view. We do it by changing the pointers used - by fix_fields to look up tables so that only tables and views in - view are seen. We also set linkage to DERIVED_TABLE_TYPE as a barrier - so that we stop resolving fields as this level. - */ - thd->lex->current_select= select_lex; - select_lex->table_list.first= (byte *)ancestor; - select_lex->master_unit()->first_select()->linkage= DERIVED_TABLE_TYPE; + for (tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->ancestor && + tbl->setup_ancestor(thd)) + { + DBUG_RETURN(TRUE); + } + } - if (field_translation) - { - DBUG_PRINT("info", ("there are already translation table")); - - select_lex->no_wrap_view_item= 1; - - thd->set_query_id= 1; - /* this view was prepared already on previous PS/SP execution */ - Field_translator *end= field_translation + select->item_list.elements; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - for (transl= field_translation; transl < end; transl++) + /* Create view fields translation table */ + + if (!(transl= + (Field_translator*)(thd->current_arena-> + alloc(select->item_list.elements * + sizeof(Field_translator))))) { - if (!transl->item->fixed && - transl->item->fix_fields(thd, ancestor, &transl->item)) - goto err; + DBUG_RETURN(TRUE); } - for (tbl= ancestor; tbl; tbl= tbl->next_local) + + while ((item= it++)) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + transl[field_count].name= item->name; + transl[field_count++].item= item; } - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, ancestor, &check_option)) - goto err; - restore_want_privilege(); + field_translation= transl; + field_translation_end= transl + field_count; + /* TODO: use hash for big number of fields */ - /* WHERE/ON resolved => we can rename fields */ - for (transl= field_translation; transl < end; transl++) + /* full text function moving to current select */ + if (view->select_lex.ftfunc_list->elements) { - transl->item->rename((char *)transl->name); + Item_func_match *ifm; + SELECT_LEX *current_select= thd->lex->current_select; + List_iterator_fast<Item_func_match> + li(*(view->select_lex.ftfunc_list)); + while ((ifm= li++)) + current_select->ftfunc_list->push_front(ifm); } - goto ok; } + DBUG_RETURN(FALSE); +} - /* Create view fields translation table */ - if (!(transl= - (Field_translator*)(thd->current_arena-> - alloc(select->item_list.elements * - sizeof(Field_translator))))) - { - res= TRUE; - goto ok; // Restore thd - } +/* + Prepare where expression of view - select_lex->no_wrap_view_item= 1; + SYNOPSIS + st_table_list::prep_where() + thd - thread handler + conds - condition of this JOIN + no_where_clause - do not build WHERE or ON outer qwery do not need it + (it is INSERT), we do not need conds if this flag is set - /* - Resolve all view items against ancestor table. + NOTE: have to be called befor CHECK OPTION preparation, because it makes + fix_fields for view WHERE clause - TODO: do it only for real used fields "on demand" to mark really - used fields correctly. - */ - thd->set_query_id= 1; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - while ((item= it++)) - { - /* save original name of view column */ - char *name= item->name; - transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item)) - goto err; - /* set new item get in fix fields and original column name */ - transl[i++].name= name; - } - field_translation= transl; - /* TODO: sort this list? Use hash for big number of fields */ + RETURN + FALSE - OK + TRUE - error +*/ - for (tbl= ancestor; tbl; tbl= tbl->next_local) +bool st_table_list::prep_where(THD *thd, Item **conds, + bool no_where_clause) +{ + DBUG_ENTER("st_table_list::prep_where"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + if (tbl->view && tbl->prep_where(thd, conds, no_where_clause)) + { + DBUG_RETURN(TRUE); + } } - if (where || - (check_opt_type == VIEW_CHECK_CASCADED && - ancestor->check_option)) - { - Query_arena *arena= thd->current_arena, backup; - TABLE_LIST *tbl= this; - if (arena->is_conventional()) - arena= 0; // For easier test - - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - - if (arena) - thd->set_n_backup_item_arena(arena, &backup); - if (check_opt_type) + if (where) + { + if (!where->fixed && where->fix_fields(thd, &where)) { - if (where) - check_option= where->copy_andor_structure(thd); - if (check_opt_type == VIEW_CHECK_CASCADED) - { - check_option= and_conds(check_option, ancestor->check_option); - } + DBUG_RETURN(TRUE); } /* check that it is not VIEW in which we insert with INSERT SELECT (in this case we can't add view WHERE condition to main SELECT_LEX) */ - if (where && !no_where_clause) + if (!no_where_clause && !where_processed) { + TABLE_LIST *tbl= this; + Query_arena *arena= thd->current_arena, backup; + arena= thd->change_arena_if_needed(&backup); // For easier test + /* Go up to join tree and try to find left join */ for (; tbl; tbl= tbl->embedding) { @@ -1972,72 +1873,107 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, } } if (tbl == 0) - { - if (outer_join) - { - /* - Store WHERE condition to ON expression for outer join, because - we can't use WHERE to correctly execute left joins on VIEWs and - this expression will not be moved to WHERE condition (i.e. will - be clean correctly for PS/SP) - */ - on_expr= and_conds(on_expr, where); - } - else - { - /* - It is conds of JOIN, but it will be stored in - st_select_lex::prep_where for next reexecution - */ - *conds= and_conds(*conds, where); - } - } + *conds= and_conds(*conds, where); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + where_processed= TRUE; } - - if (arena) - thd->restore_backup_item_arena(arena, &backup); } - restore_want_privilege(); - /* - fix_fields do not need tables, because new are only AND operation and we - just need recollect statistics - */ - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, 0, &check_option)) - goto err; + DBUG_RETURN(FALSE); +} + + +/* + Prepare check option expression of table + + SYNOPSIS + st_table_list::prep_check_option() + thd - thread handler + check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE, + VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + we use this parameter instead of direct check of + effective_with_check to change type of underlying + views to VIEW_CHECK_CASCADED if outer view have + such option and prevent processing of underlying + view check options if outer view have just + VIEW_CHECK_LOCAL option. + + NOTE + This method build check options for every call + (usual execution or every SP/PS call) + This method have to be called after WHERE preparation + (st_table_list::prep_where) - /* WHERE/ON resolved => we can rename fields */ + RETURN + FALSE - OK + TRUE - error +*/ + +bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type) +{ + DBUG_ENTER("st_table_list::prep_check_option"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - Field_translator *end= field_translation + select->item_list.elements; - for (transl= field_translation; transl < end; transl++) + /* see comment of check_opt_type parameter */ + if (tbl->view && + tbl->prep_check_option(thd, + ((check_opt_type == VIEW_CHECK_CASCADED) ? + VIEW_CHECK_CASCADED : + VIEW_CHECK_NONE))) { - transl->item->rename((char *)transl->name); + DBUG_RETURN(TRUE); } } - /* full text function moving to current select */ - if (view->select_lex.ftfunc_list->elements) + if (check_opt_type) { - Query_arena *arena= thd->current_arena, backup; - if (arena->is_conventional()) - arena= 0; // For easier test - else - thd->set_n_backup_item_arena(arena, &backup); - - Item_func_match *ifm; - List_iterator_fast<Item_func_match> - li(*(view->select_lex.ftfunc_list)); - while ((ifm= li++)) - current_select_save->ftfunc_list->push_front(ifm); - if (arena) - thd->restore_backup_item_arena(arena, &backup); + Item *item= 0; + if (where) + { + DBUG_ASSERT(where->fixed); + item= where->copy_andor_structure(thd); + } + if (check_opt_type == VIEW_CHECK_CASCADED) + { + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->check_option) + item= and_conds(item, tbl->check_option); + } + } + if (item) + thd->change_item_tree(&check_option, item); + } + + if (check_option) + { + const char *save_where= thd->where; + thd->where= "check option"; + if (!check_option->fixed && + check_option->fix_fields(thd, &check_option) || + check_option->check_cols(1)) + { + DBUG_RETURN(TRUE); + } + thd->where= save_where; } + DBUG_RETURN(FALSE); +} + - goto ok; +/* + Hide errors which show view underlying table information + + SYNOPSIS + st_table_list::hide_view_error() + thd thread handler -err: - res= TRUE; +*/ + +void st_table_list::hide_view_error(THD *thd) +{ /* Hide "Unknown column" or "Unknown function" error */ if (thd->net.last_errno == ER_BAD_FIELD_ERROR || thd->net.last_errno == ER_SP_DOES_NOT_EXIST) @@ -2045,15 +1981,12 @@ err: thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str); } - -ok: - select_lex->no_wrap_view_item= save_wrapper; - thd->lex->current_select= current_select_save; - select_lex->table_list.first= main_table_list_save; - select_lex->master_unit()->first_select()->linkage= linkage_save; - thd->set_query_id= save_set_query_id; - thd->allow_sum_func= save_allow_sum_func; - DBUG_RETURN(res); + else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD) + { + thd->clear_error(); + // TODO: make correct error message + my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str); + } } @@ -2097,9 +2030,9 @@ void st_table_list::cleanup_items() if (!field_translation) return; - Field_translator *end= (field_translation + - view->select_lex.item_list.elements); - for (Field_translator *transl= field_translation; transl < end; transl++) + for (Field_translator *transl= field_translation; + transl < field_translation_end; + transl++) transl->item->walk(&Item::cleanup_processor, 0); } @@ -2212,8 +2145,9 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) void Field_iterator_view::set(TABLE_LIST *table) { + view= table; ptr= table->field_translation; - array_end= ptr + table->view->select_lex.item_list.elements; + array_end= table->field_translation_end; } @@ -2223,9 +2157,9 @@ const char *Field_iterator_table::name() } -Item *Field_iterator_table::item(THD *thd) +Item *Field_iterator_table::create_item(THD *thd) { - return new Item_field(thd, *ptr); + return new Item_field(thd, &thd->lex->current_select->context, *ptr); } @@ -2235,6 +2169,51 @@ const char *Field_iterator_view::name() } +Item *Field_iterator_view::create_item(THD *thd) +{ + return create_view_field(thd, view, &ptr->item, ptr->name); +} + +Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, + const char *name) +{ + bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + Item *field= *field_ref; + DBUG_ENTER("create_view_field"); + + if (view->schema_table_reformed) + { + /* + In case of SHOW command (schema_table_reformed set) all items are + fixed + */ + DBUG_ASSERT(field && field->fixed); + DBUG_RETURN(field); + } + + DBUG_ASSERT(field); + thd->lex->current_select->no_wrap_view_item= TRUE; + if (!field->fixed) + { + if (field->fix_fields(thd, field_ref)) + { + thd->lex->current_select->no_wrap_view_item= save_wrapper; + DBUG_RETURN(0); + } + field= *field_ref; + } + thd->lex->current_select->no_wrap_view_item= save_wrapper; + if (thd->lex->current_select->no_wrap_view_item) + { + DBUG_RETURN(field); + } + Item *item= new Item_direct_view_ref(&view->view->select_lex.context, + field_ref, view->view_name.str, + name); + DBUG_RETURN(item); +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ |