summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc305
1 files changed, 139 insertions, 166 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 6e2b10b907e..b1336681ac4 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -760,173 +760,39 @@ void vers_select_conds_t::print(String *str, enum_query_type query_type) const
}
}
-static
-Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select,
- vers_select_conds_t *conds, bool timestamp)
-{
- 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;
-
- const LEX_CSTRING &fstart= period->start_field(share)->field_name;
- const LEX_CSTRING &fend= period->end_field(share)->field_name;
-
- 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)
- {
- 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);
- }
- }
+/**
+ Setup System Versioning conditions
- if (cond1)
- {
- cond1= and_items(thd, cond2, cond1);
- cond1= and_items(thd, cond3, cond1);
- }
- return cond1;
-#undef newx
-}
+ Add WHERE condition according to FOR SYSTEM_TIME clause.
-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();
-}
+ If the table is partitioned by SYSTEM_TIME and there is no FOR SYSTEM_TIME
+ clause, then select now-partition instead of modifying WHERE condition.
-Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where)
+ @retval
+ -1 on error
+ @retval
+ 0 on success
+*/
+int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
{
- DBUG_ENTER("SELECT_LEX::period_setup_conds");
-
- if (skip_setup_conds(thd))
- DBUG_RETURN(where);
-
- Query_arena backup;
- Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup);
+ DBUG_ENTER("SELECT_LEX::vers_setup_cond");
+#define newx new (thd->mem_root)
- DBUG_ASSERT(!tables->next_local && tables->table);
+ TABLE_LIST *table;
- Item *result= NULL;
- for (TABLE_LIST *table= tables; table; table= table->next_local)
+ if (!thd->stmt_arena->is_conventional() &&
+ !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
{
- 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);
- if (arena)
- thd->restore_active_arena(arena, &backup);
- DBUG_RETURN(NULL);
- }
-
- conds.period= &table->table->s->period;
- result= and_items(thd, result,
- period_get_condition(thd, table, this, &conds, true));
+ // statement is already prepared
+ DBUG_RETURN(0);
}
- result= and_items(thd, where, result);
- if (arena)
- thd->restore_active_arena(arena, &backup);
-
- DBUG_RETURN(result);
-}
-
-int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
-{
- DBUG_ENTER("SELECT_LEX::vers_setup_conds");
-
- if (skip_setup_conds(thd))
+ if (thd->lex->is_view_context_analysis())
DBUG_RETURN(0);
if (!versioned_tables)
{
- for (TABLE_LIST *table= tables; table; table= table->next_local)
+ for (table= tables; table; table= table->next_local)
{
if (table->table && table->table->versioned())
versioned_tables++;
@@ -966,7 +832,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
}
}
- for (TABLE_LIST *table= tables; table; table= table->next_local)
+ for (table= tables; table; table= table->next_local)
{
if (!table->table || !table->table->versioned())
continue;
@@ -974,12 +840,13 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
vers_select_conds_t &vers_conditions= table->vers_conditions;
#ifdef WITH_PARTITION_STORAGE_ENGINE
- /*
- if the history is stored in partitions, then partitions
- themselves are not versioned
- */
- if (table->partition_names && table->table->part_info->vers_info)
+ Vers_part_info *vers_info;
+ if (table->table->part_info && (vers_info= table->table->part_info->vers_info))
+ {
+ if (table->partition_names)
{
+ /* If the history is stored in partitions, then partitions
+ themselves are not versioned. */
if (vers_conditions.is_set())
{
my_error(ER_VERS_QUERY_IN_PARTITION, MYF(0), table->alias.str);
@@ -988,6 +855,16 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
else
vers_conditions.init(SYSTEM_TIME_ALL);
}
+ else if (!vers_conditions.is_set())
+ {
+ table->partition_names= newx List<String>;
+ String *s= newx String(vers_info->now_part->partition_name,
+ system_charset_info);
+ table->partition_names->push_back(s);
+ table->table->file->change_partitions_to_open(table->partition_names);
+ vers_conditions.init(SYSTEM_TIME_ALL);
+ }
+ }
#endif
if (outer_table && !vers_conditions.is_set())
@@ -1012,6 +889,16 @@ 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())
@@ -1031,17 +918,103 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
}
}
- 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;
+ 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);
+ }
+
+ table->vers_conditions.type= SYSTEM_TIME_ALL;
} // for (table= tables; ...)
DBUG_RETURN(0);
+#undef newx
}
+#undef newx
/*****************************************************************************
Check fields, find best join, do the select and output fields.