Backport 5.5=>5.1 Patch for Bug#13805127:
Stored program cache produces wrong result in same THD.
This commit is contained in:
parent
a9a7e6ea24
commit
d612986b36
@ -3040,3 +3040,106 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||||||
DEALLOCATE PREPARE stmt;
|
DEALLOCATE PREPARE stmt;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
End of 5.1 tests.
|
End of 5.1 tests.
|
||||||
|
|
||||||
|
# Bug#13805127: Stored program cache produces wrong result in same THD
|
||||||
|
|
||||||
|
PREPARE s1 FROM
|
||||||
|
"
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2
|
||||||
|
";
|
||||||
|
|
||||||
|
SET @x = 1;
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2;
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
2012-03-01 01:00:00 3 1
|
||||||
|
2012-03-01 02:00:00 3 1
|
||||||
|
|
||||||
|
EXECUTE s1;
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
2012-03-01 01:00:00 3 1
|
||||||
|
2012-03-01 02:00:00 3 1
|
||||||
|
|
||||||
|
SET @x = 2;
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2;
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
|
||||||
|
EXECUTE s1;
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
|
||||||
|
SET @x = 1;
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2;
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
2012-03-01 01:00:00 3 1
|
||||||
|
2012-03-01 02:00:00 3 1
|
||||||
|
|
||||||
|
EXECUTE s1;
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
2012-03-01 01:00:00 3 1
|
||||||
|
2012-03-01 02:00:00 3 1
|
||||||
|
DEALLOCATE PREPARE s1;
|
||||||
|
@ -7110,3 +7110,41 @@ DROP FUNCTION f1;
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# -- End of 5.1 tests
|
# -- End of 5.1 tests
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Bug#13805127: Stored program cache produces wrong result in same THD
|
||||||
|
|
||||||
|
CREATE PROCEDURE p1(x INT UNSIGNED)
|
||||||
|
BEGIN
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE x = 1 OR x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2
|
||||||
|
;
|
||||||
|
END|
|
||||||
|
|
||||||
|
CALL p1(1);
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
2012-03-01 01:00:00 3 1
|
||||||
|
2012-03-01 02:00:00 3 1
|
||||||
|
CALL p1(2);
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
CALL p1(1);
|
||||||
|
c1 c2 count(c3)
|
||||||
|
2012-03-01 01:00:00 2 1
|
||||||
|
2012-03-01 01:00:00 3 1
|
||||||
|
2012-03-01 02:00:00 3 1
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
@ -3102,3 +3102,93 @@ DEALLOCATE PREPARE stmt;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
--echo End of 5.1 tests.
|
--echo End of 5.1 tests.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo # Bug#13805127: Stored program cache produces wrong result in same THD
|
||||||
|
--echo
|
||||||
|
|
||||||
|
PREPARE s1 FROM
|
||||||
|
"
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2
|
||||||
|
";
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SET @x = 1;
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2;
|
||||||
|
--echo
|
||||||
|
EXECUTE s1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SET @x = 2;
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2;
|
||||||
|
--echo
|
||||||
|
EXECUTE s1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SET @x = 1;
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE @x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE @x = 1 OR @x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2;
|
||||||
|
--echo
|
||||||
|
EXECUTE s1;
|
||||||
|
|
||||||
|
DEALLOCATE PREPARE s1;
|
||||||
|
|
||||||
|
@ -8429,3 +8429,40 @@ DROP FUNCTION f1;
|
|||||||
--echo # ------------------------------------------------------------------
|
--echo # ------------------------------------------------------------------
|
||||||
--echo # -- End of 5.1 tests
|
--echo # -- End of 5.1 tests
|
||||||
--echo # ------------------------------------------------------------------
|
--echo # ------------------------------------------------------------------
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo # Bug#13805127: Stored program cache produces wrong result in same THD
|
||||||
|
--echo
|
||||||
|
|
||||||
|
delimiter |;
|
||||||
|
|
||||||
|
CREATE PROCEDURE p1(x INT UNSIGNED)
|
||||||
|
BEGIN
|
||||||
|
SELECT c1, t2.c2, count(c3)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT 3 as c2 FROM dual WHERE x = 1
|
||||||
|
UNION
|
||||||
|
SELECT 2 FROM dual WHERE x = 1 OR x = 2
|
||||||
|
) AS t1,
|
||||||
|
(
|
||||||
|
SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 02:00:00', 3, 2 FROM dual
|
||||||
|
UNION
|
||||||
|
SELECT '2012-03-01 01:00:00', 2, 1 FROM dual
|
||||||
|
) AS t2
|
||||||
|
WHERE t2.c2 = t1.c2
|
||||||
|
GROUP BY c1, c2
|
||||||
|
;
|
||||||
|
END|
|
||||||
|
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
--echo
|
||||||
|
CALL p1(1);
|
||||||
|
CALL p1(2);
|
||||||
|
CALL p1(1);
|
||||||
|
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
|
175
sql/mem_root_array.h
Normal file
175
sql/mem_root_array.h
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
|
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
|
||||||
|
the Free Software Foundation; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MEM_ROOT_ARRAY_INCLUDED
|
||||||
|
#define MEM_ROOT_ARRAY_INCLUDED
|
||||||
|
|
||||||
|
#include <my_alloc.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
A typesafe replacement for DYNAMIC_ARRAY.
|
||||||
|
We use MEM_ROOT for allocating storage, rather than the C++ heap.
|
||||||
|
The interface is chosen to be similar to std::vector.
|
||||||
|
|
||||||
|
@remark
|
||||||
|
Unlike DYNAMIC_ARRAY, elements are properly copied
|
||||||
|
(rather than memcpy()d) if the underlying array needs to be expanded.
|
||||||
|
|
||||||
|
@remark
|
||||||
|
Depending on has_trivial_destructor, we destroy objects which are
|
||||||
|
removed from the array (including when the array object itself is destroyed).
|
||||||
|
|
||||||
|
@remark
|
||||||
|
Note that MEM_ROOT has no facility for reusing free space,
|
||||||
|
so don't use this if multiple re-expansions are likely to happen.
|
||||||
|
|
||||||
|
@param Element_type The type of the elements of the container.
|
||||||
|
Elements must be copyable.
|
||||||
|
@param has_trivial_destructor If true, we don't destroy elements.
|
||||||
|
We could have used type traits to determine this.
|
||||||
|
__has_trivial_destructor is supported by some (but not all)
|
||||||
|
compilers we use.
|
||||||
|
*/
|
||||||
|
template<typename Element_type, bool has_trivial_destructor>
|
||||||
|
class Mem_root_array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mem_root_array(MEM_ROOT *root)
|
||||||
|
: m_root(root), m_array(NULL), m_size(0), m_capacity(0)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(m_root != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Mem_root_array()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Element_type &at(size_t n)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(n < size());
|
||||||
|
return m_array[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Element_type &at(size_t n) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(n < size());
|
||||||
|
return m_array[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a pointer to the first element in the array.
|
||||||
|
Element_type *begin() { return &m_array[0]; }
|
||||||
|
|
||||||
|
// Returns a pointer to the past-the-end element in the array.
|
||||||
|
Element_type *end() { return &m_array[size()]; }
|
||||||
|
|
||||||
|
// Erases all of the elements.
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (!empty())
|
||||||
|
chop(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Chops the tail off the array, erasing all tail elements.
|
||||||
|
@param pos Index of first element to erase.
|
||||||
|
*/
|
||||||
|
void chop(const size_t pos)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(pos < m_size);
|
||||||
|
if (!has_trivial_destructor)
|
||||||
|
{
|
||||||
|
for (size_t ix= pos; ix < m_size; ++ix)
|
||||||
|
{
|
||||||
|
Element_type *p= &m_array[ix];
|
||||||
|
p->~Element_type(); // Destroy discarded element.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_size= pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reserves space for array elements.
|
||||||
|
Copies over existing elements, in case we are re-expanding the array.
|
||||||
|
|
||||||
|
@param n number of elements.
|
||||||
|
@retval true if out-of-memory, false otherwise.
|
||||||
|
*/
|
||||||
|
bool reserve(size_t n)
|
||||||
|
{
|
||||||
|
if (n <= m_capacity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
void *mem= alloc_root(m_root, n * element_size());
|
||||||
|
if (!mem)
|
||||||
|
return true;
|
||||||
|
Element_type *array= static_cast<Element_type*>(mem);
|
||||||
|
|
||||||
|
// Copy all the existing elements into the new array.
|
||||||
|
for (size_t ix= 0; ix < m_size; ++ix)
|
||||||
|
{
|
||||||
|
Element_type *new_p= &array[ix];
|
||||||
|
Element_type *old_p= &m_array[ix];
|
||||||
|
new (new_p) Element_type(*old_p); // Copy into new location.
|
||||||
|
if (!has_trivial_destructor)
|
||||||
|
old_p->~Element_type(); // Destroy the old element.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forget the old array.
|
||||||
|
m_array= array;
|
||||||
|
m_capacity= n;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Adds a new element at the end of the array, after its current last
|
||||||
|
element. The content of this new element is initialized to a copy of
|
||||||
|
the input argument.
|
||||||
|
|
||||||
|
@param element Object to copy.
|
||||||
|
@retval true if out-of-memory, false otherwise.
|
||||||
|
*/
|
||||||
|
bool push_back(const Element_type &element)
|
||||||
|
{
|
||||||
|
const size_t min_capacity= 20;
|
||||||
|
const size_t expansion_factor= 2;
|
||||||
|
if (0 == m_capacity && reserve(min_capacity))
|
||||||
|
return true;
|
||||||
|
if (m_size == m_capacity && reserve(m_capacity * expansion_factor))
|
||||||
|
return true;
|
||||||
|
Element_type *p= &m_array[m_size++];
|
||||||
|
new (p) Element_type(element);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity() const { return m_capacity; }
|
||||||
|
size_t element_size() const { return sizeof(Element_type); }
|
||||||
|
bool empty() const { return size() == 0; }
|
||||||
|
size_t size() const { return m_size; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MEM_ROOT *const m_root;
|
||||||
|
Element_type *m_array;
|
||||||
|
size_t m_size;
|
||||||
|
size_t m_capacity;
|
||||||
|
|
||||||
|
// Not (yet) implemented.
|
||||||
|
Mem_root_array(const Mem_root_array&);
|
||||||
|
Mem_root_array &operator=(const Mem_root_array&);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MEM_ROOT_ARRAY_INCLUDED
|
@ -305,6 +305,8 @@ void lex_start(THD *thd)
|
|||||||
lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
|
lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
|
||||||
lex->select_lex.init_order();
|
lex->select_lex.init_order();
|
||||||
lex->select_lex.group_list.empty();
|
lex->select_lex.group_list.empty();
|
||||||
|
if (lex->select_lex.group_list_ptrs)
|
||||||
|
lex->select_lex.group_list_ptrs->clear();
|
||||||
lex->describe= 0;
|
lex->describe= 0;
|
||||||
lex->subqueries= FALSE;
|
lex->subqueries= FALSE;
|
||||||
lex->context_analysis_only= 0;
|
lex->context_analysis_only= 0;
|
||||||
@ -1632,6 +1634,8 @@ void st_select_lex::init_select()
|
|||||||
{
|
{
|
||||||
st_select_lex_node::init_select();
|
st_select_lex_node::init_select();
|
||||||
group_list.empty();
|
group_list.empty();
|
||||||
|
if (group_list_ptrs)
|
||||||
|
group_list_ptrs->clear();
|
||||||
type= db= 0;
|
type= db= 0;
|
||||||
having= 0;
|
having= 0;
|
||||||
table_join_options= 0;
|
table_join_options= 0;
|
||||||
@ -2901,6 +2905,8 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
|
|||||||
The passed WHERE and HAVING are to be saved for the future executions.
|
The passed WHERE and HAVING are to be saved for the future executions.
|
||||||
This function saves it, and returns a copy which can be thrashed during
|
This function saves it, and returns a copy which can be thrashed during
|
||||||
this execution of the statement. By saving/thrashing here we mean only
|
this execution of the statement. By saving/thrashing here we mean only
|
||||||
|
We also save the chain of ORDER::next in group_list, in case
|
||||||
|
the list is modified by remove_const().
|
||||||
AND/OR trees.
|
AND/OR trees.
|
||||||
The function also calls fix_prepare_info_in_table_list that saves all
|
The function also calls fix_prepare_info_in_table_list that saves all
|
||||||
ON expressions.
|
ON expressions.
|
||||||
@ -2912,6 +2918,19 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
|
|||||||
if (!thd->stmt_arena->is_conventional() && first_execution)
|
if (!thd->stmt_arena->is_conventional() && first_execution)
|
||||||
{
|
{
|
||||||
first_execution= 0;
|
first_execution= 0;
|
||||||
|
if (group_list.first)
|
||||||
|
{
|
||||||
|
if (!group_list_ptrs)
|
||||||
|
{
|
||||||
|
void *mem= thd->stmt_arena->alloc(sizeof(Group_list_ptrs));
|
||||||
|
group_list_ptrs= new (mem) Group_list_ptrs(thd->stmt_arena->mem_root);
|
||||||
|
}
|
||||||
|
group_list_ptrs->reserve(group_list.elements);
|
||||||
|
for (ORDER *order= group_list.first; order; order= order->next)
|
||||||
|
{
|
||||||
|
group_list_ptrs->push_back(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (*conds)
|
if (*conds)
|
||||||
{
|
{
|
||||||
prep_where= *conds;
|
prep_where= *conds;
|
||||||
@ -3016,3 +3035,6 @@ bool st_lex::is_partition_management() const
|
|||||||
alter_info.flags == ALTER_REORGANIZE_PARTITION));
|
alter_info.flags == ALTER_REORGANIZE_PARTITION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
||||||
|
template class Mem_root_array<ORDER*, true>;
|
||||||
|
#endif
|
||||||
|
@ -40,6 +40,7 @@ class Event_parse_data;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "set_var.h"
|
#include "set_var.h"
|
||||||
|
#include "mem_root_array.h"
|
||||||
|
|
||||||
#ifdef MYSQL_YACC
|
#ifdef MYSQL_YACC
|
||||||
#define LEX_YYSTYPE void *
|
#define LEX_YYSTYPE void *
|
||||||
@ -183,6 +184,7 @@ enum enum_drop_mode
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef List<Item> List_item;
|
typedef List<Item> List_item;
|
||||||
|
typedef Mem_root_array<ORDER*, true> Group_list_ptrs;
|
||||||
|
|
||||||
/* SERVERS CACHE CHANGES */
|
/* SERVERS CACHE CHANGES */
|
||||||
typedef struct st_lex_server_options
|
typedef struct st_lex_server_options
|
||||||
@ -590,7 +592,16 @@ public:
|
|||||||
enum olap_type olap;
|
enum olap_type olap;
|
||||||
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
|
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
|
||||||
SQL_I_List<TABLE_LIST> table_list;
|
SQL_I_List<TABLE_LIST> table_list;
|
||||||
SQL_I_List<ORDER> group_list; /* GROUP BY clause. */
|
|
||||||
|
/*
|
||||||
|
GROUP BY clause.
|
||||||
|
This list may be mutated during optimization (by remove_const()),
|
||||||
|
so for prepared statements, we keep a copy of the ORDER.next pointers in
|
||||||
|
group_list_ptrs, and re-establish the original list before each execution.
|
||||||
|
*/
|
||||||
|
SQL_I_List<ORDER> group_list;
|
||||||
|
Group_list_ptrs *group_list_ptrs;
|
||||||
|
|
||||||
List<Item> item_list; /* list of fields & expressions */
|
List<Item> item_list; /* list of fields & expressions */
|
||||||
List<String> interval_list;
|
List<String> interval_list;
|
||||||
bool is_item_list_lookup;
|
bool is_item_list_lookup;
|
||||||
@ -779,7 +790,8 @@ public:
|
|||||||
bool test_limit();
|
bool test_limit();
|
||||||
|
|
||||||
friend void lex_start(THD *thd);
|
friend void lex_start(THD *thd);
|
||||||
st_select_lex() : n_sum_items(0), n_child_sum_items(0) {}
|
st_select_lex() : group_list_ptrs(NULL), n_sum_items(0), n_child_sum_items(0)
|
||||||
|
{}
|
||||||
void make_empty_select()
|
void make_empty_select()
|
||||||
{
|
{
|
||||||
init_query();
|
init_query();
|
||||||
|
@ -2361,6 +2361,14 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
|
|||||||
DBUG_ASSERT(sl->join == 0);
|
DBUG_ASSERT(sl->join == 0);
|
||||||
ORDER *order;
|
ORDER *order;
|
||||||
/* Fix GROUP list */
|
/* Fix GROUP list */
|
||||||
|
if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0)
|
||||||
|
{
|
||||||
|
for (uint ix= 0; ix < sl->group_list_ptrs->size() - 1; ++ix)
|
||||||
|
{
|
||||||
|
order= sl->group_list_ptrs->at(ix);
|
||||||
|
order->next= sl->group_list_ptrs->at(ix+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (order= sl->group_list.first; order; order= order->next)
|
for (order= sl->group_list.first; order; order= order->next)
|
||||||
order->item= &order->item_ptr;
|
order->item= &order->item_ptr;
|
||||||
/* Fix ORDER list */
|
/* Fix ORDER list */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user