summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2022-11-02 14:58:01 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2022-11-02 15:45:27 +0100
commit15de3aa2f5b0fb5404a00f1a3cd5c0291f0ef67d (patch)
treecfd49996c72f6bbe7117fd950ededb01abc76b76 /sql
parent6449af6f2d52c7acb483fcfb186c838edaf0424a (diff)
parente5aa58190fd8697b3858add4b8f86a5fd38e07f8 (diff)
downloadmariadb-git-15de3aa2f5b0fb5404a00f1a3cd5c0291f0ef67d.tar.gz
Merge branch '10.6' into 10.7
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc2
-rw-r--r--sql/field.h6
-rw-r--r--sql/item_geofunc.cc42
-rw-r--r--sql/log.cc54
-rw-r--r--sql/mysqld.cc7
-rw-r--r--sql/rowid_filter.h11
-rw-r--r--sql/spatial.cc41
-rw-r--r--sql/spatial.h2
-rw-r--r--sql/sql_analyze_stmt.h7
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_explain.cc1
-rw-r--r--sql/sql_insert.cc10
-rw-r--r--sql/sql_plugin_services.inl5
-rw-r--r--sql/sql_select.cc60
-rw-r--r--sql/sql_table.cc12
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))