summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2016-02-25 18:19:55 +0100
committerSergei Golubchik <serg@mariadb.org>2016-02-25 18:19:55 +0100
commit00d1db7a38b17d4512a6ba5147926608aca5624d (patch)
treec2b28145304e9eacf79fcabaeb962a20d79fec93 /sql
parent0485328d030f4b742dac7b667e8ed099beb9e9f2 (diff)
parent0251232f8c3bca33b4dd15d6668105f3de9d024d (diff)
downloadmariadb-git-00d1db7a38b17d4512a6ba5147926608aca5624d.tar.gz
Merge branch '10.1' into 10.2
Diffstat (limited to 'sql')
-rw-r--r--sql/authors.h4
-rw-r--r--sql/client_settings.h2
-rw-r--r--sql/contributors.h18
-rw-r--r--sql/field.h9
-rw-r--r--sql/field_conv.cc5
-rw-r--r--sql/gcalc_slicescan.cc266
-rw-r--r--sql/gcalc_slicescan.h20
-rw-r--r--sql/gcalc_tools.cc6
-rw-r--r--sql/handler.cc12
-rw-r--r--sql/item.cc5
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_cmpfunc.cc9
-rw-r--r--sql/item_cmpfunc.h2
-rw-r--r--sql/item_geofunc.cc32
-rw-r--r--sql/item_strfunc.cc2
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/item_timefunc.cc4
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.cc34
-rw-r--r--sql/mdl.cc11
-rw-r--r--sql/mysqld.cc27
-rw-r--r--sql/opt_subselect.cc14
-rw-r--r--sql/rpl_gtid.cc4
-rw-r--r--sql/rpl_reporting.cc1
-rw-r--r--sql/rpl_utility.cc43
-rw-r--r--sql/sql_admin.cc22
-rw-r--r--sql/sql_base.cc168
-rw-r--r--sql/sql_cache.cc20
-rw-r--r--sql/sql_class.cc125
-rw-r--r--sql/sql_class.h14
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc270
-rw-r--r--sql/sql_lex.h38
-rw-r--r--sql/sql_parse.cc57
-rw-r--r--sql/sql_plugin_services.ic2
-rw-r--r--sql/sql_select.cc29
-rw-r--r--sql/sql_select.h1
-rw-r--r--sql/sql_show.cc43
-rw-r--r--sql/sql_show.h8
-rw-r--r--sql/sql_table.cc92
-rw-r--r--sql/sql_time.h3
-rw-r--r--sql/sql_type.cc16
-rw-r--r--sql/sql_update.cc9
-rw-r--r--sql/sql_view.cc3
-rw-r--r--sql/sql_yacc.yy23
-rw-r--r--sql/sys_vars.cc2
-rw-r--r--sql/sys_vars.ic11
-rw-r--r--sql/wsrep_applier.cc27
-rw-r--r--sql/wsrep_dummy.cc2
-rw-r--r--sql/wsrep_hton.cc14
-rw-r--r--sql/wsrep_mysqld.cc75
-rw-r--r--sql/wsrep_mysqld.h2
52 files changed, 1028 insertions, 586 deletions
diff --git a/sql/authors.h b/sql/authors.h
index cc9889bcdbc..3a8f5497248 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -56,7 +56,7 @@ struct show_table_authors_st show_table_authors[]= {
"Unicode and character sets" },
{ "Alexey Botchkov (Holyfoot)", "Izhevsk, Russia",
"GIS extensions, embedded server, precision math"},
- { "Daniel Bartholomew", "Raleigh, USA", "MariaDB documentation"},
+ { "Daniel Bartholomew", "Raleigh, USA", "MariaDB documentation, Buildbot, releases"},
{ "Colin Charles", "Selangor, Malesia", "MariaDB documentation, talks at a LOT of conferences"},
{ "Sergey Vojtovich", "Izhevsk, Russia",
"initial implementation of plugin architecture, maintained native storage engines (MyISAM, MEMORY, ARCHIVE, etc), rewrite of table cache"},
@@ -73,6 +73,8 @@ struct show_table_authors_st show_table_authors[]= {
{ "Pavel Ivanov", "USA", "Some patches and bug fixes"},
{ "Konstantin Osipov", "Moscow, Russia",
"Prepared statements (4.1), Cursors (5.0), GET_LOCK (10.0)" },
+ { "Ian Gilfillan", "South Africa", "MariaDB documentation"},
+ { "Federico Razolli", "Italy", "MariaDB documentation Italian translation"},
/* People working on MySQL code base (not NDB) */
{ "Guilhem Bichot", "Bordeaux, France", "Replication (since 4.0)" },
diff --git a/sql/client_settings.h b/sql/client_settings.h
index cc90d6a174d..486862b276d 100644
--- a/sql/client_settings.h
+++ b/sql/client_settings.h
@@ -37,7 +37,7 @@
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
CLIENT_CONNECT_ATTRS)
-#define read_user_name(A) {}
+#define read_user_name(A) A[0]= 0
#undef _CUSTOMCONFIG_
#define mysql_server_init(a,b,c) mysql_client_plugin_init()
diff --git a/sql/contributors.h b/sql/contributors.h
index 2479f611727..255decd19cc 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -37,18 +37,16 @@ struct show_table_contributors_st {
struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation members, in contribution, size , time order */
- {"Booking.com", "http://www.booking.com", "Founding member of the MariaDB foundation"},
- {"SkySQL Ab", "http://www.skysql.com", "Founding member of the MariaDB foundation"},
- {"Auttomatic", "http://automattic.com", "Member of the MariaDB foundation"},
- {"Parallels", "http://www.parallels.com/products/plesk", "Founding member of the MariaDB foundation"},
+ {"Booking.com", "http://www.booking.com", "Founding member of the MariaDB Foundation"},
+ {"MariaDB Corporation", "https://mariadb.com", "Founding member of the MariaDB Foundation"},
+ {"Auttomattic", "http://automattic.com", "Member of the MariaDB Foundation"},
+ {"Parallels", "http://www.parallels.com/products/plesk", "Founding member of the MariaDB Foundation"},
+ {"Acronis", "http://www.acronis.com", "Member of the MariaDB Foundation"},
/* Smaller sponsors, newer per year */
- {"Verkkokauppa.com", "Finland", "Sponsor of the MariaDB foundation"},
- {"Webyog", "Bangalor", "Sponsor of the MariaDB foundation"},
- {"Percona", "USA", "Sponsor of the MariaDB foundation"},
- {"Jelastic.com", "Russia", "Sponsor of the MariaDB foundation"},
- {"Planetta.net", "Finland", "Sponsor of the MariaDB foundation"},
- {"Open query", "Australia", "Sponsor of the MariaDB foundation"},
+ {"Verkkokauppa.com", "Finland", "Sponsor of the MariaDB Foundation"},
+ {"Webyog", "Bangalore", "Sponsor of the MariaDB Foundation"},
+ {"Wikimedia Foundation", "USA", "Sponsor of the MariaDB Foundation"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring parallel replication and GTID" },
diff --git a/sql/field.h b/sql/field.h
index 435ea20825a..8869c16cb98 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -609,6 +609,13 @@ public:
{
in_partitioning_expr= TRUE;
}
+ bool is_equal(Virtual_column_info* vcol)
+ {
+ return field_type == vcol->get_real_type()
+ && stored_in_db == vcol->is_stored()
+ && expr_str.length == vcol->expr_str.length
+ && memcmp(expr_str.str, vcol->expr_str.str, expr_str.length) == 0;
+ }
};
class Field: public Value_source
@@ -3159,7 +3166,7 @@ public:
int store_field(Field *from)
{ // Be sure the value is stored
from->val_str(&value);
- if (!value.is_alloced() && from->is_updatable())
+ if (table->copy_blobs || (!value.is_alloced() && from->is_updatable()))
value.copy();
return store(value.ptr(), value.length(), from->charset());
}
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index ecad05c7530..6823329132d 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -1,6 +1,5 @@
-/*
- Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2015, MariaDB
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2016, 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
diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc
index ed533abdaf4..f62c413fd35 100644
--- a/sql/gcalc_slicescan.cc
+++ b/sql/gcalc_slicescan.cc
@@ -49,14 +49,14 @@ typedef int (*sc_compare_func)(const void*, const void*);
static Gcalc_scan_iterator::point *eq_sp(const Gcalc_heap::Info *pi)
{
GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_eq_node);
- return (Gcalc_scan_iterator::point *) pi->eq_data;
+ return (Gcalc_scan_iterator::point *) pi->node.eq.data;
}
static Gcalc_scan_iterator::intersection_info *i_data(const Gcalc_heap::Info *pi)
{
GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_intersection);
- return (Gcalc_scan_iterator::intersection_info *) pi->intersection_data;
+ return (Gcalc_scan_iterator::intersection_info *) pi->node.intersection.data;
}
@@ -103,8 +103,8 @@ const char *gcalc_ev_name(int ev)
static int gcalc_pi_str(char *str, const Gcalc_heap::Info *pi, const char *postfix)
{
return sprintf(str, "%s %d %d | %s %d %d%s",
- GCALC_SIGN(pi->ix[0]) ? "-":"", FIRST_DIGIT(pi->ix[0]),pi->ix[1],
- GCALC_SIGN(pi->iy[0]) ? "-":"", FIRST_DIGIT(pi->iy[0]),pi->iy[1],
+ GCALC_SIGN(pi->node.shape.ix[0]) ? "-":"", FIRST_DIGIT(pi->node.shape.ix[0]),pi->node.shape.ix[1],
+ GCALC_SIGN(pi->node.shape.iy[0]) ? "-":"", FIRST_DIGIT(pi->node.shape.iy[0]),pi->node.shape.iy[1],
postfix);
}
@@ -594,8 +594,8 @@ void Gcalc_scan_iterator::intersection_info::do_calc_t()
Gcalc_coord1 a2_a1x, a2_a1y;
Gcalc_coord2 x1y2, x2y1;
- gcalc_sub_coord1(a2_a1x, edge_b->pi->ix, edge_a->pi->ix);
- gcalc_sub_coord1(a2_a1y, edge_b->pi->iy, edge_a->pi->iy);
+ gcalc_sub_coord1(a2_a1x, edge_b->pi->node.shape.ix, edge_a->pi->node.shape.ix);
+ gcalc_sub_coord1(a2_a1y, edge_b->pi->node.shape.iy, edge_a->pi->node.shape.iy);
GCALC_DBUG_ASSERT(!gcalc_is_zero(edge_a->dy, GCALC_COORD_BASE) ||
!gcalc_is_zero(edge_b->dy, GCALC_COORD_BASE));
@@ -619,7 +619,7 @@ void Gcalc_scan_iterator::intersection_info::do_calc_y()
Gcalc_coord3 a_tb, b_ta;
gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
- t_b, GCALC_COORD_BASE2, edge_a->pi->iy, GCALC_COORD_BASE);
+ t_b, GCALC_COORD_BASE2, edge_a->pi->node.shape.iy, GCALC_COORD_BASE);
gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
t_a, GCALC_COORD_BASE2, edge_a->dy, GCALC_COORD_BASE);
@@ -635,7 +635,7 @@ void Gcalc_scan_iterator::intersection_info::do_calc_x()
Gcalc_coord3 a_tb, b_ta;
gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
- t_b, GCALC_COORD_BASE2, edge_a->pi->ix, GCALC_COORD_BASE);
+ t_b, GCALC_COORD_BASE2, edge_a->pi->node.shape.ix, GCALC_COORD_BASE);
gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
t_a, GCALC_COORD_BASE2, edge_a->dx, GCALC_COORD_BASE);
@@ -656,7 +656,7 @@ static int cmp_node_isc(const Gcalc_heap::Info *node,
inf->calc_y_exp();
gcalc_mul_coord(exp, GCALC_COORD_BASE3,
- inf->t_b, GCALC_COORD_BASE2, node->iy, GCALC_COORD_BASE);
+ inf->t_b, GCALC_COORD_BASE2, node->node.shape.iy, GCALC_COORD_BASE);
result= gcalc_cmp_coord(exp, inf->y_exp, GCALC_COORD_BASE3);
#ifdef GCALC_CHECK_WITH_FLOAT
@@ -664,18 +664,18 @@ static int cmp_node_isc(const Gcalc_heap::Info *node,
isc->calc_xy_ld(&int_x, &int_y);
if (result < 0)
{
- if (!de_check(int_y, node->y) && node->y > int_y)
- GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g < %LG", node->y, int_y));
+ if (!de_check(int_y, node->node.shape.y) && node->node.shape.y > int_y)
+ GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g < %LG", node->node.shape.y, int_y));
}
else if (result > 0)
{
- if (!de_check(int_y, node->y) && node->y < int_y)
- GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g > %LG", node->y, int_y));
+ if (!de_check(int_y, node->node.shape.y) && node->node.shape.y < int_y)
+ GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g > %LG", node->node.shape.y, int_y));
}
else
{
- if (!de_check(int_y, node->y))
- GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g == %LG", node->y, int_y));
+ if (!de_check(int_y, node->node.shape.y))
+ GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g == %LG", node->node.shape.y, int_y));
}
#endif /*GCALC_CHECK_WITH_FLOAT*/
if (result)
@@ -684,27 +684,27 @@ static int cmp_node_isc(const Gcalc_heap::Info *node,
inf->calc_x_exp();
gcalc_mul_coord(exp, GCALC_COORD_BASE3,
- inf->t_b, GCALC_COORD_BASE2, node->ix, GCALC_COORD_BASE);
+ inf->t_b, GCALC_COORD_BASE2, node->node.shape.ix, GCALC_COORD_BASE);
result= gcalc_cmp_coord(exp, inf->x_exp, GCALC_COORD_BASE3);
#ifdef GCALC_CHECK_WITH_FLOAT
if (result < 0)
{
- if (!de_check(int_x, node->x) && node->x > int_x)
+ if (!de_check(int_x, node->node.shape.x) && node->node.shape.x > int_x)
GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g < %LG",
- node->x, int_x));
+ node->node.shape.x, int_x));
}
else if (result > 0)
{
- if (!de_check(int_x, node->x) && node->x < int_x)
+ if (!de_check(int_x, node->node.shape.x) && node->node.shape.x < int_x)
GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g > %LG",
- node->x, int_x));
+ node->node.shape.x, int_x));
}
else
{
- if (!de_check(int_x, node->x))
+ if (!de_check(int_x, node->node.shape.x))
GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g == %LG",
- node->x, int_x));
+ node->node.shape.x, int_x));
}
#endif /*GCALC_CHECK_WITH_FLOAT*/
exit:
@@ -844,13 +844,13 @@ Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y,
return NULL;
*m_hook= result;
m_hook= &result->next;
- result->x= x;
- result->y= y;
- result->shape= shape;
- result->top_node= 1;
+ result->node.shape.x= x;
+ result->node.shape.y= y;
+ result->node.shape.shape= shape;
+ result->node.shape.top_node= 1;
result->type= nt_shape_node;
- gcalc_set_double(result->ix, x, coord_extent);
- gcalc_set_double(result->iy, y, coord_extent);
+ gcalc_set_double(result->node.shape.ix, x, coord_extent);
+ gcalc_set_double(result->node.shape.iy, y, coord_extent);
m_n_points++;
return result;
@@ -864,11 +864,11 @@ static Gcalc_heap::Info *new_intersection(
if (!isc)
return 0;
isc->type= Gcalc_heap::nt_intersection;
- isc->p1= ii->edge_a->pi;
- isc->p2= ii->edge_a->next_pi;
- isc->p3= ii->edge_b->pi;
- isc->p4= ii->edge_b->next_pi;
- isc->intersection_data= ii;
+ isc->node.intersection.p1= ii->edge_a->pi;
+ isc->node.intersection.p2= ii->edge_a->next_pi;
+ isc->node.intersection.p3= ii->edge_b->pi;
+ isc->node.intersection.p4= ii->edge_b->next_pi;
+ isc->node.intersection.data= ii;
return isc;
}
@@ -881,46 +881,46 @@ static Gcalc_heap::Info *new_eq_point(
if (!eqp)
return 0;
eqp->type= Gcalc_heap::nt_eq_node;
- eqp->node= p;
- eqp->eq_data= edge;
+ eqp->node.eq.node= p;
+ eqp->node.eq.data= edge;
return eqp;
}
void Gcalc_heap::Info::calc_xy(double *x, double *y) const
{
- double b0_x= p2->x - p1->x;
- double b0_y= p2->y - p1->y;
- double b1_x= p4->x - p3->x;
- double b1_y= p4->y - p3->y;
+ double b0_x= node.intersection.p2->node.shape.x - node.intersection.p1->node.shape.x;
+ double b0_y= node.intersection.p2->node.shape.y - node.intersection.p1->node.shape.y;
+ double b1_x= node.intersection.p4->node.shape.x - node.intersection.p3->node.shape.x;
+ double b1_y= node.intersection.p4->node.shape.y - node.intersection.p3->node.shape.y;
double b0xb1= b0_x * b1_y - b0_y * b1_x;
- double t= (p3->x - p1->x) * b1_y - (p3->y - p1->y) * b1_x;
+ double t= (node.intersection.p3->node.shape.x - node.intersection.p1->node.shape.x) * b1_y - (node.intersection.p3->node.shape.y - node.intersection.p1->node.shape.y) * b1_x;
t/= b0xb1;
- *x= p1->x + b0_x * t;
- *y= p1->y + b0_y * t;
+ *x= node.intersection.p1->node.shape.x + b0_x * t;
+ *y= node.intersection.p1->node.shape.y + b0_y * t;
}
#ifdef GCALC_CHECK_WITH_FLOAT
void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const
{
- long double b0_x= ((long double) p2->x) - p1->x;
- long double b0_y= ((long double) p2->y) - p1->y;
- long double b1_x= ((long double) p4->x) - p3->x;
- long double b1_y= ((long double) p4->y) - p3->y;
+ long double b0_x= ((long double) p2->node.shape.x) - p1->node.shape.x;
+ long double b0_y= ((long double) p2->node.shape.y) - p1->node.shape.y;
+ long double b1_x= ((long double) p4->node.shape.x) - p3->node.shape.x;
+ long double b1_y= ((long double) p4->node.shape.y) - p3->node.shape.y;
long double b0xb1= b0_x * b1_y - b0_y * b1_x;
- long double ax= ((long double) p3->x) - p1->x;
- long double ay= ((long double) p3->y) - p1->y;
+ long double ax= ((long double) p3->node.shape.x) - p1->node.shape.x;
+ long double ay= ((long double) p3->node.shape.y) - p1->node.shape.y;
long double t_a= ax * b1_y - ay * b1_x;
- long double hx= (b0xb1 * (long double) p1->x + b0_x * t_a);
- long double hy= (b0xb1 * (long double) p1->y + b0_y * t_a);
+ long double hx= (b0xb1 * (long double) p1->node.shape.x + b0_x * t_a);
+ long double hy= (b0xb1 * (long double) p1->node.shape.y + b0_y * t_a);
if (fabs(b0xb1) < 1e-15)
{
- *x= p1->x;
- *y= p1->y;
+ *x= p1->node.shape.x;
+ *y= p1->node.shape.y;
return;
}
@@ -933,10 +933,10 @@ void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const
static int cmp_point_info(const Gcalc_heap::Info *i0,
const Gcalc_heap::Info *i1)
{
- int cmp_y= gcalc_cmp_coord1(i0->iy, i1->iy);
+ int cmp_y= gcalc_cmp_coord1(i0->node.shape.iy, i1->node.shape.iy);
if (cmp_y)
return cmp_y;
- return gcalc_cmp_coord1(i0->ix, i1->ix);
+ return gcalc_cmp_coord1(i0->node.shape.ix, i1->node.shape.ix);
}
@@ -944,11 +944,11 @@ static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node
{
if (!node)
return;
- node->top_node= 0;
- GCALC_DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node));
- if (node->left == prev_node)
- node->left= node->right;
- node->right= NULL;
+ node->node.shape.top_node= 0;
+ GCALC_DBUG_ASSERT((node->node.shape.left == prev_node) || (node->node.shape.right == prev_node));
+ if (node->node.shape.left == prev_node)
+ node->node.shape.left= node->node.shape.right;
+ node->node.shape.right= NULL;
GCALC_DBUG_ASSERT(cmp_point_info(node, prev_node));
}
@@ -972,8 +972,8 @@ void Gcalc_heap::prepare_operation()
/* TODO - move this to the 'normal_scan' loop */
for (cur= get_first(); cur; cur= cur->get_next())
{
- trim_node(cur->left, cur);
- trim_node(cur->right, cur);
+ trim_node(cur->node.shape.left, cur);
+ trim_node(cur->node.shape.right, cur);
}
}
@@ -995,7 +995,7 @@ int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info,
Gcalc_heap::Info *point= m_heap->new_point_info(x, y, Info);
if (!point)
return 1;
- point->left= point->right= 0;
+ point->node.shape.left= point->node.shape.right= 0;
return 0;
}
@@ -1018,9 +1018,9 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info,
m_heap->free_point_info(point, hook);
return 0;
}
- GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y);
- m_prev->left= point;
- point->right= m_prev;
+ GCALC_DBUG_ASSERT(!m_prev || m_prev->node.shape.x != x || m_prev->node.shape.y != y);
+ m_prev->node.shape.left= point;
+ point->node.shape.right= m_prev;
}
else
m_first= point;
@@ -1040,16 +1040,16 @@ void Gcalc_shape_transporter::int_complete()
/* simple point */
if (m_first == m_prev)
{
- m_first->right= m_first->left= NULL;
+ m_first->node.shape.right= m_first->node.shape.left= NULL;
return;
}
/* line */
if (m_shape_started == 1)
{
- m_first->right= NULL;
- m_prev->left= m_prev->right;
- m_prev->right= NULL;
+ m_first->node.shape.right= NULL;
+ m_prev->node.shape.left= m_prev->node.shape.right;
+ m_prev->node.shape.right= NULL;
return;
}
@@ -1057,32 +1057,32 @@ void Gcalc_shape_transporter::int_complete()
if (cmp_point_info(m_first, m_prev) == 0)
{
/* Coinciding points, remove the last one from the list */
- m_prev->right->left= m_first;
- m_first->right= m_prev->right;
+ m_prev->node.shape.right->node.shape.left= m_first;
+ m_first->node.shape.right= m_prev->node.shape.right;
m_heap->free_point_info(m_prev, m_prev_hook);
}
else
{
- GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y);
- m_first->right= m_prev;
- m_prev->left= m_first;
+ GCALC_DBUG_ASSERT(m_prev->node.shape.x != m_first->node.shape.x || m_prev->node.shape.y != m_first->node.shape.y);
+ m_first->node.shape.right= m_prev;
+ m_prev->node.shape.left= m_first;
}
}
inline void calc_dx_dy(Gcalc_scan_iterator::point *p)
{
- gcalc_sub_coord1(p->dx, p->next_pi->ix, p->pi->ix);
- gcalc_sub_coord1(p->dy, p->next_pi->iy, p->pi->iy);
+ gcalc_sub_coord1(p->dx, p->next_pi->node.shape.ix, p->pi->node.shape.ix);
+ gcalc_sub_coord1(p->dy, p->next_pi->node.shape.iy, p->pi->node.shape.iy);
if (GCALC_SIGN(p->dx[0]))
{
- p->l_border= &p->next_pi->ix;
- p->r_border= &p->pi->ix;
+ p->l_border= &p->next_pi->node.shape.ix;
+ p->r_border= &p->pi->node.shape.ix;
}
else
{
- p->r_border= &p->next_pi->ix;
- p->l_border= &p->pi->ix;
+ p->r_border= &p->next_pi->node.shape.ix;
+ p->l_border= &p->pi->node.shape.ix;
}
}
@@ -1143,10 +1143,10 @@ int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_heap::Info *p1,
const Gcalc_heap::Info *p4)
{
Gcalc_coord1 dx_a, dy_a, dx_b, dy_b;
- gcalc_sub_coord1(dx_a, p2->ix, p1->ix);
- gcalc_sub_coord1(dy_a, p2->iy, p1->iy);
- gcalc_sub_coord1(dx_b, p4->ix, p3->ix);
- gcalc_sub_coord1(dy_b, p4->iy, p3->iy);
+ gcalc_sub_coord1(dx_a, p2->node.shape.ix, p1->node.shape.ix);
+ gcalc_sub_coord1(dy_a, p2->node.shape.iy, p1->node.shape.iy);
+ gcalc_sub_coord1(dx_b, p4->node.shape.ix, p3->node.shape.ix);
+ gcalc_sub_coord1(dy_b, p4->node.shape.iy, p3->node.shape.iy);
return cmp_dx_dy(dx_a, dy_a, dx_b, dy_b);
}
@@ -1168,8 +1168,8 @@ void Gcalc_scan_iterator::point::calc_x(long double *x, long double y,
*x= ix;
}
else
- *x= (ddy * (long double) pi->x + gcalc_get_double(dx, GCALC_COORD_BASE) *
- (y - pi->y)) / ddy;
+ *x= (ddy * (long double) pi->node.shape.x + gcalc_get_double(dx, GCALC_COORD_BASE) *
+ (y - pi->node.shape.y)) / ddy;
}
#endif /*GCALC_CHECK_WITH_FLOAT*/
@@ -1280,7 +1280,7 @@ int Gcalc_scan_iterator::arrange_event(int do_sorting, int n_intersections)
int Gcalc_heap::Info::equal_pi(const Info *pi) const
{
if (type == nt_intersection)
- return equal_intersection;
+ return node.intersection.equal;
if (pi->type == nt_eq_node)
return 1;
if (type == nt_eq_node || pi->type == nt_intersection)
@@ -1322,7 +1322,7 @@ int Gcalc_scan_iterator::step()
#ifndef GCALC_DBUG_OFF
if (m_cur_pi->type == Gcalc_heap::nt_intersection &&
m_cur_pi->get_next()->type == Gcalc_heap::nt_intersection &&
- m_cur_pi->equal_intersection)
+ m_cur_pi->node.intersection.equal)
GCALC_DBUG_ASSERT(cmp_intersections(m_cur_pi, m_cur_pi->get_next()) == 0);
#endif /*GCALC_DBUG_OFF*/
GCALC_DBUG_CHECK_COUNTER();
@@ -1377,23 +1377,23 @@ static int node_on_right(const Gcalc_heap::Info *node,
Gcalc_coord2 ax_by, ay_bx;
int result;
- gcalc_sub_coord1(a_x, node->ix, edge_a->ix);
- gcalc_sub_coord1(a_y, node->iy, edge_a->iy);
- gcalc_sub_coord1(b_x, edge_b->ix, edge_a->ix);
- gcalc_sub_coord1(b_y, edge_b->iy, edge_a->iy);
+ gcalc_sub_coord1(a_x, node->node.shape.ix, edge_a->node.shape.ix);
+ gcalc_sub_coord1(a_y, node->node.shape.iy, edge_a->node.shape.iy);
+ gcalc_sub_coord1(b_x, edge_b->node.shape.ix, edge_a->node.shape.ix);
+ gcalc_sub_coord1(b_y, edge_b->node.shape.iy, edge_a->node.shape.iy);
gcalc_mul_coord1(ax_by, a_x, b_y);
gcalc_mul_coord1(ay_bx, a_y, b_x);
result= gcalc_cmp_coord(ax_by, ay_bx, GCALC_COORD_BASE2);
#ifdef GCALC_CHECK_WITH_FLOAT
{
- long double dx= gcalc_get_double(edge_b->ix, GCALC_COORD_BASE) -
- gcalc_get_double(edge_a->ix, GCALC_COORD_BASE);
- long double dy= gcalc_get_double(edge_b->iy, GCALC_COORD_BASE) -
- gcalc_get_double(edge_a->iy, GCALC_COORD_BASE);
- long double ax= gcalc_get_double(node->ix, GCALC_COORD_BASE) -
- gcalc_get_double(edge_a->ix, GCALC_COORD_BASE);
- long double ay= gcalc_get_double(node->iy, GCALC_COORD_BASE) -
- gcalc_get_double(edge_a->iy, GCALC_COORD_BASE);
+ long double dx= gcalc_get_double(edge_b->node.shape.ix, GCALC_COORD_BASE) -
+ gcalc_get_double(edge_a->node.shape.ix, GCALC_COORD_BASE);
+ long double dy= gcalc_get_double(edge_b->node.shape.iy, GCALC_COORD_BASE) -
+ gcalc_get_double(edge_a->node.shape.iy, GCALC_COORD_BASE);
+ long double ax= gcalc_get_double(node->node.shape.ix, GCALC_COORD_BASE) -
+ gcalc_get_double(edge_a->node.shape.ix, GCALC_COORD_BASE);
+ long double ay= gcalc_get_double(node->node.shape.iy, GCALC_COORD_BASE) -
+ gcalc_get_double(edge_a->node.shape.iy, GCALC_COORD_BASE);
long double d= ax * dy - ay * dx;
if (result == 0)
GCALC_DBUG_ASSERT(de_check(d, 0.0));
@@ -1412,8 +1412,8 @@ static int cmp_tops(const Gcalc_heap::Info *top_node,
{
int cmp_res_a, cmp_res_b;
- cmp_res_a= gcalc_cmp_coord1(edge_a->ix, top_node->ix);
- cmp_res_b= gcalc_cmp_coord1(edge_b->ix, top_node->ix);
+ cmp_res_a= gcalc_cmp_coord1(edge_a->node.shape.ix, top_node->node.shape.ix);
+ cmp_res_b= gcalc_cmp_coord1(edge_b->node.shape.ix, top_node->node.shape.ix);
if (cmp_res_a <= 0 && cmp_res_b > 0)
return -1;
@@ -1438,26 +1438,26 @@ int Gcalc_scan_iterator::insert_top_node()
if (!sp0)
GCALC_DBUG_RETURN(1);
sp0->pi= m_cur_pi;
- sp0->next_pi= m_cur_pi->left;
+ sp0->next_pi= m_cur_pi->node.shape.left;
#ifndef GCALC_DBUG_OFF
sp0->thread= m_cur_thread++;
#endif /*GCALC_DBUG_OFF*/
- if (m_cur_pi->left)
+ if (m_cur_pi->node.shape.left)
{
calc_dx_dy(sp0);
- if (m_cur_pi->right)
+ if (m_cur_pi->node.shape.right)
{
if (!(sp1= new_slice_point()))
GCALC_DBUG_RETURN(1);
sp1->event= sp0->event= scev_two_threads;
sp1->pi= m_cur_pi;
- sp1->next_pi= m_cur_pi->right;
+ sp1->next_pi= m_cur_pi->node.shape.right;
#ifndef GCALC_DBUG_OFF
sp1->thread= m_cur_thread++;
#endif /*GCALC_DBUG_OFF*/
calc_dx_dy(sp1);
/* We have two threads so should decide which one will be first */
- cmp_res= cmp_tops(m_cur_pi, m_cur_pi->left, m_cur_pi->right);
+ cmp_res= cmp_tops(m_cur_pi, m_cur_pi->node.shape.left, m_cur_pi->node.shape.right);
if (cmp_res > 0)
{
point *tmp= sp0;
@@ -1467,7 +1467,7 @@ int Gcalc_scan_iterator::insert_top_node()
else if (cmp_res == 0)
{
/* Exactly same direction of the edges. */
- cmp_res= gcalc_cmp_coord1(m_cur_pi->left->iy, m_cur_pi->right->iy);
+ cmp_res= gcalc_cmp_coord1(m_cur_pi->node.shape.left->node.shape.iy, m_cur_pi->node.shape.right->node.shape.iy);
if (cmp_res != 0)
{
if (cmp_res < 0)
@@ -1483,7 +1483,7 @@ int Gcalc_scan_iterator::insert_top_node()
}
else
{
- cmp_res= gcalc_cmp_coord1(m_cur_pi->left->ix, m_cur_pi->right->ix);
+ cmp_res= gcalc_cmp_coord1(m_cur_pi->node.shape.left->node.shape.ix, m_cur_pi->node.shape.right->node.shape.ix);
if (cmp_res != 0)
{
if (cmp_res < 0)
@@ -1517,7 +1517,7 @@ int Gcalc_scan_iterator::insert_top_node()
/* We need to find the place to insert. */
for (; sp; prev_hook= sp->next_ptr(), sp=sp->get_next())
{
- if (sp->event || gcalc_cmp_coord1(*sp->r_border, m_cur_pi->ix) < 0)
+ if (sp->event || gcalc_cmp_coord1(*sp->r_border, m_cur_pi->node.shape.ix) < 0)
continue;
cmp_res= node_on_right(m_cur_pi, sp->pi, sp->next_pi);
if (cmp_res == 0)
@@ -1743,7 +1743,7 @@ int Gcalc_scan_iterator::node_scan()
GCALC_DBUG_PRINT(("node for %d", sp->thread));
/* Handle the point itself. */
sp->pi= cur_pi;
- sp->next_pi= cur_pi->left;
+ sp->next_pi= cur_pi->node.shape.left;
sp->event= scev_point;
calc_dx_dy(sp);
@@ -1794,7 +1794,7 @@ void Gcalc_scan_iterator::intersection_scan()
ii->edge_a->event= ii->edge_b->event= scev_intersection;
ii->edge_a->ev_pi= ii->edge_b->ev_pi= m_cur_pi;
free_item(ii);
- m_cur_pi->intersection_data= NULL;
+ m_cur_pi->node.intersection.data= NULL;
GCALC_DBUG_VOID_RETURN;
}
@@ -1813,7 +1813,7 @@ int Gcalc_scan_iterator::add_intersection(point *sp_a, point *sp_b,
!(ii= new_intersection(m_heap, i_calc)))
GCALC_DBUG_RETURN(1);
- ii->equal_intersection= 0;
+ ii->node.intersection.equal= 0;
for (;
pi_from->get_next() != sp_a->next_pi &&
@@ -1824,7 +1824,7 @@ int Gcalc_scan_iterator::add_intersection(point *sp_a, point *sp_b,
if (skip_next)
{
if (cur->type == Gcalc_heap::nt_intersection)
- skip_next= cur->equal_intersection;
+ skip_next= cur->node.intersection.equal;
else
skip_next= 0;
continue;
@@ -1832,7 +1832,7 @@ int Gcalc_scan_iterator::add_intersection(point *sp_a, point *sp_b,
if (cur->type == Gcalc_heap::nt_intersection)
{
cmp_res= cmp_intersections(cur, ii);
- skip_next= cur->equal_intersection;
+ skip_next= cur->node.intersection.equal;
}
else if (cur->type == Gcalc_heap::nt_eq_node)
continue;
@@ -1840,7 +1840,7 @@ int Gcalc_scan_iterator::add_intersection(point *sp_a, point *sp_b,
cmp_res= cmp_node_isc(cur, ii);
if (cmp_res == 0)
{
- ii->equal_intersection= 1;
+ ii->node.intersection.equal= 1;
break;
}
else if (cmp_res > 0)
@@ -1881,13 +1881,13 @@ void calc_t(Gcalc_coord2 t_a, Gcalc_coord2 t_b,
Gcalc_coord2 x1y2, x2y1;
Gcalc_coord1 dya, dyb;
- gcalc_sub_coord1(a2_a1x, p3->ix, p1->ix);
- gcalc_sub_coord1(a2_a1y, p3->iy, p1->iy);
+ gcalc_sub_coord1(a2_a1x, p3->node.shape.ix, p1->node.shape.ix);
+ gcalc_sub_coord1(a2_a1y, p3->node.shape.iy, p1->node.shape.iy);
- gcalc_sub_coord1(dxa, p2->ix, p1->ix);
- gcalc_sub_coord1(dya, p2->iy, p1->iy);
- gcalc_sub_coord1(dxb, p4->ix, p3->ix);
- gcalc_sub_coord1(dyb, p4->iy, p3->iy);
+ gcalc_sub_coord1(dxa, p2->node.shape.ix, p1->node.shape.ix);
+ gcalc_sub_coord1(dya, p2->node.shape.iy, p1->node.shape.iy);
+ gcalc_sub_coord1(dxb, p4->node.shape.ix, p3->node.shape.ix);
+ gcalc_sub_coord1(dyb, p4->node.shape.iy, p3->node.shape.iy);
gcalc_mul_coord1(x1y2, dxa, dyb);
gcalc_mul_coord1(x2y1, dya, dxb);
@@ -1908,11 +1908,11 @@ double Gcalc_scan_iterator::get_y() const
Gcalc_coord2 t_a, t_b;
Gcalc_coord3 a_tb, b_ta, y_exp;
calc_t(t_a, t_b, dxa, dya,
- state.pi->p1, state.pi->p2, state.pi->p3, state.pi->p4);
+ state.pi->node.intersection.p1, state.pi->node.intersection.p2, state.pi->node.intersection.p3, state.pi->node.intersection.p4);
gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
- t_b, GCALC_COORD_BASE2, state.pi->p1->iy, GCALC_COORD_BASE);
+ t_b, GCALC_COORD_BASE2, state.pi->node.intersection.p1->node.shape.iy, GCALC_COORD_BASE);
gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
t_a, GCALC_COORD_BASE2, dya, GCALC_COORD_BASE);
@@ -1922,7 +1922,7 @@ double Gcalc_scan_iterator::get_y() const
get_pure_double(t_b, GCALC_COORD_BASE2)) / m_heap->coord_extent;
}
else
- return state.pi->y;
+ return state.pi->node.shape.y;
}
@@ -1934,11 +1934,11 @@ double Gcalc_scan_iterator::get_event_x() const
Gcalc_coord2 t_a, t_b;
Gcalc_coord3 a_tb, b_ta, x_exp;
calc_t(t_a, t_b, dxa, dya,
- state.pi->p1, state.pi->p2, state.pi->p3, state.pi->p4);
+ state.pi->node.intersection.p1, state.pi->node.intersection.p2, state.pi->node.intersection.p3, state.pi->node.intersection.p4);
gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
- t_b, GCALC_COORD_BASE2, state.pi->p1->ix, GCALC_COORD_BASE);
+ t_b, GCALC_COORD_BASE2, state.pi->node.intersection.p1->node.shape.ix, GCALC_COORD_BASE);
gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
t_a, GCALC_COORD_BASE2, dxa, GCALC_COORD_BASE);
@@ -1948,7 +1948,7 @@ double Gcalc_scan_iterator::get_event_x() const
get_pure_double(t_b, GCALC_COORD_BASE2)) / m_heap->coord_extent;
}
else
- return state.pi->x;
+ return state.pi->node.shape.x;
}
double Gcalc_scan_iterator::get_h() const
@@ -1961,7 +1961,7 @@ double Gcalc_scan_iterator::get_h() const
state.pi->calc_xy(&x, &next_y);
}
else
- next_y= state.pi->next ? state.pi->get_next()->y : 0.0;
+ next_y= state.pi->next ? state.pi->get_next()->node.shape.y : 0.0;
return next_y - cur_y;
}
@@ -1970,11 +1970,11 @@ double Gcalc_scan_iterator::get_sp_x(const point *sp) const
{
double dy;
if (sp->event & (scev_end | scev_two_ends | scev_point))
- return sp->pi->x;
- dy= sp->next_pi->y - sp->pi->y;
+ return sp->pi->node.shape.x;
+ dy= sp->next_pi->node.shape.y - sp->pi->node.shape.y;
if (fabs(dy) < 1e-12)
- return sp->pi->x;
- return sp->pi->x + (sp->next_pi->x - sp->pi->x) * dy;
+ return sp->pi->node.shape.x;
+ return sp->pi->node.shape.x + (sp->next_pi->node.shape.x - sp->pi->node.shape.x) * dy;
}
diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h
index 55de497f1ee..5a0399bc8da 100644
--- a/sql/gcalc_slicescan.h
+++ b/sql/gcalc_slicescan.h
@@ -188,7 +188,7 @@ public:
double x,y;
Gcalc_coord1 ix, iy;
int top_node;
- };
+ } shape;
struct
{
/* nt_intersection */
@@ -197,21 +197,21 @@ public:
const Info *p2;
const Info *p3;
const Info *p4;
- void *intersection_data;
- int equal_intersection;
- };
+ void *data;
+ int equal;
+ } intersection;
struct
{
/* nt_eq_node */
const Info *node;
- void *eq_data;
- };
- };
+ void *data;
+ } eq;
+ } node;
bool is_bottom() const
- { GCALC_DBUG_ASSERT(type == nt_shape_node); return !left; }
+ { GCALC_DBUG_ASSERT(type == nt_shape_node); return !node.shape.left; }
bool is_top() const
- { GCALC_DBUG_ASSERT(type == nt_shape_node); return top_node; }
+ { GCALC_DBUG_ASSERT(type == nt_shape_node); return node.shape.top_node; }
bool is_single_node() const
{ return is_bottom() && is_top(); }
@@ -383,7 +383,7 @@ public:
inline const point *c_get_next() const
{ return (const point *)next; }
inline bool is_bottom() const { return !next_pi; }
- gcalc_shape_info get_shape() const { return pi->shape; }
+ gcalc_shape_info get_shape() const { return pi->node.shape.shape; }
inline point *get_next() { return (point *)next; }
inline const point *get_next() const { return (const point *)next; }
/* Compare the dx_dy parameters regarding the horiz_dir */
diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc
index 5aac8a71249..da0252c6b67 100644
--- a/sql/gcalc_tools.cc
+++ b/sql/gcalc_tools.cc
@@ -1278,7 +1278,7 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res,
GCALC_DBUG_RETURN(1);
}
else
- if (storage->single_point(res->pi->x, res->pi->y))
+ if (storage->single_point(res->pi->node.shape.x, res->pi->node.shape.y))
GCALC_DBUG_RETURN(1);
free_result(res);
GCALC_DBUG_RETURN(0);
@@ -1304,8 +1304,8 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur,
}
else
{
- x= cur->pi->x;
- y= cur->pi->y;
+ x= cur->pi->node.shape.x;
+ y= cur->pi->node.shape.y;
}
if (storage->add_point(x, y))
GCALC_DBUG_RETURN(1);
diff --git a/sql/handler.cc b/sql/handler.cc
index 993d337a4bb..718bae8ea52 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -4224,7 +4224,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES;
if (table->file->check_if_incompatible_data(create_info, table_changes)
== COMPATIBLE_DATA_YES)
- DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
+ DBUG_RETURN(HA_ALTER_INPLACE_NO_LOCK);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
@@ -5604,15 +5604,17 @@ inline bool handler::check_table_binlog_row_based(bool binlog_row)
bool handler::check_table_binlog_row_based_internal(bool binlog_row)
{
- THD *thd;
+ THD *thd= table->in_use;
+#ifdef WITH_WSREP
/* only InnoDB tables will be replicated through binlog emulation */
if (binlog_row &&
- WSREP_EMULATE_BINLOG(thd) &&
- table->file->partition_ht()->db_type != DB_TYPE_INNODB)
+ ((WSREP_EMULATE_BINLOG(thd) &&
+ table->file->partition_ht()->db_type != DB_TYPE_INNODB) ||
+ (thd->wsrep_ignore_table == true)))
return 0;
+#endif
- thd= table->in_use;
return (table->s->cached_row_logging_check &&
thd->is_current_stmt_binlog_format_row() &&
/*
diff --git a/sql/item.cc b/sql/item.cc
index 55bd62188b4..e47974408f4 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2010, 2015, MariaDB
+ Copyright (c) 2010, 2016, 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
@@ -2339,7 +2339,7 @@ bool Item_field::update_table_bitmaps_processor(uchar *arg)
static inline void set_field_to_new_field(Field **field, Field **new_field)
{
- if (*field)
+ if (*field && (*field)->table == new_field[0]->table)
{
Field *newf= new_field[(*field)->field_index];
if ((*field)->ptr == newf->ptr)
@@ -2352,6 +2352,7 @@ bool Item_field::switch_to_nullable_fields_processor(uchar *arg)
Field **new_fields= (Field **)arg;
set_field_to_new_field(&field, new_fields);
set_field_to_new_field(&result_field, new_fields);
+ maybe_null= field && field->maybe_null();
return 0;
}
diff --git a/sql/item.h b/sql/item.h
index d0e4372d53f..9954b0ab31d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2,7 +2,7 @@
#define SQL_ITEM_INCLUDED
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index dc457ed6484..44dc8ff9e09 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
@@ -2579,7 +2579,7 @@ Item_func_nullif::fix_length_and_dec()
args[0] and args[2] should still point to the same original l_expr.
*/
DBUG_ASSERT(args[0] == args[2] || thd->stmt_arena->is_stmt_execute());
- if (args[0]->type() == SUM_FUNC_ITEM)
+ if (args[0]->type() == SUM_FUNC_ITEM && !thd->lex->context_analysis_only)
{
/*
NULLIF(l_expr, r_expr)
@@ -2703,7 +2703,8 @@ Item_func_nullif::fix_length_and_dec()
m_cache->setup(current_thd, args[0]);
m_cache->store(args[0]);
m_cache->set_used_tables(args[0]->used_tables());
- args[0]= args[2]= m_cache;
+ thd->change_item_tree(&args[0], m_cache);
+ thd->change_item_tree(&args[2], m_cache);
}
set_handler_by_field_type(args[2]->field_type());
collation.set(args[2]->collation);
@@ -2751,7 +2752,7 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
Note, the EXPLAIN EXTENDED and EXPLAIN FORMAT=JSON routines
do pass QT_ITEM_FUNC_NULLIF_TO_CASE to print().
*/
- DBUG_ASSERT(args[0] == args[2]);
+ DBUG_ASSERT(args[0] == args[2] || current_thd->lex->context_analysis_only);
str->append(func_name());
str->append('(');
args[2]->print(str, query_type);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index af9e008375a..717e9e59ddf 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,7 +1,7 @@
#ifndef ITEM_CMPFUNC_INCLUDED
#define ITEM_CMPFUNC_INCLUDED
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 352c9fd93b9..39d06fd7a26 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -436,7 +436,7 @@ String *Item_func_convexhull::val_str(String *str_value)
if (!cur_pi->get_next())
{
/* Single point. */
- if (res_receiver.single_point(cur_pi->x, cur_pi->y))
+ if (res_receiver.single_point(cur_pi->node.shape.x, cur_pi->node.shape.y))
goto mem_error;
goto build_result;
}
@@ -461,8 +461,8 @@ String *Item_func_convexhull::val_str(String *str_value)
{
/* We only have 2 nodes in the result, so we create a polyline. */
if (res_receiver.start_shape(Gcalc_function::shape_line) ||
- res_receiver.add_point(left_first->pi->x, left_first->pi->y) ||
- res_receiver.add_point(left_cur->pi->x, left_cur->pi->y) ||
+ res_receiver.add_point(left_first->pi->node.shape.x, left_first->pi->node.shape.y) ||
+ res_receiver.add_point(left_cur->pi->node.shape.x, left_cur->pi->node.shape.y) ||
res_receiver.complete_shape())
goto mem_error;
@@ -475,7 +475,7 @@ String *Item_func_convexhull::val_str(String *str_value)
while (left_first)
{
- if (res_receiver.add_point(left_first->pi->x, left_first->pi->y))
+ if (res_receiver.add_point(left_first->pi->node.shape.x, left_first->pi->node.shape.y))
goto mem_error;
left_first= left_first->get_next();
}
@@ -485,7 +485,7 @@ String *Item_func_convexhull::val_str(String *str_value)
right_cur= right_cur->prev;
while (right_cur->prev)
{
- if (res_receiver.add_point(right_cur->pi->x, right_cur->pi->y))
+ if (res_receiver.add_point(right_cur->pi->node.shape.x, right_cur->pi->node.shape.y))
goto mem_error;
right_cur= right_cur->prev;
}
@@ -1105,10 +1105,10 @@ static double count_edge_t(const Gcalc_heap::Info *ea,
double &ex, double &ey, double &vx, double &vy,
double &e_sqrlen)
{
- ex= eb->x - ea->x;
- ey= eb->y - ea->y;
- vx= v->x - ea->x;
- vy= v->y - ea->y;
+ ex= eb->node.shape.x - ea->node.shape.x;
+ ey= eb->node.shape.y - ea->node.shape.y;
+ vx= v->node.shape.x - ea->node.shape.x;
+ vy= v->node.shape.y - ea->node.shape.y;
e_sqrlen= ex * ex + ey * ey;
return (ex * vx + ey * vy) / e_sqrlen;
}
@@ -1124,8 +1124,8 @@ static double distance_to_line(double ex, double ey, double vx, double vy,
static double distance_points(const Gcalc_heap::Info *a,
const Gcalc_heap::Info *b)
{
- double x= a->x - b->x;
- double y= a->y - b->y;
+ double x= a->node.shape.x - b->node.shape.x;
+ double y= a->node.shape.y - b->node.shape.y;
return sqrt(x * x + y * y);
}
@@ -2333,7 +2333,7 @@ double Item_func_distance::val_real()
continue;
count_distance:
- if (cur_point->shape >= obj2_si)
+ if (cur_point->node.shape.shape >= obj2_si)
continue;
cur_point_edge= !cur_point->is_bottom();
@@ -2341,13 +2341,13 @@ count_distance:
{
/* We only check vertices of object 2 */
if (dist_point->type != Gcalc_heap::nt_shape_node ||
- dist_point->shape < obj2_si)
+ dist_point->node.shape.shape < obj2_si)
continue;
/* if we have an edge to check */
- if (dist_point->left)
+ if (dist_point->node.shape.left)
{
- t= count_edge_t(dist_point, dist_point->left, cur_point,
+ t= count_edge_t(dist_point, dist_point->node.shape.left, cur_point,
ex, ey, vx, vy, e_sqrlen);
if ((t>0.0) && (t<1.0))
{
@@ -2358,7 +2358,7 @@ count_distance:
}
if (cur_point_edge)
{
- t= count_edge_t(cur_point, cur_point->left, dist_point,
+ t= count_edge_t(cur_point, cur_point->node.shape.left, dist_point,
ex, ey, vx, vy, e_sqrlen);
if ((t>0.0) && (t<1.0))
{
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e22718029e5..7c1c5f7da7d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1564,7 +1564,7 @@ String *Item_func_insert::val_str(String *str)
length= res->charpos((int) length, (uint32) start);
/* Re-testing with corrected params */
- if (start > res->length())
+ if (start + 1 > res->length()) // remember, start = args[1].val_int() - 1
return res; /* purecov: inspected */ // Wrong param; skip insert
if (length > res->length() - start)
length= res->length() - start;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 6444f672176..f22716d3d81 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -5329,6 +5329,7 @@ int subselect_hash_sj_engine::exec()
item_in->reset();
item_in->make_const();
item_in->set_first_execution();
+ thd->lex->current_select= save_select;
DBUG_RETURN(FALSE);
}
@@ -5372,6 +5373,7 @@ int subselect_hash_sj_engine::exec()
item_in->null_value= 1;
item_in->make_const();
item_in->set_first_execution();
+ thd->lex->current_select= save_select;
DBUG_RETURN(FALSE);
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 4cc9f6dc5bc..16edb35c392 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab
+ Copyright (c) 2009, 2016, 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
@@ -2995,7 +2995,7 @@ void Item_func_timestamp_diff::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN("SECOND"));
break;
case INTERVAL_MICROSECOND:
- str->append(STRING_WITH_LEN("SECOND_FRAC"));
+ str->append(STRING_WITH_LEN("MICROSECOND"));
break;
default:
break;
diff --git a/sql/log.cc b/sql/log.cc
index 7f162b92118..33bd48b3c21 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ff2f9594922..e99ef164064 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2014, Monty Program Ab.
+ Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2016, 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
@@ -3525,7 +3525,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
- db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
+ db_len = (uchar)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
/*
@@ -9895,7 +9895,18 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
}
#ifdef HAVE_QUERY_CACHE
+#ifdef WITH_WSREP
+ /*
+ Moved invalidation right before the call to rows_event_stmt_cleanup(),
+ to avoid query cache being polluted with stale entries.
+ */
+ if (! (WSREP(thd) && (thd->wsrep_exec_mode == REPL_RECV)))
+ {
+#endif /* WITH_WSREP */
query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
#endif
}
@@ -10087,6 +10098,14 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
/* remove trigger's tables */
if (slave_run_triggers_for_rbr)
restore_empty_query_table_list(thd->lex);
+
+#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
+ if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
+ {
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+ }
+#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
+
if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rgi, thd)))
slave_rows_error_report(ERROR_LEVEL,
thd->is_error() ? 0 : error,
@@ -11128,8 +11147,8 @@ bool Table_map_log_event::write_data_body()
DBUG_ASSERT(m_dbnam != NULL);
DBUG_ASSERT(m_tblnam != NULL);
/* We use only one byte per length for storage in event: */
- DBUG_ASSERT(m_dblen < 128);
- DBUG_ASSERT(m_tbllen < 128);
+ DBUG_ASSERT(m_dblen <= MY_MIN(NAME_LEN, 255));
+ DBUG_ASSERT(m_tbllen <= MY_MIN(NAME_LEN, 255));
uchar const dbuf[]= { (uchar) m_dblen };
uchar const tbuf[]= { (uchar) m_tbllen };
@@ -11352,6 +11371,7 @@ bool Rows_log_event::process_triggers(trg_event_type event,
{
bool result;
DBUG_ENTER("Rows_log_event::process_triggers");
+ m_table->triggers->mark_fields_used(event);
if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
{
tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
@@ -12316,7 +12336,11 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE))
error= HA_ERR_GENERIC; // in case if error is not set yet
if (!error)
+ {
+ m_table->mark_columns_per_binlog_row_image();
error= m_table->file->ha_delete_row(m_table->record[0]);
+ m_table->default_column_bitmaps();
+ }
if (invoke_triggers && !error &&
process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE))
error= HA_ERR_GENERIC; // in case if error is not set yet
diff --git a/sql/mdl.cc b/sql/mdl.cc
index ab4f5288d4a..61591ec9f57 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -1064,7 +1064,16 @@ MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
wait_result != ETIMEDOUT && wait_result != ETIME)
{
#ifdef WITH_WSREP
- if (wsrep_thd_is_BF(owner->get_thd(), true))
+ // Allow tests to block the applier thread using the DBUG facilities
+ DBUG_EXECUTE_IF("sync.wsrep_before_mdl_wait",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.wsrep_before_mdl_wait";
+ DBUG_ASSERT(!debug_sync_set_action((owner->get_thd()),
+ STRING_WITH_LEN(act)));
+ };);
+ if (wsrep_thd_is_BF(owner->get_thd(), false))
{
wait_result= mysql_cond_wait(&m_COND_wait_status, &m_LOCK_wait_status);
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e819f003ab9..bd456bbe85e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2015, MariaDB
+ Copyright (c) 2008, 2016, 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
@@ -1501,7 +1501,6 @@ static openssl_lock_t *openssl_dynlock_create(const char *, int);
static void openssl_dynlock_destroy(openssl_lock_t *, const char *, int);
static void openssl_lock_function(int, int, const char *, int);
static void openssl_lock(int, openssl_lock_t *, const char *, int);
-static unsigned long openssl_id_function();
#endif
char *des_key_file;
#ifndef EMBEDDED_LIBRARY
@@ -4730,7 +4729,6 @@ static int init_thread_environment()
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy);
CRYPTO_set_dynlock_lock_callback(openssl_lock);
CRYPTO_set_locking_callback(openssl_lock_function);
- CRYPTO_set_id_callback(openssl_id_function);
#endif
#endif
mysql_rwlock_init(key_rwlock_LOCK_sys_init_connect, &LOCK_sys_init_connect);
@@ -4767,12 +4765,6 @@ static int init_thread_environment()
#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL)
-static unsigned long openssl_id_function()
-{
- return (unsigned long) pthread_self();
-}
-
-
static openssl_lock_t *openssl_dynlock_create(const char *file, int line)
{
openssl_lock_t *lock= new openssl_lock_t;
@@ -8753,7 +8745,7 @@ static int mysql_init_variables(void)
executed_events= 0;
global_query_id= 1;
global_thread_id= 0;
- strmov(server_version, MYSQL_SERVER_VERSION);
+ strnmov(server_version, MYSQL_SERVER_VERSION, sizeof(server_version)-1);
threads.empty();
thread_cache.empty();
key_caches.empty();
@@ -9673,17 +9665,20 @@ void set_server_version(void)
{
if (!IS_SYSVAR_AUTOSIZE(&server_version_ptr))
return;
- char *end= strxmov(server_version, MYSQL_SERVER_VERSION,
- MYSQL_SERVER_SUFFIX_STR, NullS);
+ char *version_end= server_version+sizeof(server_version)-1;
+ char *end= strxnmov(server_version, sizeof(server_version)-1,
+ MYSQL_SERVER_VERSION,
+ MYSQL_SERVER_SUFFIX_STR, NullS);
#ifdef EMBEDDED_LIBRARY
- end= strmov(end, "-embedded");
+ end= strnmov(end, "-embedded", (version_end-end));
#endif
#ifndef DBUG_OFF
if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug"))
- end= strmov(end, "-debug");
+ end= strnmov(end, "-debug", (version_end-end));
#endif
if (opt_log || global_system_variables.sql_log_slow || opt_bin_log)
- strmov(end, "-log"); // This may slow down system
+ strnmov(end, "-log", (version_end-end)); // This may slow down system
+ *end= 0;
}
@@ -9989,7 +9984,7 @@ void refresh_status(THD *thd)
Set max_used_connections to the number of currently open
connections. This is not perfect, but status data is not exact anyway.
*/
- max_used_connections= thread_count-delayed_insert_threads;
+ max_used_connections= connection_count + extra_connection_count;
}
#ifdef HAVE_PSI_INTERFACE
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index fa04f6d2637..c1052869c8f 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -833,12 +833,14 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
in_subs->sjm_scan_allowed= FALSE;
bool all_are_fields= TRUE;
+ uint32 total_key_length = 0;
for (uint i= 0; i < elements; i++)
{
Item *outer= in_subs->left_expr->element_index(i);
Item *inner= it++;
all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM &&
inner->real_item()->type() == Item::FIELD_ITEM);
+ total_key_length += inner->max_length;
if (outer->cmp_type() != inner->cmp_type())
DBUG_RETURN(FALSE);
switch (outer->cmp_type()) {
@@ -869,6 +871,15 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
}
}
+ /*
+ Make sure that create_tmp_table will not fail due to too long keys.
+ See MDEV-7122. This check is performed inside create_tmp_table also and
+ we must do it so that we know the table has keys created.
+ */
+ if (total_key_length > tmp_table_max_key_length() ||
+ elements > tmp_table_max_key_parts())
+ DBUG_RETURN(FALSE);
+
in_subs->types_allow_materialization= TRUE;
in_subs->sjm_scan_allowed= all_are_fields;
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
@@ -5533,7 +5544,8 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
outer join has not been optimized yet).
*/
if (outer_join && outer_join->table_count > 0 && // (1)
- outer_join->join_tab) // (2)
+ outer_join->join_tab && // (2)
+ !in_subs->const_item())
{
/*
TODO:
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 47c0f4e3fb7..f54ef2b0081 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -567,7 +567,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
Updates in slave state table should not be appended to galera transaction
writeset.
*/
- thd->wsrep_skip_append_keys= true;
+ thd->wsrep_ignore_table= true;
#endif
if (!in_transaction)
@@ -685,7 +685,7 @@ IF_DBUG(dbug_break:, )
end:
#ifdef WITH_WSREP
- thd->wsrep_skip_append_keys= false;
+ thd->wsrep_ignore_table= false;
#endif
if (table_opened)
diff --git a/sql/rpl_reporting.cc b/sql/rpl_reporting.cc
index 49708df40f7..ad949402511 100644
--- a/sql/rpl_reporting.cc
+++ b/sql/rpl_reporting.cc
@@ -59,6 +59,7 @@ Slave_reporting_capability::report(loglevel level, int err_code,
report_function= sql_print_information;
break;
default:
+ va_end(args);
DBUG_ASSERT(0); // should not come here
return; // don't crash production builds, just do nothing
}
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 244363e43ac..bdf5b7dea80 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -15,6 +15,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <my_global.h>
+#include <my_bit.h>
#include "rpl_utility.h"
#include "log_event.h"
@@ -23,30 +24,6 @@
#include "sql_select.h"
/**
- Function to compare two size_t integers for their relative
- order. Used below.
- */
-int compare(size_t a, size_t b)
-{
- if (a < b)
- return -1;
- if (b < a)
- return 1;
- return 0;
-}
-
-
-/**
- Max value for an unsigned integer of 'bits' bits.
-
- The somewhat contorted expression is to avoid overflow.
- */
-uint32 uint_max(int bits) {
- return (((1UL << (bits - 1)) - 1) << 1) | 1;
-}
-
-
-/**
Calculate display length for MySQL56 temporal data types from their metadata.
It contains fractional precision in the low 16-bit word.
*/
@@ -121,20 +98,22 @@ max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
return 3;
case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
return 3;
+ case MYSQL_TYPE_TIME:
+ return MIN_TIME_WIDTH;
+
case MYSQL_TYPE_TIME2:
return max_display_length_for_temporal2_field(MIN_TIME_WIDTH, metadata);
case MYSQL_TYPE_TIMESTAMP:
- return 4;
+ return MAX_DATETIME_WIDTH;
case MYSQL_TYPE_TIMESTAMP2:
return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata);
case MYSQL_TYPE_DATETIME:
- return 8;
+ return MAX_DATETIME_WIDTH;
case MYSQL_TYPE_DATETIME2:
return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata);
@@ -160,10 +139,10 @@ max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
*/
case MYSQL_TYPE_TINY_BLOB:
- return uint_max(1 * 8);
+ return my_set_bits(1 * 8);
case MYSQL_TYPE_MEDIUM_BLOB:
- return uint_max(3 * 8);
+ return my_set_bits(3 * 8);
case MYSQL_TYPE_BLOB:
/*
@@ -171,11 +150,11 @@ max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look
at the length instead to decide what the max display size is.
*/
- return uint_max(metadata * 8);
+ return my_set_bits(metadata * 8);
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_GEOMETRY:
- return uint_max(4 * 8);
+ return my_set_bits(4 * 8);
default:
return ~(uint32) 0;
@@ -205,7 +184,7 @@ int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata)
" target_length: %lu, target_type: %u",
(unsigned long) source_length, source_type,
(unsigned long) target_length, field->real_type()));
- int result= compare(source_length, target_length);
+ int result= source_length < target_length ? -1 : source_length > target_length;
DBUG_PRINT("result", ("%d", result));
DBUG_RETURN(result);
}
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index d8ca8633baa..8b58f062a3e 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2010, 2014, Oracle and/or its affiliates.
- Copyright (c) 2012, 2015, MariaDB
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2016, 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
@@ -288,7 +288,8 @@ static inline bool table_not_corrupt_error(uint sql_errno)
sql_errno == ER_LOCK_WAIT_TIMEOUT ||
sql_errno == ER_LOCK_DEADLOCK ||
sql_errno == ER_CANT_LOCK_LOG_TABLE ||
- sql_errno == ER_OPEN_AS_READONLY);
+ sql_errno == ER_OPEN_AS_READONLY ||
+ sql_errno == ER_WRONG_OBJECT);
}
@@ -399,7 +400,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
lex->query_tables_last= &table->next_global;
lex->query_tables_own_last= 0;
- if (view_operator_func == NULL)
+ /*
+ CHECK TABLE command is allowed for views as well. Check on alter flags
+ to differentiate from ALTER TABLE...CHECK PARTITION on which view is not
+ allowed.
+ */
+ if (lex->alter_info.flags & Alter_info::ALTER_ADMIN_PARTITION ||
+ view_operator_func == NULL)
{
table->required_type=FRMTYPE_TABLE;
DBUG_ASSERT(!lex->only_view);
@@ -1199,9 +1206,8 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
FALSE, UINT_MAX, FALSE))
goto error;
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
thd->enable_slow_log= opt_log_slow_admin_statements;
- WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL);
-
res= mysql_admin_table(thd, first_table, &m_lex->check_opt,
"analyze", lock_type, 1, 0, 0, 0,
&handler::ha_analyze, 0);
@@ -1256,7 +1262,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
- WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & SPECIAL_NO_NEW_FUNC) ?
mysql_recreate_table(thd, first_table, true) :
@@ -1290,7 +1296,7 @@ bool Sql_cmd_repair_table::execute(THD *thd)
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
- WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair",
TL_WRITE, 1,
MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM),
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 34a618aba98..d65b6235f01 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2015, MariaDB
+ Copyright (c) 2010, 2016, 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
@@ -168,11 +168,6 @@ static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables,
TABLE_SHARE *table_share);
static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry);
static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
-static bool
-has_write_table_with_auto_increment(TABLE_LIST *tables);
-static bool
-has_write_table_with_auto_increment_and_select(TABLE_LIST *tables);
-static bool has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables);
/**
@@ -2295,6 +2290,16 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
*/
if (dd_frm_is_view(thd, path))
{
+ /*
+ If parent_l of the table_list is non null then a merge table
+ has this view as child table, which is not supported.
+ */
+ if (table_list->parent_l)
+ {
+ my_error(ER_WRONG_MRG_TABLE, MYF(0));
+ DBUG_RETURN(true);
+ }
+
if (!tdc_open_view(thd, table_list, alias, key, key_length,
CHECK_METADATA_VERSION))
{
@@ -5417,65 +5422,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
*(ptr++)= table->table;
}
- /*
- DML statements that modify a table with an auto_increment column based on
- rows selected from a table are unsafe as the order in which the rows are
- fetched fron the select tables cannot be determined and may differ on
- master and slave.
- */
- if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables &&
- has_write_table_with_auto_increment_and_select(tables))
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
- /* Todo: merge all has_write_table_auto_inc with decide_logging_format */
- if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables)
- {
- if (has_write_table_auto_increment_not_first_in_pk(tables))
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
- }
-
-#ifdef NOT_USED_IN_MARIADB
- /*
- INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys
- can be unsafe.
- */
- uint unique_keys= 0;
- for (TABLE_LIST *query_table= tables; query_table && unique_keys <= 1;
- query_table= query_table->next_global)
- if(query_table->table)
- {
- uint keys= query_table->table->s->keys, i= 0;
- unique_keys= 0;
- for (KEY* keyinfo= query_table->table->s->key_info;
- i < keys && unique_keys <= 1; i++, keyinfo++)
- {
- if (keyinfo->flags & HA_NOSAME)
- unique_keys++;
- }
- if (!query_table->placeholder() &&
- query_table->lock_type >= TL_WRITE_ALLOW_WRITE &&
- unique_keys > 1 && thd->lex->sql_command == SQLCOM_INSERT &&
- /* Duplicate key update is not supported by INSERT DELAYED */
- thd->get_command() != COM_DELAYED_INSERT &&
- thd->lex->duplicates == DUP_UPDATE)
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
- }
-#endif
-
- /* We have to emulate LOCK TABLES if we are statement needs prelocking. */
- if (thd->lex->requires_prelocking())
- {
-
- /*
- A query that modifies autoinc column in sub-statement can make the
- master and slave inconsistent.
- We can solve these problems in mixed mode by switching to binlogging
- if at least one updated table is used by sub-statement
- */
- if (thd->wsrep_binlog_format() != BINLOG_FORMAT_ROW && tables &&
- has_write_table_with_auto_increment(thd->lex->first_not_own_table()))
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
- }
-
DEBUG_SYNC(thd, "before_lock_tables_takes_lock");
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
@@ -9270,98 +9216,6 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
return a->length == b->length && !strncmp(a->str, b->str, a->length);
}
-
-/*
- Tells if two (or more) tables have auto_increment columns and we want to
- lock those tables with a write lock.
-
- SYNOPSIS
- has_two_write_locked_tables_with_auto_increment
- tables Table list
-
- NOTES:
- Call this function only when you have established the list of all tables
- which you'll want to update (including stored functions, triggers, views
- inside your statement).
-*/
-
-static bool
-has_write_table_with_auto_increment(TABLE_LIST *tables)
-{
- for (TABLE_LIST *table= tables; table; table= table->next_global)
- {
- /* we must do preliminary checks as table->table may be NULL */
- if (!table->placeholder() &&
- table->table->found_next_number_field &&
- (table->lock_type >= TL_WRITE_ALLOW_WRITE))
- return 1;
- }
-
- return 0;
-}
-
-/*
- checks if we have select tables in the table list and write tables
- with auto-increment column.
-
- SYNOPSIS
- has_two_write_locked_tables_with_auto_increment_and_select
- tables Table list
-
- RETURN VALUES
-
- -true if the table list has atleast one table with auto-increment column
-
-
- and atleast one table to select from.
- -false otherwise
-*/
-
-static bool
-has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
-{
- bool has_select= false;
- bool has_auto_increment_tables = has_write_table_with_auto_increment(tables);
- for(TABLE_LIST *table= tables; table; table= table->next_global)
- {
- if (!table->placeholder() &&
- (table->lock_type <= TL_READ_NO_INSERT))
- {
- has_select= true;
- break;
- }
- }
- return(has_select && has_auto_increment_tables);
-}
-
-/*
- Tells if there is a table whose auto_increment column is a part
- of a compound primary key while is not the first column in
- the table definition.
-
- @param tables Table list
-
- @return true if the table exists, fais if does not.
-*/
-
-static bool
-has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables)
-{
- for (TABLE_LIST *table= tables; table; table= table->next_global)
- {
- /* we must do preliminary checks as table->table may be NULL */
- if (!table->placeholder() &&
- table->table->found_next_number_field &&
- (table->lock_type >= TL_WRITE_ALLOW_WRITE)
- && table->table->s->next_number_keypart != 0)
- return 1;
- }
-
- return 0;
-}
-
-
-
/*
Open and lock system tables for read.
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 03505dec0cf..91dd8ad7325 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1933,6 +1933,13 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.autocommit));
memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
(uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
+
+#ifdef WITH_WSREP
+ bool once_more;
+ once_more= true;
+lookup:
+#endif /* WITH_WSREP */
+
query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql,
tot_length);
/* Quick abort on unlocked data */
@@ -1945,6 +1952,19 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block));
+#ifdef WITH_WSREP
+ if (once_more && WSREP_CLIENT(thd) && wsrep_must_sync_wait(thd))
+ {
+ unlock();
+ if (wsrep_sync_wait(thd))
+ goto err;
+ if (try_lock(thd, Query_cache::TIMEOUT))
+ goto err;
+ once_more= false;
+ goto lookup;
+ }
+#endif /* WITH_WSREP */
+
/* Now lock and test that nothing changed while blocks was unlocked */
BLOCK_LOCK_RD(query_block);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c1f64c89e1b..38289b188b2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2015, MariaDB
+ Copyright (c) 2008, 2016, 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
@@ -896,7 +896,7 @@ THD::THD(bool is_wsrep_applier)
wsrep_po_handle(WSREP_PO_INITIALIZER),
wsrep_po_cnt(0),
wsrep_apply_format(0),
- wsrep_skip_append_keys(false)
+ wsrep_ignore_table(false)
#endif
{
ulong tmp;
@@ -1021,6 +1021,7 @@ THD::THD(bool is_wsrep_applier)
wsrep_TOI_pre_query = NULL;
wsrep_TOI_pre_query_len = 0;
wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */
+ wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -1441,7 +1442,8 @@ void THD::init(void)
wsrep_mysql_replicated = 0;
wsrep_TOI_pre_query = NULL;
wsrep_TOI_pre_query_len = 0;
-#endif
+ wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
+#endif /* WITH_WSREP */
if (variables.sql_log_bin)
variables.option_bits|= OPTION_BIN_LOG;
@@ -2204,6 +2206,10 @@ void THD::cleanup_after_query()
rgi_slave->cleanup_after_query();
#endif
+#ifdef WITH_WSREP
+ wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+#endif /* WITH_WSREP */
+
DBUG_VOID_RETURN;
}
@@ -5450,6 +5456,94 @@ int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *arg)
&argument);
}
+/*
+ Tells if two (or more) tables have auto_increment columns and we want to
+ lock those tables with a write lock.
+
+ SYNOPSIS
+ has_two_write_locked_tables_with_auto_increment
+ tables Table list
+
+ NOTES:
+ Call this function only when you have established the list of all tables
+ which you'll want to update (including stored functions, triggers, views
+ inside your statement).
+*/
+
+static bool
+has_write_table_with_auto_increment(TABLE_LIST *tables)
+{
+ for (TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ /* we must do preliminary checks as table->table may be NULL */
+ if (!table->placeholder() &&
+ table->table->found_next_number_field &&
+ (table->lock_type >= TL_WRITE_ALLOW_WRITE))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ checks if we have select tables in the table list and write tables
+ with auto-increment column.
+
+ SYNOPSIS
+ has_two_write_locked_tables_with_auto_increment_and_select
+ tables Table list
+
+ RETURN VALUES
+
+ -true if the table list has atleast one table with auto-increment column
+
+
+ and atleast one table to select from.
+ -false otherwise
+*/
+
+static bool
+has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
+{
+ bool has_select= false;
+ bool has_auto_increment_tables = has_write_table_with_auto_increment(tables);
+ for(TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ if (!table->placeholder() &&
+ (table->lock_type <= TL_READ_NO_INSERT))
+ {
+ has_select= true;
+ break;
+ }
+ }
+ return(has_select && has_auto_increment_tables);
+}
+
+/*
+ Tells if there is a table whose auto_increment column is a part
+ of a compound primary key while is not the first column in
+ the table definition.
+
+ @param tables Table list
+
+ @return true if the table exists, fais if does not.
+*/
+
+static bool
+has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables)
+{
+ for (TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ /* we must do preliminary checks as table->table may be NULL */
+ if (!table->placeholder() &&
+ table->table->found_next_number_field &&
+ (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ && table->table->s->next_number_keypart != 0)
+ return 1;
+ }
+
+ return 0;
+}
/**
Decide on logging format to use for the statement and issue errors
@@ -5634,6 +5728,31 @@ int THD::decide_logging_format(TABLE_LIST *tables)
}
#endif
+ if (wsrep_binlog_format() != BINLOG_FORMAT_ROW && tables)
+ {
+ /*
+ DML statements that modify a table with an auto_increment column based on
+ rows selected from a table are unsafe as the order in which the rows are
+ fetched fron the select tables cannot be determined and may differ on
+ master and slave.
+ */
+ if (has_write_table_with_auto_increment_and_select(tables))
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
+
+ if (has_write_table_auto_increment_not_first_in_pk(tables))
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
+
+ /*
+ A query that modifies autoinc column in sub-statement can make the
+ master and slave inconsistent.
+ We can solve these problems in mixed mode by switching to binlogging
+ if at least one updated table is used by sub-statement
+ */
+ if (lex->requires_prelocking() &&
+ has_write_table_with_auto_increment(lex->first_not_own_table()))
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
+ }
+
/*
Get the capabilities vector for all involved storage engines and
mask out the flags for the binary log.
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2c8270055db..4ab94b08970 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
@@ -3992,7 +3992,13 @@ public:
#endif /* GTID_SUPPORT */
void *wsrep_apply_format;
char wsrep_info[128]; /* string for dynamic proc info */
- bool wsrep_skip_append_keys;
+ /*
+ When enabled, do not replicate/binlog updates from the current table that's
+ being processed. At the moment, it is used to keep mysql.gtid_slave_pos
+ table updates from being replicated to other nodes via galera replication.
+ */
+ bool wsrep_ignore_table;
+ wsrep_gtid_t wsrep_sync_wait_gtid;
#endif /* WITH_WSREP */
/* Handling of timeouts for commands */
@@ -4495,10 +4501,14 @@ public:
#define TMP_ENGINE_COLUMNDEF MARIA_COLUMNDEF
#define TMP_ENGINE_HTON maria_hton
#define TMP_ENGINE_NAME "Aria"
+inline uint tmp_table_max_key_length() { return maria_max_key_length(); }
+inline uint tmp_table_max_key_parts() { return maria_max_key_segments(); }
#else
#define TMP_ENGINE_COLUMNDEF MI_COLUMNDEF
#define TMP_ENGINE_HTON myisam_hton
#define TMP_ENGINE_NAME "MyISAM"
+inline uint tmp_table_max_key_length() { return MI_MAX_KEY_LENGTH; }
+inline uint tmp_table_max_key_parts() { return MI_MAX_KEY_SEG; }
#endif
/*
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index b8a8a921367..f77d8cb1984 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -4257,6 +4257,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_RETURN(1);
table->mark_columns_needed_for_insert();
table->file->extra(HA_EXTRA_WRITE_CACHE);
+ // Mark table as used
+ table->query_id= thd->query_id;
DBUG_RETURN(0);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index f0bc582985b..e93ba7fc10f 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
@@ -324,9 +324,7 @@ void Lex_input_stream::body_utf8_start(THD *thd, const char *begin_ptr)
DBUG_ASSERT(begin_ptr);
DBUG_ASSERT(m_cpp_buf <= begin_ptr && begin_ptr <= m_cpp_buf + m_buf_length);
- uint body_utf8_length=
- (m_buf_length / thd->variables.character_set_client->mbminlen) *
- my_charset_utf8_bin.mbmaxlen;
+ uint body_utf8_length= get_body_utf8_maximum_length(thd);
m_body_utf8= (char *) thd->alloc(body_utf8_length + 1);
m_body_utf8_ptr= m_body_utf8;
@@ -335,6 +333,22 @@ void Lex_input_stream::body_utf8_start(THD *thd, const char *begin_ptr)
m_cpp_utf8_processed_ptr= begin_ptr;
}
+
+uint Lex_input_stream::get_body_utf8_maximum_length(THD *thd)
+{
+ /*
+ String literals can grow during escaping:
+ 1a. Character string '<TAB>' can grow to '\t', 3 bytes to 4 bytes growth.
+ 1b. Character string '1000 times <TAB>' grows from
+ 1002 to 2002 bytes (including quotes), which gives a little bit
+ less than 2 times growth.
+ "2" should be a reasonable multiplier that safely covers escaping needs.
+ */
+ return (m_buf_length / thd->variables.character_set_client->mbminlen) *
+ my_charset_utf8_bin.mbmaxlen * 2/*for escaping*/;
+}
+
+
/**
@brief The operation appends unprocessed part of pre-processed buffer till
the given pointer (ptr) and sets m_cpp_utf8_processed_ptr to end_ptr.
@@ -402,15 +416,15 @@ void Lex_input_stream::body_utf8_append(const char *ptr)
operation.
*/
-void Lex_input_stream::body_utf8_append_literal(THD *thd,
- const LEX_STRING *txt,
- CHARSET_INFO *txt_cs,
- const char *end_ptr)
+void Lex_input_stream::body_utf8_append_ident(THD *thd,
+ const LEX_STRING *txt,
+ const char *end_ptr)
{
if (!m_cpp_utf8_processed_ptr)
return;
LEX_STRING utf_txt;
+ CHARSET_INFO *txt_cs= thd->charset();
if (!my_charset_same(txt_cs, &my_charset_utf8_general_ci))
{
@@ -434,6 +448,189 @@ void Lex_input_stream::body_utf8_append_literal(THD *thd,
m_cpp_utf8_processed_ptr= end_ptr;
}
+
+
+
+extern "C" {
+
+/**
+ Escape a character. Consequently puts "escape" and "wc" characters into
+ the destination utf8 string.
+ @param cs - the character set (utf8)
+ @param escape - the escape character (backslash, single quote, double quote)
+ @param wc - the character to be escaped
+ @param str - the destination string
+ @param end - the end of the destination string
+ @returns - a code according to the wc_mb() convension.
+*/
+int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
+ uchar *str, uchar *end)
+{
+ DBUG_ASSERT(escape > 0);
+ if (str + 1 >= end)
+ return MY_CS_TOOSMALL2; // Not enough space, need at least two bytes.
+ *str= escape;
+ int cnvres= my_charset_utf8_handler.wc_mb(cs, wc, str + 1, end);
+ if (cnvres > 0)
+ return cnvres + 1; // The character was normally put
+ if (cnvres == MY_CS_ILUNI)
+ return MY_CS_ILUNI; // Could not encode "wc" (e.g. non-BMP character)
+ DBUG_ASSERT(cnvres <= MY_CS_TOOSMALL);
+ return cnvres - 1; // Not enough space
+}
+
+
+/**
+ Optionally escape a character.
+ If "escape" is non-zero, then both "escape" and "wc" are put to
+ the destination string. Otherwise, only "wc" is put.
+ @param cs - the character set (utf8)
+ @param wc - the character to be optionally escaped
+ @param escape - the escape character, or 0
+ @param ewc - the escaped replacement of "wc" (e.g. 't' for '\t')
+ @param str - the destination string
+ @param end - the end of the destination string
+ @returns - a code according to the wc_mb() conversion.
+*/
+int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
+ my_wc_t wc, my_wc_t escape, my_wc_t ewc,
+ uchar *str, uchar *end)
+{
+ return escape ? my_wc_mb_utf8_with_escape(cs, escape, ewc, str, end) :
+ my_charset_utf8_handler.wc_mb(cs, wc, str, end);
+}
+
+/**
+ Encode a character with optional backlash escaping and quote escaping.
+ Quote marks are escaped using another quote mark.
+ Additionally, if "escape" is non-zero, then special characters are
+ also escaped using "escape".
+ Otherwise (if "escape" is zero, e.g. in case of MODE_NO_BACKSLASH_ESCAPES),
+ then special characters are not escaped and handled as normal characters.
+
+ @param cs - the character set (utf8)
+ @param wc - the character to be encoded
+ @param str - the destination string
+ @param end - the end of the destination string
+ @param sep - the string delimiter (e.g. ' or ")
+ @param escape - the escape character (backslash, or 0)
+ @returns - a code according to the wc_mb() convension.
+*/
+int my_wc_mb_utf8_escape(CHARSET_INFO *cs, my_wc_t wc, uchar *str, uchar *end,
+ my_wc_t sep, my_wc_t escape)
+{
+ DBUG_ASSERT(escape == 0 || escape == '\\');
+ DBUG_ASSERT(sep == '"' || sep == '\'');
+ switch (wc) {
+ case 0: return my_wc_mb_utf8_opt_escape(cs, wc, escape, '0', str, end);
+ case '\t': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 't', str, end);
+ case '\r': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'r', str, end);
+ case '\n': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'n', str, end);
+ case '\032': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'Z', str, end);
+ case '\'':
+ case '\"':
+ if (wc == sep)
+ return my_wc_mb_utf8_with_escape(cs, wc, wc, str, end);
+ }
+ return my_charset_utf8_handler.wc_mb(cs, wc, str, end); // No escaping needed
+}
+
+
+/** wc_mb() compatible routines for all sql_mode and delimiter combinations */
+int my_wc_mb_utf8_escape_single_quote_and_backslash(CHARSET_INFO *cs,
+ my_wc_t wc,
+ uchar *str, uchar *end)
+{
+ return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', '\\');
+}
+
+
+int my_wc_mb_utf8_escape_double_quote_and_backslash(CHARSET_INFO *cs,
+ my_wc_t wc,
+ uchar *str, uchar *end)
+{
+ return my_wc_mb_utf8_escape(cs, wc, str, end, '"', '\\');
+}
+
+
+int my_wc_mb_utf8_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
+ uchar *str, uchar *end)
+{
+ return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', 0);
+}
+
+
+int my_wc_mb_utf8_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
+ uchar *str, uchar *end)
+{
+ return my_wc_mb_utf8_escape(cs, wc, str, end, '"', 0);
+}
+
+}; // End of extern "C"
+
+
+/**
+ Get an escaping function, depending on the current sql_mode and the
+ string separator.
+*/
+my_charset_conv_wc_mb
+Lex_input_stream::get_escape_func(THD *thd, my_wc_t sep) const
+{
+ return thd->backslash_escapes() ?
+ (sep == '"' ? my_wc_mb_utf8_escape_double_quote_and_backslash:
+ my_wc_mb_utf8_escape_single_quote_and_backslash) :
+ (sep == '"' ? my_wc_mb_utf8_escape_double_quote:
+ my_wc_mb_utf8_escape_single_quote);
+}
+
+
+/**
+ Append a text literal to the end of m_body_utf8.
+ The string is escaped according to the current sql_mode and the
+ string delimiter (e.g. ' or ").
+
+ @param thd - current THD
+ @param txt - the string to be appended to m_body_utf8.
+ Note, the string must be already unescaped.
+ @param cs - the character set of the string
+ @param end_ptr - m_cpp_utf8_processed_ptr will be set to this value
+ (see body_utf8_append_ident for details)
+ @param sep - the string delimiter (single or double quote)
+*/
+void Lex_input_stream::body_utf8_append_escape(THD *thd,
+ const LEX_STRING *txt,
+ CHARSET_INFO *cs,
+ const char *end_ptr,
+ my_wc_t sep)
+{
+ DBUG_ASSERT(sep == '\'' || sep == '"');
+ if (!m_cpp_utf8_processed_ptr)
+ return;
+ uint errors;
+ /**
+ We previously alloced m_body_utf8 to be able to store the query with all
+ strings properly escaped. See get_body_utf8_maximum_length().
+ So here we have guaranteedly enough space to append any string literal
+ with escaping. Passing txt->length*2 as "available space" is always safe.
+ For better safety purposes we could calculate get_body_utf8_maximum_length()
+ every time we append a string, but this would affect performance negatively,
+ so let's check that we don't get beyond the allocated buffer in
+ debug build only.
+ */
+ DBUG_ASSERT(m_body_utf8 + get_body_utf8_maximum_length(thd) >=
+ m_body_utf8_ptr + txt->length * 2);
+ uint32 cnv_length= my_convert_using_func(m_body_utf8_ptr, txt->length * 2,
+ &my_charset_utf8_general_ci,
+ get_escape_func(thd, sep),
+ txt->str, txt->length,
+ cs, cs->cset->mb_wc,
+ &errors);
+ m_body_utf8_ptr+= cnv_length;
+ *m_body_utf8_ptr= 0;
+ m_cpp_utf8_processed_ptr= end_ptr;
+}
+
+
void Lex_input_stream::add_digest_token(uint token, LEX_YYSTYPE yylval)
{
if (m_digest != NULL)
@@ -796,14 +993,14 @@ Lex_input_stream::unescape(CHARSET_INFO *cs, char *to,
Fix sometimes to do only one scan of the string
*/
-bool Lex_input_stream::get_text(LEX_STRING *dst, int pre_skip, int post_skip)
+bool Lex_input_stream::get_text(LEX_STRING *dst, uint sep,
+ int pre_skip, int post_skip)
{
- reg1 uchar c,sep;
+ reg1 uchar c;
uint found_escape=0;
CHARSET_INFO *cs= m_thd->charset();
tok_bitmap= 0;
- sep= yyGetLast(); // String should end with this
while (! eof())
{
c= yyGet();
@@ -1168,6 +1365,8 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
return((int) c);
case MY_LEX_IDENT_OR_NCHAR:
+ {
+ uint sep;
if (lip->yyPeek() != '\'')
{
state= MY_LEX_IDENT;
@@ -1175,14 +1374,20 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
}
/* Found N'string' */
lip->yySkip(); // Skip '
- if (lip->get_text(&yylval->lex_str, 2, 1))
+ if (lip->get_text(&yylval->lex_str, (sep= lip->yyGetLast()), 2, 1))
{
state= MY_LEX_CHAR; // Read char by char
break;
}
+
+ lip->body_utf8_append(lip->m_cpp_text_start);
+ lip->body_utf8_append_escape(thd, &yylval->lex_str,
+ national_charset_info,
+ lip->m_cpp_text_end, sep);
+
lex->text_string_is_7bit= (lip->tok_bitmap & 0x80) ? 0 : 1;
return(NCHAR_STRING);
-
+ }
case MY_LEX_IDENT_OR_HEX:
if (lip->yyPeek() == '\'')
{ // Found x'hex-number'
@@ -1285,8 +1490,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
lip->body_utf8_append(lip->m_cpp_text_start);
- lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
- lip->m_cpp_text_end);
+ lip->body_utf8_append_ident(thd, &yylval->lex_str, lip->m_cpp_text_end);
return(result_state); // IDENT or IDENT_QUOTED
@@ -1390,8 +1594,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
lip->body_utf8_append(lip->m_cpp_text_start);
- lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
- lip->m_cpp_text_end);
+ lip->body_utf8_append_ident(thd, &yylval->lex_str, lip->m_cpp_text_end);
return(result_state);
@@ -1434,8 +1637,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
lip->body_utf8_append(lip->m_cpp_text_start);
- lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
- lip->m_cpp_text_end);
+ lip->body_utf8_append_ident(thd, &yylval->lex_str, lip->m_cpp_text_end);
return(IDENT_QUOTED);
}
@@ -1540,23 +1742,23 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
}
/* " used for strings */
case MY_LEX_STRING: // Incomplete text string
- if (lip->get_text(&yylval->lex_str, 1, 1))
+ {
+ uint sep;
+ if (lip->get_text(&yylval->lex_str, (sep= lip->yyGetLast()), 1, 1))
{
state= MY_LEX_CHAR; // Read char by char
break;
}
-
+ CHARSET_INFO *strcs= lip->m_underscore_cs ? lip->m_underscore_cs : cs;
lip->body_utf8_append(lip->m_cpp_text_start);
- lip->body_utf8_append_literal(thd, &yylval->lex_str,
- lip->m_underscore_cs ? lip->m_underscore_cs : cs,
- lip->m_cpp_text_end);
-
+ lip->body_utf8_append_escape(thd, &yylval->lex_str, strcs,
+ lip->m_cpp_text_end, sep);
lip->m_underscore_cs= NULL;
lex->text_string_is_7bit= (lip->tok_bitmap & 0x80) ? 0 : 1;
return(TEXT_STRING);
-
+ }
case MY_LEX_COMMENT: // Comment
lex->select_lex.options|= OPTION_FOUND_COMMENT;
while ((c = lip->yyGet()) != '\n' && c) ;
@@ -1805,8 +2007,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
lip->body_utf8_append(lip->m_cpp_text_start);
- lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
- lip->m_cpp_text_end);
+ lip->body_utf8_append_ident(thd, &yylval->lex_str, lip->m_cpp_text_end);
return(result_state);
}
@@ -3915,6 +4116,19 @@ void SELECT_LEX::update_used_tables()
tl->on_expr->update_used_tables();
tl->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
}
+ /*
+ - There is no need to check sj_on_expr, because merged semi-joins inject
+ sj_on_expr into the parent's WHERE clase.
+ - For non-merged semi-joins (aka JTBMs), we need to check their
+ left_expr. There is no need to check the rest of the subselect, we know
+ it is uncorrelated and so cannot refer to any tables in this select.
+ */
+ if (tl->jtbm_subselect)
+ {
+ Item *left_expr= tl->jtbm_subselect->left_expr;
+ left_expr->walk(&Item::update_table_bitmaps_processor, FALSE, NULL);
+ }
+
embedding= tl->embedding;
while (embedding)
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9eddd6d61ee..bda4ceb7b91 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2010, 2015, MariaDB
+/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2016, 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
@@ -1072,6 +1072,13 @@ private:
index_clause_map current_index_hint_clause;
/* a list of USE/FORCE/IGNORE INDEX */
List<Index_hint> *index_hints;
+
+public:
+ inline void add_where_field(st_select_lex *sel)
+ {
+ DBUG_ASSERT(this != sel);
+ select_n_where_fields+= sel->select_n_where_fields;
+ }
};
typedef class st_select_lex SELECT_LEX;
@@ -1407,6 +1414,11 @@ public:
return get_stmt_unsafe_flags() != 0;
}
+ inline bool is_stmt_unsafe(enum_binlog_stmt_unsafe unsafe)
+ {
+ return binlog_stmt_flags & (1 << unsafe);
+ }
+
/**
Flag the current (top-level) statement as unsafe.
The flag will be reset after the statement has finished.
@@ -1803,6 +1815,7 @@ class Lex_input_stream
{
size_t unescape(CHARSET_INFO *cs, char *to,
const char *str, const char *end, int sep);
+ my_charset_conv_wc_mb get_escape_func(THD *thd, my_wc_t sep) const;
public:
Lex_input_stream()
{
@@ -2073,14 +2086,23 @@ public:
return (uint) (m_body_utf8_ptr - m_body_utf8);
}
+ /**
+ Get the maximum length of the utf8-body buffer.
+ The utf8 body can grow because of the character set conversion and escaping.
+ */
+ uint get_body_utf8_maximum_length(THD *thd);
+
void body_utf8_start(THD *thd, const char *begin_ptr);
void body_utf8_append(const char *ptr);
void body_utf8_append(const char *ptr, const char *end_ptr);
- void body_utf8_append_literal(THD *thd,
- const LEX_STRING *txt,
- CHARSET_INFO *txt_cs,
- const char *end_ptr);
-
+ void body_utf8_append_ident(THD *thd,
+ const LEX_STRING *txt,
+ const char *end_ptr);
+ void body_utf8_append_escape(THD *thd,
+ const LEX_STRING *txt,
+ CHARSET_INFO *txt_cs,
+ const char *end_ptr,
+ my_wc_t sep);
/** Current thread. */
THD *m_thd;
@@ -2101,7 +2123,7 @@ public:
/** LALR(2) resolution, value of the look ahead token.*/
LEX_YYSTYPE lookahead_yylval;
- bool get_text(LEX_STRING *to, int pre_skip, int post_skip);
+ bool get_text(LEX_STRING *to, uint sep, int pre_skip, int post_skip);
void add_digest_token(uint token, LEX_YYSTYPE yylval);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b73a26b89bc..78f9a9b286a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4518,6 +4518,11 @@ end_with_restore_list:
db_name.str= db_name_buff;
db_name.length= lex->name.length;
strmov(db_name.str, lex->name.str);
+
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
+
if (check_db_name(&db_name))
{
my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
@@ -4571,6 +4576,9 @@ end_with_restore_list:
/* lex->unit.cleanup() is called outside, no need to call it here */
break;
case SQLCOM_SHOW_CREATE_EVENT:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
res= Events::show_create_event(thd, lex->spname->m_db,
lex->spname->m_name);
break;
@@ -4799,16 +4807,29 @@ end_with_restore_list:
#ifdef WITH_WSREP
if (lex->type & (
- REFRESH_GRANT |
- REFRESH_HOSTS |
- REFRESH_DES_KEY_FILE |
+ REFRESH_GRANT |
+ REFRESH_HOSTS |
+#ifdef HAVE_OPENSSL
+ REFRESH_DES_KEY_FILE |
+#endif
+ /*
+ Write all flush log statements except
+ FLUSH LOGS
+ FLUSH BINARY LOGS
+ Check reload_acl_and_cache for why.
+ */
+ REFRESH_RELAY_LOG |
+ REFRESH_SLOW_LOG |
+ REFRESH_GENERAL_LOG |
+ REFRESH_ENGINE_LOG |
+ REFRESH_ERROR_LOG |
#ifdef HAVE_QUERY_CACHE
- REFRESH_QUERY_CACHE_FREE |
+ REFRESH_QUERY_CACHE_FREE |
#endif /* HAVE_QUERY_CACHE */
- REFRESH_STATUS |
- REFRESH_USER_RESOURCES))
+ REFRESH_STATUS |
+ REFRESH_USER_RESOURCES))
{
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL)
}
#endif /* WITH_WSREP*/
@@ -4842,11 +4863,11 @@ end_with_restore_list:
*/
if (first_table)
{
- WSREP_TO_ISOLATION_BEGIN(NULL, NULL, first_table);
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
}
else
{
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL);
}
}
#endif /* WITH_WSREP */
@@ -5451,12 +5472,18 @@ create_sp_error:
}
case SQLCOM_SHOW_CREATE_PROC:
{
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
goto error;
break;
}
case SQLCOM_SHOW_CREATE_FUNC:
{
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
goto error;
break;
@@ -5469,6 +5496,9 @@ create_sp_error:
stored_procedure_type type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
if (sp_cache_routine(thd, type, lex->spname, FALSE, &sp))
goto error;
if (!sp || sp->show_routine_code(thd))
@@ -5493,6 +5523,9 @@ create_sp_error:
goto error;
}
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
if (show_create_trigger(thd, lex->spname))
goto error; /* Error has been already logged. */
@@ -7339,6 +7372,12 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
sql_statement_info[SQLCOM_SELECT].m_key);
status_var_increment(thd->status_var.com_stat[SQLCOM_SELECT]);
thd->update_stats();
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd))
+ {
+ thd->wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+ }
+#endif /* WITH_WSREP */
}
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index da0cc17250b..c3dfde18ab6 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -133,7 +133,7 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_thd_query_state_str,
wsrep_thd_retry_counter,
wsrep_thd_set_conflict_state,
- wsrep_thd_skip_append_keys,
+ wsrep_thd_ignore_table,
wsrep_thd_trx_seqno,
wsrep_thd_ws_handle,
wsrep_trx_is_aborting,
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 8c4e8812d72..b1e46478aa6 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015 Oracle and/or its affiliates.
- Copyright (c) 2009, 2015 MariaDB
+ Copyright (c) 2009, 2016 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
@@ -9236,7 +9236,7 @@ static void add_not_null_conds(JOIN *join)
if (!referred_tab)
continue;
if (!(notnull= new (join->thd->mem_root)
- Item_func_isnotnull(join->thd, not_null_item)))
+ Item_func_isnotnull(join->thd, item)))
DBUG_VOID_RETURN;
/*
We need to do full fix_fields() call here in order to have correct
@@ -17117,6 +17117,12 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
goto err;
bzero(seg, sizeof(*seg) * keyinfo->user_defined_key_parts);
+ /*
+ Note that a similar check is performed during
+ subquery_types_allow_materialization. See MDEV-7122 for more details as
+ to why. Whenever this changes, it must be updated there as well, for
+ all tmp_table engines.
+ */
if (keyinfo->key_length > table->file->max_key_length() ||
keyinfo->user_defined_key_parts > table->file->max_key_parts() ||
share->uniques)
@@ -17316,6 +17322,12 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
goto err;
bzero(seg, sizeof(*seg) * keyinfo->user_defined_key_parts);
+ /*
+ Note that a similar check is performed during
+ subquery_types_allow_materialization. See MDEV-7122 for more details as
+ to why. Whenever this changes, it must be updated there as well, for
+ all tmp_table engines.
+ */
if (keyinfo->key_length > table->file->max_key_length() ||
keyinfo->user_defined_key_parts > table->file->max_key_parts() ||
share->uniques)
@@ -18783,7 +18795,18 @@ int join_read_key2(THD *thd, JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref)
}
}
+ /*
+ The following is needed when one makes ref (or eq_ref) access from row
+ comparisons: one must call row->bring_value() to get the new values.
+ */
+ if (tab && tab->bush_children)
+ {
+ TABLE_LIST *emb_sj_nest= tab->bush_children->start->emb_sj_nest;
+ emb_sj_nest->sj_subq_pred->left_expr->bring_value();
+ }
+
/* TODO: Why don't we do "Late NULLs Filtering" here? */
+
if (cmp_buffer_with_ref(thd, table, table_ref) ||
(table->status & (STATUS_GARBAGE | STATUS_NO_PARENT | STATUS_NULL_ROW)))
{
@@ -21194,7 +21217,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
&examined_rows, &found_rows,
join->explain->ops_tracker.report_sorting(thd));
table->sort.found_records= filesort_retval;
- tab->records= found_rows; // For SQL_CALC_ROWS
+ tab->records= join->select_options & OPTION_FOUND_ROWS ? found_rows : filesort_retval;
if (quick_created)
{
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 1b1bb6ded71..95550f56450 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -33,7 +33,6 @@
#include "records.h" /* READ_RECORD */
#include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */
-
/* Values in optimize */
#define KEY_OPTIMIZE_EXISTS 1
#define KEY_OPTIMIZE_REF_OR_NULL 2
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index f4dd24a1d0f..f40e12974b0 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
@@ -1450,20 +1450,17 @@ static const char *require_quotes(const char *name, uint name_length)
}
-/*
- Quote the given identifier if needed and append it to the target string.
- If the given identifier is empty, it will be quoted.
-
- SYNOPSIS
- append_identifier()
- thd thread handler
- packet target string
- name the identifier to be appended
- name_length length of the appending identifier
+/**
+ Convert and quote the given identifier if needed and append it to the
+ target string. If the given identifier is empty, it will be quoted.
+ @thd thread handler
+ @packet target string
+ @name the identifier to be appended
+ @length length of the appending identifier
- RETURN VALUES
- true Error
- false Ok
+ @return
+ 0 success
+ 1 error
*/
bool
@@ -5036,6 +5033,15 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
}
append_create_options(thd, &str, share->option_list, false, 0);
+ if (file)
+ {
+ HA_CREATE_INFO create_info;
+ memset(&create_info, 0, sizeof(create_info));
+ file->update_create_info(&create_info);
+ append_directory(thd, &str, "DATA", create_info.data_file_name);
+ append_directory(thd, &str, "INDEX", create_info.index_file_name);
+ }
+
if (str.length())
table->field[19]->store(str.ptr()+1, str.length()-1, cs);
@@ -7345,12 +7351,14 @@ static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
# pointer to 'schema_tables' element
*/
-ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name,
+ bool *in_plugin)
{
schema_table_ref schema_table_a;
ST_SCHEMA_TABLE *schema_table= schema_tables;
DBUG_ENTER("find_schema_table");
+ *in_plugin= false;
for (; schema_table->table_name; schema_table++)
{
if (!my_strcasecmp(system_charset_info,
@@ -7359,6 +7367,7 @@ ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
DBUG_RETURN(schema_table);
}
+ *in_plugin= true;
schema_table_a.table_name= table_name;
if (plugin_foreach(thd, find_schema_table_in_plugin,
MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
@@ -8280,8 +8289,8 @@ ST_FIELD_INFO tables_fields_info[]=
OPEN_FRM_ONLY},
{"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE},
- {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options",
- OPEN_FRM_ONLY},
+ {"CREATE_OPTIONS", 2048, MYSQL_TYPE_STRING, 0, 1, "Create_options",
+ OPEN_FULL_TABLE},
{"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
"Comment", OPEN_FRM_ONLY},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
diff --git a/sql/sql_show.h b/sql/sql_show.h
index ecb7e9468ea..9dae78e7f0e 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2005, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2016, 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
@@ -117,7 +118,10 @@ bool schema_table_store_record(THD *thd, TABLE *table);
void initialize_information_schema_acl();
COND *make_cond_for_info_schema(THD *thd, COND *cond, TABLE_LIST *table);
-ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name, bool *in_plugin);
+static inline ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
+{ bool unused; return find_schema_table(thd, table_name, &unused); }
+
ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
int make_schema_select(THD *thd, SELECT_LEX *sel,
ST_SCHEMA_TABLE *schema_table);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 8ea9db41ce4..b4cebb4f7a9 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2015, MariaDB
+ Copyright (c) 2010, 2016, 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
@@ -2232,7 +2232,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
const char *comment_start;
uint32 comment_len;
- built_query.set_charset(system_charset_info);
+ built_query.set_charset(thd->charset());
if (if_exists)
built_query.append("DROP TABLE IF EXISTS ");
else
@@ -3448,8 +3448,31 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
else
{
/* Field redefined */
+
+ /*
+ If we are replacing a BIT field, revert the increment
+ of total_uneven_bit_length that was done above.
+ */
+ if (sql_field->sql_type == MYSQL_TYPE_BIT &&
+ file->ha_table_flags() & HA_CAN_BIT_FIELD)
+ total_uneven_bit_length-= sql_field->length & 7;
+
sql_field->def= dup_field->def;
sql_field->sql_type= dup_field->sql_type;
+
+ /*
+ If we are replacing a field with a BIT field, we need
+ to initialize pack_flag. Note that we do not need to
+ increment total_uneven_bit_length here as this dup_field
+ has already been processed.
+ */
+ if (sql_field->sql_type == MYSQL_TYPE_BIT)
+ {
+ sql_field->pack_flag= FIELDFLAG_NUMBER;
+ if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD))
+ sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
+ }
+
sql_field->charset= (dup_field->charset ?
dup_field->charset :
create_info->default_table_charset);
@@ -6167,6 +6190,7 @@ static bool fill_alter_inplace_info(THD *thd,
c) flags passed to storage engine contain more detailed information
about nature of changes than those provided from parser.
*/
+ bool maybe_alter_vcol= false;
for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
{
/* Clear marker for renamed or dropped field
@@ -6190,7 +6214,8 @@ static bool fill_alter_inplace_info(THD *thd,
/*
Check if type of column has changed to some incompatible type.
*/
- switch (field->is_equal(new_field))
+ uint is_equal= field->is_equal(new_field);
+ switch (is_equal)
{
case IS_EQUAL_NO:
/* New column type is incompatible with old one. */
@@ -6242,6 +6267,20 @@ static bool fill_alter_inplace_info(THD *thd,
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
}
+ /*
+ Check if the column is computed and either
+ is stored or is used in the partitioning expression.
+ */
+ if (field->vcol_info &&
+ (field->stored_in_db() || field->vcol_info->is_in_partitioning_expr()))
+ {
+ if (is_equal == IS_EQUAL_NO ||
+ !field->vcol_info->is_equal(new_field->vcol_info))
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
+ else
+ maybe_alter_vcol= true;
+ }
+
/* Check if field was renamed */
if (my_strcasecmp(system_charset_info, field->field_name,
new_field->field_name))
@@ -6305,32 +6344,37 @@ static bool fill_alter_inplace_info(THD *thd,
}
}
+ if (maybe_alter_vcol)
+ {
+ /*
+ No virtual column was altered, but perhaps one of the other columns was,
+ and that column was part of the vcol expression?
+ We don't detect this correctly (FIXME), so let's just say that a vcol
+ *might* be affected if any other column was altered.
+ */
+ if (ha_alter_info->handler_flags &
+ ( Alter_inplace_info::ALTER_COLUMN_TYPE
+ | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE
+ | Alter_inplace_info::ALTER_COLUMN_OPTION ))
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
+ }
+
new_field_it.init(alter_info->create_list);
while ((new_field= new_field_it++))
{
- Virtual_column_info *vcol_info;
- if (new_field->field)
- vcol_info= new_field->field->vcol_info;
- else
+ if (! new_field->field)
{
- vcol_info= new_field->vcol_info;
/*
Field is not present in old version of table and therefore was added.
Again corresponding storage engine flag should be already set.
*/
DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN);
- }
- /*
- Check if the altered column is computed and either
- is stored or is used in the partitioning expression.
- TODO: Mark such a column with an alter flag only if
- the defining expression has changed.
- */
- if (vcol_info &&
- (vcol_info->stored_in_db || vcol_info->is_in_partitioning_expr()))
- {
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
+ if (new_field->vcol_info &&
+ (new_field->stored_in_db() || new_field->vcol_info->is_in_partitioning_expr()))
+ {
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
+ }
}
}
@@ -6917,7 +6961,7 @@ static bool mysql_inplace_alter_table(THD *thd,
MDL_request *target_mdl_request,
Alter_table_ctx *alter_ctx)
{
- Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
+ Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN | MYSQL_OPEN_IGNORE_KILLED);
handlerton *db_type= table->s->db_type();
MDL_ticket *mdl_ticket= table->mdl_ticket;
HA_CREATE_INFO *create_info= ha_alter_info->create_info;
@@ -9143,13 +9187,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error, but still worth reporting as it might indicate serious
problem with server.
*/
- goto err_with_mdl;
+ goto err_with_mdl_after_alter;
}
end_inplace:
if (thd->locked_tables_list.reopen_tables(thd))
- goto err_with_mdl;
+ goto err_with_mdl_after_alter;
THD_STAGE_INFO(thd, stage_end);
@@ -9230,6 +9274,10 @@ err_new_table_cleanup:
DBUG_RETURN(true);
+err_with_mdl_after_alter:
+ /* the table was altered. binlog the operation */
+ write_bin_log(thd, true, thd->query(), thd->query_length());
+
err_with_mdl:
/*
An error happened while we were holding exclusive name metadata lock
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 5a985710ee1..e0cab5cfa66 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2016, 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
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 4e492e7099d..d85664568a1 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -433,10 +433,8 @@ Field *Type_handler_timestamp::make_conversion_table_field(TABLE *table,
const Field *target)
const
{
- // We assume TIMESTAMP(0)
- return new(table->in_use->mem_root)
- Field_timestamp(NULL, MAX_DATETIME_WIDTH, (uchar *) "", 1,
- Field::NONE, TMPNAME, table->s);
+ return new_Field_timestamp(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ Field::NONE, TMPNAME, table->s, target->decimals());
}
@@ -476,9 +474,8 @@ Field *Type_handler_time::make_conversion_table_field(TABLE *table,
const Field *target)
const
{
- return new(table->in_use->mem_root)
- Field_time(NULL, MAX_TIME_WIDTH, (uchar *) "", 1,
- Field::NONE, TMPNAME);
+ return new_Field_time(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ Field::NONE, TMPNAME, target->decimals());
}
@@ -497,9 +494,8 @@ Field *Type_handler_datetime::make_conversion_table_field(TABLE *table,
const Field *target)
const
{
- return new(table->in_use->mem_root)
- Field_datetime(NULL, MAX_DATETIME_WIDTH, (uchar *) "", 1,
- Field::NONE, TMPNAME);
+ return new_Field_datetime(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ Field::NONE, TMPNAME, target->decimals());
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f343a17ee11..55e5cf2c526 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -368,6 +368,9 @@ int mysql_update(THD *thd,
if (check_unique_table(thd, table_list))
DBUG_RETURN(TRUE);
+ switch_to_nullable_trigger_fields(fields, table);
+ switch_to_nullable_trigger_fields(values, table);
+
/* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */
if (select_lex->optimize_unflattened_subqueries(false))
DBUG_RETURN(TRUE);
@@ -455,8 +458,6 @@ int mysql_update(THD *thd,
}
init_ftfuncs(thd, select_lex, 1);
- switch_to_nullable_trigger_fields(fields, table);
- switch_to_nullable_trigger_fields(values, table);
table->mark_columns_needed_for_update();
table->update_const_key_parts(conds);
@@ -2431,6 +2432,10 @@ int multi_update::do_updates()
int error;
if (table->default_field && (error= table->update_default_fields()))
goto err2;
+ if (table->vfield &&
+ update_virtual_fields(thd, table,
+ (table->triggers ? VCOL_UPDATE_ALL : VCOL_UPDATE_FOR_WRITE)))
+ goto err2;
if ((error= cur_table->view_check_option(thd, ignore)) !=
VIEW_CHECK_OK)
{
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 62e6790a142..5e6071b125d 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1535,8 +1535,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
/* Fields in this view can be used in upper select in case of merge. */
if (table->select_lex)
- table->select_lex->select_n_where_fields+=
- lex->select_lex.select_n_where_fields;
+ table->select_lex->add_where_field(&lex->select_lex);
}
/*
This method has a dependency on the proper lock type being set,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1899dd60f88..4ef9bf2382d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -10911,15 +10911,6 @@ table_factor:
sel->add_joined_table($$);
lex->pop_context();
lex->nest_level--;
- /*
- Fields in derived table can be used in upper select in
- case of merge. We do not add HAVING fields because we do
- not merge such derived. We do not add union because
- also do not merge them
- */
- if (!sel->next_select())
- $2->select_n_where_fields+=
- sel->select_n_where_fields;
}
/*else if (($3->select_lex &&
$3->select_lex->master_unit()->is_union() &&
@@ -10940,6 +10931,15 @@ table_factor:
nest_level is the same as in the outer query */
$$= $3;
}
+ /*
+ Fields in derived table can be used in upper select in
+ case of merge. We do not add HAVING fields because we do
+ not merge such derived. We do not add union because
+ also do not merge them
+ */
+ if ($$ && $$->derived &&
+ !$$->derived->first_select()->next_select())
+ $$->select_lex->add_where_field($$->derived->first_select());
}
;
@@ -12806,9 +12806,10 @@ show_param:
| IDENT_sys remember_tok_start wild_and_where
{
LEX *lex= Lex;
+ bool in_plugin;
lex->sql_command= SQLCOM_SHOW_GENERIC;
- ST_SCHEMA_TABLE *table= find_schema_table(thd, $1.str);
- if (!table || !table->old_format)
+ ST_SCHEMA_TABLE *table= find_schema_table(thd, $1.str, &in_plugin);
+ if (!table || !table->old_format || !in_plugin)
{
my_parse_error(thd, ER_SYNTAX_ERROR, $2);
MYSQL_YYABORT;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 1284cbb66cb..9ba955c5bc6 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -5059,7 +5059,7 @@ static Sys_var_set Sys_log_slow_filter(
"Log only certain types of queries",
SESSION_VAR(log_slow_filter), CMD_LINE(REQUIRED_ARG),
log_slow_filter_names,
- DEFAULT(MAX_SET(array_elements(log_slow_filter_names)-1)));
+ DEFAULT(my_set_bits(array_elements(log_slow_filter_names)-1)));
static const char *default_regex_flags_names[]=
{
diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic
index 2badd5d997a..373f5834838 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -1094,9 +1094,6 @@ public:
}
};
-// overflow-safe (1 << X)-1
-#define MAX_SET(X) ((((1UL << ((X)-1))-1) << 1) | 1)
-
/**
The class for flagset variables - a variant of SET that allows in-place
editing (turning on/off individual bits). String representations looks like
@@ -1131,7 +1128,7 @@ public:
global_var(ulonglong)= def_val;
SYSVAR_ASSERT(typelib.count > 1);
SYSVAR_ASSERT(typelib.count <= 65);
- SYSVAR_ASSERT(def_val < MAX_SET(typelib.count));
+ SYSVAR_ASSERT(def_val < my_set_bits(typelib.count));
SYSVAR_ASSERT(strcmp(values[typelib.count-1], "default") == 0);
SYSVAR_ASSERT(size == sizeof(ulonglong));
}
@@ -1179,7 +1176,7 @@ public:
{
longlong tmp=var->value->val_int();
if ((tmp < 0 && ! var->value->unsigned_flag)
- || (ulonglong)tmp > MAX_SET(typelib.count))
+ || (ulonglong)tmp > my_set_bits(typelib.count))
return true;
else
var->save_result.ulonglong_value= tmp;
@@ -1240,7 +1237,7 @@ public:
global_var(ulonglong)= def_val;
SYSVAR_ASSERT(typelib.count > 0);
SYSVAR_ASSERT(typelib.count <= 64);
- SYSVAR_ASSERT(def_val <= MAX_SET(typelib.count));
+ SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count));
SYSVAR_ASSERT(size == sizeof(ulonglong));
}
bool do_check(THD *thd, set_var *var)
@@ -1278,7 +1275,7 @@ public:
{
longlong tmp=var->value->val_int();
if ((tmp < 0 && ! var->value->unsigned_flag)
- || (ulonglong)tmp > MAX_SET(typelib.count))
+ || (ulonglong)tmp > my_set_bits(typelib.count))
return true;
else
var->save_result.ulonglong_value= tmp;
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index e098fc95897..cf1feb49f41 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -19,6 +19,7 @@
#include "log_event.h" // class THD, EVENT_LEN_OFFSET, etc.
#include "wsrep_applier.h"
+#include "debug_sync.h"
/*
read the first event from (*buf). The size of the (*buf) is (*buf_len).
@@ -220,6 +221,16 @@ wsrep_cb_status_t wsrep_apply_cb(void* const ctx,
{
THD* const thd((THD*)ctx);
+ // Allow tests to block the applier thread using the DBUG facilities.
+ DBUG_EXECUTE_IF("sync.wsrep_apply_cb",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.wsrep_apply_cb";
+ DBUG_ASSERT(!debug_sync_set_action(thd,
+ STRING_WITH_LEN(act)));
+ };);
+
thd->wsrep_trx_meta = *meta;
#ifdef WSREP_PROC_INFO
@@ -279,8 +290,7 @@ wsrep_cb_status_t wsrep_apply_cb(void* const ctx,
return rcode;
}
-static wsrep_cb_status_t wsrep_commit(THD* const thd,
- wsrep_seqno_t const global_seqno)
+static wsrep_cb_status_t wsrep_commit(THD* const thd)
{
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
@@ -299,7 +309,11 @@ static wsrep_cb_status_t wsrep_commit(THD* const thd,
#ifdef GTID_SUPPORT
thd->variables.gtid_next.set_automatic();
#endif /* GTID_SUPPORT */
- // TODO: mark snapshot with global_seqno.
+ if (thd->wsrep_apply_toi)
+ {
+ wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ }
}
#ifdef WSREP_PROC_INFO
@@ -313,8 +327,7 @@ static wsrep_cb_status_t wsrep_commit(THD* const thd,
return rcode;
}
-static wsrep_cb_status_t wsrep_rollback(THD* const thd,
- wsrep_seqno_t const global_seqno)
+static wsrep_cb_status_t wsrep_rollback(THD* const thd)
{
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
@@ -351,9 +364,9 @@ wsrep_cb_status_t wsrep_commit_cb(void* const ctx,
wsrep_cb_status_t rcode;
if (commit)
- rcode = wsrep_commit(thd, meta->gtid.seqno);
+ rcode = wsrep_commit(thd);
else
- rcode = wsrep_rollback(thd, meta->gtid.seqno);
+ rcode = wsrep_rollback(thd);
wsrep_set_apply_format(thd, NULL);
thd->mdl_context.release_transactional_locks();
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 603cd8ec5ea..0aa7f9b0aad 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -116,7 +116,7 @@ int wsrep_thd_retry_counter(THD *)
void wsrep_thd_set_conflict_state(THD *, enum wsrep_conflict_state)
{ }
-bool wsrep_thd_skip_append_keys(THD *)
+bool wsrep_thd_ignore_table(THD *)
{ return 0; }
longlong wsrep_thd_trx_seqno(THD *)
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
index 5e3f7402aa4..fa34a5bbc55 100644
--- a/sql/wsrep_hton.cc
+++ b/sql/wsrep_hton.cc
@@ -22,6 +22,7 @@
#include "wsrep_xid.h"
#include <cstdio>
#include <cstdlib>
+#include "debug_sync.h"
extern ulonglong thd_to_trx_id(THD *thd);
@@ -67,6 +68,17 @@ void wsrep_register_hton(THD* thd, bool all)
if (WSREP(thd) && thd->wsrep_exec_mode != TOTAL_ORDER &&
!thd->wsrep_apply_toi)
{
+ if (thd->wsrep_exec_mode == LOCAL_STATE &&
+ (thd_sql_command(thd) == SQLCOM_OPTIMIZE ||
+ thd_sql_command(thd) == SQLCOM_ANALYZE ||
+ thd_sql_command(thd) == SQLCOM_REPAIR) &&
+ thd->lex->no_write_to_binlog == 1)
+ {
+ WSREP_DEBUG("Skipping wsrep_register_hton for LOCAL sql admin command : %s",
+ thd->query());
+ return;
+ }
+
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
for (Ha_trx_info *i= trans->ha_list; i; i = i->next())
{
@@ -317,6 +329,8 @@ wsrep_run_wsrep_commit(THD *thd, bool all)
thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
}
+ DEBUG_SYNC(thd, "wsrep_before_replication");
+
if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK);
if (thd->wsrep_exec_mode == REPL_RECV) {
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 0ba02214b8b..f84ebe4dbb9 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -940,19 +940,24 @@ bool wsrep_start_replication()
return true;
}
+bool wsrep_must_sync_wait (THD* thd, uint mask)
+{
+ return (thd->variables.wsrep_sync_wait & mask) &&
+ thd->variables.wsrep_on &&
+ !thd->in_active_multi_stmt_transaction() &&
+ thd->wsrep_conflict_state != REPLAYING &&
+ thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
+}
+
bool wsrep_sync_wait (THD* thd, uint mask)
{
- if ((thd->variables.wsrep_sync_wait & mask) &&
- thd->variables.wsrep_on &&
- !thd->in_active_multi_stmt_transaction() &&
- thd->wsrep_conflict_state != REPLAYING)
+ if (wsrep_must_sync_wait(thd, mask))
{
WSREP_DEBUG("wsrep_sync_wait: thd->variables.wsrep_sync_wait = %u, mask = %u",
thd->variables.wsrep_sync_wait, mask);
// This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0
// TODO: modify to check if thd has locked any rows.
- wsrep_gtid_t gtid;
- wsrep_status_t ret= wsrep->causal_read (wsrep, &gtid);
+ wsrep_status_t ret= wsrep->causal_read (wsrep, &thd->wsrep_sync_wait_gtid);
if (unlikely(WSREP_OK != ret))
{
@@ -1460,16 +1465,19 @@ static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
thd->wsrep_exec_mode, thd->query() );
- ret = wsrep->desync(wsrep);
- if (ret != WSREP_OK)
+ if (!wsrep_desync)
{
- WSREP_WARN("RSU desync failed %d for schema: %s, query: %s",
- ret,
- (thd->db ? thd->db : "(null)"),
- thd->query());
- my_error(ER_LOCK_DEADLOCK, MYF(0));
- return(ret);
+ ret = wsrep->desync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("RSU desync failed %d for schema: %s, query: %s",
+ ret, (thd->db ? thd->db : "(null)"), thd->query());
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ return(ret);
+ }
}
+ else
+ WSREP_DEBUG("RSU desync skipped: %d", wsrep_desync);
mysql_mutex_lock(&LOCK_wsrep_replaying);
wsrep_replaying++;
mysql_mutex_unlock(&LOCK_wsrep_replaying);
@@ -1484,13 +1492,14 @@ static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
wsrep_replaying--;
mysql_mutex_unlock(&LOCK_wsrep_replaying);
- ret = wsrep->resync(wsrep);
- if (ret != WSREP_OK)
+ if (!wsrep_desync)
{
- WSREP_WARN("resync failed %d for schema: %s, query: %s",
- ret,
- (thd->db ? thd->db : "(null)"),
- thd->query());
+ ret = wsrep->resync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resync failed %d for schema: %s, query: %s",
+ ret, (thd->db ? thd->db : "(null)"), thd->query());
+ }
}
my_error(ER_LOCK_DEADLOCK, MYF(0));
return(1);
@@ -1527,14 +1536,18 @@ static void wsrep_RSU_end(THD *thd)
(thd->db ? thd->db : "(null)"),
thd->query());
}
- ret = wsrep->resync(wsrep);
- if (ret != WSREP_OK)
+ if (!wsrep_desync)
{
- WSREP_WARN("resync failed %d for schema: %s, query: %s", ret,
- (thd->db ? thd->db : "(null)"),
- thd->query());
- return;
+ ret = wsrep->resync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resync failed %d for schema: %s, query: %s", ret,
+ (thd->db ? thd->db : "(null)"), thd->query());
+ return;
+ }
}
+ else
+ WSREP_DEBUG("RSU resync skipped: %d", wsrep_desync);
thd->variables.wsrep_on = 1;
}
@@ -2183,9 +2196,9 @@ int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
&(thd->lex->definer->host),
saved_mode))
{
- WSREP_WARN("SP create string failed: schema: %s, query: %s",
- (thd->db ? thd->db : "(null)"), thd->query());
- return 1;
+ WSREP_WARN("SP create string failed: schema: %s, query: %s",
+ (thd->db ? thd->db : "(null)"), thd->query());
+ return 1;
}
return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
@@ -2366,9 +2379,9 @@ int wsrep_thd_retry_counter(THD *thd)
}
-extern "C" bool wsrep_thd_skip_append_keys(THD *thd)
+extern "C" bool wsrep_thd_ignore_table(THD *thd)
{
- return thd->wsrep_skip_append_keys;
+ return thd->wsrep_ignore_table;
}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index a22eb1a0b64..e91ed2302a2 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -160,6 +160,7 @@ extern void wsrep_kill_mysql(THD *thd);
/* new defines */
extern void wsrep_stop_replication(THD *thd);
extern bool wsrep_start_replication();
+extern bool wsrep_must_sync_wait(THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ);
extern bool wsrep_sync_wait(THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ);
extern int wsrep_check_opts();
extern void wsrep_prepend_PATH (const char* path);
@@ -327,6 +328,7 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
#define wsrep_prepend_PATH(X)
#define wsrep_before_SE() (0)
#define wsrep_init_startup(X)
+#define wsrep_must_sync_wait(...) (0)
#define wsrep_sync_wait(...) (0)
#define wsrep_to_isolation_begin(...) (0)
#define wsrep_register_hton(...) do { } while(0)