some small changes for MULTI-TABLE updates and other little fixes

parent 74deec5a
...@@ -684,7 +684,7 @@ class Unique :public Sql_alloc ...@@ -684,7 +684,7 @@ class Unique :public Sql_alloc
enum enum_duplicates dupl; enum enum_duplicates dupl;
uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence; uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
int error; int error;
bool do_update; bool do_update, not_trans_safe;
public: public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs, multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
enum enum_duplicates handle_duplicates, enum enum_duplicates handle_duplicates,
......
...@@ -1224,8 +1224,6 @@ mysql_execute_command(void) ...@@ -1224,8 +1224,6 @@ mysql_execute_command(void)
(table_rules_on && tables && thd->slave_thread && (table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables))) !tables_ok(thd,tables)))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
if (lex->sql_command==SQLCOM_UPDATE && select_lex->table_list.elements > 1)
lex->sql_command=SQLCOM_MULTI_UPDATE;
thread_safe_increment(com_stat[lex->sql_command],&LOCK_thread_count); thread_safe_increment(com_stat[lex->sql_command],&LOCK_thread_count);
switch (lex->sql_command) { switch (lex->sql_command) {
...@@ -1697,6 +1695,8 @@ mysql_execute_command(void) ...@@ -1697,6 +1695,8 @@ mysql_execute_command(void)
send_error(&thd->net,ER_WRONG_VALUE_COUNT); send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (select_lex->table_list.elements == 1)
{
res = mysql_update(thd,tables, res = mysql_update(thd,tables,
select_lex->item_list, select_lex->item_list,
lex->value_list, lex->value_list,
...@@ -1709,6 +1709,53 @@ mysql_execute_command(void) ...@@ -1709,6 +1709,53 @@ mysql_execute_command(void)
#ifdef DELETE_ITEMS #ifdef DELETE_ITEMS
delete select_lex->where; delete select_lex->where;
#endif #endif
}
else
{
multi_update *result;
uint table_count;
TABLE_LIST *auxi;
lex->sql_command=SQLCOM_MULTI_UPDATE;
for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
{
table_count++;
auxi->lock_type=TL_WRITE;
}
if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
{
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
DBUG_VOID_RETURN;
}
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
if ((res=open_and_lock_tables(thd,tables)))
break;
if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
!setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
(result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
lex->lock_option, table_count)))
{
List <Item> total_list;
List_iterator <Item> field_list(select_lex->item_list);
List_iterator <Item> value_list(lex->value_list);
Item *item;
while ((item=field_list++))
total_list.push_back(item);
while ((item=value_list++))
total_list.push_back(item);
res=mysql_select(thd,tables,total_list,
select_lex->where,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result);
delete result;
}
else
res= -1; // Error is not sent
close_thread_tables(thd);
}
break; break;
case SQLCOM_INSERT: case SQLCOM_INSERT:
if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege)) if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
...@@ -1879,59 +1926,6 @@ mysql_execute_command(void) ...@@ -1879,59 +1926,6 @@ mysql_execute_command(void)
close_thread_tables(thd); close_thread_tables(thd);
break; break;
} }
case SQLCOM_MULTI_UPDATE:
multi_update *result;
uint table_count;
TABLE_LIST *auxi;
if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
{
table_count++;
auxi->lock_type=TL_WRITE;
}
if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
{
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
DBUG_VOID_RETURN;
}
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
if ((res=open_and_lock_tables(thd,tables)))
break;
if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
!setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
(result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
lex->lock_option, table_count)))
{
List <Item> total_list;
List_iterator <Item> field_list(select_lex->item_list);
List_iterator <Item> value_list(lex->value_list);
Item *item;
while ((item=field_list++))
total_list.push_back(item);
while ((item=value_list++))
total_list.push_back(item);
res=mysql_select(thd,tables,total_list,
select_lex->where,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result);
delete result;
}
else
res= -1; // Error is not sent
close_thread_tables(thd);
break;
case SQLCOM_DROP_TABLE: case SQLCOM_DROP_TABLE:
{ {
if (check_table_access(thd,DROP_ACL,tables)) if (check_table_access(thd,DROP_ACL,tables))
......
...@@ -359,6 +359,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs, ...@@ -359,6 +359,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
tmp_tables = (TABLE **)NULL; tmp_tables = (TABLE **)NULL;
int counter=0; int counter=0;
ulong timestamp_query_id; ulong timestamp_query_id;
not_trans_safe=false;
for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++) for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++)
{ {
TABLE *table=ut->table; TABLE *table=ut->table;
...@@ -420,6 +421,9 @@ multi_update::prepare(List<Item> &values) ...@@ -420,6 +421,9 @@ multi_update::prepare(List<Item> &values)
{ {
num_updated++; num_updated++;
table_ref->shared=1; table_ref->shared=1;
if (!not_trans_safe && !table_ref->table->file->has_transactions())
not_trans_safe=true;
table_ref->table->no_keyread=1; // to be moved if initialize_tables has to be used
break; break;
} }
} }
...@@ -529,6 +533,7 @@ multi_update::~multi_update() ...@@ -529,6 +533,7 @@ multi_update::~multi_update()
{ {
TABLE *table=table_being_updated->table; TABLE *table=table_being_updated->table;
(void)table->file->extra(HA_EXTRA_READCHECK); (void)table->file->extra(HA_EXTRA_READCHECK);
table->no_keyread=0;
if (error) if (error)
table->time_stamp=save_time_stamps[counter]; table->time_stamp=save_time_stamps[counter];
} }
...@@ -629,27 +634,13 @@ bool multi_update::send_data(List<Item> &values) ...@@ -629,27 +634,13 @@ bool multi_update::send_data(List<Item> &values)
return 0; return 0;
} }
/* Return true if some table is not transaction safe */
static bool some_table_is_not_transaction_safe (TABLE_LIST *tl)
{
for (; tl ; tl=tl->next)
{
if (!(tl->table->file->has_transactions()))
return true;
}
return false;
}
void multi_update::send_error(uint errcode,const char *err) void multi_update::send_error(uint errcode,const char *err)
{ {
/* First send error what ever it is ... */ /* First send error what ever it is ... */
::send_error(&thd->net,errcode,err); ::send_error(&thd->net,errcode,err);
/* reset used flags */ /* reset used flags */
update_tables->table->no_keyread=0; // update_tables->table->no_keyread=0;
/* If nothing updated return */ /* If nothing updated return */
if (!updated) if (!updated)
...@@ -665,8 +656,7 @@ void multi_update::send_error(uint errcode,const char *err) ...@@ -665,8 +656,7 @@ void multi_update::send_error(uint errcode,const char *err)
In all other cases do attempt updates ... In all other cases do attempt updates ...
*/ */
if ((table_being_updated->table->file->has_transactions() && if ((table_being_updated->table->file->has_transactions() &&
table_being_updated == update_tables) || table_being_updated == update_tables) || !not_trans_safe)
!some_table_is_not_transaction_safe(update_tables->next))
ha_rollback_stmt(thd); ha_rollback_stmt(thd);
else if (do_update) else if (do_update)
VOID(do_updates(true)); VOID(do_updates(true));
...@@ -721,7 +711,6 @@ int multi_update::do_updates (bool from_send_error) ...@@ -721,7 +711,6 @@ int multi_update::do_updates (bool from_send_error)
error = tmp_table->file->rnd_init(1); error = tmp_table->file->rnd_init(1);
if (error) if (error)
return error; return error;
bool not_trans_safe = some_table_is_not_transaction_safe(update_tables);
while (!(error=tmp_table->file->rnd_next(tmp_table->record[0])) && while (!(error=tmp_table->file->rnd_next(tmp_table->record[0])) &&
(!thd->killed || from_send_error || not_trans_safe)) (!thd->killed || from_send_error || not_trans_safe))
{ {
...@@ -756,7 +745,7 @@ bool multi_update::send_eof() ...@@ -756,7 +745,7 @@ bool multi_update::send_eof()
int error = do_updates(false); /* do_updates returns 0 if success */ int error = do_updates(false); /* do_updates returns 0 if success */
/* reset used flags */ /* reset used flags */
update_tables->table->no_keyread=0; // update_tables->table->no_keyread=0;
if (error == -1) error = 0; if (error == -1) error = 0;
thd->proc_info="end"; thd->proc_info="end";
if (error) if (error)
...@@ -767,8 +756,7 @@ bool multi_update::send_eof() ...@@ -767,8 +756,7 @@ bool multi_update::send_eof()
was a non-transaction-safe table involved, since was a non-transaction-safe table involved, since
modifications in it cannot be rolled back. */ modifications in it cannot be rolled back. */
if (updated && if (updated || not_trans_safe)
(!error || some_table_is_not_transaction_safe(update_tables)))
{ {
mysql_update_log.write(thd,thd->query,thd->query_length); mysql_update_log.write(thd,thd->query,thd->query_length);
Query_log_event qinfo(thd, thd->query); Query_log_event qinfo(thd, thd->query);
...@@ -777,7 +765,7 @@ bool multi_update::send_eof() ...@@ -777,7 +765,7 @@ bool multi_update::send_eof()
is not used */ is not used */
if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) && if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
!some_table_is_not_transaction_safe(update_tables)) !not_trans_safe)
error=1; /* Log write failed: roll back error=1; /* Log write failed: roll back
the SQL statement */ the SQL statement */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment