summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <timour@askmonty.org>2011-02-10 16:16:06 +0200
committerunknown <timour@askmonty.org>2011-02-10 16:16:06 +0200
commitca37339585cd73363cb0d11cea73561cf78ee79f (patch)
tree6303cd62b5d49c95870a7ca6262a3514b63cf0f5
parent648e604615dfe852abbd467dbd8e6c3c9476dd07 (diff)
downloadmariadb-git-ca37339585cd73363cb0d11cea73561cf78ee79f.tar.gz
MWL#89
Fixed a memory leak found by valgrind. The memory leak was a result of JOINs corresponding to subselects in a global ORDER BY of a UNION not being cleaned up because the fake_select of the UNION didn't point down to the subquery select.
-rw-r--r--sql/item_subselect.cc20
-rw-r--r--sql/sql_lex.cc25
-rw-r--r--sql/sql_lex.h2
3 files changed, 34 insertions, 13 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index b30cf450d6d..bb99d20b305 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -326,23 +326,19 @@ bool Item_subselect::set_fake_select_as_master_processor(uchar *arg)
/*
Move the st_select_lex_unit of a subquery from a global ORDER BY clause to
become a direct child of the fake_select of a UNION. In this way the
- ORDER BY is applied to the temporary table that contains the result of the
- whole UNION, and all columns in the subquery are resolved against this table.
-
- Apply the transformation only for immediate child subqueries of a
- UNION query.
+ ORDER BY that is applied to the temporary table that contains the result of
+ the whole UNION, and all columns in the subquery are resolved against this
+ table. The transformation is applied only for immediate child subqueries of
+ a UNION query.
*/
if (unit->outer_select()->master_unit()->fake_select_lex == fake_select)
{
/*
- Set the master of the subquery to be the fake select (i.e. the whole UNION),
- instead of the last query in the UNION.
- TODO:
- This is a hack, instead we should call: unit->include_down(fake_select);
- However, this call results in an infinite loop where
- some_select_lex->master == some_select_lex.
+ Set the master of the subquery to be the fake select (i.e. the whole
+ UNION), instead of the last query in the UNION.
*/
- unit->set_master(fake_select);
+ fake_select->add_slave(unit);
+ DBUG_ASSERT(unit->outer_select() == fake_select);
/* Adjust the name resolution context hierarchy accordingly. */
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
sl->context.outer_context= &(fake_select->context);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e8a724cea82..f7e2f1835ad 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1684,6 +1684,31 @@ void st_select_lex_node::include_down(st_select_lex_node *upper)
slave= 0;
}
+
+void st_select_lex_node::add_slave(st_select_lex_node *slave_arg)
+{
+ for (; slave; slave= slave->next)
+ if (slave == slave_arg)
+ return;
+
+ if (slave)
+ {
+ st_select_lex_node *slave_arg_slave= slave_arg->slave;
+ /* Insert in the front of list of slaves if any. */
+ slave_arg->include_neighbour(slave);
+ /* include_neighbour() sets slave_arg->slave=0, restore it. */
+ slave_arg->slave= slave_arg_slave;
+ /* Count on include_neighbour() setting the master. */
+ DBUG_ASSERT(slave_arg->master == this);
+ }
+ else
+ {
+ slave= slave_arg;
+ slave_arg->master= this;
+ }
+}
+
+
/*
include on level down (but do not link)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 525d7c5cf46..eb5a7acbbd2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -439,10 +439,10 @@ public:
st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {}
virtual ~st_select_lex_node() {}
inline st_select_lex_node* get_master() { return master; }
- inline void set_master(st_select_lex_node* master_arg) { master= master_arg; }
virtual void init_query();
virtual void init_select();
void include_down(st_select_lex_node *upper);
+ void add_slave(st_select_lex_node *slave_arg);
void include_neighbour(st_select_lex_node *before);
void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref);
void include_global(st_select_lex_node **plink);