diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2022-11-02 14:58:01 +0100 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2022-11-02 15:45:27 +0100 |
commit | 15de3aa2f5b0fb5404a00f1a3cd5c0291f0ef67d (patch) | |
tree | cfd49996c72f6bbe7117fd950ededb01abc76b76 /sql | |
parent | 6449af6f2d52c7acb483fcfb186c838edaf0424a (diff) | |
parent | e5aa58190fd8697b3858add4b8f86a5fd38e07f8 (diff) | |
download | mariadb-git-15de3aa2f5b0fb5404a00f1a3cd5c0291f0ef67d.tar.gz |
Merge branch '10.6' into 10.7
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 2 | ||||
-rw-r--r-- | sql/field.h | 6 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 42 | ||||
-rw-r--r-- | sql/log.cc | 54 | ||||
-rw-r--r-- | sql/mysqld.cc | 7 | ||||
-rw-r--r-- | sql/rowid_filter.h | 11 | ||||
-rw-r--r-- | sql/spatial.cc | 41 | ||||
-rw-r--r-- | sql/spatial.h | 2 | ||||
-rw-r--r-- | sql/sql_analyze_stmt.h | 7 | ||||
-rw-r--r-- | sql/sql_class.cc | 4 | ||||
-rw-r--r-- | sql/sql_explain.cc | 1 | ||||
-rw-r--r-- | sql/sql_insert.cc | 10 | ||||
-rw-r--r-- | sql/sql_plugin_services.inl | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 60 | ||||
-rw-r--r-- | sql/sql_table.cc | 12 |
15 files changed, 208 insertions, 56 deletions
diff --git a/sql/field.cc b/sql/field.cc index ca45aeb5278..5e4ac02819d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10877,8 +10877,6 @@ Column_definition::Column_definition(THD *thd, Field *old_field, type_handler()->Column_definition_reuse_fix_attributes(thd, this, old_field); - type_handler()->Column_definition_implicit_upgrade(this); - /* Copy the default (constant/function) from the column object orig_field, if supplied. We do this if all these conditions are met: diff --git a/sql/field.h b/sql/field.h index 73cd83f1836..059163da82d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -5697,6 +5697,12 @@ public: } /* Used to make a clone of this object for ALTER/CREATE TABLE */ Create_field *clone(MEM_ROOT *mem_root) const; + static void upgrade_data_types(List<Create_field> &list) + { + List_iterator<Create_field> it(list); + while (Create_field *f= it++) + f->type_handler()->Column_definition_implicit_upgrade(f); + } }; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 7a1115425d9..0010e86557d 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -2585,56 +2585,58 @@ double Item_func_sphere_distance::spherical_distance_points(Geometry *g1, double res= 0.0; // Length for the single point (25 Bytes) uint32 len= SRID_SIZE + POINT_DATA_SIZE + WKB_HEADER_SIZE; - int error= 0; + int err_hv= 0, err_sph= 0; switch (g2->get_class_info()->m_type_id) { case Geometry::wkb_point: - // Optimization for point-point case + { + Gis_point *g2p= static_cast<Gis_point *>(g2); + // Optimization for point-point case if (g1->get_class_info()->m_type_id == Geometry::wkb_point) { - res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error); + res= g2p->calculate_haversine(g1, r, &err_hv); } else { // Optimization for single point in Multipoint if (g1->get_data_size() == len) { - res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error); + res= g2p->calculate_haversine(g1, r, &err_hv); } else { // There are multipoints in g1 // g1 is MultiPoint and calculate MP.sphericaldistance from g2 Point if (g1->get_data_size() != GET_SIZE_ERROR) - static_cast<Gis_point *>(g2)->spherical_distance_multipoints( - (Gis_multi_point *)g1, r, &res, &error); + err_sph= g2p->spherical_distance_multipoints(g1, r, &res, &err_hv); } } break; + } case Geometry::wkb_multipoint: // Optimization for point-point case if (g1->get_class_info()->m_type_id == Geometry::wkb_point) { + Gis_point *g1p= static_cast<Gis_point *>(g1); // Optimization for single point in Multipoint g2 if (g2->get_data_size() == len) { - res= static_cast<Gis_point *>(g1)->calculate_haversine(g2, r, &error); + res= g1p->calculate_haversine(g2, r, &err_hv); } else { if (g2->get_data_size() != GET_SIZE_ERROR) // g1 is a point (casted to multi_point) and g2 multipoint - static_cast<Gis_point *>(g1)->spherical_distance_multipoints( - (Gis_multi_point *)g2, r, &res, &error); + err_sph= g1p->spherical_distance_multipoints(g2, r, &res, &err_hv); } } else { + Gis_multi_point *g1mp= static_cast<Gis_multi_point *>(g1); // Multipoints in g1 and g2 - no optimization - static_cast<Gis_multi_point *>(g1)->spherical_distance_multipoints( - (Gis_multi_point *)g2, r, &res, &error); + err_sph= g1mp->spherical_distance_multipoints(g2, r, &res, &err_hv); } break; @@ -2643,16 +2645,14 @@ double Item_func_sphere_distance::spherical_distance_points(Geometry *g1, break; } - if (res < 0) - goto handle_error; - - handle_error: - if (error > 0) - my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0), - "Longitude should be [-180,180]", "ST_Distance_Sphere"); - else if(error < 0) - my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0), - "Latitude should be [-90,90]", "ST_Distance_Sphere"); + if (err_hv == 1) + my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0), + "Longitude should be [-180,180]", "ST_Distance_Sphere"); + else if(err_hv < 0) + my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0), + "Latitude should be [-90,90]", "ST_Distance_Sphere"); + else if (err_sph || err_hv == 2) + my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0)); return res; } diff --git a/sql/log.cc b/sql/log.cc index f9fd684c620..282db568621 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1995,29 +1995,62 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) int binlog_commit_by_xid(handlerton *hton, XID *xid) { + int rc= 0; THD *thd= current_thd; if (thd->is_current_stmt_binlog_disabled()) return 0; + + /* the asserted state can't be reachable with xa commit */ + DBUG_ASSERT(!thd->get_stmt_da()->is_error() || + thd->get_stmt_da()->sql_errno() != ER_XA_RBROLLBACK); + /* + This is a recovered user xa transaction commit. + Create a "temporary" binlog transaction to write the commit record + into binlog. + */ + THD_TRANS trans; + trans.ha_list= NULL; + + thd->ha_data[hton->slot].ha_info[1].register_ha(&trans, hton); + thd->ha_data[binlog_hton->slot].ha_info[1].set_trx_read_write(); (void) thd->binlog_setup_trx_data(); DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT); - return binlog_commit(thd, TRUE, FALSE); + rc= binlog_commit(thd, TRUE, FALSE); + thd->ha_data[binlog_hton->slot].ha_info[1].reset(); + + return rc; } int binlog_rollback_by_xid(handlerton *hton, XID *xid) { + int rc= 0; THD *thd= current_thd; if (thd->is_current_stmt_binlog_disabled()) return 0; + + if (thd->get_stmt_da()->is_error() && + thd->get_stmt_da()->sql_errno() == ER_XA_RBROLLBACK) + return rc; + + THD_TRANS trans; + trans.ha_list= NULL; + + thd->ha_data[hton->slot].ha_info[1].register_ha(&trans, hton); + thd->ha_data[hton->slot].ha_info[1].set_trx_read_write(); (void) thd->binlog_setup_trx_data(); DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK || (thd->transaction->xid_state.get_state_code() == XA_ROLLBACK_ONLY)); - return binlog_rollback(hton, thd, TRUE); + + rc= binlog_rollback(hton, thd, TRUE); + thd->ha_data[hton->slot].ha_info[1].reset(); + + return rc; } @@ -2151,10 +2184,16 @@ int binlog_commit(THD *thd, bool all, bool ro_1pc) } if (cache_mngr->trx_cache.empty() && - thd->transaction->xid_state.get_state_code() != XA_PREPARED) + (thd->transaction->xid_state.get_state_code() != XA_PREPARED || + !(thd->ha_data[binlog_hton->slot].ha_info[1].is_started() && + thd->ha_data[binlog_hton->slot].ha_info[1].is_trx_read_write()))) { /* - we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid() + This is an empty transaction commit (both the regular and xa), + or such transaction xa-prepare or + either one's statement having no effect on the transactional cache + as any prior to it. + The empty xa-prepare sinks in only when binlog is read-only. */ cache_mngr->reset(false, true); THD_STAGE_INFO(thd, org_stage); @@ -2239,10 +2278,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) } if (!cache_mngr->trx_cache.has_incident() && cache_mngr->trx_cache.empty() && - thd->transaction->xid_state.get_state_code() != XA_PREPARED) + (thd->transaction->xid_state.get_state_code() != XA_PREPARED || + !(thd->ha_data[binlog_hton->slot].ha_info[1].is_started() && + thd->ha_data[binlog_hton->slot].ha_info[1].is_trx_read_write()))) { /* - we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid() + The same comments apply as in the binlog commit method's branch. */ cache_mngr->reset(false, true); thd->reset_binlog_for_next_statement(); @@ -10443,6 +10484,7 @@ int TC_LOG_BINLOG::unlog_xa_prepare(THD *thd, bool all) /* an empty XA-prepare event group is logged */ rc= write_empty_xa_prepare(thd, cache_mngr); // normally gains need_unlog trans_register_ha(thd, true, binlog_hton, 0); // do it for future commmit + thd->ha_data[binlog_hton->slot].ha_info[1].set_trx_read_write(); } if (rw_count == 0 || !cache_mngr->need_unlog) return rc; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e3c136dc283..8e209516861 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4645,10 +4645,9 @@ static void init_ssl() DBUG_PRINT("info",("ssl_acceptor_fd: %p", ssl_acceptor_fd)); if (!ssl_acceptor_fd) { - sql_print_warning("Failed to setup SSL"); - sql_print_warning("SSL error: %s", sslGetErrString(error)); - opt_use_ssl = 0; - have_ssl= SHOW_OPTION_DISABLED; + sql_print_error("Failed to setup SSL"); + sql_print_error("SSL error: %s", sslGetErrString(error)); + unireg_abort(1); } else ssl_acceptor_stats.init(); diff --git a/sql/rowid_filter.h b/sql/rowid_filter.h index 12710aecb18..cb1615c5925 100644 --- a/sql/rowid_filter.h +++ b/sql/rowid_filter.h @@ -192,6 +192,9 @@ public: */ virtual bool check(void *ctxt, char *elem) = 0; + /* True if the container does not contain any element */ + virtual bool is_empty() = 0; + virtual ~Rowid_filter_container() {} }; @@ -231,6 +234,8 @@ public: virtual ~Rowid_filter() {} + bool is_empty() { return container->is_empty(); } + Rowid_filter_container *get_container() { return container; } void set_tracker(Rowid_filter_tracker *track_arg) { tracker= track_arg; } @@ -268,6 +273,8 @@ public: bool check(char *elem) { + if (container->is_empty()) + return false; bool was_checked= container->check(table, elem); tracker->increment_checked_elements_count(was_checked); return was_checked; @@ -340,6 +347,8 @@ public: my_qsort2(array->front(), array->elements()/elem_size, elem_size, (qsort2_cmp) cmp, cmp_arg); } + + bool is_empty() { return elements() == 0; } }; @@ -369,6 +378,8 @@ public: bool add(void *ctxt, char *elem) { return refpos_container.add(elem); } bool check(void *ctxt, char *elem); + + bool is_empty() { return refpos_container.is_empty(); } }; /** diff --git a/sql/spatial.cc b/sql/spatial.cc index 527a1df9d1f..ec8279daa7a 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1094,10 +1094,9 @@ double Gis_point::calculate_haversine(const Geometry *g, point_temp[point_size-1]= '\0'; Geometry_buffer gbuff; Geometry *gg= Geometry::construct(&gbuff, point_temp, point_size-1); - DBUG_ASSERT(gg); - if (static_cast<Gis_point *>(gg)->get_xy_radian(&x2r, &y2r)) + if (!gg || static_cast<Gis_point *>(gg)->get_xy_radian(&x2r, &y2r)) { - DBUG_ASSERT(0); + *error= 2; return -1; } } @@ -1105,15 +1104,16 @@ double Gis_point::calculate_haversine(const Geometry *g, { if (static_cast<const Gis_point *>(g)->get_xy_radian(&x2r, &y2r)) { - DBUG_ASSERT(0); + *error= 2; return -1; } } if (this->get_xy_radian(&x1r, &y1r)) { - DBUG_ASSERT(0); + *error= 2; return -1; } + // // Check boundary conditions: longitude[-180,180] if (!((x2r >= -M_PI && x2r <= M_PI) && (x1r >= -M_PI && x1r <= M_PI))) { @@ -1166,15 +1166,20 @@ int Gis_point::spherical_distance_multipoints(Geometry *g, const double r, { Geometry_buffer buff_temp; Geometry *temp; + const char *pt_ptr= g->get_data_ptr()+ + 4+WKB_HEADER_SIZE*i + POINT_DATA_SIZE*(i-1); // First 4 bytes are handled already, make sure to create a Point memset(s + 4, Geometry::wkb_point, 1); + if (g->no_data(pt_ptr, POINT_DATA_SIZE)) + return 1; + memcpy(s + 5, g->get_data_ptr() + 5, 4); - memcpy(s + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\ - POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE); + memcpy(s + 4 + WKB_HEADER_SIZE, pt_ptr, POINT_DATA_SIZE); s[len-1]= '\0'; temp= Geometry::construct(&buff_temp, s, len); - DBUG_ASSERT(temp); + if (!temp) + return 1; temp_res= this->calculate_haversine(temp, r, err); if (res > temp_res) res= temp_res; @@ -2351,14 +2356,18 @@ int Gis_multi_point::spherical_distance_multipoints(Geometry *g, const double r, Geometry *temp; double temp_res= 0.0; char s[len]; + const char *pt_ptr= get_data_ptr()+ + 4+WKB_HEADER_SIZE*i + POINT_DATA_SIZE*(i-1); // First 4 bytes are handled already, make sure to create a Point memset(s + 4, Geometry::wkb_point, 1); + if (no_data(pt_ptr, POINT_DATA_SIZE)) + return 1; memcpy(s + 5, this->get_data_ptr() + 5, 4); - memcpy(s + 4 + WKB_HEADER_SIZE, this->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\ - POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE); + memcpy(s + 4 + WKB_HEADER_SIZE, pt_ptr, POINT_DATA_SIZE); s[len-1]= '\0'; temp= Geometry::construct(&buff_temp, s, len); - DBUG_ASSERT(temp); + if (!temp) + return 1; // Optimization for single Multipoint if (num_of_points2 == 1) { @@ -2370,14 +2379,18 @@ int Gis_multi_point::spherical_distance_multipoints(Geometry *g, const double r, Geometry_buffer buff_temp2; Geometry *temp2; char s2[len]; + const char *pt_ptr= g->get_data_ptr()+ + 4+WKB_HEADER_SIZE*j + POINT_DATA_SIZE*(j-1); // First 4 bytes are handled already, make sure to create a Point memset(s2 + 4, Geometry::wkb_point, 1); + if (g->no_data(pt_ptr, POINT_DATA_SIZE)) + return 1; memcpy(s2 + 5, g->get_data_ptr() + 5, 4); - memcpy(s2 + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*j +\ - POINT_DATA_SIZE*(j-1), POINT_DATA_SIZE); + memcpy(s2 + 4 + WKB_HEADER_SIZE, pt_ptr, POINT_DATA_SIZE); s2[len-1]= '\0'; temp2= Geometry::construct(&buff_temp2, s2, len); - DBUG_ASSERT(temp2); + if (!temp2) + return 1; temp_res= static_cast<Gis_point *>(temp)->calculate_haversine(temp2, r, err); if (res > temp_res) res= temp_res; diff --git a/sql/spatial.h b/sql/spatial.h index 7b33529ee94..8974511adf9 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -353,6 +353,7 @@ protected: const char *get_mbr_for_points(MBR *mbr, const char *data, uint offset) const; +public: /** Check if there're enough data remaining as requested @@ -383,6 +384,7 @@ protected: (expected_points > ((m_data_end - data) / (POINT_DATA_SIZE + extra_point_space)))); } +protected: const char *m_data; const char *m_data_end; }; diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h index 990c79fb9ad..968b8d38295 100644 --- a/sql/sql_analyze_stmt.h +++ b/sql/sql_analyze_stmt.h @@ -416,12 +416,13 @@ public: uint get_container_elements() const { return container_elements; } + uint get_container_lookups() { return n_checks; } + double get_r_selectivity_pct() const { - return static_cast<double>(n_positive_checks) / - static_cast<double>(n_checks); + return n_checks ? static_cast<double>(n_positive_checks) / + static_cast<double>(n_checks) : 0; } size_t get_container_buff_size() const { return container_buff_size; } }; - diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ad983ab35d6..876a59c542d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3721,8 +3721,10 @@ int select_max_min_finder_subselect::send_data(List<Item> &items) { cache= val_item->get_cache(thd); set_op(val_item->type_handler()); + cache->setup(thd, val_item); } - cache->store(val_item); + else + cache->store(val_item); it->store(0, cache); } it->assigned(1); diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index 79e06640768..480a1259ba8 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -1683,6 +1683,7 @@ void Explain_rowid_filter::print_explain_json(Explain_query *query, if (is_analyze) { writer->add_member("r_rows").add_double(tracker->get_container_elements()); + writer->add_member("r_lookups").add_ll(tracker->get_container_lookups()); writer->add_member("r_selectivity_pct"). add_double(tracker->get_r_selectivity_pct() * 100.0); writer->add_member("r_buffer_size"). diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7d05e2bae79..c7bef0f7027 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4540,6 +4540,16 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items, alter_info->create_list.push_back(cr_field, thd->mem_root); } + /* + Item*::type_handler() always returns pointers to + type_handler_{time2|datetime2|timestamp2} no matter what + the current mysql56_temporal_format says. + Let's convert them according to mysql56_temporal_format. + QQ: This perhaps should eventually be fixed to have Item*::type_handler() + respect mysql56_temporal_format, and remove the upgrade from here. + */ + Create_field::upgrade_data_types(alter_info->create_list); + if (create_info->check_fields(thd, alter_info, create_table->table_name, create_table->db, diff --git a/sql/sql_plugin_services.inl b/sql/sql_plugin_services.inl index 3dd41ffbed9..e883081e9f7 100644 --- a/sql/sql_plugin_services.inl +++ b/sql/sql_plugin_services.inl @@ -245,6 +245,11 @@ struct sql_service_st sql_service_handler= mysql_free_result, mysql_fetch_row, mysql_close, + mysql_options, + mysql_fetch_lengths, + mysql_set_character_set, + mysql_num_fields, + mysql_select_db }; #define DEFINE_warning_function(name, ret) { \ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 66e29712de1..419fa4fb1fe 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1324,6 +1324,15 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num, /* Fix items that requires the join structure to exist */ fix_items_after_optimize(thd, select_lex); + /* + It is hack which force creating EXPLAIN object always on runt-time arena + (because very top JOIN::prepare executes always with runtime arena, but + constant subquery like (SELECT 'x') can be called with statement arena + during prepare phase of top SELECT). + */ + if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE)) + create_explain_query_if_not_exists(thd->lex, thd->mem_root); + if (select_lex->handle_derived(thd->lex, DT_PREPARE)) DBUG_RETURN(-1); @@ -1811,7 +1820,6 @@ bool JOIN::build_explain() int JOIN::optimize() { int res= 0; - create_explain_query_if_not_exists(thd->lex, thd->mem_root); join_optimization_state init_state= optimization_state; if (select_lex->pushdown_select) { @@ -7726,6 +7734,7 @@ best_access_path(JOIN *join, double best= DBL_MAX; double best_time= DBL_MAX; double records= DBL_MAX; + ha_rows records_for_key= 0; table_map best_ref_depends_map= 0; /* key_dependent is 0 if all key parts could be used or if there was an @@ -7736,6 +7745,7 @@ best_access_path(JOIN *join, table_map key_dependent= 0; Range_rowid_filter_cost_info *best_filter= 0; double tmp; + double keyread_tmp= 0; ha_rows rec; bool best_uses_jbuf= FALSE; MY_BITMAP *eq_join_set= &s->table->eq_join_set; @@ -8020,8 +8030,12 @@ best_access_path(JOIN *join, /* Limit the number of matched rows */ tmp= cost_for_index_read(thd, table, key, (ha_rows) records, (ha_rows) s->worst_seeks); + records_for_key= (ha_rows) records; + set_if_smaller(records_for_key, thd->variables.max_seeks_for_key); + keyread_tmp= table->file->keyread_time(key, 1, records_for_key); got_cost: tmp= COST_MULT(tmp, record_count); + keyread_tmp= COST_MULT(keyread_tmp, record_count); } } else @@ -8195,12 +8209,14 @@ best_access_path(JOIN *join, } /* Limit the number of matched rows */ - tmp= records; - set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); - tmp= cost_for_index_read(thd, table, key, (ha_rows) tmp, + tmp= cost_for_index_read(thd, table, key, (ha_rows) records, (ha_rows) s->worst_seeks); + records_for_key= (ha_rows) records; + set_if_smaller(records_for_key, thd->variables.max_seeks_for_key); + keyread_tmp= table->file->keyread_time(key, 1, records_for_key); got_cost2: tmp= COST_MULT(tmp, record_count); + keyread_tmp= COST_MULT(keyread_tmp, record_count); } else { @@ -8219,7 +8235,35 @@ best_access_path(JOIN *join, (found_part & 1)) // start_key->key can be used for index access { double rows= record_count * records; - double access_cost_factor= MY_MIN(tmp / rows, 1.0); + + /* + If we use filter F with selectivity s the the cost of fetching data + by key using this filter will be + cost_of_fetching_1_row * rows * s + + cost_of_fetching_1_key_tuple * rows * (1 - s) + + cost_of_1_lookup_into_filter * rows + Without using any filter the cost would be just + cost_of_fetching_1_row * rows + + So the gain in access cost per row will be + cost_of_fetching_1_row * (1 - s) - + cost_of_fetching_1_key_tuple * (1 - s) - + cost_of_1_lookup_into_filter + = + (cost_of_fetching_1_row - cost_of_fetching_1_key_tuple) * (1 - s) + - cost_of_1_lookup_into_filter + + Here we have: + cost_of_fetching_1_row = tmp/rows + cost_of_fetching_1_key_tuple = keyread_tmp/rows + + Note that access_cost_factor may be greater than 1.0. In this case + we still can expect a gain of using rowid filter due to smaller number + of checks for conditions pushed to the joined table. + */ + double rows_access_cost= MY_MIN(rows, s->worst_seeks); + double access_cost_factor= MY_MIN((rows_access_cost - keyread_tmp) / + rows, 1.0); filter= table->best_range_rowid_filter_for_partial_join(start_key->key, rows, access_cost_factor); @@ -8404,6 +8448,10 @@ best_access_path(JOIN *join, double rows= record_count * s->found_records; double access_cost_factor= MY_MIN(tmp / rows, 1.0); uint key_no= s->quick->index; + + /* See the comment concerning using rowid filter for with ref access */ + keyread_tmp= s->table->opt_range[key_no].index_only_cost; + access_cost_factor= MY_MIN((rows - keyread_tmp) / rows, 1.0); filter= s->table->best_range_rowid_filter_for_partial_join(key_no, rows, access_cost_factor); @@ -21255,6 +21303,8 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) DBUG_RETURN(NESTED_LOOP_ERROR); join_tab->build_range_rowid_filter_if_needed(); + if (join_tab->rowid_filter && join_tab->rowid_filter->is_empty()) + rc= NESTED_LOOP_NO_MORE_ROWS; join->return_tab= join_tab; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 99661a1c090..833865f17b5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10083,6 +10083,18 @@ do_continue:; set_table_default_charset(thd, create_info, alter_ctx.db); + /* + The ALTER related code cannot alter partitions and change column data types + at the same time. So in case of partition change statements like: + ALTER TABLE t1 DROP PARTITION p1; + we skip implicit data type upgrade (such as "MariaDB 5.3 TIME" to + "MySQL 5.6 TIME" or vice versa according to mysql56_temporal_format). + Note, one can run a separate "ALTER TABLE t1 FORCE;" statement + before or after the partition change ALTER statement to upgrade data types. + */ + if (IF_PARTITIONING(!fast_alter_partition, 1)) + Create_field::upgrade_data_types(alter_info->create_list); + if (create_info->check_fields(thd, alter_info, table_list->table_name, table_list->db) || create_info->fix_period_fields(thd, alter_info)) |