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

@ -67,6 +67,7 @@
#include "opt_range.h" // store_key_image_to_rec
#include "sql_alter.h" // Alter_table_ctx
#include "sql_select.h"
#include "sql_tablespace.h" // check_tablespace_name
#include <algorithm>
using std::max;
@ -87,6 +88,7 @@ static int get_partition_id_list_col(partition_info *, uint32 *, longlong *);
static int get_partition_id_list(partition_info *, uint32 *, longlong *);
static int get_partition_id_range_col(partition_info *, uint32 *, longlong *);
static int get_partition_id_range(partition_info *, uint32 *, longlong *);
static int vers_get_partition_id(partition_info *, uint32 *, longlong *);
static int get_part_id_charset_func_part(partition_info *, uint32 *, longlong *);
static int get_part_id_charset_func_subpart(partition_info *, uint32 *);
static int get_partition_id_hash_nosub(partition_info *, uint32 *, longlong *);
@ -1295,6 +1297,24 @@ static void set_up_partition_func_pointers(partition_info *part_info)
part_info->get_subpartition_id= get_partition_id_hash_sub;
}
}
else if (part_info->part_type == VERSIONING_PARTITION)
{
part_info->get_part_partition_id= vers_get_partition_id;
if (part_info->list_of_subpart_fields)
{
if (part_info->linear_hash_ind)
part_info->get_subpartition_id= get_partition_id_linear_key_sub;
else
part_info->get_subpartition_id= get_partition_id_key_sub;
}
else
{
if (part_info->linear_hash_ind)
part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
else
part_info->get_subpartition_id= get_partition_id_hash_sub;
}
}
else /* LIST Partitioning */
{
if (part_info->column_list)
@ -1335,6 +1355,10 @@ static void set_up_partition_func_pointers(partition_info *part_info)
else
part_info->get_partition_id= get_partition_id_list;
}
else if (part_info->part_type == VERSIONING_PARTITION)
{
part_info->get_partition_id= vers_get_partition_id;
}
else /* HASH partitioning */
{
if (part_info->list_of_part_fields)
@ -1607,6 +1631,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
}
}
DBUG_ASSERT(part_info->part_type != NOT_A_PARTITION);
DBUG_ASSERT(part_info->part_type != VERSIONING_PARTITION || part_info->column_list);
/*
Partition is defined. We need to verify that partitioning
function is correct.
@ -1639,6 +1664,9 @@ bool fix_partition_func(THD *thd, TABLE *table,
const char *error_str;
if (part_info->column_list)
{
if (part_info->part_type == VERSIONING_PARTITION &&
part_info->vers_setup_expression(thd))
goto end;
List_iterator<const char> it(part_info->part_field_list);
if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE)))
goto end;
@ -1662,6 +1690,12 @@ bool fix_partition_func(THD *thd, TABLE *table,
if (unlikely(part_info->check_list_constants(thd)))
goto end;
}
else if (part_info->part_type == VERSIONING_PARTITION)
{
error_str= "SYSTEM_TIME";
if (unlikely(part_info->check_range_constants(thd)))
goto end;
}
else
{
DBUG_ASSERT(0);
@ -2182,6 +2216,20 @@ static int add_partition_values(String *str, partition_info *part_info,
} while (++i < num_items);
err+= str->append(')');
}
else if (part_info->part_type == VERSIONING_PARTITION)
{
switch (p_elem->type())
{
case partition_element::AS_OF_NOW:
err+= str->append(STRING_WITH_LEN(" AS OF NOW"));
break;
case partition_element::VERSIONING:
err+= str->append(STRING_WITH_LEN(" VERSIONING"));
break;
default:
DBUG_ASSERT(0 && "wrong p_elem->type");
}
}
end:
return err;
}
@ -2275,13 +2323,32 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
else
err+= str.append(STRING_WITH_LEN("HASH "));
break;
case VERSIONING_PARTITION:
err+= str.append(STRING_WITH_LEN("SYSTEM_TIME"));
break;
default:
DBUG_ASSERT(0);
/* We really shouldn't get here, no use in continuing from here */
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
DBUG_RETURN(NULL);
}
if (part_info->part_expr)
if (part_info->part_type == VERSIONING_PARTITION)
{
Vers_part_info *vers_info= part_info->vers_info;
DBUG_ASSERT(vers_info);
if (vers_info->interval)
{
err+= str.append(STRING_WITH_LEN("INTERVAL "));
err+= str.append_ulonglong(vers_info->interval);
err+= str.append(STRING_WITH_LEN(" SECOND "));
}
if (vers_info->limit)
{
err+= str.append(STRING_WITH_LEN("LIMIT "));
err+= str.append_ulonglong(vers_info->limit);
}
}
else if (part_info->part_expr)
{
err+= str.append('(');
part_info->part_expr->print_for_table_def(&str);
@ -3088,6 +3155,83 @@ int get_partition_id_range_col(partition_info *part_info,
}
int vers_get_partition_id(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
DBUG_ENTER("vers_get_partition_id");
DBUG_ASSERT(part_info);
Field *sys_trx_end= part_info->part_field_array[STAT_TRX_END];
DBUG_ASSERT(sys_trx_end);
TABLE *table= part_info->table;
DBUG_ASSERT(table);
Vers_part_info *vers_info= part_info->vers_info;
DBUG_ASSERT(vers_info);
DBUG_ASSERT(vers_info->initialized());
DBUG_ASSERT(sys_trx_end->table == table);
bool tmp_off= false;
if (!table->versioned() && table->file->native_versioned())
{
// in copy_data_between_tables() versioning may be temporarily turned off
tmp_off= true;
table->s->versioned= true;
}
DBUG_ASSERT(table->versioned());
DBUG_ASSERT(table->vers_end_field() == sys_trx_end);
// new rows have NULL in sys_trx_end
if (sys_trx_end->is_max() || sys_trx_end->is_null())
{
*part_id= vers_info->now_part->id;
}
else // row is historical
{
THD *thd= current_thd;
switch (thd->lex->sql_command)
{
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
case SQLCOM_ALTER_TABLE:
mysql_mutex_lock(&table->s->LOCK_rotation);
if (table->s->busy_rotation)
{
table->s->vers_wait_rotation();
part_info->vers_hist_part();
}
else
{
table->s->busy_rotation= true;
mysql_mutex_unlock(&table->s->LOCK_rotation);
// transaction is not yet pushed to VTQ, so we use now-time
my_time_t end_ts= sys_trx_end->table->versioned_by_engine() ?
my_time(0) : sys_trx_end->get_timestamp();
if (part_info->vers_limit_exceed() || part_info->vers_interval_exceed(end_ts))
{
part_info->vers_part_rotate(thd);
}
mysql_mutex_lock(&table->s->LOCK_rotation);
mysql_cond_broadcast(&table->s->COND_rotation);
table->s->busy_rotation= false;
}
mysql_mutex_unlock(&table->s->LOCK_rotation);
break;
default:
;
}
*part_id= vers_info->hist_part->id;
}
if (tmp_off)
table->s->versioned= false;
DBUG_PRINT("exit",("partition: %d", *part_id));
DBUG_RETURN(0);
}
int get_partition_id_range(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
@ -4654,7 +4798,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
must know the number of new partitions in this case.
*/
if (thd->lex->no_write_to_binlog &&
tab_part_info->part_type != HASH_PARTITION)
tab_part_info->part_type != HASH_PARTITION &&
tab_part_info->part_type != VERSIONING_PARTITION)
{
my_error(ER_NO_BINLOG_ERROR, MYF(0));
goto err;
@ -4859,6 +5004,21 @@ that are reorganised.
partition configuration is made.
*/
{
partition_element *now_part= NULL;
if (tab_part_info->part_type == VERSIONING_PARTITION)
{
List_iterator<partition_element> it(tab_part_info->partitions);
partition_element *el;
while ((el= it++))
{
if (el->type() == partition_element::AS_OF_NOW)
{
DBUG_ASSERT(tab_part_info->vers_info && el == tab_part_info->vers_info->now_part);
it.remove();
now_part= el;
}
}
}
List_iterator<partition_element> alt_it(alt_part_info->partitions);
uint part_count= 0;
do
@ -4873,6 +5033,15 @@ that are reorganised.
}
} while (++part_count < num_new_partitions);
tab_part_info->num_parts+= num_new_partitions;
if (tab_part_info->part_type == VERSIONING_PARTITION)
{
DBUG_ASSERT(now_part);
if (tab_part_info->partitions.push_back(now_part, thd->mem_root))
{
mem_alloc_error(1);
goto err;
}
}
}
/*
If we specify partitions explicitly we don't use defaults anymore.
@ -4906,16 +5075,28 @@ that are reorganised.
List_iterator<partition_element> part_it(tab_part_info->partitions);
tab_part_info->is_auto_partitioned= FALSE;
if (!(tab_part_info->part_type == RANGE_PARTITION ||
tab_part_info->part_type == LIST_PARTITION))
if (tab_part_info->part_type == VERSIONING_PARTITION)
{
my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
goto err;
if (num_parts_dropped >= tab_part_info->num_parts - 1)
{
DBUG_ASSERT(table && table->s && table->s->table_name.str);
my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str);
goto err;
}
}
if (num_parts_dropped >= tab_part_info->num_parts)
else
{
my_error(ER_DROP_LAST_PARTITION, MYF(0));
goto err;
if (!(tab_part_info->part_type == RANGE_PARTITION ||
tab_part_info->part_type == LIST_PARTITION))
{
my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
goto err;
}
if (num_parts_dropped >= tab_part_info->num_parts)
{
my_error(ER_DROP_LAST_PARTITION, MYF(0));
goto err;
}
}
do
{
@ -4923,6 +5104,12 @@ that are reorganised.
if (is_name_in_list(part_elem->partition_name,
alter_info->partition_names))
{
if (part_elem->type() == partition_element::AS_OF_NOW)
{
DBUG_ASSERT(table && table->s && table->s->table_name.str);
my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str);
goto err;
}
/*
Set state to indicate that the partition is to be dropped.
*/
@ -5245,6 +5432,12 @@ the generated partition syntax in a correct manner.
tab_part_info->use_default_subpartitions= FALSE;
tab_part_info->use_default_num_subpartitions= FALSE;
}
if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION &&
tab_part_info->part_type == VERSIONING_PARTITION &&
tab_part_info->vers_setup_expression(thd, alt_part_info->partitions.elements))
goto err;
if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
table->file, 0, TRUE))
{
@ -6916,6 +7109,39 @@ err:
}
#endif
/*
Prepare for calling val_int on partition function by setting fields to
point to the record where the values of the PF-fields are stored.
SYNOPSIS
set_field_ptr()
ptr Array of fields to change ptr
new_buf New record pointer
old_buf Old record pointer
DESCRIPTION
Set ptr in field objects of field array to refer to new_buf record
instead of previously old_buf. Used before calling val_int and after
it is used to restore pointers to table->record[0].
This routine is placed outside of partition code since it can be useful
also for other programs.
*/
void set_field_ptr(Field **ptr, const uchar *new_buf,
const uchar *old_buf)
{
my_ptrdiff_t diff= (new_buf - old_buf);
DBUG_ENTER("set_field_ptr");
do
{
(*ptr)->move_field_offset(diff);
} while (*(++ptr));
DBUG_VOID_RETURN;
}
/*
Prepare for calling val_int on partition function by setting fields to
point to the record where the values of the PF-fields are stored.
@ -6954,6 +7180,61 @@ void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
}
/**
Append all fields in read_set to string
@param[in,out] str String to append to.
@param[in] row Row to append.
@param[in] table Table containing read_set and fields for the row.
*/
void append_row_to_str(String &str, const uchar *row, TABLE *table)
{
Field **fields, **field_ptr;
const uchar *rec;
uint num_fields= bitmap_bits_set(table->read_set);
uint curr_field_index= 0;
bool is_rec0= !row || row == table->record[0];
if (!row)
rec= table->record[0];
else
rec= row;
/* Create a new array of all read fields. */
fields= (Field**) my_malloc(sizeof(void*) * (num_fields + 1),
MYF(0));
if (!fields)
return;
fields[num_fields]= NULL;
for (field_ptr= table->field;
*field_ptr;
field_ptr++)
{
if (!bitmap_is_set(table->read_set, (*field_ptr)->field_index))
continue;
fields[curr_field_index++]= *field_ptr;
}
if (!is_rec0)
set_field_ptr(fields, rec, table->record[0]);
for (field_ptr= fields;
*field_ptr;
field_ptr++)
{
Field *field= *field_ptr;
str.append(" ");
str.append(field->field_name);
str.append(":");
field_unpack(&str, field, rec, 0, false);
}
if (!is_rec0)
set_field_ptr(fields, table->record[0], rec);
my_free(fields);
}
/*
SYNOPSIS
mem_alloc_error()
@ -7100,6 +7381,7 @@ static void set_up_range_analysis_info(partition_info *part_info)
switch (part_info->part_type) {
case RANGE_PARTITION:
case LIST_PARTITION:
case VERSIONING_PARTITION:
if (!part_info->column_list)
{
if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
@ -7400,7 +7682,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
uint full_length= 0;
DBUG_ENTER("get_part_iter_for_interval_cols_via_map");
if (part_info->part_type == RANGE_PARTITION)
if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION)
{
get_col_endpoint= get_partition_id_cols_range_for_endpoint;
part_iter->get_next= get_next_partition_id_range;
@ -7446,7 +7728,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
}
if (flags & NO_MAX_RANGE)
{
if (part_info->part_type == RANGE_PARTITION)
if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION)
part_iter->part_nums.end= part_info->num_parts;
else /* LIST_PARTITION */
{
@ -8143,4 +8425,52 @@ uint get_partition_field_store_length(Field *field)
store_length+= HA_KEY_BLOB_LENGTH;
return store_length;
}
// FIXME: duplicate of ha_partition::set_up_table_before_create
bool set_up_table_before_create(THD *thd,
TABLE_SHARE *share,
const char *partition_name_with_path,
HA_CREATE_INFO *info,
partition_element *part_elem)
{
bool error= false;
const char *partition_name;
DBUG_ENTER("set_up_table_before_create");
DBUG_ASSERT(part_elem);
if (!part_elem)
DBUG_RETURN(true);
share->max_rows= part_elem->part_max_rows;
share->min_rows= part_elem->part_min_rows;
partition_name= strrchr(partition_name_with_path, FN_LIBCHAR);
if ((part_elem->index_file_name &&
(error= append_file_to_dir(thd,
const_cast<const char**>(&part_elem->index_file_name),
partition_name+1))) ||
(part_elem->data_file_name &&
(error= append_file_to_dir(thd,
const_cast<const char**>(&part_elem->data_file_name),
partition_name+1))))
{
DBUG_RETURN(error);
}
if (part_elem->index_file_name != NULL)
{
info->index_file_name= part_elem->index_file_name;
}
if (part_elem->data_file_name != NULL)
{
info->data_file_name= part_elem->data_file_name;
}
if (part_elem->tablespace_name != NULL)
{
if (check_tablespace_name(part_elem->tablespace_name) != IDENT_NAME_OK)
{
DBUG_RETURN(true);
}
info->tablespace= part_elem->tablespace_name;
}
DBUG_RETURN(error);
}
#endif