diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 305 |
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. |