1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Manual merge of patch fixing several trigger related bugs with main tree.

This commit is contained in:
dlenev@mysql.com
2005-05-24 22:35:41 +04:00
12 changed files with 634 additions and 127 deletions

View File

@@ -398,7 +398,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (fields.elements || !value_count)
{
restore_record(table,s->default_values); // Get empty record
if (fill_record(thd, fields, *values, 0))
if (fill_record_n_invoke_before_triggers(thd, fields, *values, 0,
table->triggers,
TRG_EVENT_INSERT))
{
if (values_list.elements != 1 && !thd->net.report_error)
{
@@ -419,8 +421,17 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (thd->used_tables) // Column used in values()
restore_record(table,s->default_values); // Get empty record
else
table->record[0][0]= table->s->default_values[0]; // Fix delete marker
if (fill_record(thd, table->field, *values, 0))
{
/*
Fix delete marker. No need to restore rest of record since it will
be overwritten by fill_record() anyway (and fill_record() does not
use default values in this case).
*/
table->record[0][0]= table->s->default_values[0];
}
if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
table->triggers,
TRG_EVENT_INSERT))
{
if (values_list.elements != 1 && ! thd->net.report_error)
{
@@ -432,14 +443,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
}
/*
FIXME: Actually we should do this before
check_that_all_fields_are_given_values Or even go into write_record ?
*/
if (table->triggers)
table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
TRG_ACTION_BEFORE);
if ((res= table_list->view_check_option(thd,
(values_list.elements == 1 ?
0 :
@@ -473,9 +476,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (error)
break;
thd->row_count++;
if (table->triggers)
table->triggers->process_triggers(thd, TRG_EVENT_INSERT, TRG_ACTION_AFTER);
}
/*
@@ -802,15 +802,35 @@ static int last_uniq_key(TABLE *table,uint keynr)
/*
Write a record to table with optional deleting of conflicting records
Write a record to table with optional deleting of conflicting records,
invoke proper triggers if needed.
Sets thd->no_trans_update if table which is updated didn't have transactions
SYNOPSIS
write_record()
thd - thread context
table - table to which record should be written
info - COPY_INFO structure describing handling of duplicates
and which is used for counting number of records inserted
and deleted.
NOTE
Once this record will be written to table after insert trigger will
be invoked. If instead of inserting new record we will update old one
then both on update triggers will work instead. Similarly both on
delete triggers will be invoked if we will delete conflicting records.
Sets thd->no_trans_update if table which is updated didn't have
transactions.
RETURN VALUE
0 - success
non-0 - error
*/
int write_record(THD *thd, TABLE *table,COPY_INFO *info)
{
int error;
int error, trg_error= 0;
char *key=0;
DBUG_ENTER("write_record");
@@ -881,25 +901,33 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
restore_record(table,record[1]);
DBUG_ASSERT(info->update_fields->elements ==
info->update_values->elements);
if (fill_record(thd, *info->update_fields, *info->update_values, 0))
goto err;
if (fill_record_n_invoke_before_triggers(thd, *info->update_fields,
*info->update_values, 0,
table->triggers,
TRG_EVENT_UPDATE))
goto before_trg_err;
/* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
if (info->view &&
(res= info->view->view_check_option(current_thd, info->ignore)) ==
VIEW_CHECK_SKIP)
break;
goto ok_or_after_trg_err;
if (res == VIEW_CHECK_ERROR)
goto err;
goto before_trg_err;
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
if ((error == HA_ERR_FOUND_DUPP_KEY) && info->ignore)
break;
goto ok_or_after_trg_err;
goto err;
}
info->updated++;
break;
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE));
info->copied++;
goto ok_or_after_trg_err;
}
else /* DUP_REPLACE */
{
@@ -916,20 +944,48 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
(table->timestamp_field_type == TIMESTAMP_NO_AUTO_SET ||
table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH))
{
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_BEFORE, TRUE))
goto before_trg_err;
if ((error=table->file->update_row(table->record[1],
table->record[0])))
goto err;
info->deleted++;
break; /* Update logfile and count */
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER,
TRUE));
/* Update logfile and count */
info->copied++;
goto ok_or_after_trg_err;
}
else
{
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, TRUE))
goto before_trg_err;
if ((error=table->file->delete_row(table->record[1])))
goto err;
info->deleted++;
if (!table->file->has_transactions())
thd->no_trans_update= 1;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, TRUE))
{
trg_error= 1;
goto ok_or_after_trg_err;
}
/* Let us attempt do write_row() once more */
}
else if ((error=table->file->delete_row(table->record[1])))
goto err;
info->deleted++;
if (!table->file->has_transactions())
thd->no_trans_update= 1;
}
}
info->copied++;
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
TRG_ACTION_AFTER, TRUE));
}
else if ((error=table->file->write_row(table->record[0])))
{
@@ -939,18 +995,27 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
table->file->restore_auto_increment();
}
else
{
info->copied++;
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
TRG_ACTION_AFTER, TRUE));
}
ok_or_after_trg_err:
if (key)
my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH);
if (!table->file->has_transactions())
thd->no_trans_update= 1;
DBUG_RETURN(0);
DBUG_RETURN(trg_error);
err:
if (key)
my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH);
info->last_errno= error;
table->file->print_error(error,MYF(0));
before_trg_err:
if (key)
my_safe_afree(key, table->s->max_unique_length, MAX_KEY_LENGTH);
DBUG_RETURN(1);
}
@@ -2014,12 +2079,27 @@ bool select_insert::send_data(List<Item> &values)
DBUG_RETURN(1);
}
}
if (!(error= write_record(thd, table,&info)) && table->next_number_field)
if (!(error= write_record(thd, table, &info)))
{
/* Clear for next record */
table->next_number_field->reset();
if (! last_insert_id && thd->insert_id_used)
last_insert_id=thd->insert_id();
if (table->triggers)
{
/*
If triggers exist then whey can modify some fields which were not
originally touched by INSERT ... SELECT, so we have to restore
their original values for the next row.
*/
restore_record(table, s->default_values);
}
if (table->next_number_field)
{
/*
Clear auto-increment field for the next record, if triggers are used
we will clear it twice, but this should be cheap.
*/
table->next_number_field->reset();
if (!last_insert_id && thd->insert_id_used)
last_insert_id= thd->insert_id();
}
}
DBUG_RETURN(error);
}
@@ -2028,9 +2108,11 @@ bool select_insert::send_data(List<Item> &values)
void select_insert::store_values(List<Item> &values)
{
if (fields->elements)
fill_record(thd, *fields, values, 1);
fill_record_n_invoke_before_triggers(thd, *fields, values, 1,
table->triggers, TRG_EVENT_INSERT);
else
fill_record(thd, table->field, values, 1);
fill_record_n_invoke_before_triggers(thd, table->field, values, 1,
table->triggers, TRG_EVENT_INSERT);
}
void select_insert::send_error(uint errcode,const char *err)
@@ -2173,7 +2255,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
void select_create::store_values(List<Item> &values)
{
fill_record(thd, field, values, 1);
fill_record_n_invoke_before_triggers(thd, field, values, 1,
table->triggers, TRG_EVENT_INSERT);
}