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

MDEV-16973 Application-time periods: DELETE

* inject portion of time updates into mysql_delete main loop
* triggered case emits delete+insert, no updates
* PORTION OF `SYSTEM_TIME` is forbidden
* `DELETE HISTORY .. FOR PORTION OF ...` is forbidden as well
This commit is contained in:
Nikita Malyavin
2019-02-04 09:37:58 +10:00
committed by Sergei Golubchik
parent 073c93b194
commit 47e28a94d5
15 changed files with 1048 additions and 128 deletions

View File

@ -758,26 +758,163 @@ void vers_select_conds_t::print(String *str, enum_query_type query_type) const
}
}
int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
static
Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select,
vers_select_conds_t *conds, bool timestamp)
{
DBUG_ENTER("SELECT_LEX::vers_setup_cond");
DBUG_ASSERT(table);
DBUG_ASSERT(table->table);
#define newx new (thd->mem_root)
TABLE_SHARE *share= table->table->s;
const TABLE_SHARE::period_info_t *period= conds->period;
TABLE_LIST *table;
const LEX_CSTRING &fstart= period->start_field(share)->field_name;
const LEX_CSTRING &fend= period->end_field(share)->field_name;
if (!thd->stmt_arena->is_conventional() &&
!thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
conds->field_start= newx Item_field(thd, &select->context,
table->db.str, table->alias.str,
thd->make_clex_string(fstart));
conds->field_end= newx Item_field(thd, &select->context,
table->db.str, table->alias.str,
thd->make_clex_string(fend));
Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL;
if (timestamp)
{
// statement is already prepared
DBUG_RETURN(0);
MYSQL_TIME max_time;
switch (conds->type)
{
case SYSTEM_TIME_UNSPECIFIED:
thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE);
max_time.second_part= TIME_MAX_SECOND_PART;
curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS);
cond1= newx Item_func_eq(thd, conds->field_end, curr);
break;
case SYSTEM_TIME_AS_OF:
cond1= newx Item_func_le(thd, conds->field_start, conds->start.item);
cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item);
break;
case SYSTEM_TIME_FROM_TO:
cond1= newx Item_func_lt(thd, conds->field_start, conds->end.item);
cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item);
cond3= newx Item_func_lt(thd, conds->start.item, conds->end.item);
break;
case SYSTEM_TIME_BETWEEN:
cond1= newx Item_func_le(thd, conds->field_start, conds->end.item);
cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item);
cond3= newx Item_func_le(thd, conds->start.item, conds->end.item);
break;
case SYSTEM_TIME_BEFORE:
cond1= newx Item_func_lt(thd, conds->field_end, conds->start.item);
break;
default:
DBUG_ASSERT(0);
}
}
else
{
DBUG_ASSERT(table->table->s && table->table->s->db_plugin);
Item *trx_id0= conds->start.item;
Item *trx_id1= conds->end.item;
if (conds->start.item && conds->start.unit == VERS_TIMESTAMP)
{
bool backwards= conds->type != SYSTEM_TIME_AS_OF;
trx_id0= newx Item_func_trt_id(thd, conds->start.item,
TR_table::FLD_TRX_ID, backwards);
}
if (conds->end.item && conds->end.unit == VERS_TIMESTAMP)
{
trx_id1= newx Item_func_trt_id(thd, conds->end.item,
TR_table::FLD_TRX_ID, false);
}
switch (conds->type)
{
case SYSTEM_TIME_UNSPECIFIED:
curr= newx Item_int(thd, ULONGLONG_MAX);
cond1= newx Item_func_eq(thd, conds->field_end, curr);
DBUG_ASSERT(!conds->start.item);
DBUG_ASSERT(!conds->end.item);
break;
case SYSTEM_TIME_AS_OF:
cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id0, conds->field_start);
cond2= newx Item_func_trt_trx_sees(thd, conds->field_end, trx_id0);
DBUG_ASSERT(!conds->end.item);
break;
case SYSTEM_TIME_FROM_TO:
cond1= newx Item_func_trt_trx_sees(thd, trx_id1, conds->field_start);
cond2= newx Item_func_trt_trx_sees_eq(thd, conds->field_end, trx_id0);
cond3= newx Item_func_lt(thd, conds->start.item, conds->end.item);
break;
case SYSTEM_TIME_BETWEEN:
cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id1, conds->field_start);
cond2= newx Item_func_trt_trx_sees_eq(thd, conds->field_end, trx_id0);
cond3= newx Item_func_le(thd, conds->start.item, conds->end.item);
break;
case SYSTEM_TIME_BEFORE:
cond1= newx Item_func_trt_trx_sees(thd, trx_id0, conds->field_end);
break;
default:
DBUG_ASSERT(0);
}
}
if (thd->lex->is_view_context_analysis())
if (cond1)
{
cond1= and_items(thd, cond2, cond1);
cond1= and_items(thd, cond3, cond1);
}
return cond1;
#undef newx
}
static
bool skip_setup_conds(THD *thd)
{
return (!thd->stmt_arena->is_conventional()
&& !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
|| thd->lex->is_view_context_analysis();
}
Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where)
{
DBUG_ENTER("SELECT_LEX::period_setup_conds");
if (skip_setup_conds(thd))
DBUG_RETURN(NULL);
DBUG_ASSERT(!tables->next_local && tables->table);
Item *result= NULL;
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
if (!table->table)
continue;
vers_select_conds_t &conds= table->period_conditions;
if (!table->table->s->period.name.streq(conds.name))
{
my_error(ER_PERIOD_NOT_FOUND, MYF(0), conds.name.str);
DBUG_RETURN(NULL);
}
conds.period= &table->table->s->period;
result= and_items(thd, result,
period_get_condition(thd, table, this, &conds, true));
}
DBUG_RETURN(and_items(thd, where, result));
}
int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("SELECT_LEX::vers_setup_conds");
if (skip_setup_conds(thd))
DBUG_RETURN(0);
if (!versioned_tables)
{
for (table= tables; table; table= table->next_local)
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
if (table->table && table->table->versioned())
versioned_tables++;
@ -817,7 +954,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
}
}
for (table= tables; table; table= table->next_local)
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
if (!table->table || !table->table->versioned())
continue;
@ -863,16 +1000,6 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
lock_type= TL_READ; // ignore TL_WRITE, history is immutable anyway
}
const LEX_CSTRING *fstart=
thd->make_clex_string(table->table->vers_start_field()->field_name);
const LEX_CSTRING *fend=
thd->make_clex_string(table->table->vers_end_field()->field_name);
Item *row_start=
newx Item_field(thd, &this->context, table->db.str, table->alias.str, fstart);
Item *row_end=
newx Item_field(thd, &this->context, table->db.str, table->alias.str, fend);
bool timestamps_only= table->table->versioned(VERS_TIMESTAMP);
if (vers_conditions.is_set())
@ -892,101 +1019,16 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
}
}
Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL;
Item *point_in_time1= vers_conditions.start.item;
Item *point_in_time2= vers_conditions.end.item;
TABLE *t= table->table;
if (t->versioned(VERS_TIMESTAMP))
{
MYSQL_TIME max_time;
switch (vers_conditions.type)
{
case SYSTEM_TIME_UNSPECIFIED:
thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE);
max_time.second_part= TIME_MAX_SECOND_PART;
curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS);
cond1= newx Item_func_eq(thd, row_end, curr);
break;
case SYSTEM_TIME_AS_OF:
cond1= newx Item_func_le(thd, row_start, point_in_time1);
cond2= newx Item_func_gt(thd, row_end, point_in_time1);
break;
case SYSTEM_TIME_FROM_TO:
cond1= newx Item_func_lt(thd, row_start, point_in_time2);
cond2= newx Item_func_gt(thd, row_end, point_in_time1);
cond3= newx Item_func_lt(thd, point_in_time1, point_in_time2);
break;
case SYSTEM_TIME_BETWEEN:
cond1= newx Item_func_le(thd, row_start, point_in_time2);
cond2= newx Item_func_gt(thd, row_end, point_in_time1);
cond3= newx Item_func_le(thd, point_in_time1, point_in_time2);
break;
case SYSTEM_TIME_BEFORE:
cond1= newx Item_func_lt(thd, row_end, point_in_time1);
break;
default:
DBUG_ASSERT(0);
}
}
else
{
DBUG_ASSERT(table->table->s && table->table->s->db_plugin);
Item *trx_id0, *trx_id1;
switch (vers_conditions.type)
{
case SYSTEM_TIME_UNSPECIFIED:
curr= newx Item_int(thd, ULONGLONG_MAX);
cond1= newx Item_func_eq(thd, row_end, curr);
break;
case SYSTEM_TIME_AS_OF:
trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP
? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID)
: point_in_time1;
cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id0, row_start);
cond2= newx Item_func_trt_trx_sees(thd, row_end, trx_id0);
break;
case SYSTEM_TIME_FROM_TO:
cond3= newx Item_func_lt(thd, point_in_time1, point_in_time2);
/* fall through */
case SYSTEM_TIME_BETWEEN:
trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP
? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true)
: point_in_time1;
trx_id1= vers_conditions.end.unit == VERS_TIMESTAMP
? newx Item_func_trt_id(thd, point_in_time2, TR_table::FLD_TRX_ID, false)
: point_in_time2;
cond1= vers_conditions.type == SYSTEM_TIME_FROM_TO
? newx Item_func_trt_trx_sees(thd, trx_id1, row_start)
: newx Item_func_trt_trx_sees_eq(thd, trx_id1, row_start);
cond2= newx Item_func_trt_trx_sees_eq(thd, row_end, trx_id0);
if (!cond3)
cond3= newx Item_func_le(thd, point_in_time1, point_in_time2);
break;
case SYSTEM_TIME_BEFORE:
trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP
? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true)
: point_in_time1;
cond1= newx Item_func_trt_trx_sees(thd, trx_id0, row_end);
break;
default:
DBUG_ASSERT(0);
}
}
if (cond1)
{
cond1= and_items(thd, cond2, cond1);
cond1= and_items(thd, cond3, cond1);
table->on_expr= and_items(thd, table->on_expr, cond1);
}
vers_conditions.period = &table->table->s->vers;
Item *cond= period_get_condition(thd, table, this, &vers_conditions,
timestamps_only);
if (cond)
table->on_expr= and_items(thd, table->on_expr, cond);
table->vers_conditions.type= SYSTEM_TIME_ALL;
} // for (table= tables; ...)
DBUG_RETURN(0);
#undef newx
}
/*****************************************************************************