sql_union.cc 16.6 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

   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; either version 2 of the License, or
   (at your option) any later version.

   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 */


/*
  UNION  of select's
  UNION's  were introduced by Monty and Sinisa <sinisa@mysql.com>
*/


#include "mysql_priv.h"
#include "sql_select.h"

27
int mysql_union(THD *thd, LEX *lex, select_result *result,
28
		SELECT_LEX_UNIT *unit)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
29 30 31
{
  DBUG_ENTER("mysql_union");
  int res= 0;
32
  if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK)))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
33 34 35 36 37 38 39 40 41 42 43
    res= unit->exec();
  res|= unit->cleanup();
  DBUG_RETURN(res);
}


/***************************************************************************
** store records in temporary table for UNION
***************************************************************************/

select_union::select_union(TABLE *table_par)
44
  :table(table_par)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
{
  bzero((char*) &info,sizeof(info));
  /*
    We can always use DUP_IGNORE because the temporary table will only
    contain a unique key if we are using not using UNION ALL
  */
  info.handle_duplicates= DUP_IGNORE;
}

select_union::~select_union()
{
}


int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
  unit= u;
  return 0;
}

65

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
66 67 68 69 70 71 72
bool select_union::send_data(List<Item> &values)
{
  if (unit->offset_limit_cnt)
  {						// using limit offset,count
    unit->offset_limit_cnt--;
    return 0;
  }
73
  fill_record(table->field, values, 1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
74
  if (thd->net.report_error || write_record(table,&info))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
75
  {
76 77 78
    if (thd->net.last_errno == ER_RECORD_FILE_FULL)
    {
      thd->clear_error(); // do not report user about table overflow
79
      if (create_myisam_from_heap(thd, table, &tmp_table_param,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
80
				  info.last_errno, 1))
81 82 83
	return 1;
    }
    else
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
84 85 86 87 88
      return 1;
  }
  return 0;
}

89

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
90 91 92 93
bool select_union::send_eof()
{
  return 0;
}
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
94

95

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
96
bool select_union::flush()
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
97
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
98 99 100 101
  int error;
  if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
  {
    table->file->print_error(error,MYF(0));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
102
    ::send_error(thd);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
103 104 105 106 107
    return 1;
  }
  return 0;
}

108

109 110 111 112 113 114 115 116 117 118 119 120 121 122
/*
  initialization procedures before fake_select_lex preparation()

  SYNOPSIS
    st_select_lex_unit::init_prepare_fake_select_lex()
    thd		- thread handler

  RETURN
    options of SELECT
*/

ulong
st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) 
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
123
  ulong options_tmp= thd->options | fake_select_lex->options;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  thd->lex->current_select= fake_select_lex;
  offset_limit_cnt= global_parameters->offset_limit;
  select_limit_cnt= global_parameters->select_limit +
    global_parameters->offset_limit;

  if (select_limit_cnt < global_parameters->select_limit)
    select_limit_cnt= HA_POS_ERROR;		// no limit
  if (select_limit_cnt == HA_POS_ERROR)
    options_tmp&= ~OPTION_FOUND_ROWS;
  else if (found_rows_for_union && !thd->lex->describe)
    options_tmp|= OPTION_FOUND_ROWS;
  fake_select_lex->ftfunc_list_alloc.empty();
  fake_select_lex->ftfunc_list= &fake_select_lex->ftfunc_list_alloc;
  fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
					   (byte **)
					   &result_table_list.next);
  return options_tmp;
}


144 145
int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
				ulong additional_options)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
146
{
147
  SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
148 149
  SELECT_LEX *sl, *first_select;
  select_result *tmp_result;
150
  bool is_union;
151 152
  DBUG_ENTER("st_select_lex_unit::prepare");

153 154
  describe= test(additional_options & SELECT_DESCRIBE);

155 156 157 158 159 160
  /*
    result object should be reassigned even if preparing already done for
    max/min subquery (ALL/ANY optimization)
  */
  result= sel_result;

161
  if (prepared)
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  {
    if (describe)
    {
      /* fast reinit for EXPLAIN */
      for (sl= first_select_in_union(); sl; sl= sl->next_select())
      {
	sl->join->result= result;
	select_limit_cnt= HA_POS_ERROR;
	offset_limit_cnt= 0;
	if (!sl->join->procedure &&
	    result->prepare(sl->join->fields_list, this))
	{
	  DBUG_RETURN(1);
	}
	sl->join->select_options|= SELECT_DESCRIBE;
	sl->join->reinit();
      }
    }
180
    DBUG_RETURN(0);
181
  }
182
  prepared= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
183
  res= 0;
184
  
185
  thd_arg->lex->current_select= sl= first_select= first_select_in_union();
186
  found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
187
  is_union= test(first_select->next_select());
188

189
  /* Global option */
190

191
  if (is_union)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
192
  {
193 194
    if (!(tmp_result= union_result= new select_union(0)))
      goto err;
195
    union_result->tmp_table_param.init();
196 197
    if (describe)
      tmp_result= sel_result;
198 199
  }
  else
200
    tmp_result= sel_result;
201

202
  for (;sl; sl= sl->next_select())
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
203
  {
204
    bool can_skip_order_by;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
205
    sl->options|=  SELECT_NO_UNLOCK;
206
    JOIN *join= new JOIN(thd_arg, sl->item_list, 
207
			 sl->options | thd_arg->options | additional_options,
208
			 tmp_result);
monty@mysql.com's avatar
monty@mysql.com committed
209 210 211
    if (!join)
      goto err;

212
    thd_arg->lex->current_select= sl;
213 214 215 216
    offset_limit_cnt= sl->offset_limit;
    select_limit_cnt= sl->select_limit+sl->offset_limit;
    if (select_limit_cnt < sl->select_limit)
      select_limit_cnt= HA_POS_ERROR;		// no limit
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
217
    if (select_limit_cnt == HA_POS_ERROR || sl->braces)
218
      sl->options&= ~OPTION_FOUND_ROWS;
219 220 221 222

    can_skip_order_by= is_union &&
                       (!sl->braces || select_limit_cnt == HA_POS_ERROR);

223 224 225
    res= join->prepare(&sl->ref_pointer_array,
		       (TABLE_LIST*) sl->table_list.first, sl->with_wild,
		       sl->where,
226 227 228 229
                       (can_skip_order_by ? 0 : sl->order_list.elements) +
                       sl->group_list.elements,
                       can_skip_order_by ?
                       (ORDER*) 0 : (ORDER *)sl->order_list.first,
230 231 232
		       (ORDER*) sl->group_list.first,
		       sl->having,
		       (ORDER*) NULL,
233
		       sl, this);
234
    if (res || thd_arg->is_fatal_error)
235
      goto err;
236 237 238 239
    if (sl == first_select)
    {
      types.empty();
      List_iterator_fast<Item> it(sl->item_list);
240 241
      Item *item_tmp;
      while ((item_tmp= it++))
242
      {
monty@mysql.com's avatar
monty@mysql.com committed
243
	/* Error's in 'new' will be detected after loop */
244
	types.push_back(new Item_type_holder(thd_arg, item_tmp));
245 246
      }

247
      if (thd_arg->is_fatal_error)
248 249 250 251 252 253 254 255 256 257 258 259
	goto err; // out of memory
    }
    else
    {
      if (types.elements != sl->item_list.elements)
      {
	my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
		   ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
	goto err;
      }
      List_iterator_fast<Item> it(sl->item_list);
      List_iterator_fast<Item> tp(types);	
260 261
      Item *type, *item_tmp;
      while ((type= tp++, item_tmp= it++))
262
      {
263
	if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
264
	  DBUG_RETURN(-1);
265 266
      }
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
267
  }
268

269
  if (is_union)
270 271
  {
    /*
bar@mysql.com's avatar
bar@mysql.com committed
272 273
      Check that it was possible to aggregate
      all collations together for UNION.
274 275
    */
    List_iterator_fast<Item> tp(types);
276
    Item_arena *arena= thd->current_arena;
277 278 279 280 281 282 283 284 285 286 287
    Item *type;
    while ((type= tp++))
    {
      if (type->result_type() == STRING_RESULT &&
          type->collation.derivation == DERIVATION_NONE)
      {
        my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), "UNION");
        goto err;
      }
    }

288 289 290
    union_result->tmp_table_param.field_count= types.elements;
    if (!(table= create_tmp_table(thd_arg,
				  &union_result->tmp_table_param, types,
291
				  (ORDER*) 0, (bool) union_distinct, 1, 
292
				  (first_select_in_union()->options |
293
				   thd_arg->options |
294 295 296 297 298 299 300 301 302 303
				   TMP_TABLE_ALL_COLUMNS),
				  HA_POS_ERROR, (char*) "")))
      goto err;
    table->file->extra(HA_EXTRA_WRITE_CACHE);
    table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
    bzero((char*) &result_table_list, sizeof(result_table_list));
    result_table_list.db= (char*) "";
    result_table_list.real_name= result_table_list.alias= (char*) "union";
    result_table_list.table= table;
    union_result->set_table(table);
304

305
    thd_arg->lex->current_select= lex_select_save;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
306 307
    if (!item_list.elements)
    {
308 309 310 311 312
      /*
        We're in statement prepare or in execution
        of a conventional statement.
      */
      Item_arena backup;
313 314
      if (arena->is_stmt_prepare())
	thd->set_n_backup_item_arena(arena, &backup);
315 316 317
      Field **field;
      for (field= table->field; *field; field++)
      {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
318 319
	Item_field *item= new Item_field(*field);
	if (!item || item_list.push_back(item))
320
	{
321 322
          if (arena->is_stmt_prepare())
	    thd->restore_backup_item_arena(arena, &backup);
323
	  DBUG_RETURN(-1);
324
	}
325
      }
326
      if (arena->is_stmt_prepare())
327
      {
328
	thd->restore_backup_item_arena(arena, &backup);
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350

	/* prepare fake select to initialize it correctly */
	ulong options_tmp= init_prepare_fake_select_lex(thd);
	if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
					      result)))
	{
	  fake_select_lex->table_list.empty();
	  DBUG_RETURN(-1);
	}
	fake_select_lex->item_list= item_list;

	thd_arg->lex->current_select= fake_select_lex;
	res= fake_select_lex->join->
	  prepare(&fake_select_lex->ref_pointer_array,
		  (TABLE_LIST*) fake_select_lex->table_list.first,
		  0, 0,
		  fake_select_lex->order_list.elements,
		  (ORDER*) fake_select_lex->order_list.first,
		  (ORDER*) NULL, NULL, (ORDER*) NULL,
		  fake_select_lex, this);
	fake_select_lex->table_list.empty();
      }
351
    }
352 353 354 355 356 357 358 359 360 361 362
    else if (arena->is_stmt_execute())
    {
      /*
        We're in execution of a prepared statement: reset field items
        to point at fields from the created temporary table.
      */
      List_iterator_fast<Item> it(item_list);
      for (Field **field= table->field; *field; field++)
      {
        Item_field *item_field= (Item_field*) it++;
        DBUG_ASSERT(item_field);
363
        item_field->reset_field(*field);
364 365
      }
    }
366
  }
367

368
  thd_arg->lex->current_select= lex_select_save;
369

370
  DBUG_RETURN(res || thd_arg->is_fatal_error ? 1 : 0);
371

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
372
err:
373
  thd_arg->lex->current_select= lex_select_save;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
374
  DBUG_RETURN(-1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
375 376
}

377

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
378 379
int st_select_lex_unit::exec()
{
380
  SELECT_LEX *lex_select_save= thd->lex->current_select;
381
  SELECT_LEX *select_cursor=first_select_in_union();
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
382
  ulonglong add_rows=0;
383
  ha_rows examined_rows= 0;
384 385
  DBUG_ENTER("st_select_lex_unit::exec");

386
  if (executed && !uncacheable && !describe)
387 388 389
    DBUG_RETURN(0);
  executed= 1;
  
390
  if (uncacheable || !item || !item->assigned() || describe)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
391
  {
392
    if (optimized && item)
393
    {
394 395 396 397 398 399 400 401 402
      if (item->assigned())
      {
        item->assigned(0); // We will reinit & rexecute unit
        item->reset();
        table->file->delete_all_rows();
      }
      /* re-enabling indexes for next subselect iteration */
      if (union_distinct && table->file->enable_indexes(HA_KEY_SWITCH_ALL))
        DBUG_ASSERT(1);
403
    }
404
    for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
405
    {
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
406
      ha_rows records_at_start= 0;
407
      thd->lex->current_select= sl;
408

409
      if (optimized)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
410
	res= sl->join->reinit();
411 412
      else
      {
413
	if (sl != global_parameters && !describe)
414 415 416 417 418 419 420 421 422 423 424
	{
	  offset_limit_cnt= sl->offset_limit;
	  select_limit_cnt= sl->select_limit+sl->offset_limit;
	}
	else
	{
	  offset_limit_cnt= 0;
	  /*
	    We can't use LIMIT at this stage if we are using ORDER BY for the
	    whole query
	  */
425
	  if (sl->order_list.first || describe)
426 427 428 429
	    select_limit_cnt= HA_POS_ERROR;
	  else
	    select_limit_cnt= sl->select_limit+sl->offset_limit;
	}
430 431
	if (select_limit_cnt < sl->select_limit)
	  select_limit_cnt= HA_POS_ERROR;		// no limit
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
432 433 434 435 436

	/*
	  When using braces, SQL_CALC_FOUND_ROWS affects the whole query.
	  We don't calculate found_rows() per union part
	*/
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
437
	if (select_limit_cnt == HA_POS_ERROR || sl->braces)
438
	  sl->options&= ~OPTION_FOUND_ROWS;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
439
	else 
440
	{
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
441 442 443 444 445
	  /*
	    We are doing an union without braces.  In this case
	    SQL_CALC_FOUND_ROWS should be done on all sub parts
	  */
	  sl->options|= found_rows_for_union;
446
	}
447
	sl->join->select_options=sl->options;
448 449
	res= sl->join->optimize();
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
450 451
      if (!res)
      {
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
452
	records_at_start= table->file->records;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
453
	sl->join->exec();
454
        if (sl == union_distinct)
455 456 457 458 459
	{
	  if (table->file->disable_indexes(HA_KEY_SWITCH_ALL))
	    DBUG_RETURN(1);
	  table->no_keyread=1;
	}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
460
	res= sl->join->error;
461
	offset_limit_cnt= sl->offset_limit;
462 463
	if (!res && union_result->flush())
	{
464
          examined_rows+= thd->examined_row_count;
465
	  thd->lex->current_select= lex_select_save;
466 467
	  DBUG_RETURN(1);
	}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
468
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
469
      if (res)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
470
      {
471
	thd->lex->current_select= lex_select_save;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
472
	DBUG_RETURN(res);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
473
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
474 475
      /* Needed for the following test and for records_at_start in next loop */
      table->file->info(HA_STATUS_VARIABLE);
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
476 477 478
      if (found_rows_for_union & sl->options)
      {
	/*
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
479 480
	  This is a union without braces. Remember the number of rows that
	  could also have been part of the result set.
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
481 482 483
	  We get this from the difference of between total number of possible
	  rows and actual rows added to the temporary table.
	*/
484
	add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong)
485
			      ((table->file->records -  records_at_start)));
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
486
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
487
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
488
  }
489
  optimized= 1;
490 491

  /* Send result to 'result' */
492
  res= -1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
493
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
494 495
    List<Item_func_match> empty_list;
    empty_list.empty();
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
496

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
497
    if (!thd->is_fatal_error)				// Check if EOM
498
    {
499
      ulong options_tmp= init_prepare_fake_select_lex(thd);
500 501 502 503
      JOIN *join= fake_select_lex->join;
      if (!join)
      {
	/*
monty@mysql.com's avatar
monty@mysql.com committed
504
	  allocate JOIN for fake select only once (prevent
505 506
	  mysql_select automatic allocation)
	*/
monty@mysql.com's avatar
monty@mysql.com committed
507 508
	if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
					      result)))
509 510
	{
	  fake_select_lex->table_list.empty();
monty@mysql.com's avatar
monty@mysql.com committed
511
	  DBUG_RETURN(-1);
512
	}
monty@mysql.com's avatar
monty@mysql.com committed
513

514 515 516 517 518
	/*
	  Fake st_select_lex should have item list for correctref_array
	  allocation.
	*/
	fake_select_lex->item_list= item_list;
519 520 521 522 523 524 525 526 527 528 529
      }
      else
      {
	JOIN_TAB *tab,*end;
	for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
	{
	  delete tab->select;
	  delete tab->quick;
	}
	join->init(thd, item_list, thd->options, result);
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
530 531
      res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
			&result_table_list,
532 533
			0, item_list, NULL,
			global_parameters->order_list.elements,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
534
			(ORDER*)global_parameters->order_list.first,
535
			(ORDER*) NULL, NULL, (ORDER*) NULL,
536
			options_tmp | SELECT_NO_UNLOCK,
537
			result, this, fake_select_lex);
538 539

      fake_select_lex->table_list.empty();
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
540
      if (!res)
541
      {
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
542
	thd->limit_found_rows = (ulonglong)table->file->records + add_rows;
543
        thd->examined_row_count+= examined_rows;
544
      }
545 546 547 548
      /*
	Mark for slow query log if any of the union parts didn't use
	indexes efficiently
      */
549
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
550
  }
551
  thd->lex->current_select= lex_select_save;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
552 553 554
  DBUG_RETURN(res);
}

555

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
556
int st_select_lex_unit::cleanup()
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
557
{
558
  int error= 0;
559
  DBUG_ENTER("st_select_lex_unit::cleanup");
560

561 562 563 564
  if (cleaned)
  {
    DBUG_RETURN(0);
  }
565
  cleaned= 1;
566

567 568 569
  if (union_result)
  {
    delete union_result;
570
    union_result=0; // Safety
571 572
    if (table)
      free_tmp_table(thd, table);
573 574
    table= 0; // Safety
  }
575
  JOIN *join;
576 577
  SELECT_LEX *sl= first_select_in_union();
  for (; sl; sl= sl->next_select())
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
578
  {
579 580
    if ((join= sl->join))
    {
581
      error|= sl->join->cleanup();
582 583
      delete join;
    }
584 585 586 587 588 589 590 591 592 593
    else
    {
      // it can be DO/SET with subqueries
      for (SELECT_LEX_UNIT *lex_unit= sl->first_inner_unit();
	   lex_unit != 0;
	   lex_unit= lex_unit->next_unit())
      {
	error|= lex_unit->cleanup();
      }
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
594
  }
595 596 597 598 599 600 601
  if (fake_select_lex && (join= fake_select_lex->join))
  {
    join->tables_list= 0;
    join->tables= 0;
    error|= join->cleanup();
    delete join;
  }
602
  DBUG_RETURN(error);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
603
}
604 605 606 607 608


void st_select_lex_unit::reinit_exec_mechanism()
{
  prepared= optimized= executed= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
609
#ifndef DBUG_OFF
610
  if (first_select()->next_select())
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
611
  {
612 613 614 615 616 617 618 619 620 621 622
    List_iterator_fast<Item> it(item_list);
    Item *field;
    while ((field= it++))
    {
      /*
	we can't cleanup here, because it broke link to temporary table field,
	but have to drop fixed flag to allow next fix_field of this field
	during re-executing
      */
      field->fixed= 0;
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
623 624
  }
#endif
625
}
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654


/*
  change select_result object of unit

  SYNOPSIS
    st_select_lex_unit::change_result()
    result	new select_result object
    old_result	old select_result object

  RETURN
    0 - OK
    -1 - error
*/

int st_select_lex_unit::change_result(select_subselect *result,
				      select_subselect *old_result)
{
  int res= 0;
  for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
  {
    if (sl->join && sl->join->result == old_result)
      if ((res= sl->join->change_result(result)))
	return (res);
  }
  if (fake_select_lex && fake_select_lex->join)
    res= fake_select_lex->join->change_result(result);
  return (res);
}