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

parent 74deec5a
......@@ -684,7 +684,7 @@ public:
enum enum_duplicates dupl;
uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
int error;
bool do_update;
bool do_update, not_trans_safe;
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
enum enum_duplicates handle_duplicates,
......
......@@ -1224,8 +1224,6 @@ mysql_execute_command(void)
(table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables)))
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);
switch (lex->sql_command) {
......@@ -1697,19 +1695,68 @@ mysql_execute_command(void)
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
res = mysql_update(thd,tables,
select_lex->item_list,
lex->value_list,
select_lex->where,
(ORDER *) select_lex->order_list.first,
select_lex->select_limit,
lex->duplicates,
lex->lock_option);
if (select_lex->table_list.elements == 1)
{
res = mysql_update(thd,tables,
select_lex->item_list,
lex->value_list,
select_lex->where,
(ORDER *) select_lex->order_list.first,
select_lex->select_limit,
lex->duplicates,
lex->lock_option);
#ifdef DELETE_ITEMS
delete select_lex->where;
delete select_lex->where;
#endif
break;
}
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;
case SQLCOM_INSERT:
if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */
......@@ -1879,59 +1926,6 @@ mysql_execute_command(void)
close_thread_tables(thd);
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:
{
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,
tmp_tables = (TABLE **)NULL;
int counter=0;
ulong timestamp_query_id;
not_trans_safe=false;
for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++)
{
TABLE *table=ut->table;
......@@ -420,6 +421,9 @@ multi_update::prepare(List<Item> &values)
{
num_updated++;
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;
}
}
......@@ -529,6 +533,7 @@ multi_update::~multi_update()
{
TABLE *table=table_being_updated->table;
(void)table->file->extra(HA_EXTRA_READCHECK);
table->no_keyread=0;
if (error)
table->time_stamp=save_time_stamps[counter];
}
......@@ -629,27 +634,13 @@ bool multi_update::send_data(List<Item> &values)
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)
{
/* First send error what ever it is ... */
::send_error(&thd->net,errcode,err);
/* reset used flags */
update_tables->table->no_keyread=0;
// update_tables->table->no_keyread=0;
/* If nothing updated return */
if (!updated)
......@@ -665,8 +656,7 @@ void multi_update::send_error(uint errcode,const char *err)
In all other cases do attempt updates ...
*/
if ((table_being_updated->table->file->has_transactions() &&
table_being_updated == update_tables) ||
!some_table_is_not_transaction_safe(update_tables->next))
table_being_updated == update_tables) || !not_trans_safe)
ha_rollback_stmt(thd);
else if (do_update)
VOID(do_updates(true));
......@@ -721,7 +711,6 @@ int multi_update::do_updates (bool from_send_error)
error = tmp_table->file->rnd_init(1);
if (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])) &&
(!thd->killed || from_send_error || not_trans_safe))
{
......@@ -756,7 +745,7 @@ bool multi_update::send_eof()
int error = do_updates(false); /* do_updates returns 0 if success */
/* reset used flags */
update_tables->table->no_keyread=0;
// update_tables->table->no_keyread=0;
if (error == -1) error = 0;
thd->proc_info="end";
if (error)
......@@ -767,8 +756,7 @@ bool multi_update::send_eof()
was a non-transaction-safe table involved, since
modifications in it cannot be rolled back. */
if (updated &&
(!error || some_table_is_not_transaction_safe(update_tables)))
if (updated || not_trans_safe)
{
mysql_update_log.write(thd,thd->query,thd->query_length);
Query_log_event qinfo(thd, thd->query);
......@@ -777,7 +765,7 @@ bool multi_update::send_eof()
is not used */
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
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