1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

System Versioning pre0.12

Merge remote-tracking branch 'origin/archive/2017-10-17' into 10.3
This commit is contained in:
Aleksey Midenkov
2017-11-07 00:37:49 +03:00
354 changed files with 20615 additions and 1638 deletions

View File

@ -55,6 +55,9 @@
#include "transaction.h"
#include "sql_audit.h"
#include "sql_sequence.h"
#include "tztime.h"
#include "vtmd.h" // System Versioning
#ifdef __WIN__
#include <io.h>
@ -2293,6 +2296,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
const char *db= table->db;
size_t db_length= table->db_length;
handlerton *table_type= 0;
VTMD_drop vtmd(*table);
DBUG_PRINT("table", ("table_l: '%s'.'%s' table: %p s: %p",
table->db, table->table_name, table->table,
@ -2453,6 +2457,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
else
{
char *end;
int frm_delete_error= 0;
/*
It could happen that table's share in the table definition cache
is the only thing that keeps the engine plugin loaded
@ -2491,30 +2496,51 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
// Remove extension for delete
*(end= path + path_length - reg_ext_length)= '\0';
error= ha_delete_table(thd, table_type, path, db, table->table_name,
!dont_log_query);
if ((thd->lex->sql_command == SQLCOM_DROP_TABLE ||
thd->lex->sql_command == SQLCOM_CREATE_TABLE) &&
thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE &&
table_type && table_type != view_pseudo_hton)
{
error= vtmd.check_exists(thd);
if (error)
goto non_tmp_err;
if (!vtmd.exists)
goto drop_table;
error= mysql_rename_table(table_type, table->db, table->table_name,
table->db, vtmd.archive_name(thd), NO_FK_CHECKS);
}
else
{
drop_table:
error= ha_delete_table(thd, table_type, path, db, table->table_name,
!dont_log_query);
if (!error)
{
/* Delete the table definition file */
strmov(end,reg_ext);
if (table_type && table_type != view_pseudo_hton &&
table_type->discover_table)
{
/*
Table type is using discovery and may not need a .frm file.
Delete it silently if it exists
*/
(void) mysql_file_delete(key_file_frm, path, MYF(0));
}
else if (mysql_file_delete(key_file_frm, path,
MYF(MY_WME)))
{
frm_delete_error= my_errno;
DBUG_ASSERT(frm_delete_error);
}
}
}
if (!error)
{
int frm_delete_error, trigger_drop_error= 0;
/* Delete the table definition file */
strmov(end,reg_ext);
if (table_type && table_type != view_pseudo_hton &&
table_type->discover_table)
{
/*
Table type is using discovery and may not need a .frm file.
Delete it silently if it exists
*/
(void) mysql_file_delete(key_file_frm, path, MYF(0));
frm_delete_error= 0;
}
else
frm_delete_error= mysql_file_delete(key_file_frm, path,
MYF(MY_WME));
if (frm_delete_error)
frm_delete_error= my_errno;
else
int trigger_drop_error= 0;
if (!frm_delete_error)
{
non_tmp_table_deleted= TRUE;
trigger_drop_error=
@ -2527,8 +2553,21 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
else if (frm_delete_error && if_exists)
thd->clear_error();
}
non_tmp_err:
non_tmp_error|= MY_TEST(error);
}
if (!error && vtmd.exists)
{
enum_sql_command sql_command= thd->lex->sql_command;
thd->lex->sql_command= SQLCOM_DROP_TABLE;
error= vtmd.update(thd);
thd->lex->sql_command= sql_command;
if (error)
mysql_rename_table(table_type, table->db, vtmd.archive_name(),
table->db, table->table_name, NO_FK_CHECKS);
}
if (error)
{
if (wrong_tables.length())
@ -3022,10 +3061,12 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
if (column_definition->is_timestamp_type() || // TIMESTAMP
column_definition->unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy
{
DBUG_PRINT("info", ("field-ptr:%p", column_definition->field));
if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL,
column_definition->default_value == NULL && // no constant default,
column_definition->unireg_check == Field::NONE && // no function default
column_definition->vcol_info == NULL)
column_definition->vcol_info == NULL &&
!(column_definition->flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG))) // column isn't generated
{
DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to "
"DEFAULT CURRENT_TIMESTAMP ON UPDATE "
@ -3336,6 +3377,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
select_field_pos= alter_info->create_list.elements - select_field_count;
for (field_no=0; (sql_field=it++) ; field_no++)
{
/*
@ -4281,6 +4323,51 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root)
}
static bool
vers_prepare_keys(THD *thd,
HA_CREATE_INFO *create_info,
Alter_info *alter_info,
KEY **key_info,
uint key_count)
{
DBUG_ASSERT(create_info->versioned());
const char *row_start_field= create_info->vers_info.as_row.start;
DBUG_ASSERT(row_start_field);
const char *row_end_field= create_info->vers_info.as_row.end;
DBUG_ASSERT(row_end_field);
List_iterator<Key> key_it(alter_info->key_list);
Key *key= NULL;
while ((key=key_it++))
{
if (key->type != Key::PRIMARY && key->type != Key::UNIQUE)
continue;
Key_part_spec *key_part= NULL;
List_iterator<Key_part_spec> part_it(key->columns);
while ((key_part=part_it++))
{
if (!my_strcasecmp(system_charset_info,
row_start_field,
key_part->field_name.str) ||
!my_strcasecmp(system_charset_info,
row_end_field,
key_part->field_name.str))
break;
}
if (key_part)
continue; // Key already contains Sys_start or Sys_end
Key_part_spec *key_part_sys_end_col=
new (thd->mem_root) Key_part_spec(&create_info->vers_info.as_row.end, 0);
key->columns.push_back(key_part_sys_end_col);
}
return false;
}
handler *mysql_create_frm_image(THD *thd,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
@ -4439,7 +4526,10 @@ handler *mysql_create_frm_image(THD *thd,
part_info->part_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
if ((!(engine_type->partition_flags &&
engine_type->partition_flags() & HA_CAN_PARTITION)) ||
((engine_type->partition_flags() & HA_CAN_PARTITION) ||
(part_info->part_type == VERSIONING_PARTITION &&
engine_type->partition_flags() & HA_ONLY_VERS_PARTITION))
)) ||
create_info->db_type == partition_hton)
{
/*
@ -4520,6 +4610,13 @@ handler *mysql_create_frm_image(THD *thd,
}
#endif
if (create_info->versioned())
{
if(vers_prepare_keys(thd, create_info, alter_info, key_info,
*key_count))
goto err;
}
if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options,
file, key_info, key_count,
create_table_mode))
@ -4977,6 +5074,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
{
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
result= 1;
goto err;
}
else
{
@ -4985,6 +5083,20 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
}
}
if (create_info->versioned() &&
thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
{
VTMD_table vtmd(*create_table);
if (vtmd.update(thd))
{
thd->variables.vers_alter_history = VERS_ALTER_HISTORY_KEEP;
mysql_rm_table_no_locks(thd, create_table, 0, 0, 0, 0, 1, 1);
thd->variables.vers_alter_history = VERS_ALTER_HISTORY_SURVIVE;
result= 1;
goto err;
}
}
err:
/* In RBR we don't need to log CREATE TEMPORARY TABLE */
if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
@ -5095,6 +5207,66 @@ static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
** Alter a table definition
****************************************************************************/
bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs)
{
return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day ||
lhs.hour != rhs.hour || lhs.minute != rhs.minute ||
lhs.second_part != rhs.second_part || lhs.neg != rhs.neg ||
lhs.time_type != rhs.time_type;
}
// Sets sys_trx_end=MAX for rows with sys_trx_end=now(6)
static bool vers_reset_alter_copy(THD *thd, TABLE *table)
{
const MYSQL_TIME query_start= thd->query_start_TIME();
READ_RECORD info;
int error= 0;
bool will_batch= false;
uint dup_key_found= 0;
if (init_read_record(&info, thd, table, NULL, NULL, 0, 1, true))
goto err;
will_batch= !table->file->start_bulk_update();
while (!(error= info.read_record()))
{
MYSQL_TIME current;
if (table->vers_end_field()->get_date(&current, 0))
goto err_read_record;
if (current != query_start)
{
continue;
}
store_record(table, record[1]);
table->vers_end_field()->set_max();
if (will_batch)
error= table->file->ha_bulk_update_row(table->record[1], table->record[0],
&dup_key_found);
else
error= table->file->ha_update_row(table->record[1], table->record[0]);
if (error && table->file->is_fatal_error(error, HA_CHECK_ALL))
{
table->file->print_error(error, MYF(ME_FATALERROR));
goto err_read_record;
}
}
if (will_batch && (error= table->file->exec_bulk_update(&dup_key_found)))
table->file->print_error(error, MYF(ME_FATALERROR));
if (will_batch)
table->file->end_bulk_update();
err_read_record:
end_read_record(&info);
err:
if (table->file->ha_external_lock(thd, F_UNLCK))
return true;
return error ? true : false;
}
/**
Rename a table.
@ -5318,6 +5490,13 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
thd->work_part_info= src_table->table->part_info->get_clone(thd);
#endif
if (src_table->table->versioned() &&
local_create_info.vers_info.fix_create_like(thd, &local_alter_info,
&local_create_info, src_table))
{
goto err;
}
/*
Adjust description of source table before using it for creation of
target table.
@ -5330,6 +5509,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
/* Replace type of source table with one specified in the statement. */
local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
local_create_info.options|= create_info->tmp_table();
local_create_info.options|= create_info->options;
/* Reset auto-increment counter for the new table. */
local_create_info.auto_increment_value= 0;
/*
@ -6214,6 +6394,8 @@ static bool fill_alter_inplace_info(THD *thd,
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ADD_CHECK_CONSTRAINT;
if (alter_info->flags & Alter_info::ALTER_DROP_CHECK_CONSTRAINT)
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_CHECK_CONSTRAINT;
if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP)
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_HISTORICAL;
/*
If we altering table with old VARCHAR fields we will be automatically
@ -8479,18 +8661,30 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
if (mysql_rename_table(old_db_type, alter_ctx->db, alter_ctx->table_name,
alter_ctx->new_db, alter_ctx->new_alias, 0))
error= -1;
else if (Table_triggers_list::change_table_name(thd,
alter_ctx->db,
alter_ctx->alias,
alter_ctx->table_name,
alter_ctx->new_db,
alter_ctx->new_alias))
else
{
(void) mysql_rename_table(old_db_type,
alter_ctx->new_db, alter_ctx->new_alias,
alter_ctx->db, alter_ctx->table_name,
NO_FK_CHECKS);
error= -1;
VTMD_rename vtmd(*table_list);
if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE &&
vtmd.try_rename(thd, new_db_name, new_table_name))
{
goto revert_table_name;
}
else if (Table_triggers_list::change_table_name(thd,
alter_ctx->db,
alter_ctx->alias,
alter_ctx->table_name,
alter_ctx->new_db,
alter_ctx->new_alias))
{
if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
vtmd.revert_rename(thd, new_db_name);
revert_table_name:
(void) mysql_rename_table(old_db_type,
alter_ctx->new_db, alter_ctx->new_alias,
alter_ctx->db, alter_ctx->table_name,
NO_FK_CHECKS);
error= -1;
}
}
}
@ -8621,6 +8815,30 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
bool error= open_tables(thd, &table_list, &tables_opened, 0,
&alter_prelocking_strategy);
thd->open_options&= ~HA_OPEN_FOR_ALTER;
bool versioned= table_list->table && table_list->table->versioned();
bool vers_data_mod= versioned &&
thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE &&
alter_info->vers_data_modifying();
if (vers_data_mod)
{
table_list->set_lock_type(thd, TL_WRITE);
if (thd->mdl_context.upgrade_shared_lock(table_list->table->mdl_ticket,
MDL_EXCLUSIVE,
thd->variables.lock_wait_timeout))
{
DBUG_RETURN(true);
}
if (table_list->table->versioned_by_engine() &&
alter_info->requested_algorithm ==
Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT &&
!table_list->table->s->partition_info_str)
{
// Changle default ALGORITHM to COPY for INNODB
alter_info->requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY;
}
}
DEBUG_SYNC(thd, "alter_opened_table");
@ -8749,6 +8967,12 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
if (check_engine(thd, alter_ctx.new_db, alter_ctx.new_name, create_info))
DBUG_RETURN(true);
if (create_info->vers_info.check_and_fix_alter(thd, alter_info, create_info,
table->s))
{
DBUG_RETURN(true);
}
if ((create_info->db_type != table->s->db_type() ||
alter_info->flags & Alter_info::ALTER_PARTITION) &&
!table->file->can_switch_engines())
@ -8927,9 +9151,11 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
Upgrade from MDL_SHARED_UPGRADABLE to MDL_SHARED_NO_WRITE.
Afterwards it's safe to take the table level lock.
*/
if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE,
thd->variables.lock_wait_timeout)
|| lock_tables(thd, table_list, alter_ctx.tables_opened, 0))
if ((!vers_data_mod &&
thd->mdl_context.upgrade_shared_lock(
mdl_ticket, MDL_SHARED_NO_WRITE,
thd->variables.lock_wait_timeout)) ||
lock_tables(thd, table_list, alter_ctx.tables_opened, 0))
{
DBUG_RETURN(true);
}
@ -8991,6 +9217,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
handlerton *new_db_type= create_info->db_type;
handlerton *old_db_type= table->s->db_type();
TABLE *new_table= NULL;
bool new_versioned= false;
ha_rows copied=0,deleted=0;
/*
@ -9327,6 +9554,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
}
if (!new_table)
goto err_new_table_cleanup;
new_versioned= new_table->versioned();
/*
Note: In case of MERGE table, we do not attach children. We do not
copy data for MERGE tables. Only the children have data.
@ -9353,7 +9581,14 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
order_num, order, &copied, &deleted,
alter_info->keys_onoff,
&alter_ctx))
{
if (vers_data_mod && new_versioned && table->versioned_by_sql())
{
// Failure of this function may result in corruption of an original table.
vers_reset_alter_copy(thd, table);
}
goto err_new_table_cleanup;
}
}
else
{
@ -9448,9 +9683,14 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
Rename the old table to temporary name to have a backup in case
anything goes wrong while renaming the new table.
*/
char backup_name[32];
my_snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%lx", tmp_file_prefix,
current_pid, (long) thd->thread_id);
char backup_name[FN_LEN];
if (vers_data_mod)
VTMD_table::archive_name(thd, alter_ctx.table_name, backup_name,
sizeof(backup_name));
else
my_snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%lx",
tmp_file_prefix, current_pid, thd->thread_id);
if (lower_case_table_names)
my_casedn_str(files_charset_info, backup_name);
if (mysql_rename_table(old_db_type, alter_ctx.db, alter_ctx.table_name,
@ -9478,6 +9718,17 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
goto err_with_mdl;
}
if (vers_data_mod && new_versioned)
{
DBUG_ASSERT(alter_info && table_list);
VTMD_rename vtmd(*table_list);
bool rc= alter_info->flags & Alter_info::ALTER_RENAME ?
vtmd.try_rename(thd, alter_ctx.new_db, alter_ctx.new_alias, backup_name) :
vtmd.update(thd, backup_name);
if (rc)
goto err_after_rename;
}
// Check if we renamed the table and if so update trigger files.
if (alter_ctx.is_table_renamed())
{
@ -9488,6 +9739,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
alter_ctx.new_db,
alter_ctx.new_alias))
{
err_after_rename:
// Rename succeeded, delete the new table.
(void) quick_rm_table(thd, new_db_type,
alter_ctx.new_db, alter_ctx.new_alias, 0);
@ -9502,7 +9754,8 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
}
// ALTER TABLE succeeded, delete the backup of the old table.
if (quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, FN_IS_TMP))
if (!(vers_data_mod && new_versioned) &&
quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, FN_IS_TMP))
{
/*
The fact that deletion of the backup failed is not critical
@ -9689,6 +9942,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
sql_mode_t save_sql_mode= thd->variables.sql_mode;
ulonglong prev_insert_id, time_to_report_progress;
Field **dfield_ptr= to->default_field;
bool make_versioned= !from->versioned() && to->versioned();
bool make_unversioned= from->versioned() && !to->versioned();
bool keep_versioned= from->versioned() && to->versioned();
Field *to_sys_trx_start= NULL, *to_sys_trx_end= NULL, *from_sys_trx_end= NULL;
MYSQL_TIME query_start;
DBUG_ENTER("copy_data_between_tables");
/* Two or 3 stages; Sorting, copying data and update indexes */
@ -9789,6 +10047,30 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
thd_progress_next_stage(thd);
}
if (make_versioned)
{
query_start= thd->query_start_TIME();
to_sys_trx_start= to->vers_start_field();
to_sys_trx_end= to->vers_end_field();
}
else if (make_unversioned)
{
from_sys_trx_end= from->vers_end_field();
}
else if (keep_versioned)
{
to->file->vers_auto_decrement= 0xffffffffffffffff;
if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
{
query_start= thd->query_start_TIME();
from_sys_trx_end= from->vers_end_field();
to_sys_trx_start= to->vers_start_field();
} else if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP)
{
from_sys_trx_end= from->vers_end_field();
}
}
THD_STAGE_INFO(thd, stage_copy_to_tmp_table);
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns();
@ -9842,6 +10124,36 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
{
copy_ptr->do_copy(copy_ptr);
}
if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP &&
from_sys_trx_end && !from_sys_trx_end->is_max())
{
continue;
}
if (make_versioned)
{
to_sys_trx_start->set_notnull();
to_sys_trx_start->store_time(&query_start);
to_sys_trx_end->set_max();
}
else if (make_unversioned)
{
if (!from_sys_trx_end->is_max())
continue; // Drop history rows.
}
else if (keep_versioned &&
thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
{
if (!from_sys_trx_end->is_max())
continue; // Do not copy history rows.
store_record(from, record[1]);
from->vers_end_field()->store_time(&query_start);
from->file->ha_update_row(from->record[1], from->record[0]);
to_sys_trx_start->store_time(&query_start);
}
prev_insert_id= to->file->next_insert_id;
if (to->default_field)
to->update_default_fields(0, ignore);
@ -9856,7 +10168,17 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
error= 1;
break;
}
error=to->file->ha_write_row(to->record[0]);
if (keep_versioned && to->versioned_by_engine() &&
thd->variables.vers_alter_history != VERS_ALTER_HISTORY_SURVIVE)
{
to->s->versioned= false;
}
error= to->file->ha_write_row(to->record[0]);
if (keep_versioned && to->versioned_by_engine() &&
thd->variables.vers_alter_history != VERS_ALTER_HISTORY_SURVIVE)
{
to->s->versioned= true;
}
to->auto_increment_field_not_null= FALSE;
if (error)
{