diff options
Diffstat (limited to 'sql/sql_view.cc')
-rw-r--r-- | sql/sql_view.cc | 110 |
1 files changed, 78 insertions, 32 deletions
diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1b51786fd63..ca9faddb07a 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -485,17 +485,24 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, { /* TODO: change here when we will support UNIONs */ for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first; - tbl; - tbl= tbl->next_local) + tbl; + tbl= tbl->next_local) { if ((tbl->view && !tbl->updatable_view) || tbl->schema_table) + view->updatable_view= 0; + break; + } + for (TABLE_LIST *up= tbl; up; up= up->embedding) { - view->updatable_view= 0; - break; + if (up->outer_join) + { + view->updatable_view= 0; + goto loop_out; + } } } } - +loop_out: /* Check that table of main select do not used in subqueries. @@ -561,6 +568,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) SELECT_LEX *end; THD *thd= current_thd; LEX *old_lex= thd->lex, *lex; + SELECT_LEX *view_select; int res= 0; /* @@ -603,7 +611,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) */ table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; lex_start(thd, (uchar*)table->query.str, table->query.length); - lex->select_lex.select_number= ++thd->select_number; + view_select= &lex->select_lex; + view_select->select_number= ++thd->select_number; old_lex->derived_tables|= DERIVED_VIEW; { ulong options= thd->options; @@ -646,6 +655,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table); TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables_tail= 0; + TABLE_LIST *tbl; if (lex->spfuns.records) { @@ -704,7 +714,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query && lex->safe_to_cache_query); /* move SQL_CACHE to whole query */ - if (lex->select_lex.options & OPTION_TO_QUERY_CACHE) + if (view_select->options & OPTION_TO_QUERY_CACHE) old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE; /* @@ -741,9 +751,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) old_lex->can_use_merged()) && !old_lex->can_not_use_merged()) { - /* - TODO: support multi tables substitutions - */ /* lex should contain at least one table */ DBUG_ASSERT(view_tables != 0); @@ -753,20 +760,48 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->effective_with_check= (uint8)table->with_check; table->ancestor= view_tables; - /* - next table should include SELECT_LEX under this table SELECT_LEX - TODO: here should be loop for multi tables substitution - */ + /* next table should include SELECT_LEX under this table SELECT_LEX */ table->ancestor->select_lex= table->select_lex; + /* - move lock type (TODO: should we issue error in case of TMPTABLE - algorithm and non-read locking)? + Process upper level tables of view. As far as we do noy suport union + here we can go through local tables of view most upper SELECT */ - view_tables->lock_type= table->lock_type; + for(tbl= (TABLE_LIST*)view_select->table_list.first; + tbl; + tbl= tbl->next_local) + { + /* + move lock type (TODO: should we issue error in case of TMPTABLE + algorithm and non-read locking)? + */ + tbl->lock_type= table->lock_type; + } + + /* multi table view */ + if (view_tables->next_local) + { + /* make nested join structure for view tables */ + NESTED_JOIN *nested_join; + if (!(nested_join= table->nested_join= + (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN)))) + goto err; + nested_join->join_list= view_select->top_join_list; + + /* re-nest tables of VIEW */ + { + List_iterator_fast<TABLE_LIST> ti(nested_join->join_list); + while(tbl= ti++) + { + tbl->join_list= &nested_join->join_list; + tbl->embedding= table; + } + } + } /* Store WHERE clause for post-processing in setup_ancestor */ - table->where= lex->select_lex.where; + table->where= view_select->where; /* Add subqueries units to SELECT in which we merging current view. @@ -793,13 +828,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE; DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE")); - lex->select_lex.linkage= DERIVED_TABLE_TYPE; + view_select->linkage= DERIVED_TABLE_TYPE; table->updatable= 0; table->effective_with_check= VIEW_CHECK_NONE; /* SELECT tree link */ lex->unit.include_down(table->select_lex); - lex->unit.slave= &lex->select_lex; // fix include_down initialisation + lex->unit.slave= view_select; // fix include_down initialisation table->derived= &lex->unit; } @@ -810,7 +845,7 @@ ok: if (arena) thd->restore_backup_item_arena(arena, &backup); /* global SELECT list linking */ - end= &lex->select_lex; // primary SELECT_LEX is always last + end= view_select; // primary SELECT_LEX is always last end->link_next= old_lex->all_selects_list; old_lex->all_selects_list->link_prev= &end->link_next; old_lex->all_selects_list= lex->all_selects_list; @@ -946,24 +981,26 @@ frm_type_enum mysql_frm_type(char *path) bool check_key_in_view(THD *thd, TABLE_LIST *view) { TABLE *table; - Item **trans; + Field_translator *trans; KEY *key_info, *key_info_end; uint i, elements_in_view; DBUG_ENTER("check_key_in_view"); /* - we do not support updatable UNIONs in VIW, so we can check just limit of + we do not support updatable UNIONs in VIEW, so we can check just limit of LEX::select_lex */ - if (!view->view || thd->lex->sql_command == SQLCOM_INSERT || + if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT || thd->lex->select_lex.select_limit == HA_POS_ERROR) DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */ table= view->table; + if (view->belong_to_view) + view= view->belong_to_view; trans= view->field_translation; key_info_end= (key_info= table->key_info)+ table->keys; elements_in_view= view->view->select_lex.item_list.elements; - DBUG_ASSERT(view->table != 0 && view->field_translation != 0); + DBUG_ASSERT(table != 0 && view->field_translation != 0); /* Loop over all keys to see if a unique-not-null key is used */ for (;key_info != key_info_end ; key_info++) @@ -980,7 +1017,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) for (k= 0; k < elements_in_view; k++) { Item_field *field; - if ((field= trans[k]->filed_for_view_update()) && + if ((field= trans[k].item->filed_for_view_update()) && field->field == key_part->field) break; } @@ -1001,7 +1038,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) for (i= 0; i < elements_in_view; i++) { Item_field *field; - if ((field= trans[i]->filed_for_view_update()) && + if ((field= trans[i].item->filed_for_view_update()) && field->field == *field_ptr) break; } @@ -1035,24 +1072,33 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) insert_view_fields() list list for insertion view view for processing + + RETURN + 0 - OK + -1 - error (is not sent to cliet) */ -void insert_view_fields(List<Item> *list, TABLE_LIST *view) +int insert_view_fields(List<Item> *list, TABLE_LIST *view) { uint elements_in_view= view->view->select_lex.item_list.elements; - Item **trans; + Field_translator *trans; DBUG_ENTER("insert_view_fields"); if (!(trans= view->field_translation)) - DBUG_VOID_RETURN; + DBUG_RETURN(0); for (uint i= 0; i < elements_in_view; i++) { Item_field *fld; - if ((fld= trans[i]->filed_for_view_update())) + if ((fld= trans[i].item->filed_for_view_update())) list->push_back(fld); + else + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT"); + DBUG_RETURN(-1); + } } - DBUG_VOID_RETURN; + DBUG_RETURN(0); } /* |