1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

MDEV-16974 Application-time periods: UPDATE

This commit is contained in:
Nikita Malyavin
2018-09-18 00:25:25 +10:00
committed by Sergei Golubchik
parent 47e28a94d5
commit b2bd52290a
8 changed files with 579 additions and 25 deletions

View File

@ -132,7 +132,8 @@ bool compare_record(const TABLE *table)
FALSE Items are OK
*/
static bool check_fields(THD *thd, List<Item> &items, bool update_view)
static bool check_fields(THD *thd, TABLE_LIST *table, List<Item> &items,
bool update_view)
{
Item *item;
if (update_view)
@ -177,6 +178,22 @@ static bool check_fields(THD *thd, List<Item> &items, bool update_view)
f->set_has_explicit_value();
}
}
if (table->has_period())
{
DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE);
for (List_iterator_fast<Item> it(items); (item=it++);)
{
Field *f= item->field_for_view_update()->field;
vers_select_conds_t &period= table->period_conditions;
if (period.field_start->field == f || period.field_end->field == f)
{
my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0),
item->name.str, period.name.str);
return true;
}
}
}
return FALSE;
}
@ -267,6 +284,31 @@ static void prepare_record_for_error_message(int error, TABLE *table)
}
static
int cut_fields_for_portion_of_time(THD *thd, TABLE *table,
const vers_select_conds_t &period_conds)
{
bool lcond= period_conds.field_start->val_datetime_packed(thd)
< period_conds.start.item->val_datetime_packed(thd);
bool rcond= period_conds.field_end->val_datetime_packed(thd)
> period_conds.end.item->val_datetime_packed(thd);
Field *start_field= table->field[table->s->period.start_fieldno];
Field *end_field= table->field[table->s->period.end_fieldno];
DBUG_ASSERT(!start_field->has_explicit_value()
&& !end_field->has_explicit_value());
int res= 0;
if (lcond)
res= period_conds.start.item->save_in_field(start_field, true);
if (likely(!res) && rcond)
res= period_conds.end.item->save_in_field(end_field, true);
return res;
}
/*
Process usual UPDATE
@ -330,7 +372,7 @@ int mysql_update(THD *thd,
query_plan.using_filesort= FALSE;
// For System Versioning (may need to insert new fields to a table).
ha_rows updated_sys_ver= 0;
ha_rows rows_inserted= 0;
DBUG_ENTER("mysql_update");
@ -398,7 +440,7 @@ int mysql_update(THD *thd,
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(1); /* purecov: inspected */
if (check_fields(thd, fields, table_list->view))
if (check_fields(thd, table_list, fields, table_list->view))
{
DBUG_RETURN(1);
}
@ -509,7 +551,10 @@ int mysql_update(THD *thd,
if (unlikely(init_ftfuncs(thd, select_lex, 1)))
goto err;
table->mark_columns_needed_for_update();
if (table_list->has_period())
table->use_all_columns();
else
table->mark_columns_needed_for_update();
table->update_const_key_parts(conds);
order= simple_remove_const(order, conds);
@ -590,6 +635,14 @@ int mysql_update(THD *thd,
TRG_ACTION_BEFORE) ||
table->triggers->has_triggers(TRG_EVENT_UPDATE,
TRG_ACTION_AFTER)));
if (table_list->has_period())
has_triggers= table->triggers &&
(table->triggers->has_triggers(TRG_EVENT_INSERT,
TRG_ACTION_BEFORE)
|| table->triggers->has_triggers(TRG_EVENT_INSERT,
TRG_ACTION_AFTER)
|| has_triggers);
DBUG_PRINT("info", ("has_triggers: %s", has_triggers ? "TRUE" : "FALSE"));
binlog_is_row= thd->is_current_stmt_binlog_format_row();
DBUG_PRINT("info", ("binlog_is_row: %s", binlog_is_row ? "TRUE" : "FALSE"));
@ -880,14 +933,25 @@ update_begin:
explain->tracker.on_record_after_where();
store_record(table,record[1]);
if (table_list->has_period())
cut_fields_for_portion_of_time(thd, table,
table_list->period_conditions);
if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0,
TRG_EVENT_UPDATE))
break; /* purecov: inspected */
found++;
if (!can_compare_record || compare_record(table))
bool record_was_same= false;
bool need_update= !can_compare_record || compare_record(table);
if (need_update)
{
if (table->versioned(VERS_TIMESTAMP) &&
thd->lex->sql_command == SQLCOM_DELETE)
table->vers_update_end();
if (table->default_field && table->update_default_fields(1, ignore))
{
error= 1;
@ -946,7 +1010,9 @@ update_begin:
error= table->file->ha_update_row(table->record[1],
table->record[0]);
}
if (unlikely(error == HA_ERR_RECORD_IS_THE_SAME))
record_was_same= error == HA_ERR_RECORD_IS_THE_SAME;
if (unlikely(record_was_same))
{
error= 0;
}
@ -961,12 +1027,22 @@ update_begin:
restore_record(table, record[2]);
}
if (likely(!error))
updated_sys_ver++;
rows_inserted++;
}
if (likely(!error))
updated++;
}
if (likely(!error) && !record_was_same && table_list->has_period())
{
store_record(table, record[2]);
restore_record(table, record[1]);
error= table->insert_portion_of_time(thd,
table_list->period_conditions,
&rows_inserted);
restore_record(table, record[2]);
}
if (unlikely(error) &&
(!ignore || table->file->is_fatal_error(error, HA_CHECK_ALL)))
{
@ -1107,6 +1183,8 @@ update_end:
delete select;
select= NULL;
THD_STAGE_INFO(thd, stage_end);
if (table_list->has_period())
table->file->ha_release_auto_increment();
(void) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
/*
@ -1169,14 +1247,14 @@ update_end:
if (likely(error < 0) && likely(!thd->lex->analyze_stmt))
{
char buff[MYSQL_ERRMSG_SIZE];
if (!table->versioned(VERS_TIMESTAMP))
if (!table->versioned(VERS_TIMESTAMP) && !table_list->has_period())
my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), (ulong) found,
(ulong) updated,
(ulong) thd->get_stmt_da()->current_statement_warn_count());
else
my_snprintf(buff, sizeof(buff),
ER_THD(thd, ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING),
(ulong) found, (ulong) updated, (ulong) updated_sys_ver,
(ulong) found, (ulong) updated, (ulong) rows_inserted,
(ulong) thd->get_stmt_da()->current_statement_warn_count());
my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
id, buff);
@ -1257,6 +1335,19 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
thd->lex->allow_sum_func.clear_all();
if (table_list->has_period())
{
if (table_list->is_view_or_derived())
{
my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
DBUG_RETURN(true);
}
*conds= select_lex->period_setup_conds(thd, table_list, *conds);
if (!*conds)
DBUG_RETURN(true);
}
/*
We do not call DT_MERGE_FOR_INSERT because it has no sense for simple
(not multi-) update
@ -1276,6 +1367,16 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
if (table_list->has_period())
{
if (!table_list->period_conditions.start.item->const_item()
|| !table_list->period_conditions.end.item->const_item())
{
my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF");
DBUG_RETURN(true);
}
}
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
}
@ -1589,7 +1690,7 @@ int mysql_multi_update_prepare(THD *thd)
}
}
if (check_fields(thd, *fields, update_view))
if (check_fields(thd, table_list, *fields, update_view))
{
DBUG_RETURN(TRUE);
}