diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 193 |
1 files changed, 131 insertions, 62 deletions
diff --git a/sql/table.cc b/sql/table.cc index 93684cb5221..c38fe249741 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2016, MariaDB +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. + Copyright (c) 2008, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -677,7 +677,7 @@ err: mysql_file_close(file, MYF(MY_WME)); err_not_open: - if (share->error && !error_given) + if (unlikely(share->error && !error_given)) { share->open_errno= my_errno; open_table_error(share, share->error, share->open_errno); @@ -1856,6 +1856,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, vers_can_native= plugin_hton(se_plugin)->flags & HTON_NATIVE_SYS_VERSIONING; row_start_field= row_start; row_end_field= row_end; + status_var_increment(thd->status_var.feature_system_versioning); } // if (system_period == NULL) for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) @@ -2804,8 +2805,8 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, thd->reset_db(&db); lex_start(thd); - if ((error= parse_sql(thd, & parser_state, NULL) || - sql_unusable_for_discovery(thd, hton, sql_copy))) + if (unlikely((error= parse_sql(thd, & parser_state, NULL) || + sql_unusable_for_discovery(thd, hton, sql_copy)))) goto ret; thd->lex->create_info.db_type= hton; @@ -2837,7 +2838,7 @@ ret: reenable_binlog(thd); thd->variables.sql_mode= saved_mode; thd->variables.character_set_client= old_cs; - if (thd->is_error() || error) + if (unlikely(thd->is_error() || error)) { thd->clear_error(); my_error(ER_SQL_DISCOVER_ERROR, MYF(0), @@ -2997,14 +2998,14 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, res.errors= 0; int error= func_expr->walk(&Item::check_vcol_func_processor, 0, &res); - if (error || (res.errors & VCOL_IMPOSSIBLE)) + if (unlikely(error || (res.errors & VCOL_IMPOSSIBLE))) { // this can only happen if the frm was corrupted my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), res.name, vcol->get_vcol_type_name(), vcol->name.str); DBUG_RETURN(1); } - else if (res.errors & VCOL_AUTO_INC) + else if (unlikely(res.errors & VCOL_AUTO_INC)) { /* An auto_increment field may not be used in an expression for @@ -3085,7 +3086,7 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table, lex.last_field= &vcol_storage; error= parse_sql(thd, &parser_state, NULL); - if (error) + if (unlikely(error)) goto end; if (lex.current_select->table_list.first[0].next_global) @@ -3354,7 +3355,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, if (share->table_check_constraints || share->field_check_constraints) outparam->check_constraints= check_constraint_ptr; - if (parse_vcol_defs(thd, &outparam->mem_root, outparam, &error_reported)) + if (unlikely(parse_vcol_defs(thd, &outparam->mem_root, outparam, + &error_reported))) { error= OPEN_FRM_CORRUPTED; goto err; @@ -3506,7 +3508,8 @@ partititon_err: /* Set a flag if the table is crashed and it can be auto. repaired */ share->crashed= (outparam->file->auto_repair(ha_err) && !(ha_open_flags & HA_OPEN_FOR_REPAIR)); - outparam->file->print_error(ha_err, MYF(0)); + if (!thd->is_error()) + outparam->file->print_error(ha_err, MYF(0)); error_reported= TRUE; if (ha_err == HA_ERR_TABLE_DEF_CHANGED) @@ -3579,7 +3582,7 @@ partititon_err: table TABLE object to free */ -int closefrm(register TABLE *table) +int closefrm(TABLE *table) { int error=0; DBUG_ENTER("closefrm"); @@ -3616,7 +3619,7 @@ int closefrm(register TABLE *table) /* Deallocate temporary blob storage */ -void free_blobs(register TABLE *table) +void free_blobs(TABLE *table) { uint *ptr, *end; for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ; @@ -3810,17 +3813,6 @@ void append_unescaped(String *res, const char *pos, size_t length) for (; pos != end ; pos++) { -#if defined(USE_MB) && MYSQL_VERSION_ID < 40100 - uint mblen; - if (use_mb(default_charset_info) && - (mblen= my_ismbchar(default_charset_info, pos, end))) - { - res->append(pos, mblen); - pos+= mblen; - continue; - } -#endif - switch (*pos) { case 0: /* Must be escaped for 'mysql' */ res->append('\\'); @@ -4235,7 +4227,7 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) /* Whether the table definition has already been validated. */ if (table->s->table_field_def_cache == table_def) - DBUG_RETURN(FALSE); + goto end; if (table->s->fields != table_def->count) { @@ -4268,6 +4260,8 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) is backward compatible. */ } + else + { StringBuffer<1024> sql_type(system_charset_info); sql_type.extra_allocation(256); // Allocate min 256 characters at once for (i=0 ; i < table_def->count; i++, field_def++) @@ -4353,6 +4347,7 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) error= TRUE; } } + } if (table_def->primary_key_parts) { @@ -4394,9 +4389,19 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) } } - if (! error) + if (likely(! error)) table->s->table_field_def_cache= table_def; +end: + + if (has_keys && !error && !table->key_info) + { + report_error(0, "Incorrect definition of table %s.%s: " + "indexes are missing", + table->s->db.str, table->alias.c_ptr()); + error= TRUE; + } + DBUG_RETURN(error); } @@ -5258,14 +5263,25 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) int TABLE::verify_constraints(bool ignore_failure) { + /* + We have to check is_error() first as we are checking it for each + constraint to catch fatal warnings. + */ + if (in_use->is_error()) + return (VIEW_CHECK_ERROR); + /* go trough check option clauses for fields and table */ if (check_constraints && !(in_use->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS)) { for (Virtual_column_info **chk= check_constraints ; *chk ; chk++) { - /* yes! NULL is ok, see 4.23.3.4 Table check constraints, part 2, SQL:2016 */ - if ((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value) + /* + yes! NULL is ok. + see 4.23.3.4 Table check constraints, part 2, SQL:2016 + */ + if (((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value) || + in_use->is_error()) { my_error(ER_CONSTRAINT_FAILED, MYF(ignore_failure ? ME_JUST_WARNING : 0), (*chk)->name.str, @@ -5274,7 +5290,11 @@ int TABLE::verify_constraints(bool ignore_failure) } } } - return(VIEW_CHECK_OK); + /* + We have to check in_use() as checking constraints may have generated + warnings that should be treated as errors + */ + return(!in_use->is_error() ? VIEW_CHECK_OK : VIEW_CHECK_ERROR); } /* @@ -6780,7 +6800,7 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl) if (bitmap_is_set(write_set, tmp_vfield->field_index)) bitmap_updated= mark_virtual_col(tmp_vfield); else if (tmp_vfield->vcol_info->stored_in_db || - (tmp_vfield->flags & PART_KEY_FLAG)) + (tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG))) { if (insert_fl) { @@ -7789,8 +7809,8 @@ void TABLE::vers_update_fields() { if (!vers_write) return; - if (vers_start_field()->store_timestamp(in_use->systime(), - in_use->systime_sec_part())) + if (vers_start_field()->store_timestamp(in_use->query_start(), + in_use->query_start_sec_part())) DBUG_ASSERT(0); } else @@ -7805,8 +7825,8 @@ void TABLE::vers_update_fields() void TABLE::vers_update_end() { - if (vers_end_field()->store_timestamp(in_use->systime(), - in_use->systime_sec_part())) + if (vers_end_field()->store_timestamp(in_use->query_start(), + in_use->query_start_sec_part())) DBUG_ASSERT(0); } @@ -7957,7 +7977,7 @@ bool TABLE::insert_all_rows_into_tmp_table(THD *thd, tmp_table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL); file->ha_index_or_rnd_end(); - if (file->ha_rnd_init_with_error(1)) + if (unlikely(file->ha_rnd_init_with_error(1))) DBUG_RETURN(1); if (tmp_table->no_rows) @@ -7969,10 +7989,10 @@ bool TABLE::insert_all_rows_into_tmp_table(THD *thd, tmp_table->file->ha_start_bulk_insert(file->stats.records); } - while (!file->ha_rnd_next(tmp_table->record[0])) + while (likely(!file->ha_rnd_next(tmp_table->record[0]))) { write_err= tmp_table->file->ha_write_tmp_row(tmp_table->record[0]); - if (write_err) + if (unlikely(write_err)) { bool is_duplicate; if (tmp_table->file->is_fatal_error(write_err, HA_CHECK_DUP) && @@ -7983,7 +8003,7 @@ bool TABLE::insert_all_rows_into_tmp_table(THD *thd, DBUG_RETURN(1); } - if (thd->check_killed()) + if (unlikely(thd->check_killed())) { thd->send_kill_message(); goto err_killed; @@ -8154,7 +8174,21 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view) (first_table && first_table->is_multitable())) set_multitable(); - unit->derived= this; + if (!unit->derived) + unit->derived= this; + else if (!is_with_table_recursive_reference() && unit->derived != this) + { + if (unit->derived->is_with_table_recursive_reference()) + unit->derived= this; + else if (vers_conditions.eq(unit->derived->vers_conditions)) + vers_conditions.empty(); + else + { + my_error(ER_CONFLICTING_FOR_SYSTEM_TIME, MYF(0)); + return TRUE; + } + } + if (init_view && !view) { /* This is all what we can do for a derived table for now. */ @@ -8440,17 +8474,15 @@ bool TR_table::update(ulonglong start_id, ulonglong end_id) if (!table && open()) return true; - timeval start_time= {thd->systime(), long(thd->systime_sec_part())}; - thd->set_start_time(); - timeval end_time= {thd->systime(), long(thd->systime_sec_part())}; + store(FLD_BEGIN_TS, thd->transaction_time()); + timeval end_time= {thd->query_start(), long(thd->query_start_sec_part())}; store(FLD_TRX_ID, start_id); store(FLD_COMMIT_ID, end_id); - store(FLD_BEGIN_TS, start_time); store(FLD_COMMIT_TS, end_time); store_iso_level(thd->tx_isolation); int error= table->file->ha_write_row(table->record[0]); - if (error) + if (unlikely(error)) table->file->print_error(error, MYF(0)); return error; } @@ -8469,10 +8501,10 @@ bool TR_table::query(ulonglong trx_id) Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]); Item *value= newx Item_int(thd, trx_id); COND *conds= newx Item_func_eq(thd, field, value); - if ((error= setup_conds(thd, this, dummy, &conds))) + if (unlikely((error= setup_conds(thd, this, dummy, &conds)))) return false; select= make_select(table, 0, 0, conds, NULL, 0, &error); - if (error || !select) + if (unlikely(error || !select)) return false; // FIXME: (performance) force index 'transaction_id' error= init_read_record(&info, thd, table, select, NULL, @@ -8503,11 +8535,11 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards) conds= newx Item_func_ge(thd, field, value); else conds= newx Item_func_le(thd, field, value); - if ((error= setup_conds(thd, this, dummy, &conds))) + if (unlikely((error= setup_conds(thd, this, dummy, &conds)))) return false; // FIXME: (performance) force index 'commit_timestamp' select= make_select(table, 0, 0, conds, NULL, 0, &error); - if (error || !select) + if (unlikely(error || !select)) return false; error= init_read_record(&info, thd, table, select, NULL, 1 /* use_record_cache */, true /* print_error */, @@ -8567,6 +8599,12 @@ bool TR_table::query_sees(bool &result, ulonglong trx_id1, ulonglong trx_id0, return false; } + if (trx_id0 == ULONGLONG_MAX || trx_id1 == 0) + { + result= false; + return false; + } + if (!commit_id1) { if (!query(trx_id1)) @@ -8702,28 +8740,53 @@ bool TR_table::check(bool error) return false; } -void vers_select_conds_t::resolve_units(bool timestamps_only) +bool vers_select_conds_t::resolve_units(THD *thd) { DBUG_ASSERT(type != SYSTEM_TIME_UNSPECIFIED); DBUG_ASSERT(start.item); - start.resolve_unit(timestamps_only); - end.resolve_unit(timestamps_only); + return start.resolve_unit(thd) || + end.resolve_unit(thd); } -void Vers_history_point::resolve_unit(bool timestamps_only) +bool vers_select_conds_t::eq(const vers_select_conds_t &conds) const { - if (item && unit == VERS_UNDEFINED) - { - if (item->type() == Item::FIELD_ITEM || timestamps_only) - unit= VERS_TIMESTAMP; - else if (item->result_type() == INT_RESULT || - item->result_type() == REAL_RESULT) - unit= VERS_TRX_ID; - else - unit= VERS_TIMESTAMP; + if (type != conds.type) + return false; + switch (type) { + case SYSTEM_TIME_UNSPECIFIED: + case SYSTEM_TIME_ALL: + return true; + case SYSTEM_TIME_BEFORE: + DBUG_ASSERT(0); + case SYSTEM_TIME_AS_OF: + return start.eq(conds.start); + case SYSTEM_TIME_FROM_TO: + case SYSTEM_TIME_BETWEEN: + return start.eq(conds.start) && end.eq(conds.end); } + DBUG_ASSERT(0); + return false; } + +bool Vers_history_point::resolve_unit(THD *thd) +{ + if (!item) + return false; + if (!item->fixed && item->fix_fields(thd, &item)) + return true; + return item->this_item()->type_handler_for_system_time()-> + Vers_history_point_resolve_unit(thd, this); +} + + +void Vers_history_point::bad_expression_data_type_error(const char *type) const +{ + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + type, "FOR SYSTEM_TIME"); +} + + void Vers_history_point::fix_item() { if (item && item->decimals == 0 && item->type() == Item::FUNC_ITEM && @@ -8731,8 +8794,14 @@ void Vers_history_point::fix_item() item->decimals= 6; } + +bool Vers_history_point::eq(const vers_history_point_t &point) const +{ + return unit == point.unit && item->eq(point.item, false); +} + void Vers_history_point::print(String *str, enum_query_type query_type, - const char *prefix, size_t plen) + const char *prefix, size_t plen) const { const static LEX_CSTRING unit_type[]= { |