diff options
author | unknown <monty@mysql.com> | 2004-10-06 19:14:33 +0300 |
---|---|---|
committer | unknown <monty@mysql.com> | 2004-10-06 19:14:33 +0300 |
commit | bbab9ec678f9e8a0309f0b018cf6d22cd93acf84 (patch) | |
tree | 4e2cfa6a6a8032773454e22aa802b2798b2935b8 /sql/sql_update.cc | |
parent | 7d583c5834f420406c9abe8bb9c44518e49e74c3 (diff) | |
parent | 95e1c07483005b784aaefa35b5a8597ffb1d3932 (diff) | |
download | mariadb-git-bbab9ec678f9e8a0309f0b018cf6d22cd93acf84.tar.gz |
Merge with 4.0 for 4.1 release
Noteworthy:
- New HANDLER code
- New multi-update-grant-check code
- Table lock code in ha_innodb.cc was not applied
BitKeeper/etc/logging_ok:
auto-union
BitKeeper/deleted/.del-ctype-latin1_de.c~c5d8f9208bceb98e:
Auto merged
Build-tools/mysql-copyright-2:
Auto merged
acinclude.m4:
Auto merged
client/mysqladmin.c:
Auto merged
client/mysqldump.c:
Auto merged
include/config-win.h:
Auto merged
include/my_global.h:
Auto merged
include/myisam.h:
Auto merged
innobase/btr/btr0btr.c:
Auto merged
innobase/buf/buf0buf.c:
Auto merged
ltmain.sh:
Auto merged
innobase/dict/dict0dict.c:
Auto merged
innobase/fsp/fsp0fsp.c:
Auto merged
innobase/include/dict0dict.h:
Auto merged
innobase/include/row0mysql.h:
Auto merged
innobase/log/log0log.c:
Auto merged
innobase/log/log0recv.c:
Auto merged
innobase/pars/pars0opt.c:
Auto merged
innobase/row/row0row.c:
Auto merged
innobase/sync/sync0arr.c:
Auto merged
innobase/ut/ut0dbg.c:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/mi_close.c:
Auto merged
myisam/mi_create.c:
Auto merged
myisam/mi_locking.c:
Auto merged
myisam/myisampack.c:
Auto merged
mysql-test/r/delete.result:
Auto merged
mysql-test/r/func_if.result:
Auto merged
Build-tools/mysql-copyright:
Merge with 4.0 (too most of the code from 4.0)
Makefile.am:
merge
client/mysql.cc:
Used 4.1 code
configure.in:
merge
innobase/os/os0file.c:
merge
innobase/row/row0mysql.c:
merge
mysql-test/r/ctype_latin1_de.result:
merge
mysql-test/r/flush_table.result:
merge
mysql-test/r/func_str.result:
merge
mysql-test/r/handler.result:
merge
mysql-test/r/multi_update.result:
merge
mysql-test/r/type_timestamp.result:
Removed testing of 'new' mode, as this is only relevant for 4.0
mysql-test/r/update.result:
merge
mysql-test/t/delete.test:
merge
mysql-test/t/flush_table.test:
merge
mysql-test/t/func_str.test:
merge
mysql-test/t/handler.test:
merge
mysql-test/t/multi_update.test:
merge
mysql-test/t/type_timestamp.test:
Removed testing of 'new' mode, as this is only relevant for 4.0
mysql-test/t/update.test:
merge
mysys/errors.c:
merge
mysys/my_fstream.c:
merge
mysys/my_pread.c:
merge
mysys/my_write.c:
merge
mysys/mysys_priv.h:
merge
scripts/mysqlhotcopy.sh:
merge
sql/field.cc:
Keep code from 4.1
sql/field.h:
Keep code from 4.1
sql/ha_innodb.cc:
Don't merge lock code from 4.0; Heikki will look at this
sql/ha_myisam.cc:
merge
sql/handler.cc:
merge
sql/item_cmpfunc.cc:
merge
sql/item_cmpfunc.h:
merge
sql/item_strfunc.cc:
merge
sql/mysql_priv.h:
merge
sql/mysqld.cc:
merge
sql/protocol.cc:
merge
sql/records.cc:
merge
sql/repl_failsafe.cc:
merge
mysql-test/r/lock_multi.result:
merge
mysql-test/t/ctype_latin1_de.test:
merge
mysql-test/t/func_if.test:
merge
mysql-test/t/lock_multi.test:
merge
sql/repl_failsafe.h:
merge
Remove unnessessary header protection
sql/slave.h:
merge
sql/sql_acl.cc:
merge
sql/sql_base.cc:
merge
sql/sql_cache.cc:
auto merge
sql/sql_class.cc:
merge
sql/sql_class.h:
merge
sql/sql_delete.cc:
merge
sql/sql_handler.cc:
Get new HANDLER code into 4.1
sql/sql_parse.cc:
Keep old file
sql/sql_repl.cc:
merge
sql/sql_repl.h:
merge
sql/sql_show.cc:
merge
sql/sql_table.cc:
merge
sql/sql_union.cc:
Applied the examine_rows bug fix from 4.0 by hand
sql/sql_update.cc:
New multi-update-grant-check code from 4.0
sql/sql_yacc.yy:
New multi-update-grant-check code from 4.0
sql/stacktrace.c:
merge
sql/table.h:
merge
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r-- | sql/sql_update.cc | 227 |
1 files changed, 151 insertions, 76 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c6fb3d6e415..25d94d6d039 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -449,6 +449,24 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, ***************************************************************************/ /* + Get table map for list of Item_field +*/ + +static table_map get_table_map(List<Item> *items) +{ + List_iterator_fast<Item> item_it(*items); + Item_field *item; + table_map map= 0; + + while ((item= (Item_field *) item_it++)) + map|= item->used_tables(); + DBUG_PRINT("info",("table_map: 0x%08x", map)); + return map; +} + + + +/* Setup multi-update handling and call SELECT to do the join */ @@ -465,107 +483,163 @@ int mysql_multi_update(THD *thd, multi_update *result; TABLE_LIST *tl; TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first; - table_map item_tables= 0, derived_tables= 0; + List<Item> total_list; DBUG_ENTER("mysql_multi_update"); - if ((res=open_and_lock_tables(thd,table_list))) - DBUG_RETURN(res); - select_lex->select_limit= HA_POS_ERROR; /* - Ensure that we have update privilege for all tables and columns in the - SET part + The following loop is here to to ensure that we only lock tables + that we are going to update with a write lock */ - for (tl= update_list; tl; tl= tl->next) + for (;;) { - TABLE *table= tl->table; + table_map update_tables, derived_tables=0; + uint tnr, counter; + + if ((res=open_tables(thd,table_list, &counter))) + DBUG_RETURN(res); + + /* Only need to call lock_tables if we are not using LOCK TABLES */ + if (!using_lock_tables && ((res= lock_tables(thd, table_list)))) + DBUG_RETURN(res); + /* - 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" + Ensure that we have update privilege for all tables and columns in the + SET part + While we are here, initialize the table->map field to check which + tables are updated and updatability of derived tables */ - if (!tl->derived) - table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); - } + for (tl= update_list, tnr=0 ; tl ; tl=tl->next) + { + 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) + table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); + table->map= (table_map) 1 << (tnr++); + } - /* Assign table map values to check updatability of derived tables */ - { - uint tablenr=0; - for (TABLE_LIST *table_list= update_list; - table_list; - table_list= table_list->next, tablenr++) + if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + + update_tables= get_table_map(fields); + + /* Unlock the tables in preparation for relocking */ + if (!using_lock_tables) + { + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + } + + /* + Count tables and setup timestamp handling + Set also the table locking strategy according to the update map + */ + for (tl= update_list; tl; tl= tl->next) { - table_list->table->map= (table_map) 1 << tablenr; + TABLE *table= tl->table; + /* if table will be updated then check that it is unique */ + if (table->map & update_tables) + { + /* + Multi-update can't be constructed over-union => we always have + single SELECT on top and have to check underlaying SELECTs of it + */ + if (select_lex->check_updateable_in_subqueries(tl->db, + tl->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), + tl->real_name); + DBUG_RETURN(-1); + } + DBUG_PRINT("info",("setting table `%s` for update", tl->alias)); + tl->lock_type= thd->lex.lock_option; + tl->updating= 1; + } + else + { + DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias)); + tl->lock_type= TL_READ; + tl->updating= 0; + } + if (tl->derived) + derived_tables|= table->map; } - } - if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0)) - DBUG_RETURN(-1); + if (thd->lex->derived_tables && (update_tables & derived_tables)) + { + // find derived table which cause error + for (tl= update_list; tl; tl= tl->next) + { + if (tl->derived && (update_tables & tl->table->map)) + { + my_printf_error(ER_NON_UPDATABLE_TABLE, ER(ER_NON_UPDATABLE_TABLE), + MYF(0), tl->alias, "UPDATE"); + DBUG_RETURN(-1); + } + } + } - /* Find tables used in items */ - { - List_iterator_fast<Item> it(*fields); - Item *item; - while ((item= it++)) + /* Relock the tables with the correct modes */ + res= lock_tables(thd,table_list); + if (using_lock_tables) { - item_tables|= item->used_tables(); + if (res) + DBUG_RETURN(res); + break; // Don't have to do setup_field() } + + /* + We must setup fields again as the file may have been reopened + during lock_tables + */ + { + List_iterator_fast<Item> field_it(*fields); + Item_field *item; + + while ((item= (Item_field *) field_it++)) + { + item->field->query_id= 0; + item->cleanup(); + } + } + if (setup_fields(thd, table_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + /* + If lock succeded and the table map didn't change since the above lock + we can continue. + */ + if (!res && update_tables == get_table_map(fields)) + break; + + /* + There was some very unexpected changes in the table definition between + open tables and lock tables. Close tables and try again. + */ + close_thread_tables(thd); } /* - Count tables and setup timestamp handling + Setup timestamp handling */ for (tl= update_list; tl; tl= tl->next) { TABLE *table= tl->table; - - /* We only need SELECT privilege for columns in the values list */ - table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); - // Only set timestamp column if this is not modified + /* 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 */ - if (table->map & item_tables) - { - /* - Multi-update can't be constructed over-union => we always have - single SELECT on top and have to check underlaying SELECTs of it - */ - if (select_lex->check_updateable_in_subqueries(tl->db, - tl->real_name)) - { - my_error(ER_UPDATE_TABLE_USED, MYF(0), - tl->real_name); - DBUG_RETURN(-1); - } - } - - if (tl->derived) - derived_tables|= table->map; - } - if (thd->lex->derived_tables && (item_tables & derived_tables)) - { - // find derived table which cause error - for (tl= update_list; tl; tl= tl->next) - { - if (tl->derived && (item_tables & tl->table->map)) - { - my_printf_error(ER_NON_UPDATABLE_TABLE, ER(ER_NON_UPDATABLE_TABLE), - MYF(0), tl->alias, "UPDATE"); - DBUG_RETURN(-1); - } - } } if (!(result=new multi_update(thd, update_list, fields, values, handle_duplicates))) DBUG_RETURN(-1); - List<Item> total_list; res= mysql_select(thd, &select_lex->ref_pointer_array, select_lex->get_table_list(), select_lex->with_wild, total_list, @@ -597,7 +671,7 @@ int multi_update::prepare(List<Item> ¬_used_values, { TABLE_LIST *table_ref; SQL_LIST update; - table_map tables_to_update= 0; + table_map tables_to_update; Item_field *item; List_iterator_fast<Item> field_it(*fields); List_iterator_fast<Item> value_it(*values); @@ -608,8 +682,7 @@ int multi_update::prepare(List<Item> ¬_used_values, thd->cuted_fields=0L; thd->proc_info="updating main table"; - while ((item= (Item_field *) field_it++)) - tables_to_update|= item->used_tables(); + tables_to_update= get_table_map(fields); if (!tables_to_update) { @@ -672,7 +745,6 @@ int multi_update::prepare(List<Item> ¬_used_values, /* Split fields into fields_for_table[] and values_by_table[] */ - field_it.rewind(); while ((item= (Item_field *) field_it++)) { Item *value= value_it++; @@ -918,9 +990,13 @@ bool multi_update::send_data(List<Item> ¬_used_values) if ((error=table->file->update_row(table->record[1], table->record[0]))) { - table->file->print_error(error,MYF(0)); updated--; - DBUG_RETURN(1); + if (handle_duplicates != DUP_IGNORE || + error != HA_ERR_FOUND_DUPP_KEY) + { + table->file->print_error(error,MYF(0)); + DBUG_RETURN(1); + } } } } @@ -986,7 +1062,6 @@ int multi_update::do_updates(bool from_send_error) TABLE *table, *tmp_table; DBUG_ENTER("do_updates"); - do_update= 0; // Don't retry this function if (!found) DBUG_RETURN(0); |