Commit 936688fe authored by unknown's avatar unknown
Browse files

A followup patch for Bug#7306 (limit in prepared statements):

don't evaluate subqueries during statement prepare, even if they
are not correlated.
With post-review fixes.


sql/mysql_priv.h:
  Add UNCACHEABLE_PREPARE to mark subqueries as non-constant in 
  mysql_stmt_prepare
sql/sql_lex.cc:
  Add a missing assert: noone can call unit::set_limit from 
  mysql_stmt_prepare.
sql/sql_lex.h:
  Comment fixed.
sql/sql_parse.cc:
  Mark new SELECT_LEXes as uncacheable if they created during 
  statement prepare.
sql/sql_prepare.cc:
  Switch off the uncacheable flag when prepare is done.
parent 0bc3c622
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -336,6 +336,8 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define UNCACHEABLE_SIDEEFFECT	4
// forcing to save JOIN for explain
#define UNCACHEABLE_EXPLAIN     8
/* Don't evaluate subqueries in prepare even if they're not correlated */
#define UNCACHEABLE_PREPARE    16

#ifdef EXTRA_DEBUG
/*
+1 −0
Original line number Diff line number Diff line
@@ -1757,6 +1757,7 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl)
{
  ulonglong select_limit_val;

  DBUG_ASSERT(! thd->current_arena->is_stmt_prepare());
  select_limit_val= sl->select_limit ? sl->select_limit->val_uint() :
                                       HA_POS_ERROR;
  offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0);
+1 −0
Original line number Diff line number Diff line
@@ -303,6 +303,7 @@ class st_select_lex_node {
      UNCACHEABLE_RAND
      UNCACHEABLE_SIDEEFFECT
      UNCACHEABLE_EXPLAIN
      UNCACHEABLE_PREPARE
  */
  uint8 uncacheable;
  enum sub_select_type linkage;
+8 −6
Original line number Diff line number Diff line
@@ -5169,26 +5169,28 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
  SELECT_LEX *select_lex;
  THD *thd;
  THD *thd= lex->thd;
  DBUG_ENTER("mysql_new_select");

  if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
    DBUG_RETURN(1);
  select_lex->select_number= ++lex->thd->select_number;
  select_lex->select_number= ++thd->select_number;
  select_lex->init_query();
  select_lex->init_select();
  select_lex->parent_lex= lex;
  if (thd->current_arena->is_stmt_prepare())
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
  if (move_down)
  {
    SELECT_LEX_UNIT *unit;
    lex->subqueries= TRUE;
    /* first select_lex of subselect or derived table */
    if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
      DBUG_RETURN(1);

    unit->init_query();
    unit->init_select();
    unit->thd= lex->thd;
    unit->thd= thd;
    unit->include_down(lex->current_select);
    unit->link_next= 0;
    unit->link_prev= 0;
@@ -5212,7 +5214,7 @@ mysql_new_select(LEX *lex, bool move_down)
	as far as we included SELECT_LEX for UNION unit should have
	fake SELECT_LEX for UNION processing
      */
      if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
      if (!(fake= unit->fake_select_lex= new (thd->mem_root) SELECT_LEX()))
        DBUG_RETURN(1);
      fake->include_standalone(unit,
			       (SELECT_LEX_NODE**)&unit->fake_select_lex);
+3 −0
Original line number Diff line number Diff line
@@ -1838,7 +1838,10 @@ void init_stmt_after_parse(THD *thd, LEX *lex)
    optimisation.
  */
  for (; sl; sl= sl->next_select_in_list())
  {
    sl->prep_where= sl->where;
    sl->uncacheable&= ~UNCACHEABLE_PREPARE;
  }

  for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
    table->prep_on_expr= table->on_expr;