From 55a8c28c27778d018a145ce25e61bdcda7a764a5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Sep 2004 19:28:29 +0300 Subject: [PATCH 01/48] fixed merged view fields names (BUG#5147) support of merged VIEW over several tables added (WL#1809) mysql-test/r/view.result: merge of VIEW with several tables mysql-test/t/view.test: merge of VIEW with several tables sql/item.cc: renaming Item and restoring item name on cleunup() sql/item.h: renaming Item and restoring item name on cleunup() debug output added sql/item_cmpfunc.h: setup_conds() changed to support two tables lists sql/item_subselect.cc: list of table leaves used instead of local table list for name resolving sql/mysql_priv.h: setup_conds() and setup_tables() changed to support two tables lists sql/opt_sum.cc: list of table leaves used instead of local table list for name resolving sql/sp.cc: setup_tables() changed to support two tables lists sql/sql_base.cc: skip temporary tables in table finding fixed merged view fields names (BUG#5147) sql/sql_delete.cc: setup_conds() and setup_tables() changed to support two tables lists sql/sql_help.cc: setup_tables() changed to support two tables lists sql/sql_insert.cc: setup_tables() changed to support two tables lists name handling support sql/sql_lex.cc: allow view with several tables for MERGE sql/sql_lex.h: new table list sql/sql_load.cc: setup_tables() changed to support two tables lists sql/sql_olap.cc: setup_tables() changed to support two tables lists sql/sql_parse.cc: new list support sql/sql_prepare.cc: new list support sql/sql_select.cc: list of table leaves used instead of local table list for name resolving sql/sql_update.cc: setup_conds() and setup_tables() changed to support two tables lists sql/sql_view.cc: support of MERGED VIEWS with several tables sql/sql_yacc.yy: removed blanks in new code sql/table.cc: fixed setup view code support of merged VIEW over several tables added sql/table.h: fixed merged view fields names (BUG#5147) --- mysql-test/r/view.result | 52 +++++++++- mysql-test/t/view.test | 29 +++++- sql/item.cc | 34 ++++++- sql/item.h | 27 ++++- sql/item_cmpfunc.h | 3 +- sql/item_subselect.cc | 7 +- sql/mysql_priv.h | 6 +- sql/opt_sum.cc | 10 +- sql/sp.cc | 3 +- sql/sql_base.cc | 212 +++++++++++++++++++++++++++++---------- sql/sql_delete.cc | 7 +- sql/sql_help.cc | 3 +- sql/sql_insert.cc | 20 ++-- sql/sql_lex.cc | 4 +- sql/sql_lex.h | 3 + sql/sql_load.cc | 3 +- sql/sql_olap.cc | 2 +- sql/sql_parse.cc | 2 +- sql/sql_prepare.cc | 7 ++ sql/sql_select.cc | 44 +++++--- sql/sql_update.cc | 35 ++++--- sql/sql_view.cc | 91 ++++++++++++----- sql/sql_yacc.yy | 12 +-- sql/table.cc | 147 +++++++++++++++++++++------ sql/table.h | 18 +++- 25 files changed, 599 insertions(+), 182 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 2551977200e..c1462bf8c74 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -877,7 +877,7 @@ insert into t1 values (1), (2), (3), (200); create view v1 (x) as select a from t1 where a > 1; create view v2 (y) as select x from v1 where x < 100; select * from v2; -x +y 2 3 drop table t1; @@ -1310,4 +1310,52 @@ a a a 3 2 3 3 3 3 drop view v1; -drop table t1; +drop table t1,t2; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +insert into t1 values (1), (2), (3); +insert into t2 values (1), (3); +insert into t3 values (1), (2), (4); +create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a); +select * from t3 left join v3 on (t3.a = v3.a); +a a b +1 1 1 +2 2 NULL +4 NULL NULL +explain extended select * from t3 left join v3 on (t3.a = v3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join `test`.`t2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1 +create view v1 (a) as select a from t1; +create view v2 (a) as select a from t2; +create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a); +select * from t3 left join v4 on (t3.a = v4.a); +a a b +1 1 1 +2 2 NULL +4 NULL NULL +explain extended select * from t3 left join v4 on (t3.a = v4.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`v1` left join `test`.`v2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1 +prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);"; +execute stmt1; +a a b +1 1 1 +2 2 NULL +4 NULL NULL +execute stmt1; +a a b +1 1 1 +2 2 NULL +4 NULL NULL +deallocate prepare stmt1; +drop view v4,v3,v2,v1; +drop tables t1,t2,t3; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 682646a6c02..9dbb0facf40 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1270,4 +1270,31 @@ create view v1 as select a from t1 where a > 1; select * from t1 left join (t2 as t, v1) on v1.a=t1.a; select * from t1 left join (t2 as t, t2) on t2.a=t1.a; drop view v1; -drop table t1; +drop table t1,t2; + +# +# merge of VIEW with several tables +# +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +insert into t1 values (1), (2), (3); +insert into t2 values (1), (3); +insert into t3 values (1), (2), (4); +# view over tables +create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a); +select * from t3 left join v3 on (t3.a = v3.a); +explain extended select * from t3 left join v3 on (t3.a = v3.a); +# view over views +create view v1 (a) as select a from t1; +create view v2 (a) as select a from t2; +create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a); +select * from t3 left join v4 on (t3.a = v4.a); +explain extended select * from t3 left join v4 on (t3.a = v4.a); +# PS with view over views +prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; +drop view v4,v3,v2,v1; +drop tables t1,t2,t3; diff --git a/sql/item.cc b/sql/item.cc index cbb760156b3..1e8b4d8630d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -45,12 +45,11 @@ void item_init(void) } Item::Item(): - name_length(0), fixed(0) + name(0), orig_name(0), name_length(0), fixed(0) { marker= 0; maybe_null=null_value=with_sum_func=unsigned_flag=0; collation.set(default_charset(), DERIVATION_COERCIBLE); - name= 0; decimals= 0; max_length= 0; /* Put item in free list so that we can free all items at end */ @@ -80,6 +79,7 @@ Item::Item(): Item::Item(THD *thd, Item *item): str_value(item->str_value), name(item->name), + orig_name(item->orig_name), max_length(item->max_length), marker(item->marker), decimals(item->decimals), @@ -110,12 +110,35 @@ void Item::print_item_w_name(String *str) void Item::cleanup() { DBUG_ENTER("Item::cleanup"); - DBUG_PRINT("info", ("Item: 0x%lx", this)); - DBUG_PRINT("info", ("Type: %d", (int)type())); + DBUG_PRINT("info", ("Item: 0x%lx, Type: %d, name %s, original name %s", + this, (int)type(), name, orig_name)); fixed=0; + if (orig_name) + name= orig_name; DBUG_VOID_RETURN; } + +/* + rename item (used for views, cleanup() return original name) + + SYNOPSIS + Item::rename() + new_name new name of item; +*/ + +void Item::rename(char *new_name) +{ + /* + we can compare pointers to names here, bacause if name was not changed, + pointer will be same + */ + if (!orig_name && new_name != name) + orig_name= name; + name= new_name; +} + + Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par) :orig_db_name(db_name_par), orig_table_name(table_name_par), @@ -2279,6 +2302,9 @@ void Item_ref::cleanup() DBUG_ENTER("Item_ref::cleanup"); Item_ident::cleanup(); result_field= 0; + DBUG_PRINT("info", ("hook: 0x%lx(0x%lx) original item: 0x%lx", + (ulong)hook_ptr, (ulong)(hook_ptr?*hook_ptr:0), + (ulong)orig_item)); if (hook_ptr) *hook_ptr= orig_item; DBUG_VOID_RETURN; diff --git a/sql/item.h b/sql/item.h index a237e7ce6f5..8dc928574e1 100644 --- a/sql/item.h +++ b/sql/item.h @@ -115,6 +115,8 @@ public: */ String str_value; my_string name; /* Name from select */ + /* Original item name (if it was renamed)*/ + my_string orig_name; Item *next; uint32 max_length; uint name_length; /* Length of name */ @@ -142,6 +144,7 @@ public: name=0; } /*lint -e1509 */ void set_name(const char *str,uint length, CHARSET_INFO *cs); + void rename(char *new_name); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup(); virtual void make_field(Send_field *field); @@ -928,15 +931,33 @@ public: Item_ref(Item **hook, Item *original,const char *db_par, const char *table_name_par, const char *field_name_par) :Item_ident(db_par, table_name_par, field_name_par), result_field(0), - ref(0), hook_ptr(hook), orig_item(original) {} + ref(0), hook_ptr(hook), orig_item(original) + { + DBUG_ENTER("Item_ref::Item_ref (Item **, Item * ...) "); + DBUG_PRINT("info", ("hook 0x%lx, original item: 0x%lx", + hook_ptr, orig_item)); + DBUG_VOID_RETURN; + } Item_ref(Item **item, Item **hook, const char *table_name_par, const char *field_name_par) :Item_ident(NullS, table_name_par, field_name_par), result_field(0), - ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {} + ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) + { + DBUG_ENTER("Item_ref::Item_ref (Item **, Item ** ...) "); + DBUG_PRINT("info", ("hook 0x%lx, original item: 0x%lx", + hook_ptr, orig_item)); + DBUG_VOID_RETURN; + } // Constructor need to process subselect with temporary tables (see Item) Item_ref(THD *thd, Item_ref *item, Item **hook) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref), - hook_ptr(hook), orig_item(hook ? *hook : 0) {} + hook_ptr(hook), orig_item(hook ? *hook : 0) + { + DBUG_ENTER("Item_ref::Item_ref (THD*, Item_ref, ...)"); + DBUG_PRINT("info", ("hook 0x%lx, original item: 0x%lx", + hook_ptr, orig_item)); + DBUG_VOID_RETURN; + } enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const { return ref && (*ref)->eq(item, binary_cmp); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index e7bef18e629..b07dd10a5bc 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -965,7 +965,8 @@ public: void update_used_tables(); void print(String *str); void split_sum_func(Item **ref_pointer_array, List &fields); - friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); + friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, + COND **conds); void top_level_item() { abort_on_null=1; } void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, byte *arg); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 25bb2701101..5b730ab983a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1411,7 +1411,7 @@ void subselect_uniquesubquery_engine::exclude() table_map subselect_engine::calc_const_tables(TABLE_LIST *table) { table_map map= 0; - for(; table; table= table->next_local) + for(; table; table= table->next_leaf) { TABLE *tbl= table->table; if (tbl && tbl->const_table) @@ -1424,14 +1424,13 @@ table_map subselect_engine::calc_const_tables(TABLE_LIST *table) table_map subselect_single_select_engine::upper_select_const_tables() { return calc_const_tables((TABLE_LIST *) select_lex->outer_select()-> - table_list.first); + leaf_tables); } table_map subselect_union_engine::upper_select_const_tables() { - return calc_const_tables((TABLE_LIST *) unit->outer_select()-> - table_list.first); + return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 029da71c41b..a43ec6f00ed 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -764,13 +764,15 @@ bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges, bool allocate_view_names); -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds); +bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, + TABLE_LIST **leaves, bool refresh_only); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, uint wild_num); int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, List &item, bool set_query_id, List *sum_func_list, bool allow_sum_func); -int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); +int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, + COND **conds); int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_refresh(THD *thd); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 314decb7041..56d20b58072 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -59,9 +59,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond); SYNOPSIS opt_sum_query() - tables Tables in query - all_fields All fields to be returned - conds WHERE clause + tables list of leaves of join table tree + all_fields All fields to be returned + conds WHERE clause NOTE: This function is only called for queries with sum functions and no @@ -89,7 +89,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) where_tables= conds->used_tables(); /* Don't replace expression on a table that is part of an outer join */ - for (TABLE_LIST *tl= tables; tl; tl= tl->next_local) + for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf) { if (tl->on_expr) { @@ -128,7 +128,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) { longlong count= 1; TABLE_LIST *table; - for (table= tables; table; table= table->next_local) + for (table= tables; table; table= table->next_leaf) { if (outer_tables || (table->table->file->table_flags() & HA_NOT_EXACT_COUNT)) diff --git a/sql/sp.cc b/sql/sp.cc index 6475b64eb18..5b0afbf5558 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -551,6 +551,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) Item *item; List field_list; struct st_used_field *used_field; + TABLE_LIST *leaves= 0; st_used_field used_fields[array_elements(init_fields)]; memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields)); @@ -583,7 +584,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) tables is not VIEW for sure => we can pass 0 as condition */ - setup_tables(thd, &tables, 0); + setup_tables(thd, &tables, 0, &leaves, 0); for (used_field= &used_fields[0]; used_field->field_name; used_field++) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 80090ba288e..c0deeba6148 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -554,10 +554,10 @@ void close_temporary_tables(THD *thd) SYNOPSIS find_table_in_list() - table Pointer to table list + table Pointer to table list offset Offset to which list in table structure to use - db_name Data base name - table_name Table name + db_name Data base name + table_name Table name NOTES: This is called by find_table_in_local_list() and @@ -577,13 +577,14 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, { for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) { - if ((!strcmp(table->db, db_name) && - !strcmp(table->real_name, table_name)) || - (table->view && - !my_strcasecmp(table_alias_charset, - table->table->table_cache_key, db_name) && - !my_strcasecmp(table_alias_charset, - table->table->table_name, table_name))) + if (table->table->tmp_table == NO_TMP_TABLE && + ((!strcmp(table->db, db_name) && + !strcmp(table->real_name, table_name)) || + (table->view && + !my_strcasecmp(table_alias_charset, + table->table->table_cache_key, db_name) && + !my_strcasecmp(table_alias_charset, + table->table->table_name, table_name)))) break; } } @@ -591,11 +592,12 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, { for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) { - if ((!strcmp(table->db, db_name) && - !strcmp(table->real_name, table_name)) || - (table->view && - !strcmp(table->table->table_cache_key, db_name) && - !strcmp(table->table->table_name, table_name))) + if (table->table->tmp_table == NO_TMP_TABLE && + ((!strcmp(table->db, db_name) && + !strcmp(table->real_name, table_name)) || + (table->view && + !strcmp(table->table->table_cache_key, db_name) && + !strcmp(table->table->table_name, table_name)))) break; } } @@ -2005,15 +2007,18 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, bool allow_rowid, uint *cached_field_index_ptr) { + DBUG_ENTER("find_field_in_table"); + DBUG_PRINT("enter", ("table:%s name: %s item name %s, ref 0x%lx", + table_list->alias, name, item_name, (ulong)ref)); Field *fld; if (table_list->field_translation) { DBUG_ASSERT(ref != 0 && table_list->view != 0); uint num= table_list->view->select_lex.item_list.elements; - Item **trans= table_list->field_translation; + Field_translator *trans= table_list->field_translation; for (uint i= 0; i < num; i ++) { - if (strcmp(trans[i]->name, name) == 0) + if (strcmp(trans[i].name, name) == 0) { #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants_view && @@ -2021,22 +2026,22 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str, name, length)) - return WRONG_GRANT; + DBUG_RETURN(WRONG_GRANT); #endif if (thd->lex->current_select->no_wrap_view_item) - *ref= trans[i]; + *ref= trans[i].item; else { - *ref= new Item_ref(trans + i, ref, table_list->view_name.str, + *ref= new Item_ref(&trans[i].item, ref, table_list->view_name.str, item_name); /* as far as Item_ref have defined refernce it do not need tables */ if (*ref) (*ref)->fix_fields(thd, 0, ref); } - return (Field*) view_ref_found; + DBUG_RETURN((Field*) view_ref_found); } } - return 0; + DBUG_RETURN(0); } fld= find_field_in_real_table(thd, table_list->table, name, length, check_grants_table, allow_rowid, @@ -2050,10 +2055,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, table_list->view_name.str, name, length)) { - return WRONG_GRANT; + DBUG_RETURN(WRONG_GRANT); } #endif - return fld; + DBUG_RETURN(fld); } @@ -2182,17 +2187,33 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, field makes some prepared query ambiguous and so erronous, but we accept this trade off. */ - found= find_field_in_real_table(thd, item->cached_table->table, - name, length, - test(item->cached_table-> - table->grant.want_privilege) && - check_privileges, - 1, &(item->cached_field_index)); + if (item->cached_table->table) + { + found= find_field_in_real_table(thd, item->cached_table->table, + name, length, + test(item->cached_table-> + table->grant.want_privilege) && + check_privileges, + 1, &(item->cached_field_index)); + } + else + { + TABLE_LIST *table= item->cached_table; + Field *find= find_field_in_table(thd, table, name, item->name, length, + ref, + (table->table && + test(table->table->grant. + want_privilege) && + check_privileges), + (test(table->grant.want_privilege) && + check_privileges), + 1, &(item->cached_field_index)); + } if (found) { if (found == WRONG_GRANT) - return (Field*) 0; + return (Field*) 0; return found; } } @@ -2220,7 +2241,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, found_table=1; Field *find= find_field_in_table(thd, tables, name, item->name, length, ref, - (test(tables->table->grant. + (tables->table && + test(tables->table->grant. want_privilege) && check_privileges), (test(tables->grant.want_privilege) && @@ -2284,7 +2306,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Field *field= find_field_in_table(thd, tables, name, item->name, length, ref, - (test(tables->table->grant. + (tables->table && + test(tables->table->grant. want_privilege) && check_privileges), (test(tables->grant.want_privilege) && @@ -2597,7 +2620,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, if (!item->fixed && item->fix_fields(thd, tables, it.ref()) || (item= *(it.ref()))->check_cols(1)) { - select_lex->no_wrap_view_item= 0; DBUG_RETURN(-1); /* purecov: inspected */ } if (ref) @@ -2611,14 +2633,46 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, } +/* + make list of leaves of join table tree + + SYNOPSIS + make_leaves_list() + list pointer to pointer on list first element + tables table list + + RETURN pointer on pointer to next_leaf of last element +*/ + +TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) +{ + for (TABLE_LIST *table= tables; table; table= table->next_local) + { + if (table->view && !table->table) + { + /* it is for multi table views only, check it */ + DBUG_ASSERT(table->ancestor->next_local); + list= make_leaves_list(list, table->ancestor); + } + else + { + *list= table; + list= &table->next_leaf; + } + } + return list; +} + /* prepare tables SYNOPSIS setup_tables() - thd - thread handler - tables - tables list - conds - condition of current SELECT (can be changed by VIEW) + thd - thread handler + tables - tables list + conds - condition of current SELECT (can be changed by VIEW) + leaves - list of join table leaves list + refresh - it is onle refresh for subquery RETURN 0 ok; In this case *map will includes the choosed index @@ -2635,16 +2689,23 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, if tables do not contain VIEWs it is OK to pass 0 as conds */ -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds) +bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, + TABLE_LIST **leaves, bool refresh) { DBUG_ENTER("setup_tables"); if (!tables || tables->setup_is_done) DBUG_RETURN(0); tables->setup_is_done= 1; + + if (!(*leaves)) + { + make_leaves_list(leaves, tables); + } + uint tablenr=0; - for (TABLE_LIST *table_list= tables; + for (TABLE_LIST *table_list= *leaves; table_list; - table_list= table_list->next_local, tablenr++) + table_list= table_list->next_leaf, tablenr++) { TABLE *table= table_list->table; setup_table_map(table, table_list, tablenr); @@ -2666,14 +2727,22 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds) table->keys_in_use_for_query.subtract(map); } table->used_keys.intersect(table->keys_in_use_for_query); - if (table_list->ancestor && table_list->setup_ancestor(thd, conds)) - DBUG_RETURN(1); } if (tablenr > MAX_TABLES) { my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES); DBUG_RETURN(1); } + if (!refresh) + { + for (TABLE_LIST *table_list= tables; + table_list; + table_list= table_list->next_local) + { + if (table_list->ancestor && table_list->setup_ancestor(thd, conds)) + DBUG_RETURN(1); + } + } DBUG_RETURN(0); } @@ -2776,9 +2845,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, tables->alias) && (!db_name || !strcmp(tables->db,db_name)))) { + bool view; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Ensure that we have access right to all columns */ - if (!(table->grant.privilege & SELECT_ACL) && !any_privileges) + if (!((table && (table->grant.privilege & SELECT_ACL) || + tables->view && (tables->grant.privilege & SELECT_ACL))) && + !any_privileges) { if (tables->view) { @@ -2791,6 +2863,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } else { + DBUG_ASSERT(table != 0); table_iter.set(tables); if (check_grant_all_columns(thd, SELECT_ACL, &table->grant, table->table_cache_key, table->real_name, @@ -2799,8 +2872,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } } #endif + if (table) + thd->used_tables|= table->map; + else + { + view_iter.set(tables); + for (; !view_iter.end_of_fields(); view_iter.next()) + { + thd->used_tables|= view_iter.item(thd)->used_tables(); + } + } natural_join_table= 0; - thd->used_tables|= table->map; last= embedded= tables; while ((embedding= embedded->embedding) && @@ -2827,9 +2909,15 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, natural_join_table= embedding; } if (tables->field_translation) + { iterator= &view_iter; + view= 1; + } else + { iterator= &table_iter; + view= 0; + } iterator->set(tables); for (; !iterator->end_of_fields(); iterator->next()) @@ -2849,6 +2937,11 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, (void) it->replace(item); // Replace '*' else it->after(item); + if (view && !thd->lex->current_select->no_wrap_view_item) + { + item= new Item_ref(it->ref(), NULL, tables->view_name.str, + field_name); + } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (any_privileges) { @@ -2914,8 +3007,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } } - /* All fields are used */ - table->used_fields=table->fields; + /* + All fields are used in case if usual tables (in case of view used + fields merked in setu_tables during fix_fields of view columns + */ + if (table) + table->used_fields=table->fields; } } if (found) @@ -2933,10 +3030,16 @@ err: /* -** Fix all conditions and outer join expressions + Fix all conditions and outer join expressions + + SYNOPSIS + setup_conds() + thd thread handler + tables list of tables for name resolving + leaves list of leaves of join table tree */ -int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) +int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { table_map not_null_tables= 0; SELECT_LEX *select_lex= thd->lex->current_select; @@ -2960,7 +3063,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } /* Check if we are using outer joins */ - for (TABLE_LIST *table= tables; table; table= table->next_local) + for (TABLE_LIST *table= leaves; table; table= table->next_leaf) { TABLE_LIST *embedded; TABLE_LIST *embedding= table; @@ -3024,8 +3127,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) Field_iterator_view view_iter; Field_iterator *iterator; Field *t1_field, *t2_field; - Item *item_t2; - Item_cond_and *cond_and=new Item_cond_and(); + Item *item_t2= 0; + Item_cond_and *cond_and= new Item_cond_and(); if (!cond_and) // If not out of memory DBUG_RETURN(1); @@ -3061,6 +3164,13 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) t2_field->query_id= thd->query_id; t2->used_keys.intersect(t2_field->part_of_key); } + else + { + DBUG_ASSERT(t2_field == view_ref_found && + item_t2->type() == Item::REF_ITEM); + /* remove hooking to stack variable */ + ((Item_ref*) item_t2)->hook_ptr= 0; + } if ((t1_field= iterator->field())) { /* Mark field used for table cache */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index f9dba49d2e3..4885470846b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -284,8 +284,8 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_delete"); - if (setup_tables(thd, table_list, conds) || - setup_conds(thd, table_list, conds) || + if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) || + setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(-1); if (!table_list->updatable || check_key_in_view(thd, table_list)) @@ -341,7 +341,8 @@ int mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables(thd, lex->query_tables, &lex->select_lex.where)) + if (setup_tables(thd, lex->query_tables, &lex->select_lex.where, + &lex->select_lex.leaf_tables, 0)) DBUG_RETURN(-1); /* Fix tables-to-be-deleted-from list to point at opened tables */ diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 8fc0671c808..93900dbec8a 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -619,6 +619,7 @@ int mysqld_help(THD *thd, const char *mask) st_find_field used_fields[array_elements(init_used_fields)]; DBUG_ENTER("mysqld_help"); + TABLE_LIST *leaves= 0; TABLE_LIST tables[4]; bzero((gptr)tables,sizeof(tables)); tables[0].alias= tables[0].real_name= (char*) "help_topic"; @@ -647,7 +648,7 @@ int mysqld_help(THD *thd, const char *mask) tables do not contain VIEWs => we can pass 0 as conds */ - setup_tables(thd, tables, 0); + setup_tables(thd, tables, 0, &leaves, 0); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ac63445c1de..03028a13d19 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -476,8 +476,9 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) { uint num= view->view->select_lex.item_list.elements; TABLE *table= view->table; - Item **trans_start= view->field_translation, **trans_end=trans_start+num; - Item **trans; + Field_translator *trans_start= view->field_translation, + *trans_end= trans_start + num; + Field_translator *trans; Field **field_ptr= table->field; ulong other_query_id= query_id - 1; DBUG_ENTER("check_key_in_view"); @@ -490,9 +491,9 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) { Item_field *field; /* simple SELECT list entry (field without expression) */ - if ((*trans)->type() != Item::FIELD_ITEM) + if (trans->item->type() != Item::FIELD_ITEM) DBUG_RETURN(TRUE); - field= (Item_field *)(*trans); + field= (Item_field *)trans->item; if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ @@ -502,7 +503,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) for (trans= trans_start; trans != trans_end; trans++) { /* Thanks to test above, we know that all columns are of type Item_field */ - Item_field *field= (Item_field *)(*trans); + Item_field *field= (Item_field *)trans->item; if (field->field->query_id == query_id) DBUG_RETURN(TRUE); field->field->query_id= query_id; @@ -521,7 +522,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) { if (trans == trans_end) DBUG_RETURN(TRUE); // Field was not part of view - if (((Item_field *)(*trans))->field == *field_ptr) + if (((Item_field *)trans->item)->field == *field_ptr) break; // ok } } @@ -551,7 +552,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); - if (setup_tables(thd, table_list, where)) + if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables, + 0)) DBUG_RETURN(1); if (insert_into_view && !fields.elements) @@ -1616,6 +1618,10 @@ int mysql_insert_select_prepare(THD *thd) lex->field_list, &lex->select_lex.where)) DBUG_RETURN(-1); + /* exclude first table from leaf tables list, because it belong to INSERT */ + DBUG_ASSERT(lex->select_lex.leaf_tables); + lex->leaf_tables_insert= lex->select_lex.leaf_tables; + lex->select_lex.leaf_tables= lex->select_lex.leaf_tables->next_leaf; DBUG_RETURN(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f5382e6df99..e6c9f973b9b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1006,7 +1006,7 @@ void st_select_lex::init_query() table_list.empty(); top_join_list.empty(); join_list= &top_join_list; - embedding= 0; + embedding= leaf_tables= 0; item_list.empty(); join= 0; where= prep_where= 0; @@ -1564,7 +1564,7 @@ bool st_lex::can_be_merged() select_lex.group_list.elements == 0 && select_lex.having == 0 && select_lex.with_sum_func == 0 && - select_lex.table_list.elements == 1 && + select_lex.table_list.elements >= 1 && !(select_lex.options & SELECT_DISTINCT) && select_lex.select_limit == HA_POS_ERROR); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d43b1f81f3d..a32b8465a88 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -432,6 +432,7 @@ public: List top_join_list; /* join list of the top level */ List *join_list; /* list for the currently parsed join */ TABLE_LIST *embedding; /* table embedding to the above list */ + TABLE_LIST *leaf_tables; /* list of leaves in join table tree */ const char *type; /* type of select for EXPLAIN */ SQL_LIST order_list; /* ORDER clause */ @@ -650,6 +651,8 @@ typedef struct st_lex */ TABLE_LIST **query_tables_last; TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */ + /* store original leaf_tables for INSERT SELECT and PS/SP */ + TABLE_LIST *leaf_tables_insert; List col_list; List ref_list; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 9b050c0863a..e0138e642e0 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -138,7 +138,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, thd->dupp_field=0; /* TODO: use this conds for 'WITH CHECK OPTIONS' */ Item *unused_conds= 0; - if (setup_tables(thd, table_list, &unused_conds) || + TABLE_LIST *leaves= 0; + if (setup_tables(thd, table_list, &unused_conds, &leaves, 0) || setup_fields(thd, 0, table_list, fields, 1, 0, 0)) DBUG_RETURN(-1); if (thd->dupp_field) diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 20fd7fe2ee0..c287b9e71e7 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -153,7 +153,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first - &select_lex->where) || + &select_lex->where, &select_lex->leaf_tables, 0) || setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, select_lex->item_list, 1, &all_fields,1) || setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e1baf47b234..115dda49666 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4344,7 +4344,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length, bool lexonly) lex->found_colon= 0; lex->safe_to_cache_query= 1; lex->time_zone_tables_used= 0; - lex->proc_table= lex->query_tables= 0; + lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; lex->variables_used= 0; lex->select_lex.parent_lex= lex; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 124db39ef3f..99510d900bc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1717,8 +1717,15 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) were closed in the end of previous prepare or execute call. */ tables->table= 0; + if (tables->nested_join) + tables->nested_join->counter= 0; } lex->current_select= &lex->select_lex; + + /* restore original list used in INSERT ... SELECT */ + if (lex->leaf_tables_insert) + lex->select_lex.leaf_tables= lex->leaf_tables_insert; + if (lex->result) lex->result->cleanup(); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 789a4dc3086..ab7af598673 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -38,7 +38,7 @@ const key_map key_map_empty(0); const key_map key_map_full(~0); static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); -static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, +static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds, DYNAMIC_ARRAY *keyuse); static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, JOIN_TAB *join_tab, @@ -243,6 +243,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) */ inline int setup_without_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + TABLE_LIST *leaves, List &fields, List &all_fields, COND **conds, @@ -255,7 +256,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, save_allow_sum_func= thd->allow_sum_func; thd->allow_sum_func= 0; - res= (setup_conds(thd, tables, conds) || + res= (setup_conds(thd, tables, leaves, conds) || setup_order(thd, ref_pointer_array, tables, fields, all_fields, order) || setup_group(thd, ref_pointer_array, tables, fields, all_fields, @@ -302,13 +303,14 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ - if (setup_tables(thd, tables_list, &conds) || + if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 0) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, &all_fields, 1) || - setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list, - all_fields, &conds, order, group_list, + setup_without_group(thd, (*rref_pointer_array), tables_list, + select_lex->leaf_tables, fields_list, + all_fields, &conds, order, group_list, &hidden_group_fields)) DBUG_RETURN(-1); /* purecov: inspected */ @@ -375,7 +377,9 @@ JOIN::prepare(Item ***rref_pointer_array, } } TABLE_LIST *table_ptr; - for (table_ptr= tables_list; table_ptr; table_ptr= table_ptr->next_local) + for (table_ptr= select_lex->leaf_tables; + table_ptr; + table_ptr= table_ptr->next_leaf) tables++; } { @@ -552,7 +556,7 @@ JOIN::optimize() opt_sum_query() returns -1 if no rows match to the WHERE conditions, or 1 if all items were resolved, or 0, or an error number HA_ERR_... */ - if ((res=opt_sum_query(tables_list, all_fields, conds))) + if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { if (res > 1) { @@ -578,11 +582,11 @@ JOIN::optimize() DBUG_RETURN(0); } error= -1; // Error is sent to client - sort_by_table= get_sort_by_table(order, group_list, tables_list); + sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables); /* Calculate how to do the join */ thd->proc_info= "statistics"; - if (make_join_statistics(this, tables_list, conds, &keyuse) || + if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) || thd->is_fatal_error) { DBUG_PRINT("error",("Error: make_join_statistics() failed")); @@ -1016,7 +1020,7 @@ JOIN::reinit() if (tables_list) { tables_list->setup_is_done= 0; - if (setup_tables(thd, tables_list, &conds)) + if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 1)) DBUG_RETURN(1); } @@ -1121,7 +1125,7 @@ JOIN::exec() if (zero_result_cause) { - (void) return_zero_rows(this, result, tables_list, fields_list, + (void) return_zero_rows(this, result, select_lex->leaf_tables, fields_list, send_row_on_empty_set(), select_options, zero_result_cause, @@ -2030,7 +2034,7 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, */ static bool -make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, +make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, DYNAMIC_ARRAY *keyuse_array) { int error; @@ -2060,7 +2064,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, for (s= stat, i= 0; tables; - s++, tables= tables->next_local, i++) + s++, tables= tables->next_leaf, i++) { TABLE_LIST *embedding= tables->embedding; stat_vector[i]=s; @@ -4836,6 +4840,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) static void make_outerjoin_info(JOIN *join) { + DBUG_ENTER("make_outerjoin_info"); for (uint i=join->const_tables ; i < join->tables ; i++) { JOIN_TAB *tab=join->join_tab+i; @@ -4877,6 +4882,7 @@ make_outerjoin_info(JOIN *join) nested_join->first_nested->last_inner= tab; } } + DBUG_VOID_RETURN; } @@ -4952,7 +4958,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) in the ON part of an OUTER JOIN. In this case we want the code below to check if we should use 'quick' instead. */ + DBUG_PRINT("info", ("Item_int")); tmp= new Item_int((longlong) 1,1); // Always true + DBUG_PRINT("info", ("Item_int 0x%lx", (ulong)tmp)); } } @@ -5122,13 +5130,18 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) Now add the guard turning the predicate off for the null complemented row. */ + DBUG_PRINT("info", ("Item_func_trig_cond")); tmp= new Item_func_trig_cond(tmp, &first_inner_tab->not_null_compl); + DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp)); if (tmp) tmp->quick_fix_field(); /* Add the predicate to other pushed down predicates */ + DBUG_PRINT("info", ("Item_cond_and")); cond_tab->select_cond= !cond_tab->select_cond ? tmp : new Item_cond_and(cond_tab->select_cond,tmp); + DBUG_PRINT("info", ("Item_cond_and 0x%lx", + (ulong)cond_tab->select_cond)); if (!cond_tab->select_cond) DBUG_RETURN(1); cond_tab->select_cond->quick_fix_field(); @@ -5674,7 +5687,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, if (send_row) { - for (TABLE_LIST *table= tables; table; table= table->next_local) + for (TABLE_LIST *table= tables; table; table= table->next_leaf) mark_as_null_row(table->table); // All fields are NULL if (having && having->val_int() == 0) send_row=0; @@ -7702,6 +7715,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) join->thd->send_kill_message(); return -2; /* purecov: inspected */ } + DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); if (!select_cond || select_cond->val_int()) { /* @@ -10376,7 +10390,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables) if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))) DBUG_RETURN(0); - for (; !(map & tables->table->map); tables= tables->next_local); + for (; !(map & tables->table->map); tables= tables->next_leaf); if (map != tables->table->map) DBUG_RETURN(0); // More than one table DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr)); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index dc867968262..79f3950e21f 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -497,8 +497,8 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.table= table; tables.alias= table_list->alias; - if (setup_tables(thd, table_list, conds) || - setup_conds(thd, table_list, conds) || + if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) || + setup_conds(thd, table_list, select_lex->leaf_tables, conds) || select_lex->setup_ref_array(thd, order_num) || setup_order(thd, select_lex->ref_pointer_array, table_list, all_fields, all_fields, order) || @@ -542,25 +542,31 @@ int mysql_multi_update_prepare(THD *thd) TABLE_LIST *table_list= lex->query_tables; List *fields= &lex->select_lex.item_list; TABLE_LIST *tl; + TABLE_LIST *leaves; table_map tables_for_update= 0, readonly_tables= 0; int res; bool update_view= 0; DBUG_ENTER("mysql_multi_update_prepare"); + + if (setup_tables(thd, table_list, &lex->select_lex.where, + &lex->select_lex.leaf_tables, 0)) + DBUG_RETURN(-1); /* Ensure that we have update privilege for all tables and columns in the SET part */ - for (tl= table_list; tl; tl= tl->next_local) + for (tl= (leaves= lex->select_lex.leaf_tables); tl; tl= tl->next_leaf) { - TABLE *table= tl->table; /* Update of derived tables is checked later We don't check privileges here, becasue then we would get error "UPDATE command denided .. for column N" instead of "Target table ... is not updatable" */ - if (!tl->derived) - tl->grant.want_privilege= table->grant.want_privilege= + TABLE *table= tl->table; + TABLE_LIST *tlist; + if (!(tlist= tl->belong_to_view?tl->belong_to_view:tl)->derived) + tlist->grant.want_privilege= table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); } @@ -568,14 +574,13 @@ int mysql_multi_update_prepare(THD *thd) setup_tables() need for VIEWs. JOIN::prepare() will not do it second time. */ - if (setup_tables(thd, table_list, &lex->select_lex.where) || - (thd->lex->select_lex.no_wrap_view_item= 1, + if ((thd->lex->select_lex.no_wrap_view_item= 1, res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), thd->lex->select_lex.no_wrap_view_item= 0, res)) DBUG_RETURN(-1); - for (tl= table_list; tl ; tl= tl->next_local) + for (tl= table_list; tl; tl= tl->next_local) { if (tl->view) { @@ -602,25 +607,26 @@ int mysql_multi_update_prepare(THD *thd) /* Count tables and setup timestamp handling */ - for (tl= table_list; tl ; tl= tl->next_local) + for (tl= leaves; tl; tl= tl->next_leaf) { TABLE *table= tl->table; + TABLE_LIST *tlist= tl->belong_to_view?tl->belong_to_view:tl; /* We only need SELECT privilege for columns in the values list */ - tl->grant.want_privilege= table->grant.want_privilege= + tlist->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); // Only set timestamp column if this is not modified if (table->timestamp_field && table->timestamp_field->query_id == thd->query_id) table->timestamp_on_update_now= 0; - if (!tl->updatable || check_key_in_view(thd, tl)) + if (!tlist->updatable || check_key_in_view(thd, tl)) readonly_tables|= table->map; } if (tables_for_update & readonly_tables) { // find readonly table/view which cause error - for (tl= table_list; tl ; tl= tl->next_local) + for (tl= leaves; tl; tl= tl->next_local) { if ((readonly_tables & tl->table->map) && (tables_for_update & tl->table->map)) @@ -726,6 +732,7 @@ int multi_update::prepare(List ¬_used_values, update.empty(); for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local) { + /* TODO: add support of view of join support */ TABLE *table=table_ref->table; if (tables_to_update & table->map) { @@ -796,7 +803,7 @@ int multi_update::prepare(List ¬_used_values, for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local) { TABLE *table=table_ref->table; - if (!(tables_to_update & table->map) && + if (!(tables_to_update & table->map) && find_table_in_local_list(update_tables, table_ref->db, table_ref->real_name)) table->no_cache= 1; // Disable row cache diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 2364be228f8..12923af0ecf 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -465,15 +465,20 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, if ((view->updatable_view= (can_be_merged && view->algorithm != VIEW_ALGORITHM_TMPTABLE))) { - // TODO: change here when we will support UNIONs - for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first; - tbl; - tbl= tbl->next_local) + if (thd->lex->select_lex.table_list.elements > 1) + view->updatable_view= 0; + else { - if (tbl->view && !tbl->updatable_view) + // TODO: change here when we will support UNIONs + for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first; + tbl; + tbl= tbl->next_local) { - view->updatable_view= 0; - break; + if (tbl->view && !tbl->updatable_view) + { + view->updatable_view= 0; + break; + } } } } @@ -516,6 +521,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; /* @@ -558,7 +564,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) */ table->view= lex= thd->lex= (LEX*) new(&thd->mem_root) st_lex_local; mysql_init_query(thd, (uchar*)table->query.str, table->query.length, TRUE); - 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; @@ -601,6 +608,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) { @@ -655,7 +663,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; /* @@ -704,20 +712,51 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->updatable= (table->updatable_view != 0); table->ancestor= view_tables; + /* next table should include SELECT_LEX under this table SELECT_LEX - - TODO: ehere should be loop for multi tables substitution */ 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) + { + table->updatable= 0; + /* 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 ti(nested_join->join_list); + while(tbl= ti++) + { + tbl->join_list= &nested_join->join_list; + tbl->embedding= table; + } + } + } /* Store WHERE clause for postprocessing in setup_ancestor */ - table->where= lex->select_lex.where; + table->where= view_select->where; /* This SELECT_LEX will be linked in global SELECT_LEX list @@ -730,12 +769,12 @@ 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; /* 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; } @@ -746,7 +785,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; @@ -875,7 +914,7 @@ 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"); @@ -903,8 +942,8 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) uint k; for (k= 0; k < elements_in_view; k++) { - if (trans[k]->type() == Item::FIELD_ITEM && - ((Item_field *)trans[k])->field == key_part->field) + if (trans[k].item->type() == Item::FIELD_ITEM && + ((Item_field *)trans[k].item)->field == key_part->field) break; } if (k == elements_in_view) @@ -923,8 +962,8 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) { for (i= 0; i < elements_in_view; i++) { - if (trans[i]->type() == Item::FIELD_ITEM && - ((Item_field *)trans[i])->field == *field_ptr) + if (trans[i].item->type() == Item::FIELD_ITEM && + ((Item_field *)trans[i].item)->field == *field_ptr) break; } if (i == elements_in_view) // If field didn't exists @@ -968,7 +1007,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) void insert_view_fields(List *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)) @@ -976,8 +1015,8 @@ void insert_view_fields(List *list, TABLE_LIST *view) for (uint i= 0; i < elements_in_view; i++) { - if (trans[i]->type() == Item::FIELD_ITEM) - list->push_back(trans[i]); + if (trans[i].item->type() == Item::FIELD_ITEM) + list->push_back(trans[i].item); } DBUG_VOID_RETURN; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fab8f19950f..ed2243c4b77 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4840,11 +4840,11 @@ when_list2: table_ref: table_factor { $$=$1; } | join_table { $$=$1; } - { + { LEX *lex= Lex; if (!($$= lex->current_select->nest_last_join(lex->thd))) YYABORT; - } + } ; join_table_list: @@ -4934,20 +4934,20 @@ table_factor: sel->get_use_index(), sel->get_ignore_index()))) YYABORT; - sel->add_joined_table($$); + sel->add_joined_table($$); } | '(' - { + { LEX *lex= Lex; if (lex->current_select->init_nested_join(lex->thd)) YYABORT; - } + } join_table_list ')' { LEX *lex= Lex; if (!($$= lex->current_select->end_nested_join(lex->thd))) YYABORT; - } + } | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}' { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } | '(' SELECT_SYM select_derived ')' opt_table_alias diff --git a/sql/table.cc b/sql/table.cc index e6b84a5acb0..851e99ef4f6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1481,10 +1481,65 @@ void st_table_list::calc_md5(char *buffer) void st_table_list::set_ancestor() { - if (ancestor->ancestor) - ancestor->set_ancestor(); - table= ancestor->table; - ancestor->table->grant= grant; + /* process all tables of view */ + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->ancestor) + ancestor->set_ancestor(); + tbl->table->grant= grant; + } + /* if view contain only one table, substitute TABLE of it */ + if (!ancestor->next_local) + table= ancestor->table; +} + + +/* + 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 + { + DBUG_ASSERT(tbl->view && tbl->ancestor && + tbl->ancestor->next_local); + 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 + { + DBUG_ASSERT(tbl->view && tbl->ancestor && + tbl->ancestor->next_local); + tbl->restore_want_privilege(); + } + } } @@ -1509,10 +1564,11 @@ void st_table_list::set_ancestor() bool st_table_list::setup_ancestor(THD *thd, Item **conds) { - Item **transl; + Field_translator *transl; SELECT_LEX *select= &view->select_lex; SELECT_LEX *current_select_save= thd->lex->current_select; Item *item; + TABLE_LIST *tbl; List_iterator_fast it(select->item_list); uint i= 0; bool save_set_query_id= thd->set_query_id; @@ -1520,35 +1576,53 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) bool save_allow_sum_func= thd->allow_sum_func; DBUG_ENTER("st_table_list::setup_ancestor"); - if (ancestor->ancestor && - ancestor->setup_ancestor(thd, conds)) - DBUG_RETURN(1); + for (tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->ancestor && tbl->setup_ancestor(thd, conds)) + DBUG_RETURN(1); + } if (field_translation) { /* prevent look up in SELECTs tree */ thd->lex->current_select= &thd->lex->select_lex; + thd->lex->select_lex.no_wrap_view_item= 1; thd->set_query_id= 1; /* this view was prepared already on previous PS/SP execution */ - Item **end= field_translation + select->item_list.elements; - for (Item **item= field_translation; item < end; item++) + 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++) { - /* TODO: fix for several tables in VIEW */ - uint want_privilege= ancestor->table->grant.want_privilege; - /* real rights will be checked in VIEW field */ - ancestor->table->grant.want_privilege= 0; - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item)) + if (!transl->item->fixed && + transl->item->fix_fields(thd, ancestor, &transl->item)) goto err; - ancestor->table->grant.want_privilege= want_privilege; + } + for (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 (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) + goto err; + restore_want_privilege(); + + /* WHERE/ON resolved => we can rename fields */ + for (transl= field_translation; transl < end; transl++) + { + transl->item->rename((char *)transl->name); } goto ok; } /* view fields translation table */ if (!(transl= - (Item**)(thd->current_arena->alloc(select->item_list.elements * sizeof(Item*))))) + (Field_translator*)(thd->current_arena-> + alloc(select->item_list.elements * + sizeof(Field_translator))))) { DBUG_RETURN(1); } @@ -1564,22 +1638,29 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) 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++)) { - /* TODO: fix for several tables in VIEW */ - uint want_privilege= ancestor->table->grant.want_privilege; - /* real rights will be checked in VIEW field */ - ancestor->table->grant.want_privilege= 0; - /* aggregate function are allowed */ - thd->allow_sum_func= 1; + /* save original name of view column */ + char *name= item->name; if (!item->fixed && item->fix_fields(thd, ancestor, &item)) goto err; - ancestor->table->grant.want_privilege= want_privilege; - transl[i++]= item; + /* set new item get in fix fields and original column name */ + transl[i].name= name; + transl[i++].item= item; } field_translation= transl; /* TODO: sort this list? Use hash for big number of fields */ + for (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 (where) { Item_arena *arena= thd->current_arena, backup; @@ -1620,6 +1701,16 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) if (arena) thd->restore_backup_item_arena(arena, &backup); } + restore_want_privilege(); + + /* WHERE/ON resolved => we can rename fields */ + { + Field_translator *end= field_translation + select->item_list.elements; + for (transl= field_translation; transl < end; transl++) + { + transl->item->rename((char *)transl->name); + } + } /* full text function moving to current select */ if (view->select_lex.ftfunc_list->elements) @@ -1674,7 +1765,7 @@ Item *Field_iterator_table::item(THD *thd) const char *Field_iterator_view::name() { - return (*ptr)->name; + return ptr->name; } diff --git a/sql/table.h b/sql/table.h index f31c3c21d63..b5139919889 100644 --- a/sql/table.h +++ b/sql/table.h @@ -190,6 +190,13 @@ struct st_table { struct st_lex; + +struct Field_translator +{ + Item *item; + const char *name; +}; + typedef struct st_table_list { /* link in a local table list (used by SQL_LIST) */ @@ -215,13 +222,15 @@ typedef struct st_table_list /* link to select_lex where this table was used */ st_select_lex *select_lex; st_lex *view; /* link on VIEW lex for merging */ - Item **field_translation; /* array of VIEW fields */ + Field_translator *field_translation; /* array of VIEW fields */ /* ancestor of this table (VIEW merge algorithm) */ st_table_list *ancestor; /* most upper view this table belongs to */ st_table_list *belong_to_view; /* next_global before adding VIEW tables */ st_table_list *old_next; + /* list of join table tree leaves */ + st_table_list *next_leaf; Item *where; /* VIEW WHERE clause condition */ LEX_STRING query; /* text of (CRETE/SELECT) statement */ LEX_STRING md5; /* md5 of query tesxt */ @@ -234,6 +243,7 @@ typedef struct st_table_list ulonglong revision; /* revision control number */ ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */ uint effective_algorithm; /* which algorithm was really used */ + uint privilege_backup; /* place for saving privileges */ GRANT_INFO grant; thr_lock_type lock_type; uint outer_join; /* Which join type */ @@ -265,6 +275,8 @@ typedef struct st_table_list bool setup_ancestor(THD *thd, Item **conds); bool placeholder() {return derived || view; } void print(THD *thd, String *str); + void save_and_clear_want_privilege(); + void restore_want_privilege(); inline st_table_list *next_independent() { if (view) @@ -305,14 +317,14 @@ public: class Field_iterator_view: public Field_iterator { - Item **ptr, **array_end; + Field_translator *ptr, *array_end; public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table); void next() { ptr++; } bool end_of_fields() { return ptr == array_end; } const char *name(); - Item *item(THD *thd) { return *ptr; } + Item *item(THD *thd) { return ptr->item; } Field *field() { return 0; } }; From 9aa459f0df7e000224e4ac54c5009eac42ef365a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Sep 2004 23:42:56 +0300 Subject: [PATCH 02/48] support of join view updateability (WL#1809) include/mysqld_error.h: new error mesaages mysql-test/r/view.result: tests of updatint/inserting join views mysql-test/t/view.test: tests of updatint/inserting join views sql/mysql_priv.h: support of "usual UPDATE" -> "multi UPDATE" conversion sql/share/czech/errmsg.txt: new error mesaages sql/share/danish/errmsg.txt: new error mesaages sql/share/dutch/errmsg.txt: new error mesaages sql/share/english/errmsg.txt: new error mesaages sql/share/estonian/errmsg.txt: new error mesaages sql/share/french/errmsg.txt: new error mesaages sql/share/german/errmsg.txt: new error mesaages sql/share/greek/errmsg.txt: new error mesaages sql/share/hungarian/errmsg.txt: new error mesaages sql/share/italian/errmsg.txt: new error mesaages sql/share/japanese/errmsg.txt: new error mesaages sql/share/korean/errmsg.txt: new error mesaages sql/share/norwegian-ny/errmsg.txt: new error mesaages sql/share/norwegian/errmsg.txt: new error mesaages sql/share/polish/errmsg.txt: new error mesaages sql/share/portuguese/errmsg.txt: new error mesaages sql/share/romanian/errmsg.txt: new error mesaages sql/share/russian/errmsg.txt: new error mesaages sql/share/serbian/errmsg.txt: new error mesaages sql/share/slovak/errmsg.txt: new error mesaages sql/share/spanish/errmsg.txt: new error mesaages sql/share/swedish/errmsg.txt: new error mesaages sql/share/ukrainian/errmsg.txt: new error mesaages sql/sql_base.cc: test to avoid join virew to be catched here sql/sql_class.h: support of join views add to update sql/sql_delete.cc: support of join views add to delete(error issue) sql/sql_insert.cc: support of join views add to insert (order of some check changed, to allow find table which will be inserted in, when we will know which fields will be inserted) mechanism of calling setup_tables() only once fixed for INSERT SELECT sql/sql_parse.cc: support of "usual UPDATE" -> "multi UPDATE" conversion mysql_insert_select_prepare now called in same environment for usual queries and PS preparing support of join views add to delete (error issue) sql/sql_prepare.cc: support of "usual UPDATE" -> "multi UPDATE" conversion support of join views add to delete (error issue) sql/sql_update.cc: support of join views add to update sql/sql_view.cc: join views made updatable sql/sql_view.h: insert_view_fields now can check some errors sql/table.cc: methods to support recursive walk by tables tree sql/table.h: methods to support recursive walk by tables tree --- include/mysqld_error.h | 5 +- mysql-test/r/view.result | 149 ++++++++++++++++++++++++++++++ mysql-test/t/view.test | 90 ++++++++++++++++++ sql/mysql_priv.h | 3 +- sql/share/czech/errmsg.txt | 3 + sql/share/danish/errmsg.txt | 3 + sql/share/dutch/errmsg.txt | 3 + sql/share/english/errmsg.txt | 3 + sql/share/estonian/errmsg.txt | 3 + sql/share/french/errmsg.txt | 3 + sql/share/german/errmsg.txt | 3 + sql/share/greek/errmsg.txt | 3 + sql/share/hungarian/errmsg.txt | 3 + sql/share/italian/errmsg.txt | 3 + sql/share/japanese/errmsg.txt | 3 + sql/share/korean/errmsg.txt | 3 + sql/share/norwegian-ny/errmsg.txt | 3 + sql/share/norwegian/errmsg.txt | 3 + sql/share/polish/errmsg.txt | 3 + sql/share/portuguese/errmsg.txt | 3 + sql/share/romanian/errmsg.txt | 3 + sql/share/russian/errmsg.txt | 5 +- sql/share/serbian/errmsg.txt | 3 + sql/share/slovak/errmsg.txt | 3 + sql/share/spanish/errmsg.txt | 3 + sql/share/swedish/errmsg.txt | 3 + sql/share/ukrainian/errmsg.txt | 3 + sql/sql_base.cc | 2 +- sql/sql_class.h | 9 +- sql/sql_delete.cc | 9 +- sql/sql_insert.cc | 143 ++++++++++++++++++++++------ sql/sql_parse.cc | 58 +++++++----- sql/sql_prepare.cc | 53 +++++++++-- sql/sql_update.cc | 80 +++++++++++++--- sql/sql_view.cc | 53 ++++++----- sql/sql_view.h | 2 +- sql/table.cc | 89 ++++++++++++++++++ sql/table.h | 3 + 38 files changed, 717 insertions(+), 102 deletions(-) diff --git a/include/mysqld_error.h b/include/mysqld_error.h index cf032380e2f..1f66eb54df5 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -380,4 +380,7 @@ #define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 #define ER_TRG_CANT_CHANGE_ROW 1362 #define ER_TRG_NO_SUCH_ROW_IN_TRG 1363 -#define ER_ERROR_MESSAGES 364 +#define ER_VIEW_MULTIUPDATE 1364 +#define ER_VIEW_NO_INSERT_FIELD_LIST 1365 +#define ER_VIEW_DELETE_MERGE_VIEW 1366 +#define ER_ERROR_MESSAGES 367 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index c1462bf8c74..43b90c0e779 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1359,3 +1359,152 @@ a a b deallocate prepare stmt1; drop view v4,v3,v2,v1; drop tables t1,t2,t3; +create table t1 (a int, primary key (a), b int); +create table t2 (a int, primary key (a)); +insert into t1 values (1,100), (2,200); +insert into t2 values (1), (3); +create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; +update v3 set a= 10 where a=1; +select * from t1; +a b +10 100 +2 200 +select * from t2; +a +1 +3 +create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; +update v2 set a= 10 where a=200; +ERROR HY000: The target table v2 of the UPDATE is not updatable +select * from v3; +a b +2 1 +10 1 +2 3 +10 3 +select * from v2; +a b +100 1 +200 1 +100 3 +200 3 +set @a= 10; +set @b= 100; +prepare stmt1 from "update v3 set a= ? where a=?"; +execute stmt1 using @a,@b; +select * from v3; +a b +2 1 +10 1 +2 3 +10 3 +set @a= 300; +set @b= 10; +execute stmt1 using @a,@b; +select * from v3; +a b +2 1 +300 1 +2 3 +300 3 +deallocate prepare stmt1; +drop view v3,v2; +drop tables t1,t2; +create table t1 (a int, primary key (a), b int); +create table t2 (a int, primary key (a), b int); +insert into t2 values (1000, 2000); +create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; +insert into v3 values (1,2); +ERROR HY000: Can not insert into join view 'test.v3' without fields list +insert into v3 select * from t2; +ERROR HY000: Can not insert into join view 'test.v3' without fields list +insert into v3(a,b) values (1,2); +ERROR HY000: Can not modify more than one base table through a join view 'test.v3' +insert into v3(a,b) select * from t2; +ERROR HY000: Can not modify more than one base table through a join view 'test.v3' +insert into v3(a) values (1); +insert into v3(b) values (10); +insert into v3(a) select a from t2; +insert into v3(b) select b from t2; +Warnings: +Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 2 +insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a); +select * from t1; +a b +10002 NULL +10 NULL +1000 NULL +select * from t2; +a b +1000 2000 +10 NULL +2000 NULL +0 NULL +create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; +insert into v2(a) values (10); +ERROR HY000: The target table v2 of the INSERT is not updatable +select * from v3; +a b +10 1000 +1000 1000 +10002 1000 +10 10 +1000 10 +10002 10 +10 2000 +1000 2000 +10002 2000 +10 0 +1000 0 +10002 0 +select * from v2; +a b +NULL 1000 +NULL 1000 +NULL 1000 +NULL 10 +NULL 10 +NULL 10 +NULL 2000 +NULL 2000 +NULL 2000 +NULL 0 +NULL 0 +NULL 0 +delete from v3; +ERROR HY000: Can not delete from join view 'test.v3' +delete v3,t1 from v3,t1; +ERROR HY000: Can not delete from join view 'test.v3' +delete from t1; +prepare stmt1 from "insert into v3(a) values (?);"; +set @a= 100; +execute stmt1 using @a; +set @a= 300; +execute stmt1 using @a; +deallocate prepare stmt1; +prepare stmt1 from "insert into v3(a) select ?;"; +set @a= 101; +execute stmt1 using @a; +set @a= 301; +execute stmt1 using @a; +deallocate prepare stmt1; +select * from v3; +a b +100 1000 +101 1000 +300 1000 +301 1000 +100 10 +101 10 +300 10 +301 10 +100 2000 +101 2000 +300 2000 +301 2000 +100 0 +101 0 +300 0 +301 0 +drop view v3,v2; +drop tables t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 9dbb0facf40..4fe4bcc6df2 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1298,3 +1298,93 @@ execute stmt1; deallocate prepare stmt1; drop view v4,v3,v2,v1; drop tables t1,t2,t3; + +# +# updating of join view +# +create table t1 (a int, primary key (a), b int); +create table t2 (a int, primary key (a)); +insert into t1 values (1,100), (2,200); +insert into t2 values (1), (3); +# legal view for update +create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; +update v3 set a= 10 where a=1; +select * from t1; +select * from t2; +# view without primary key +create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; +-- error 1288 +update v2 set a= 10 where a=200; +# just view selects +select * from v3; +select * from v2; +# prepare statement with updating join view +set @a= 10; +set @b= 100; +prepare stmt1 from "update v3 set a= ? where a=?"; +execute stmt1 using @a,@b; +select * from v3; +set @a= 300; +set @b= 10; +execute stmt1 using @a,@b; +select * from v3; +deallocate prepare stmt1; +drop view v3,v2; +drop tables t1,t2; + +# +# inserting/deleting join view +# +create table t1 (a int, primary key (a), b int); +create table t2 (a int, primary key (a), b int); +insert into t2 values (1000, 2000); +create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; +# inserting into join view without field list +-- error 1365 +insert into v3 values (1,2); +-- error 1365 +insert into v3 select * from t2; +# inserting in several tables of join view +-- error 1364 +insert into v3(a,b) values (1,2); +-- error 1364 +insert into v3(a,b) select * from t2; +# correct inserts into join view +insert into v3(a) values (1); +insert into v3(b) values (10); +insert into v3(a) select a from t2; +insert into v3(b) select b from t2; +insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a); +select * from t1; +select * from t2; +# view without primary key +create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; +-- error 1288 +insert into v2(a) values (10); +# just view selects +select * from v3; +select * from v2; +# try delete from join view +-- error 1366 +delete from v3; +-- error 1366 +delete v3,t1 from v3,t1; +# delete from t1 just to reduce result set size +delete from t1; +# prepare statement with insert join view +prepare stmt1 from "insert into v3(a) values (?);"; +set @a= 100; +execute stmt1 using @a; +set @a= 300; +execute stmt1 using @a; +deallocate prepare stmt1; +prepare stmt1 from "insert into v3(a) select ?;"; +set @a= 101; +execute stmt1 using @a; +set @a= 301; +execute stmt1 using @a; +deallocate prepare stmt1; +select * from v3; + +drop view v3,v2; +drop tables t1,t2; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a43ec6f00ed..b84ecdb2296 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -611,7 +611,8 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, COND *conds, ulong options, enum enum_duplicates handle_duplicates, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + bool converted); int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index c613a22088a..3565343a012 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -392,3 +392,6 @@ character-set=latin2 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 0f3a8f6ffdb..1f861dbc08e 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -383,3 +383,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index d0d86a07b7e..2c9e5830a66 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -392,3 +392,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 0b502244a64..a6ca0bdda99 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -380,3 +380,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 7886c785c40..65bdb7ce354 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -385,3 +385,6 @@ character-set=latin7 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 9668cbf3c9f..116dec98742 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -380,3 +380,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index c2c82443f91..dea95536212 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -393,3 +393,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 3aac21ec481..5e1fb04c392 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -380,3 +380,6 @@ character-set=greek "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 8f96a0bf183..1a63fcc68aa 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -385,3 +385,6 @@ character-set=latin2 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8d63656bac2..4817281f0cd 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -380,3 +380,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 30eb8daffa4..ab7bc51a31a 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -384,3 +384,6 @@ character-set=ujis "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index dac28683a78..3c67464b51d 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -380,3 +380,6 @@ character-set=euckr "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 58661f16bcf..b6e8b173078 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -382,3 +382,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index ea204145d54..ec92d713d74 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -382,3 +382,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index db0d4914c19..412977f0de8 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -385,3 +385,6 @@ character-set=latin2 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index d3508f120db..46e2e598e82 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -382,3 +382,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 65ab66e1256..76b74c89cf4 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -385,3 +385,6 @@ character-set=latin2 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 6501598383c..6d39ddb6cef 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -376,7 +376,7 @@ character-set=koi8r "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'" "View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×" "áÌÇÏÒÉÔÍ ÓÌÉÑÎÉÑ view ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ÓÅÊÞÁÓ (ÁÌÇÏÒÉÔÍ ÂÕÄÅÔ ÎÅÏÐÅÒÅÄÅÌÅÎÎÙÍ)" -"ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÏÊ × ÎÅÍ ÔÁÂÌÉÃ(Ù)" +"ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÙÈ(ÏÊ) × ÎÅÍ ÔÁÂÌÉÃ(Ù)" "View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ" "Can't drop a %s from within another stored routine" "GOTO is not allowed in a stored procedure handler" @@ -385,3 +385,6 @@ character-set=koi8r "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"îÅÌØÚÑ ÉÚÍÅÎÉÔØ ÂÏÌØÛÅ ÞÅÍ ÏÄÎÕ ÂÁÚÏ×ÕÀ ÔÁÂÌÉÃÕ ÉÓÐÏÌØÚÕÑ ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.64s.%-.64s'" +"îÅÌØÚÑ ×ÓÔÁ×ÌÑÔØ ÚÁÐÉÓÉ × ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.64s.%-.64s' ÂÅÚ ÓÐÉÓËÁ ÐÏÌÅÊ" +"îÅÌØÚÑ ÕÄÁÌÑÔØ ÉÚ ÍÎÏÇÏÔÁÂÌÉÞÎÏÇÏ VIEW '%-.64s.%-.64s'" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 6e7826e33d6..7ad12dcee77 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -373,3 +373,6 @@ character-set=cp1250 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 4c82ae5e3af..cfbfeff587b 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -388,3 +388,6 @@ character-set=latin2 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index c9a1d7229ea..e663492f010 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -384,3 +384,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index e80cb48d157..bbf8bddea1a 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -380,3 +380,6 @@ character-set=latin1 "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"Can not modify more than one base table through a join view '%-.64s.%-.64s'" +"Can not insert into join view '%-.64s.%-.64s' without fields list" +"Can not delete from join view '%-.64s.%-.64s'" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 2a71aa088f4..00cfb02a95d 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -386,3 +386,6 @@ character-set=koi8u "Trigger's '%-.64s' is view or temporary table" "Updating of %s row is not allowed in %strigger" "There is no %s row in %s trigger" +"îÅÍÏÖÌÉ×Ï ÏÎÏ×ÉÔÉ Â¦ÌØÛ ÎÉÖ ÏÄÎÕ ÂÁÚÏ×Õ ÔÁÂÌÉÃÀ ×ÙËÏÒÉÓÔÏ×ÕÀÞÉ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔ¦ÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ" +"îÅÍÏÖÌÉ×Ï ÕÓÔÁ×ÉÔÉ ÒÑÄËÉ Õ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ, ÂÅÚ ÓÐÉÓËÕ ÓÔÏ×Âæ×" +"îÅÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÑÄËÉ Õ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c0deeba6148..c68f3b36284 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2296,7 +2296,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, bool allow_rowid= tables && !tables->next_local; // Only one table for (; tables ; tables= tables->next_local) { - if (!tables->table) + if (!tables->table && !tables->ancestor) { if (report_error) my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), diff --git a/sql/sql_class.h b/sql/sql_class.h index d1a8366653f..7bcc3bea447 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1504,7 +1504,9 @@ public: class multi_update :public select_result { - TABLE_LIST *all_tables, *update_tables, *table_being_updated; + TABLE_LIST *all_tables; /* query/update command tables */ + TABLE_LIST *leaves; /* list of leves of join table tree */ + TABLE_LIST *update_tables, *table_being_updated; THD *thd; TABLE **tmp_tables, *main_table, *table_to_update; TMP_TABLE_PARAM *tmp_table_param; @@ -1517,8 +1519,9 @@ class multi_update :public select_result bool do_update, trans_safe, transactional_tables, log_delayed; public: - multi_update(THD *thd_arg, TABLE_LIST *ut, List *fields, - List *values, enum_duplicates handle_duplicates); + multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list, + List *fields, List *values, + enum_duplicates handle_duplicates); ~multi_update(); int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flags) { return 0; } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4885470846b..753efb29b36 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -43,7 +43,14 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, if ((error= open_and_lock_tables(thd, table_list))) DBUG_RETURN(error); - table= table_list->table; + if (!(table= table_list->table)) + { + DBUG_ASSERT(table_list->view && + table_list->ancestor && table_list->ancestor->next_local); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + DBUG_RETURN(-1); + } table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; table->map=1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 03028a13d19..9690b9289ba 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -21,6 +21,7 @@ #include "sql_acl.h" #include "sp_head.h" #include "sql_trigger.h" +#include "sql_select.h" static int check_null_fields(THD *thd,TABLE *entry); #ifndef EMBEDDED_LIBRARY @@ -31,6 +32,7 @@ static void end_delayed_insert(THD *thd); extern "C" pthread_handler_decl(handle_delayed_insert,arg); static void unlink_blobs(register TABLE *table); #endif +static bool check_view_insertability(TABLE_LIST *view, ulong query_id); /* Define to force use of my_malloc() if the allocated memory block is big */ @@ -54,8 +56,22 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, { TABLE *table= table_list->table; + if (!table_list->updatable) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); + return -1; + } + if (fields.elements == 0 && values.elements != 0) { + if (!table) + { + DBUG_ASSERT(table_list->view && + table_list->ancestor && table_list->ancestor->next_local); + my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), + table_list->view_db.str, table_list->view_name.str); + return -1; + } if (values.elements != table->fields) { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, @@ -97,6 +113,23 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, thd->lex->select_lex.no_wrap_view_item= 0; if (res) return -1; + if (table == 0) + { + /* it is join view => we need to find table for update */ + List_iterator_fast it(fields); + Item *item; + TABLE_LIST *tbl= 0; + table_map map= 0; + while (item= it++) + map|= item->used_tables(); + if (table_list->check_single_table(&tbl, map) || tbl == 0) + { + my_error(ER_VIEW_MULTIUPDATE, MYF(0), + table_list->view_db.str, table_list->view_name.str); + return -1; + } + table_list->table= table= tbl->table; + } if (check_unique && thd->dupp_field) { @@ -111,6 +144,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, #ifndef NO_EMBEDDED_ACCESS_CHECKS table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); #endif + + if (check_key_in_view(thd, table_list) || + (table_list->view && + check_view_insertability(table_list, thd->query_id))) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); + return -1; + } + return 0; } @@ -134,7 +176,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, ulong counter = 1; ulonglong id; COPY_INFO info; - TABLE *table; + TABLE *table= 0; List_iterator_fast its(values_list); List_item *values; #ifndef EMBEDDED_LIBRARY @@ -201,17 +243,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, if (res || thd->is_fatal_error) DBUG_RETURN(-1); - table= table_list->table; thd->proc_info="init"; thd->used_tables=0; values= its++; - if (duplic == DUP_UPDATE && !table->insert_values) + if (duplic == DUP_UPDATE) { /* it should be allocated before Item::fix_fields() */ - table->insert_values= - (byte *)alloc_root(&thd->mem_root, table->rec_buff_length); - if (!table->insert_values) + if (table_list->set_insert_values(&thd->mem_root)) goto abort; } @@ -219,6 +258,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, update_fields, update_values, duplic)) goto abort; + /* mysql_prepare_insert set table_list->table if it was not set */ + table= table_list->table; + // is table which we are changing used somewhere in other parts of query value_count= values->elements; while ((values= its++)) @@ -437,7 +479,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, ::send_ok(thd, (ulong) thd->row_count_func, id, buff); } free_underlaid_joins(thd, &thd->lex->select_lex); - table->insert_values=0; + table_list->clear_insert_values(); DBUG_RETURN(0); abort: @@ -446,7 +488,7 @@ abort: end_delayed_insert(thd); #endif free_underlaid_joins(thd, &thd->lex->select_lex); - table->insert_values=0; + table_list->clear_insert_values(); DBUG_RETURN(-1); } @@ -542,11 +584,12 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) where Pointer to where clause RETURN - 0 ok - 1 ERROR + 0 ok + 1 ERROR and message sent to client + -1 ERROR but message is not sent to client */ -static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, +static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, List &fields, COND **where) { bool insert_into_view= (table_list->view != 0); @@ -554,22 +597,22 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables, 0)) - DBUG_RETURN(1); + DBUG_RETURN(thd->net.report_error ? -1 : 1); if (insert_into_view && !fields.elements) { thd->lex->empty_field_list_on_rset= 1; - insert_view_fields(&fields, table_list); + if (!table_list->table) + { + DBUG_ASSERT(table_list->view && + table_list->ancestor && table_list->ancestor->next_local); + my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), + table_list->view_db.str, table_list->view_name.str); + DBUG_RETURN(-1); + } + DBUG_RETURN(insert_view_fields(&fields, table_list)); } - if (!table_list->updatable || - check_key_in_view(thd, table_list) || - (insert_into_view && - check_view_insertability(table_list, thd->query_id))) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); - DBUG_RETURN(1); - } DBUG_RETURN(0); } @@ -598,8 +641,9 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, int res; DBUG_ENTER("mysql_prepare_insert"); - if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds)) - DBUG_RETURN(-1); + if ((res= mysql_prepare_insert_check_table(thd, table_list, + fields, &unused_conds))) + DBUG_RETURN(res); if (check_insert_fields(thd, table_list, fields, *values, 1, !insert_into_view) || @@ -1607,21 +1651,43 @@ bool delayed_insert::handle_inserts(void) RETURN 0 OK - -1 Error + 1 Error sent to client + -1 Error is not sent to client */ int mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; + TABLE_LIST* first_select_table= + (TABLE_LIST*)lex->select_lex.table_list.first; + TABLE_LIST* first_select_leaf_table; + int res; DBUG_ENTER("mysql_insert_select_prepare"); - if (mysql_prepare_insert_check_table(thd, lex->query_tables, - lex->field_list, - &lex->select_lex.where)) - DBUG_RETURN(-1); - /* exclude first table from leaf tables list, because it belong to INSERT */ + if ((res= mysql_prepare_insert_check_table(thd, lex->query_tables, + lex->field_list, + &lex->select_lex.where))) + DBUG_RETURN(res); + /* + setup was done in mysql_insert_select_prepare, but we have to mark + first local table + */ + if (first_select_table) + first_select_table->setup_is_done= 1; + /* + exclude first table from leaf tables list, because it belong to + INSERT + */ DBUG_ASSERT(lex->select_lex.leaf_tables); lex->leaf_tables_insert= lex->select_lex.leaf_tables; - lex->select_lex.leaf_tables= lex->select_lex.leaf_tables->next_leaf; + /* skip all leaf tables belonged to view where we are insert */ + for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf; + first_select_leaf_table && + first_select_leaf_table->belong_to_view && + first_select_leaf_table->belong_to_view == + lex->leaf_tables_insert->belong_to_view; + first_select_leaf_table= first_select_leaf_table->next_leaf) + {} + lex->select_lex.leaf_tables= first_select_leaf_table; DBUG_RETURN(0); } @@ -1635,6 +1701,23 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) if (check_insert_fields(thd, table_list, *fields, values, 1, !insert_into_view)) DBUG_RETURN(1); + /* + if it is INSERT into join view then check_insert_fields already found + real table for insert + */ + table= table_list->table; + + /* + Is table which we are changing used somewhere in other parts of + query + */ + if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) && + unique_table(table_list, table_list->next_independent())) + { + /* Using same table for INSERT and SELECT */ + thd->lex->current_select->options|= OPTION_BUFFER_RESULT; + thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT; + } restore_record(table,default_values); // Get empty record table->next_number_field=table->found_next_number_field; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 115dda49666..f9a6275abeb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2747,18 +2747,29 @@ unsent_create_error: lex->duplicates); if (thd->net.report_error) res= -1; - break; + if (res != 2) + break; case SQLCOM_UPDATE_MULTI: { + bool converted= 0; DBUG_ASSERT(first_table == all_tables && first_table != 0); - if ((res= multi_update_precheck(thd, all_tables))) - break; + if (res != 2) + { + if ((res= multi_update_precheck(thd, all_tables))) + break; + } + else + { + res= 0; + converted= 1; + } res= mysql_multi_update(thd, all_tables, &select_lex->item_list, &lex->value_list, select_lex->where, select_lex->options, - lex->duplicates, unit, select_lex); + lex->duplicates, unit, select_lex, + converted); break; } case SQLCOM_REPLACE: @@ -2796,31 +2807,26 @@ unsent_create_error: if (!(res= open_and_lock_tables(thd, all_tables))) { - /* - Is table which we are changing used somewhere in other parts of - query - */ - if (unique_table(first_table, all_tables->next_independent())) - { - /* Using same table for INSERT and SELECT */ - select_lex->options |= OPTION_BUFFER_RESULT; - } + /* Skip first table, which is the table we are inserting in */ + lex->select_lex.table_list.first= (byte*)first_table->next_local; + + res= mysql_insert_select_prepare(thd); + if (!res && (result= new select_insert(first_table, first_table->table, + &lex->field_list, + lex->duplicates))) + { + TABLE_LIST *first_select_table; - if ((res= mysql_insert_select_prepare(thd))) - break; - if ((result= new select_insert(first_table, first_table->table, - &lex->field_list, lex->duplicates))) - /* Skip first table, which is the table we are inserting in */ - lex->select_lex.table_list.first= (byte*) first_table->next_local; /* insert/replace from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; res= handle_select(thd, lex, result); - /* revert changes for SP */ - lex->select_lex.table_list.first= (byte*) first_table; lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; + } + /* revert changes for SP */ + lex->select_lex.table_list.first= (byte*) first_table; if (thd->net.report_error) res= -1; } @@ -2884,6 +2890,16 @@ unsent_create_error: if ((res= open_and_lock_tables(thd, all_tables))) break; + if (!first_table->table) + { + DBUG_ASSERT(first_table->view && + first_table->ancestor && first_table->ancestor->next_local); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + first_table->view_db.str, first_table->view_name.str); + res= -1; + break; + } + if ((res= mysql_multi_delete_prepare(thd))) break; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 99510d900bc..12a69c359bb 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -959,6 +959,7 @@ error: RETURN VALUE 0 success + 2 convert to multi_update 1 error, sent to client -1 error, not sent to client */ @@ -975,6 +976,15 @@ static int mysql_test_update(Prepared_statement *stmt, if (!(res=open_and_lock_tables(thd, table_list))) { + if (table_list->table == 0) + { + DBUG_ASSERT(table_list->view && + table_list->ancestor && table_list->ancestor->next_local); + stmt->lex->sql_command= SQLCOM_UPDATE_MULTI; + DBUG_PRINT("info", ("Switch to multi-update (command replaced)")); + /* convert to multiupdate */ + return 2; + } if (!(res= mysql_prepare_update(thd, table_list, &select->where, select->order_list.elements, @@ -1027,6 +1037,15 @@ static int mysql_test_delete(Prepared_statement *stmt, if (!(res=open_and_lock_tables(thd, table_list))) { + if (!table_list->table) + { + DBUG_ASSERT(table_list->view && + table_list->ancestor && table_list->ancestor->next_local); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + DBUG_RETURN(-1); + } + res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where); lex->unit.cleanup(); } @@ -1219,7 +1238,10 @@ static int select_like_statement_test(Prepared_statement *stmt, LEX *lex= stmt->lex; int res= 0; - if (tables && (res= open_and_lock_tables(thd, tables))) + /* check that tables was not opened during conversion from usual update */ + if (tables && + (!tables->table && !tables->view) && + (res= open_and_lock_tables(thd, tables))) goto end; if (specific_prepare && (res= (*specific_prepare)(thd))) @@ -1285,6 +1307,7 @@ static int mysql_test_create_table(Prepared_statement *stmt) mysql_test_multiupdate() stmt prepared statemen handler tables list of tables queries + converted converted to multi-update from usual update RETURN VALUE 0 success @@ -1292,10 +1315,11 @@ static int mysql_test_create_table(Prepared_statement *stmt) -1 error, not sent to client */ static int mysql_test_multiupdate(Prepared_statement *stmt, - TABLE_LIST *tables) + TABLE_LIST *tables, + bool converted) { int res; - if ((res= multi_update_precheck(stmt->thd, tables))) + if (!converted && (res= multi_update_precheck(stmt->thd, tables))) return res; return select_like_statement_test(stmt, tables, &mysql_multi_update_prepare); } @@ -1325,7 +1349,19 @@ static int mysql_test_multidelete(Prepared_statement *stmt, uint fake_counter; if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) return res; - return select_like_statement_test(stmt, tables, &mysql_multi_delete_prepare); + if ((res= select_like_statement_test(stmt, tables, + &mysql_multi_delete_prepare))) + return res; + if (!tables->table) + { + DBUG_ASSERT(tables->view && + tables->ancestor && tables->ancestor->next_local); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + tables->view_db.str, tables->view_name.str); + return -1; + } + return 0; + } @@ -1404,6 +1440,11 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) case SQLCOM_UPDATE: res= mysql_test_update(stmt, tables); + if (res != 2) + break; + + case SQLCOM_UPDATE_MULTI: + res= mysql_test_multiupdate(stmt, tables, res == 2); break; case SQLCOM_DELETE: @@ -1431,10 +1472,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) case SQLCOM_DELETE_MULTI: res= mysql_test_multidelete(stmt, tables); break; - - case SQLCOM_UPDATE_MULTI: - res= mysql_test_multiupdate(stmt, tables); - break; case SQLCOM_INSERT_SELECT: res= mysql_test_insert_select(stmt, tables); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 79f3950e21f..1e8cb73fa92 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -87,6 +87,28 @@ static bool check_fields(THD *thd, List &items) } +/* + Process usual UPDATE + + SYNOPSIS + mysql_update() + thd thread handler + fields fields for update + values values of fields for update + conds WHERE clause expression + order_num number of elemen in ORDER BY clause + order ORDER BY clause list + limit limit clause + handle_duplicates how to handle duplicates + + RETURN + 0 - OK + 2 - privilege check and openning table passed, but we need to convert to + multi-update because of view substitution + 1 - error and error sent to client + -1 - error and error is not sent to client +*/ + int mysql_update(THD *thd, TABLE_LIST *table_list, List &fields, @@ -96,7 +118,7 @@ int mysql_update(THD *thd, ha_rows limit, enum enum_duplicates handle_duplicates) { - bool using_limit=limit != HA_POS_ERROR; + bool using_limit=limit != HA_POS_ERROR; bool safe_update= thd->options & OPTION_SAFE_UPDATES; bool used_key_is_modified, transactional_table, log_delayed; int error=0; @@ -117,6 +139,15 @@ int mysql_update(THD *thd, if ((error= open_and_lock_tables(thd, table_list))) DBUG_RETURN(error); + + if (table_list->table == 0) + { + DBUG_ASSERT(table_list->view && + table_list->ancestor && table_list->ancestor->next_local); + DBUG_PRINT("info", ("Switch to multi-update")); + /* convert to multiupdate */ + return 2; + } thd->proc_info="init"; table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -626,12 +657,30 @@ int mysql_multi_update_prepare(THD *thd) if (tables_for_update & readonly_tables) { // find readonly table/view which cause error - for (tl= leaves; tl; tl= tl->next_local) + for (tl= leaves; tl; tl= tl->next_leaf) { if ((readonly_tables & tl->table->map) && (tables_for_update & tl->table->map)) { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE"); + TABLE_LIST *table= tl->belong_to_view ? tl->belong_to_view : tl; + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table->alias, "UPDATE"); + DBUG_RETURN(-1); + } + } + } + + /* check single table update for view compound from several tables */ + for (tl= table_list; tl; tl= tl->next_local) + { + if (tl->table == 0) + { + DBUG_ASSERT(tl->view && + tl->ancestor && tl->ancestor->next_local); + TABLE_LIST *for_update= 0; + if (tl->check_single_table(&for_update, tables_for_update)) + { + my_error(ER_VIEW_MULTIUPDATE, MYF(0), + tl->view_db.str, tl->view_name.str); DBUG_RETURN(-1); } } @@ -647,19 +696,22 @@ int mysql_multi_update(THD *thd, COND *conds, ulong options, enum enum_duplicates handle_duplicates, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + bool converted) { - int res; + int res= 0; multi_update *result; DBUG_ENTER("mysql_multi_update"); - if ((res= open_and_lock_tables(thd, table_list))) + if (!converted && (res= open_and_lock_tables(thd, table_list))) DBUG_RETURN(res); if ((res= mysql_multi_update_prepare(thd))) DBUG_RETURN(res); - if (!(result= new multi_update(thd, table_list, fields, values, + if (!(result= new multi_update(thd, table_list, + thd->lex->select_lex.leaf_tables, + fields, values, handle_duplicates))) DBUG_RETURN(-1); @@ -677,12 +729,14 @@ int mysql_multi_update(THD *thd, multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, + TABLE_LIST *leaves_list, List *field_list, List *value_list, enum enum_duplicates handle_duplicates_arg) - :all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0), - updated(0), found(0), fields(field_list), values(value_list), - table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), - do_update(1), trans_safe(0), transactional_tables(1) + :all_tables(table_list), leaves(leaves_list), update_tables(0), + thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list), + values(value_list), table_count(0), copy_field(0), + handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), + transactional_tables(1) {} @@ -730,7 +784,7 @@ int multi_update::prepare(List ¬_used_values, */ update.empty(); - for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local) + for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) { /* TODO: add support of view of join support */ TABLE *table=table_ref->table; @@ -800,7 +854,7 @@ int multi_update::prepare(List ¬_used_values, which will cause an error when reading a row. (This issue is mostly relevent for MyISAM tables) */ - for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local) + for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) { TABLE *table=table_ref->table; if (!(tables_to_update & table->map) && diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 12923af0ecf..3e950f6d3a0 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -465,23 +465,27 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, if ((view->updatable_view= (can_be_merged && view->algorithm != VIEW_ALGORITHM_TMPTABLE))) { - if (thd->lex->select_lex.table_list.elements > 1) - view->updatable_view= 0; - else + // TODO: change here when we will support UNIONs + for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first; + tbl; + tbl= tbl->next_local) { - // TODO: change here when we will support UNIONs - for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first; - tbl; - tbl= tbl->next_local) + if (tbl->view && !tbl->updatable_view) { - if (tbl->view && !tbl->updatable_view) - { - view->updatable_view= 0; - break; - } + view->updatable_view= 0; + break; + } + for (TABLE_LIST *up= tbl; up; up= up->embedding) + { + if (up->outer_join) + { + view->updatable_view= 0; + goto loop_out; + } } } } +loop_out: if (sql_create_definition_file(&dir, &file, view_file_type, (gptr)view, view_parameters, 3)) { @@ -701,9 +705,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); @@ -736,7 +737,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) /* multi table view */ if (view_tables->next_local) { - table->updatable= 0; /* make nested join structure for view tables */ NESTED_JOIN *nested_join; if (!(nested_join= table->nested_join= @@ -919,14 +919,16 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) uint i, elements_in_view; DBUG_ENTER("check_key_in_view"); - if (!view->view) + if (!view->view && !view->belong_to_view) DBUG_RETURN(FALSE); /* it is normal table */ 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++) @@ -1002,21 +1004,30 @@ 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 *list, TABLE_LIST *view) +int insert_view_fields(List *list, TABLE_LIST *view) { uint elements_in_view= view->view->select_lex.item_list.elements; 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++) { if (trans[i].item->type() == Item::FIELD_ITEM) list->push_back(trans[i].item); + else + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT"); + DBUG_RETURN(-1); + } } - DBUG_VOID_RETURN; + DBUG_RETURN(0); } diff --git a/sql/sql_view.h b/sql/sql_view.h index 431f82a5bb8..e76cf13a4c4 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -25,7 +25,7 @@ int mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool check_key_in_view(THD *thd, TABLE_LIST * view); -void insert_view_fields(List *list, TABLE_LIST *view); +int insert_view_fields(List *list, TABLE_LIST *view); frm_type_enum mysql_frm_type(char *path); diff --git a/sql/table.cc b/sql/table.cc index 851e99ef4f6..40d20fadec3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1744,6 +1744,95 @@ err: } +/* + Find table in underlaying tables by mask and check that only this + table sbelong to given mask + + SYNOPSIS + st_table_list::check_single_table() + table reference on variable where to store found table + (should be 0 on call, to find table, or point to table for + unique test) + map bit mask of tables + + RETURN + 0 table not found or found only one + 1 found several tables +*/ + +bool st_table_list::check_single_table(st_table_list **table, table_map map) +{ + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->table) + { + if (tbl->table->map & map) + { + if (*table) + return 1; + else + *table= tbl; + } + } + else + if (tbl->check_single_table(table, map)) + return 1; + } +} + + +/* + Set insert_values buffer + + SYNOPSIS + set_insert_values() + mem_root memory pool for allocating + + RETURN + FALSE - OK + TRUE - out of memory +*/ + +bool st_table_list::set_insert_values(MEM_ROOT *mem_root) +{ + if (table) + { + if (!table->insert_values && + !(table->insert_values= (byte *)alloc_root(mem_root, + table->rec_buff_length))) + return TRUE; + } + else + { + DBUG_ASSERT(view && ancestor && ancestor->next_local); + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + if (tbl->set_insert_values(mem_root)) + return TRUE; + } + return FALSE; +} + + +/* + clear insert_values reference + + SYNOPSIS + clear_insert_values() +*/ + +void st_table_list::clear_insert_values() +{ + if (table) + table->insert_values= 0; + else + { + DBUG_ASSERT(view && ancestor && ancestor->next_local); + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + tbl->clear_insert_values(); + } +} + + void Field_iterator_view::set(TABLE_LIST *table) { ptr= table->field_translation; diff --git a/sql/table.h b/sql/table.h index b5139919889..5f6222f3343 100644 --- a/sql/table.h +++ b/sql/table.h @@ -277,6 +277,9 @@ typedef struct st_table_list void print(THD *thd, String *str); void save_and_clear_want_privilege(); void restore_want_privilege(); + bool check_single_table(st_table_list **table, table_map map); + bool set_insert_values(MEM_ROOT *mem_root); + void clear_insert_values(); inline st_table_list *next_independent() { if (view) From 61e96be77fdc0eee96c86903b5b66f8edf6b9238 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Oct 2004 15:07:31 +0300 Subject: [PATCH 03/48] postmerge fix --- mysql-test/r/view.result | 3 +-- mysql-test/t/view.test | 1 - sql/sql_insert.cc | 6 +++++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index bcec53f4722..7fec5ea174e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1424,7 +1424,6 @@ a 1 drop view v1; drop table t1; -drop table t1,t2; create table t1 (a int); create table t2 (a int); create table t3 (a int); @@ -1541,7 +1540,7 @@ insert into v3(b) values (10); insert into v3(a) select a from t2; insert into v3(b) select b from t2; Warnings: -Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 2 +Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2 insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a); select * from t1; a b diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7d3c0e2dc45..5c0c628a99e 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1387,7 +1387,6 @@ insert ignore into v1 values (1) on duplicate key update a=2; select * from t1; drop view v1; drop table t1; -drop table t1,t2; # # merge of VIEW with several tables diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d14cc1cf780..160d77b512e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -567,7 +567,11 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) view->contain_auto_increment= 1; /* prepare unique test */ field->field->query_id= other_query_id; - *trans= field; // remove collation if we have it + /* + remove collation (or other transparent for update function) if we have + it + */ + trans->item= field; } /* unique test */ for (trans= trans_start; trans != trans_end; trans++) From 3f07afbea005900c185a769ea23381f1bba0ef23 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 6 Nov 2004 09:37:30 +0400 Subject: [PATCH 04/48] A fix (bug #6441: Aggregate UDF in multi-table query crashes MySQL when returning multiple rows). sql/item_func.cc: A fix (bug #6441: Aggregate UDF in multi-table query crashes MySQL when returning multiple rows). Do nothing in the udf_handler destructor if not_original flag is set. sql/item_sum.h: A fix (bug #6441: Aggregate UDF in multi-table query crashes MySQL when returning multiple rows). Set udf.not_original flag if we create an Item from the existent one. sql/sql_udf.h: A fix (bug #6441: Aggregate UDF in multi-table query crashes MySQL when returning multiple rows). not_original flag added. --- sql/item_func.cc | 19 +++++++++++-------- sql/item_sum.h | 2 +- sql/sql_udf.h | 3 ++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index 09d7e50eaa3..32708ecb4ca 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1602,18 +1602,21 @@ longlong Item_func_bit_count::val_int() udf_handler::~udf_handler() { - if (initialized) + if (!not_original) { - if (u_d->func_deinit != NULL) + if (initialized) { - void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*)) - u_d->func_deinit; - (*deinit)(&initid); + if (u_d->func_deinit != NULL) + { + void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*)) + u_d->func_deinit; + (*deinit)(&initid); + } + free_udf(u_d); } - free_udf(u_d); + if (buffers) // Because of bug in ecc + delete [] buffers; } - if (buffers) // Because of bug in ecc - delete [] buffers; } diff --git a/sql/item_sum.h b/sql/item_sum.h index 5aa0d37190b..74c28765f8d 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -532,7 +532,7 @@ public: :Item_sum( list ), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) {} + :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 7b10b80f148..d1f99a6d232 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -56,8 +56,9 @@ class udf_handler :public Sql_alloc public: table_map used_tables_cache; bool const_item_cache; + bool not_original; udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), - is_null(0), initialized(0) + is_null(0), initialized(0), not_original(0) {} ~udf_handler(); const char *name() const { return u_d ? u_d->name.str : "?"; } From 22b56d235427b435fd29b054c23d9fd4db8cbf0b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Nov 2004 18:38:38 +0000 Subject: [PATCH 05/48] changed mysqladmin.c to mysqladmin.cc no need for dvlags to have DEFINE_CXA_PURE_VIRTUAL anymore aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals enabled multiple management servrs to fetch data configurations from eachother client/Makefile.am: changed mysqladmin.c to mysqladmin.cc client/mysqladmin.cc: changed mysqladmin.c to mysqladmin.cc configure.in: no need for dvlags to have DEFINE_CXA_PURE_VIRTUAL anymore ndb/include/mgmapi/mgmapi.h: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/include/mgmcommon/ConfigRetriever.hpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/include/ndbapi/ndb_cluster_connection.hpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/common/mgmcommon/ConfigRetriever.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/kernel/main.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/kernel/vm/Configuration.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals changed to config setting to always use noOfMetaTables to make sure we don't overflow arrays ndb/src/kernel/vm/Configuration.hpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmapi/LocalConfig.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmapi/LocalConfig.hpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmapi/mgmapi.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmclient/CommandInterpreter.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmclient/main.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmclient/ndb_mgmclient.hpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmclient/ndb_mgmclient.h: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmsrv/MgmtSrvr.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals enabled multiple management servrs to fetch data configurations from eachother ndb/src/mgmsrv/MgmtSrvr.hpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmsrv/MgmtSrvrConfig.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/mgmsrv/main.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/src/ndbapi/ndb_cluster_connection.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals ndb/tools/waiter.cpp: aligned the parsing of connectstring, retries for connect, allocation of nodeid for all cluster nodes removed all dependencies of LocalConfig, except for mgmapi internals --- client/Makefile.am | 1 + client/{mysqladmin.c => mysqladmin.cc} | 3 - configure.in | 1 - ndb/include/mgmapi/mgmapi.h | 30 +++- ndb/include/mgmcommon/ConfigRetriever.hpp | 26 +-- ndb/include/ndbapi/ndb_cluster_connection.hpp | 2 - ndb/src/common/mgmcommon/ConfigRetriever.cpp | 163 ++++++++---------- ndb/src/kernel/main.cpp | 12 +- ndb/src/kernel/vm/Configuration.cpp | 34 ++-- ndb/src/kernel/vm/Configuration.hpp | 3 +- ndb/src/mgmapi/LocalConfig.cpp | 17 +- ndb/{include => src}/mgmapi/LocalConfig.hpp | 1 + ndb/src/mgmapi/mgmapi.cpp | 138 ++++++++++----- ndb/src/mgmclient/CommandInterpreter.cpp | 30 +--- ndb/src/mgmclient/main.cpp | 3 +- ndb/src/mgmclient/ndb_mgmclient.h | 2 +- ndb/src/mgmclient/ndb_mgmclient.hpp | 2 +- ndb/src/mgmsrv/MgmtSrvr.cpp | 109 +++++++----- ndb/src/mgmsrv/MgmtSrvr.hpp | 13 +- ndb/src/mgmsrv/MgmtSrvrConfig.cpp | 18 +- ndb/src/mgmsrv/main.cpp | 54 +----- ndb/src/ndbapi/ndb_cluster_connection.cpp | 30 ++-- ndb/tools/waiter.cpp | 46 ++--- 23 files changed, 358 insertions(+), 380 deletions(-) rename client/{mysqladmin.c => mysqladmin.cc} (99%) rename ndb/{include => src}/mgmapi/LocalConfig.hpp (97%) diff --git a/client/Makefile.am b/client/Makefile.am index 1c552036f9b..07167d97df5 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -28,6 +28,7 @@ bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \ noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ client_priv.h mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc +mysqladmin_SOURCES = mysqladmin.cc mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) mysql_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) diff --git a/client/mysqladmin.c b/client/mysqladmin.cc similarity index 99% rename from client/mysqladmin.c rename to client/mysqladmin.cc index a32dfa14d28..a9fc3f31d03 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.cc @@ -1287,9 +1287,6 @@ static my_bool wait_pidfile(char *pidfile, time_t last_modified, } DBUG_RETURN(error); } -#ifdef HAVE_NDBCLUSTER_DB -/* lib linked in contains c++ code */ #ifdef __GNUC__ FIX_GCC_LINKING_PROBLEM #endif -#endif diff --git a/configure.in b/configure.in index f360ee46453..1fcba6b8f5f 100644 --- a/configure.in +++ b/configure.in @@ -399,7 +399,6 @@ then then if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1 then - CFLAGS="$CFLAGS -DDEFINE_CXA_PURE_VIRTUAL" CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL" fi fi diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index f1ef357421b..a4e1fc1d1a8 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -356,11 +356,28 @@ extern "C" { /** * Create a handle to a management server * - * @return A management handle
- * or NULL if no management handle could be created. + * @param connect_string Connect string to the management server, + * + * @return A management handle
+ * or NULL if no management handle could be created. */ NdbMgmHandle ndb_mgm_create_handle(); + /** + * Set connecst string to management server + * + * @param handle Management handle + * @param connect_string Connect string to the management server, + * + * @return -1 on error. + */ + int ndb_mgm_set_connectstring(NdbMgmHandle handle, + const char *connect_string); + + int ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle); + int ndb_mgm_get_connected_port(NdbMgmHandle handle); + const char *ndb_mgm_get_connected_host(NdbMgmHandle handle); + /** * Destroy a management server handle * @@ -378,11 +395,10 @@ extern "C" { * Connect to a management server * * @param handle Management handle. - * @param mgmsrv Hostname and port of the management server, - * "hostname:port". * @return -1 on error. */ - int ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv); + int ndb_mgm_connect(NdbMgmHandle handle, int no_retries, + int retry_delay_in_seconds, int verbose); /** * Disconnect from a management server @@ -709,9 +725,7 @@ extern "C" { void ndb_mgm_destroy_configuration(struct ndb_mgm_configuration *); int ndb_mgm_alloc_nodeid(NdbMgmHandle handle, - unsigned version, - unsigned *pnodeid, - int nodetype); + unsigned version, int nodetype); /** * Config iterator */ diff --git a/ndb/include/mgmcommon/ConfigRetriever.hpp b/ndb/include/mgmcommon/ConfigRetriever.hpp index 6c32255e921..80449628867 100644 --- a/ndb/include/mgmcommon/ConfigRetriever.hpp +++ b/ndb/include/mgmcommon/ConfigRetriever.hpp @@ -20,7 +20,6 @@ #include #include #include -#include /** * @class ConfigRetriever @@ -28,10 +27,11 @@ */ class ConfigRetriever { public: - ConfigRetriever(LocalConfig &local_config, Uint32 version, Uint32 nodeType); + ConfigRetriever(const char * _connect_string, + Uint32 version, Uint32 nodeType); ~ConfigRetriever(); - int do_connect(int exit_on_connect_failure= false); + int do_connect(int no_retries, int retry_delay_in_seconds, int verbose); /** * Get configuration for current node. @@ -46,12 +46,14 @@ public: */ struct ndb_mgm_configuration * getConfig(); + void resetError(); + int hasError(); const char * getErrorString(); /** * @return Node id of this node (as stated in local config or connectString) */ - Uint32 allocNodeId(); + Uint32 allocNodeId(int no_retries, int retry_delay_in_seconds); /** * Get config using socket @@ -68,22 +70,26 @@ public: */ bool verifyConfig(const struct ndb_mgm_configuration *, Uint32 nodeid); - Uint32 get_mgmd_port() const {return m_mgmd_port;}; - const char *get_mgmd_host() const {return m_mgmd_host;}; + Uint32 get_mgmd_port() const; + const char *get_mgmd_host() const; + + Uint32 get_configuration_nodeid() const; private: BaseString errorString; enum ErrorType { - CR_ERROR = 0, - CR_RETRY = 1 + CR_NO_ERROR = 0, + CR_ERROR = 1, + CR_RETRY = 2 }; ErrorType latestErrorType; void setError(ErrorType, const char * errorMsg); - struct LocalConfig& _localConfig; - Uint32 _ownNodeId; + Uint32 _ownNodeId; + /* Uint32 m_mgmd_port; const char *m_mgmd_host; + */ Uint32 m_version; Uint32 m_node_type; diff --git a/ndb/include/ndbapi/ndb_cluster_connection.hpp b/ndb/include/ndbapi/ndb_cluster_connection.hpp index f8e6f25ce73..59d5a038844 100644 --- a/ndb/include/ndbapi/ndb_cluster_connection.hpp +++ b/ndb/include/ndbapi/ndb_cluster_connection.hpp @@ -19,7 +19,6 @@ #define CLUSTER_CONNECTION_HPP class TransporterFacade; -class LocalConfig; class ConfigRetriever; class NdbThread; @@ -38,7 +37,6 @@ private: void connect_thread(); char *m_connect_string; TransporterFacade *m_facade; - LocalConfig *m_local_config; ConfigRetriever *m_config_retriever; NdbThread *m_connect_thread; int (*m_connect_callback)(void); diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp index a1b979f62d8..0af5eb2f83c 100644 --- a/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -20,7 +20,6 @@ #include #include -#include "LocalConfig.hpp" #include #include @@ -45,90 +44,62 @@ //**************************************************************************** //**************************************************************************** -ConfigRetriever::ConfigRetriever(LocalConfig &local_config, +ConfigRetriever::ConfigRetriever(const char * _connect_string, Uint32 version, Uint32 node_type) - : _localConfig(local_config) { - m_handle= 0; m_version = version; m_node_type = node_type; - _ownNodeId = _localConfig._ownNodeId; + _ownNodeId= 0; + + m_handle= ndb_mgm_create_handle(); + + if (m_handle == 0) { + setError(CR_ERROR, "Unable to allocate mgm handle"); + return; + } + + if (ndb_mgm_set_connectstring(m_handle, _connect_string)) + { + setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); + return; + } + resetError(); } -ConfigRetriever::~ConfigRetriever(){ - +ConfigRetriever::~ConfigRetriever() +{ if (m_handle) { ndb_mgm_disconnect(m_handle); ndb_mgm_destroy_handle(&m_handle); } } +Uint32 +ConfigRetriever::get_configuration_nodeid() const +{ + return ndb_mgm_get_configuration_nodeid(m_handle); +} + +Uint32 ConfigRetriever::get_mgmd_port() const +{ + return ndb_mgm_get_connected_port(m_handle); +} + +const char *ConfigRetriever::get_mgmd_host() const +{ + return ndb_mgm_get_connected_host(m_handle); +} //**************************************************************************** //**************************************************************************** int -ConfigRetriever::do_connect(int exit_on_connect_failure){ - - m_mgmd_port= 0; - m_mgmd_host= 0; - - if(!m_handle) - m_handle= ndb_mgm_create_handle(); - - if (m_handle == 0) { - setError(CR_ERROR, "Unable to allocate mgm handle"); - return -1; - } - - int retry = 1; - int retry_max = 12; // Max number of retry attempts - int retry_interval= 5; // Seconds between each retry - while(retry < retry_max){ - Uint32 type = CR_ERROR; - BaseString tmp; - for (unsigned int i = 0; i<_localConfig.ids.size(); i++){ - MgmtSrvrId * m = &_localConfig.ids[i]; - DBUG_PRINT("info",("trying %s:%d", - m->name.c_str(), - m->port)); - switch(m->type){ - case MgmId_TCP: - tmp.assfmt("%s:%d", m->name.c_str(), m->port); - if (ndb_mgm_connect(m_handle, tmp.c_str()) == 0) { - m_mgmd_port= m->port; - m_mgmd_host= m->name.c_str(); - DBUG_PRINT("info",("connected to ndb_mgmd at %s:%d", - m_mgmd_host, - m_mgmd_port)); - return 0; - } - setError(CR_RETRY, ndb_mgm_get_latest_error_desc(m_handle)); - case MgmId_File: - break; - } - } - if(latestErrorType == CR_RETRY){ - DBUG_PRINT("info",("CR_RETRY")); - if (exit_on_connect_failure) - return 1; - REPORT_WARNING("Failed to retrieve cluster configuration"); - ndbout << "(Cause of failure: " << getErrorString() << ")" << endl; - ndbout << "Attempt " << retry << " of " << retry_max << ". " - << "Trying again in "<< retry_interval <<" seconds..." - << endl << endl; - NdbSleep_SecSleep(retry_interval); - } else { - break; - } - retry++; - } - - ndb_mgm_destroy_handle(&m_handle); - m_handle= 0; - m_mgmd_port= 0; - m_mgmd_host= 0; - return -1; +ConfigRetriever::do_connect(int no_retries, + int retry_delay_in_seconds, int verbose) +{ + return + (ndb_mgm_connect(m_handle,no_retries,retry_delay_in_seconds,verbose)==0) ? + 0 : -1; } //**************************************************************************** @@ -140,22 +111,9 @@ ConfigRetriever::getConfig() { struct ndb_mgm_configuration * p = 0; - if(m_handle != 0){ + if(m_handle != 0) p = getConfig(m_handle); - } else { - for (unsigned int i = 0; i<_localConfig.ids.size(); i++){ - MgmtSrvrId * m = &_localConfig.ids[i]; - switch(m->type){ - case MgmId_File: - p = getConfig(m->name.c_str()); - break; - case MgmId_TCP: - break; - } - if(p) - break; - } - } + if(p == 0) return 0; @@ -227,6 +185,16 @@ ConfigRetriever::setError(ErrorType et, const char * s){ latestErrorType = et; } +void +ConfigRetriever::resetError(){ + setError(CR_NO_ERROR,0); +} + +int +ConfigRetriever::hasError() +{ + return latestErrorType != CR_NO_ERROR; +} const char * ConfigRetriever::getErrorString(){ @@ -341,16 +309,23 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 } Uint32 -ConfigRetriever::allocNodeId(){ - unsigned nodeid= _ownNodeId; - - if(m_handle != 0){ - int res= ndb_mgm_alloc_nodeid(m_handle, m_version, &nodeid, m_node_type); - if(res != 0) { - setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); - return 0; +ConfigRetriever::allocNodeId(int no_retries, int retry_delay_in_seconds) +{ + _ownNodeId= 0; + if(m_handle != 0) + { + while (1) + { + int res= ndb_mgm_alloc_nodeid(m_handle, m_version, m_node_type); + if(res >= 0) + return _ownNodeId= (Uint32)res; + if (no_retries == 0) + break; + no_retries--; + NdbSleep_SecSleep(retry_delay_in_seconds); } - } - - return _ownNodeId= nodeid; + setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); + } else + setError(CR_ERROR, "management server handle not initialized"); + return 0; } diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 926647838c9..f34e16318cd 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -19,7 +19,6 @@ #include #include "Configuration.hpp" -#include #include #include "vm/SimBlockList.hpp" @@ -69,16 +68,9 @@ int main(int argc, char** argv) return NRT_Default; } - LocalConfig local_config; - if (!local_config.init(theConfig->getConnectString(),0)){ - local_config.printError(); - local_config.printUsage(); - return NRT_Default; - } - { // Do configuration signal(SIGPIPE, SIG_IGN); - theConfig->fetch_configuration(local_config); + theConfig->fetch_configuration(); } chdir(NdbConfig_get_path(0)); @@ -141,7 +133,7 @@ int main(int argc, char** argv) exit(0); } g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); - theConfig->fetch_configuration(local_config); + theConfig->fetch_configuration(); } g_eventLogger.info("Angel pid: %d ndb pid: %d", getppid(), getpid()); diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index b3a436275f7..9019782f4db 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -17,7 +17,6 @@ #include #include -#include #include "Configuration.hpp" #include #include "GlobalData.hpp" @@ -189,7 +188,7 @@ Configuration::closeConfiguration(){ } void -Configuration::fetch_configuration(LocalConfig &local_config){ +Configuration::fetch_configuration(){ /** * Fetch configuration from management server */ @@ -199,8 +198,17 @@ Configuration::fetch_configuration(LocalConfig &local_config){ m_mgmd_port= 0; m_mgmd_host= 0; - m_config_retriever= new ConfigRetriever(local_config, NDB_VERSION, NODE_TYPE_DB); - if(m_config_retriever->do_connect() == -1){ + m_config_retriever= new ConfigRetriever(getConnectString(), + NDB_VERSION, NODE_TYPE_DB); + + if (m_config_retriever->hasError()) + { + ERROR_SET(fatal, ERR_INVALID_CONFIG, + "Could not connect initialize handle to management server", + m_config_retriever->getErrorString()); + } + + if(m_config_retriever->do_connect(12,5,1) == -1){ const char * s = m_config_retriever->getErrorString(); if(s == 0) s = "No error given!"; @@ -215,13 +223,7 @@ Configuration::fetch_configuration(LocalConfig &local_config){ ConfigRetriever &cr= *m_config_retriever; - if((globalData.ownId = cr.allocNodeId()) == 0){ - for(Uint32 i = 0; i<3; i++){ - NdbSleep_SecSleep(3); - if((globalData.ownId = cr.allocNodeId()) != 0) - break; - } - } + globalData.ownId = cr.allocNodeId(2 /*retry*/,3 /*delay*/); if(globalData.ownId == 0){ ERROR_SET(fatal, ERR_INVALID_CONFIG, @@ -599,7 +601,8 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ Uint32 noOfTCScanRecords = noOfScanRecords; { - Uint32 noOfAccTables= noOfTables + noOfUniqueHashIndexes; + Uint32 noOfAccTables= noOfTables + noOfUniqueHashIndexes * + noOfOrderedIndexes /* should be removed */; /** * Acc Size Alt values */ @@ -758,13 +761,14 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ * Tux Size Alt values */ cfg.put(CFG_TUX_INDEX, - noOfOrderedIndexes); + noOfMetaTables /*noOfOrderedIndexes*/); cfg.put(CFG_TUX_FRAGMENT, - 2 * NO_OF_FRAG_PER_NODE * noOfOrderedIndexes * noOfReplicas); + 2 * NO_OF_FRAG_PER_NODE * noOfMetaTables /*noOfOrderedIndexes*/ * + noOfReplicas); cfg.put(CFG_TUX_ATTRIBUTE, - noOfOrderedIndexes * 4); + noOfMetaTables /*noOfOrderedIndexes*/ * 4); cfg.put(CFG_TUX_SCAN_OP, noOfLocalScanRecords); } diff --git a/ndb/src/kernel/vm/Configuration.hpp b/ndb/src/kernel/vm/Configuration.hpp index e4cd64f5ca8..acf0e163a84 100644 --- a/ndb/src/kernel/vm/Configuration.hpp +++ b/ndb/src/kernel/vm/Configuration.hpp @@ -21,7 +21,6 @@ #include class ConfigRetriever; -class LocalConfig; class Configuration { public: @@ -33,7 +32,7 @@ public: */ bool init(int argc, char** argv); - void fetch_configuration(LocalConfig &local_config); + void fetch_configuration(); void setupConfiguration(); void closeConfiguration(); diff --git a/ndb/src/mgmapi/LocalConfig.cpp b/ndb/src/mgmapi/LocalConfig.cpp index d0ff97cdedf..8f1e2ee8100 100644 --- a/ndb/src/mgmapi/LocalConfig.cpp +++ b/ndb/src/mgmapi/LocalConfig.cpp @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include "LocalConfig.hpp" #include #include #include @@ -294,4 +294,19 @@ LocalConfig::readConnectString(const char * connectString, return return_value; } +char * +LocalConfig::makeConnectString(char *buf, int sz) +{ + int p= BaseString::snprintf(buf,sz,"nodeid=%d", _ownNodeId); + for (int i = 0; (i < ids.size()) && (sz-p > 0); i++) + { + if (ids[i].type != MgmId_TCP) + continue; + p+=BaseString::snprintf(buf+p,sz-p,",%s:%d", + ids[i].name.c_str(), ids[i].port); + } + buf[sz-1]=0; + return buf; +} + template class Vector; diff --git a/ndb/include/mgmapi/LocalConfig.hpp b/ndb/src/mgmapi/LocalConfig.hpp similarity index 97% rename from ndb/include/mgmapi/LocalConfig.hpp rename to ndb/src/mgmapi/LocalConfig.hpp index 9ceeffdba36..c415ec1be91 100644 --- a/ndb/include/mgmapi/LocalConfig.hpp +++ b/ndb/src/mgmapi/LocalConfig.hpp @@ -61,6 +61,7 @@ struct LocalConfig { bool parseHostName(const char *buf); bool parseFileName(const char *buf); bool parseString(const char *buf, BaseString &err); + char * makeConnectString(char *buf, int sz); }; #endif // LocalConfig_H diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 51f2d7cee01..ca3a2a2186d 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "mgmapi.h" #include "mgmapi_debug.h" @@ -83,8 +84,8 @@ typedef Parser Parser_t; #define NDB_MGM_MAX_ERR_DESC_SIZE 256 struct ndb_mgm_handle { - char * hostname; - unsigned short port; + char * connectstring; + int cfg_i; int connected; int last_error; @@ -95,7 +96,7 @@ struct ndb_mgm_handle { NDB_SOCKET_TYPE socket; - char cfg_ptr[sizeof(LocalConfig)]; + LocalConfig cfg; #ifdef MGMAPI_LOG FILE* logfile; @@ -148,14 +149,16 @@ ndb_mgm_create_handle() h->connected = 0; h->last_error = 0; h->last_error_line = 0; - h->hostname = 0; h->socket = NDB_INVALID_SOCKET; h->read_timeout = 50000; h->write_timeout = 100; - - new (h->cfg_ptr) LocalConfig; + h->cfg_i = 0; strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE); + + new (&(h->cfg)) LocalConfig; + h->cfg.init(0, 0); + #ifdef MGMAPI_LOG h->logfile = 0; #endif @@ -163,6 +166,23 @@ ndb_mgm_create_handle() return h; } +extern "C" +int +ndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv) +{ + new (&(handle->cfg)) LocalConfig; + if (!handle->cfg.init(mgmsrv, 0) || + handle->cfg.ids.size() == 0) + { + new (&(handle->cfg)) LocalConfig; + handle->cfg.init(0, 0); /* reset the LocalCongig */ + SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, ""); + return -1; + } + handle->cfg_i= 0; + return 0; +} + /** * Destroy a handle */ @@ -175,14 +195,13 @@ ndb_mgm_destroy_handle(NdbMgmHandle * handle) if((* handle)->connected){ ndb_mgm_disconnect(* handle); } - my_free((* handle)->hostname,MYF(MY_ALLOW_ZERO_PTR)); #ifdef MGMAPI_LOG if ((* handle)->logfile != 0){ fclose((* handle)->logfile); (* handle)->logfile = 0; } #endif - ((LocalConfig*)((*handle)->cfg_ptr))->~LocalConfig(); + (*handle)->cfg.~LocalConfig(); my_free((char*)* handle,MYF(MY_ALLOW_ZERO_PTR)); * handle = 0; } @@ -314,7 +333,8 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, */ extern "C" int -ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv) +ndb_mgm_connect(NdbMgmHandle handle, int no_retries, + int retry_delay_in_seconds, int verbose) { SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect"); CHECK_HANDLE(handle, -1); @@ -331,36 +351,48 @@ ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv) /** * Do connect */ - LocalConfig *cfg= (LocalConfig*)(handle->cfg_ptr); - new (cfg) LocalConfig; - if (!cfg->init(mgmsrv, 0) || - cfg->ids.size() == 0) - { - SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, ""); - return -1; - } - + LocalConfig &cfg= handle->cfg; NDB_SOCKET_TYPE sockfd= NDB_INVALID_SOCKET; Uint32 i; - for (i = 0; i < cfg->ids.size(); i++) + while (sockfd == NDB_INVALID_SOCKET) { - if (cfg->ids[i].type != MgmId_TCP) - continue; - SocketClient s(cfg->ids[i].name.c_str(), cfg->ids[i].port); - sockfd = s.connect(); + // do all the mgmt servers + for (i = 0; i < cfg.ids.size(); i++) + { + if (cfg.ids[i].type != MgmId_TCP) + continue; + SocketClient s(cfg.ids[i].name.c_str(), cfg.ids[i].port); + sockfd = s.connect(); + if (sockfd != NDB_INVALID_SOCKET) + break; + } if (sockfd != NDB_INVALID_SOCKET) break; - } - if (sockfd == NDB_INVALID_SOCKET) - { - setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, - "Unable to connect using connectstring %s", mgmsrv); - return -1; + if (verbose > 0) { + char buf[1024]; + ndbout_c("Unable to connect with connect string: %s", + cfg.makeConnectString(buf,sizeof(buf))); + verbose= -1; + } + if (no_retries == 0) { + char buf[1024]; + setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, + "Unable to connect with connect string: %s", + cfg.makeConnectString(buf,sizeof(buf))); + return -1; + } + if (verbose == -1) { + ndbout << "retrying every " << retry_delay_in_seconds << " seconds:"; + verbose= -2; + } + NdbSleep_SecSleep(retry_delay_in_seconds); + if (verbose == -2) { + ndbout << " " << no_retries; + } + no_retries--; } - my_free(handle->hostname,MYF(MY_ALLOW_ZERO_PTR)); - handle->hostname = my_strdup(cfg->ids[i].name.c_str(),MYF(MY_WME)); - handle->port = cfg->ids[i].port; + handle->cfg_i = i; handle->socket = sockfd; handle->connected = 1; @@ -1068,7 +1100,9 @@ ndb_mgm_listen_event(NdbMgmHandle handle, int filter[]) }; CHECK_HANDLE(handle, -1); - SocketClient s(handle->hostname, handle->port); + const char *hostname= ndb_mgm_get_connected_host(handle); + int port= ndb_mgm_get_connected_port(handle); + SocketClient s(hostname, port); const NDB_SOCKET_TYPE sockfd = s.connect(); if (sockfd < 0) { setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, @@ -1613,16 +1647,37 @@ ndb_mgm_destroy_configuration(struct ndb_mgm_configuration *cfg) extern "C" int -ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, unsigned *pnodeid, int nodetype) +ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle) { + CHECK_HANDLE(handle, 0); + return handle->cfg._ownNodeId; +} +extern "C" +int ndb_mgm_get_connected_port(NdbMgmHandle handle) +{ + return handle->cfg.ids[handle->cfg_i].port; +} + +extern "C" +const char *ndb_mgm_get_connected_host(NdbMgmHandle handle) +{ + return handle->cfg.ids[handle->cfg_i].name.c_str(); +} + +extern "C" +int +ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, int nodetype) +{ CHECK_HANDLE(handle, 0); CHECK_CONNECTED(handle, 0); + int nodeid= handle->cfg._ownNodeId; + Properties args; args.put("version", version); args.put("nodetype", nodetype); - args.put("nodeid", *pnodeid); + args.put("nodeid", nodeid); args.put("user", "mysqld"); args.put("password", "mysqld"); args.put("public key", "a public key"); @@ -1638,26 +1693,29 @@ ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, unsigned *pnodei prop= ndb_mgm_call(handle, reply, "get nodeid", &args); CHECK_REPLY(prop, -1); - int res= -1; + nodeid= -1; do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ + const char *hostname= ndb_mgm_get_connected_host(handle); + unsigned port= ndb_mgm_get_connected_port(handle); BaseString err; err.assfmt("Could not alloc node id at %s port %d: %s", - handle->hostname, handle->port, buf); + hostname, port, buf); setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, err.c_str()); break; } - if(!prop->get("nodeid", pnodeid) != 0){ + Uint32 _nodeid; + if(!prop->get("nodeid", &_nodeid) != 0){ ndbout_c("ERROR Message: \n"); break; } - res= 0; + nodeid= _nodeid; }while(0); delete prop; - return res; + return nodeid; } /***************************************************************************** diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index d940f6e165a..00e0a8c1919 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -153,7 +153,6 @@ private: NdbMgmHandle m_mgmsrv; bool connected; - const char *host; int try_reconnect; #ifdef HAVE_GLOBAL_REPLICATION NdbRepHandle m_repserver; @@ -193,7 +192,7 @@ extern "C" { { return (Ndb_mgmclient_handle) new Ndb_mgmclient(connect_string); } - int ndb_mgmclient_execute(Ndb_mgmclient_handle h, int argc, const char** argv) + int ndb_mgmclient_execute(Ndb_mgmclient_handle h, int argc, char** argv) { return ((Ndb_mgmclient*)h)->execute(argc, argv, 1); } @@ -226,7 +225,7 @@ extern "C" { #include #include -int Ndb_mgmclient::execute(int argc, const char** argv, int _try_reconnect) +int Ndb_mgmclient::execute(int argc, char** argv, int _try_reconnect) { if (argc <= 0) return 0; @@ -379,15 +378,16 @@ CommandInterpreter::CommandInterpreter(const char *_host) m_mgmsrv = ndb_mgm_create_handle(); if(m_mgmsrv == NULL) { ndbout_c("Cannot create handle to management server."); + exit(-1); + } + if (ndb_mgm_set_connectstring(m_mgmsrv, _host)) + { printError(); + exit(-1); } connected = false; try_reconnect = 0; - if (_host) - host= my_strdup(_host,MYF(MY_WME)); - else - host= 0; #ifdef HAVE_GLOBAL_REPLICATION rep_host = NULL; m_repserver = NULL; @@ -402,8 +402,6 @@ CommandInterpreter::~CommandInterpreter() { connected = false; ndb_mgm_destroy_handle(&m_mgmsrv); - my_free((char *)host,MYF(MY_ALLOW_ZERO_PTR)); - host = NULL; } static bool @@ -438,18 +436,8 @@ bool CommandInterpreter::connect() { if(!connected) { - int tries = try_reconnect; // tries == 0 => infinite - while(!connected) { - if(ndb_mgm_connect(m_mgmsrv, host) == -1) { - ndbout << "Cannot connect to management server (" << host << ")."; - tries--; - if (tries == 0) - break; - ndbout << "Retrying in 5 seconds." << endl; - NdbSleep_SecSleep(5); - } else - connected = true; - } + if(!ndb_mgm_connect(m_mgmsrv, try_reconnect-1, 5, 1)) + connected = true; } return connected; } diff --git a/ndb/src/mgmclient/main.cpp b/ndb/src/mgmclient/main.cpp index 401a9198f30..e2de4b277a9 100644 --- a/ndb/src/mgmclient/main.cpp +++ b/ndb/src/mgmclient/main.cpp @@ -30,9 +30,10 @@ extern "C" int add_history(const char *command); /* From readline directory */ #include #include +#include +#include #include #include -#include #include "ndb_mgmclient.hpp" diff --git a/ndb/src/mgmclient/ndb_mgmclient.h b/ndb/src/mgmclient/ndb_mgmclient.h index 265e6bc67ec..b62a33999a3 100644 --- a/ndb/src/mgmclient/ndb_mgmclient.h +++ b/ndb/src/mgmclient/ndb_mgmclient.h @@ -23,7 +23,7 @@ extern "C" { typedef void* Ndb_mgmclient_handle; Ndb_mgmclient_handle ndb_mgmclient_handle_create(const char *connect_string); -int ndb_mgmclient_execute(Ndb_mgmclient_handle, int argc, const char** argv); +int ndb_mgmclient_execute(Ndb_mgmclient_handle, int argc, char** argv); int ndb_mgmclient_handle_destroy(Ndb_mgmclient_handle); #ifdef __cplusplus diff --git a/ndb/src/mgmclient/ndb_mgmclient.hpp b/ndb/src/mgmclient/ndb_mgmclient.hpp index 933d1bab5ce..f6bcebc3896 100644 --- a/ndb/src/mgmclient/ndb_mgmclient.hpp +++ b/ndb/src/mgmclient/ndb_mgmclient.hpp @@ -24,7 +24,7 @@ public: Ndb_mgmclient(const char*); ~Ndb_mgmclient(); int execute(const char *_line, int _try_reconnect=-1); - int execute(int argc, const char** argv, int _try_reconnect=-1); + int execute(int argc, char** argv, int _try_reconnect=-1); int disconnect(); private: CommandInterpreter *m_cmd; diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index a49b29af275..81b5eb9dfb3 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -399,16 +399,20 @@ MgmtSrvr::getPort() const { } /* Constructor */ -MgmtSrvr::MgmtSrvr(NodeId nodeId, - SocketServer *socket_server, - const BaseString &configFilename, - LocalConfig &local_config, - Config * config): +int MgmtSrvr::init() +{ + if ( _ownNodeId > 0) + return 0; + return -1; +} + +MgmtSrvr::MgmtSrvr(SocketServer *socket_server, + const char *config_filename, + const char *connect_string) : _blockNumber(1), // Hard coded block number since it makes it easy to send // signals to other management servers. m_socket_server(socket_server), _ownReference(0), - m_local_config(local_config), theSignalIdleList(NULL), theWaitState(WAIT_SUBSCRIBE_CONF), m_statisticsListner(this) @@ -416,6 +420,8 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, DBUG_ENTER("MgmtSrvr::MgmtSrvr"); + _ownNodeId= 0; + _config = NULL; _isStopThread = false; @@ -426,12 +432,43 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, theFacade = 0; m_newConfig = NULL; - m_configFilename = configFilename; + m_configFilename.assign(config_filename); m_nextConfigGenerationNumber = 0; - _config = (config == 0 ? readConfig() : config); - + m_config_retriever= new ConfigRetriever(connect_string, + NDB_VERSION, NDB_MGM_NODE_TYPE_MGM); + + // first try to allocate nodeid from another management server + if(m_config_retriever->do_connect(0,0,0) == 0) + { + int tmp_nodeid= 0; + tmp_nodeid= m_config_retriever->allocNodeId(0 /*retry*/,0 /*delay*/); + if (tmp_nodeid == 0) + { + ndbout_c(m_config_retriever->getErrorString()); + exit(-1); + } + // read config from other managent server + _config= fetchConfig(); + if (_config == 0) + { + ndbout << m_config_retriever->getErrorString() << endl; + exit(-1); + } + _ownNodeId= tmp_nodeid; + } + + if (_ownNodeId == 0) + { + // read config locally + _config= readConfig(); + if (_config == 0) { + ndbout << "Unable to read config file" << endl; + exit(-1); + } + } + theMgmtWaitForResponseCondPtr = NdbCondition_Create(); m_configMutex = NdbMutex_Create(); @@ -443,9 +480,11 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, nodeTypes[i] = (enum ndb_mgm_node_type)-1; m_connect_address[i].s_addr= 0; } + { - ndb_mgm_configuration_iterator * iter = ndb_mgm_create_configuration_iterator - (config->m_configValues, CFG_SECTION_NODE); + ndb_mgm_configuration_iterator + *iter = ndb_mgm_create_configuration_iterator(_config->m_configValues, + CFG_SECTION_NODE); for(ndb_mgm_first(iter); ndb_mgm_valid(iter); ndb_mgm_next(iter)){ unsigned type, id; if(ndb_mgm_get_int_parameter(iter, CFG_TYPE_OF_SECTION, &type) != 0) @@ -478,8 +517,6 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, } _props = NULL; - _ownNodeId= 0; - NodeId tmp= nodeId; BaseString error_string; if ((m_node_id_mutex = NdbMutex_Create()) == 0) @@ -488,43 +525,25 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, exit(-1); } -#if 0 - char my_hostname[256]; - struct sockaddr_in tmp_addr; - SOCKET_SIZE_TYPE addrlen= sizeof(tmp_addr); - if (!g_no_nodeid_checks) { - if (gethostname(my_hostname, sizeof(my_hostname))) { - ndbout << "error: gethostname() - " << strerror(errno) << endl; - exit(-1); - } - if (Ndb_getInAddr(&(((sockaddr_in*)&tmp_addr)->sin_addr),my_hostname)) { - ndbout << "error: Ndb_getInAddr(" << my_hostname << ") - " - << strerror(errno) << endl; + if (_ownNodeId == 0) // we did not get node id from other server + { + NodeId tmp= m_config_retriever->get_configuration_nodeid(); + + if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM, + 0, 0, error_string)){ + ndbout << "Unable to obtain requested nodeid: " + << error_string.c_str() << endl; exit(-1); } + _ownNodeId = tmp; } - if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM, - (struct sockaddr *)&tmp_addr, - &addrlen, error_string)){ - ndbout << "Unable to obtain requested nodeid: " - << error_string.c_str() << endl; - exit(-1); - } -#else - if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM, - 0, 0, error_string)){ - ndbout << "Unable to obtain requested nodeid: " - << error_string.c_str() << endl; - exit(-1); - } -#endif - _ownNodeId = tmp; { DBUG_PRINT("info", ("verifyConfig")); - ConfigRetriever cr(m_local_config, NDB_VERSION, NDB_MGM_NODE_TYPE_MGM); - if (!cr.verifyConfig(config->m_configValues, _ownNodeId)) { - ndbout << cr.getErrorString() << endl; + if (!m_config_retriever->verifyConfig(_config->m_configValues, + _ownNodeId)) + { + ndbout << m_config_retriever->getErrorString() << endl; exit(-1); } } @@ -657,6 +676,8 @@ MgmtSrvr::~MgmtSrvr() NdbThread_WaitFor(m_signalRecvThread, &res); NdbThread_Destroy(&m_signalRecvThread); } + if (m_config_retriever) + delete m_config_retriever; } //**************************************************************************** diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp index b3257491123..2ab11250d81 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -175,11 +175,10 @@ public: /* Constructor */ - MgmtSrvr(NodeId nodeId, /* Local nodeid */ - SocketServer *socket_server, - const BaseString &config_filename, /* Where to save config */ - LocalConfig &local_config, /* Ndb.cfg filename */ - Config * config); + MgmtSrvr(SocketServer *socket_server, + const char *config_filename, /* Where to save config */ + const char *connect_string); + int init(); NodeId getOwnNodeId() const {return _ownNodeId;}; /** @@ -538,7 +537,6 @@ private: NdbMutex *m_configMutex; const Config * _config; Config * m_newConfig; - LocalConfig &m_local_config; BaseString m_configFilename; Uint32 m_nextConfigGenerationNumber; @@ -755,6 +753,9 @@ private: Config *_props; int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type); + + ConfigRetriever *m_config_retriever; + public: /** * This method does not exist diff --git a/ndb/src/mgmsrv/MgmtSrvrConfig.cpp b/ndb/src/mgmsrv/MgmtSrvrConfig.cpp index 1d51061e909..6c4b4e9ae3c 100644 --- a/ndb/src/mgmsrv/MgmtSrvrConfig.cpp +++ b/ndb/src/mgmsrv/MgmtSrvrConfig.cpp @@ -272,30 +272,20 @@ MgmtSrvr::saveConfig(const Config *conf) { Config * MgmtSrvr::readConfig() { - Config *conf = NULL; - if(m_configFilename.length() != 0) { - /* Use config file */ - InitConfigFileParser parser; - conf = parser.parseConfig(m_configFilename.c_str()); - - if(conf == NULL) { - /* Try to get configuration from other MGM server */ - return fetchConfig(); - } - } + Config *conf; + InitConfigFileParser parser; + conf = parser.parseConfig(m_configFilename.c_str()); return conf; } Config * MgmtSrvr::fetchConfig() { - ConfigRetriever cr(m_local_config, NDB_VERSION, NODE_TYPE_MGM); - struct ndb_mgm_configuration * tmp = cr.getConfig(); + struct ndb_mgm_configuration * tmp = m_config_retriever->getConfig(); if(tmp != 0){ Config * conf = new Config(); conf->m_configValues = tmp; return conf; } - return 0; } diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 76f0679b069..625a303f7c0 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -62,7 +62,6 @@ struct MgmGlobals { int non_interactive; int interactive; const char * config_filename; - const char * local_config_filename; /** Stuff found in environment or in local config */ NodeId localNodeId; @@ -70,9 +69,6 @@ struct MgmGlobals { char * interface_name; int port; - /** The configuration of the cluster */ - Config * cluster_config; - /** The Mgmt Server */ MgmtSrvr * mgmObject; @@ -86,9 +82,6 @@ static MgmGlobals glob; /****************************************************************************** * Function prototypes ******************************************************************************/ -static bool readLocalConfig(); -static bool readGlobalConfig(); - /** * Global variables */ @@ -122,9 +115,6 @@ static struct my_option my_long_options[] = { "daemon", 'd', "Run ndb_mgmd in daemon mode (default)", (gptr*) &glob.daemon, (gptr*) &glob.daemon, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, - { "l", 'l', "Specify configuration file connect string (default Ndb.cfg if available)", - (gptr*) &glob.local_config_filename, (gptr*) &glob.local_config_filename, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "interactive", 256, "Run interactive. Not supported but provided for testing purposes", (gptr*) &glob.interactive, (gptr*) &glob.interactive, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, @@ -212,29 +202,16 @@ int main(int argc, char** argv) MgmApiService * mapi = new MgmApiService(); - /**************************** - * Read configuration files * - ****************************/ - LocalConfig local_config; - if(!local_config.init(opt_connect_str,glob.local_config_filename)){ - local_config.printError(); - goto error_end; - } - glob.localNodeId = local_config._ownNodeId; + glob.mgmObject = new MgmtSrvr(glob.socketServer, + glob.config_filename, + opt_connect_str); - if (!readGlobalConfig()) + if (glob.mgmObject->init()) goto error_end; - glob.mgmObject = new MgmtSrvr(glob.localNodeId, glob.socketServer, - BaseString(glob.config_filename), - local_config, - glob.cluster_config); - chdir(NdbConfig_get_path(0)); - glob.cluster_config = 0; glob.localNodeId= glob.mgmObject->getOwnNodeId(); - if (glob.localNodeId == 0) { goto error_end; } @@ -345,9 +322,7 @@ MgmGlobals::MgmGlobals(){ // Default values port = 0; config_filename = NULL; - local_config_filename = NULL; interface_name = 0; - cluster_config = 0; daemon = 1; non_interactive = 0; interactive = 0; @@ -360,27 +335,6 @@ MgmGlobals::~MgmGlobals(){ delete socketServer; if (mgmObject) delete mgmObject; - if (cluster_config) - delete cluster_config; if (interface_name) free(interface_name); } - -/** - * @fn readGlobalConfig - * @param glob : Global variables - * @return true if success, false otherwise. - */ -static bool -readGlobalConfig() { - if(glob.config_filename == NULL) - return false; - - /* Use config file */ - InitConfigFileParser parser; - glob.cluster_config = parser.parseConfig(glob.config_filename); - if(glob.cluster_config == 0){ - return false; - } - return true; -} diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 4c42fe1aeef..b2043b2c2c1 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -45,7 +45,6 @@ Ndb_cluster_connection::Ndb_cluster_connection(const char *connect_string) else m_connect_string= 0; m_config_retriever= 0; - m_local_config= 0; m_connect_thread= 0; m_connect_callback= 0; @@ -125,38 +124,31 @@ int Ndb_cluster_connection::connect(int reconnect) do { if (m_config_retriever == 0) { - if (m_local_config == 0) { - m_local_config= new LocalConfig(); - if (!m_local_config->init(m_connect_string,0)) { - ndbout_c("Configuration error: Unable to retrieve local config"); - m_local_config->printError(); - m_local_config->printUsage(); - DBUG_RETURN(-1); - } - } m_config_retriever= - new ConfigRetriever(*m_local_config, NDB_VERSION, NODE_TYPE_API); + new ConfigRetriever(m_connect_string, NDB_VERSION, NODE_TYPE_API); + if (m_config_retriever->hasError()) + { + printf("Could not connect initialize handle to management server", + m_config_retriever->getErrorString()); + DBUG_RETURN(-1); + } } else if (reconnect == 0) DBUG_RETURN(0); if (reconnect) { - int r= m_config_retriever->do_connect(1); + int r= m_config_retriever->do_connect(0,0,0); if (r == 1) DBUG_RETURN(1); // mgmt server not up yet if (r == -1) break; } else - if(m_config_retriever->do_connect() == -1) + if(m_config_retriever->do_connect(12,5,1) == -1) break; - Uint32 nodeId = m_config_retriever->allocNodeId(); - for(Uint32 i = 0; nodeId == 0 && i<5; i++){ - NdbSleep_SecSleep(3); - nodeId = m_config_retriever->allocNodeId(); - } + Uint32 nodeId = m_config_retriever->allocNodeId(4/*retries*/,3/*delay*/); if(nodeId == 0) break; ndb_mgm_configuration * props = m_config_retriever->getConfig(); @@ -200,8 +192,6 @@ Ndb_cluster_connection::~Ndb_cluster_connection() my_free(m_connect_string,MYF(MY_ALLOW_ZERO_PTR)); if (m_config_retriever) delete m_config_retriever; - if (m_local_config) - delete m_local_config; DBUG_VOID_RETURN; } diff --git a/ndb/tools/waiter.cpp b/ndb/tools/waiter.cpp index e24164ea807..cb694ae5877 100644 --- a/ndb/tools/waiter.cpp +++ b/ndb/tools/waiter.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include @@ -85,39 +84,8 @@ int main(int argc, char** argv){ char buf[255]; _hostName = argv[0]; - if (_hostName == NULL){ - LocalConfig lcfg; - if(!lcfg.init(opt_connect_str, 0)) - { - lcfg.printError(); - lcfg.printUsage(); - g_err << "Error parsing local config file" << endl; - return NDBT_ProgramExit(NDBT_FAILED); - } - - for (unsigned i = 0; itype){ - case MgmId_TCP: - snprintf(buf, 255, "%s:%d", m->name.c_str(), m->port); - _hostName = buf; - break; - case MgmId_File: - break; - default: - break; - } - if (_hostName != NULL) - break; - } - if (_hostName == NULL) - { - g_err << "No management servers configured in local config file" << endl; - return NDBT_ProgramExit(NDBT_FAILED); - } - } + if (_hostName == 0) + _hostName= opt_connect_str; if (_no_contact) { if (waitClusterStatus(_hostName, NDB_MGM_NODE_STATUS_NO_CONTACT, _timeout) != 0) @@ -210,13 +178,19 @@ waitClusterStatus(const char* _addr, int _nodes[MAX_NDB_NODES]; int _num_nodes = 0; - handle = ndb_mgm_create_handle(); + handle = ndb_mgm_create_handle(); if (handle == NULL){ g_err << "handle == NULL" << endl; return -1; } g_info << "Connecting to mgmsrv at " << _addr << endl; - if (ndb_mgm_connect(handle, _addr) == -1) { + if (ndb_mgm_set_connectstring(handle, _addr)) + { + MGMERR(handle); + g_err << "Connectstring " << _addr << " invalid" << endl; + return -1; + } + if (ndb_mgm_connect(handle,0,0,1)) { MGMERR(handle); g_err << "Connection to " << _addr << " failed" << endl; return -1; From 57b6bfc9cff184daf6f44a89dbbb9084a8e92032 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Nov 2004 19:07:14 +0000 Subject: [PATCH 06/48] bug#6684, error messages id wrong settings --- ndb/tools/restore/main.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/ndb/tools/restore/main.cpp b/ndb/tools/restore/main.cpp index 482212911cb..064fbad43a3 100644 --- a/ndb/tools/restore/main.cpp +++ b/ndb/tools/restore/main.cpp @@ -74,7 +74,7 @@ static struct my_option my_long_options[] = "No of parallel transactions during restore of data." "(parallelism can be 1 to 1024)", (gptr*) &ga_nParallelism, (gptr*) &ga_nParallelism, 0, - GET_INT, REQUIRED_ARG, 128, 0, 0, 0, 0, 0 }, + GET_INT, REQUIRED_ARG, 128, 1, 1024, 0, 1, 0 }, { "print", 256, "Print data and log to stdout", (gptr*) &_print, (gptr*) &_print, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, @@ -120,6 +120,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); + case 'n': + if (ga_nodeId == 0) + { + printf("Error in --nodeid|-n setting, see --help\n"); + exit(1); + } + case 'b': + if (ga_backupId == 0) + { + printf("Error in --backupid|-b setting, see --help\n"); + exit(1); + } case '?': usage(); exit(0); @@ -131,11 +143,8 @@ readArguments(int *pargc, char*** pargv) { const char *load_default_groups[]= { "ndb_tools","ndb_restore",0 }; load_defaults("my",load_default_groups,pargc,pargv); - if (handle_options(pargc, pargv, my_long_options, get_one_option) || - ga_nodeId == 0 || - ga_backupId == 0 || - ga_nParallelism < 1 || - ga_nParallelism >1024) { + if (handle_options(pargc, pargv, my_long_options, get_one_option)) + { exit(1); } @@ -343,7 +352,8 @@ main(int argc, char** argv) if (res < 0) { - err << "Restore: An error occured while restoring data. Exiting... res=" << res << endl; + err << "Restore: An error occured while restoring data. Exiting... " + << "res=" << res << endl; return -1; } @@ -369,7 +379,8 @@ main(int argc, char** argv) } if (res < 0) { - err << "Restore: An restoring the data log. Exiting... res=" << res << endl; + err << "Restore: An restoring the data log. Exiting... res=" + << res << endl; return -1; } logIter.validateFooter(); //not implemented From 6a87e0060d7e137e5d306237676ed07c44adf3ce Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Nov 2004 20:54:35 +0100 Subject: [PATCH 07/48] wl2077 moved inline to .hpp file --- ndb/src/kernel/blocks/dblqh/Dblqh.hpp | 19 +++ ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 54 +++---- ndb/src/kernel/blocks/dbtc/Dbtc.hpp | 11 +- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 80 ++++++---- ndb/src/kernel/blocks/suma/Suma.cpp | 2 +- ndb/src/ndbapi/NdbConnection.cpp | 6 - ndb/src/ndbapi/NdbConnectionScan.cpp | 24 +-- ndb/src/ndbapi/NdbScanOperation.cpp | 135 ++++++++++++----- ndb/test/include/HugoTransactions.hpp | 16 +- ndb/test/include/UtilTransactions.hpp | 4 +- ndb/test/ndbapi/testScan.cpp | 9 +- ndb/test/src/HugoTransactions.cpp | 170 ++++++++++++++++++++-- ndb/test/src/UtilTransactions.cpp | 23 +-- ndb/test/tools/create_index.cpp | 2 +- ndb/test/tools/hugoScanRead.cpp | 50 ++++++- ndb/tools/select_all.cpp | 7 +- 16 files changed, 439 insertions(+), 173 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index d6987f3e478..983fda9b7be 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -2925,4 +2925,23 @@ Dblqh::ScanRecord::check_scan_batch_completed() const (max_bytes > 0 && (m_curr_batch_size_bytes >= max_bytes)); } +inline +void +Dblqh::i_get_acc_ptr(ScanRecord* scanP, Uint32* &acc_ptr, Uint32 index) +{ + if (index == 0) { + acc_ptr= (Uint32*)&scanP->scan_acc_op_ptr[0]; + } else { + Uint32 attr_buf_index, attr_buf_rec; + + AttrbufPtr regAttrPtr; + jam(); + attr_buf_rec= (index + 31) / 32; + attr_buf_index= (index - 1) & 31; + regAttrPtr.i= scanP->scan_acc_op_ptr[attr_buf_rec]; + ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); + acc_ptr= (Uint32*)®AttrPtr.p->attrbuf[attr_buf_index]; + } +} + #endif diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index cd15ad0c3b2..e9e81d55488 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -7058,10 +7058,7 @@ void Dblqh::continueScanNextReqLab(Signal* signal) // Update timer on tcConnectRecord tcConnectptr.p->tcTimer = cLqhTimeOutCount; - init_acc_ptr_list(scanptr.p); - scanptr.p->m_curr_batch_size_rows = 0; - scanptr.p->m_curr_batch_size_bytes= 0; scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT; scanNextLoopLab(signal); }//Dblqh::continueScanNextReqLab() @@ -7260,22 +7257,32 @@ void Dblqh::scanLockReleasedLab(Signal* signal) tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); releaseActiveFrag(signal); + if (scanptr.p->scanReleaseCounter == scanptr.p->m_curr_batch_size_rows) { if ((scanptr.p->scanErrorCounter > 0) || (scanptr.p->scanCompletedStatus == ZTRUE)) { jam(); + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes = 0; closeScanLab(signal); } else if (scanptr.p->check_scan_batch_completed() && scanptr.p->scanLockHold != ZTRUE) { jam(); scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); + } else if (scanptr.p->m_last_row && !scanptr.p->scanLockHold) { + jam(); + closeScanLab(signal); + return; } else { jam(); /* - We came here after releasing locks after receiving SCAN_NEXTREQ from TC. We only - come here when scanHoldLock == ZTRUE - */ + * We came here after releasing locks after + * receiving SCAN_NEXTREQ from TC. We only come here + * when scanHoldLock == ZTRUE + */ + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes = 0; continueScanNextReqLab(signal); }//if } else if (scanptr.p->scanReleaseCounter < scanptr.p->m_curr_batch_size_rows) { @@ -7362,25 +7369,6 @@ Dblqh::init_acc_ptr_list(ScanRecord* scanP) scanP->scan_acc_index = 0; } -inline -void -Dblqh::i_get_acc_ptr(ScanRecord* scanP, Uint32* &acc_ptr, Uint32 index) -{ - if (index == 0) { - acc_ptr= (Uint32*)&scanP->scan_acc_op_ptr[0]; - } else { - Uint32 attr_buf_index, attr_buf_rec; - - AttrbufPtr regAttrPtr; - jam(); - attr_buf_rec= (index + 31) / 32; - attr_buf_index= (index - 1) & 31; - regAttrPtr.i= scanP->scan_acc_op_ptr[attr_buf_rec]; - ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); - acc_ptr= (Uint32*)®AttrPtr.p->attrbuf[attr_buf_index]; - } -} - Uint32 Dblqh::get_acc_ptr_from_scan_record(ScanRecord* scanP, Uint32 index, @@ -7904,6 +7892,13 @@ void Dblqh::nextScanConfScanLab(Signal* signal) /************************************************************* * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. ************************************************************ */ + if (!scanptr.p->scanLockHold) + { + jam(); + closeScanLab(signal); + return; + } + if (scanptr.p->scanCompletedStatus == ZTRUE) { if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { @@ -8404,8 +8399,6 @@ void Dblqh::tupScanCloseConfLab(Signal* signal) ScanFragRef::SignalLength, JBB); } else { jam(); - scanptr.p->m_curr_batch_size_rows = 0; - scanptr.p->m_curr_batch_size_bytes= 0; sendScanFragConf(signal, ZSCAN_FRAG_CLOSED); }//if finishScanrec(signal); @@ -8809,6 +8802,13 @@ void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted) conf->total_len= total_len; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGCONF, signal, ScanFragConf::SignalLength, JBB); + + if(!scanptr.p->scanLockHold) + { + jam(); + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes= 0; + } }//Dblqh::sendScanFragConf() /* ######################################################################### */ diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index a209df24c44..fb90ccc8c90 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -1054,9 +1054,8 @@ public: // Id of the ScanRecord this fragment scan belongs to Uint32 scanRec; - // The maximum number of operations that can be scanned before - // returning to TC - Uint16 scanFragConcurrency; + // The value of fragmentCompleted in the last received SCAN_FRAGCONF + Uint8 m_scan_frag_conf_status; inline void startFragTimer(Uint32 timeVal){ scanFragTimer = timeVal; @@ -1193,8 +1192,10 @@ public: // Number of operation records per scanned fragment // Number of operations in first batch // Max number of bytes per batch - Uint16 noOprecPerFrag; - Uint16 first_batch_size; + union { + Uint16 first_batch_size_rows; + Uint16 batch_size_rows; + }; Uint32 batch_byte_size; Uint32 scanRequestInfo; // ScanFrag format diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index d8b3ee10532..c7f467484bd 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -8646,9 +8646,9 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, scanptr.p->scanTableref = tabptr.i; scanptr.p->scanSchemaVersion = scanTabReq->tableSchemaVersion; scanptr.p->scanParallel = scanParallel; - scanptr.p->noOprecPerFrag = noOprecPerFrag; - scanptr.p->first_batch_size= scanTabReq->first_batch_size; - scanptr.p->batch_byte_size= scanTabReq->batch_byte_size; + scanptr.p->first_batch_size_rows = scanTabReq->first_batch_size; + scanptr.p->batch_byte_size = scanTabReq->batch_byte_size; + scanptr.p->batch_size_rows = noOprecPerFrag; Uint32 tmp = 0; const UintR ri = scanTabReq->requestInfo; @@ -8672,7 +8672,6 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, ndbrequire(list.seize(ptr)); ptr.p->scanRec = scanptr.i; ptr.p->scanFragId = 0; - ptr.p->scanFragConcurrency = noOprecPerFrag; ptr.p->m_apiPtr = cdata[i]; }//for @@ -9141,6 +9140,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) const ScanFragConf * const conf = (ScanFragConf*)&signal->theData[0]; const Uint32 noCompletedOps = conf->completedOps; + const Uint32 status = conf->fragmentCompleted; scanFragptr.i = conf->senderData; c_scan_frag_pool.getPtr(scanFragptr); @@ -9163,11 +9163,9 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE); - const Uint32 status = conf->fragmentCompleted; - if(scanptr.p->scanState == ScanRecord::CLOSING_SCAN){ jam(); - if(status == ZFALSE){ + if(status == 0){ /** * We have started closing = we sent a close -> ignore this */ @@ -9184,11 +9182,11 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) return; } - if(status == ZCLOSED && scanptr.p->scanNextFragId < scanptr.p->scanNoFrag){ + if(noCompletedOps == 0 && status != 0 && + scanptr.p->scanNextFragId < scanptr.p->scanNoFrag){ /** * Start on next fragment */ - ndbrequire(noCompletedOps == 0); scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; scanFragptr.p->startFragTimer(ctcTimer); @@ -9218,6 +9216,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) scanptr.p->m_queued_count++; } + scanFragptr.p->m_scan_frag_conf_status = status; scanFragptr.p->m_ops = noCompletedOps; scanFragptr.p->m_totalLen = total_len; scanFragptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY; @@ -9330,11 +9329,12 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) // Copy op ptrs so I dont overwrite them when sending... memcpy(signal->getDataPtrSend()+25, signal->getDataPtr()+4, 4 * len); - ScanFragNextReq * nextReq = (ScanFragNextReq*)&signal->theData[0]; - nextReq->closeFlag = ZFALSE; - nextReq->transId1 = apiConnectptr.p->transid[0]; - nextReq->transId2 = apiConnectptr.p->transid[1]; - nextReq->batch_size_bytes= scanP->batch_byte_size; + ScanFragNextReq tmp; + tmp.closeFlag = ZFALSE; + tmp.transId1 = apiConnectptr.p->transid[0]; + tmp.transId2 = apiConnectptr.p->transid[1]; + tmp.batch_size_rows = scanP->batch_size_rows; + tmp.batch_size_bytes = scanP->batch_byte_size; ScanFragList running(c_scan_frag_pool, scanP->m_running_scan_frags); ScanFragList delivered(c_scan_frag_pool, scanP->m_delivered_scan_frags); @@ -9344,15 +9344,37 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) c_scan_frag_pool.getPtr(scanFragptr); ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::DELIVERED); - scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; scanFragptr.p->startFragTimer(ctcTimer); - scanFragptr.p->m_ops = 0; - nextReq->senderData = scanFragptr.i; - nextReq->batch_size_rows= scanFragptr.p->scanFragConcurrency; - sendSignal(scanFragptr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, - ScanFragNextReq::SignalLength, JBB); + if(scanFragptr.p->m_scan_frag_conf_status) + { + /** + * last scan was complete + */ + jam(); + ndbrequire(scanptr.p->scanNextFragId < scanptr.p->scanNoFrag); + scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; + + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); + scanFragptr.p->scanFragId = scanptr.p->scanNextFragId++; + signal->theData[0] = tcConnectptr.p->dihConnectptr; + signal->theData[1] = scanFragptr.i; + signal->theData[2] = scanptr.p->scanTableref; + signal->theData[3] = scanFragptr.p->scanFragId; + sendSignal(cdihblockref, GSN_DIGETPRIMREQ, signal, 4, JBB); + } + else + { + jam(); + scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; + ScanFragNextReq * req = (ScanFragNextReq*)signal->getDataPtrSend(); + * req = tmp; + req->senderData = scanFragptr.i; + sendSignal(scanFragptr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, + ScanFragNextReq::SignalLength, JBB); + } delivered.remove(scanFragptr); running.add(scanFragptr); }//for @@ -9551,7 +9573,7 @@ void Dbtc::sendScanFragReq(Signal* signal, req->transId1 = apiConnectptr.p->transid[0]; req->transId2 = apiConnectptr.p->transid[1]; req->clientOpPtr = scanFragP->m_apiPtr; - req->batch_size_rows= scanFragP->scanFragConcurrency; + req->batch_size_rows= scanP->batch_size_rows; req->batch_size_bytes= scanP->batch_byte_size; sendSignal(scanFragP->lqhBlockref, GSN_SCAN_FRAGREQ, signal, ScanFragReq::SignalLength, JBB); @@ -9573,6 +9595,8 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) { jam(); ops += 21; } + + Uint32 left = scanPtr.p->scanNoFrag - scanPtr.p->scanNextFragId; ScanTabConf * conf = (ScanTabConf*)&signal->theData[0]; conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect; @@ -9588,24 +9612,25 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) { ScanFragRecPtr curr = ptr; // Remove while iterating... queued.next(ptr); + bool done = curr.p->m_scan_frag_conf_status && --left; + * ops++ = curr.p->m_apiPtr; - * ops++ = curr.i; + * ops++ = done ? RNIL : curr.i; * ops++ = (curr.p->m_totalLen << 10) + curr.p->m_ops; queued.remove(curr); - if(curr.p->m_ops > 0){ + if(!done){ delivered.add(curr); curr.p->scanFragState = ScanFragRec::DELIVERED; curr.p->stopFragTimer(); } else { - (* --ops) = ScanTabConf::EndOfData; ops++; c_scan_frag_pool.release(curr); curr.p->scanFragState = ScanFragRec::COMPLETED; curr.p->stopFragTimer(); } } } - + if(scanPtr.p->m_delivered_scan_frags.isEmpty() && scanPtr.p->m_running_scan_frags.isEmpty()){ conf->requestInfo = op_count | ScanTabConf::EndOfData; @@ -10424,9 +10449,8 @@ Dbtc::execDUMP_STATE_ORD(Signal* signal) sfp.i, sfp.p->scanFragState, sfp.p->scanFragId); - infoEvent(" nodeid=%d, concurr=%d, timer=%d", + infoEvent(" nodeid=%d, timer=%d", refToNode(sfp.p->lqhBlockref), - sfp.p->scanFragConcurrency, sfp.p->scanFragTimer); } @@ -10504,7 +10528,7 @@ Dbtc::execDUMP_STATE_ORD(Signal* signal) sp.p->scanAiLength, sp.p->scanParallel, sp.p->scanReceivedOperations, - sp.p->noOprecPerFrag); + sp.p->batch_size_rows); infoEvent(" schv=%d, tab=%d, sproc=%d", sp.p->scanSchemaVersion, sp.p->scanTableref, diff --git a/ndb/src/kernel/blocks/suma/Suma.cpp b/ndb/src/kernel/blocks/suma/Suma.cpp index d11d5f7176a..f6d9a0ac35a 100644 --- a/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/ndb/src/kernel/blocks/suma/Suma.cpp @@ -1888,7 +1888,7 @@ SumaParticipant::SyncRecord::nextScan(Signal* signal){ req->requestInfo = 0; req->savePointId = 0; ScanFragReq::setLockMode(req->requestInfo, 0); - ScanFragReq::setHoldLockFlag(req->requestInfo, 0); + ScanFragReq::setHoldLockFlag(req->requestInfo, 1); ScanFragReq::setKeyinfoFlag(req->requestInfo, 0); ScanFragReq::setAttrLen(req->requestInfo, attrLen); req->fragmentNoKeyLen = fd.m_fragDesc.m_fragmentNo; diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index c21a85fd24d..aecc7124d15 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -1577,9 +1577,6 @@ from other transactions. /** * There's always a TCKEYCONF when using IgnoreError */ -#ifdef VM_TRACE - ndbout_c("Not completing transaction 2"); -#endif return -1; } /**********************************************************************/ @@ -1831,9 +1828,6 @@ NdbConnection::OpCompleteFailure(Uint8 abortOption, bool setFailure) /** * There's always a TCKEYCONF when using IgnoreError */ -#ifdef VM_TRACE - ndbout_c("Not completing transaction"); -#endif return -1; } diff --git a/ndb/src/ndbapi/NdbConnectionScan.cpp b/ndb/src/ndbapi/NdbConnectionScan.cpp index 3fe8993a42b..a7a8f1350b1 100644 --- a/ndb/src/ndbapi/NdbConnectionScan.cpp +++ b/ndb/src/ndbapi/NdbConnectionScan.cpp @@ -97,7 +97,7 @@ NdbConnection::receiveSCAN_TABCONF(NdbApiSignal* aSignal, theScanningOp->execCLOSE_SCAN_REP(); return 0; } - + for(Uint32 i = 0; iint2void(ptrI); assert(tPtr); // For now NdbReceiver* tOp = theNdb->void2rec(tPtr); - if (tOp && tOp->checkMagicNumber()){ - if(tOp->execSCANOPCONF(tcPtrI, totalLen, opCount)){ - /** - * - */ - theScanningOp->receiver_delivered(tOp); - } else if(info == ScanTabConf::EndOfData){ + if (tOp && tOp->checkMagicNumber()) + { + if (tcPtrI == RNIL && opCount == 0) theScanningOp->receiver_completed(tOp); - } - } - } - if (conf->requestInfo & ScanTabConf::EndOfData) { - if(theScanningOp->m_ordered) - theScanningOp->m_api_receivers_count = 0; - if(theScanningOp->m_api_receivers_count + - theScanningOp->m_conf_receivers_count + - theScanningOp->m_sent_receivers_count){ - abort(); + else if (tOp->execSCANOPCONF(tcPtrI, totalLen, opCount)) + theScanningOp->receiver_delivered(tOp); } } return 0; diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 373fec1a2b0..30b596d7098 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -35,6 +35,8 @@ #include #include +#define DEBUG_NEXT_RESULT 0 + NdbScanOperation::NdbScanOperation(Ndb* aNdb) : NdbOperation(aNdb), m_resultSet(0), @@ -275,6 +277,9 @@ NdbScanOperation::fix_receivers(Uint32 parallel){ void NdbScanOperation::receiver_delivered(NdbReceiver* tRec){ if(theError.code == 0){ + if(DEBUG_NEXT_RESULT) + ndbout_c("receiver_delivered"); + Uint32 idx = tRec->m_list_index; Uint32 last = m_sent_receivers_count - 1; if(idx != last){ @@ -298,6 +303,9 @@ NdbScanOperation::receiver_delivered(NdbReceiver* tRec){ void NdbScanOperation::receiver_completed(NdbReceiver* tRec){ if(theError.code == 0){ + if(DEBUG_NEXT_RESULT) + ndbout_c("receiver_completed"); + Uint32 idx = tRec->m_list_index; Uint32 last = m_sent_receivers_count - 1; if(idx != last){ @@ -445,8 +453,6 @@ NdbScanOperation::executeCursor(int nodeId){ return -1; } -#define DEBUG_NEXT_RESULT 0 - int NdbScanOperation::nextResult(bool fetchAllowed) { if(m_ordered) @@ -579,7 +585,8 @@ int NdbScanOperation::nextResult(bool fetchAllowed) int NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ - if(cnt > 0 || stopScanFlag){ + if(cnt > 0) + { NdbApiSignal tSignal(theNdb->theMyRef); tSignal.setSignal(GSN_SCAN_NEXTREQ); @@ -595,33 +602,40 @@ NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ */ Uint32 last = m_sent_receivers_count; Uint32 * prep_array = (cnt > 21 ? m_prepared_receivers : theData + 4); + Uint32 sent = 0; for(Uint32 i = 0; im_list_index = last+i; - prep_array[i] = tRec->m_tcPtrI; - tRec->prepareSend(); + if((prep_array[sent] = tRec->m_tcPtrI) != RNIL) + { + m_sent_receivers[last+sent] = tRec; + tRec->m_list_index = last+sent; + tRec->prepareSend(); + sent++; + } } memcpy(&m_api_receivers[0], &m_api_receivers[cnt], cnt * sizeof(char*)); - Uint32 nodeId = theNdbCon->theDBnode; - TransporterFacade * tp = TransporterFacade::instance(); - int ret; - if(cnt > 21){ - tSignal.setLength(4); - LinearSectionPtr ptr[3]; - ptr[0].p = prep_array; - ptr[0].sz = cnt; - ret = tp->sendSignal(&tSignal, nodeId, ptr, 1); - } else { - tSignal.setLength(4+cnt); - ret = tp->sendSignal(&tSignal, nodeId); + int ret = 0; + if(sent) + { + Uint32 nodeId = theNdbCon->theDBnode; + TransporterFacade * tp = TransporterFacade::instance(); + if(cnt > 21 && !stopScanFlag){ + tSignal.setLength(4); + LinearSectionPtr ptr[3]; + ptr[0].p = prep_array; + ptr[0].sz = sent; + ret = tp->sendSignal(&tSignal, nodeId, ptr, 1); + } else { + tSignal.setLength(4+(stopScanFlag ? 0 : sent)); + ret = tp->sendSignal(&tSignal, nodeId); + } } - - m_sent_receivers_count = last + cnt + stopScanFlag; + + m_sent_receivers_count = last + sent; m_api_receivers_count -= cnt; m_current_api_receiver = 0; - + return ret; } return 0; @@ -1412,10 +1426,22 @@ NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ if(idx == theParallelism) return 0; + NdbReceiver* tRec = m_api_receivers[idx]; NdbApiSignal tSignal(theNdb->theMyRef); tSignal.setSignal(GSN_SCAN_NEXTREQ); + Uint32 last = m_sent_receivers_count; Uint32* theData = tSignal.getDataPtrSend(); + Uint32* prep_array = theData + 4; + + m_current_api_receiver = idx + 1; + if((prep_array[0] = tRec->m_tcPtrI) == RNIL) + { + if(DEBUG_NEXT_RESULT) + ndbout_c("receiver completed, don't send"); + return 0; + } + theData[0] = theNdbCon->theTCConPtr; theData[1] = 0; Uint64 transId = theNdbCon->theTransactionId; @@ -1425,17 +1451,10 @@ NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ /** * Prepare ops */ - Uint32 last = m_sent_receivers_count; - Uint32 * prep_array = theData + 4; - - NdbReceiver * tRec = m_api_receivers[idx]; m_sent_receivers[last] = tRec; tRec->m_list_index = last; - prep_array[0] = tRec->m_tcPtrI; tRec->prepareSend(); - m_sent_receivers_count = last + 1; - m_current_api_receiver = idx + 1; Uint32 nodeId = theNdbCon->theDBnode; TransporterFacade * tp = TransporterFacade::instance(); @@ -1448,12 +1467,17 @@ NdbScanOperation::close_impl(TransporterFacade* tp){ Uint32 seq = theNdbCon->theNodeSequence; Uint32 nodeId = theNdbCon->theDBnode; - if(seq != tp->getNodeSequence(nodeId)){ + if(seq != tp->getNodeSequence(nodeId)) + { theNdbCon->theReleaseOnClose = true; return -1; } - while(theError.code == 0 && m_sent_receivers_count){ + /** + * Wait for outstanding + */ + while(theError.code == 0 && m_sent_receivers_count) + { theNdb->theWaiter.m_node = nodeId; theNdb->theWaiter.m_state = WAIT_SCAN; int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); @@ -1471,18 +1495,52 @@ NdbScanOperation::close_impl(TransporterFacade* tp){ } } - if(m_api_receivers_count+m_conf_receivers_count){ - // Send close scan - if(send_next_scan(0, true) == -1){ // Close scan - theNdbCon->theReleaseOnClose = true; - return -1; - } + /** + * move all conf'ed into api + * so that send_next_scan can check if they needs to be closed + */ + Uint32 api = m_api_receivers_count; + Uint32 conf = m_conf_receivers_count; + + if(m_ordered) + { + /** + * Ordered scan, keep the m_api_receivers "to the right" + */ + memmove(m_api_receivers, m_api_receivers+m_current_api_receiver, + (theParallelism - m_current_api_receiver) * sizeof(char*)); + api = (theParallelism - m_current_api_receiver); + m_api_receivers_count = api; + } + + if(DEBUG_NEXT_RESULT) + ndbout_c("close_impl: [order api conf sent curr parr] %d %d %d %d %d %d", + m_ordered, api, conf, + m_sent_receivers_count, m_current_api_receiver, theParallelism); + + if(api+conf) + { + /** + * There's something to close + * setup m_api_receivers (for send_next_scan) + */ + memcpy(m_api_receivers+api, m_conf_receivers, conf * sizeof(char*)); + m_api_receivers_count = api + conf; + m_conf_receivers_count = 0; + } + + // Send close scan + if(send_next_scan(api+conf, true) == -1) + { + theNdbCon->theReleaseOnClose = true; + return -1; } /** * wait for close scan conf */ - while(m_sent_receivers_count+m_api_receivers_count+m_conf_receivers_count){ + while(m_sent_receivers_count+m_api_receivers_count+m_conf_receivers_count) + { theNdb->theWaiter.m_node = nodeId; theNdb->theWaiter.m_state = WAIT_SCAN; int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); @@ -1499,6 +1557,7 @@ NdbScanOperation::close_impl(TransporterFacade* tp){ return -1; } } + return 0; } diff --git a/ndb/test/include/HugoTransactions.hpp b/ndb/test/include/HugoTransactions.hpp index 19e4cb43336..b833f2ac629 100644 --- a/ndb/test/include/HugoTransactions.hpp +++ b/ndb/test/include/HugoTransactions.hpp @@ -36,15 +36,21 @@ public: bool allowConstraintViolation = true, int doSleep = 0, bool oneTrans = false); + int scanReadRecords(Ndb*, int records, int abort = 0, int parallelism = 0, - bool committed = false); - int scanReadCommittedRecords(Ndb*, - int records, - int abort = 0, - int parallelism = 0); + NdbOperation::LockMode = NdbOperation::LM_Read); + + int scanReadRecords(Ndb*, + const NdbDictionary::Index*, + int records, + int abort = 0, + int parallelism = 0, + NdbOperation::LockMode = NdbOperation::LM_Read, + bool sorted = false); + int pkReadRecords(Ndb*, int records, int batchsize = 1, diff --git a/ndb/test/include/UtilTransactions.hpp b/ndb/test/include/UtilTransactions.hpp index 37cd99550a5..23902f3b317 100644 --- a/ndb/test/include/UtilTransactions.hpp +++ b/ndb/test/include/UtilTransactions.hpp @@ -53,11 +53,11 @@ public: int selectCount(Ndb*, int parallelism = 0, int* count_rows = NULL, - ScanLock lock = SL_Read, + NdbOperation::LockMode lm = NdbOperation::LM_CommittedRead, NdbConnection* pTrans = NULL); int scanReadRecords(Ndb*, int parallelism, - bool exclusive, + NdbOperation::LockMode lm, int records, int noAttribs, int* attrib_list, diff --git a/ndb/test/ndbapi/testScan.cpp b/ndb/test/ndbapi/testScan.cpp index 0cd30dfefde..51913e8fbf9 100644 --- a/ndb/test/ndbapi/testScan.cpp +++ b/ndb/test/ndbapi/testScan.cpp @@ -242,8 +242,9 @@ int runScanReadCommitted(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); while (iisTestStopped()) { g_info << i << ": "; - if (hugoTrans.scanReadCommittedRecords(GETNDB(step), records, - abort, parallelism) != 0){ + if (hugoTrans.scanReadRecords(GETNDB(step), records, + abort, parallelism, + NdbOperation::LM_CommittedRead) != 0){ return NDBT_FAILED; } i++; @@ -639,7 +640,7 @@ int runCheckGetValue(NDBT_Context* ctx, NDBT_Step* step){ g_info << (unsigned)i << endl; if(utilTrans.scanReadRecords(GETNDB(step), parallelism, - false, + NdbOperation::LM_Read, records, alist.attriblist[i]->numAttribs, alist.attriblist[i]->attribs) != 0){ @@ -647,7 +648,7 @@ int runCheckGetValue(NDBT_Context* ctx, NDBT_Step* step){ } if(utilTrans.scanReadRecords(GETNDB(step), parallelism, - true, + NdbOperation::LM_Read, records, alist.attriblist[i]->numAttribs, alist.attriblist[i]->attribs) != 0){ diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp index 456bfffbb77..096f5406bbf 100644 --- a/ndb/test/src/HugoTransactions.cpp +++ b/ndb/test/src/HugoTransactions.cpp @@ -29,20 +29,13 @@ HugoTransactions::~HugoTransactions(){ deallocRows(); } - -int HugoTransactions::scanReadCommittedRecords(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ - return scanReadRecords(pNdb, records, abortPercent, parallelism, true); -} - int HugoTransactions::scanReadRecords(Ndb* pNdb, int records, int abortPercent, int parallelism, - bool committed){ + NdbOperation::LockMode lm) +{ int retryAttempt = 0; const int retryMax = 100; @@ -80,8 +73,163 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, } NdbResultSet * rs; - rs = pOp ->readTuples(committed ? NdbScanOperation::LM_CommittedRead : - NdbScanOperation::LM_Read); + rs = pOp ->readTuples(lm); + + if( rs == 0 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + check = pOp->interpret_exit_ok(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + for(a = 0; agetValue(tab.getColumn(a)->getName())) == 0) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + check = pTrans->execute(NoCommit); + if( check == -1 ) { + const NdbError err = pTrans->getNdbError(); + if (err.status == NdbError::TemporaryError){ + ERR(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + // Abort after 1-100 or 1-records rows + int ranVal = rand(); + int abortCount = ranVal % (records == 0 ? 100 : records); + bool abortTrans = false; + if (abort > 0){ + // Abort if abortCount is less then abortPercent + if (abortCount < abortPercent) + abortTrans = true; + } + + int eof; + int rows = 0; + while((eof = rs->nextResult(true)) == 0){ + rows++; + if (calc.verifyRowValues(&row) != 0){ + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (abortCount == rows && abortTrans == true){ + ndbout << "Scan is aborted" << endl; + g_info << "Scan is aborted" << endl; + rs->close(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + return NDBT_OK; + } + } + if (eof == -1) { + const NdbError err = pTrans->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR_INFO(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + switch (err.code){ + case 488: + case 245: + case 490: + // Too many active scans, no limit on number of retry attempts + break; + default: + retryAttempt++; + } + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + + g_info << rows << " rows have been read" << endl; + if (records != 0 && rows != records){ + g_err << "Check expected number of records failed" << endl + << " expected=" << records <<", " << endl + << " read=" << rows << endl; + return NDBT_FAILED; + } + + return NDBT_OK; + } + return NDBT_FAILED; +} + +int +HugoTransactions::scanReadRecords(Ndb* pNdb, + const NdbDictionary::Index * pIdx, + int records, + int abortPercent, + int parallelism, + NdbOperation::LockMode lm, + bool sorted) +{ + + int retryAttempt = 0; + const int retryMax = 100; + int check, a; + NdbConnection *pTrans; + NdbIndexScanOperation *pOp; + + while (true){ + + if (retryAttempt >= retryMax){ + g_err << "ERROR: has retried this operation " << retryAttempt + << " times, failing!" << endl; + return NDBT_FAILED; + } + + pTrans = pNdb->startTransaction(); + if (pTrans == NULL) { + const NdbError err = pNdb->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + return NDBT_FAILED; + } + + pOp = pTrans->getNdbIndexScanOperation(pIdx->getName(), tab.getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + NdbResultSet * rs; + rs = pOp ->readTuples(lm, 0, parallelism, sorted); if( rs == 0 ) { ERR(pTrans->getNdbError()); diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp index c0e6effd244..869f7fc76cb 100644 --- a/ndb/test/src/UtilTransactions.cpp +++ b/ndb/test/src/UtilTransactions.cpp @@ -619,7 +619,7 @@ UtilTransactions::addRowToInsert(Ndb* pNdb, int UtilTransactions::scanReadRecords(Ndb* pNdb, int parallelism, - bool exclusive, + NdbOperation::LockMode lm, int records, int noAttribs, int *attrib_list, @@ -669,10 +669,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, return NDBT_FAILED; } - NdbResultSet * rs = pOp->readTuples(exclusive ? - NdbScanOperation::LM_Exclusive : - NdbScanOperation::LM_Read, - 0, parallelism); + NdbResultSet * rs = pOp->readTuples(lm, 0, parallelism); if( rs == 0 ) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); @@ -761,7 +758,7 @@ int UtilTransactions::selectCount(Ndb* pNdb, int parallelism, int* count_rows, - ScanLock lock, + NdbOperation::LockMode lm, NdbConnection* pTrans){ int retryAttempt = 0; @@ -785,19 +782,7 @@ UtilTransactions::selectCount(Ndb* pNdb, return NDBT_FAILED; } - NdbResultSet * rs; - switch(lock){ - case SL_ReadHold: - rs = pOp->readTuples(NdbScanOperation::LM_Read); - break; - case SL_Exclusive: - rs = pOp->readTuples(NdbScanOperation::LM_Exclusive); - break; - case SL_Read: - default: - rs = pOp->readTuples(NdbScanOperation::LM_CommittedRead); - } - + NdbResultSet * rs = pOp->readTuples(lm); if( rs == 0) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); diff --git a/ndb/test/tools/create_index.cpp b/ndb/test/tools/create_index.cpp index 75a657522f6..6e4c5377f4a 100644 --- a/ndb/test/tools/create_index.cpp +++ b/ndb/test/tools/create_index.cpp @@ -30,7 +30,7 @@ main(int argc, const char** argv){ const char* _dbname = "TEST_DB"; int _help = 0; - int _ordered, _pk; + int _ordered = 0, _pk = 1; struct getargs args[] = { { "database", 'd', arg_string, &_dbname, "dbname", diff --git a/ndb/test/tools/hugoScanRead.cpp b/ndb/test/tools/hugoScanRead.cpp index cdfdcea4654..42180207a8a 100644 --- a/ndb/test/tools/hugoScanRead.cpp +++ b/ndb/test/tools/hugoScanRead.cpp @@ -35,13 +35,17 @@ int main(int argc, const char** argv){ int _parallelism = 1; const char* _tabname = NULL; int _help = 0; - + int lock = NdbOperation::LM_Read; + int sorted = 0; + struct getargs args[] = { { "aborts", 'a', arg_integer, &_abort, "percent of transactions that are aborted", "abort%" }, { "loops", 'l', arg_integer, &_loops, "number of times to run this program(0=infinite loop)", "loops" }, { "parallelism", 'p', arg_integer, &_parallelism, "parallelism(1-240)", "para" }, { "records", 'r', arg_integer, &_records, "Number of records", "recs" }, - { "usage", '?', arg_flag, &_help, "Print help", "" } + { "usage", '?', arg_flag, &_help, "Print help", "" }, + { "lock", 'm', arg_integer, &lock, "lock mode", "" }, + { "sorted", 's', arg_flag, &sorted, "sorted", "" } }; int num_args = sizeof(args) / sizeof(args[0]); int optind = 0; @@ -73,16 +77,48 @@ int main(int argc, const char** argv){ ndbout << " Table " << _tabname << " does not exist!" << endl; return NDBT_ProgramExit(NDBT_WRONGARGS); } + + const NdbDictionary::Index * pIdx = 0; + if(optind+1 < argc) + { + pIdx = MyNdb.getDictionary()->getIndex(argv[optind+1], _tabname); + if(!pIdx) + ndbout << " Index " << argv[optind+1] << " not found" << endl; + else + if(pIdx->getType() != NdbDictionary::Index::UniqueOrderedIndex && + pIdx->getType() != NdbDictionary::Index::OrderedIndex) + { + ndbout << " Index " << argv[optind+1] << " is not scannable" << endl; + pIdx = 0; + } + } HugoTransactions hugoTrans(*pTab); int i = 0; while (i<_loops || _loops==0) { ndbout << i << ": "; - if(hugoTrans.scanReadRecords(&MyNdb, - 0, - _abort, - _parallelism) != 0){ - return NDBT_ProgramExit(NDBT_FAILED); + if(!pIdx) + { + if(hugoTrans.scanReadRecords(&MyNdb, + 0, + _abort, + _parallelism, + (NdbOperation::LockMode)lock) != 0) + { + return NDBT_ProgramExit(NDBT_FAILED); + } + } + else + { + if(hugoTrans.scanReadRecords(&MyNdb, pIdx, + 0, + _abort, + _parallelism, + (NdbOperation::LockMode)lock, + sorted) != 0) + { + return NDBT_ProgramExit(NDBT_FAILED); + } } i++; } diff --git a/ndb/tools/select_all.cpp b/ndb/tools/select_all.cpp index 758c1e48c88..9c944c8c93e 100644 --- a/ndb/tools/select_all.cpp +++ b/ndb/tools/select_all.cpp @@ -133,13 +133,18 @@ int main(int argc, char** argv){ const NdbDictionary::Table* pTab = NDBT_Table::discoverTableFromDb(&MyNdb, _tabname); const NdbDictionary::Index * pIdx = 0; if(argc > 1){ - pIdx = MyNdb.getDictionary()->getIndex(argv[0], _tabname); + pIdx = MyNdb.getDictionary()->getIndex(argv[1], _tabname); } if(pTab == NULL){ ndbout << " Table " << _tabname << " does not exist!" << endl; return NDBT_ProgramExit(NDBT_WRONGARGS); } + + if(argc > 1 && pIdx == 0) + { + ndbout << " Index " << argv[1] << " does not exists" << endl; + } if(_order && pIdx == NULL){ ndbout << " Order flag given without an index" << endl; From 18f12ee494d96a7e2caf6ab5d725fe6d371f9cba Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Nov 2004 20:35:19 +0000 Subject: [PATCH 08/48] adopted testprograms to changes in mgmapi --- ndb/test/run-test/main.cpp | 22 ++++++++++-------- ndb/test/src/NdbBackup.cpp | 10 ++++---- ndb/test/src/NdbRestarter.cpp | 43 ++++++++--------------------------- 3 files changed, 27 insertions(+), 48 deletions(-) diff --git a/ndb/test/run-test/main.cpp b/ndb/test/run-test/main.cpp index e5f73bc6a5c..ac7710d9546 100644 --- a/ndb/test/run-test/main.cpp +++ b/ndb/test/run-test/main.cpp @@ -538,15 +538,19 @@ connect_ndb_mgm(atrt_process & proc){ } BaseString tmp = proc.m_hostname; tmp.appfmt(":%d", proc.m_ndb_mgm_port); - time_t start = time(0); - const time_t max_connect_time = 30; - do { - if(ndb_mgm_connect(handle, tmp.c_str()) != -1){ - proc.m_ndb_mgm_handle = handle; - return true; - } - sleep(1); - } while(time(0) < (start + max_connect_time)); + + if (ndb_mgm_set_connectstring(handle,tmp.c_str())) + { + g_logger.critical("Unable to create parse connectstring"); + return false; + } + + if(ndb_mgm_connect(handle, 30, 1, 0) != -1) + { + proc.m_ndb_mgm_handle = handle; + return true; + } + g_logger.critical("Unable to connect to ndb mgm %s", tmp.c_str()); return false; } diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 1ce48d495a5..398a7c32fc4 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -69,16 +69,14 @@ NdbBackup::getBackupDataDirForNode(int _node_id){ /** * Fetch configuration from management server */ - LocalConfig lc; - if (!lc.init(0,0)) { - abort(); - } - ConfigRetriever cr(lc, 0, NODE_TYPE_API); + ConfigRetriever cr(0, 0, NODE_TYPE_API); ndb_mgm_configuration * p = 0; BaseString tmp; tmp.assfmt("%s:%d", host.c_str(), port); NdbMgmHandle handle = ndb_mgm_create_handle(); - if(handle == 0 || ndb_mgm_connect(handle, tmp.c_str()) != 0 || + if(handle == 0 || + ndb_mgm_set_connectstring(handle,tmp.c_str()) != 0 || + ndb_mgm_connect(handle,0,0,0) != 0 || (p = ndb_mgm_get_configuration(handle, 0)) == 0){ const char * s = 0; diff --git a/ndb/test/src/NdbRestarter.cpp b/ndb/test/src/NdbRestarter.cpp index 4d6d3ddc001..e1802f36e82 100644 --- a/ndb/test/src/NdbRestarter.cpp +++ b/ndb/test/src/NdbRestarter.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -38,37 +37,7 @@ NdbRestarter::NdbRestarter(const char* _addr): m_config(0) { if (_addr == NULL){ - LocalConfig lcfg; - if(!lcfg.init()){ - lcfg.printError(); - lcfg.printUsage(); - g_err << "NdbRestarter - Error parsing local config file" << endl; - return; - } - - if (lcfg.ids.size() == 0){ - g_err << "NdbRestarter - No management servers configured in local config file" << endl; - return; - } - - for (int i = 0; itype){ - case MgmId_TCP: - char buf[255]; - snprintf(buf, 255, "%s:%d", m->name.c_str(), m->port); - addr.assign(buf); - host.assign(m->name.c_str()); - port = m->port; - return; - break; - case MgmId_File: - break; - default: - break; - } - } + addr.assign(""); } else { addr.assign(_addr); } @@ -397,7 +366,15 @@ NdbRestarter::connect(){ return -1; } g_info << "Connecting to mgmsrv at " << addr.c_str() << endl; - if (ndb_mgm_connect(handle, addr.c_str()) == -1) { + if (ndb_mgm_set_connectstring(handle,addr.c_str())) + { + MGMERR(handle); + g_err << "Connection to " << addr.c_str() << " failed" << endl; + return -1; + } + + if (ndb_mgm_connect(handle, 0, 0, 0) == -1) + { MGMERR(handle); g_err << "Connection to " << addr.c_str() << " failed" << endl; return -1; From f080e78f628b9f2bc0613f35de5f5cd298ed73ce Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Nov 2004 22:41:31 +0100 Subject: [PATCH 09/48] wl2077 - ndb scan optimizations ndb/test/ndbapi/testScanPerf.cpp: Add reset_bounds option Impl. eq bound queries --- ndb/test/ndbapi/testScanPerf.cpp | 78 ++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/ndb/test/ndbapi/testScanPerf.cpp b/ndb/test/ndbapi/testScanPerf.cpp index c1334125978..fca67c6abcb 100644 --- a/ndb/test/ndbapi/testScanPerf.cpp +++ b/ndb/test/ndbapi/testScanPerf.cpp @@ -39,8 +39,9 @@ struct Parameter { #define P_LOOPS 8 #define P_CREATE 9 #define P_LOAD 10 +#define P_RESET 11 -#define P_MAX 11 +#define P_MAX 12 static Parameter @@ -55,7 +56,8 @@ g_paramters[] = { { "size", 1000000, 1, ~0 }, { "iterations", 3, 1, ~0 }, { "create_drop", 1, 0, 1 }, - { "data", 1, 0, 1 } + { "data", 1, 0, 1 }, + { "q-reset bounds", 0, 1, 0 } }; static Ndb* g_ndb = 0; @@ -218,21 +220,29 @@ run_scan(){ NDB_TICKS start1, stop; int sum_time= 0; + int sample_rows = 0; + NDB_TICKS sample_start = NdbTick_CurrentMillisecond(); + Uint32 tot = g_paramters[P_ROWS].value; + if(g_paramters[P_BOUND].value == 2 || g_paramters[P_FILT].value == 2) + iter *= g_paramters[P_ROWS].value; + + NdbScanOperation * pOp = 0; + NdbIndexScanOperation * pIOp = 0; + NdbConnection * pTrans = 0; + NdbResultSet * rs = 0; + int check = 0; + for(int i = 0; istartTransaction(); + pTrans = pTrans ? pTrans : g_ndb->startTransaction(); if(!pTrans){ g_err << "Failed to start transaction" << endl; err(g_ndb->getNdbError()); return -1; } - NdbScanOperation * pOp; - NdbIndexScanOperation * pIOp; - - NdbResultSet * rs; int par = g_paramters[P_PARRA].value; int bat = g_paramters[P_BATCH].value; NdbScanOperation::LockMode lm; @@ -255,9 +265,17 @@ run_scan(){ assert(pOp); rs = pOp->readTuples(lm, bat, par); } else { - pOp = pIOp = pTrans->getNdbIndexScanOperation(g_indexname, g_tablename); - bool ord = g_paramters[P_ACCESS].value == 2; - rs = pIOp->readTuples(lm, bat, par, ord); + if(g_paramters[P_RESET].value == 0 || pIOp == 0) + { + pOp= pIOp= pTrans->getNdbIndexScanOperation(g_indexname, g_tablename); + bool ord = g_paramters[P_ACCESS].value == 2; + rs = pIOp->readTuples(lm, bat, par, ord); + } + else + { + pIOp->reset_bounds(); + } + switch(g_paramters[P_BOUND].value){ case 0: // All break; @@ -267,20 +285,22 @@ run_scan(){ case 2: { // 1 row default: assert(g_table->getNoOfPrimaryKeys() == 1); // only impl. so far - abort(); -#if 0 int tot = g_paramters[P_ROWS].value; int row = rand() % tot; +#if 0 fix_eq_bound(pIOp, row); +#else + pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row); #endif break; } } + if(g_paramters[P_RESET].value == 1) + goto execute; } assert(pOp); assert(rs); - int check = 0; switch(g_paramters[P_FILT].value){ case 0: // All check = pOp->interpret_exit_ok(); @@ -312,7 +332,7 @@ run_scan(){ for(int i = 0; igetNoOfColumns(); i++){ pOp->getValue(i); } - +execute: int rows = 0; check = pTrans->execute(NoCommit); assert(check == 0); @@ -333,19 +353,29 @@ run_scan(){ return -1; } assert(check == 1); - g_info << "Found " << rows << " rows" << endl; - - pTrans->close(); - + if(g_paramters[P_RESET].value == 0) + { + pTrans->close(); + pTrans = 0; + } stop = NdbTick_CurrentMillisecond(); + int time_passed= (int)(stop - start1); - g_err.println("Time: %d ms = %u rows/sec", time_passed, - (1000*tot)/time_passed); + sample_rows += rows; sum_time+= time_passed; + + if(sample_rows >= tot) + { + int sample_time = (int)(stop - sample_start); + g_info << "Found " << sample_rows << " rows" << endl; + g_err.println("Time: %d ms = %u rows/sec", sample_time, + (1000*sample_rows)/sample_time); + sample_rows = 0; + sample_start = stop; + } } - sum_time= sum_time / iter; - - g_err.println("Avg time: %d ms = %u rows/sec", sum_time, - (1000*tot)/sum_time); + + g_err.println("Avg time: %d ms = %u rows/sec", sum_time/iter, + (1000*tot*iter)/sum_time); return 0; } From f3374eec82129fe4e258c0fd825c1e0dc66c3a37 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Nov 2004 22:44:34 +0000 Subject: [PATCH 10/48] merge error --- ndb/include/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/ndb/include/Makefile.am b/ndb/include/Makefile.am index ca2e8152352..7b3f80b5560 100644 --- a/ndb/include/Makefile.am +++ b/ndb/include/Makefile.am @@ -28,7 +28,6 @@ ndbapi/NdbIndexScanOperation.hpp \ ndbapi/ndberror.h mgmapiinclude_HEADERS = \ -mgmapi/LocalConfig.hpp \ mgmapi/mgmapi.h \ mgmapi/mgmapi_debug.h From c3211458aca33f32e1849b4309d22aa6d8e5b184 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 19 Nov 2004 11:31:20 +0100 Subject: [PATCH 11/48] wl2077 - ndb scan optimizations ndb/src/kernel/blocks/dbdih/Dbdih.hpp: remove unused variable ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Always supply all nodes ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Enable scanning of backup fragments when read committed ndb/test/ndbapi/testReadPerf.cpp: Better printout --- ndb/src/kernel/blocks/dbdih/Dbdih.hpp | 1 - ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 20 +++++++++----------- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 14 ++++++++++++++ ndb/test/ndbapi/testReadPerf.cpp | 11 +++++++++-- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/ndb/src/kernel/blocks/dbdih/Dbdih.hpp b/ndb/src/kernel/blocks/dbdih/Dbdih.hpp index 14fa262f871..0a2d50cb876 100644 --- a/ndb/src/kernel/blocks/dbdih/Dbdih.hpp +++ b/ndb/src/kernel/blocks/dbdih/Dbdih.hpp @@ -147,7 +147,6 @@ public: Uint32 nfConnect; Uint32 table; Uint32 userpointer; - Uint32 nodeCount; BlockReference userblockref; }; typedef Ptr ConnectRecordPtr; diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 76aa745c3e0..4592b121c7e 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -7080,24 +7080,22 @@ void Dbdih::execDIGETPRIMREQ(Signal* signal) ndbrequire(tabPtr.p->tabStatus == TabRecord::TS_ACTIVE); connectPtr.i = signal->theData[0]; - if(connectPtr.i != RNIL){ + if(connectPtr.i != RNIL) + { jam(); ptrCheckGuard(connectPtr, cconnectFileSize, connectRecord); - ndbrequire(connectPtr.p->connectState == ConnectRecord::INUSE); - getFragstore(tabPtr.p, fragId, fragPtr); - connectPtr.p->nodeCount = extractNodeInfo(fragPtr.p, connectPtr.p->nodes); signal->theData[0] = connectPtr.p->userpointer; - signal->theData[1] = passThrough; - signal->theData[2] = connectPtr.p->nodes[0]; - sendSignal(connectPtr.p->userblockref, GSN_DIGETPRIMCONF, signal, 3, JBB); - return; - }//if - //connectPtr.i == RNIL -> question without connect record + } + else + { + jam(); + signal->theData[0] = RNIL; + } + Uint32 nodes[MAX_REPLICAS]; getFragstore(tabPtr.p, fragId, fragPtr); Uint32 count = extractNodeInfo(fragPtr.p, nodes); - signal->theData[0] = RNIL; signal->theData[1] = passThrough; signal->theData[2] = nodes[0]; signal->theData[3] = nodes[1]; diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index c7f467484bd..8c663b42cbe 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -8944,6 +8944,20 @@ void Dbtc::execDIGETPRIMCONF(Signal* signal) scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); + if(ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo)) + { + jam(); + Uint32 max = 3+signal->theData[6]; + Uint32 nodeid = getOwnNodeId(); + for(Uint32 i = 3; itheData[i] == nodeid) + { + jam(); + tnodeid = nodeid; + break; + } + } + { /** * Check table diff --git a/ndb/test/ndbapi/testReadPerf.cpp b/ndb/test/ndbapi/testReadPerf.cpp index 380a809ad00..3adcb5a2d9b 100644 --- a/ndb/test/ndbapi/testReadPerf.cpp +++ b/ndb/test/ndbapi/testReadPerf.cpp @@ -391,8 +391,15 @@ run_read(){ void print_result(){ + int tmp = 1; + tmp *= g_paramters[P_RANGE].value; + tmp *= g_paramters[P_LOOPS].value; + + int t, t2; for(int i = 0; i Date: Fri, 19 Nov 2004 11:37:16 +0100 Subject: [PATCH 12/48] wl2077 - scan optimizations (recommit in clean clone) ndb/src/kernel/blocks/dbdih/Dbdih.hpp: removed unused variable ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Always give all nodes in DIGETPRIMREQ ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Allow readcommited-scans to scan backup fragments ndb/test/ndbapi/testReadPerf.cpp: better printous --- ndb/docs/wl2077.txt | 35 +++++++++++++++++++++++ ndb/src/kernel/blocks/dbdih/Dbdih.hpp | 1 - ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 20 ++++++------- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 14 +++++++++ ndb/test/ndbapi/testReadPerf.cpp | 11 +++++-- 5 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 ndb/docs/wl2077.txt diff --git a/ndb/docs/wl2077.txt b/ndb/docs/wl2077.txt new file mode 100644 index 00000000000..5a77c18aa2a --- /dev/null +++ b/ndb/docs/wl2077.txt @@ -0,0 +1,35 @@ + +100' * (select 1 from T1 (1M rows) where key = rand()); +1 host, 1 ndbd, api co-hosted +results in 1000 rows / sec + + wo/reset bounds w/ rb +4.1-read committed a) 4.9 b) 7.4 +4.1-read hold lock c) 4.7 d) 6.7 + +wl2077-read committed 6.4 (+30%) 10.8 (+45%) +wl2077-read hold lock 4.6 (-1%) 6.7 (+ 0%) + +-- Comparision e) +serial pk: 10.9' +batched (1000): 59' +serial uniq index: 8.4' +batched (1000): 33' +index range (1000): 186' + +---- + +load) testScanPerf -c 1 -d 1 T1 +a) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 0 -r 2 -q 0 T1 +b) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 0 -r 2 -q 1 T1 +c) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 1 -r 2 -q 0 T1 +d) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 1 -r 2 -q 1 T1 +e) testReadPerf -i 25 -c 0 -d 0 T1 + +--- music join 1db-co 2db-co + +4.1 13s 14s +4.1 wo/ blobs 1.7s 3.2s + +wl2077 12s 14s +wl2077 wo/ blobs 1.2s (-30%) 2.5s (-22%) diff --git a/ndb/src/kernel/blocks/dbdih/Dbdih.hpp b/ndb/src/kernel/blocks/dbdih/Dbdih.hpp index 14fa262f871..0a2d50cb876 100644 --- a/ndb/src/kernel/blocks/dbdih/Dbdih.hpp +++ b/ndb/src/kernel/blocks/dbdih/Dbdih.hpp @@ -147,7 +147,6 @@ public: Uint32 nfConnect; Uint32 table; Uint32 userpointer; - Uint32 nodeCount; BlockReference userblockref; }; typedef Ptr ConnectRecordPtr; diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 76aa745c3e0..4592b121c7e 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -7080,24 +7080,22 @@ void Dbdih::execDIGETPRIMREQ(Signal* signal) ndbrequire(tabPtr.p->tabStatus == TabRecord::TS_ACTIVE); connectPtr.i = signal->theData[0]; - if(connectPtr.i != RNIL){ + if(connectPtr.i != RNIL) + { jam(); ptrCheckGuard(connectPtr, cconnectFileSize, connectRecord); - ndbrequire(connectPtr.p->connectState == ConnectRecord::INUSE); - getFragstore(tabPtr.p, fragId, fragPtr); - connectPtr.p->nodeCount = extractNodeInfo(fragPtr.p, connectPtr.p->nodes); signal->theData[0] = connectPtr.p->userpointer; - signal->theData[1] = passThrough; - signal->theData[2] = connectPtr.p->nodes[0]; - sendSignal(connectPtr.p->userblockref, GSN_DIGETPRIMCONF, signal, 3, JBB); - return; - }//if - //connectPtr.i == RNIL -> question without connect record + } + else + { + jam(); + signal->theData[0] = RNIL; + } + Uint32 nodes[MAX_REPLICAS]; getFragstore(tabPtr.p, fragId, fragPtr); Uint32 count = extractNodeInfo(fragPtr.p, nodes); - signal->theData[0] = RNIL; signal->theData[1] = passThrough; signal->theData[2] = nodes[0]; signal->theData[3] = nodes[1]; diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index c7f467484bd..8c663b42cbe 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -8944,6 +8944,20 @@ void Dbtc::execDIGETPRIMCONF(Signal* signal) scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); + if(ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo)) + { + jam(); + Uint32 max = 3+signal->theData[6]; + Uint32 nodeid = getOwnNodeId(); + for(Uint32 i = 3; itheData[i] == nodeid) + { + jam(); + tnodeid = nodeid; + break; + } + } + { /** * Check table diff --git a/ndb/test/ndbapi/testReadPerf.cpp b/ndb/test/ndbapi/testReadPerf.cpp index 8d0d78cbe8c..f8ecc6192dc 100644 --- a/ndb/test/ndbapi/testReadPerf.cpp +++ b/ndb/test/ndbapi/testReadPerf.cpp @@ -390,8 +390,15 @@ run_read(){ void print_result(){ + int tmp = 1; + tmp *= g_paramters[P_RANGE].value; + tmp *= g_paramters[P_LOOPS].value; + + int t, t2; for(int i = 0; i Date: Fri, 19 Nov 2004 13:52:01 +0100 Subject: [PATCH 13/48] wl2077: ndb, disable scanning of backup fragments (temporary) --- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 8c663b42cbe..9af770db5b7 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -8944,7 +8944,12 @@ void Dbtc::execDIGETPRIMCONF(Signal* signal) scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); - if(ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo)) + /** + * This must be false as select count(*) otherwise + * can "pass" committing on backup fragments and + * get incorrect row count + */ + if(false && ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo)) { jam(); Uint32 max = 3+signal->theData[6]; From c9497e2365461fb2547a8cfceb33b68a99d7fe0b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 21 Nov 2004 19:33:49 +0200 Subject: [PATCH 14/48] post merge --- sql/item.cc | 5 ---- sql/mysql_priv.h | 6 ++--- sql/sql_acl.cc | 2 +- sql/sql_base.cc | 34 ++++++++++++------------ sql/sql_insert.cc | 2 +- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 1 + sql/sql_load.cc | 7 +++-- sql/sql_parse.cc | 8 ++---- sql/sql_update.cc | 66 ++++++++++++++++++++++++++++++++++++++--------- sql/table.cc | 18 +++++++------ 11 files changed, 96 insertions(+), 55 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 41203e3365c..6613d758840 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2670,11 +2670,6 @@ void Item_ref::cleanup() DBUG_ENTER("Item_ref::cleanup"); Item_ident::cleanup(); result_field= 0; - DBUG_PRINT("info", ("hook: 0x%lx(0x%lx) original item: 0x%lx", - (ulong)hook_ptr, (ulong)(hook_ptr?*hook_ptr:0), - (ulong)orig_item)); - if (hook_ptr) - *hook_ptr= orig_item; DBUG_VOID_RETURN; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8dfc976071d..b43889b91da 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -619,8 +619,7 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, COND *conds, ulong options, enum enum_duplicates handle_duplicates, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - bool converted); + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, @@ -661,7 +660,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, uint length, Item **ref, bool check_grants_table, bool check_grants_view, bool allow_rowid, - uint *cached_field_index_ptr); + uint *cached_field_index_ptr, + bool register_tree_change); Field * find_field_in_real_table(THD *thd, TABLE *table, const char *name, uint length, bool check_grants, bool allow_rowid, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3e3642dd0bd..f478da9076d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2360,7 +2360,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!find_field_in_table(thd, table_list, column->column.ptr(), column->column.ptr(), column->column.length(), 0, 0, 0, 0, - &unused_field_idx)) + &unused_field_idx, FALSE)) { my_error(ER_BAD_FIELD_ERROR, MYF(0), column->column.c_ptr(), table_list->alias); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5146a140479..a15d9e4fe11 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2069,6 +2069,8 @@ const Field *view_ref_found= (Field*) 0x2; allow_rowid do allow finding of "_rowid" field? cached_field_index_ptr cached position in field list (used to speedup prepared tables field finding) + register_tree_change TRUE if ref is not stack variable and we + need register changes in item tree RETURN 0 field is not found @@ -2082,7 +2084,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, uint length, Item **ref, bool check_grants_table, bool check_grants_view, bool allow_rowid, - uint *cached_field_index_ptr) + uint *cached_field_index_ptr, + bool register_tree_change) { DBUG_ENTER("find_field_in_table"); DBUG_PRINT("enter", ("table:%s name: %s item name %s, ref 0x%lx", @@ -2109,10 +2112,11 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, *ref= trans[i].item; else { - Item_ref *item_ref= new Item_ref(trans[i].item, table_list->view_name.str, + Item_ref *item_ref= new Item_ref(&trans[i].item, + table_list->view_name.str, item_name); /* as far as Item_ref have defined reference it do not need tables */ - if (item_ref) + if (register_tree_change && item_ref) { thd->change_item_tree(ref, item_ref); (*ref)->fix_fields(thd, 0, ref); @@ -2288,7 +2292,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, check_privileges), (test(table->grant.want_privilege) && check_privileges), - 1, &(item->cached_field_index)); + 1, &(item->cached_field_index), + TRUE); } if (found) { @@ -2327,7 +2332,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, check_privileges), (test(tables->grant.want_privilege) && check_privileges), - 1, &(item->cached_field_index)); + 1, &(item->cached_field_index), + TRUE); if (find) { item->cached_table= tables; @@ -2392,7 +2398,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, check_privileges), (test(tables->grant.want_privilege) && check_privileges), - allow_rowid, &(item->cached_field_index)); + allow_rowid, + &(item->cached_field_index), + TRUE); if (field) { if (field == WRONG_GRANT) @@ -3028,7 +3036,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, !find_field_in_table(thd, natural_join_table, field_name, field_name, strlen(field_name), ¬_used_item, 0, 0, 0, - ¬_used_field_index)) + ¬_used_field_index, TRUE)) { Item *item= iterator->item(thd); if (!found++) @@ -3037,7 +3045,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, it->after(item); if (view && !thd->lex->current_select->no_wrap_view_item) { - item= new Item_ref(it->ref(), NULL, tables->view_name.str, + item= new Item_ref(it->ref(), tables->view_name.str, field_name); } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -3252,7 +3260,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) t1_field_name, strlen(t1_field_name), &item_t2, 0, 0, 0, - ¬_used_field_index))) + ¬_used_field_index, + FALSE))) { if (t2_field != view_ref_found) { @@ -3262,13 +3271,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) t2_field->query_id= thd->query_id; t2->used_keys.intersect(t2_field->part_of_key); } - else - { - DBUG_ASSERT(t2_field == view_ref_found && - item_t2->type() == Item::REF_ITEM); - /* remove hooking to stack variable */ - ((Item_ref*) item_t2)->hook_ptr= 0; - } if ((t1_field= iterator->field())) { /* Mark field used for table cache */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index dfd9fd45b70..007898cd8cf 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1781,7 +1781,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) query */ if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) && - unique_table(table_list, table_list->next_independent())) + unique_table(table_list, table_list->next_global)) { /* Using same table for INSERT and SELECT */ thd->lex->current_select->options|= OPTION_BUFFER_RESULT; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 97c5058cd61..72a955e6601 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -150,7 +150,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->found_colon= 0; lex->safe_to_cache_query= 1; lex->time_zone_tables_used= 0; - lex->proc_table= lex->query_tables= 0; + lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; lex->variables_used= 0; lex->select_lex.parent_lex= lex; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7d72d8ec5e1..6853bab019f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -710,6 +710,7 @@ typedef struct st_lex uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; uint slave_thd_opt; + uint table_count; /* used when usual update transformed in multiupdate */ uint8 describe; uint8 derived_tables; uint8 create_view_algorithm; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 40529103f00..c3a7f6ad230 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -121,9 +121,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table_list->lock_type= lock_type; if ((res= open_and_lock_tables(thd, table_list))) DBUG_RETURN(res); - if (setup_tables(thd, table_list, &unused_conds)) + if (setup_tables(thd, table_list, &unused_conds, + &thd->lex->select_lex.leaf_tables, 0)) DBUG_RETURN(-1); - if (!table_list->updatable || check_key_in_view(thd, table_list)) + if (!table_list->table || // do not suport join view + !table_list->updatable || // and derived tables + check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD"); DBUG_RETURN(-1); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 891ff5b8c7e..0f31fbdb077 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2801,7 +2801,6 @@ unsent_create_error: break; case SQLCOM_UPDATE_MULTI: { - bool converted= 0; DBUG_ASSERT(first_table == all_tables && first_table != 0); if (res != 2) { @@ -2809,17 +2808,14 @@ unsent_create_error: break; } else - { res= 0; - converted= 1; - } + res= mysql_multi_update(thd, all_tables, &select_lex->item_list, &lex->value_list, select_lex->where, select_lex->options, - lex->duplicates, unit, select_lex, - converted); + lex->duplicates, unit, select_lex); break; } case SQLCOM_REPLACE: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b60c0d95658..5f84c7435ad 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -127,6 +127,7 @@ int mysql_update(THD *thd, #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif + uint table_count= 0; ulong query_id=thd->query_id, timestamp_query_id; ha_rows updated, found; key_map old_used_keys; @@ -138,17 +139,26 @@ int mysql_update(THD *thd, LINT_INIT(used_index); LINT_INIT(timestamp_query_id); - if ((error= open_and_lock_tables(thd, table_list))) - DBUG_RETURN(error); + if (open_tables(thd, table_list, &table_count)) + DBUG_RETURN(thd->net.report_error ? -1 : 1); if (table_list->table == 0) { DBUG_ASSERT(table_list->view && table_list->ancestor && table_list->ancestor->next_local); DBUG_PRINT("info", ("Switch to multi-update")); + /* pass counter value */ + thd->lex->table_count= table_count; /* convert to multiupdate */ return 2; } + + if (lock_tables(thd, table_list, table_count) || + mysql_handle_derived(thd->lex, &mysql_derived_prepare) || + (thd->fill_derived_tables() && + mysql_handle_derived(thd->lex, &mysql_derived_filling))) + DBUG_RETURN(thd->net.report_error ? -1 : 1); + thd->proc_info="init"; table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -614,14 +624,25 @@ int mysql_multi_update_prepare(THD *thd) table_map tables_for_update; int res; bool update_view= 0; - uint table_count; + /* + if this multi-update was converted from usual update, here is table + counter else junk will be assigned here, but then replaced with real + count in open_tables() + */ + uint table_count= lex->table_count; const bool using_lock_tables= thd->locked_tables != 0; + bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI); DBUG_ENTER("mysql_multi_update_prepare"); /* open tables and create derived ones, but do not lock and fill them */ - if (open_tables(thd, table_list, & table_count) || + if ((original_multiupdate && open_tables(thd, table_list, & table_count)) || mysql_handle_derived(lex, &mysql_derived_prepare)) DBUG_RETURN(thd->net.report_error ? -1 : 1); + /* + setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables() + second time, but this call will do nothing (there are check for second + call in setup_tables()). + */ if (setup_tables(thd, table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, 0)) DBUG_RETURN(-1); @@ -644,11 +665,6 @@ int mysql_multi_update_prepare(THD *thd) (UPDATE_ACL & ~table->grant.privilege); } - /* - setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables() - second time, but this call will do nothing (there are check for second - call in setup_tables()). - */ if ((lex->select_lex.no_wrap_view_item= 1, res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), lex->select_lex.no_wrap_view_item= 0, @@ -675,7 +691,16 @@ int mysql_multi_update_prepare(THD *thd) Setup timestamp handling and locking mode */ for (tl= leaves; tl; tl= tl->next_leaf) + { + TABLE *table= tl->table; + TABLE_LIST *tlist= tl->belong_to_view?tl->belong_to_view:tl; + /* We only need SELECT privilege for columns in the values list */ + tlist->grant.want_privilege= table->grant.want_privilege= + (SELECT_ACL & ~table->grant.privilege); + /* Only set timestamp column if this is not modified */ + if (table->timestamp_field && + table->timestamp_field->query_id == thd->query_id) table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; /* if table will be updated then check that it is unique */ @@ -711,6 +736,23 @@ int mysql_multi_update_prepare(THD *thd) tl->table->reginfo.lock_type= tl->lock_type; } + /* check single table update for view compound from several tables */ + for (tl= table_list; tl; tl= tl->next_local) + { + if (tl->table == 0) + { + DBUG_ASSERT(tl->view && + tl->ancestor && tl->ancestor->next_local); + TABLE_LIST *for_update= 0; + if (tl->check_single_table(&for_update, tables_for_update)) + { + my_error(ER_VIEW_MULTIUPDATE, MYF(0), + tl->view_db.str, tl->view_name.str); + DBUG_RETURN(-1); + } + } + } + opened_tables= thd->status_var.opened_tables; /* now lock and fill tables */ if (lock_tables(thd, table_list, table_count)) @@ -740,7 +782,8 @@ int mysql_multi_update_prepare(THD *thd) /* undone setup_tables() */ table_list->setup_is_done= 0; - if (setup_tables(thd, table_list, &lex->select_lex.where) || + if (setup_tables(thd, table_list, &lex->select_lex.where, + &lex->select_lex.leaf_tables, 0) || (lex->select_lex.no_wrap_view_item= 1, res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), lex->select_lex.no_wrap_view_item= 0, @@ -765,8 +808,7 @@ int mysql_multi_update(THD *thd, COND *conds, ulong options, enum enum_duplicates handle_duplicates, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - bool converted) + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) { int res= 0; multi_update *result; diff --git a/sql/table.cc b/sql/table.cc index 74e35e0f2d7..71d74c3eafc 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1841,9 +1841,10 @@ void st_table_list::cleanup_items() if (!field_translation) return; - Item **end= field_translation + view->select_lex.item_list.elements; - for (Item **item= field_translation; item < end; item++) - (*item)->walk(&Item::cleanup_processor, 0); + Field_translator *end= (field_translation + + view->select_lex.item_list.elements); + for (Field_translator *transl= field_translation; transl < end; transl++) + transl->item->walk(&Item::cleanup_processor, 0); } @@ -1883,7 +1884,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) /* Find table in underlaying tables by mask and check that only this - table sbelong to given mask + table belong to given mask SYNOPSIS st_table_list::check_single_table() @@ -1893,8 +1894,8 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) map bit mask of tables RETURN - 0 table not found or found only one - 1 found several tables + FALSE table not found or found only one + TRUE found several tables */ bool st_table_list::check_single_table(st_table_list **table, table_map map) @@ -1906,15 +1907,16 @@ bool st_table_list::check_single_table(st_table_list **table, table_map map) if (tbl->table->map & map) { if (*table) - return 1; + return TRUE; else *table= tbl; } } else if (tbl->check_single_table(table, map)) - return 1; + return TRUE; } + return FALSE; } From 9e26c327a0530ea104e32960cef7a407dad060dc Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 21 Nov 2004 22:15:44 +0100 Subject: [PATCH 15/48] wl2077 - ndb close scan - fix introduced bugs wrt premature close of scan ndb/src/common/debugger/signaldata/ScanTab.cpp: Fix printout ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Handle already closed fragments ndb/src/ndbapi/NdbConnectionScan.cpp: Better handling of SCAN_TABREF ndb/src/ndbapi/NdbScanOperation.cpp: Removed some special cases by setting up them instead ndb/test/src/NDBT_Test.cpp: Fix createTable(false) ndb/tools/select_all.cpp: Use full scan as default --- ndb/src/common/debugger/signaldata/ScanTab.cpp | 5 +++-- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 3 +-- ndb/src/ndbapi/NdbConnectionScan.cpp | 10 ++++++++-- ndb/src/ndbapi/NdbScanOperation.cpp | 8 +++++--- ndb/test/src/NDBT_Test.cpp | 4 +--- ndb/tools/select_all.cpp | 2 +- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ndb/src/common/debugger/signaldata/ScanTab.cpp b/ndb/src/common/debugger/signaldata/ScanTab.cpp index 72a4d9f94b9..0755ee0a856 100644 --- a/ndb/src/common/debugger/signaldata/ScanTab.cpp +++ b/ndb/src/common/debugger/signaldata/ScanTab.cpp @@ -30,13 +30,14 @@ printSCANTABREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiv fprintf(output, " apiConnectPtr: H\'%.8x", sig->apiConnectPtr); fprintf(output, " requestInfo: H\'%.8x:\n", requestInfo); - fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Keyinfo: %u Holdlock: %u, RangeScan: %u\n", + fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Keyinfo: %u Holdlock: %u, RangeScan: %u ReadCommitted: %u\n", sig->getParallelism(requestInfo), sig->getScanBatch(requestInfo), sig->getLockMode(requestInfo), + sig->getKeyinfoFlag(requestInfo), sig->getHoldLockFlag(requestInfo), sig->getRangeScanFlag(requestInfo), - sig->getKeyinfoFlag(requestInfo)); + sig->getReadCommittedFlag(requestInfo)); Uint32 keyLen = (sig->attrLenKeyLen >> 16); Uint32 attrLen = (sig->attrLenKeyLen & 0xFFFF); diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 9af770db5b7..07dbb370ec6 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -9329,7 +9329,6 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) /********************************************************************* * APPLICATION IS CLOSING THE SCAN. **********************************************************************/ - ndbrequire(len == 0); close_scan_req(signal, scanptr, true); return; }//if @@ -9457,7 +9456,7 @@ Dbtc::close_scan_req(Signal* signal, ScanRecordPtr scanPtr, bool req_received){ ndbrequire(curr.p->scanFragState == ScanFragRec::DELIVERED); delivered.remove(curr); - if(curr.p->m_ops > 0){ + if(curr.p->m_ops > 0 && curr.p->m_scan_frag_conf_status == 0){ jam(); running.add(curr); curr.p->scanFragState = ScanFragRec::LQH_ACTIVE; diff --git a/ndb/src/ndbapi/NdbConnectionScan.cpp b/ndb/src/ndbapi/NdbConnectionScan.cpp index a7a8f1350b1..a1a220caacf 100644 --- a/ndb/src/ndbapi/NdbConnectionScan.cpp +++ b/ndb/src/ndbapi/NdbConnectionScan.cpp @@ -57,12 +57,18 @@ NdbConnection::receiveSCAN_TABREF(NdbApiSignal* aSignal){ if(checkState_TransId(&ref->transId1)){ theScanningOp->theError.code = ref->errorCode; + theScanningOp->execCLOSE_SCAN_REP(); if(!ref->closeNeeded){ - theScanningOp->execCLOSE_SCAN_REP(); return 0; } - assert(theScanningOp->m_sent_receivers_count); + + /** + * Setup so that close_impl will actually perform a close + * and not "close scan"-optimze it away + */ theScanningOp->m_conf_receivers_count++; + theScanningOp->m_conf_receivers[0] = theScanningOp->m_receivers[0]; + theScanningOp->m_conf_receivers[0]->m_tcPtrI = ~0; return 0; } else { #ifdef NDB_NO_DROPPED_SIGNAL diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 30b596d7098..0fe68c5bab8 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -613,21 +613,22 @@ NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ sent++; } } - memcpy(&m_api_receivers[0], &m_api_receivers[cnt], cnt * sizeof(char*)); + memmove(m_api_receivers, m_api_receivers+cnt, + (theParallelism-cnt) * sizeof(char*)); int ret = 0; if(sent) { Uint32 nodeId = theNdbCon->theDBnode; TransporterFacade * tp = TransporterFacade::instance(); - if(cnt > 21 && !stopScanFlag){ + if(cnt > 21){ tSignal.setLength(4); LinearSectionPtr ptr[3]; ptr[0].p = prep_array; ptr[0].sz = sent; ret = tp->sendSignal(&tSignal, nodeId, ptr, 1); } else { - tSignal.setLength(4+(stopScanFlag ? 0 : sent)); + tSignal.setLength(4+sent); ret = tp->sendSignal(&tSignal, nodeId); } } @@ -687,6 +688,7 @@ NdbScanOperation::execCLOSE_SCAN_REP(){ m_api_receivers_count = 0; m_conf_receivers_count = 0; m_sent_receivers_count = 0; + m_current_api_receiver = theParallelism; } void NdbScanOperation::release() diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 367223f8c98..10233cb5859 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -839,9 +839,7 @@ void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab, continue; } pTab2 = pDict->getTable(pTab->getName()); - } else { - pTab2 = pTab; - } + } ctx = new NDBT_Context(); ctx->setTab(pTab2); diff --git a/ndb/tools/select_all.cpp b/ndb/tools/select_all.cpp index 9c944c8c93e..a670a2ed49a 100644 --- a/ndb/tools/select_all.cpp +++ b/ndb/tools/select_all.cpp @@ -50,7 +50,7 @@ static struct my_option my_long_options[] = GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "parallelism", 'p', "parallelism", (gptr*) &_parallelism, (gptr*) &_parallelism, 0, - GET_INT, REQUIRED_ARG, 240, 0, 0, 0, 0, 0 }, + GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "lock", 'l', "Read(0), Read-hold(1), Exclusive(2)", (gptr*) &_lock, (gptr*) &_lock, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, From 9db732ebe6e73bc5c61ceadf92d8fd1582c94e33 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Nov 2004 07:22:08 +0100 Subject: [PATCH 16/48] wl2077 - ndb, fix testDict --- ndb/test/src/NDBT_Test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 10233cb5859..1434617c988 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -839,6 +839,8 @@ void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab, continue; } pTab2 = pDict->getTable(pTab->getName()); + } else if(!pTab2) { + pTab2 = pTab; } ctx = new NDBT_Context(); From 3e779698ab519aaec70fe1292ff5a7565e8d533a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Nov 2004 08:06:39 +0000 Subject: [PATCH 17/48] aligned connect string option on all cluster executables, --ndb-connectstring is now supported by all enabled new section in my.cnf [mysql_cluster], which is read by all executables, where connect string can be put for all cluster executables --- ndb/include/util/ndb_opts.h | 18 ++++++++++++------ ndb/src/kernel/vm/Configuration.cpp | 2 +- ndb/src/mgmclient/main.cpp | 2 +- ndb/src/mgmsrv/main.cpp | 12 ++++++++---- ndb/tools/delete_all.cpp | 2 +- ndb/tools/desc.cpp | 2 +- ndb/tools/drop_index.cpp | 2 +- ndb/tools/drop_tab.cpp | 2 +- ndb/tools/listTables.cpp | 2 +- ndb/tools/restore/restore_main.cpp | 2 +- ndb/tools/select_all.cpp | 2 +- ndb/tools/select_count.cpp | 2 +- ndb/tools/waiter.cpp | 2 +- 13 files changed, 31 insertions(+), 21 deletions(-) diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index 6cba9c04449..f7ae3b5489e 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -32,10 +32,13 @@ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ { "version", 'V', "Output version information and exit.", 0, 0, 0, \ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ - { "connect-string", 'c', \ + { "ndb-connectstring", 'c', \ "Set connect string for connecting to ndb_mgmd. " \ - "=\"host=[;nodeid=]\". " \ - "Overides specifying entries in NDB_CONNECTSTRING and config file", \ + "Syntax: \"[nodeid=;][host=][:]\". " \ + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \ + (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "connect-string", 'c', "same as --ndb-connectstring",\ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } #else @@ -46,11 +49,14 @@ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ { "version", 'V', "Output version information and exit.", 0, 0, 0, \ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ - { "connect-string", 'c', \ + { "ndb-connectstring", 'c', \ "Set connect string for connecting to ndb_mgmd. " \ - "=\"host=[;nodeid=]\". " \ - "Overides specifying entries in NDB_CONNECTSTRING and config file", \ + "Syntax: \"[nodeid=;][host=][:]\". " \ + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "connect-string", 'c', "same as --ndb-connectstring",\ + (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } #endif diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index aac035fe1b7..61615c85337 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -108,7 +108,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), bool Configuration::init(int argc, char** argv) { - const char *load_default_groups[]= { "ndbd",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndbd",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; diff --git a/ndb/src/mgmclient/main.cpp b/ndb/src/mgmclient/main.cpp index 401a9198f30..8cdba854fc4 100644 --- a/ndb/src/mgmclient/main.cpp +++ b/ndb/src/mgmclient/main.cpp @@ -138,7 +138,7 @@ int main(int argc, char** argv){ NDB_INIT(argv[0]); const char *_host = 0; int _port = 0; - const char *load_default_groups[]= { "ndb_mgm",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndb_mgm",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 76f0679b069..85bcb849d0e 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -110,10 +110,14 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "connect-string", 1023, + { "ndb-connectstring", 1023, "Set connect string for connecting to ndb_mgmd. " - "=\"host=[;nodeid=]\". " - "Overides specifying entries in NDB_CONNECTSTRING and config file", + "Syntax: \"[nodeid=;][host=][:]\". " + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", + (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "connect-string", 1023, + "same as --ndb-connectstring.", (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "config-file", 'f', "Specify cluster configuration file", @@ -196,7 +200,7 @@ int main(int argc, char** argv) global_mgmt_server_check = 1; glob.config_filename= "config.ini"; - const char *load_default_groups[]= { "ndb_mgmd",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndb_mgmd",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; diff --git a/ndb/tools/delete_all.cpp b/ndb/tools/delete_all.cpp index a4fd73a5128..046ac8005d2 100644 --- a/ndb/tools/delete_all.cpp +++ b/ndb/tools/delete_all.cpp @@ -67,7 +67,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/desc.cpp b/ndb/tools/desc.cpp index 8f7a2031ef0..c5e9efdfa8a 100644 --- a/ndb/tools/desc.cpp +++ b/ndb/tools/desc.cpp @@ -67,7 +67,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/drop_index.cpp b/ndb/tools/drop_index.cpp index 1d4b454682f..6600811e0c4 100644 --- a/ndb/tools/drop_index.cpp +++ b/ndb/tools/drop_index.cpp @@ -64,7 +64,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/drop_tab.cpp b/ndb/tools/drop_tab.cpp index 3362c7de47b..0661a8c599b 100644 --- a/ndb/tools/drop_tab.cpp +++ b/ndb/tools/drop_tab.cpp @@ -64,7 +64,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/listTables.cpp b/ndb/tools/listTables.cpp index 05e864a35c4..b923207a4fe 100644 --- a/ndb/tools/listTables.cpp +++ b/ndb/tools/listTables.cpp @@ -220,7 +220,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); const char* _tabname; - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index c43791c6723..409ebd54764 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -143,7 +143,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), bool readArguments(int *pargc, char*** pargv) { - const char *load_default_groups[]= { "ndb_tools","ndb_restore",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 }; load_defaults("my",load_default_groups,pargc,pargv); if (handle_options(pargc, pargv, my_long_options, get_one_option)) { diff --git a/ndb/tools/select_all.cpp b/ndb/tools/select_all.cpp index 758c1e48c88..77e5e14548e 100644 --- a/ndb/tools/select_all.cpp +++ b/ndb/tools/select_all.cpp @@ -105,7 +105,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); const char* _tabname; int ho_error; diff --git a/ndb/tools/select_count.cpp b/ndb/tools/select_count.cpp index 6ee49ddbff0..c3491f842d8 100644 --- a/ndb/tools/select_count.cpp +++ b/ndb/tools/select_count.cpp @@ -83,7 +83,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/waiter.cpp b/ndb/tools/waiter.cpp index e24164ea807..753e56cabde 100644 --- a/ndb/tools/waiter.cpp +++ b/ndb/tools/waiter.cpp @@ -75,7 +75,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); const char* _hostName = NULL; int ho_error; From 404b1524857330187a01209465758e2e02ad8bdb Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Nov 2004 10:47:59 +0000 Subject: [PATCH 18/48] removed unused variables assigned "localhost" as default connectstring added a disconnect() first in connect() removed double implementation of connect code, use connect() in NdbRestarter removed extra "host=" in connectstring ndb/include/mgmapi/mgmapi.h: removed wrong comment ndb/test/include/NdbRestarter.hpp: removed unused variables ndb/test/src/NdbBackup.cpp: removed double implementation of connect code, use connect() in NdbRestarter removed extra "host=" in connectstring ndb/test/src/NdbRestarter.cpp: removed unused variables assigned "localhost" as default connectstring added a disconnect() first in connect() --- ndb/include/mgmapi/mgmapi.h | 2 -- ndb/test/include/NdbRestarter.hpp | 2 -- ndb/test/src/NdbBackup.cpp | 31 ++++++++++++------------------- ndb/test/src/NdbRestarter.cpp | 4 ++-- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index a4e1fc1d1a8..a23417f153a 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -356,8 +356,6 @@ extern "C" { /** * Create a handle to a management server * - * @param connect_string Connect string to the management server, - * * @return A management handle
* or NULL if no management handle could be created. */ diff --git a/ndb/test/include/NdbRestarter.hpp b/ndb/test/include/NdbRestarter.hpp index 114726f6a2b..19a88b4f8ad 100644 --- a/ndb/test/include/NdbRestarter.hpp +++ b/ndb/test/include/NdbRestarter.hpp @@ -87,8 +87,6 @@ protected: bool connected; BaseString addr; - BaseString host; - int port; NdbMgmHandle handle; ndb_mgm_configuration * m_config; protected: diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 398a7c32fc4..655fdda7c95 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -69,26 +69,19 @@ NdbBackup::getBackupDataDirForNode(int _node_id){ /** * Fetch configuration from management server */ - ConfigRetriever cr(0, 0, NODE_TYPE_API); - ndb_mgm_configuration * p = 0; + ndb_mgm_configuration *p; + if (connect()) + return NULL; - BaseString tmp; tmp.assfmt("%s:%d", host.c_str(), port); - NdbMgmHandle handle = ndb_mgm_create_handle(); - if(handle == 0 || - ndb_mgm_set_connectstring(handle,tmp.c_str()) != 0 || - ndb_mgm_connect(handle,0,0,0) != 0 || - (p = ndb_mgm_get_configuration(handle, 0)) == 0){ - - const char * s = 0; - if(p == 0 && handle != 0){ - s = ndb_mgm_get_latest_error_msg(handle); - if(s == 0) - s = "No error given!"; + if ((p = ndb_mgm_get_configuration(handle, 0)) == 0) + { + const char * s= ndb_mgm_get_latest_error_msg(handle); + if(s == 0) + s = "No error given!"; - ndbout << "Could not fetch configuration" << endl; - ndbout << s << endl; - return NULL; - } + ndbout << "Could not fetch configuration" << endl; + ndbout << s << endl; + return NULL; } /** @@ -153,7 +146,7 @@ NdbBackup::execRestore(bool _restore_data, ndbout << "scp res: " << res << endl; - BaseString::snprintf(buf, 255, "%sndb_restore -c \"host=%s\" -n %d -b %d %s %s .", + BaseString::snprintf(buf, 255, "%sndb_restore -c \"%s\" -n %d -b %d %s %s .", #if 1 "", #else diff --git a/ndb/test/src/NdbRestarter.cpp b/ndb/test/src/NdbRestarter.cpp index e1802f36e82..1c5fbbabb42 100644 --- a/ndb/test/src/NdbRestarter.cpp +++ b/ndb/test/src/NdbRestarter.cpp @@ -32,12 +32,11 @@ NdbRestarter::NdbRestarter(const char* _addr): connected(false), - port(-1), handle(NULL), m_config(0) { if (_addr == NULL){ - addr.assign(""); + addr.assign("localhost"); } else { addr.assign(_addr); } @@ -360,6 +359,7 @@ NdbRestarter::isConnected(){ int NdbRestarter::connect(){ + disconnect(); handle = ndb_mgm_create_handle(); if (handle == NULL){ g_err << "handle == NULL" << endl; From cfca008544454203b914c5e2888acd0034a0df20 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Nov 2004 13:41:46 +0000 Subject: [PATCH 19/48] added force send interface to scan prepared for using query cache in ndb ndb/include/ndbapi/NdbIndexScanOperation.hpp: added force send interface to scan ndb/include/ndbapi/NdbResultSet.hpp: added force send interface to scan ndb/include/ndbapi/NdbScanOperation.hpp: added force send interface to scan ndb/src/ndbapi/NdbResultSet.cpp: added force send interface to scan ndb/src/ndbapi/NdbScanOperation.cpp: added force send interface to scan --- ndb/include/ndbapi/NdbIndexScanOperation.hpp | 6 +-- ndb/include/ndbapi/NdbResultSet.hpp | 6 +-- ndb/include/ndbapi/NdbScanOperation.hpp | 11 +++-- ndb/src/ndbapi/NdbResultSet.cpp | 12 ++--- ndb/src/ndbapi/NdbScanOperation.cpp | 50 +++++++++++++------- sql/ha_ndbcluster.cc | 33 ++++++++----- sql/ha_ndbcluster.h | 2 + 7 files changed, 74 insertions(+), 46 deletions(-) diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index 66b3fc9d43b..a3388f62f58 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -113,7 +113,7 @@ public: * Reset bounds and put operation in list that will be * sent on next execute */ - int reset_bounds(); + int reset_bounds(bool forceSend = false); bool getSorted() const { return m_ordered; } private: @@ -127,8 +127,8 @@ private: virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*); void fix_get_values(); - int next_result_ordered(bool fetchAllowed); - int send_next_scan_ordered(Uint32 idx); + int next_result_ordered(bool fetchAllowed, bool forceSend = false); + int send_next_scan_ordered(Uint32 idx, bool forceSend = false); int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*); Uint32 m_sort_columns; diff --git a/ndb/include/ndbapi/NdbResultSet.hpp b/ndb/include/ndbapi/NdbResultSet.hpp index 478daf8aad2..dc0288a380c 100644 --- a/ndb/include/ndbapi/NdbResultSet.hpp +++ b/ndb/include/ndbapi/NdbResultSet.hpp @@ -89,17 +89,17 @@ public: * - 1: if there are no more tuples to scan. * - 2: if there are no more cached records in NdbApi */ - int nextResult(bool fetchAllowed = true); + int nextResult(bool fetchAllowed = true, bool forceSend = false); /** * Close result set (scan) */ - void close(); + void close(bool forceSend = false); /** * Restart */ - int restart(); + int restart(bool forceSend = false); /** * Transfer scan operation to an updating transaction. Use this function diff --git a/ndb/include/ndbapi/NdbScanOperation.hpp b/ndb/include/ndbapi/NdbScanOperation.hpp index 2e4d173ac75..3c95c79e776 100644 --- a/ndb/include/ndbapi/NdbScanOperation.hpp +++ b/ndb/include/ndbapi/NdbScanOperation.hpp @@ -90,11 +90,11 @@ protected: NdbScanOperation(Ndb* aNdb); virtual ~NdbScanOperation(); - int nextResult(bool fetchAllowed = true); + int nextResult(bool fetchAllowed = true, bool forceSend = false); virtual void release(); - void closeScan(); - int close_impl(class TransporterFacade*); + void closeScan(bool forceSend = false); + int close_impl(class TransporterFacade*, bool forceSend = false); // Overloaded methods from NdbCursorOperation int executeCursor(int ProcessorId); @@ -103,6 +103,7 @@ protected: int init(const NdbTableImpl* tab, NdbConnection* myConnection); int prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId); int doSend(int ProcessorId); + void checkForceSend(bool forceSend); virtual void setErrorCode(int aErrorCode); virtual void setErrorCodeAbort(int aErrorCode); @@ -138,7 +139,7 @@ protected: Uint32 m_sent_receivers_count; // NOTE needs mutex to access NdbReceiver** m_sent_receivers; // receive thread puts them here - int send_next_scan(Uint32 cnt, bool close); + int send_next_scan(Uint32 cnt, bool close, bool forceSend = false); void receiver_delivered(NdbReceiver*); void receiver_completed(NdbReceiver*); void execCLOSE_SCAN_REP(); @@ -148,7 +149,7 @@ protected: Uint32 m_ordered; - int restart(); + int restart(bool forceSend = false); }; inline diff --git a/ndb/src/ndbapi/NdbResultSet.cpp b/ndb/src/ndbapi/NdbResultSet.cpp index f270584d227..d9d71464026 100644 --- a/ndb/src/ndbapi/NdbResultSet.cpp +++ b/ndb/src/ndbapi/NdbResultSet.cpp @@ -44,10 +44,10 @@ void NdbResultSet::init() { } -int NdbResultSet::nextResult(bool fetchAllowed) +int NdbResultSet::nextResult(bool fetchAllowed, bool forceSend) { int res; - if ((res = m_operation->nextResult(fetchAllowed)) == 0) { + if ((res = m_operation->nextResult(fetchAllowed, forceSend)) == 0) { // handle blobs NdbBlob* tBlob = m_operation->theBlobList; while (tBlob != 0) { @@ -67,9 +67,9 @@ int NdbResultSet::nextResult(bool fetchAllowed) return res; } -void NdbResultSet::close() +void NdbResultSet::close(bool forceSend) { - m_operation->closeScan(); + m_operation->closeScan(forceSend); } NdbOperation* @@ -98,6 +98,6 @@ NdbResultSet::deleteTuple(NdbConnection * takeOverTrans){ } int -NdbResultSet::restart(){ - return m_operation->restart(); +NdbResultSet::restart(bool forceSend){ + return m_operation->restart(forceSend); } diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 4b10ebb10cd..33fa826e470 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -447,10 +447,11 @@ NdbScanOperation::executeCursor(int nodeId){ #define DEBUG_NEXT_RESULT 0 -int NdbScanOperation::nextResult(bool fetchAllowed) +int NdbScanOperation::nextResult(bool fetchAllowed, bool forceSend) { if(m_ordered) - return ((NdbIndexScanOperation*)this)->next_result_ordered(fetchAllowed); + return ((NdbIndexScanOperation*)this)->next_result_ordered(fetchAllowed, + forceSend); /** * Check current receiver @@ -487,7 +488,8 @@ int NdbScanOperation::nextResult(bool fetchAllowed) TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); Uint32 seq = theNdbCon->theNodeSequence; - if(seq == tp->getNodeSequence(nodeId) && send_next_scan(idx, false) == 0){ + if(seq == tp->getNodeSequence(nodeId) && send_next_scan(idx, false, + forceSend) == 0){ idx = m_current_api_receiver; last = m_api_receivers_count; @@ -578,7 +580,8 @@ int NdbScanOperation::nextResult(bool fetchAllowed) } int -NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ +NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag, + bool forceSend){ if(cnt > 0 || stopScanFlag){ NdbApiSignal tSignal(theNdb->theMyRef); tSignal.setSignal(GSN_SCAN_NEXTREQ); @@ -618,6 +621,8 @@ NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ ret = tp->sendSignal(&tSignal, nodeId); } + if (!ret) checkForceSend(forceSend); + m_sent_receivers_count = last + cnt + stopScanFlag; m_api_receivers_count -= cnt; m_current_api_receiver = 0; @@ -627,6 +632,15 @@ NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ return 0; } +void NdbScanOperation::checkForceSend(bool forceSend) +{ + if (forceSend) { + TransporterFacade::instance()->forceSend(theNdb->theNdbBlockNumber); + } else { + TransporterFacade::instance()->checkForceSend(theNdb->theNdbBlockNumber); + }//if +} + int NdbScanOperation::prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId) { @@ -642,7 +656,7 @@ NdbScanOperation::doSend(int ProcessorId) return 0; } -void NdbScanOperation::closeScan() +void NdbScanOperation::closeScan(bool forceSend) { if(m_transConnection){ if(DEBUG_NEXT_RESULT) @@ -657,7 +671,7 @@ void NdbScanOperation::closeScan() TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); - close_impl(tp); + close_impl(tp, forceSend); } while(0); @@ -1293,7 +1307,8 @@ NdbIndexScanOperation::compare(Uint32 skip, Uint32 cols, } int -NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ +NdbIndexScanOperation::next_result_ordered(bool fetchAllowed, + bool forceSend){ Uint32 u_idx = 0, u_last = 0; Uint32 s_idx = m_current_api_receiver; // first sorted @@ -1319,7 +1334,8 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ Guard guard(tp->theMutexPtr); Uint32 seq = theNdbCon->theNodeSequence; Uint32 nodeId = theNdbCon->theDBnode; - if(seq == tp->getNodeSequence(nodeId) && !send_next_scan_ordered(s_idx)){ + if(seq == tp->getNodeSequence(nodeId) && + !send_next_scan_ordered(s_idx, forceSend)){ Uint32 tmp = m_sent_receivers_count; s_idx = m_current_api_receiver; while(m_sent_receivers_count > 0 && !theError.code){ @@ -1408,7 +1424,7 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ } int -NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ +NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx, bool forceSend){ if(idx == theParallelism) return 0; @@ -1440,11 +1456,13 @@ NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ Uint32 nodeId = theNdbCon->theDBnode; TransporterFacade * tp = TransporterFacade::instance(); tSignal.setLength(4+1); - return tp->sendSignal(&tSignal, nodeId); + int ret= tp->sendSignal(&tSignal, nodeId); + if (!ret) checkForceSend(forceSend); + return ret; } int -NdbScanOperation::close_impl(TransporterFacade* tp){ +NdbScanOperation::close_impl(TransporterFacade* tp, bool forceSend){ Uint32 seq = theNdbCon->theNodeSequence; Uint32 nodeId = theNdbCon->theDBnode; @@ -1473,7 +1491,7 @@ NdbScanOperation::close_impl(TransporterFacade* tp){ if(m_api_receivers_count+m_conf_receivers_count){ // Send close scan - if(send_next_scan(0, true) == -1){ // Close scan + if(send_next_scan(0, true, forceSend) == -1){ // Close scan theNdbCon->theReleaseOnClose = true; return -1; } @@ -1520,7 +1538,7 @@ NdbScanOperation::reset_receivers(Uint32 parallell, Uint32 ordered){ } int -NdbScanOperation::restart() +NdbScanOperation::restart(bool forceSend) { TransporterFacade* tp = TransporterFacade::instance(); @@ -1529,7 +1547,7 @@ NdbScanOperation::restart() { int res; - if((res= close_impl(tp))) + if((res= close_impl(tp, forceSend))) { return res; } @@ -1548,13 +1566,13 @@ NdbScanOperation::restart() } int -NdbIndexScanOperation::reset_bounds(){ +NdbIndexScanOperation::reset_bounds(bool forceSend){ int res; { TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); - res= close_impl(tp); + res= close_impl(tp, forceSend); } if(!res) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index bec4dfd9401..6f7940caf75 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1247,7 +1247,7 @@ inline int ha_ndbcluster::next_result(byte *buf) m_ops_pending= 0; m_blobs_pending= FALSE; } - check= cursor->nextResult(contact_ndb); + check= cursor->nextResult(contact_ndb, m_force_send); if (check == 0) { // One more record found @@ -1540,7 +1540,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, DBUG_ASSERT(op->getSorted() == sorted); DBUG_ASSERT(op->getLockMode() == (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); - if(op->reset_bounds()) + if(op->reset_bounds(m_force_send)) DBUG_RETURN(ndb_err(m_active_trans)); } @@ -2367,7 +2367,7 @@ int ha_ndbcluster::index_last(byte *buf) int res; if((res= ordered_index_scan(0, 0, TRUE, buf)) == 0){ NdbResultSet *cursor= m_active_cursor; - while((res= cursor->nextResult(TRUE)) == 0); + while((res= cursor->nextResult(TRUE, m_force_send)) == 0); if(res == 1){ unpack_record(buf); table->status= 0; @@ -2453,7 +2453,7 @@ int ha_ndbcluster::rnd_init(bool scan) { if (!scan) DBUG_RETURN(1); - int res= cursor->restart(); + int res= cursor->restart(m_force_send); DBUG_ASSERT(res == 0); } index_init(table->primary_key); @@ -2484,7 +2484,7 @@ int ha_ndbcluster::close_scan() m_ops_pending= 0; } - cursor->close(); + cursor->close(m_force_send); m_active_cursor= NULL; DBUG_RETURN(0); } @@ -3004,6 +3004,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) m_transaction_on= FALSE; else m_transaction_on= thd->variables.ndb_use_transactions; + // m_use_local_query_cache= thd->variables.ndb_use_local_query_cache; m_active_trans= thd->transaction.all.ndb_tid ? (NdbConnection*)thd->transaction.all.ndb_tid: @@ -3728,7 +3729,8 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_ha_not_exact_count(FALSE), m_force_send(TRUE), m_autoincrement_prefetch(32), - m_transaction_on(TRUE) + m_transaction_on(TRUE), + m_use_local_query_cache(FALSE) { int i; @@ -4415,7 +4417,7 @@ bool ha_ndbcluster::low_byte_first() const } bool ha_ndbcluster::has_transactions() { - return TRUE; + return m_transaction_on; } const char* ha_ndbcluster::index_type(uint key_number) { @@ -4432,7 +4434,10 @@ const char* ha_ndbcluster::index_type(uint key_number) } uint8 ha_ndbcluster::table_cache_type() { - return HA_CACHE_TBL_NOCACHE; + if (m_use_local_query_cache) + return HA_CACHE_TBL_TRANSACT; + else + return HA_CACHE_TBL_NOCACHE; } /* @@ -4600,13 +4605,12 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, { DBUG_ENTER("ndb_get_table_statistics"); DBUG_PRINT("enter", ("table: %s", table)); - + NdbConnection* pTrans= ndb->startTransaction(); do { - NdbConnection* pTrans= ndb->startTransaction(); if (pTrans == NULL) break; - + NdbScanOperation* pOp= pTrans->getNdbScanOperation(table); if (pOp == NULL) break; @@ -4623,13 +4627,13 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, pOp->getValue(NdbDictionary::Column::ROW_COUNT, (char*)&rows); pOp->getValue(NdbDictionary::Column::COMMIT_COUNT, (char*)&commits); - check= pTrans->execute(NoCommit); + check= pTrans->execute(NoCommit, AbortOnError, TRUE); if (check == -1) break; Uint64 sum_rows= 0; Uint64 sum_commits= 0; - while((check= rs->nextResult(TRUE)) == 0) + while((check= rs->nextResult(TRUE, TRUE)) == 0) { sum_rows+= rows; sum_commits+= commits; @@ -4638,6 +4642,8 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, if (check == -1) break; + rs->close(TRUE); + ndb->closeTransaction(pTrans); if(row_count) * row_count= sum_rows; @@ -4647,6 +4653,7 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, DBUG_RETURN(0); } while(0); + ndb->closeTransaction(pTrans); DBUG_PRINT("exit", ("failed")); DBUG_RETURN(-1); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 9d7cba459cb..6b878681c05 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -238,10 +238,12 @@ class ha_ndbcluster: public handler char *m_blobs_buffer; uint32 m_blobs_buffer_size; uint m_dupkey; + // set from thread variables at external lock bool m_ha_not_exact_count; bool m_force_send; ha_rows m_autoincrement_prefetch; bool m_transaction_on; + bool m_use_local_query_cache; void set_rec_per_key(); void records_update(); From 223c5d04a0d3e58f3498ec11c1dff7ace3d802f2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Nov 2004 15:27:28 +0100 Subject: [PATCH 20/48] wl2077 - bug fix for SCAN_TABREF ndb/src/ndbapi/NdbScanOperation.cpp: 1 more fix of premature scan closure --- ndb/src/ndbapi/NdbScanOperation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index c037fe732fc..282b831f8fd 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -688,7 +688,7 @@ NdbScanOperation::execCLOSE_SCAN_REP(){ m_api_receivers_count = 0; m_conf_receivers_count = 0; m_sent_receivers_count = 0; - m_current_api_receiver = theParallelism; + m_current_api_receiver = m_ordered ? theParallelism : 0; } void NdbScanOperation::release() From 0b6f218e710ce1a3822a2c5e960bc8ce0de6704d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Nov 2004 09:12:56 +0000 Subject: [PATCH 21/48] small bug fix for ndb restarter --- ndb/test/src/NdbBackup.cpp | 5 +++-- ndb/test/src/NdbRestarter.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 655fdda7c95..09f52bf0bed 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -146,13 +146,14 @@ NdbBackup::execRestore(bool _restore_data, ndbout << "scp res: " << res << endl; - BaseString::snprintf(buf, 255, "%sndb_restore -c \"%s\" -n %d -b %d %s %s .", + BaseString::snprintf(buf, 255, "%sndb_restore -c \"%s:%d\" -n %d -b %d %s %s .", #if 1 "", #else "valgrind --leak-check=yes -v " #endif - addr.c_str(), + ndb_mgm_get_connected_host(handle), + ndb_mgm_get_connected_port(handle), _node_id, _backup_id, _restore_data?"-r":"", diff --git a/ndb/test/src/NdbRestarter.cpp b/ndb/test/src/NdbRestarter.cpp index 1c5fbbabb42..91c0963feae 100644 --- a/ndb/test/src/NdbRestarter.cpp +++ b/ndb/test/src/NdbRestarter.cpp @@ -36,7 +36,7 @@ NdbRestarter::NdbRestarter(const char* _addr): m_config(0) { if (_addr == NULL){ - addr.assign("localhost"); + addr.assign(""); } else { addr.assign(_addr); } From a9aff01ebdf9e1ea27c6e7cc0fef8c1c406df454 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Nov 2004 17:18:41 +0100 Subject: [PATCH 22/48] Change "Do-compile" to make automatic build log analysis easier and to run the standard tests with "--force" (default, can be switched off). Build-tools/Do-compile: 1) For an automated log analysis, we need a clear marker in the build log whether compile + link succeeded: Write it after successful "make". 2) Ensure the standard tests are run with "--force" in the default case, but allow the old behaviour by an option "--one-error". 3) Correct a typing error in the usage message. --- Build-tools/Do-compile | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index f92af463a0a..af03f3209aa 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -10,7 +10,7 @@ use Sys::Hostname; $opt_distribution=$opt_user=$opt_config_env=$opt_config_extra_env=""; $opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_suffix=""; $opt_tmp=$opt_version_suffix=""; -$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=0; +$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_one_error=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=0; $opt_innodb=$opt_bdb=$opt_raid=$opt_libwrap=$opt_clearlogs=$opt_without_ndbcluster=0; GetOptions( @@ -36,6 +36,7 @@ GetOptions( "no-test", "no-mysqltest", "no-benchmark", + "one-error", "perl-files=s", "perl-options=s", "raid", @@ -298,6 +299,7 @@ if ($opt_stage <= 2) $command=$make; $command.= " $opt_make_options" if (defined($opt_make_options) && $opt_make_options ne ""); safe_system($command); + print LOG "Do-compile: Build successful\n"; } # @@ -358,10 +360,16 @@ $ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" . # if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest) { + my $force= ""; + if (!$opt_one_error) + { + $force= "--force"; # default + } log_timestamp(); system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir); safe_cd("${test_dir}/mysql-test"); - check_system("./mysql-test-run --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful"); + check_system("./mysql-test-run $force --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful"); + # 'mysql-test-run' writes its own final message for log evaluation. } # @@ -535,7 +543,10 @@ Do not run any tests. Do not run the benchmark test (written in perl) --no-mysqltest -Do not run the the mysql-test-run test (Same as 'make test') +Do not run the mysql-test-run test (Same as 'make test') + +--one-error +Terminate the mysql-test-run test after the first difference (default: use '--force') --perl-files=list of files Compile and install the given perl modules. From 343b645ba2b038e8f545057672f3f22e0a9bcce8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 09:36:49 +0100 Subject: [PATCH 23/48] ndb - debug printout ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: print state on rare crash --- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 5622706a96c..a40c7842fcd 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -3084,6 +3084,7 @@ void Dblqh::execATTRINFO(Signal* signal) return; break; default: + ndbout_c("%d", regTcPtr->transactionState); ndbrequire(false); break; }//switch From e26a5dbc6a4a9cd24f12d20bf08c3988ee5d0527 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 09:39:05 +0100 Subject: [PATCH 24/48] ndb - Add testcase to autotest ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: print on state on rare crash ndb/test/run-test/daily-basic-tests.txt: more test cases --- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 1 + ndb/test/run-test/daily-basic-tests.txt | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index fc0f39a4f5f..432bb1511aa 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -3084,6 +3084,7 @@ void Dblqh::execATTRINFO(Signal* signal) return; break; default: + ndbout_c("%d", regTcPtr->transactionState); ndbrequire(false); break; }//switch diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index 8d7e8a06c72..aa38fb4763c 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -222,6 +222,10 @@ max-time: 500 cmd: testScan args: -n ScanRead488 -l 10 T6 +max-time: 500 +cmd: testScan +args: -n ScanRead488Timeout -l 10 T6 + max-time: 600 cmd: testScan args: -n ScanRead40 -l 100 T2 From 135cdcef24a41e07495baae1b5e01f7ba897e031 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 13:28:48 +0400 Subject: [PATCH 25/48] uca-dump.c: Use less wide spaces on the primary level, to avoid big diff for ctype-uca.c. strings/uca-dump.c: Use less wide spaces on the primary level, to avoid big diff for ctype-uca.c. --- strings/uca-dump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/strings/uca-dump.c b/strings/uca-dump.c index db5cb7e999a..dd3b74a55e8 100644 --- a/strings/uca-dump.c +++ b/strings/uca-dump.c @@ -269,7 +269,7 @@ int main(int ac, char **av) */ int tmp= weight[i]; if (w == 2 && tmp) - tmp= (int)(0x100 - weight[i]); + tmp= (int)(0x20 - weight[i]); printf("0x%04X", tmp); @@ -304,7 +304,7 @@ int main(int ac, char **av) const char *comma= page < MY_UCA_NPAGES-1 ? "," : ""; const char *nline= (page+1) % 4 ? "" : "\n"; if (!pagemaxlen[page]) - printf("NULL %s%s", comma , nline); + printf("NULL %s%s%s", w ? " ": "", comma , nline); else printf("page%03Xdata%s%s%s", page, pname[w], comma, nline); } From 5909722f04b80ad9ac9eb0d44a723e2a75c9d860 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 11:01:54 +0100 Subject: [PATCH 26/48] harmless "buffer overflow" fixed --- myisam/mi_test3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c index dca04a9a64b..27d23317b5c 100644 --- a/myisam/mi_test3.c +++ b/myisam/mi_test3.c @@ -40,7 +40,7 @@ #endif -const char *filename= "test3.MSI"; +const char *filename= "test3"; uint tests=10,forks=10,key_cacheing=0,use_log=0; static void get_options(int argc, char *argv[]); @@ -363,7 +363,7 @@ int test_write(MI_INFO *file,int id,int lock_type) } sprintf(record.id,"%7d",getpid()); - strmov(record.text,"Testing..."); + strnmov(record.text,"Testing...", sizeof(record.text)); tries=(uint) rnd(100)+10; for (i=count=0 ; i < tries ; i++) From 1b9ea9b3c835cdfc3f473273f47cb30f72d21b1b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 11:03:54 +0100 Subject: [PATCH 27/48] ndb - 4.1.8 is not online software upgradable with 4.1.7 (due to close scan optimizations) ndb/src/common/util/version.c: 4.1.8 is not online software upgradable with 4.1.7 (due to close scan optimizations) --- ndb/src/common/util/version.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c index 82acd949c46..f2b3d5bd522 100644 --- a/ndb/src/common/util/version.c +++ b/ndb/src/common/util/version.c @@ -70,7 +70,6 @@ struct NdbUpGradeCompatible { #ifndef TEST_VERSION struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { { MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact }, - { MAKE_VERSION(4,1,8), MAKE_VERSION(3,5,4), UG_Exact }, /* Aligned version with MySQL */ { 0, 0, UG_Null } }; From 3a56452c77ac116082d7734fa6e7f7f9ccc4b557 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 12:33:09 +0100 Subject: [PATCH 28/48] merge error --- client/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/client/Makefile.am b/client/Makefile.am index 0b261b1b105..fa317367f71 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -26,7 +26,6 @@ bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \ mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ client_priv.h -mysqladmin_SOURCES = mysqladmin.cc mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc mysqladmin_SOURCES = mysqladmin.cc mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) From 15edb7fc15fe78041409b3512f724913f57709d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 13:59:03 +0000 Subject: [PATCH 29/48] added mgmapi/mgmapi_config_parameters.h, mgmapi/mgmapi_config_parameters_debug.h to distribution --- ndb/include/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ndb/include/Makefile.am b/ndb/include/Makefile.am index 7b3f80b5560..61f55cf9d61 100644 --- a/ndb/include/Makefile.am +++ b/ndb/include/Makefile.am @@ -29,13 +29,13 @@ ndbapi/ndberror.h mgmapiinclude_HEADERS = \ mgmapi/mgmapi.h \ -mgmapi/mgmapi_debug.h +mgmapi/mgmapi_debug.h \ +mgmapi/mgmapi_config_parameters.h \ +mgmapi/mgmapi_config_parameters_debug.h noinst_HEADERS = \ ndb_global.h \ -ndb_net.h \ -mgmapi/mgmapi_config_parameters.h \ -mgmapi/mgmapi_config_parameters_debug.h +ndb_net.h EXTRA_DIST = debugger editline kernel logger mgmcommon \ portlib transporter util From 55ea7c8b0eb65d7834995774b1607011c0fd65f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 15:24:23 +0100 Subject: [PATCH 30/48] Ensure consistent sources up to 5.0 where a C++ problem occurs. client/mysqladmin.c: Cast to overcome a C vs. C++ signature problem, occurring in 5.0 where this is a C++ file. --- client/mysqladmin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqladmin.c b/client/mysqladmin.c index 153fcdde96d..978e0c7e88b 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -554,7 +554,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { char *pos,buff[40]; ulong sec; - pos=strchr(status,' '); + pos= (char*) strchr(status,' '); *pos++=0; printf("%s\t\t\t",status); /* print label */ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec))) From 98de7e010f6f3dda87a07b680a28beffbe75872f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 16:36:18 +0100 Subject: [PATCH 31/48] bug#6775 - ndb Queue scan on real fragment. Index fragment for range scans Table fragment for table scans ndb/src/kernel/blocks/dblqh/Dblqh.hpp: Document meaning of fragPtrI and how it differs from scanTcRec->fragmentptr ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: Queue scan on real fragment. Index fragment for range scans Table fragment for table scans ndb/src/ndbapi/NdbConnection.cpp: Check tOp before assigning --- ndb/src/kernel/blocks/dblqh/Dblqh.hpp | 5 +++ ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 41 ++++++++++++----------- ndb/src/ndbapi/NdbConnection.cpp | 7 ++-- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index 6c8c2bb2dae..0c63cb5fe17 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -550,6 +550,11 @@ public: UintR scanErrorCounter; UintR scanLocalFragid; UintR scanSchemaVersion; + + /** + * This is _always_ main table, even in range scan + * in which case scanTcrec->fragmentptr is different + */ Uint32 fragPtrI; UintR scanStoredProcId; ScanState scanState; diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 432bb1511aa..88e8f25b004 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -7703,6 +7703,9 @@ void Dblqh::abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode){ jam(); scanptr.i = scan_ptr_i; c_scanRecordPool.getPtr(scanptr); + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); finishScanrec(signal); releaseScanrec(signal); tcConnectptr.p->transactionState = TcConnectionrec::IDLE; @@ -8570,10 +8573,12 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) /** * Used for scan take over */ - FragrecordPtr tFragPtr; - tFragPtr.i = fragptr.p->tableFragptr; - ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); - scanptr.p->fragPtrI = fragptr.p->tableFragptr; + { + FragrecordPtr tFragPtr; + tFragPtr.i = fragptr.p->tableFragptr; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + scanptr.p->fragPtrI = fragptr.p->tableFragptr; + } /** * !idx uses 1 - (MAX_PARALLEL_SCANS_PER_FRAG - 1) = 1-11 @@ -8582,8 +8587,8 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) Uint32 start = (idx ? MAX_PARALLEL_SCANS_PER_FRAG : 1 ); Uint32 stop = (idx ? MAX_PARALLEL_INDEX_SCANS_PER_FRAG : MAX_PARALLEL_SCANS_PER_FRAG - 1); stop += start; - Uint32 free = tFragPtr.p->m_scanNumberMask.find(start); - + Uint32 free = fragptr.p->m_scanNumberMask.find(start); + if(free == Fragrecord::ScanNumberMask::NotFound || free >= stop){ jam(); @@ -8597,16 +8602,16 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) */ scanptr.p->scanState = ScanRecord::IN_QUEUE; LocalDLFifoList queue(c_scanRecordPool, - tFragPtr.p->m_queuedScans); + fragptr.p->m_queuedScans); queue.add(scanptr); return ZOK; } - + scanptr.p->scanNumber = free; - tFragPtr.p->m_scanNumberMask.clear(free);// Update mask + fragptr.p->m_scanNumberMask.clear(free);// Update mask - LocalDLList active(c_scanRecordPool, tFragPtr.p->m_activeScans); + LocalDLList active(c_scanRecordPool, fragptr.p->m_activeScans); active.add(scanptr); if(scanptr.p->scanKeyinfoFlag){ jam(); @@ -8666,12 +8671,8 @@ void Dblqh::finishScanrec(Signal* signal) { release_acc_ptr_list(scanptr.p); - FragrecordPtr tFragPtr; - tFragPtr.i = scanptr.p->fragPtrI; - ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); - LocalDLFifoList queue(c_scanRecordPool, - tFragPtr.p->m_queuedScans); + fragptr.p->m_queuedScans); if(scanptr.p->scanState == ScanRecord::IN_QUEUE){ jam(); @@ -8689,11 +8690,11 @@ void Dblqh::finishScanrec(Signal* signal) ndbrequire(tmp.p == scanptr.p); } - LocalDLList scans(c_scanRecordPool, tFragPtr.p->m_activeScans); + LocalDLList scans(c_scanRecordPool, fragptr.p->m_activeScans); scans.release(scanptr); const Uint32 scanNumber = scanptr.p->scanNumber; - ndbrequire(!tFragPtr.p->m_scanNumberMask.get(scanNumber)); + ndbrequire(!fragptr.p->m_scanNumberMask.get(scanNumber)); ScanRecordPtr restart; /** @@ -8701,13 +8702,13 @@ void Dblqh::finishScanrec(Signal* signal) */ if(scanNumber == NR_ScanNo || !queue.first(restart)){ jam(); - tFragPtr.p->m_scanNumberMask.set(scanNumber); + fragptr.p->m_scanNumberMask.set(scanNumber); return; } if(ERROR_INSERTED(5034)){ jam(); - tFragPtr.p->m_scanNumberMask.set(scanNumber); + fragptr.p->m_scanNumberMask.set(scanNumber); return; } @@ -8718,7 +8719,7 @@ void Dblqh::finishScanrec(Signal* signal) ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); restart.p->scanNumber = scanNumber; restart.p->scanState = ScanRecord::WAIT_ACC_SCAN; - + queue.remove(restart); scans.add(restart); if(restart.p->scanKeyinfoFlag){ diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index 6284ae8ce6e..f3ddc68245a 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -1086,8 +1086,11 @@ NdbConnection::getNdbIndexScanOperation(const NdbIndexImpl* index, if (indexTable != 0){ NdbIndexScanOperation* tOp = getNdbScanOperation((NdbTableImpl *) indexTable); - tOp->m_currentTable = table; - if(tOp) tOp->m_cursor_type = NdbScanOperation::IndexCursor; + if(tOp) + { + tOp->m_currentTable = table; + tOp->m_cursor_type = NdbScanOperation::IndexCursor; + } return tOp; } else { setOperationErrorCodeAbort(theNdb->theError.code); From 61dbdff2a6f80e15721e245d168f5f276d78b0b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 15:51:59 +0000 Subject: [PATCH 32/48] calculation of noOfTriggers --- ndb/src/kernel/vm/Configuration.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index 31853b7a3b7..92b09891a2f 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -34,6 +34,7 @@ #include #include +#include #include "pc.hpp" #include #include @@ -454,6 +455,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ unsigned int noOfTables = 0; unsigned int noOfUniqueHashIndexes = 0; unsigned int noOfOrderedIndexes = 0; + unsigned int noOfTriggers = 0; unsigned int noOfReplicas = 0; unsigned int noOfDBNodes = 0; unsigned int noOfAPINodes = 0; @@ -478,6 +480,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ { CFG_DB_NO_TABLES, &noOfTables, false }, { CFG_DB_NO_ORDERED_INDEXES, &noOfOrderedIndexes, false }, { CFG_DB_NO_UNIQUE_HASH_INDEXES, &noOfUniqueHashIndexes, false }, + { CFG_DB_NO_TRIGGERS, &noOfTriggers, true }, { CFG_DB_NO_REPLICAS, &noOfReplicas, false }, { CFG_DB_NO_ATTRIBUTES, &noOfAttributes, false }, { CFG_DB_NO_OPS, &noOfOperations, false }, @@ -586,6 +589,16 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ ConfigValues::Iterator it2(*ownConfig, db.m_config); it2.set(CFG_DB_NO_TABLES, noOfTables); it2.set(CFG_DB_NO_ATTRIBUTES, noOfAttributes); + { + Uint32 neededNoOfTriggers = + 3 * (noOfUniqueHashIndexes + NDB_MAX_ACTIVE_EVENTS)+ + noOfOrderedIndexes; + if (noOfTriggers < neededNoOfTriggers) + { + noOfTriggers= neededNoOfTriggers; + it2.set(CFG_DB_NO_TRIGGERS, noOfTriggers); + } + } /** * Do size calculations From f4db89ea85fdadbf32d4c24eb8c7b92fd84c0bc0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 16:04:11 +0000 Subject: [PATCH 33/48] also backup needs triggers --- ndb/src/kernel/vm/Configuration.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index 92b09891a2f..931b4da5a17 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -590,9 +590,11 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ it2.set(CFG_DB_NO_TABLES, noOfTables); it2.set(CFG_DB_NO_ATTRIBUTES, noOfAttributes); { - Uint32 neededNoOfTriggers = - 3 * (noOfUniqueHashIndexes + NDB_MAX_ACTIVE_EVENTS)+ - noOfOrderedIndexes; + Uint32 neededNoOfTriggers = /* types: Insert/Update/Delete/Custom */ + 3 * noOfUniqueHashIndexes + /* for unique hash indexes, I/U/D */ + 3 * NDB_MAX_ACTIVE_EVENTS + /* for events in suma, I/U/D */ + 3 * noOfTables + /* for backup, I/U/D */ + noOfOrderedIndexes; /* for ordered indexes, C */ if (noOfTriggers < neededNoOfTriggers) { noOfTriggers= neededNoOfTriggers; From 03cba628f6fdfaf66d4d737a87086aa360c6edf5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 20:09:54 +0400 Subject: [PATCH 34/48] Bug#6787 LIKE not working properly with _ and utf8 data --- mysql-test/r/ctype_uca.result | 3 +++ mysql-test/r/ctype_utf8.result | 3 +++ mysql-test/t/ctype_uca.test | 5 +++++ mysql-test/t/ctype_utf8.test | 6 ++++++ strings/ctype-uca.c | 4 +++- strings/ctype-utf8.c | 26 ++++++++++++++------------ 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 7620b18eea6..cb060ad7ee4 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -19,6 +19,9 @@ select 'a ' = 'a\t', 'a ' < 'a\t', 'a ' > 'a\t'; select 'a a' > 'a', 'a \t' < 'a'; 'a a' > 'a' 'a \t' < 'a' 1 1 +select 'c' like '\_' as want0; +want0 +0 CREATE TABLE t ( c char(20) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 945ec8eae99..599d49208e7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -814,3 +814,6 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t2; drop table t1; +select 'c' like '\_' as want0; +want0 +0 diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index e640e6b53dc..11833ba9bc7 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -24,6 +24,11 @@ select 'a ' = 'a\t', 'a ' < 'a\t', 'a ' > 'a\t'; select 'a a' > 'a', 'a \t' < 'a'; +# +# Bug #6787 LIKE not working properly with _ and utf8 data +# +select 'c' like '\_' as want0; + # # Bug #5679 utf8_unicode_ci LIKE--trailing % doesn't equal zero characters # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index c75b1dee63c..42031be8f3c 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -660,3 +660,9 @@ create table t2 select concat(a,_utf8'') as a, concat(b,_utf8'')as b from t1; show create table t2; drop table t2; drop table t1; + +# +# Bug #6787 LIKE not working properly with _ and utf8 data +# +select 'c' like '\_' as want0; + diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 8df5b3277c1..89c876ad10c 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -7288,6 +7288,7 @@ int my_wildcmp_uca(CHARSET_INFO *cs, { while (1) { + my_bool escaped= 0; if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, (const uchar*)wildend)) <= 0) return 1; @@ -7305,6 +7306,7 @@ int my_wildcmp_uca(CHARSET_INFO *cs, (const uchar*)wildend)) <= 0) return 1; wildstr+= scan; + escaped= 1; } if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, @@ -7312,7 +7314,7 @@ int my_wildcmp_uca(CHARSET_INFO *cs, return 1; str+= scan; - if (w_wc == (my_wc_t)w_one) + if (!escaped && w_wc == (my_wc_t)w_one) { result= 1; /* Found an anchor char */ } diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index b3097649158..ce9346eb475 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1545,31 +1545,33 @@ int my_wildcmp_unicode(CHARSET_INFO *cs, { while (1) { + my_bool escaped= 0; if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, (const uchar*)wildend)) <= 0) return 1; - - if (w_wc == (my_wc_t)escape) - { - wildstr+= scan; - if ((scan= mb_wc(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend)) <= 0) - return 1; - } - + if (w_wc == (my_wc_t)w_many) { result= 1; /* Found an anchor char */ break; } - + wildstr+= scan; + if (w_wc == (my_wc_t)escape) + { + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <= 0) + return 1; + wildstr+= scan; + escaped= 1; + } + if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, - (const uchar*)str_end)) <=0) + (const uchar*)str_end)) <= 0) return 1; str+= scan; - if (w_wc == (my_wc_t)w_one) + if (!escaped && w_wc == (my_wc_t)w_one) { result= 1; /* Found an anchor char */ } From 3392e3178a9dbf656cc8dceda760f08a73542704 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 19:32:10 +0300 Subject: [PATCH 35/48] Fixed bug related to lower case table names on Power Mac 'information_schema' test is splitted because of innodb mysql-test/r/information_schema.result: Test is splitted because of innodb mysql-test/t/information_schema.test: Test is splitted because of innodb sql/sql_show.cc: Fixed bug related to lower case table names on Power Mac sql/table.h: Fixed bug related to lower case table names on Power Mac tests/client_test.c: Don't check field length for blob filed --- mysql-test/r/information_schema.result | 25 +-------------------- mysql-test/r/information_schema_inno.result | 19 ++++++++++++++++ mysql-test/t/information_schema.test | 10 --------- mysql-test/t/information_schema_inno.test | 16 +++++++++++++ sql/sql_show.cc | 11 +++++---- sql/table.h | 2 +- tests/client_test.c | 5 +++-- 7 files changed, 45 insertions(+), 43 deletions(-) create mode 100644 mysql-test/r/information_schema_inno.result create mode 100644 mysql-test/t/information_schema_inno.test diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index cdbed168df2..8f5ac88b7d0 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -363,40 +363,17 @@ NULL test PRIMARY NULL test t1 a 1 NULL NULL NULL NULL test constraint_1 NULL test t1 a 1 NULL NULL NULL NULL test key_1 NULL test t1 a 1 NULL NULL NULL NULL test key_2 NULL test t1 a 1 NULL NULL NULL -drop table t1; -CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; -CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), -FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE, -FOREIGN KEY (t1_id) REFERENCES t1(id) ON UPDATE CASCADE) ENGINE=INNODB; -select * from information_schema.TABLE_CONSTRAINTS where -TABLE_SCHEMA= "test"; -CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE CONSTRAINT_METHOD -NULL test PRIMARY test t1 PRIMARY KEY NULL -NULL test PRIMARY test t2 PRIMARY KEY NULL -NULL test t2_ibfk_1 test t2 FOREIGN KEY ON DELETE CASCADE -NULL test t2_ibfk_2 test t2 FOREIGN KEY ON UPDATE CASCADE -select * from information_schema.KEY_COLUMN_USAGE where -TABLE_SCHEMA= "test"; -CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION REFERENCED_TABLE_SCHEMA REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME -NULL test PRIMARY NULL test t1 id 1 NULL NULL NULL -NULL test PRIMARY NULL test t2 id 1 NULL NULL NULL -NULL test t2_ibfk_1 NULL test t2 t1_id 1 NULL id -NULL test t2_ibfk_2 NULL test t2 t1_id 1 NULL id select table_name from information_schema.TABLES where table_schema like "test%"; table_name t1 -t2 select table_name,column_name from information_schema.COLUMNS where table_schema like "test%"; table_name column_name -t1 id -t2 id -t2 t1_id +t1 a select ROUTINE_NAME from information_schema.ROUTINES; ROUTINE_NAME sel2 sub1 delete from mysql.user where user='mysqltest_1'; -drop table t2; drop table t1; drop procedure sel2; drop function sub1; diff --git a/mysql-test/r/information_schema_inno.result b/mysql-test/r/information_schema_inno.result new file mode 100644 index 00000000000..e6dcda2c15d --- /dev/null +++ b/mysql-test/r/information_schema_inno.result @@ -0,0 +1,19 @@ +CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), +FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE, +FOREIGN KEY (t1_id) REFERENCES t1(id) ON UPDATE CASCADE) ENGINE=INNODB; +select * from information_schema.TABLE_CONSTRAINTS where +TABLE_SCHEMA= "test"; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE CONSTRAINT_METHOD +NULL test PRIMARY test t1 PRIMARY KEY NULL +NULL test PRIMARY test t2 PRIMARY KEY NULL +NULL test t2_ibfk_1 test t2 FOREIGN KEY ON DELETE CASCADE +NULL test t2_ibfk_2 test t2 FOREIGN KEY ON UPDATE CASCADE +select * from information_schema.KEY_COLUMN_USAGE where +TABLE_SCHEMA= "test"; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION REFERENCED_TABLE_SCHEMA REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME +NULL test PRIMARY NULL test t1 id 1 NULL NULL NULL +NULL test PRIMARY NULL test t2 id 1 NULL NULL NULL +NULL test t2_ibfk_1 NULL test t2 t1_id 1 NULL id +NULL test t2_ibfk_2 NULL test t2 t1_id 1 NULL id +drop table t2, t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index b52a3c2edec..411301445a3 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -162,16 +162,7 @@ select * from information_schema.TABLE_CONSTRAINTS where TABLE_SCHEMA= "test"; select * from information_schema.KEY_COLUMN_USAGE where TABLE_SCHEMA= "test"; -drop table t1; -CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; -CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), -FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE, -FOREIGN KEY (t1_id) REFERENCES t1(id) ON UPDATE CASCADE) ENGINE=INNODB; -select * from information_schema.TABLE_CONSTRAINTS where -TABLE_SCHEMA= "test"; -select * from information_schema.KEY_COLUMN_USAGE where -TABLE_SCHEMA= "test"; connect (user1,localhost,mysqltest_1,,); connection user1; @@ -181,7 +172,6 @@ select ROUTINE_NAME from information_schema.ROUTINES; disconnect user1; connection default; delete from mysql.user where user='mysqltest_1'; -drop table t2; drop table t1; drop procedure sel2; drop function sub1; diff --git a/mysql-test/t/information_schema_inno.test b/mysql-test/t/information_schema_inno.test new file mode 100644 index 00000000000..15643ebe90c --- /dev/null +++ b/mysql-test/t/information_schema_inno.test @@ -0,0 +1,16 @@ +-- source include/have_innodb.inc + +# +# Test for KEY_COLUMN_USAGE & TABLE_CONSTRAINTS tables +# + +CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), +FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE, +FOREIGN KEY (t1_id) REFERENCES t1(id) ON UPDATE CASCADE) ENGINE=INNODB; +select * from information_schema.TABLE_CONSTRAINTS where +TABLE_SCHEMA= "test"; +select * from information_schema.KEY_COLUMN_USAGE where +TABLE_SCHEMA= "test"; + +drop table t2, t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f41eab1ba14..55c38ff37c9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2909,12 +2909,13 @@ ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx) 0 Can't create table */ -TABLE *create_schema_table(THD *thd, ST_SCHEMA_TABLE *schema_table) +TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) { int field_count= 0; Item *item; TABLE *table; List field_list; + ST_SCHEMA_TABLE *schema_table= table_list->schema_table; ST_FIELD_INFO *fields_info= schema_table->fields_info; CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("create_schema_table"); @@ -2959,8 +2960,7 @@ TABLE *create_schema_table(THD *thd, ST_SCHEMA_TABLE *schema_table) field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->options | TMP_TABLE_ALL_COLUMNS), - HA_POS_ERROR, - (char *) schema_table->table_name))) + HA_POS_ERROR, table_list->real_name))) DBUG_RETURN(0); DBUG_RETURN(table); } @@ -3130,8 +3130,7 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { TABLE *table; DBUG_ENTER("mysql_schema_table"); - if (!(table= table_list->schema_table-> - create_table(thd, table_list->schema_table))) + if (!(table= table_list->schema_table->create_table(thd, table_list))) { DBUG_RETURN(1); } @@ -3292,7 +3291,7 @@ ST_FIELD_INFO columns_fields_info[]= {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, {"COLUMN_DEFAULT", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Default"}, {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"}, - {"DATA_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, 0}, + {"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, diff --git a/sql/table.h b/sql/table.h index 09c7719980b..235a7d9add7 100644 --- a/sql/table.h +++ b/sql/table.h @@ -243,7 +243,7 @@ typedef struct st_schema_table const char* table_name; ST_FIELD_INFO *fields_info; /* Create information_schema table */ - TABLE *(*create_table) (THD *thd, struct st_schema_table *schema_table); + TABLE *(*create_table) (THD *thd, struct st_table_list *table_list); /* Fill table with data */ int (*fill_table) (THD *thd, struct st_table_list *tables, COND *cond); /* Handle fileds for old SHOW */ diff --git a/tests/client_test.c b/tests/client_test.c index 4f76600aa2e..8bc945eac2c 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -694,7 +694,8 @@ static void verify_prepare_field(MYSQL_RES *result, as utf8. Field length is calculated as number of characters * maximum number of bytes a character can occupy. */ - DIE_UNLESS(field->length == length * cs->mbmaxlen); + if (length) + DIE_UNLESS(field->length == length * cs->mbmaxlen); if (def) DIE_UNLESS(strcmp(field->def, def) == 0); } @@ -7280,7 +7281,7 @@ static void test_explain_bug() MYSQL_TYPE_STRING, 0, 0, "", 192, 0); verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", - MYSQL_TYPE_BLOB, 0, 0, "", 193203, 0); + MYSQL_TYPE_BLOB, 0, 0, "", 0, 0); verify_prepare_field(result, 2, "Null", "IS_NULLABLE", MYSQL_TYPE_STRING, 0, 0, "", 9, 0); From 2f36bf74186fcb0129f576b01f3753ae0fa10d31 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 17:40:40 +0000 Subject: [PATCH 36/48] added explanation of error code 4335 --- ndb/src/ndbapi/ndberror.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index e08b80f2433..bc49358cc63 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -426,7 +426,8 @@ ErrorBundle ErrorCodes[] = { { 4267, IE, "Corrupted blob value" }, { 4268, IE, "Error in blob head update forced rollback of transaction" }, { 4268, IE, "Unknown blob error" }, - { 4269, IE, "No connection to ndb management server" } + { 4269, IE, "No connection to ndb management server" }, + { 4335, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" } }; static From c3272ae7186bb59a406a671080b98766dc8e4064 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 19:41:38 +0200 Subject: [PATCH 37/48] configure.in: Fix linking error in 5.0: the build system for Linux/S390 does not have inlining working in the compiler; remove inlining on that system innobase/configure.in: Fix linking error in 5.0: the build system for Linux/S390 does not have inlining working in the compiler; remove inlining on that system --- innobase/configure.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/innobase/configure.in b/innobase/configure.in index 652291f1f38..d83da9fdc5c 100644 --- a/innobase/configure.in +++ b/innobase/configure.in @@ -110,6 +110,9 @@ esac case "$target" in i[[4567]]86-*-*) CFLAGS="$CFLAGS -DUNIV_INTEL_X86";; + # The compiler on Linux/S390 does not seem to have inlining + s390-*-*) + CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; esac AC_OUTPUT(Makefile os/Makefile ut/Makefile btr/Makefile dnl From c774eb0e6d6ded18d8dabf0c718a4313780cbd24 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 19:48:30 +0200 Subject: [PATCH 38/48] fixed problem in MacOS correct printing of aliases mysql-test/r/lowercase_view.result: aliases in VIEWs mysql-test/t/lowercase_view.test: aliases in VIEWs sql/item.cc: tracking using aliases in indentifiers sql/item.h: tracking using aliases in indentifiers sql/sql_base.cc: tracking using aliases in indentifiers sql/sql_lex.cc: tracking using aliases in indentifiers sql/sql_lex.h: tracking using aliases in indentifiers sql/table.h: tracking using aliases in indentifiers --- mysql-test/r/lowercase_view.result | 16 ++++++++++++++++ mysql-test/t/lowercase_view.test | 15 +++++++++++++++ sql/item.cc | 13 ++++++++++--- sql/item.h | 1 + sql/sql_base.cc | 5 ++++- sql/sql_lex.cc | 27 +++++++++++++++++++++++++++ sql/sql_lex.h | 1 + sql/table.h | 1 + 8 files changed, 75 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/lowercase_view.result b/mysql-test/r/lowercase_view.result index 64b40389690..0644b32015c 100644 --- a/mysql-test/r/lowercase_view.result +++ b/mysql-test/r/lowercase_view.result @@ -22,3 +22,19 @@ insert into v2aA values ((select max(col1) from v1aA)); ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause drop view v2Aa,v1Aa; drop table t1Aa,t2Aa; +create table t1Aa (col1 int); +create view v1Aa as select col1 from t1Aa as AaA; +show create view v1AA; +View Create View +v1aa CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1aa` AS select `aaa`.`col1` AS `col1` from `test`.`t1aa` `AaA` +drop view v1AA; +select Aaa.col1 from t1Aa as AaA; +col1 +create view v1Aa as select Aaa.col1 from t1Aa as AaA; +drop view v1AA; +create view v1Aa as select AaA.col1 from t1Aa as AaA; +show create view v1AA; +View Create View +v1aa CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1aa` AS select `aaa`.`col1` AS `col1` from `test`.`t1aa` `AaA` +drop view v1AA; +drop table t1Aa; diff --git a/mysql-test/t/lowercase_view.test b/mysql-test/t/lowercase_view.test index 2a2757650ae..4b688cfb922 100644 --- a/mysql-test/t/lowercase_view.test +++ b/mysql-test/t/lowercase_view.test @@ -32,3 +32,18 @@ delete from v2aA where col1 = (select max(col1) from v1aA); insert into v2aA values ((select max(col1) from v1aA)); drop view v2Aa,v1Aa; drop table t1Aa,t2Aa; + +# +# aliases in VIEWs +# +create table t1Aa (col1 int); +create view v1Aa as select col1 from t1Aa as AaA; +show create view v1AA; +drop view v1AA; +select Aaa.col1 from t1Aa as AaA; +create view v1Aa as select Aaa.col1 from t1Aa as AaA; +drop view v1AA; +create view v1Aa as select AaA.col1 from t1Aa as AaA; +show create view v1AA; +drop view v1AA; +drop table t1Aa; diff --git a/sql/item.cc b/sql/item.cc index 42535b9c904..a3781677cf9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -138,7 +138,7 @@ bool Item::cleanup_processor(byte *arg) Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par) :orig_db_name(db_name_par), orig_table_name(table_name_par), - orig_field_name(field_name_par), + orig_field_name(field_name_par), alias_name_used(FALSE), db_name(db_name_par), table_name(table_name_par), field_name(field_name_par), cached_field_index(NO_CACHED_FIELD_INDEX), cached_table(0), depended_from(0) @@ -152,6 +152,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) orig_db_name(item->orig_db_name), orig_table_name(item->orig_table_name), orig_field_name(item->orig_field_name), + alias_name_used(item->alias_name_used), db_name(item->db_name), table_name(item->table_name), field_name(item->field_name), @@ -609,6 +610,7 @@ void Item_field::set_field(Field *field_par) table_name=field_par->table_name; field_name=field_par->field_name; db_name=field_par->table->table_cache_key; + alias_name_used= field_par->table->alias_name_used; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); collation.set(field_par->charset(), DERIVATION_IMPLICIT); fixed= 1; @@ -658,7 +660,8 @@ void Item_ident::print(String *str) THD *thd= current_thd; char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; const char *d_name= db_name, *t_name= table_name; - if (lower_case_table_names) + if (lower_case_table_names== 1 || + (lower_case_table_names == 2 && !alias_name_used)) { if (table_name && table_name[0]) { @@ -680,7 +683,7 @@ void Item_ident::print(String *str) append_identifier(thd, str, nm, strlen(nm)); return; } - if (db_name && db_name[0]) + if (db_name && db_name[0] && !alias_name_used) { append_identifier(thd, str, d_name, strlen(d_name)); str->append('.'); @@ -2911,6 +2914,10 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) decimals= (*ref)->decimals; collation.set((*ref)->collation); with_sum_func= (*ref)->with_sum_func; + if ((*ref)->type() == FIELD_ITEM) + alias_name_used= ((Item_ident *) (*ref))->alias_name_used; + else + alias_name_used= TRUE; // it is not field, so it is was resolved by alias fixed= 1; if (ref && (*ref)->check_cols(1)) diff --git a/sql/item.h b/sql/item.h index 9c036c28408..5dbcd902cfc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -459,6 +459,7 @@ public: const char *db_name; const char *table_name; const char *field_name; + bool alias_name_used; /* true if item was resolved against alias */ /* Cached value of index for this field in table->field array, used by prep. stmts for speeding up their re-execution. Holds NO_CACHED_FIELD_INDEX diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0373585af2a..299dbab6d75 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1050,8 +1050,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->reginfo.lock_type=TL_READ; /* Assume read */ reset: + if (thd->lex->need_correct_ident()) + table->alias_name_used= my_strcasecmp(table_alias_charset, + table->real_name, alias); /* Fix alias if table name changes */ - if (strcmp(table->table_name,alias)) + if (strcmp(table->table_name, alias)) { uint length=(uint) strlen(alias)+1; table->table_name= (char*) my_realloc(table->table_name,length, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1cbe004caa0..882a7372f46 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1724,6 +1724,7 @@ bool st_lex::can_not_use_merged() TRUE yes, we need only structure FALSE no, we need data */ + bool st_lex::only_view_structure() { switch(sql_command) @@ -1742,6 +1743,32 @@ bool st_lex::only_view_structure() } +/* + Should Items_ident be printed correctly + + SYNOPSIS + need_correct_ident() + + RETURN + TRUE yes, we need only structure + FALSE no, we need data +*/ + + +bool st_lex::need_correct_ident() +{ + switch(sql_command) + { + case SQLCOM_SHOW_CREATE: + case SQLCOM_SHOW_TABLES: + case SQLCOM_CREATE_VIEW: + return TRUE; + default: + return FALSE; + } +} + + /* initialize limit counters diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ce22caa13fc..e427de27d1d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -800,6 +800,7 @@ typedef struct st_lex bool can_use_merged(); bool can_not_use_merged(); bool only_view_structure(); + bool need_correct_ident(); } LEX; extern TABLE_LIST fake_time_zone_tables_list; diff --git a/sql/table.h b/sql/table.h index b12e82f3c73..e851f0d5e14 100644 --- a/sql/table.h +++ b/sql/table.h @@ -160,6 +160,7 @@ struct st_table { my_bool no_keyread, no_cache; my_bool clear_query_id; /* To reset query_id for tables and cols */ my_bool auto_increment_field_not_null; + my_bool alias_name_used; /* true if table_name is alias */ Field *next_number_field, /* Set if next_number is activated */ *found_next_number_field, /* Set on open */ *rowid_field; From 0f61fec47e427e7780dbe67900b173a5fd99ac73 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 22:18:28 +0400 Subject: [PATCH 39/48] A fix. Why didn't we use UINT_MAX32? --- sql/field.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index e372a37d2f6..e8669dad406 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1863,9 +1863,9 @@ int Field_long::store(double nr) res=0; error= 1; } - else if (nr > (double) (ulong) ~0L) + else if (nr > (double) UINT_MAX32) { - res=(int32) (uint32) ~0L; + res= UINT_MAX32; error= 1; } else From b23fe2ac670ae4770dc111c5a1c8f17ded1e99b9 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 00:04:03 +0200 Subject: [PATCH 40/48] lowercase_table3.result: Correct InnoDB's result output in test; the pseudo-file-extension for InnoDB tables '.InnoDB' was replaced by a more realistic '.ibd' extension mysql-test/r/lowercase_table3.result: Correct InnoDB's result output in test; the pseudo-file-extension for InnoDB tables '.InnoDB' was replaced by a more realistic '.ibd' extension --- mysql-test/r/lowercase_table3.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/lowercase_table3.result b/mysql-test/r/lowercase_table3.result index a645e46be9e..8182d07c26b 100644 --- a/mysql-test/r/lowercase_table3.result +++ b/mysql-test/r/lowercase_table3.result @@ -6,5 +6,5 @@ drop table t1; flush tables; CREATE TABLE t1 (a int) ENGINE=INNODB; SELECT * from T1; -ERROR HY000: Can't open file: 'T1.InnoDB' (errno: 1) +ERROR HY000: Can't open file: 'T1.ibd' (errno: 1) drop table t1; From 6429a0c59897e94e7d467209bd5bd903fd3a5b9a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Nov 2004 23:16:16 +0100 Subject: [PATCH 41/48] bug#6784 mi_flush_bulk_insert (on dup key error in mi_write) was mangling info->dupp_key_pos --- myisam/mi_write.c | 16 ++++++---------- mysql-test/r/fulltext.result | 6 ++++++ mysql-test/t/fulltext.test | 13 +++++++++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/myisam/mi_write.c b/myisam/mi_write.c index e059bbb569f..303e924118f 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -165,12 +165,7 @@ err: { uint j; for (j=0 ; j < share->base.keys ; j++) - { - if (is_tree_inited(&info->bulk_insert[j])) - { - reset_tree(&info->bulk_insert[j]); - } - } + mi_flush_bulk_insert(info, j); } info->errkey= (int) i; while ( i-- > 0) @@ -329,7 +324,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *temp_buff,*keypos; uchar keybuff[MI_MAX_KEY_BUFF]; my_bool was_last_key; - my_off_t next_page; + my_off_t next_page, dupp_key_pos; DBUG_ENTER("w_search"); DBUG_PRINT("enter",("page: %ld",page)); @@ -349,9 +344,9 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, /* get position to record with duplicated key */ tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff); if (tmp_key_length) - info->dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); + dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); else - info->dupp_key_pos= HA_OFFSET_ERROR; + dupp_key_pos= HA_OFFSET_ERROR; if (keyinfo->flag & HA_FULLTEXT) { uint off; @@ -370,7 +365,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, else { /* popular word. two-level tree. going down */ - my_off_t root=info->dupp_key_pos; + my_off_t root=dupp_key_pos; keyinfo=&info->s->ft2_keyinfo; get_key_full_length_rdonly(off, key); key+=off; @@ -389,6 +384,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, } else /* not HA_FULLTEXT, normal HA_NOSAME key */ { + info->dupp_key_pos= dupp_key_pos; my_afree((byte*) temp_buff); my_errno=HA_ERR_FOUND_DUPP_KEY; DBUG_RETURN(-1); diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index cff43a821b3..7acc8a2d23f 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -399,3 +399,9 @@ select count(*) from t1; count(*) 1 drop table t1; +create table t1 (a int primary key, b text, fulltext(b)); +create table t2 (a int, b text); +insert t1 values (1, "aaaa"), (2, "bbbb"); +insert t2 values (10, "aaaa"), (2, "cccc"); +replace t1 select * from t2; +drop table t1, t2; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 41fbf3f27ac..008e965297f 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -308,3 +308,16 @@ REPAIR TABLE t1; select count(*) from t1; drop table t1; +# +# bug#6784 +# mi_flush_bulk_insert (on dup key error in mi_write) +# was mangling info->dupp_key_pos +# + +create table t1 (a int primary key, b text, fulltext(b)); +create table t2 (a int, b text); +insert t1 values (1, "aaaa"), (2, "bbbb"); +insert t2 values (10, "aaaa"), (2, "cccc"); +replace t1 select * from t2; +drop table t1, t2; + From 9c03e9cf000e806d259f9f3aa85935091fbecc8c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 01:06:37 +0100 Subject: [PATCH 42/48] sql_select.cc: my_message_sql does not tolerate a NullS argument (segfault) sql/sql_select.cc: my_message_sql does not tolerate a NullS argument (segfault) --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4c652ee972a..eaa44e2f5ef 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -238,7 +238,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result) /* If we have real error reported erly then this will be ignored */ - result->send_error(ER_UNKNOWN_ERROR, NullS); + result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); result->abort(); } DBUG_RETURN(res); From f88d01932f4a81682267e21022686d3dea4edb78 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 02:23:13 +0200 Subject: [PATCH 43/48] post-merge fix mysql-test/r/view.result: changes in error number, and key in view processing mysql-test/t/view.test: changes in error number, and key in view processing sql/mysql_priv.h: changes functions sql/sp.cc: now we report to setup_tables(), are we setuping SELECT...INSERT sql/sql_base.cc: fixed finding table, taking in account join view, which can have not TABLE pointer now we report to setup_tables(), are we setuping SELECT...INSERT and ennumerete insert table separately sql/sql_delete.cc: now we report to setup_tables(), are we setuping SELECT...INSERT sql/sql_help.cc: now we report to setup_tables(), are we setuping SELECT...INSERT sql/sql_insert.cc: fixed returning value of functions sql/sql_load.cc: now we report to setup_tables(), are we setuping SELECT...INSERT removed second setup_tables call (merge) sql/sql_olap.cc: now we report to setup_tables(), are we setuping SELECT...INSERT sql/sql_parse.cc: UPDATE->MULTIUPDATE switching fixed sql/sql_prepare.cc: UPDATE->MULTIUPDATE switching fixed sql/sql_select.cc: now we report to setup_tables(), are we setuping SELECT...INSERT sql/sql_update.cc: UPDATE->MULTIUPDATE switching fixed sql/sql_view.cc: returning value fixed sql/sql_view.h: returning value fixed --- mysql-test/r/view.result | 40 +++++----------------------------- mysql-test/t/view.test | 25 +++++++++------------ sql/mysql_priv.h | 14 +++++++----- sql/sp.cc | 2 +- sql/sql_base.cc | 41 +++++++++++++++++++++++++---------- sql/sql_delete.cc | 5 +++-- sql/sql_help.cc | 2 +- sql/sql_insert.cc | 38 +++++++++++++++++++------------- sql/sql_load.cc | 5 ++--- sql/sql_olap.cc | 3 ++- sql/sql_parse.cc | 47 ++++++++++++++++++++-------------------- sql/sql_prepare.cc | 27 ++++++++++++++++++----- sql/sql_select.cc | 6 +++-- sql/sql_update.cc | 19 +++++++++++----- sql/sql_view.cc | 13 ++++++----- sql/sql_view.h | 2 +- 16 files changed, 155 insertions(+), 134 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 1bfbc28935a..e2c6b3f2ae2 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1661,6 +1661,7 @@ check table v1; Table Op Msg_type Msg_text test.v1 check error View 'test.v1' references invalid table(s) or column(s) drop view v1; +create table t1 (a int); create table t2 (a int); create table t3 (a int); insert into t1 values (1), (2), (3); @@ -1723,8 +1724,10 @@ a 1 3 create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; -update v2 set a= 10 where a=200; -ERROR HY000: The target table v2 of the UPDATE is not updatable +set updatable_views_with_limit=NO; +update v2 set a= 10 where a=200 limit 1; +ERROR HY000: The target table t1 of the UPDATE is not updatable +set updatable_views_with_limit=DEFAULT; select * from v3; a b 2 1 @@ -1789,37 +1792,6 @@ a b 10 NULL 2000 NULL 0 NULL -create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; -insert into v2(a) values (10); -ERROR HY000: The target table v2 of the INSERT is not updatable -select * from v3; -a b -10 1000 -1000 1000 -10002 1000 -10 10 -1000 10 -10002 10 -10 2000 -1000 2000 -10002 2000 -10 0 -1000 0 -10002 0 -select * from v2; -a b -NULL 1000 -NULL 1000 -NULL 1000 -NULL 10 -NULL 10 -NULL 10 -NULL 2000 -NULL 2000 -NULL 2000 -NULL 0 -NULL 0 -NULL 0 delete from v3; ERROR HY000: Can not delete from join view 'test.v3' delete v3,t1 from v3,t1; @@ -1855,5 +1827,5 @@ a b 101 0 300 0 301 0 -drop view v3,v2; +drop view v3; drop tables t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index bf50800fbe3..92747323336 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1641,8 +1641,10 @@ select * from t1; select * from t2; # view without primary key create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; +set updatable_views_with_limit=NO; -- error 1288 -update v2 set a= 10 where a=200; +update v2 set a= 10 where a=200 limit 1; +set updatable_views_with_limit=DEFAULT; # just view selects select * from v3; select * from v2; @@ -1668,14 +1670,14 @@ create table t2 (a int, primary key (a), b int); insert into t2 values (1000, 2000); create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; # inserting into join view without field list --- error 1365 +-- error 1394 insert into v3 values (1,2); --- error 1365 +-- error 1394 insert into v3 select * from t2; # inserting in several tables of join view --- error 1364 +-- error 1393 insert into v3(a,b) values (1,2); --- error 1364 +-- error 1393 insert into v3(a,b) select * from t2; # correct inserts into join view insert into v3(a) values (1); @@ -1685,17 +1687,10 @@ insert into v3(b) select b from t2; insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a); select * from t1; select * from t2; -# view without primary key -create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2; --- error 1288 -insert into v2(a) values (10); -# just view selects -select * from v3; -select * from v2; # try delete from join view --- error 1366 +-- error 1395 delete from v3; --- error 1366 +-- error 1395 delete v3,t1 from v3,t1; # delete from t1 just to reduce result set size delete from t1; @@ -1714,5 +1709,5 @@ execute stmt1 using @a; deallocate prepare stmt1; select * from v3; -drop view v3,v2; +drop view v3; drop tables t1,t2; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6a0ec13eac2..581d82f2c2b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -614,10 +614,10 @@ bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info); bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, Item **conds, uint order_num, ORDER *order); -bool mysql_update(THD *thd,TABLE_LIST *tables,List &fields, - List &values,COND *conds, - uint order_num, ORDER *order, ha_rows limit, - enum enum_duplicates handle_duplicates); +int mysql_update(THD *thd,TABLE_LIST *tables,List &fields, + List &values,COND *conds, + uint order_num, ORDER *order, ha_rows limit, + enum enum_duplicates handle_duplicates); bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, COND *conds, ulong options, @@ -800,9 +800,11 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges, - bool allocate_view_names); + bool allocate_view_names, + bool select_insert); bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, - TABLE_LIST **leaves, bool refresh_only); + TABLE_LIST **leaves, bool refresh_only, + bool select_insert); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, uint wild_num); bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, diff --git a/sql/sp.cc b/sql/sp.cc index 3b3a307c859..41ce3552292 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -608,7 +608,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) tables is not VIEW for sure => we can pass 0 as condition */ - setup_tables(thd, &tables, 0, &leaves, 0); + setup_tables(thd, &tables, 0, &leaves, FALSE, FALSE); for (used_field= &used_fields[0]; used_field->field_name; used_field++) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9b51c7ecd8a..e2a9ac5680d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -580,7 +580,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, { for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) { - if (table->table->tmp_table == NO_TMP_TABLE && + if ((table->table == 0 || table->table->tmp_table == NO_TMP_TABLE) && ((!strcmp(table->db, db_name) && !strcmp(table->real_name, table_name)) || (table->view && @@ -595,7 +595,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, { for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) { - if (table->table->tmp_table == NO_TMP_TABLE && + if ((table->table == 0 || table->table->tmp_table == NO_TMP_TABLE) && ((!strcmp(table->db, db_name) && !strcmp(table->real_name, table_name)) || (table->view && @@ -2786,14 +2786,14 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) SYNOPSIS setup_tables() - thd Thread handler - tables Table list - conds Condition of current SELECT (can be changed by VIEW) - leaves List of join table leaves list - refresh It is onle refresh for subquery + thd Thread handler + tables Table list + conds Condition of current SELECT (can be changed by VIEW) + leaves List of join table leaves list + refresh It is onle refresh for subquery + select_insert It is SELECT ... INSERT command NOTE - Remap table numbers if INSERT ... SELECT Check also that the 'used keys' and 'ignored keys' exists and set up the table structure accordingly Create leaf tables list @@ -2802,29 +2802,46 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) table->map is not set and all Item_field will be regarded as const items. RETURN - 0 ok; In this case *map will includes the choosed index - 1 error + FALSE ok; In this case *map will includes the choosed index + TRUE error */ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, - TABLE_LIST **leaves, bool refresh) + TABLE_LIST **leaves, bool refresh, bool select_insert) { DBUG_ENTER("setup_tables"); + /* + this is used for INSERT ... SELECT. + For select we setup tables except first (and its underlaying tables) + */ + TABLE_LIST *first_select_table= (select_insert ? + tables->next_local: + 0); if (!tables || tables->setup_is_done) DBUG_RETURN(0); tables->setup_is_done= 1; + if (!(*leaves)) { make_leaves_list(leaves, tables); } - uint tablenr=0; + uint tablenr= 0; for (TABLE_LIST *table_list= *leaves; table_list; table_list= table_list->next_leaf, tablenr++) { TABLE *table= table_list->table; + if (first_select_table && + (table_list->belong_to_view ? + table_list->belong_to_view : + table_list) == first_select_table) + { + /* new counting for SELECT of INSERT ... SELECT command */ + first_select_table= 0; + tablenr= 0; + } setup_table_map(table, table_list, tablenr); table->used_keys= table->keys_for_keyread; if (table_list->use_index) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 26ca837bdbd..d4f3cddd4a0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -296,7 +296,8 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_delete"); - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) || + if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, + FALSE, FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -353,7 +354,7 @@ bool mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ if (setup_tables(thd, lex->query_tables, &lex->select_lex.where, - &lex->select_lex.leaf_tables, 0)) + &lex->select_lex.leaf_tables, FALSE, FALSE)) DBUG_RETURN(TRUE); /* Fix tables-to-be-deleted-from list to point at opened tables */ diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 52548803984..bcde1dc46f2 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -647,7 +647,7 @@ bool mysqld_help(THD *thd, const char *mask) tables do not contain VIEWs => we can pass 0 as conds */ - setup_tables(thd, tables, 0, &leaves, 0); + setup_tables(thd, tables, 0, &leaves, FALSE, FALSE); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) goto error; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index dca2a498d7d..673d7425c36 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -612,25 +612,26 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) SYNOPSIS mysql_prepare_insert_check_table() thd Thread handle - table_list Table list (only one table) + table_list Table list fields List of fields to be updated where Pointer to where clause + select_insert Check is making for SELECT ... INSERT RETURN - 0 ok - 1 ERROR and message sent to client - -1 ERROR but message is not sent to client + FALSE ok + TRUE ERROR */ -static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, - List &fields, COND **where) +static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, + List &fields, COND **where, + bool select_insert) { bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables, - 0)) - DBUG_RETURN(thd->net.report_error ? -1 : 1); + FALSE, select_insert)) + DBUG_RETURN(TRUE); if (insert_into_view && !fields.elements) { @@ -641,12 +642,12 @@ static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, table_list->ancestor && table_list->ancestor->next_local); my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), table_list->view_db.str, table_list->view_name.str); - DBUG_RETURN(-1); + DBUG_RETURN(TRUE); } DBUG_RETURN(insert_view_fields(&fields, table_list)); } - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } @@ -674,9 +675,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, bool res; DBUG_ENTER("mysql_prepare_insert"); - if ((res= mysql_prepare_insert_check_table(thd, table_list, - fields, &unused_conds))) - DBUG_RETURN(res); + DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", + (ulong)table_list, (ulong)table, + (int)insert_into_view)); + if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds, + FALSE)) + DBUG_RETURN(TRUE); if (check_insert_fields(thd, table_list, fields, *values, 1, !insert_into_view) || @@ -689,6 +693,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, setup_fields(thd, 0, table_list, update_values, 1, 0, 0)))) DBUG_RETURN(TRUE); + if (!table) + table= table_list->table; + if (unique_table(table_list, table_list->next_global)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); @@ -1716,8 +1723,9 @@ bool mysql_insert_select_prepare(THD *thd) lex->query_tables->no_where_clause= 1; if (mysql_prepare_insert_check_table(thd, lex->query_tables, lex->field_list, - &lex->select_lex.where)) - DBUG_RETURN(FALSE); + &lex->select_lex.where, + TRUE)) + DBUG_RETURN(TRUE); /* setup was done in mysql_insert_select_prepare, but we have to mark first local table diff --git a/sql/sql_load.cc b/sql/sql_load.cc index edd72851a21..21dd2318504 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -122,7 +122,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); if (setup_tables(thd, table_list, &unused_conds, - &thd->lex->select_lex.leaf_tables, 0)) + &thd->lex->select_lex.leaf_tables, FALSE, FALSE)) DBUG_RETURN(-1); if (!table_list->table || // do not suport join view !table_list->updatable || // and derived tables @@ -147,8 +147,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* TODO: use this conds for 'WITH CHECK OPTIONS' */ Item *unused_conds= 0; TABLE_LIST *leaves= 0; - if (setup_tables(thd, table_list, &unused_conds, &leaves, 0) || - setup_fields(thd, 0, table_list, fields, 1, 0, 0)) + if (setup_fields(thd, 0, table_list, fields, 1, 0, 0)) DBUG_RETURN(TRUE); if (thd->dupp_field) { diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index c287b9e71e7..07271d40492 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -153,7 +153,8 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first - &select_lex->where, &select_lex->leaf_tables, 0) || + &select_lex->where, &select_lex->leaf_tables, + FALSE, FALSE) || setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, select_lex->item_list, 1, &all_fields,1) || setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ca19f982826..7089a79124d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2030,6 +2030,7 @@ bool mysql_execute_command(THD *thd) { bool res= FALSE; + int result= 0; LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ SELECT_LEX *select_lex= &lex->select_lex; @@ -2874,33 +2875,33 @@ create_error: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (update_precheck(thd, all_tables)) break; - res= mysql_update(thd, all_tables, - select_lex->item_list, - lex->value_list, - select_lex->where, - select_lex->order_list.elements, - (ORDER *) select_lex->order_list.first, - select_lex->select_limit, - lex->duplicates); - if (res != 2) + res= (result= mysql_update(thd, all_tables, + select_lex->item_list, + lex->value_list, + select_lex->where, + select_lex->order_list.elements, + (ORDER *) select_lex->order_list.first, + select_lex->select_limit, + lex->duplicates)); + if (result != 2) break; case SQLCOM_UPDATE_MULTI: - { - DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (res != 2) { - if ((res= multi_update_precheck(thd, all_tables))) - break; - } - else - res= 0; + DBUG_ASSERT(first_table == all_tables && first_table != 0); + if (result != 2) + { + if ((res= multi_update_precheck(thd, all_tables))) + break; + } + else + res= 0; - res= mysql_multi_update(thd, all_tables, - &select_lex->item_list, - &lex->value_list, - select_lex->where, - select_lex->options, - lex->duplicates, unit, select_lex); + res= mysql_multi_update(thd, all_tables, + &select_lex->item_list, + &lex->value_list, + select_lex->where, + select_lex->options, + lex->duplicates, unit, select_lex); break; } case SQLCOM_REPLACE: diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fed240b865a..bff5a2fc999 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -944,23 +944,36 @@ static int mysql_test_update(Prepared_statement *stmt, { int res; THD *thd= stmt->thd; + uint table_count= 0; SELECT_LEX *select= &stmt->lex->select_lex; DBUG_ENTER("mysql_test_update"); if (update_precheck(thd, table_list)) DBUG_RETURN(1); - if (!(res=open_and_lock_tables(thd, table_list))) + if (!open_tables(thd, table_list, &table_count)) { - if (table_list->table == 0) + if (table_list->ancestor && table_list->ancestor->next_local) { - DBUG_ASSERT(table_list->view && - table_list->ancestor && table_list->ancestor->next_local); - stmt->lex->sql_command= SQLCOM_UPDATE_MULTI; - DBUG_PRINT("info", ("Switch to multi-update (command replaced)")); + DBUG_ASSERT(table_list->view); + DBUG_PRINT("info", ("Switch to multi-update")); + /* pass counter value */ + thd->lex->table_count= table_count; + /* + give correct value to multi_lock_option, because it will be used + in multiupdate + */ + thd->lex->multi_lock_option= table_list->lock_type; /* convert to multiupdate */ return 2; } + + if (lock_tables(thd, table_list, table_count) || + mysql_handle_derived(thd->lex, &mysql_derived_prepare) || + (thd->fill_derived_tables() && + mysql_handle_derived(thd->lex, &mysql_derived_filling))) + DBUG_RETURN(1); + if (!(res= mysql_prepare_update(thd, table_list, &select->where, select->order_list.elements, @@ -982,6 +995,8 @@ static int mysql_test_update(Prepared_statement *stmt, } stmt->lex->unit.cleanup(); } + else + res= 1; /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(res); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 433bc147169..ae60eb759d0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -310,7 +310,8 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ - if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 0) || + if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, + FALSE, FALSE) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, @@ -1081,7 +1082,8 @@ JOIN::reinit() if (tables_list) { tables_list->setup_is_done= 0; - if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 1)) + if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, + TRUE, FALSE)) DBUG_RETURN(1); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0927fcfd9bc..a14c20caad8 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -142,13 +142,17 @@ int mysql_update(THD *thd, if (open_tables(thd, table_list, &table_count)) DBUG_RETURN(1); - if (table_list->table == 0) + if (table_list->ancestor && table_list->ancestor->next_local) { - DBUG_ASSERT(table_list->view && - table_list->ancestor && table_list->ancestor->next_local); + DBUG_ASSERT(table_list->view); DBUG_PRINT("info", ("Switch to multi-update")); /* pass counter value */ thd->lex->table_count= table_count; + /* + give correct value to multi_lock_option, because it will be used + in multiupdate + */ + thd->lex->multi_lock_option= table_list->lock_type; /* convert to multiupdate */ return 2; } @@ -559,7 +563,8 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.table= table; tables.alias= table_list->alias; - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) || + if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, + FALSE, FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || select_lex->setup_ref_array(thd, order_num) || setup_order(thd, select_lex->ref_pointer_array, @@ -630,6 +635,8 @@ bool mysql_multi_update_prepare(THD *thd) uint table_count= lex->table_count; const bool using_lock_tables= thd->locked_tables != 0; bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI); + /* following need for prepared statements, to run next time multi-update */ + thd->lex->sql_command= SQLCOM_UPDATE_MULTI; DBUG_ENTER("mysql_multi_update_prepare"); /* open tables and create derived ones, but do not lock and fill them */ @@ -643,7 +650,7 @@ bool mysql_multi_update_prepare(THD *thd) */ if (setup_tables(thd, table_list, &lex->select_lex.where, - &lex->select_lex.leaf_tables, 0)) + &lex->select_lex.leaf_tables, FALSE, FALSE)) DBUG_RETURN(TRUE); /* Ensure that we have update privilege for all tables and columns in the @@ -782,7 +789,7 @@ bool mysql_multi_update_prepare(THD *thd) table_list->setup_is_done= 0; if (setup_tables(thd, table_list, &lex->select_lex.where, - &lex->select_lex.leaf_tables, 0) || + &lex->select_lex.leaf_tables, FALSE, FALSE) || (lex->select_lex.no_wrap_view_item= 1, res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), lex->select_lex.no_wrap_view_item= 0, diff --git a/sql/sql_view.cc b/sql/sql_view.cc index ca9faddb07a..38ab3a3db9f 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -489,6 +489,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, tbl= tbl->next_local) { if ((tbl->view && !tbl->updatable_view) || tbl->schema_table) + { view->updatable_view= 0; break; } @@ -1074,18 +1075,18 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) view view for processing RETURN - 0 - OK - -1 - error (is not sent to cliet) + FALSE OK + TRUE error (is not sent to cliet) */ -int insert_view_fields(List *list, TABLE_LIST *view) +bool insert_view_fields(List *list, TABLE_LIST *view) { uint elements_in_view= view->view->select_lex.item_list.elements; Field_translator *trans; DBUG_ENTER("insert_view_fields"); if (!(trans= view->field_translation)) - DBUG_RETURN(0); + DBUG_RETURN(FALSE); for (uint i= 0; i < elements_in_view; i++) { @@ -1095,10 +1096,10 @@ int insert_view_fields(List *list, TABLE_LIST *view) else { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT"); - DBUG_RETURN(-1); + DBUG_RETURN(TRUE); } } - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } /* diff --git a/sql/sql_view.h b/sql/sql_view.h index 8efa9afeccb..4e6aaf7f477 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -25,7 +25,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool check_key_in_view(THD *thd, TABLE_LIST * view); -int insert_view_fields(List *list, TABLE_LIST *view); +bool insert_view_fields(List *list, TABLE_LIST *view); frm_type_enum mysql_frm_type(char *path); From 7108deee6e9b2e805462df4e0002dbb32e0665b0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 09:28:32 +0200 Subject: [PATCH 44/48] spelling fixed/comments added (postreview fixes) sql/mysqld.cc: spelling fixed sql/sql_base.cc: spelling fixed sql/sql_delete.cc: spelling fixed sql/sql_parse.cc: comments added sql/sql_prepare.cc: comments added sql/sql_update.cc: spelling fixed sql/sql_view.cc: spelling fixed sql/table.cc: spelling fixed --- sql/mysqld.cc | 2 +- sql/sql_base.cc | 4 ++-- sql/sql_delete.cc | 2 +- sql/sql_parse.cc | 2 ++ sql/sql_prepare.cc | 2 ++ sql/sql_update.cc | 2 +- sql/sql_view.cc | 2 +- sql/table.cc | 2 +- 8 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3001cda8b2b..48b60cc6824 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5287,7 +5287,7 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT, - "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlaying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).", + "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).", (gptr*) &global_system_variables.updatable_views_with_limit, (gptr*) &max_system_variables.updatable_views_with_limit, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 1, 0, 1, 0}, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8fba30e2df8..97e2a2cf0d0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2815,7 +2815,7 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, DBUG_ENTER("setup_tables"); /* this is used for INSERT ... SELECT. - For select we setup tables except first (and its underlaying tables) + For select we setup tables except first (and its underlying tables) */ TABLE_LIST *first_select_table= (select_insert ? tables->next_local: @@ -3148,7 +3148,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } /* All fields are used in case if usual tables (in case of view used - fields merked in setu_tables during fix_fields of view columns + fields marked in setup_tables during fix_fields of view columns */ if (table) table->used_fields=table->fields; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d4f3cddd4a0..51cf085cfb5 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -374,7 +374,7 @@ bool mysql_multi_delete_prepare(THD *thd) Check are deleted table used somewhere inside subqueries. Multi-delete can't be constructed over-union => we always have - single SELECT on top and have to check underlaying SELECTs of it + single SELECT on top and have to check underlying SELECTs of it */ for (SELECT_LEX_UNIT *un= lex->select_lex.first_inner_unit(); un; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index af3392349ab..fce8d294456 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2883,11 +2883,13 @@ create_error: (ORDER *) select_lex->order_list.first, select_lex->select_limit, lex->duplicates)); + /* mysql_update return 2 if we need to switch to multi-update */ if (result != 2) break; case SQLCOM_UPDATE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); + /* if we switched from normal update, rights are checked */ if (result != 2) { if ((res= multi_update_precheck(thd, all_tables))) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index bff5a2fc999..d4851393a89 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1309,6 +1309,7 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, TABLE_LIST *tables, bool converted) { + /* if we switched from normal update, rights are checked */ if (!converted && multi_update_precheck(stmt->thd, tables)) return TRUE; /* @@ -1457,6 +1458,7 @@ static int check_prepared_statement(Prepared_statement *stmt, case SQLCOM_UPDATE: res= mysql_test_update(stmt, tables); + /* mysql_test_update return 2 if we need to switch to multi-update */ if (res != 2) break; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a14c20caad8..4a2790f7d78 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -720,7 +720,7 @@ bool mysql_multi_update_prepare(THD *thd) /* Multi-update can't be constructed over-union => we always have - single SELECT on top and have to check underlaying SELECTs of it + single SELECT on top and have to check underlying SELECTs of it */ if (lex->select_lex.check_updateable_in_subqueries(tl->db, tl->real_name)) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 38ab3a3db9f..81d8000831b 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1046,7 +1046,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) if (i == elements_in_view) // If field didn't exists { /* - Keys or all fields of underlaying tables are not foud => we have + Keys or all fields of underlying tables are not foud => we have to check variable updatable_views_with_limit to decide should we issue an error or just a warning */ diff --git a/sql/table.cc b/sql/table.cc index c1288bf8f24..625f04846a8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1886,7 +1886,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) /* - Find table in underlaying tables by mask and check that only this + Find table in underlying tables by mask and check that only this table belong to given mask SYNOPSIS From a0f2ecf7fbb0194ed26a8b6dadd4fffa672c46bc Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 10:23:47 +0200 Subject: [PATCH 45/48] do not leave sql command uninitialized, because it used for detection need of preparation correct idends printing during finding identifiers i sql/sql_lex.h: do not leave sql command uninitialized, because it used for detection need of preparation correct idends printing during finding identifiers in table list (alias resolving tracking) --- sql/sql_lex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 169ee4e66eb..605204fe35d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -762,7 +762,7 @@ typedef struct st_lex */ SQL_LIST trg_table_fields; - st_lex() :result(0) + st_lex() :result(0), sql_command(SQLCOM_END) { extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first); hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_spfuns_key, 0, 0); From 5aaffe9b3cb36846b77d81a51814dd1c334d724c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 10:38:46 +0100 Subject: [PATCH 46/48] bug#6775 - ndb - fix bug introduced by bug fix ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: Scan number allocation must be on table even in case of range scan Otherwise scan takeover won't work as LQHKEYREQ contains table --- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 88e8f25b004..c106a6ddfac 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -8573,13 +8573,11 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) /** * Used for scan take over */ - { - FragrecordPtr tFragPtr; - tFragPtr.i = fragptr.p->tableFragptr; - ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); - scanptr.p->fragPtrI = fragptr.p->tableFragptr; - } - + FragrecordPtr tFragPtr; + tFragPtr.i = fragptr.p->tableFragptr; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + scanptr.p->fragPtrI = fragptr.p->tableFragptr; + /** * !idx uses 1 - (MAX_PARALLEL_SCANS_PER_FRAG - 1) = 1-11 * idx uses from MAX_PARALLEL_SCANS_PER_FRAG - MAX = 12-42) @@ -8587,11 +8585,11 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) Uint32 start = (idx ? MAX_PARALLEL_SCANS_PER_FRAG : 1 ); Uint32 stop = (idx ? MAX_PARALLEL_INDEX_SCANS_PER_FRAG : MAX_PARALLEL_SCANS_PER_FRAG - 1); stop += start; - Uint32 free = fragptr.p->m_scanNumberMask.find(start); - + Uint32 free = tFragPtr.p->m_scanNumberMask.find(start); + if(free == Fragrecord::ScanNumberMask::NotFound || free >= stop){ jam(); - + if(scanPrio == 0){ jam(); return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR; @@ -8607,10 +8605,9 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) return ZOK; } - scanptr.p->scanNumber = free; - fragptr.p->m_scanNumberMask.clear(free);// Update mask - + tFragPtr.p->m_scanNumberMask.clear(free);// Update mask + LocalDLList active(c_scanRecordPool, fragptr.p->m_activeScans); active.add(scanptr); if(scanptr.p->scanKeyinfoFlag){ @@ -8693,8 +8690,12 @@ void Dblqh::finishScanrec(Signal* signal) LocalDLList scans(c_scanRecordPool, fragptr.p->m_activeScans); scans.release(scanptr); + FragrecordPtr tFragPtr; + tFragPtr.i = scanptr.p->fragPtrI; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + const Uint32 scanNumber = scanptr.p->scanNumber; - ndbrequire(!fragptr.p->m_scanNumberMask.get(scanNumber)); + ndbrequire(!tFragPtr.p->m_scanNumberMask.get(scanNumber)); ScanRecordPtr restart; /** @@ -8702,13 +8703,13 @@ void Dblqh::finishScanrec(Signal* signal) */ if(scanNumber == NR_ScanNo || !queue.first(restart)){ jam(); - fragptr.p->m_scanNumberMask.set(scanNumber); + tFragPtr.p->m_scanNumberMask.set(scanNumber); return; } if(ERROR_INSERTED(5034)){ jam(); - fragptr.p->m_scanNumberMask.set(scanNumber); + tFragPtr.p->m_scanNumberMask.set(scanNumber); return; } From 45f941cb5c05077900c4842627b3d579d5d009b4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 12:14:15 +0000 Subject: [PATCH 47/48] ndb/src/common/logger/LogHandler.cpp changed so that error is returned if format is wrong in logger param parsing ndb/src/common/logger/Logger.cpp some debuf printout added ndb/src/mgmsrv/InitConfigFileParser.cpp rewrote parsing on parseNameValuePair, was buggy ndb/src/common/logger/LogHandler.cpp: changed so that error is returned if format is wrong in logger param parsing ndb/src/common/logger/Logger.cpp: some debuf printout added ndb/src/mgmsrv/InitConfigFileParser.cpp: rewrote parsing on parseNameValuePair, was buggy --- ndb/src/common/logger/LogHandler.cpp | 7 ++- ndb/src/common/logger/Logger.cpp | 9 ++-- ndb/src/mgmsrv/InitConfigFileParser.cpp | 68 +++++++++---------------- 3 files changed, 33 insertions(+), 51 deletions(-) diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index 4fab957fc50..a76cb622878 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -117,10 +117,9 @@ LogHandler::parseParams(const BaseString &_params) { _params.split(v_args, ","); for(size_t i=0; i < v_args.size(); i++) { Vector v_param_value; - - v_args[i].split(v_param_value, "=", 2); - if(v_param_value.size() == 2 && - !setParam(v_param_value[0], v_param_value[1])) + if(v_args[i].split(v_param_value, "=", 2) != 2) + ret = false; + else if (!setParam(v_param_value[0], v_param_value[1])) ret = false; } diff --git a/ndb/src/common/logger/Logger.cpp b/ndb/src/common/logger/Logger.cpp index 00a2fae67bc..1dc3bd43716 100644 --- a/ndb/src/common/logger/Logger.cpp +++ b/ndb/src/common/logger/Logger.cpp @@ -169,10 +169,13 @@ Logger::addHandler(const BaseString &logstring) { size_t i; Vector logdest; Vectorloghandlers; + DBUG_ENTER("Logger::addHandler"); logstring.split(logdest, ";"); for(i = 0; i < logdest.size(); i++) { + DBUG_PRINT("info",("adding: %s",logdest[i])); + Vector v_type_args; logdest[i].split(v_type_args, ":", 2); @@ -191,16 +194,16 @@ Logger::addHandler(const BaseString &logstring) { handler = new ConsoleLogHandler(); if(handler == NULL) - return false; + DBUG_RETURN(false); if(!handler->parseParams(params)) - return false; + DBUG_RETURN(false); loghandlers.push_back(handler); } for(i = 0; i < loghandlers.size(); i++) addHandler(loghandlers[i]); - return true; /* @todo handle errors */ + DBUG_RETURN(true); /* @todo handle errors */ } bool diff --git a/ndb/src/mgmsrv/InitConfigFileParser.cpp b/ndb/src/mgmsrv/InitConfigFileParser.cpp index fdfe7823fc2..05102255eaa 100644 --- a/ndb/src/mgmsrv/InitConfigFileParser.cpp +++ b/ndb/src/mgmsrv/InitConfigFileParser.cpp @@ -213,48 +213,41 @@ InitConfigFileParser::parseConfig(FILE * file) { // Parse Name-Value Pair //**************************************************************************** -bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) { - - char tmpLine[MAX_LINE_LENGTH]; - char fname[MAX_LINE_LENGTH], rest[MAX_LINE_LENGTH]; - char* t; - const char *separator_list[]= {":", "=", 0}; - const char *separator= 0; - +bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) +{ if (ctx.m_currentSection == NULL){ ctx.reportError("Value specified outside section"); return false; } - strncpy(tmpLine, line, MAX_LINE_LENGTH); - // ************************************* - // Check if a separator exists in line + // Split string at first occurrence of + // '=' or ':' // ************************************* - for(int i= 0; separator_list[i] != 0; i++) { - if(strchr(tmpLine, separator_list[i][0])) { - separator= separator_list[i]; - break; - } - } - if (separator == 0) { + Vector tmp_string_split; + if (BaseString(line).split(tmp_string_split, + BaseString("=:"), + 2) != 2) + { ctx.reportError("Parse error"); return false; } - // ******************************************* - // Get pointer to substring before separator - // ******************************************* - t = strtok(tmpLine, separator); - - // ***************************************** - // Count number of tokens before separator - // ***************************************** - if (sscanf(t, "%120s%120s", fname, rest) != 1) { - ctx.reportError("Multiple names before \'%c\'", separator[0]); - return false; + // ************************************* + // Remove leading and trailing chars + // ************************************* + { + for (int i = 0; i < 2; i++) + tmp_string_split[i].trim("\r\n \t"); } + + // ************************************* + // First in split is fname + // ************************************* + + const char *fname= tmp_string_split[0].c_str(); + if (!ctx.m_currentInfo->contains(fname)) { ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname); return false; @@ -273,24 +266,11 @@ bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) { } } - // ****************************************** - // Get pointer to substring after separator - // ****************************************** - t = strtok(NULL, "\0"); - if (t == NULL) { - ctx.reportError("No value for parameter"); - return false; - } - - // ****************************************** - // Remove prefix and postfix spaces and tabs - // ******************************************* - trim(t); - // *********************** // Store name-value pair // *********************** - return storeNameValuePair(ctx, fname, t); + + return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str()); } From 26339663b87159075a37899f05231aedefa61d2e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Nov 2004 16:18:47 +0400 Subject: [PATCH 48/48] table.cc: Bug #6802 MySQL 4.0's VARCHAR(NN) BINARY is interpreted as VARBINARY(NN) in 4.1 sql/table.cc: Bug #6802 MySQL 4.0's VARCHAR(NN) BINARY is interpreted as VARBINARY(NN) in 4.1 --- sql/table.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sql/table.cc b/sql/table.cc index 20ac714020d..cb565097c0b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -463,7 +463,26 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, /* old frm file */ field_type= (enum_field_types) f_packtype(pack_flag); - charset=f_is_binary(pack_flag) ? &my_charset_bin : outparam->table_charset; + if (f_is_binary(pack_flag)) + { + /* + Try to choose the best 4.1 type: + - for 4.0 "CHAR(N) BINARY" or "VARCHAR(N) BINARY" + try to find a binary collation for character set. + - for other types (e.g. BLOB) just use my_charset_bin. + */ + if (!f_is_blob(pack_flag)) + { + // 3.23 or 4.0 string + if (!(charset= get_charset_by_csname(outparam->table_charset->csname, + MY_CS_BINSORT, MYF(0)))) + charset= &my_charset_bin; + } + else + charset= &my_charset_bin; + } + else + charset= outparam->table_charset; bzero((char*) &comment, sizeof(comment)); } *field_ptr=reg_field=