diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-02-25 18:19:55 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2016-02-25 18:19:55 +0100 |
commit | 00d1db7a38b17d4512a6ba5147926608aca5624d (patch) | |
tree | c2b28145304e9eacf79fcabaeb962a20d79fec93 /sql | |
parent | 0485328d030f4b742dac7b667e8ed099beb9e9f2 (diff) | |
parent | 0251232f8c3bca33b4dd15d6668105f3de9d024d (diff) | |
download | mariadb-git-00d1db7a38b17d4512a6ba5147926608aca5624d.tar.gz |
Merge branch '10.1' into 10.2
Diffstat (limited to 'sql')
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, >id); + 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) |