sql_union.cc 16.5 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 151
  DBUG_ENTER("st_select_lex_unit::prepare");

152 153
  describe= test(additional_options & SELECT_DESCRIBE);

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

160
  if (prepared)
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  {
    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();
      }
    }
179
    DBUG_RETURN(0);
180
  }
181
  prepared= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
182
  res= 0;
183
  
184
  thd_arg->lex->current_select= sl= first_select= first_select_in_union();
185 186
  found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;

187
  /* Global option */
188 189

  if (first_select->next_select())
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
190
  {
191 192
    if (!(tmp_result= union_result= new select_union(0)))
      goto err;
193
    union_result->tmp_table_param.init();
194 195
    if (describe)
      tmp_result= sel_result;
196 197 198
  }
  else
  {
199 200 201
    tmp_result= sel_result;
    // single select should be processed like select in p[arantses
    first_select->braces= 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
202
  }
203

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

213
    thd_arg->lex->current_select= sl;
214 215 216 217
    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
218
    if (select_limit_cnt == HA_POS_ERROR || sl->braces)
219 220 221 222 223 224 225 226 227 228 229 230
      sl->options&= ~OPTION_FOUND_ROWS;
    
    res= join->prepare(&sl->ref_pointer_array,
		       (TABLE_LIST*) sl->table_list.first, sl->with_wild,
		       sl->where,
		       ((sl->braces) ? sl->order_list.elements : 0) +
		       sl->group_list.elements,
		       (sl->braces) ? 
		       (ORDER *)sl->order_list.first : (ORDER *) 0,
		       (ORDER*) sl->group_list.first,
		       sl->having,
		       (ORDER*) NULL,
231
		       sl, this);
232
    if (res || thd_arg->is_fatal_error)
233
      goto err;
234 235 236 237
    if (sl == first_select)
    {
      types.empty();
      List_iterator_fast<Item> it(sl->item_list);
238 239
      Item *item_tmp;
      while ((item_tmp= it++))
240
      {
monty@mysql.com's avatar
monty@mysql.com committed
241
	/* Error's in 'new' will be detected after loop */
242
	types.push_back(new Item_type_holder(thd_arg, item_tmp));
243 244
      }

245
      if (thd_arg->is_fatal_error)
246 247 248 249 250 251 252 253 254 255 256 257
	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);	
258 259
      Item *type, *item_tmp;
      while ((type= tp++, item_tmp= it++))
260
      {
261
	if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
262
	  DBUG_RETURN(-1);
263 264
      }
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
265
  }
266

bar@mysql.com's avatar
bar@mysql.com committed
267
  if (first_select->next_select())
268
  {
269
    /* This is not a single select */
bar@mysql.com's avatar
bar@mysql.com committed
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 369
  else
    first_select->braces= 0; // remove our changes

370
  thd_arg->lex->current_select= lex_select_save;
371

372
  DBUG_RETURN(res || thd_arg->is_fatal_error ? 1 : 0);
373

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

379

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

388
  if (executed && !uncacheable && !describe)
389 390 391
    DBUG_RETURN(0);
  executed= 1;
  
392
  if (uncacheable || !item || !item->assigned() || describe)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
393
  {
394
    if (optimized && item)
395
    {
396 397 398 399 400 401 402 403 404
      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);
405
    }
406
    for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
407
    {
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
408
      ha_rows records_at_start= 0;
409
      thd->lex->current_select= sl;
410

411
      if (optimized)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
412
	res= sl->join->reinit();
413 414
      else
      {
415
	if (sl != global_parameters && !describe)
416 417 418 419 420 421 422 423 424 425 426
	{
	  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
	  */
427
	  if (sl->order_list.first || describe)
428 429 430 431
	    select_limit_cnt= HA_POS_ERROR;
	  else
	    select_limit_cnt= sl->select_limit+sl->offset_limit;
	}
432 433
	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
434 435 436 437 438

	/*
	  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
439
	if (select_limit_cnt == HA_POS_ERROR || sl->braces)
440
	  sl->options&= ~OPTION_FOUND_ROWS;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
441
	else 
442
	{
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
443 444 445 446 447
	  /*
	    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;
448
	}
449
	sl->join->select_options=sl->options;
450 451
	res= sl->join->optimize();
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
452 453
      if (!res)
      {
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
454
	records_at_start= table->file->records;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
455
	sl->join->exec();
456
        if (sl == union_distinct)
457 458 459 460 461
	{
	  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
462
	res= sl->join->error;
463
	offset_limit_cnt= sl->offset_limit;
464 465
	if (!res && union_result->flush())
	{
466
          examined_rows+= thd->examined_row_count;
467
	  thd->lex->current_select= lex_select_save;
468 469
	  DBUG_RETURN(1);
	}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
470
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
471
      if (res)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
472
      {
473
	thd->lex->current_select= lex_select_save;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
474
	DBUG_RETURN(res);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
475
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
476 477
      /* 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
478 479 480
      if (found_rows_for_union & sl->options)
      {
	/*
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
481 482
	  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
483 484 485
	  We get this from the difference of between total number of possible
	  rows and actual rows added to the temporary table.
	*/
486
	add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong)
487
			      ((table->file->records -  records_at_start)));
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
488
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
489
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
490
  }
491
  optimized= 1;
492 493

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

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

516 517 518 519 520
	/*
	  Fake st_select_lex should have item list for correctref_array
	  allocation.
	*/
	fake_select_lex->item_list= item_list;
521 522 523 524 525 526 527 528 529 530 531
      }
      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
532 533
      res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
			&result_table_list,
534 535
			0, item_list, NULL,
			global_parameters->order_list.elements,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
536
			(ORDER*)global_parameters->order_list.first,
537
			(ORDER*) NULL, NULL, (ORDER*) NULL,
538
			options_tmp | SELECT_NO_UNLOCK,
539
			result, this, fake_select_lex);
540 541

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

557

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

563 564 565 566
  if (cleaned)
  {
    DBUG_RETURN(0);
  }
567
  cleaned= 1;
568

569 570 571
  if (union_result)
  {
    delete union_result;
572
    union_result=0; // Safety
573 574
    if (table)
      free_tmp_table(thd, table);
575 576
    table= 0; // Safety
  }
577
  JOIN *join;
578 579
  SELECT_LEX *sl= first_select_in_union();
  for (; sl; sl= sl->next_select())
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
580
  {
581 582
    if ((join= sl->join))
    {
583
      error|= sl->join->cleanup();
584 585
      delete join;
    }
586 587 588 589 590 591 592 593 594 595
    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
596
  }
597 598 599 600 601 602 603
  if (fake_select_lex && (join= fake_select_lex->join))
  {
    join->tables_list= 0;
    join->tables= 0;
    error|= join->cleanup();
    delete join;
  }
604
  DBUG_RETURN(error);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
605
}
606 607 608 609 610


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
611
#ifndef DBUG_OFF
612
  if (first_select()->next_select())
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
613
  {
614 615 616 617 618 619 620 621 622 623 624
    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
625 626
  }
#endif
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 655 656


/*
  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);
}