summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc190
1 files changed, 147 insertions, 43 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e846424ef13..b16c49cf17a 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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,27 @@ static bool check_fields(THD *thd, List<Item> &items, bool update_view)
f->set_has_explicit_value();
}
}
+
+ if (table->has_period())
+ {
+ if (table->is_view_or_derived())
+ {
+ my_error(ER_IT_IS_A_VIEW, MYF(0), table->table_name.str);
+ return TRUE;
+ }
+ 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;
}
@@ -275,6 +297,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
@@ -325,7 +372,7 @@ int mysql_update(THD *thd,
SQL_SELECT *select= NULL;
SORT_INFO *file_sort= 0;
READ_RECORD info;
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
ulonglong id;
List<Item> all_fields;
killed_state killed_status= NOT_KILLED;
@@ -337,7 +384,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");
@@ -349,6 +396,12 @@ int mysql_update(THD *thd,
if (mysql_handle_derived(thd->lex, DT_INIT))
DBUG_RETURN(1);
+ if (table_list->has_period() && table_list->is_view_or_derived())
+ {
+ my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
+ DBUG_RETURN(TRUE);
+ }
+
if (((update_source_table=unique_table(thd, table_list,
table_list->next_global, 0)) ||
table_list->is_multitable()))
@@ -384,7 +437,7 @@ int mysql_update(THD *thd,
table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
- query_plan.select_lex= &thd->lex->select_lex;
+ query_plan.select_lex= thd->lex->first_select_lex();
query_plan.table= table;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Force privilege re-checking for views after they have been opened. */
@@ -394,6 +447,16 @@ int mysql_update(THD *thd,
if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
DBUG_RETURN(1);
+ 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);
+ }
+ }
+
old_covering_keys= table->covering_keys; // Keys used in WHERE
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -407,7 +470,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);
}
@@ -518,7 +581,15 @@ 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();
+ table->rpl_write_set= table->write_set;
+ }
+ else
+ {
+ table->mark_columns_needed_for_update();
+ }
table->update_const_key_parts(conds);
order= simple_remove_const(order, conds);
@@ -599,6 +670,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"));
@@ -889,14 +968,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;
@@ -955,7 +1045,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;
}
@@ -971,12 +1063,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)))
{
@@ -987,7 +1089,7 @@ update_begin:
myf flags= 0;
if (table->file->is_fatal_error(error, HA_CHECK_ALL))
- flags|= ME_FATALERROR; /* Other handler errors are fatal */
+ flags|= ME_FATAL; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
table->file->print_error(error,MYF(flags));
@@ -1098,7 +1200,7 @@ update_begin:
{
/* purecov: begin inspected */
prepare_record_for_error_message(loc_error, table);
- table->file->print_error(loc_error,MYF(ME_FATALERROR));
+ table->file->print_error(loc_error,MYF(ME_FATAL));
error= 1;
/* purecov: end */
}
@@ -1117,6 +1219,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);
/*
@@ -1179,14 +1283,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);
@@ -1256,7 +1360,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
TABLE *table= table_list->table;
#endif
List<Item> all_fields;
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
DBUG_ENTER("mysql_prepare_update");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1267,6 +1371,13 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
thd->lex->allow_sum_func.clear_all();
+ if (table_list->has_period())
+ {
+ *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
@@ -1275,8 +1386,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
if (setup_tables_and_check_access(thd, &select_lex->context,
- &select_lex->top_join_list,
- table_list,
+ &select_lex->top_join_list, table_list,
select_lex->leaf_tables,
FALSE, UPDATE_ACL, SELECT_ACL, TRUE) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
@@ -1286,6 +1396,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
+
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
}
@@ -1544,7 +1655,7 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
DBUG_RETURN(0);
LEX *lex= thd->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
TABLE_LIST *table_list= lex->query_tables, *tl;
done= true;
@@ -1568,7 +1679,7 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
if (select_lex->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(1);
- List<Item> *fields= &lex->select_lex.item_list;
+ List<Item> *fields= &lex->first_select_lex()->item_list;
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
*fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(1);
@@ -1578,7 +1689,7 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
if (tl->view)
break;
// ... and pass this knowlage in check_fields call
- if (check_fields(thd, *fields, tl != NULL ))
+ if (check_fields(thd, table_list, *fields, tl != NULL ))
DBUG_RETURN(1);
table_map tables_for_update= thd->table_map_for_update= get_table_map(fields);
@@ -1589,7 +1700,7 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
/*
Setup timestamp handling and locking mode
*/
- List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
+ List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables);
const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
while ((tl= ti++))
{
@@ -1733,9 +1844,9 @@ int mysql_multi_update_prepare(THD *thd)
Check that we are not using table that we are updating, but we should
skip all tables of UPDATE SELECT itself
*/
- lex->select_lex.exclude_from_table_unique_test= TRUE;
+ lex->first_select_lex()->exclude_from_table_unique_test= TRUE;
/* We only need SELECT privilege for columns in the values list */
- List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
+ List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables);
while ((tl= ti++))
{
if (tl->is_jtbm())
@@ -1755,7 +1866,7 @@ int mysql_multi_update_prepare(THD *thd)
Set exclude_from_table_unique_test value back to FALSE. It is needed for
further check in multi_update::prepare whether to use record cache.
*/
- lex->select_lex.exclude_from_table_unique_test= FALSE;
+ lex->first_select_lex()->exclude_from_table_unique_test= FALSE;
if (lex->save_prep_leaf_tables())
DBUG_RETURN(TRUE);
@@ -1778,7 +1889,7 @@ bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields,
DBUG_ENTER("mysql_multi_update");
if (!(*result= new (thd->mem_root) multi_update(thd, table_list,
- &thd->lex->select_lex.leaf_tables,
+ &thd->lex->first_select_lex()->leaf_tables,
fields, values, handle_duplicates, ignore)))
{
DBUG_RETURN(TRUE);
@@ -2280,11 +2391,11 @@ int multi_update::prepare2(JOIN *join)
{
if (item_rowid_table(*it2) != tbl)
continue;
- Item *fld= new (thd->mem_root)
- Item_field(thd, (*it)->get_tmp_table_field());
+ Item_field *fld= new (thd->mem_root)
+ Item_field(thd, (*it)->get_tmp_table_field());
if (!fld)
return 1;
- fld->set_result_field((*it2)->get_tmp_table_field());
+ fld->result_field= (*it2)->get_tmp_table_field();
*it2= fld;
}
}
@@ -2416,7 +2527,7 @@ int multi_update::send_data(List<Item> &not_used_values)
myf flags= 0;
if (table->file->is_fatal_error(error, HA_CHECK_ALL))
- flags|= ME_FATALERROR; /* Other handler errors are fatal */
+ flags|= ME_FATAL; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
table->file->print_error(error,MYF(flags));
@@ -2571,17 +2682,10 @@ int multi_update::do_updates()
not its dependencies
*/
while(TABLE *tbl= check_opt_it++)
- {
- if (tbl->vcol_set)
- {
- bitmap_clear_all(tbl->vcol_set);
- for (Field **vf= tbl->vfield; *vf; vf++)
- {
+ if (Field **vf= tbl->vfield)
+ for (; *vf; vf++)
if (bitmap_is_set(tbl->read_set, (*vf)->field_index))
- tbl->mark_virtual_col(*vf);
- }
- }
- }
+ (*vf)->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0);
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
@@ -2671,10 +2775,10 @@ int multi_update::do_updates()
uint field_num= 0;
do
{
- if (unlikely((local_error=
- tbl->file->ha_rnd_pos(tbl->record[0],
- (uchar *) tmp_table->
- field[field_num]->ptr))))
+ String rowid;
+ tmp_table->field[field_num]->val_str(&rowid);
+ if (unlikely((local_error= tbl->file->ha_rnd_pos(tbl->record[0],
+ (uchar*)rowid.ptr()))))
{
err_table= tbl;
goto err;
@@ -2791,7 +2895,7 @@ int multi_update::do_updates()
err:
{
prepare_record_for_error_message(local_error, err_table);
- err_table->file->print_error(local_error,MYF(ME_FATALERROR));
+ err_table->file->print_error(local_error,MYF(ME_FATAL));
}
err2: