sql_select.cc 200 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

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


/* mysql_select and join optimization */

#ifdef __GNUC__
#pragma implementation				// gcc: Class implementation
#endif

#include "mysql_priv.h"
#include "sql_select.h"
unknown's avatar
unknown committed
26

27
#include "opt_ft.h"
unknown's avatar
unknown committed
28

unknown's avatar
unknown committed
29 30 31 32 33 34
#include <m_ctype.h>
#include <hash.h>
#include <ft_global.h>
#include <assert.h>

const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
35
			      "MAYBE_REF","ALL","range","index","fulltext" };
unknown's avatar
unknown committed
36 37

static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
unknown's avatar
unknown committed
38
				 DYNAMIC_ARRAY *keyuse);
39 40
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
				JOIN_TAB *join_tab,
41
                                uint tables,COND *conds,table_map table_map);
unknown's avatar
unknown committed
42 43
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
44 45
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
			       table_map used_tables);
unknown's avatar
unknown committed
46 47 48 49 50 51
static void find_best_combination(JOIN *join,table_map rest_tables);
static void find_best(JOIN *join,table_map rest_tables,uint index,
		      double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
static double prev_record_reads(JOIN *join,table_map found_ref);
static bool get_best_combination(JOIN *join);
unknown's avatar
unknown committed
52 53
static store_key *get_store_key(THD *thd,
				KEYUSE *keyuse, table_map used_tables,
unknown's avatar
unknown committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
				KEY_PART_INFO *key_part, char *key_buff,
				uint maybe_null);
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
static void make_join_readinfo(JOIN *join,uint options);
static void join_free(JOIN *join);
static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables);
static void update_depend_map(JOIN *join);
static void update_depend_map(JOIN *join, ORDER *order);
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
			   bool *simple_order);
static int return_zero_rows(select_result *res,TABLE_LIST *tables,
			    List<Item> &fields, bool send_row,
			    uint select_options, const char *info,
			    Item *having, Procedure *proc);
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
74
				    ulong options);
unknown's avatar
unknown committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
		     Procedure *proc);
static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last);
static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records);
static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static int end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static int end_unique_update(JOIN *join,JOIN_TAB *join_tab,
			     bool end_of_records);
static int end_write_group(JOIN *join, JOIN_TAB *join_tab,
			   bool end_of_records);
static int test_if_group_changed(List<Item_buff> &list);
89
static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
unknown's avatar
unknown committed
90 91 92 93
static int join_read_system(JOIN_TAB *tab);
static int join_read_const(JOIN_TAB *tab);
static int join_read_key(JOIN_TAB *tab);
static int join_read_always_key(JOIN_TAB *tab);
94
static int join_read_last_key(JOIN_TAB *tab);
unknown's avatar
unknown committed
95 96 97 98 99
static int join_no_more_records(READ_RECORD *info);
static int join_read_next(READ_RECORD *info);
static int join_init_quick_read_record(JOIN_TAB *tab);
static int test_if_quick_select(JOIN_TAB *tab);
static int join_init_read_record(JOIN_TAB *tab);
100 101 102 103 104 105
static int join_read_first(JOIN_TAB *tab);
static int join_read_next(READ_RECORD *info);
static int join_read_next_same(READ_RECORD *info);
static int join_read_last(JOIN_TAB *tab);
static int join_read_prev_same(READ_RECORD *info);
static int join_read_prev(READ_RECORD *info);
unknown's avatar
unknown committed
106 107 108 109 110 111 112
static int join_ft_read_first(JOIN_TAB *tab);
static int join_ft_read_next(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
				 table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
113
				    ha_rows select_limit, bool no_changes);
unknown's avatar
unknown committed
114
static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit);
115 116
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
			     Item *having);
unknown's avatar
unknown committed
117
static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
118
				   ulong offset,Item *having);
unknown's avatar
unknown committed
119 120
static int remove_dup_with_hash_index(THD *thd, TABLE *table,
				      uint field_count, Field **first_field,
121
				      ulong key_length,Item *having);
unknown's avatar
unknown committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
static int join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count);
static ulong used_blob_length(CACHE_FIELD **ptr);
static bool store_record_in_cache(JOIN_CACHE *cache);
static void reset_cache(JOIN_CACHE *cache);
static void read_cached_record(JOIN_TAB *tab);
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
static int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
		       List<Item> &all_fields, ORDER *order, bool *hidden);
static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
			     List<Item> &all_fields,ORDER *new_order);
static ORDER *create_distinct_group(ORDER *order, List<Item> &fields);
static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool alloc_group_fields(JOIN *join,ORDER *group);
static bool make_sum_func_list(JOIN *join,List<Item> &fields);
138
static bool change_to_use_tmp_fields(List<Item> &func);
unknown's avatar
unknown committed
139 140 141 142 143 144 145
static bool change_refs_to_tmp_fields(THD *thd, List<Item> &func);
static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static void init_sum_functions(Item_sum **func);
static bool update_sum_func(Item_sum **func);
unknown's avatar
unknown committed
146
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
unknown's avatar
unknown committed
147
			    bool distinct, const char *message=NullS);
148
static void describe_info(THD *thd, const char *info);
unknown's avatar
unknown committed
149

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
/*
  This handles SELECT with and without UNION
*/

int handle_select(THD *thd, LEX *lex, select_result *result)
{
  int res;
  register SELECT_LEX *select_lex = &lex->select_lex;
  if (select_lex->next)
    res=mysql_union(thd,lex,result);
  else
    res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first,
		     select_lex->item_list,
		     select_lex->where,
		     (ORDER*) select_lex->order_list.first,
		     (ORDER*) select_lex->group_list.first,
		     select_lex->having,
		     (ORDER*) lex->proc_list.first,
		     select_lex->options | thd->options,
		     result);
  if (res && result)
    result->abort();
  delete result;
  return res;
}


unknown's avatar
unknown committed
177
/*****************************************************************************
178 179
  Check fields, find best join, do the select and output fields.
  mysql_select assumes that all tables are already opened
unknown's avatar
unknown committed
180 181 182 183 184
*****************************************************************************/

int
mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
	     ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
unknown's avatar
unknown committed
185
	     ulong select_options,select_result *result)
unknown's avatar
unknown committed
186 187
{
  TABLE		*tmp_table;
unknown's avatar
unknown committed
188
  int		error, tmp_error;
unknown's avatar
unknown committed
189
  bool		need_tmp,hidden_group_fields;
unknown's avatar
unknown committed
190
  bool		simple_order,simple_group,no_order, skip_sort_order, buffer_result;
unknown's avatar
unknown committed
191 192 193 194 195 196 197
  Item::cond_result cond_value;
  SQL_SELECT	*select;
  DYNAMIC_ARRAY keyuse;
  JOIN		join;
  Procedure	*procedure;
  List<Item>	all_fields(fields);
  bool		select_distinct;
unknown's avatar
unknown committed
198
  SELECT_LEX *select_lex = &(thd->lex.select_lex);
199
  SELECT_LEX *cur_sel = thd->lex.select;
unknown's avatar
unknown committed
200 201 202 203 204
  DBUG_ENTER("mysql_select");

  /* Check that all tables, fields, conds and order are ok */

  select_distinct=test(select_options & SELECT_DISTINCT);
unknown's avatar
unknown committed
205
  buffer_result=test(select_options & OPTION_BUFFER_RESULT) && !test(select_options & OPTION_FOUND_ROWS);
unknown's avatar
unknown committed
206 207
  tmp_table=0;
  select=0;
208
  no_order=skip_sort_order=0;
unknown's avatar
unknown committed
209 210
  bzero((char*) &keyuse,sizeof(keyuse));
  thd->proc_info="init";
unknown's avatar
unknown committed
211
  thd->used_tables=0;				// Updated by setup_fields
unknown's avatar
unknown committed
212

213
  if (setup_tables(tables) ||
unknown's avatar
unknown committed
214
      setup_fields(thd,tables,fields,1,&all_fields,1) ||
unknown's avatar
unknown committed
215 216
      setup_conds(thd,tables,&conds) ||
      setup_order(thd,tables,fields,all_fields,order) ||
unknown's avatar
unknown committed
217
      setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
unknown's avatar
unknown committed
218 219 220 221 222 223 224 225 226 227 228
    DBUG_RETURN(-1);				/* purecov: inspected */

  if (having)
  {
    thd->where="having clause";
    thd->allow_sum_func=1;
    if (having->fix_fields(thd,tables) || thd->fatal_error)
      DBUG_RETURN(-1);				/* purecov: inspected */
    if (having->with_sum_func)
      having->split_sum_func(all_fields);
  }
229
  if (setup_ftfuncs(thd)) /* should be after having->fix_fields */
unknown's avatar
unknown committed
230
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
231 232 233 234 235 236 237 238 239 240 241 242
  /*
    Check if one one uses a not constant column with group functions
    and no GROUP BY.
    TODO:  Add check of calculation of GROUP functions and fields:
	   SELECT COUNT(*)+table.col1 from table1;
    */
  join.table=0;
  join.tables=0;
  {
    if (!group)
    {
      uint flag=0;
unknown's avatar
unknown committed
243
      List_iterator_fast<Item> it(fields);
unknown's avatar
unknown committed
244 245 246 247 248
      Item *item;
      while ((item= it++))
      {
	if (item->with_sum_func)
	  flag|=1;
unknown's avatar
unknown committed
249
	else if (!(flag & 2) && !item->const_item())
unknown's avatar
unknown committed
250 251 252 253 254 255 256 257 258 259
	  flag|=2;
      }
      if (flag == 3)
      {
	my_error(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,MYF(0));
	DBUG_RETURN(-1);
      }
    }
    TABLE_LIST *table;
    for (table=tables ; table ; table=table->next)
260
    {
unknown's avatar
unknown committed
261
      join.tables++;
262 263 264 265 266 267
      if (!thd->used_tables)
      {
	TABLE *tbl=table->table;
	tbl->keys_in_use_for_query=tbl->used_keys= tbl->keys_in_use=0;
      }
    }
unknown's avatar
unknown committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
  }
  procedure=setup_procedure(thd,proc_param,result,fields,&error);
  if (error)
    DBUG_RETURN(-1);				/* purecov: inspected */
  if (procedure)
  {
    if (setup_new_fields(thd,tables,fields,all_fields,procedure->param_fields))
    {						/* purecov: inspected */
      delete procedure;				/* purecov: inspected */
      DBUG_RETURN(-1);				/* purecov: inspected */
    }
    if (procedure->group)
    {
      if (!test_if_subpart(procedure->group,group))
      {						/* purecov: inspected */
	my_message(0,"Can't handle procedures with differents groups yet",
		   MYF(0));			/* purecov: inspected */
	delete procedure;			/* purecov: inspected */
	DBUG_RETURN(-1);			/* purecov: inspected */
      }
    }
#ifdef NOT_NEEDED
    else if (!group && procedure->flags & PROC_GROUP)
    {
      my_message(0,"Select must have a group with this procedure",MYF(0));
      delete procedure;
      DBUG_RETURN(-1);
    }
#endif
    if (order && (procedure->flags & PROC_NO_SORT))
    { /* purecov: inspected */
      my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */
      delete procedure; /* purecov: inspected */
      DBUG_RETURN(-1); /* purecov: inspected */
    }
  }

  /* Init join struct */
  join.thd=thd;
  join.lock=thd->lock;
  join.join_tab=0;
  join.tmp_table_param.copy_field=0;
  join.sum_funcs=0;
311
  join.send_records=join.found_records=join.examined_rows=0;
unknown's avatar
unknown committed
312 313 314 315
  join.tmp_table_param.end_write_records= HA_POS_ERROR;
  join.first_record=join.sort_and_group=0;
  join.select_options=select_options;
  join.result=result;
unknown's avatar
unknown committed
316
  count_field_types(&join.tmp_table_param,all_fields,0);
unknown's avatar
unknown committed
317 318
  join.const_tables=0;
  join.having=0;
319
  join.do_send_rows = 1;
unknown's avatar
unknown committed
320
  join.group= group != 0;
unknown's avatar
unknown committed
321 322
  join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR :
		   thd->select_limit);
unknown's avatar
unknown committed
323 324 325 326

#ifdef RESTRICTED_GROUP
  if (join.sum_func_count && !group && (join.func_count || join.field_count))
  {
unknown's avatar
unknown committed
327
    my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
unknown's avatar
unknown committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
    delete procedure;
    DBUG_RETURN(-1);
  }
#endif
  if (!procedure && result->prepare(fields))
  {						/* purecov: inspected */
    DBUG_RETURN(-1);				/* purecov: inspected */
  }

#ifdef HAVE_REF_TO_FIELDS			// Not done yet
  /* Add HAVING to WHERE if possible */
  if (having && !group && ! join.sum_func_count)
  {
    if (!conds)
    {
      conds=having;
      having=0;
    }
    else if ((conds=new Item_cond_and(conds,having)))
    {
      conds->fix_fields(thd,tables);
      conds->change_ref_to_fields(thd,tables);
      having=0;
    }
  }
#endif

  conds=optimize_cond(conds,&cond_value);
  if (thd->fatal_error)				// Out of memory
  {
    delete procedure;
    DBUG_RETURN(0);
  }
  if (cond_value == Item::COND_FALSE || !thd->select_limit)
  {					/* Impossible cond */
unknown's avatar
unknown committed
363 364 365 366 367 368 369
    if (select_options & SELECT_DESCRIBE && select_lex->next)
      select_describe(&join,false,false,false,"Impossible WHERE");
    else 
      error=return_zero_rows(result, tables, fields,
			     join.tmp_table_param.sum_func_count != 0 && !group,
			     select_options,"Impossible WHERE",having,
			     procedure);
unknown's avatar
unknown committed
370 371 372 373 374 375 376 377 378 379 380 381
    delete procedure;
    DBUG_RETURN(error);
  }

  /* Optimize count(*), min() and max() */
  if (tables && join.tmp_table_param.sum_func_count && ! group)
  {
    int res;
    if ((res=opt_sum_query(tables, all_fields, conds)))
    {
      if (res < 0)
      {
unknown's avatar
unknown committed
382 383 384 385 386 387
	if (select_options & SELECT_DESCRIBE && select_lex->next)
	  select_describe(&join,false,false,false,"No matching min/max row");
	else 
	  error=return_zero_rows(result, tables, fields, !group,
				 select_options,"No matching min/max row",
				 having,procedure);
unknown's avatar
unknown committed
388 389 390 391 392
	delete procedure;
	DBUG_RETURN(error);
      }
      if (select_options & SELECT_DESCRIBE)
      {
unknown's avatar
unknown committed
393 394 395 396
	if (select_lex->next)
	  select_describe(&join,false,false,false,"Select tables optimized away");
	else
	  describe_info(thd,"Select tables optimized away");
unknown's avatar
unknown committed
397
	delete procedure;
unknown's avatar
unknown committed
398
	DBUG_RETURN(error);
unknown's avatar
unknown committed
399 400 401 402 403 404 405 406
      }
      tables=0;					// All tables resolved
    }
  }
  if (!tables)
  {						// Only test of functions
    error=0;
    if (select_options & SELECT_DESCRIBE)
unknown's avatar
unknown committed
407 408 409 410 411 412
    {
      if (select_lex->next)
	select_describe(&join,false,false,false,"No tables used");
      else
	describe_info(thd,"No tables used");
    }
unknown's avatar
unknown committed
413 414 415 416 417
    else
    {
      result->send_fields(fields,1);
      if (!having || having->val_int())
      {
418
	if (join.do_send_rows && result->send_data(fields))
unknown's avatar
unknown committed
419 420 421 422 423 424 425 426 427 428 429
	{
	  result->send_error(0,NullS);		/* purecov: inspected */
	  error=1;
	}
	else
	  error=(int) result->send_eof();
      }
      else
	error=(int) result->send_eof();
    }
    delete procedure;
unknown's avatar
unknown committed
430
    DBUG_RETURN(error);
unknown's avatar
unknown committed
431 432 433 434 435 436 437
  }

  error = -1;
  join.sort_by_table=get_sort_by_table(order,group,tables);

  /* Calculate how to do the join */
  thd->proc_info="statistics";
438
  if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
unknown's avatar
unknown committed
439 440
    goto err;
  thd->proc_info="preparing";
unknown's avatar
unknown committed
441
  result->initialize_tables(&join);
442 443
  if (join.const_table_map != join.found_const_table_map &&
      !(select_options & SELECT_DESCRIBE))
unknown's avatar
unknown committed
444 445 446
  {
    error=return_zero_rows(result,tables,fields,
			   join.tmp_table_param.sum_func_count != 0 &&
447
			   !group,0,"",having,procedure);
unknown's avatar
unknown committed
448 449 450 451 452 453 454 455 456 457
    goto err;
  }
  if (!(thd->options & OPTION_BIG_SELECTS) &&
      join.best_read > (double) thd->max_join_size &&
      !(select_options & SELECT_DESCRIBE))
  {						/* purecov: inspected */
    result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
    error= 1;					/* purecov: inspected */
    goto err;					/* purecov: inspected */
  }
unknown's avatar
unknown committed
458 459
  if (join.const_tables && !thd->locked_tables &&
      !(select_options & SELECT_NO_UNLOCK))
460 461 462 463 464 465 466 467 468 469 470 471 472 473
  {
    TABLE **table, **end;
    for (table=join.table, end=table + join.const_tables ;
	 table != end;
	 table++)
    {
      /* BDB tables require that we call index_end() before doing an unlock */
      if ((*table)->key_read)
      {
	(*table)->key_read=0;
	(*table)->file->extra(HA_EXTRA_NO_KEYREAD);
      }
      (*table)->file->index_end();
    }
unknown's avatar
unknown committed
474
    mysql_unlock_some_tables(thd, join.table,join.const_tables);
475
  }
476 477 478 479 480
  if (!conds && join.outer_join)
  {
    /* Handle the case where we have an OUTER JOIN without a WHERE */
    conds=new Item_int((longlong) 1,1);	// Always true
  }
unknown's avatar
unknown committed
481 482 483 484 485 486 487 488 489
  select=make_select(*join.table, join.const_table_map,
		     join.const_table_map,conds,&error);
  if (error)
  { /* purecov: inspected */
    error= -1; /* purecov: inspected */
    goto err; /* purecov: inspected */
  }
  if (make_join_select(&join,select,conds))
  {
unknown's avatar
unknown committed
490 491 492 493 494 495 496 497
    if (select_options & SELECT_DESCRIBE && select_lex->next)
      select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables");
    else 
      error=return_zero_rows(result,tables,fields,
			     join.tmp_table_param.sum_func_count != 0 && !group,
			     select_options,
			     "Impossible WHERE noticed after reading const tables",
			     having,procedure);
unknown's avatar
unknown committed
498 499 500 501 502 503 504 505 506 507 508 509 510
    goto err;
  }

  error= -1;					/* if goto err */

  /* Optimize distinct away if possible */
  order=remove_const(&join,order,conds,&simple_order);
  if (group || join.tmp_table_param.sum_func_count)
  {
    if (! hidden_group_fields)
      select_distinct=0;
  }
  else if (select_distinct && join.tables - join.const_tables == 1 &&
511 512
	   (thd->select_limit == HA_POS_ERROR ||
	    (join.select_options & OPTION_FOUND_ROWS) ||
513
	    order &&
unknown's avatar
unknown committed
514 515 516
	    !(skip_sort_order=
	      test_if_skip_sort_order(&join.join_tab[join.const_tables],
				      order, thd->select_limit,1))))
unknown's avatar
unknown committed
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
  {
    if ((group=create_distinct_group(order,fields)))
    {
      select_distinct=0;
      no_order= !order;
      join.group=1;				// For end_write_group
    }
    else if (thd->fatal_error)			// End of memory
      goto err;
  }
  group=remove_const(&join,group,conds,&simple_group);
  if (!group && join.group)
  {
    order=0;					// The output has only one row
    simple_order=1;
  }

  calc_group_buffer(&join,group);
  join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */
  if (procedure && procedure->group)
  {
    group=procedure->group=remove_const(&join,procedure->group,conds,
					&simple_group);
    calc_group_buffer(&join,group);
  }

  if (test_if_subpart(group,order) ||
      (!group && join.tmp_table_param.sum_func_count))
    order=0;

unknown's avatar
unknown committed
547
  // Can't use sort on head table if using row cache
unknown's avatar
unknown committed
548 549 550 551 552 553 554 555 556 557
  if (join.full_join)
  {
    if (group)
      simple_group=0;
    if (order)
      simple_order=0;
  }

  need_tmp= (join.const_tables != join.tables &&
	     ((select_distinct || !simple_order || !simple_group) ||
unknown's avatar
unknown committed
558
	      (group && order) || buffer_result));
unknown's avatar
unknown committed
559

unknown's avatar
unknown committed
560 561 562
  // No cache for MATCH
  make_join_readinfo(&join,
		     (select_options & (SELECT_DESCRIBE |
563
					SELECT_NO_JOIN_CACHE)) |
564
     (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
unknown's avatar
unknown committed
565 566 567 568 569 570 571 572 573 574 575 576

  /* Need to tell Innobase that to play it safe, it should fetch all
     columns of the tables: this is because MySQL
     may build row pointers for the rows, and for all columns of the primary
     key the field->query_id has not necessarily been set to thd->query_id
     by MySQL. */

#ifdef HAVE_INNOBASE_DB
  if (need_tmp || select_distinct || group || order)
  {
    for (uint i_h = join.const_tables; i_h < join.tables; i_h++)
    {
577
      TABLE*	  table_h = join.join_tab[i_h].table;
578
      if (table_h->db_type == DB_TYPE_INNODB)
579
	table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
unknown's avatar
unknown committed
580 581 582 583
    }
  }
#endif

unknown's avatar
unknown committed
584 585 586 587 588 589 590 591
  DBUG_EXECUTE("info",TEST_join(&join););
  /*
    Because filesort always does a full table scan or a quick range scan
    we must add the removed reference to the select for the table.
    We only need to do this when we have a simple_order or simple_group
    as in other cases the join is done before the sort.
    */
  if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL &&
592
      join.join_tab[join.const_tables].type != JT_FT &&
unknown's avatar
unknown committed
593 594 595 596 597 598 599 600
      (order && simple_order || group && simple_group))
  {
    if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables]))
      goto err;
  }

  if (!(select_options & SELECT_BIG_RESULT) &&
      ((group && join.const_tables != join.tables &&
601 602
	(!simple_group ||
	 !test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
unknown's avatar
merge  
unknown committed
603
				  thd->select_limit,0))) ||
unknown's avatar
unknown committed
604 605 606 607 608 609 610 611 612 613 614 615
       select_distinct) &&
      join.tmp_table_param.quick_group && !procedure)
  {
    need_tmp=1; simple_order=simple_group=0;	// Force tmp table without sort
  }

  if (select_options & SELECT_DESCRIBE)
  {
    if (!order && !no_order)
      order=group;
    if (order &&
	(join.const_tables == join.tables ||
616 617
	 (simple_order &&
	  test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
unknown's avatar
merge  
unknown committed
618 619 620
				  (join.const_tables != join.tables - 1 ||
				   (join.select_options & OPTION_FOUND_ROWS)) ?
				  HA_POS_ERROR : thd->select_limit,0))))
unknown's avatar
unknown committed
621 622
      order=0;
    select_describe(&join,need_tmp,
623
		    order != 0 && !skip_sort_order,
unknown's avatar
unknown committed
624
		    select_distinct);
unknown's avatar
unknown committed
625 626 627 628
    error=0;
    goto err;
  }

629
  /* Perform FULLTEXT search before all regular searches */
630
  init_ftfuncs(thd,test(order));
631

unknown's avatar
unknown committed
632 633 634 635 636 637 638 639 640 641 642 643 644
  /* Create a tmp table if distinct or if the sort is too complicated */
  if (need_tmp)
  {
    DBUG_PRINT("info",("Creating tmp table"));
    thd->proc_info="Creating tmp table";

    if (!(tmp_table =
	  create_tmp_table(thd,&join.tmp_table_param,all_fields,
			   ((!simple_group && !procedure &&
			     !(test_flags & TEST_NO_KEY_GROUP)) ?
			    group : (ORDER*) 0),
			   group ? 0 : select_distinct,
			   group && simple_group,
645
			   (order == 0 || skip_sort_order) &&
646
			   !(join.select_options & OPTION_FOUND_ROWS),
unknown's avatar
unknown committed
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
			   join.select_options)))
      goto err;					/* purecov: inspected */

    if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
      join.having=having;

    /* if group or order on first table, sort first */
    if (group && simple_group)
    {
      DBUG_PRINT("info",("Sorting for group"));
      thd->proc_info="Sorting for group";
      if (create_sort_index(&join.join_tab[join.const_tables],group,
			    HA_POS_ERROR) ||
	  make_sum_func_list(&join,all_fields) ||
	  alloc_group_fields(&join,group))
	goto err;
      group=0;
    }
    else
    {
      if (make_sum_func_list(&join,all_fields))
	goto err;
      if (!group && ! tmp_table->distinct && order && simple_order)
      {
	DBUG_PRINT("info",("Sorting for order"));
	thd->proc_info="Sorting for order";
	if (create_sort_index(&join.join_tab[join.const_tables],order,
			      HA_POS_ERROR))
	  goto err;				/* purecov: inspected */
	order=0;
      }
    }
unknown's avatar
unknown committed
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695

    /*
      Optimize distinct when used on some of the tables
      SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b
      In this case we can stop scanning t2 when we have found one t1.a
    */

    if (tmp_table->distinct)
    {
      table_map used_tables= thd->used_tables;
      JOIN_TAB *join_tab=join.join_tab+join.tables-1;
      do
      {
	if (used_tables & join_tab->table->map)
	  break;
	join_tab->not_used_in_distinct=1;
      } while (join_tab-- != join.join_tab);
696 697 698 699 700 701 702
      /* Optimize "select distinct b from t1 order by key_part_1 limit #" */
      if (order && skip_sort_order)
      {
	(void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
				       order, thd->select_limit,0);
	order=0;
      }
unknown's avatar
unknown committed
703 704 705
    }

    /* Copy data to the temporary table */
unknown's avatar
unknown committed
706
    thd->proc_info="Copying to tmp table";
707 708 709
    if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
    {
      error=tmp_error;
unknown's avatar
unknown committed
710
      goto err;					/* purecov: inspected */
711
    }
unknown's avatar
unknown committed
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
    if (join.having)
      join.having=having=0;			// Allready done

    /* Change sum_fields reference to calculated fields in tmp_table */
    if (join.sort_and_group || tmp_table->group)
    {
      if (change_to_use_tmp_fields(all_fields))
	goto err;
      join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+
	join.tmp_table_param.func_count;
      join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0;
    }
    else
    {
      if (change_refs_to_tmp_fields(thd,all_fields))
	goto err;
      join.tmp_table_param.field_count+=join.tmp_table_param.func_count;
      join.tmp_table_param.func_count=0;
    }
    if (procedure)
      procedure->update_refs();
    if (tmp_table->group)
    {						// Already grouped
      if (!order && !no_order)
	order=group;				/* order by group */
      group=0;
    }

    /*
741 742 743 744 745
      If we have different sort & group then we must sort the data by group
      and copy it to another tmp table
      This code is also used if we are using distinct something
      we haven't been able to store in the temporary table yet
      like SEC_TO_TIME(SUM(...)).
unknown's avatar
unknown committed
746 747
    */

unknown's avatar
unknown committed
748 749 750
    if (group && (!test_if_subpart(group,order) || select_distinct) ||
	(select_distinct &&
	 join.tmp_table_param.using_indirect_summary_function))
unknown's avatar
unknown committed
751 752 753 754 755 756 757 758 759
    {					/* Must copy to another table */
      TABLE *tmp_table2;
      DBUG_PRINT("info",("Creating group table"));

      /* Free first data from old join */
      join_free(&join);
      if (make_simple_join(&join,tmp_table))
	goto err;
      calc_group_buffer(&join,group);
unknown's avatar
unknown committed
760 761 762 763
      count_field_types(&join.tmp_table_param,all_fields,
			select_distinct && !group);
      join.tmp_table_param.hidden_field_count=(all_fields.elements-
					       fields.elements);
unknown's avatar
unknown committed
764 765 766

      /* group data to new table */
      if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
unknown's avatar
unknown committed
767 768 769
					  (ORDER*) 0,
					  select_distinct && !group,
					  1, 0,
unknown's avatar
unknown committed
770 771 772 773 774 775 776 777
					  join.select_options)))
	goto err;				/* purecov: inspected */
      if (group)
      {
	thd->proc_info="Creating sort index";
	if (create_sort_index(join.join_tab,group,HA_POS_ERROR) ||
	    alloc_group_fields(&join,group))
	{
unknown's avatar
unknown committed
778
	  free_tmp_table(thd,tmp_table2);	/* purecov: inspected */
unknown's avatar
unknown committed
779 780 781 782 783
	  goto err;				/* purecov: inspected */
	}
	group=0;
      }
      thd->proc_info="Copying to group table";
784
      tmp_error= -1;
unknown's avatar
unknown committed
785
      if (make_sum_func_list(&join,all_fields) ||
786
	  (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
unknown's avatar
unknown committed
787
      {
788
	error=tmp_error;
unknown's avatar
unknown committed
789 790 791 792 793 794 795 796 797
	free_tmp_table(thd,tmp_table2);
	goto err;				/* purecov: inspected */
      }
      end_read_record(&join.join_tab->read_record);
      free_tmp_table(thd,tmp_table);
      join.const_tables=join.tables;		// Mark free for join_free()
      tmp_table=tmp_table2;
      join.join_tab[0].table=0;			// Table is freed

798
      if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
unknown's avatar
unknown committed
799 800 801 802 803 804
	goto err;
      join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count;
      join.tmp_table_param.sum_func_count=0;
    }

    if (tmp_table->distinct)
805
      select_distinct=0;			/* Each row is unique */
unknown's avatar
unknown committed
806 807 808 809 810

    join_free(&join);				/* Free quick selects */
    if (select_distinct && ! group)
    {
      thd->proc_info="Removing duplicates";
811 812 813 814 815
      if (having)
	having->update_used_tables();
      if (remove_duplicates(&join,tmp_table,fields, having))
	goto err;				/* purecov: inspected */
      having=0;
unknown's avatar
unknown committed
816 817 818 819 820 821
      select_distinct=0;
    }
    tmp_table->reginfo.lock_type=TL_UNLOCK;
    if (make_simple_join(&join,tmp_table))
      goto err;
    calc_group_buffer(&join,group);
unknown's avatar
unknown committed
822
    count_field_types(&join.tmp_table_param,all_fields,0);
unknown's avatar
unknown committed
823 824 825 826 827 828
  }
  if (procedure)
  {
    if (procedure->change_columns(fields) ||
	result->prepare(fields))
      goto err;
unknown's avatar
unknown committed
829
    count_field_types(&join.tmp_table_param,all_fields,0);
unknown's avatar
unknown committed
830 831 832 833 834
  }
  if (join.group || join.tmp_table_param.sum_func_count ||
      (procedure && (procedure->flags & PROC_GROUP)))
  {
    alloc_group_fields(&join,group);
unknown's avatar
unknown committed
835
    setup_copy_fields(thd, &join.tmp_table_param,all_fields);
unknown's avatar
unknown committed
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
    if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
      goto err; /* purecov: inspected */
  }
  if (group || order)
  {
    DBUG_PRINT("info",("Sorting for send_fields"));
    thd->proc_info="Sorting result";
    /* If we have already done the group, add HAVING to sorted table */
    if (having && ! group && ! join.sort_and_group)
    {
      having->update_used_tables();	// Some tables may have been const
      JOIN_TAB *table=&join.join_tab[join.const_tables];
      table_map used_tables= join.const_table_map | table->table->map;

      Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables);
      if (sort_table_cond)
      {
	if (!table->select)
	  if (!(table->select=new SQL_SELECT))
	    goto err;
	if (!table->select->cond)
	  table->select->cond=sort_table_cond;
	else					// This should never happen
	  if (!(table->select->cond=new Item_cond_and(table->select->cond,
						      sort_table_cond)))
	    goto err;
	table->select_cond=table->select->cond;
	DBUG_EXECUTE("where",print_where(table->select->cond,
					 "select and having"););
	having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
	DBUG_EXECUTE("where",print_where(conds,"having after sort"););
      }
    }
    if (create_sort_index(&join.join_tab[join.const_tables],
			  group ? group : order,
			  (having || group ||
872 873
			   join.const_tables != join.tables - 1 ||
			   (join.select_options & OPTION_FOUND_ROWS)) ?
unknown's avatar
unknown committed
874 875 876 877 878 879 880 881
			  HA_POS_ERROR : thd->select_limit))
      goto err; /* purecov: inspected */
  }
  join.having=having;				// Actually a parameter
  thd->proc_info="Sending data";
  error=do_select(&join,&fields,NULL,procedure);

err:
882
  thd->limit_found_rows = join.send_records;
883
  thd->examined_row_count = join.examined_rows;
unknown's avatar
unknown committed
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
  thd->proc_info="end";
  join.lock=0;					// It's faster to unlock later
  join_free(&join);
  thd->proc_info="end2";			// QQ
  if (tmp_table)
    free_tmp_table(thd,tmp_table);
  thd->proc_info="end3";			// QQ
  delete select;
  delete_dynamic(&keyuse);
  delete procedure;
  thd->proc_info="end4";			// QQ
  DBUG_RETURN(error);
}

/*****************************************************************************
899 900
  Create JOIN_TABS, make a guess about the table types,
  Approximate how many records will be used in each table
unknown's avatar
unknown committed
901 902 903
*****************************************************************************/

static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
unknown's avatar
unknown committed
904
				      key_map keys,ha_rows limit)
unknown's avatar
unknown committed
905 906 907 908 909 910 911
{
  int error;
  DBUG_ENTER("get_quick_record_count");
  if (select)
  {
    select->head=table;
    table->reginfo.impossible_range=0;
unknown's avatar
unknown committed
912
    if ((error=select->test_quick_select(keys,(table_map) 0,limit))
unknown's avatar
unknown committed
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
	== 1)
      DBUG_RETURN(select->quick->records);
    if (error == -1)
    {
      table->reginfo.impossible_range=1;
      DBUG_RETURN(0);
    }
    DBUG_PRINT("warning",("Couldn't use record count on const keypart"));
  }
  DBUG_RETURN(HA_POS_ERROR);			/* This shouldn't happend */
}


static bool
make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
928
		     DYNAMIC_ARRAY *keyuse_array)
unknown's avatar
unknown committed
929 930 931
{
  int error;
  uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part;
932
  table_map const_table_map,found_const_table_map,all_table_map;
unknown's avatar
unknown committed
933 934 935 936 937 938 939 940 941
  TABLE **table_vector;
  JOIN_TAB *stat,*stat_end,*s,**stat_ref;
  SQL_SELECT *select;
  KEYUSE *keyuse,*start_keyuse;
  table_map outer_join=0;
  JOIN_TAB *stat_vector[MAX_TABLES+1];
  DBUG_ENTER("make_join_statistics");

  table_count=join->tables;
942 943
  stat=(JOIN_TAB*) join->thd->calloc(sizeof(JOIN_TAB)*table_count);
  stat_ref=(JOIN_TAB**) join->thd->alloc(sizeof(JOIN_TAB*)*MAX_TABLES);
944
  table_vector=(TABLE**) join->thd->alloc(sizeof(TABLE*)*(table_count*2));
unknown's avatar
unknown committed
945 946 947 948 949 950 951
  if (!stat || !stat_ref || !table_vector)
    DBUG_RETURN(1);				// Eom /* purecov: inspected */
  select=0;

  join->best_ref=stat_vector;

  stat_end=stat+table_count;
952
  const_table_map=found_const_table_map=all_table_map=0;
unknown's avatar
unknown committed
953 954 955 956 957 958 959 960 961 962 963 964 965
  const_count=0;

  for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
  {
    TABLE *table;
    stat_vector[i]=s;
    table_vector[i]=s->table=table=tables->table;
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
    table->quick_keys=0;
    table->reginfo.join_tab=s;
    table->reginfo.not_exists_optimize=0;
    bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
    all_table_map|= table->map;
966
    s->join=join;
967
    s->info=0;					// For describe
unknown's avatar
unknown committed
968 969
    if ((s->on_expr=tables->on_expr))
    {
970
      /* Left join */
unknown's avatar
unknown committed
971 972
      if (!table->file->records)
      {						// Empty table
973
	s->key_dependent=s->dependent=0;	// Ignore LEFT JOIN depend.
unknown's avatar
unknown committed
974 975 976
	set_position(join,const_count++,s,(KEYUSE*) 0);
	continue;
      }
unknown's avatar
unknown committed
977 978
      s->key_dependent=s->dependent=
	s->on_expr->used_tables() & ~(table->map);
979 980 981 982
      if (table->outer_join & JOIN_TYPE_LEFT)
	s->dependent|=stat_vector[i-1]->dependent | table_vector[i-1]->map;
      if (tables->outer_join & JOIN_TYPE_RIGHT)
	s->dependent|=tables->next->table->map;
unknown's avatar
unknown committed
983 984 985 986 987 988 989 990
      outer_join|=table->map;
      continue;
    }
    if (tables->straight)			// We don't have to move this
      s->dependent= table_vector[i-1]->map | stat_vector[i-1]->dependent;
    else
      s->dependent=(table_map) 0;
    s->key_dependent=(table_map) 0;
unknown's avatar
unknown committed
991
    if ((table->system || table->file->records <= 1) && ! s->dependent &&
992
	!(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
unknown's avatar
unknown committed
993
        !table->fulltext_searched)
unknown's avatar
unknown committed
994 995 996 997 998
    {
      set_position(join,const_count++,s,(KEYUSE*) 0);
    }
  }
  stat_vector[i]=0;
999
  join->outer_join=outer_join;
unknown's avatar
unknown committed
1000 1001

  /*
1002 1003 1004 1005
    If outer join: Re-arrange tables in stat_vector so that outer join
    tables are after all tables it is dependent of.
    For example: SELECT * from A LEFT JOIN B ON B.c=C.c, C WHERE A.C=C.C
    Will shift table B after table C.
unknown's avatar
unknown committed
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
  */
  if (outer_join)
  {
    table_map used_tables=0L;
    for (i=0 ; i < join->tables-1 ; i++)
    {
      if (stat_vector[i]->dependent & ~used_tables)
      {
	JOIN_TAB *save= stat_vector[i];
	uint j;
	for (j=i+1;
	     j < join->tables && stat_vector[j]->dependent & ~used_tables;
	     j++)
	{
	  JOIN_TAB *tmp=stat_vector[j];		// Move element up
	  stat_vector[j]=save;
	  save=tmp;
	}
	if (j == join->tables)
	{
	  join->tables=0;			// Don't use join->table
	  my_error(ER_WRONG_OUTER_JOIN,MYF(0));
	  DBUG_RETURN(1);
	}
	stat_vector[i]=stat_vector[j];
	stat_vector[j]=save;
      }
      used_tables|= stat_vector[i]->table->map;
    }
  }

  if (conds || outer_join)
1038
    if (update_ref_and_keys(join->thd,keyuse_array,stat,join->tables,
1039
                            conds,~outer_join))
unknown's avatar
unknown committed
1040 1041
      DBUG_RETURN(1);

1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
  /* Read tables with 0 or 1 rows (system tables) */
  join->const_table_map=const_table_map;

  for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
       p_pos < p_end ;
       p_pos++)
  {
    int tmp;
    s= p_pos->table;
    s->type=JT_SYSTEM;
    join->const_table_map|=s->table->map;
    if ((tmp=join_read_const_table(s, p_pos)))
    {
      if (tmp > 0)
	DBUG_RETURN(1);			// Fatal error
    }
    else
      found_const_table_map|= s->table->map;
  }

unknown's avatar
unknown committed
1062
  /* loop until no more const tables are found */
1063
  int ref_changed;
unknown's avatar
unknown committed
1064 1065
  do
  {
1066
    ref_changed = 0;
unknown's avatar
unknown committed
1067
    found_ref=0;
1068 1069 1070 1071 1072 1073 1074

    /*
      We only have to loop from stat_vector + const_count as
      set_position() will move all const_tables first in stat_vector
    */

    for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
unknown's avatar
unknown committed
1075
    {
1076
      TABLE *table=s->table;
unknown's avatar
unknown committed
1077 1078
      if (s->dependent)				// If dependent on some table
      {
1079 1080
	// All dep. must be constants
	if (s->dependent & ~(join->const_table_map))
unknown's avatar
unknown committed
1081
	  continue;
1082
	if (table->file->records <= 1L &&
1083
	    !(table->file->table_flags() & HA_NOT_EXACT_COUNT))
unknown's avatar
unknown committed
1084
	{					// system table
1085
	  int tmp;
unknown's avatar
unknown committed
1086
	  s->type=JT_SYSTEM;
1087
	  join->const_table_map|=table->map;
unknown's avatar
unknown committed
1088
	  set_position(join,const_count++,s,(KEYUSE*) 0);
1089 1090 1091 1092 1093 1094 1095
	  if ((tmp=join_read_const_table(s,join->positions+const_count-1)))
	  {
	    if (tmp > 0)
	      DBUG_RETURN(1);			// Fatal error
	  }
	  else
	    found_const_table_map|= table->map;
unknown's avatar
unknown committed
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
	  continue;
	}
      }
      /* check if table can be read by key or table only uses const refs */
      if ((keyuse=s->keyuse))
      {
	s->type= JT_REF;
	while (keyuse->table == table)
	{
	  start_keyuse=keyuse;
	  key=keyuse->key;
	  s->keys|= (key_map) 1 << key;		// QQ: remove this ?

	  refs=const_ref=eq_part=0;
	  do
	  {
	    if (keyuse->val->type() != Item::NULL_ITEM)
	    {
1114
	      if (!((~join->const_table_map) & keyuse->used_tables))
unknown's avatar
unknown committed
1115 1116 1117 1118 1119 1120 1121 1122 1123
		const_ref|= (key_map) 1 << keyuse->keypart;
	      else
		refs|=keyuse->used_tables;
	      eq_part|= (uint) 1 << keyuse->keypart;
	    }
	    keyuse++;
	  } while (keyuse->table == table && keyuse->key == key);

	  if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
unknown's avatar
unknown committed
1124 1125
	      (table->key_info[key].flags & HA_NOSAME) &&
              !table->fulltext_searched)
unknown's avatar
unknown committed
1126 1127 1128
	  {
	    if (const_ref == eq_part)
	    {					// Found everything for ref.
1129 1130
	      int tmp;
	      ref_changed = 1;
unknown's avatar
unknown committed
1131
	      s->type=JT_CONST;
1132
	      join->const_table_map|=table->map;
unknown's avatar
unknown committed
1133
	      set_position(join,const_count++,s,start_keyuse);
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
	      if (create_ref_for_key(join, s, start_keyuse,
				     join->const_table_map))
		DBUG_RETURN(1);
	      if ((tmp=join_read_const_table(s,
					     join->positions+const_count-1)))
	      {
		if (tmp > 0)
		  DBUG_RETURN(1);			// Fatal error
	      }
	      else
		found_const_table_map|= table->map;
unknown's avatar
unknown committed
1145 1146 1147 1148 1149 1150 1151 1152
	      break;
	    }
	    else
	      found_ref|= refs;		// Table is const if all refs are const
	  }
	}
      }
    }
1153
  } while (join->const_table_map & found_ref && ref_changed);
unknown's avatar
unknown committed
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166

  /* Calc how many (possible) matched records in each table */

  for (s=stat ; s < stat_end ; s++)
  {
    if (s->type == JT_SYSTEM || s->type == JT_CONST)
    {
      /* Only one matching row */
      s->found_records=s->records=s->read_time=1; s->worst_seeks=1.0;
      continue;
    }
    /* Approximate found rows and time to read them */
    s->found_records=s->records=s->table->file->records;
1167
    s->read_time=(ha_rows) s->table->file->scan_time();
unknown's avatar
unknown committed
1168

1169 1170 1171 1172
    /*
      Set a max range of how many seeks we can expect when using keys
      This was (s->read_time*5), but this was too low with small rows
    */
unknown's avatar
unknown committed
1173
    s->worst_seeks= (double) s->found_records / 5;
unknown's avatar
unknown committed
1174 1175 1176 1177 1178 1179 1180 1181 1182
    if (s->worst_seeks < 2.0)			// Fix for small tables
      s->worst_seeks=2.0;

    /* if (s->type == JT_EQ_REF)
      continue; */
    if (s->const_keys)
    {
      ha_rows records;
      if (!select)
1183 1184
	select=make_select(s->table, join->const_table_map,
			   join->const_table_map,
unknown's avatar
unknown committed
1185
			   and_conds(conds,s->on_expr),&error);
unknown's avatar
unknown committed
1186 1187
      records=get_quick_record_count(select,s->table, s->const_keys,
				     join->row_limit);
unknown's avatar
unknown committed
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
      s->quick=select->quick;
      s->needed_reg=select->needed_reg;
      select->quick=0;
      if (records != HA_POS_ERROR)
      {
	s->found_records=records;
	s->read_time= (ha_rows) (s->quick ? s->quick->read_time : 0.0);
      }
    }
  }
  delete select;

  /* Find best combination and return it */
  join->join_tab=stat;
  join->map2table=stat_ref;
  join->table= join->all_tables=table_vector;
  join->const_tables=const_count;
1205
  join->found_const_table_map=found_const_table_map;
unknown's avatar
unknown committed
1206 1207

  if (join->const_tables != join->tables)
1208
    find_best_combination(join,all_table_map & ~join->const_table_map);
unknown's avatar
unknown committed
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
  else
  {
    memcpy((gptr) join->best_positions,(gptr) join->positions,
	   sizeof(POSITION)*join->const_tables);
    join->best_read=1.0;
  }
  DBUG_RETURN(get_best_combination(join));
}


/*****************************************************************************
1220 1221 1222 1223 1224
  Check with keys are used and with tables references with tables
  Updates in stat:
	  keys	     Bitmap of all used keys
	  const_keys Bitmap of all keys with may be used with quick_select
	  keyuse     Pointer to possible keys
unknown's avatar
unknown committed
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
*****************************************************************************/

typedef struct key_field_t {		// Used when finding key fields
  Field		*field;
  Item		*val;			// May be empty if diff constant
  uint		level,const_level;	// QQ: Remove const_level
  bool		eq_func;
  bool		exists_optimize;
} KEY_FIELD;


/* merge new key definitions to old ones, remove those not used in both */

static KEY_FIELD *
merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
		 uint and_level)
{
  if (start == new_fields)
    return start;				// Impossible or
  if (new_fields == end)
unknown's avatar
unknown committed
1245
    return start;				// No new fields, skip all
unknown's avatar
unknown committed
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257

  KEY_FIELD *first_free=new_fields;

  /* Mark all found fields in old array */
  for (; new_fields != end ; new_fields++)
  {
    for (KEY_FIELD *old=start ; old != first_free ; old++)
    {
      if (old->field == new_fields->field)
      {
	if (new_fields->val->used_tables())
	{
1258
	  if (old->val->eq(new_fields->val, old->field->binary()))
unknown's avatar
unknown committed
1259 1260 1261 1262 1263
	  {
	    old->level=old->const_level=and_level;
	    old->exists_optimize&=new_fields->exists_optimize;
	  }
	}
1264 1265
	else if (old->val->eq(new_fields->val, old->field->binary()) &&
		 old->eq_func && new_fields->eq_func)
unknown's avatar
unknown committed
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
	{
	  old->level=old->const_level=and_level;
	  old->exists_optimize&=new_fields->exists_optimize;
	}
	else					// Impossible; remove it
	{
	  if (old == --first_free)		// If last item
	    break;
	  *old= *first_free;			// Remove old value
	  old--;				// Retry this value
	}
      }
    }
  }
  /* Remove all not used items */
  for (KEY_FIELD *old=start ; old != first_free ;)
  {
    if (old->level != and_level && old->const_level != and_level)
    {						// Not used in all levels
      if (old == --first_free)
	break;
      *old= *first_free;			// Remove old value
      continue;
    }
    old++;
  }
  return first_free;
}


static void
add_key_field(KEY_FIELD **key_fields,uint and_level,
	      Field *field,bool eq_func,Item *value,
	      table_map usable_tables)
{
  bool exists_optimize=0;
  if (!(field->flags & PART_KEY_FLAG))
  {
    // Don't remove column IS NULL on a LEFT JOIN table
    if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
	!field->table->maybe_null || field->null_ptr)
unknown's avatar
unknown committed
1307
      return;					// Not a key. Skip it
unknown's avatar
unknown committed
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
    exists_optimize=1;
  }
  else
  {
    table_map used_tables=0;
    if (value && (used_tables=value->used_tables()) &
	(field->table->map | RAND_TABLE_BIT))
      return;
    if (!(usable_tables & field->table->map))
    {
      if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
	  !field->table->maybe_null || field->null_ptr)
	return;					// Can't use left join optimize
      exists_optimize=1;
    }
    else
    {
      JOIN_TAB *stat=field->table->reginfo.join_tab;
unknown's avatar
unknown committed
1326 1327 1328
      key_map possible_keys= (field->key_start &
			      field->table->keys_in_use_for_query);
      stat[0].keys|= possible_keys;		// Add possible keys
unknown's avatar
unknown committed
1329 1330 1331

      if (!value)
      {						// Probably BETWEEN or IN
unknown's avatar
unknown committed
1332
	stat[0].const_keys |= possible_keys;
unknown's avatar
unknown committed
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
	return;					// Can't be used as eq key
      }

      /* Save the following cases:
	 Field op constant
	 Field LIKE constant where constant doesn't start with a wildcard
	 Field = field2 where field2 is in a different table
	 Field op formula
	 Field IS NULL
	 Field IS NOT NULL
      */
      stat[0].key_dependent|=used_tables;
      if (value->const_item())
unknown's avatar
unknown committed
1346
	stat[0].const_keys |= possible_keys;
unknown's avatar
unknown committed
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372

      /* We can't always use indexes when comparing a string index to a
	 number. cmp_type() is checked to allow compare of dates to numbers */
      if (!eq_func ||
	  field->result_type() == STRING_RESULT &&
	  value->result_type() != STRING_RESULT &&
	  field->cmp_type() != value->result_type())
	return;
    }
  }
  /* Store possible eq field */
  (*key_fields)->field=field;
  (*key_fields)->eq_func=eq_func;
  (*key_fields)->val=value;
  (*key_fields)->level=(*key_fields)->const_level=and_level;
  (*key_fields)->exists_optimize=exists_optimize;
  (*key_fields)++;
}


static void
add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
	       COND *cond, table_map usable_tables)
{
  if (cond->type() == Item_func::COND_ITEM)
  {
unknown's avatar
unknown committed
1373
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
unknown's avatar
unknown committed
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
    KEY_FIELD *org_key_fields= *key_fields;

    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      Item *item;
      while ((item=li++))
	add_key_fields(stat,key_fields,and_level,item,usable_tables);
      for (; org_key_fields != *key_fields ; org_key_fields++)
      {
	if (org_key_fields->const_level == org_key_fields->level)
	  org_key_fields->const_level=org_key_fields->level= *and_level;
	else
	  org_key_fields->const_level= *and_level;
      }
    }
    else
    {
      (*and_level)++;
      add_key_fields(stat,key_fields,and_level,li++,usable_tables);
      Item *item;
      while ((item=li++))
      {
	KEY_FIELD *start_key_fields= *key_fields;
	(*and_level)++;
	add_key_fields(stat,key_fields,and_level,item,usable_tables);
	*key_fields=merge_key_fields(org_key_fields,start_key_fields,
				     *key_fields,++(*and_level));
      }
    }
    return;
  }
  /* If item is of type 'field op field/constant' add it to key_fields */

  if (cond->type() != Item::FUNC_ITEM)
    return;
  Item_func *cond_func= (Item_func*) cond;
  switch (cond_func->select_optimize()) {
  case Item_func::OPTIMIZE_NONE:
    break;
  case Item_func::OPTIMIZE_KEY:
    if (cond_func->key_item()->type() == Item::FIELD_ITEM)
      add_key_field(key_fields,*and_level,
		    ((Item_field*) (cond_func->key_item()))->field,
		    0,(Item*) 0,usable_tables);
    break;
  case Item_func::OPTIMIZE_OP:
  {
    bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC ||
		     cond_func->functype() == Item_func::EQUAL_FUNC);

    if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
    {
      add_key_field(key_fields,*and_level,
		    ((Item_field*) (cond_func->arguments()[0]))->field,
		    equal_func,
		    (cond_func->arguments()[1]),usable_tables);
    }
    if (cond_func->arguments()[1]->type() == Item::FIELD_ITEM &&
	cond_func->functype() != Item_func::LIKE_FUNC)
    {
      add_key_field(key_fields,*and_level,
		    ((Item_field*) (cond_func->arguments()[1]))->field,
		    equal_func,
		    (cond_func->arguments()[0]),usable_tables);
    }
    break;
  }
  case Item_func::OPTIMIZE_NULL:
    /* column_name IS [NOT] NULL */
    if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
    {
      add_key_field(key_fields,*and_level,
		    ((Item_field*) (cond_func->arguments()[0]))->field,
		    cond_func->functype() == Item_func::ISNULL_FUNC,
		    new Item_null, usable_tables);
    }
    break;
  }
  return;
}

/*
1456 1457
  Add all keys with uses 'field' for some keypart
  If field->and_level != and_level then only mark key_part as const_part
unknown's avatar
unknown committed
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
*/

static uint
max_part_bit(key_map bits)
{
  uint found;
  for (found=0; bits & 1 ; found++,bits>>=1) ;
  return found;
}


static void
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
  Field *field=key_field->field;
  TABLE *form= field->table;
  KEYUSE keyuse;

  if (key_field->eq_func && !key_field->exists_optimize)
  {
    for (uint key=0 ; key < form->keys ; key++)
    {
      if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
	continue;
      if (form->key_info[key].flags & HA_FULLTEXT)
	continue;    // ToDo: ft-keys in non-ft queries.   SerG

      uint key_parts= (uint) form->key_info[key].key_parts;
      for (uint part=0 ; part <  key_parts ; part++)
      {
	if (field->eq(form->key_info[key].key_part[part].field))
	{
	  keyuse.table= field->table;
	  keyuse.val =  key_field->val;
	  keyuse.key =  key;
	  keyuse.keypart=part;
	  keyuse.used_tables=key_field->val->used_tables();
	  VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
	}
      }
    }
  }
  /* Mark that we can optimize LEFT JOIN */
  if (key_field->val->type() == Item::NULL_ITEM &&
      !key_field->field->real_maybe_null())
    key_field->field->table->reginfo.not_exists_optimize=1;
}

static void
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
            JOIN_TAB *stat,COND *cond,table_map usable_tables)
{
1510
  Item_func_match *cond_func=NULL;
unknown's avatar
unknown committed
1511

1512 1513 1514
  if (!cond)
    return;

1515 1516
  if (cond->type() == Item::FUNC_ITEM)
  {
1517 1518 1519
    Item_func *func=(Item_func *)cond;
    Item_func::Functype functype=  func->functype();
    if (functype == Item_func::FT_FUNC)
1520
      cond_func=(Item_func_match *)cond;
1521 1522 1523 1524 1525 1526
    else if (func->arg_count == 2)
    {
      Item_func *arg0=(Item_func *)(func->arguments()[0]),
                *arg1=(Item_func *)(func->arguments()[1]);
      if ((functype == Item_func::GE_FUNC ||
           functype == Item_func::GT_FUNC)  &&
1527
           arg0->type() == Item::FUNC_ITEM          &&
1528
           arg0->functype() == Item_func::FT_FUNC   &&
1529
           arg1->const_item() && arg1->val()>0)
1530 1531 1532 1533 1534
        cond_func=(Item_func_match *) arg0;
      else if ((functype == Item_func::LE_FUNC ||
                functype == Item_func::LT_FUNC)  &&
                arg1->type() == Item::FUNC_ITEM          &&
                arg1->functype() == Item_func::FT_FUNC   &&
1535
                arg0->const_item() && arg0->val()>0)
1536 1537
        cond_func=(Item_func_match *) arg1;
    }
1538 1539 1540
  }
  else if (cond->type() == Item::COND_ITEM)
  {
unknown's avatar
unknown committed
1541
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
1542 1543 1544 1545

    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      Item *item;
1546
      /*
1547
         I'm (Sergei) too lazy to implement proper recursive descent here,
1548 1549 1550
         and anyway, nobody will use such a stupid queries
         that will require it :-)
         May be later...
1551
      */
1552
      while ((item=li++))
1553
      {
1554 1555 1556 1557 1558 1559
        if (item->type() == Item::FUNC_ITEM &&
            ((Item_func *)item)->functype() == Item_func::FT_FUNC)
        {
          cond_func=(Item_func_match *)item;
          break;
        }
1560
      }
1561 1562 1563
    }
  }

1564
  if (!cond_func || cond_func->key == NO_SUCH_KEY)
1565
    return;
unknown's avatar
unknown committed
1566 1567 1568 1569

  KEYUSE keyuse;

  keyuse.table= cond_func->table;
1570
  keyuse.val =  cond_func;
unknown's avatar
unknown committed
1571 1572 1573
  keyuse.key =  cond_func->key;
#define FT_KEYPART   (MAX_REF_PARTS+10)
  keyuse.keypart=FT_KEYPART;
1574
  keyuse.used_tables=cond_func->key_item()->used_tables();
unknown's avatar
unknown committed
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
  VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
}

static int
sort_keyuse(KEYUSE *a,KEYUSE *b)
{
  if (a->table->tablenr != b->table->tablenr)
    return (int) (a->table->tablenr - b->table->tablenr);
  if (a->key != b->key)
    return (int) (a->key - b->key);
  if (a->keypart != b->keypart)
    return (int) (a->keypart - b->keypart);
  return test(a->used_tables) - test(b->used_tables);	// Place const first
}


/*
1592 1593 1594
  Update keyuse array with all possible keys we can use to fetch rows
  join_tab is a array in tablenr_order
  stat is a reference array in 'prefered' order.
unknown's avatar
unknown committed
1595 1596 1597
*/

static bool
1598
update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
1599
		    uint tables, COND *cond, table_map normal_tables)
unknown's avatar
unknown committed
1600 1601 1602 1603 1604 1605 1606
{
  uint	and_level,i,found_eq_constant;

  {
    KEY_FIELD *key_fields,*end;

    if (!(key_fields=(KEY_FIELD*)
unknown's avatar
unknown committed
1607
	  thd->alloc(sizeof(key_fields[0])*(thd->cond_count+1)*2)))
unknown's avatar
unknown committed
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619
      return TRUE; /* purecov: inspected */
    and_level=0; end=key_fields;
    if (cond)
      add_key_fields(join_tab,&end,&and_level,cond,normal_tables);
    for (i=0 ; i < tables ; i++)
    {
      if (join_tab[i].on_expr)
      {
	add_key_fields(join_tab,&end,&and_level,join_tab[i].on_expr,
		       join_tab[i].table->map);
      }
    }
1620
    if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
unknown's avatar
unknown committed
1621 1622 1623 1624 1625 1626
      return TRUE;
    /* fill keyuse with found key parts */
    for (KEY_FIELD *field=key_fields ; field != end ; field++)
      add_key_part(keyuse,field);
  }

1627
  if (thd->lex.select->ftfunc_list.elements)
unknown's avatar
unknown committed
1628 1629 1630 1631 1632
  {
    add_ft_keys(keyuse,join_tab,cond,normal_tables);
  }

  /*
1633 1634 1635
    Remove ref if there is a keypart which is a ref and a const.
    Remove keyparts without previous keyparts.
    Special treatment for ft-keys.
unknown's avatar
unknown committed
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
  */
  if (keyuse->elements)
  {
    KEYUSE end,*prev,*save_pos,*use;

    qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE),
	  (qsort_cmp) sort_keyuse);

    bzero((char*) &end,sizeof(end));		/* Add for easy testing */
    VOID(insert_dynamic(keyuse,(gptr) &end));

    use=save_pos=dynamic_element(keyuse,0,KEYUSE*);
    prev=&end;
    found_eq_constant=0;
    for (i=0 ; i < keyuse->elements-1 ; i++,use++)
    {
      if (!use->used_tables)
1653
	use->table->const_key_parts[use->key] |=
unknown's avatar
unknown committed
1654 1655 1656
	  (key_part_map) 1 << use->keypart;
      if (use->keypart != FT_KEYPART)
      {
1657 1658 1659 1660 1661 1662 1663 1664
	if (use->key == prev->key && use->table == prev->table)
	{
	  if (prev->keypart+1 < use->keypart ||
	      prev->keypart == use->keypart && found_eq_constant)
	    continue;				/* remove */
	}
	else if (use->keypart != 0)		// First found must be 0
	  continue;
unknown's avatar
unknown committed
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
      }

      *save_pos= *use;
      prev=use;
      found_eq_constant= !use->used_tables;
      /* Save ptr to first use */
      if (!use->table->reginfo.join_tab->keyuse)
	use->table->reginfo.join_tab->keyuse=save_pos;
      use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
      save_pos++;
    }
    i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
    VOID(set_dynamic(keyuse,(gptr) &end,i));
    keyuse->elements=i;
  }
  return FALSE;
}


/*****************************************************************************
1685 1686
  Go through all combinations of not marked tables and find the one
  which uses least records
unknown's avatar
unknown committed
1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
*****************************************************************************/

/* Save const tables first as used tables */

static void
set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
{
  join->positions[idx].table= table;
  join->positions[idx].key=key;
  join->positions[idx].records_read=1.0;	/* This is a const table */

  /* Move the const table as down as possible in best_ref */
  JOIN_TAB **pos=join->best_ref+idx+1;
  JOIN_TAB *next=join->best_ref[idx];
1701
  for (;next != table ; pos++)
unknown's avatar
unknown committed
1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
  {
    JOIN_TAB *tmp=pos[0];
    pos[0]=next;
    next=tmp;
  }
  join->best_ref[idx]=table;
}


static void
find_best_combination(JOIN *join, table_map rest_tables)
{
  DBUG_ENTER("find_best_combination");
  join->best_read=DBL_MAX;
  find_best(join,rest_tables, join->const_tables,1.0,0.0);
  DBUG_VOID_RETURN;
}


static void
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
	  double read_time)
{
  ulong rec;
  double tmp;

  if (!rest_tables)
  {
    DBUG_PRINT("best",("read_time: %g  record_count: %g",read_time,
		       record_count));

    read_time+=record_count/(double) TIME_FOR_COMPARE;
    if (join->sort_by_table &&
	join->sort_by_table != join->positions[join->const_tables].table->table)
      read_time+=record_count;			// We have to make a temp table
    if (read_time < join->best_read)
    {
      memcpy((gptr) join->best_positions,(gptr) join->positions,
	     sizeof(POSITION)*idx);
      join->best_read=read_time;
    }
    return;
  }
  if (read_time+record_count/(double) TIME_FOR_COMPARE >= join->best_read)
    return;					/* Found better before */

  JOIN_TAB *s;
  double best_record_count=DBL_MAX,best_read_time=DBL_MAX;
  for (JOIN_TAB **pos=join->best_ref+idx ; (s=*pos) ; pos++)
  {
    table_map real_table_bit=s->table->map;
    if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent))
    {
      double best,best_time,records;
      best=best_time=records=DBL_MAX;
      KEYUSE *best_key=0;
1758
      uint best_max_key_part=0;
unknown's avatar
unknown committed
1759 1760 1761 1762 1763 1764

      if (s->keyuse)
      {						/* Use key if possible */
	TABLE *table=s->table;
	KEYUSE *keyuse,*start_key=0;
	double best_records=DBL_MAX;
1765
	uint max_key_part=0;
unknown's avatar
unknown committed
1766 1767

	/* Test how we can use keys */
1768
	rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE;  /* Assumed records/key */
unknown's avatar
unknown committed
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
	for (keyuse=s->keyuse ; keyuse->table == table ;)
	{
	  key_map found_part=0;
	  table_map found_ref=0;
	  uint key=keyuse->key;
	  KEY *keyinfo=table->key_info+key;
          bool ft_key=(keyuse->keypart == FT_KEYPART);

	  start_key=keyuse;
	  do
	  {
            uint keypart=keyuse->keypart;
	    do
	    {
1783
              if (!ft_key)
unknown's avatar
unknown committed
1784
              {
1785 1786
		table_map map;
		if (!(rest_tables & keyuse->used_tables))
unknown's avatar
unknown committed
1787
		{
1788 1789 1790 1791
		  found_part|= (key_part_map) 1 << keypart;
		  found_ref|= keyuse->used_tables;
		}
		/*
1792 1793 1794 1795 1796 1797
		  If we find a ref, assume this table matches a proportional
		  part of this table.
		  For example 100 records matching a table with 5000 records
		  gives 5000/100 = 50 records per key
		  Constant tables are ignored and to avoid bad matches,
		  we don't make rec less than 100.
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
		*/
		if (keyuse->used_tables &
		    (map=(keyuse->used_tables & ~join->const_table_map)))
		{
		  uint tablenr;
		  for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ;
		  if (map == 1)			// Only one table
		  {
		    TABLE *tmp_table=join->all_tables[tablenr];
		    if (rec > tmp_table->file->records && rec > 100)
		      rec=max(tmp_table->file->records,100);
		  }
unknown's avatar
unknown committed
1810 1811 1812 1813 1814 1815 1816 1817
		}
              }
	      keyuse++;
	    } while (keyuse->table == table && keyuse->key == key &&
		     keyuse->keypart == keypart);
	  } while (keyuse->table == table && keyuse->key == key);

	  /*
1818
	    Assume that that each key matches a proportional part of table.
unknown's avatar
unknown committed
1819 1820 1821 1822 1823 1824 1825
	  */
          if (!found_part && !ft_key)
	    continue;				// Nothing usable found
	  if (rec == 0)
	    rec=1L;				// Fix for small tables

          /*
1826
	    ft-keys require special treatment
unknown's avatar
unknown committed
1827 1828 1829 1830
          */
          if (ft_key)
          {
            /*
1831 1832
	      Really, there should be records=0.0 (yes!)
	      but 1.0 would be probably safer
unknown's avatar
unknown committed
1833 1834 1835 1836 1837 1838 1839
            */
            tmp=prev_record_reads(join,found_ref);
            records=1.0;
          }
          else
          {
	  /*
1840
	    Check if we found full key
unknown's avatar
unknown committed
1841 1842 1843
	  */
	  if (found_part == PREV_BITS(uint,keyinfo->key_parts))
	  {				/* use eq key */
1844
	    max_key_part= (uint) ~0;
unknown's avatar
unknown committed
1845 1846 1847 1848 1849 1850 1851
	    if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
	    {
	      tmp=prev_record_reads(join,found_ref);
	      records=1.0;
	    }
	    else
	    {
1852 1853
	      if (!found_ref)
	      {					// We found a const key
unknown's avatar
unknown committed
1854 1855 1856
		if (table->quick_keys & ((key_map) 1 << key))
		  records= (double) table->quick_rows[key];
		else
1857
		  records= (double) s->records/rec; // quick_range couldn't use key!
unknown's avatar
unknown committed
1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
	      }
	      else
	      {
		if (!(records=keyinfo->rec_per_key[keyinfo->key_parts-1]))
		{				// Prefere longer keys
		  records=
		    ((double) s->records / (double) rec *
		     (1.0 +
		      ((double) (table->max_key_length-keyinfo->key_length) /
		       (double) table->max_key_length)));
		  if (records < 2.0)
		    records=2.0;		// Can't be as good as a unique
		}
	      }
	      if (table->used_keys & ((key_map) 1 << key))
	      {
		/* we can use only index tree */
		uint keys_per_block= table->file->block_size/2/
unknown's avatar
unknown committed
1876
		  (keyinfo->key_length+table->file->ref_length)+1;
unknown's avatar
unknown committed
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886
		tmp=(record_count*(records+keys_per_block-1)/
		     keys_per_block);
	      }
	      else
		tmp=record_count*min(records,s->worst_seeks);
	    }
	  }
	  else
	  {
	    /*
1887 1888 1889
	      Use as much key-parts as possible and a uniq key is better
	      than a not unique key
	      Set tmp to (previous record count) * (records / combination)
unknown's avatar
unknown committed
1890
	    */
1891
	    if ((found_part & 1) &&
1892
		!(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX))
unknown's avatar
unknown committed
1893
	    {
1894
	      max_key_part=max_part_bit(found_part);
1895 1896 1897 1898
	      /*
		Check if quick_range could determinate how many rows we
		will match
	      */
unknown's avatar
unknown committed
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
	      if (table->quick_keys & ((key_map) 1 << key) &&
		  table->quick_key_parts[key] <= max_key_part)
		tmp=records= (double) table->quick_rows[key];
	      else
	      {
		/* Check if we have statistic about the distribution */
		if ((records=keyinfo->rec_per_key[max_key_part-1]))
		  tmp=records;
		else
		{
		  /*
1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
		    Assume that the first key part matches 1% of the file
		    and that the hole key matches 10 (dupplicates) or 1
		    (unique) records.
		    Assume also that more key matches proportionally more
		    records
		    This gives the formula:
		    records= (x * (b-a) + a*c-b)/(c-1)
		    
		    b = records matched by whole key
		    a = records matched by first key part (10% of all records?)
		    c = number of key parts in key
		    x = used key parts (1 <= x <= c)
unknown's avatar
unknown committed
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946
		  */
		  double rec_per_key;
		  if (!(rec_per_key=(double)
			keyinfo->rec_per_key[keyinfo->key_parts-1]))
		    rec_per_key=(double) s->records/rec+1;

		  if (!s->records)
		    tmp=0;
		  else if (rec_per_key/(double) s->records >= 0.01)
		    tmp=rec_per_key;
		  else
		  {
		    double a=s->records*0.01;
		    tmp=(max_key_part * (rec_per_key - a) +
			 a*keyinfo->key_parts - rec_per_key)/
		      (keyinfo->key_parts-1);
		    set_if_bigger(tmp,1.0);
		  }
		  records=(ulong) tmp;
		}
	      }
	      if (table->used_keys & ((key_map) 1 << key))
	      {
		/* we can use only index tree */
		uint keys_per_block= table->file->block_size/2/
unknown's avatar
unknown committed
1947
		  (keyinfo->key_length+table->file->ref_length)+1;
unknown's avatar
unknown committed
1948 1949 1950 1951 1952 1953 1954 1955
		tmp=record_count*(tmp+keys_per_block-1)/keys_per_block;
	      }
	      else
		tmp=record_count*min(tmp,s->worst_seeks);
	    }
	    else
	      tmp=best_time;			// Do nothing
	  }
1956
          } /* not ft_key */
unknown's avatar
unknown committed
1957 1958 1959 1960 1961 1962
	  if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
	  {
	    best_time=tmp + records/(double) TIME_FOR_COMPARE;
	    best=tmp;
	    best_records=records;
	    best_key=start_key;
1963
	    best_max_key_part=max_key_part;
unknown's avatar
unknown committed
1964 1965 1966 1967
	  }
	}
	records=best_records;
      }
1968 1969 1970 1971

      /*
	Don't test table scan if it can't be better.
	Prefer key lookup if we would use the same key for scanning.
1972 1973 1974 1975 1976

	Don't do a table scan on InnoDB tables, if we can read the used
	parts of the row from any of the used index.
	This is because table scans uses index and we would not win
	anything by using a table scan.
1977 1978 1979
      */
      if ((records >= s->found_records || best > s->read_time) &&
	  !(s->quick && best_key && s->quick->index == best_key->key &&
1980
	    best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
1981
	  !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
1982
	    s->table->used_keys && best_key))
unknown's avatar
unknown committed
1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
      {						// Check full join
	if (s->on_expr)
	{
	  tmp=s->found_records;			// Can't use read cache
	}
	else
	{
	  tmp=(double) s->read_time;
	  /* Calculate time to read through cache */
	  tmp*=(1.0+floor((double) cache_record_length(join,idx)*
			  record_count/(double) join_buff_size));
	}
	if (best == DBL_MAX ||
	    (tmp  + record_count/(double) TIME_FOR_COMPARE*s->found_records <
	     best + record_count/(double) TIME_FOR_COMPARE*records))
	{
1999 2000 2001 2002
	  /*
	    If the table has a range (s->quick is set) make_join_select()
	    will ensure that this will be used
	  */
unknown's avatar
unknown committed
2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
	  best=tmp;
	  records=s->found_records;
	  best_key=0;
	}
      }
      join->positions[idx].records_read=(double) records;
      join->positions[idx].key=best_key;
      join->positions[idx].table= s;
      if (!best_key && idx == join->const_tables &&
	  s->table == join->sort_by_table)
	join->sort_by_table= (TABLE*) 1;	// Must use temporary table

     /*
	Go to the next level only if there hasn't been a better key on
	this level! This will cut down the search for a lot simple cases!
       */
      double current_record_count=record_count*records;
      double current_read_time=read_time+best;
      if (best_record_count > current_record_count ||
	  best_read_time > current_read_time ||
	  idx == join->const_tables && s->table == join->sort_by_table)
      {
	if (best_record_count >= current_record_count &&
	    best_read_time >= current_read_time &&
	    (!(s->key_dependent & rest_tables) || records < 2.0))
	{
	  best_record_count=current_record_count;
	  best_read_time=current_read_time;
	}
	swap(JOIN_TAB*,join->best_ref[idx],*pos);
	find_best(join,rest_tables & ~real_table_bit,idx+1,
		  current_record_count,current_read_time);
	swap(JOIN_TAB*,join->best_ref[idx],*pos);
      }
      if (join->select_options & SELECT_STRAIGHT_JOIN)
	break;				// Don't test all combinations
    }
  }
}


/*
2045
  Find how much space the prevous read not const tables takes in cache
unknown's avatar
unknown committed
2046 2047
*/

2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082
static void calc_used_field_length(THD *thd, JOIN_TAB *join_tab)
{
  uint null_fields,blobs,fields,rec_length;
  null_fields=blobs=fields=rec_length=0;

  Field **f_ptr,*field;
  for (f_ptr=join_tab->table->field ; (field= *f_ptr) ; f_ptr++)
  {
    if (field->query_id == thd->query_id)
    {
      uint flags=field->flags;
      fields++;
      rec_length+=field->pack_length();
      if (flags & BLOB_FLAG)
	blobs++;
      if (!(flags & NOT_NULL_FLAG))
	null_fields++;
    }
  }
  if (null_fields)
    rec_length+=(join_tab->table->null_fields+7)/8;
  if (join_tab->table->maybe_null)
    rec_length+=sizeof(my_bool);
  if (blobs)
  {
    uint blob_length=(uint) (join_tab->table->file->mean_rec_length-
			     (join_tab->table->reclength- rec_length));
    rec_length+=(uint) max(4,blob_length);
  }
  join_tab->used_fields=fields;
  join_tab->used_fieldlength=rec_length;
  join_tab->used_blobs=blobs;
}


unknown's avatar
unknown committed
2083 2084 2085
static uint
cache_record_length(JOIN *join,uint idx)
{
2086
  uint length=0;
unknown's avatar
unknown committed
2087
  JOIN_TAB **pos,**end;
2088
  THD *thd=join->thd;
unknown's avatar
unknown committed
2089 2090 2091 2092 2093 2094

  for (pos=join->best_ref+join->const_tables,end=join->best_ref+idx ;
       pos != end ;
       pos++)
  {
    JOIN_TAB *join_tab= *pos;
2095 2096
    if (!join_tab->used_fieldlength)		/* Not calced yet */
      calc_used_field_length(thd, join_tab);
unknown's avatar
unknown committed
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120
    length+=join_tab->used_fieldlength;
  }
  return length;
}


static double
prev_record_reads(JOIN *join,table_map found_ref)
{
  double found=1.0;

  for (POSITION *pos=join->positions ; found_ref ; pos++)
  {
    if (pos->table->table->map & found_ref)
    {
      found_ref&= ~pos->table->table->map;
      found*=pos->records_read;
    }
  }
  return found;
}


/*****************************************************************************
2121
  Set up join struct according to best position.
unknown's avatar
unknown committed
2122 2123 2124 2125 2126
*****************************************************************************/

static bool
get_best_combination(JOIN *join)
{
2127
  uint i,tablenr;
unknown's avatar
unknown committed
2128 2129 2130 2131
  table_map used_tables;
  JOIN_TAB *join_tab,*j;
  KEYUSE *keyuse;
  uint table_count;
2132
  THD *thd=join->thd;
unknown's avatar
unknown committed
2133 2134 2135

  table_count=join->tables;
  if (!(join->join_tab=join_tab=
2136
	(JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*table_count)))
unknown's avatar
unknown committed
2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150
    return TRUE;

  join->full_join=0;

  used_tables=0;
  for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
  {
    TABLE *form;
    *j= *join->best_positions[tablenr].table;
    form=join->table[tablenr]=j->table;
    used_tables|= form->map;
    form->reginfo.join_tab=j;
    if (!j->on_expr)
      form->reginfo.not_exists_optimize=0;	// Only with LEFT JOIN
2151 2152 2153 2154 2155
    if (j->type == JT_CONST)
      continue;					// Handled in make_join_stat..

    j->ref.key = -1;
    j->ref.key_parts=0;
unknown's avatar
unknown committed
2156 2157 2158 2159 2160 2161 2162 2163 2164

    if (j->type == JT_SYSTEM)
      continue;
    if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
    {
      j->type=JT_ALL;
      if (tablenr != join->const_tables)
	join->full_join=1;
    }
2165 2166 2167
    else if (create_ref_for_key(join, j, keyuse, used_tables))
      return TRUE;				// Something went wrong
  }
unknown's avatar
unknown committed
2168

2169 2170 2171 2172 2173
  for (i=0 ; i < table_count ; i++)
    join->map2table[join->join_tab[i].table->tablenr]=join->join_tab+i;
  update_depend_map(join);
  return 0;
}
2174

unknown's avatar
unknown committed
2175

2176 2177 2178 2179 2180 2181 2182 2183 2184
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
			       table_map used_tables)
{
  KEYUSE *keyuse=org_keyuse;
  bool ftkey=(keyuse->keypart == FT_KEYPART);
  THD  *thd= join->thd;
  uint keyparts,length,key;
  TABLE *table;
  KEY *keyinfo;
2185

2186
  /*
2187
    Use best key from find_best
2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206
  */
  table=j->table;
  key=keyuse->key;
  keyinfo=table->key_info+key;

  if (ftkey)
  {
    Item_func_match *ifm=(Item_func_match *)keyuse->val;

    length=0;
    keyparts=1;
    ifm->join_key=1;
  }
  else
  {
    keyparts=length=0;
    do
    {
      if (!((~used_tables) & keyuse->used_tables))
unknown's avatar
unknown committed
2207
      {
2208
	if (keyparts == keyuse->keypart)
unknown's avatar
unknown committed
2209
	{
2210 2211
	  keyparts++;
	  length+=keyinfo->key_part[keyuse->keypart].store_length;
unknown's avatar
unknown committed
2212 2213
	}
      }
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266
      keyuse++;
    } while (keyuse->table == table && keyuse->key == key);
  } /* not ftkey */

  /* set up fieldref */
  keyinfo=table->key_info+key;
  j->ref.key_parts=keyparts;
  j->ref.key_length=length;
  j->ref.key=(int) key;
  if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) ||
      !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
						   (keyparts+1)))) ||
      !(j->ref.items=    (Item**) thd->alloc(sizeof(Item*)*keyparts)))
  {
    return TRUE;
  }
  j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
  j->ref.key_err=1;
  keyuse=org_keyuse;

  store_key **ref_key=j->ref.key_copy;
  byte *key_buff=j->ref.key_buff;
  if (ftkey)
  {
    j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
    if (keyuse->used_tables)
      return TRUE; // not supported yet. SerG

    j->type=JT_FT;
  }
  else
  {
    uint i;
    for (i=0 ; i < keyparts ; keyuse++,i++)
    {
      while (keyuse->keypart != i ||
	     ((~used_tables) & keyuse->used_tables))
	keyuse++;				/* Skip other parts */

      uint maybe_null= test(keyinfo->key_part[i].null_bit);
      j->ref.items[i]=keyuse->val;		// Save for cond removal
      if (!keyuse->used_tables &&
	  !(join->select_options & SELECT_DESCRIBE))
      {					// Compare against constant
	store_key_item *tmp=new store_key_item(thd,
					       keyinfo->key_part[i].field,
					       (char*)key_buff +
					       maybe_null,
					       maybe_null ?
					       (char*) key_buff : 0,
					       keyinfo->key_part[i].length,
					       keyuse->val);
	if (thd->fatal_error)
unknown's avatar
unknown committed
2267
	{
2268
	  return TRUE;
unknown's avatar
unknown committed
2269
	}
2270
	tmp->copy();
unknown's avatar
unknown committed
2271 2272
      }
      else
2273 2274 2275 2276 2277
	*ref_key++= get_store_key(thd,
				  keyuse,join->const_table_map,
				  &keyinfo->key_part[i],
				  (char*) key_buff,maybe_null);
      key_buff+=keyinfo->key_part[i].store_length;
unknown's avatar
unknown committed
2278
    }
2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
  } /* not ftkey */
  *ref_key=0;				// end_marker
  if (j->type == JT_FT)  /* no-op */;
  else if (j->type == JT_CONST)
    j->table->const_table=1;
  else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY))
	    != HA_NOSAME) ||
	   keyparts != keyinfo->key_parts)
    j->type=JT_REF;				/* Must read with repeat */
  else if (ref_key == j->ref.key_copy)
  {						/* Should never be reached */
    /*
      This happen if we are using a constant expression in the ON part
      of an LEFT JOIN.
      SELECT * FROM a LEFT JOIN b ON b.key=30
      Here we should not mark the table as a 'const' as a field may
      have a 'normal' value or a NULL value.
    */
    j->type=JT_CONST;
unknown's avatar
unknown committed
2298
  }
2299 2300
  else
    j->type=JT_EQ_REF;
unknown's avatar
unknown committed
2301 2302 2303 2304
  return 0;
}


2305

unknown's avatar
unknown committed
2306
static store_key *
unknown's avatar
unknown committed
2307 2308
get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
	      KEY_PART_INFO *key_part, char *key_buff, uint maybe_null)
unknown's avatar
unknown committed
2309 2310 2311
{
  if (!((~used_tables) & keyuse->used_tables))		// if const item
  {
unknown's avatar
unknown committed
2312 2313
    return new store_key_const_item(thd,
				    key_part->field,
unknown's avatar
unknown committed
2314 2315 2316 2317 2318 2319
				    key_buff + maybe_null,
				    maybe_null ? key_buff : 0,
				    key_part->length,
				    keyuse->val);
  }
  else if (keyuse->val->type() == Item::FIELD_ITEM)
unknown's avatar
unknown committed
2320 2321
    return new store_key_field(thd,
			       key_part->field,
unknown's avatar
unknown committed
2322 2323 2324 2325 2326
			       key_buff + maybe_null,
			       maybe_null ? key_buff : 0,
			       key_part->length,
			       ((Item_field*) keyuse->val)->field,
			       keyuse->val->full_name());
unknown's avatar
unknown committed
2327 2328
  return new store_key_item(thd,
			    key_part->field,
unknown's avatar
unknown committed
2329 2330 2331 2332 2333 2334 2335
			    key_buff + maybe_null,
			    maybe_null ? key_buff : 0,
			    key_part->length,
			    keyuse->val);
}

/*
2336 2337
  This function is only called for const items on fields which are keys
  returns 1 if there was some conversion made when the field was stored.
unknown's avatar
unknown committed
2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
*/

bool
store_val_in_field(Field *field,Item *item)
{
  THD *thd=current_thd;
  ulong cuted_fields=thd->cuted_fields;
  thd->count_cuted_fields=1;
  item->save_in_field(field);
  thd->count_cuted_fields=0;
  return cuted_fields != thd->cuted_fields;
}


static bool
make_simple_join(JOIN *join,TABLE *tmp_table)
{
  TABLE **tableptr;
  JOIN_TAB *join_tab;

2358 2359
  if (!(tableptr=(TABLE**) join->thd->alloc(sizeof(TABLE*))) ||
      !(join_tab=(JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
unknown's avatar
unknown committed
2360 2361 2362 2363 2364 2365
    return TRUE;
  join->join_tab=join_tab;
  join->table=tableptr; tableptr[0]=tmp_table;
  join->tables=1;
  join->const_tables=0;
  join->const_table_map=0;
unknown's avatar
unknown committed
2366 2367 2368
  join->tmp_table_param.field_count= join->tmp_table_param.sum_func_count=
    join->tmp_table_param.func_count=0;
  join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0;
unknown's avatar
unknown committed
2369 2370
  join->first_record=join->sort_and_group=0;
  join->sum_funcs=0;
unknown's avatar
unknown committed
2371
  join->send_records=(ha_rows) 0;
unknown's avatar
unknown committed
2372
  join->group=0;
2373
  join->do_send_rows = 1;
2374
  join->row_limit=join->thd->select_limit;
unknown's avatar
unknown committed
2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385

  join_tab->cache.buff=0;			/* No cacheing */
  join_tab->table=tmp_table;
  join_tab->select=0;
  join_tab->select_cond=0;
  join_tab->quick=0;
  join_tab->type= JT_ALL;			/* Map through all records */
  join_tab->keys= (uint) ~0;			/* test everything in quick */
  join_tab->info=0;
  join_tab->on_expr=0;
  join_tab->ref.key = -1;
unknown's avatar
unknown committed
2386 2387
  join_tab->not_used_in_distinct=0;
  join_tab->read_first_record= join_init_read_record;
2388
  join_tab->join=join;
unknown's avatar
unknown committed
2389
  bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
unknown's avatar
unknown committed
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409
  tmp_table->status=0;
  tmp_table->null_row=0;
  return FALSE;
}


static bool
make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
  DBUG_ENTER("make_join_select");
  if (select)
  {
    table_map used_tables;
    if (join->tables > 1)
      cond->update_used_tables();		// Tablenr may have changed
    {						// Check const tables
      COND *const_cond=
	make_cond_for_table(cond,join->const_table_map,(table_map) 0);
      DBUG_EXECUTE("where",print_where(const_cond,"constants"););
      if (const_cond && !const_cond->val_int())
2410 2411
      {
	DBUG_PRINT("info",("Found impossible WHERE condition"));
unknown's avatar
unknown committed
2412
	DBUG_RETURN(1);				// Impossible const condition
2413
      }
unknown's avatar
unknown committed
2414 2415 2416 2417 2418 2419
    }
    used_tables=(select->const_tables=join->const_table_map) | RAND_TABLE_BIT;
    for (uint i=join->const_tables ; i < join->tables ; i++)
    {
      JOIN_TAB *tab=join->join_tab+i;
      table_map current_map= tab->table->map;
2420
      bool use_quick_range=0;
unknown's avatar
unknown committed
2421
      used_tables|=current_map;
2422 2423

      if (tab->type == JT_REF && tab->quick &&
unknown's avatar
unknown committed
2424
	  (uint) tab->ref.key == tab->quick->index &&
2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
	  tab->ref.key_length < tab->quick->max_used_key_length)
      {
	/* Range uses longer key;  Use this instead of ref on key */
	tab->type=JT_ALL;
	use_quick_range=1;
	tab->use_quick=1;
	tab->ref.key_parts=0;		// Don't use ref key.
	join->best_positions[i].records_read=tab->quick->records;
      }

unknown's avatar
unknown committed
2435
      COND *tmp=make_cond_for_table(cond,used_tables,current_map);
2436 2437 2438 2439 2440 2441 2442 2443
      if (!tmp && tab->quick)
      {						// Outer join
	/*
	  Hack to handle the case where we only refer to a table
	  in the ON part of an OUTER JOIN.
	*/
	tmp=new Item_int((longlong) 1,1);	// Always true
      }
unknown's avatar
unknown committed
2444 2445 2446 2447
      if (tmp)
      {
	DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
	SQL_SELECT *sel=tab->select=(SQL_SELECT*)
2448
	  join->thd->memdup((gptr) select, sizeof(SQL_SELECT));
unknown's avatar
unknown committed
2449 2450 2451 2452 2453 2454
	if (!sel)
	  DBUG_RETURN(1);			// End of memory
	tab->select_cond=sel->cond=tmp;
	sel->head=tab->table;
	if (tab->quick)
	{
2455 2456
	  /* Use quick key read if it's a constant and it's not used
	     with key reading */
2457 2458
	  if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
	      && tab->type != JT_FT && (tab->type != JT_REF ||
unknown's avatar
unknown committed
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476
	       (uint) tab->ref.key == tab->quick->index))
	  {
	    sel->quick=tab->quick;		// Use value from get_quick_...
	    sel->quick_keys=0;
	    sel->needed_reg=0;
	  }
	  else
	  {
	    delete tab->quick;
	  }
	  tab->quick=0;
	}
	uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
	if (i == join->const_tables && ref_key)
	{
	  if (tab->const_keys && tab->table->reginfo.impossible_range)
	    DBUG_RETURN(1);
	}
2477
	else if (tab->type == JT_ALL && ! use_quick_range)
unknown's avatar
unknown committed
2478 2479 2480 2481 2482 2483
	{
	  if (tab->const_keys &&
	      tab->table->reginfo.impossible_range)
	    DBUG_RETURN(1);				// Impossible range
	  /*
	    We plan to scan all rows.
2484 2485 2486
	    Check again if we should use an index.
	    We could have used an column from a previous table in
	    the index if we are using limit and this is the first table
unknown's avatar
unknown committed
2487 2488 2489
	  */

	  if ((tab->keys & ~ tab->const_keys && i > 0) ||
2490 2491 2492
	      (tab->const_keys && i == join->const_tables &&
	       join->thd->select_limit < join->best_positions[i].records_read &&
	       !(join->select_options & OPTION_FOUND_ROWS)))
unknown's avatar
unknown committed
2493
	  {
2494 2495 2496
	    /* Join with outer join condition */
	    COND *orig_cond=sel->cond;
	    sel->cond=and_conds(sel->cond,tab->on_expr);
unknown's avatar
unknown committed
2497 2498
	    if (sel->test_quick_select(tab->keys,
				       used_tables & ~ current_map,
2499 2500 2501 2502
				       (join->select_options &
					OPTION_FOUND_ROWS ?
					HA_POS_ERROR :
					join->thd->select_limit)) < 0)
2503 2504
	      DBUG_RETURN(1);				// Impossible range
	    sel->cond=orig_cond;
unknown's avatar
unknown committed
2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
	  }
	  else
	  {
	    sel->needed_reg=tab->needed_reg;
	    sel->quick_keys=0;
	  }
	  if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
	  {
	    tab->keys=sel->quick_keys | sel->needed_reg;
	    tab->use_quick= (sel->needed_reg &&
			     (!select->quick_keys ||
			      (select->quick &&
			       (select->quick->records >= 100L)))) ?
	      2 : 1;
	    sel->read_tables= used_tables;
	  }
	  if (i != join->const_tables && tab->use_quick != 2)
	  {					/* Read with cache */
	    if ((tmp=make_cond_for_table(cond,
					 join->const_table_map |
					 current_map,
					 current_map)))
	    {
	      DBUG_EXECUTE("where",print_where(tmp,"cache"););
2529 2530
	      tab->cache.select=(SQL_SELECT*)
		join->thd->memdup((gptr) sel, sizeof(SQL_SELECT));
unknown's avatar
unknown committed
2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546
	      tab->cache.select->cond=tmp;
	      tab->cache.select->read_tables=join->const_table_map;
	    }
	  }
	}
      }
    }
  }
  DBUG_RETURN(0);
}


static void
make_join_readinfo(JOIN *join,uint options)
{
  uint i;
unknown's avatar
unknown committed
2547
  SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
unknown's avatar
unknown committed
2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569
  DBUG_ENTER("make_join_readinfo");

  for (i=join->const_tables ; i < join->tables ; i++)
  {
    JOIN_TAB *tab=join->join_tab+i;
    TABLE *table=tab->table;
    tab->read_record.table= table;
    tab->read_record.file=table->file;
    tab->next_select=sub_select;		/* normal select */
    switch (tab->type) {
    case JT_SYSTEM:				// Only happens with left join
      table->status=STATUS_NO_RECORD;
      tab->read_first_record= join_read_system;
      tab->read_record.read_record= join_no_more_records;
      break;
    case JT_CONST:				// Only happens with left join
      table->status=STATUS_NO_RECORD;
      tab->read_first_record= join_read_const;
      tab->read_record.read_record= join_no_more_records;
      break;
    case JT_EQ_REF:
      table->status=STATUS_NO_RECORD;
2570 2571 2572 2573 2574
      if (tab->select)
      {
	delete tab->select->quick;
	tab->select->quick=0;
      }
unknown's avatar
unknown committed
2575 2576 2577 2578 2579
      delete tab->quick;
      tab->quick=0;
      table->file->index_init(tab->ref.key);
      tab->read_first_record= join_read_key;
      tab->read_record.read_record= join_no_more_records;
unknown's avatar
unknown committed
2580 2581
      if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
	  !table->no_keyread)
unknown's avatar
unknown committed
2582 2583 2584 2585 2586 2587 2588
      {
	table->key_read=1;
	table->file->extra(HA_EXTRA_KEYREAD);
      }
      break;
    case JT_REF:
      table->status=STATUS_NO_RECORD;
2589 2590 2591 2592 2593
      if (tab->select)
      {
	delete tab->select->quick;
	tab->select->quick=0;
      }
unknown's avatar
unknown committed
2594 2595 2596 2597
      delete tab->quick;
      tab->quick=0;
      table->file->index_init(tab->ref.key);
      tab->read_first_record= join_read_always_key;
2598
      tab->read_record.read_record= join_read_next_same;
unknown's avatar
unknown committed
2599 2600
      if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
	  !table->no_keyread)
unknown's avatar
unknown committed
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613
      {
	table->key_read=1;
	table->file->extra(HA_EXTRA_KEYREAD);
      }
      break;
    case JT_FT:
      table->status=STATUS_NO_RECORD;
      table->file->index_init(tab->ref.key);
      tab->read_first_record= join_ft_read_first;
      tab->read_record.read_record= join_ft_read_next;
      break;
    case JT_ALL:
      /*
2614
	If previous table use cache
unknown's avatar
unknown committed
2615 2616
      */
      table->status=STATUS_NO_RECORD;
unknown's avatar
unknown committed
2617
      if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
unknown's avatar
unknown committed
2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
	  tab->use_quick != 2 && !tab->on_expr)
      {
	if ((options & SELECT_DESCRIBE) ||
	    !join_init_cache(join->thd,join->join_tab+join->const_tables,
			     i-join->const_tables))
	{
	  tab[-1].next_select=sub_select_cache; /* Patch previous */
	}
      }
      /* These init changes read_record */
      if (tab->use_quick == 2)
2629
      {
unknown's avatar
unknown committed
2630
	select_lex->options|=QUERY_NO_GOOD_INDEX_USED;
unknown's avatar
unknown committed
2631
	tab->read_first_record= join_init_quick_read_record;
2632 2633
	statistic_increment(select_range_check_count, &LOCK_status);
      }
unknown's avatar
unknown committed
2634 2635 2636
      else
      {
	tab->read_first_record= join_init_read_record;
2637 2638 2639 2640 2641 2642 2643 2644
	if (i == join->const_tables)
	{
	  if (tab->select && tab->select->quick)
	  {
	    statistic_increment(select_range_count, &LOCK_status);
	  }
	  else
	  {
unknown's avatar
unknown committed
2645
	    select_lex->options|=QUERY_NO_INDEX_USED;
2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656
	    statistic_increment(select_scan_count, &LOCK_status);
	  }
	}
	else
	{
	  if (tab->select && tab->select->quick)
	  {
	    statistic_increment(select_full_range_join_count, &LOCK_status);
	  }
	  else
	  {
unknown's avatar
unknown committed
2657
	    select_lex->options|=QUERY_NO_INDEX_USED;
2658 2659 2660
	    statistic_increment(select_full_join_count, &LOCK_status);
	  }
	}
unknown's avatar
unknown committed
2661
	if (!table->no_keyread)
unknown's avatar
unknown committed
2662
	{
unknown's avatar
unknown committed
2663 2664 2665 2666 2667 2668 2669 2670 2671 2672
	  if (tab->select && tab->select->quick &&
	      table->used_keys & ((key_map) 1 << tab->select->quick->index))
	  {
	    table->key_read=1;
	    table->file->extra(HA_EXTRA_KEYREAD);
	  }
	  else if (table->used_keys && ! (tab->select && tab->select->quick))
	  {					// Only read index tree
	    tab->index=find_shortest_key(table, table->used_keys);
	    tab->table->file->index_init(tab->index);
2673
	    tab->read_first_record= join_read_first;
unknown's avatar
unknown committed
2674 2675
	    tab->type=JT_NEXT;		// Read with index_first / index_next
	  }
unknown's avatar
unknown committed
2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
	}
      }
      break;
    default:
      DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */
      break;					/* purecov: deadcode */
    case JT_UNKNOWN:
    case JT_MAYBE_REF:
      abort();					/* purecov: deadcode */
    }
  }
  join->join_tab[join->tables-1].next_select=0; /* Set by do_select */
  DBUG_VOID_RETURN;
}


static void
join_free(JOIN *join)
{
  JOIN_TAB *tab,*end;
unknown's avatar
unknown committed
2696
  DBUG_ENTER("join_free");
unknown's avatar
unknown committed
2697 2698 2699

  if (join->table)
  {
2700 2701 2702 2703 2704
    /*
      Only a sorted table may be cached.  This sorted table is always the
      first non const table in join->table
    */
    if (join->tables > join->const_tables) // Test for not-const tables
unknown's avatar
unknown committed
2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717
      free_io_cache(join->table[join->const_tables]);
    for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
    {
      delete tab->select;
      delete tab->quick;
      x_free(tab->cache.buff);
      if (tab->table)
      {
	if (tab->table->key_read)
	{
	  tab->table->key_read=0;
	  tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
	}
unknown's avatar
unknown committed
2718 2719 2720
	/* Don't free index if we are using read_record */
	if (!tab->read_record.table)
	  tab->table->file->index_end();
unknown's avatar
unknown committed
2721
      }
unknown's avatar
unknown committed
2722
      end_read_record(&tab->read_record);
unknown's avatar
unknown committed
2723 2724 2725
    }
    join->table=0;
  }
2726 2727 2728 2729
  /*
    We are not using tables anymore
    Unlock all tables. We may be in an INSERT .... SELECT statement.
  */
unknown's avatar
unknown committed
2730 2731
  if (join->lock && join->thd->lock &&
      !(join->select_options & SELECT_NO_UNLOCK))
unknown's avatar
unknown committed
2732 2733 2734 2735 2736 2737
  {
    mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock
    join->lock=0;
  }
  join->group_fields.delete_elements();
  join->tmp_table_param.copy_funcs.delete_elements();
2738 2739
  if (join->tmp_table_param.copy_field)		// Because of bug in ecc
    delete [] join->tmp_table_param.copy_field;
unknown's avatar
unknown committed
2740
  join->tmp_table_param.copy_field=0;
unknown's avatar
unknown committed
2741
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2742 2743 2744 2745
}


/*****************************************************************************
2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758
  Remove the following expressions from ORDER BY and GROUP BY:
  Constant expressions
  Expression that only uses tables that are of type EQ_REF and the reference
  is in the ORDER list or if all refereed tables are of the above type.

  In the following, the X field can be removed:
  SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t1.a,t2.X
  SELECT * FROM t1,t2,t3 WHERE t1.a=t2.a AND t2.b=t3.b ORDER BY t1.a,t3.X

  These can't be optimized:
  SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.X,t1.a
  SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b ORDER BY t1.a,t2.c
  SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.b,t1.a
unknown's avatar
unknown committed
2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782
*****************************************************************************/

static bool
eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
{
  if (tab->cached_eq_ref_table)			// If cached
    return tab->eq_ref_table;
  tab->cached_eq_ref_table=1;
  if (tab->type == JT_CONST)			// We can skip const tables
    return (tab->eq_ref_table=1);		/* purecov: inspected */
  if (tab->type != JT_EQ_REF)
    return (tab->eq_ref_table=0);		// We must use this
  Item **ref_item=tab->ref.items;
  Item **end=ref_item+tab->ref.key_parts;
  uint found=0;
  table_map map=tab->table->map;

  for (; ref_item != end ; ref_item++)
  {
    if (! (*ref_item)->const_item())
    {						// Not a const ref
      ORDER *order;
      for (order=start_order ; order ; order=order->next)
      {
2783
	if ((*ref_item)->eq(order->item[0],0))
unknown's avatar
unknown committed
2784 2785 2786 2787 2788
	  break;
      }
      if (order)
      {
	found++;
unknown's avatar
unknown committed
2789
	DBUG_ASSERT(!(order->used & map));
unknown's avatar
unknown committed
2790 2791 2792 2793 2794 2795 2796 2797
	order->used|=map;
	continue;				// Used in ORDER BY
      }
      if (!only_eq_ref_tables(join,start_order, (*ref_item)->used_tables()))
	return (tab->eq_ref_table=0);
    }
  }
  /* Check that there was no reference to table before sort order */
2798
  for (; found && start_order ; start_order=start_order->next)
unknown's avatar
unknown committed
2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815
  {
    if (start_order->used & map)
    {
      found--;
      continue;
    }
    if (start_order->depend_map & map)
      return (tab->eq_ref_table=0);
  }
  return tab->eq_ref_table=1;
}


static bool
only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables)
{
  if (specialflag &  SPECIAL_SAFE_MODE)
2816
    return 0;			// skip this optimize /* purecov: inspected */
unknown's avatar
unknown committed
2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831
  for (JOIN_TAB **tab=join->map2table ; tables ; tab++, tables>>=1)
  {
    if (tables & 1 && !eq_ref_table(join, order, *tab))
      return 0;
  }
  return 1;
}


/* Update the dependency map for the tables */

static void update_depend_map(JOIN *join)
{
  JOIN_TAB *join_tab=join->join_tab, *end=join_tab+join->tables;

2832
  for (; join_tab != end ; join_tab++)
unknown's avatar
unknown committed
2833 2834 2835 2836 2837 2838 2839 2840
  {
    TABLE_REF *ref= &join_tab->ref;
    table_map depend_map=0;
    Item **item=ref->items;
    uint i;
    for (i=0 ; i < ref->key_parts ; i++,item++)
      depend_map|=(*item)->used_tables();
    ref->depend_map=depend_map;
2841
    for (JOIN_TAB **tab=join->map2table;
unknown's avatar
unknown committed
2842
	 depend_map ;
2843
	 tab++,depend_map>>=1 )
unknown's avatar
unknown committed
2844 2845
    {
      if (depend_map & 1)
2846
	ref->depend_map|=(*tab)->ref.depend_map;
unknown's avatar
unknown committed
2847 2848 2849 2850 2851 2852 2853 2854 2855
    }
  }
}


/* Update the dependency map for the sort order */

static void update_depend_map(JOIN *join, ORDER *order)
{
2856
  for (; order ; order=order->next)
unknown's avatar
unknown committed
2857 2858 2859 2860 2861 2862
  {
    table_map depend_map;
    order->item[0]->update_used_tables();
    order->depend_map=depend_map=order->item[0]->used_tables();
    if (!(order->depend_map & RAND_TABLE_BIT))	// Not item_sum() or RAND()
    {
2863
      for (JOIN_TAB **tab=join->map2table;
unknown's avatar
unknown committed
2864
	   depend_map ;
2865
	   tab++, depend_map>>=1)
unknown's avatar
unknown committed
2866 2867
      {
	if (depend_map & 1)
2868
	  order->depend_map|=(*tab)->ref.depend_map;
unknown's avatar
unknown committed
2869 2870 2871 2872 2873 2874 2875
      }
    }
  }
}


/*
unknown's avatar
unknown committed
2876 2877
  simple_order is set to 1 if sort_order only uses fields from head table
  and the head table is not a LEFT JOIN table
unknown's avatar
unknown committed
2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903
*/

static ORDER *
remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
{
  if (join->tables == join->const_tables)
    return 0;					// No need to sort
  DBUG_ENTER("remove_const");
  ORDER *order,**prev_ptr;
  table_map first_table= join->join_tab[join->const_tables].table->map;
  table_map not_const_tables= ~join->const_table_map;
  table_map ref;
  prev_ptr= &first_order;
  *simple_order= join->join_tab[join->const_tables].on_expr ? 0 : 1;

  /* NOTE: A variable of not_const_tables ^ first_table; breaks gcc 2.7 */

  update_depend_map(join, first_order);
  for (order=first_order; order ; order=order->next)
  {
    table_map order_tables=order->item[0]->used_tables();
    if (order->item[0]->with_sum_func)
      *simple_order=0;				// Must do a temp table to sort
    else if (!(order_tables & not_const_tables))
    {
      DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
unknown's avatar
unknown committed
2904
      continue;					// skip const item
unknown's avatar
unknown committed
2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946
    }
    else
    {
      if (order_tables & RAND_TABLE_BIT)
	*simple_order=0;
      else
      {
	Item *comp_item=0;
	if (cond && const_expression_in_where(cond,order->item[0], &comp_item))
	{
	  DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
	  continue;
	}
	if ((ref=order_tables & (not_const_tables ^ first_table)))
	{
	  if (only_eq_ref_tables(join,first_order,ref))
	  {
	    DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
	    continue;
	  }
	  *simple_order=0;			// Must do a temp table to sort
	}
      }
    }
    *prev_ptr= order;				// use this entry
    prev_ptr= &order->next;
  }
  *prev_ptr=0;
  if (!first_order)				// Nothing to sort/group
    *simple_order=1;
  DBUG_PRINT("exit",("simple_order: %d",(int) *simple_order));
  DBUG_RETURN(first_order);
}

static int
return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
		 bool send_row, uint select_options,const char *info,
		 Item *having, Procedure *procedure)
{
  DBUG_ENTER("return_zero_rows");

  if (select_options & SELECT_DESCRIBE)
unknown's avatar
unknown committed
2947
  {	
2948
    describe_info(current_thd, info);
unknown's avatar
unknown committed
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959
    DBUG_RETURN(0);
  }
  if (procedure)
  {
    if (result->prepare(fields))		// This hasn't been done yet
      DBUG_RETURN(-1);
  }
  if (send_row)
  {
    for (TABLE_LIST *table=tables; table ; table=table->next)
      mark_as_null_row(table->table);		// All fields are NULL
2960
    if (having && having->val_int() == 0)
unknown's avatar
unknown committed
2961 2962
      send_row=0;
  }
2963
  if (!(result->send_fields(fields,1)))
unknown's avatar
unknown committed
2964 2965 2966
  {
    if (send_row)
      result->send_data(fields);
2967
    if (tables)				// Not from do_select()
2968 2969 2970 2971 2972
    {
      /* Close open cursors */
      for (TABLE_LIST *table=tables; table ; table=table->next)
	table->table->file->index_end();
    }
2973
    result->send_eof();				// Should be safe
unknown's avatar
unknown committed
2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985
  }
  DBUG_RETURN(0);
}


static void clear_tables(JOIN *join)
{
  for (uint i=0 ; i < join->tables ; i++)
    mark_as_null_row(join->table[i]);		// All fields are NULL
}

/*****************************************************************************
2986 2987 2988 2989 2990 2991
  Make som simple condition optimization:
  If there is a test 'field = const' change all refs to 'field' to 'const'
  Remove all dummy tests 'item = item', 'const op const'.
  Remove all 'item is NULL', when item can never be null!
  item->marker should be 0 for all items on entry
  Return in cond_value FALSE if condition is impossible (1 = 2)
unknown's avatar
unknown committed
2992 2993 2994 2995
*****************************************************************************/

class COND_CMP :public ilink {
public:
unknown's avatar
unknown committed
2996
  static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
unknown's avatar
unknown committed
2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012
  static void operator delete(void *ptr __attribute__((unused)),
			      size_t size __attribute__((unused))) {} /*lint -e715 */

  Item *and_level;
  Item_func *cmp_func;
  COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {}
};

#ifdef __GNUC__
template class I_List<COND_CMP>;
template class I_List_iterator<COND_CMP>;
template class List<Item_func_match>;
template class List_iterator<Item_func_match>;
#endif

/*
3013 3014
  change field = field to field = const for each found field = const in the
  and_level
unknown's avatar
unknown committed
3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039
*/

static void
change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
			 Item *cond, Item *field, Item *value)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= ((Item_cond*) cond)->functype() ==
      Item_func::COND_AND_FUNC;
    List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
    Item *item;
    while ((item=li++))
      change_cond_ref_to_const(save_list,and_level ? cond : item, item,
			       field, value);
    return;
  }
  if (cond->eq_cmp_result() == Item::COND_OK)
    return;					// Not a boolean function

  Item_bool_func2 *func=  (Item_bool_func2*) cond;
  Item *left_item=  func->arguments()[0];
  Item *right_item= func->arguments()[1];
  Item_func::Functype functype=  func->functype();

3040
  if (right_item->eq(field,0) && left_item != value)
unknown's avatar
unknown committed
3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058
  {
    Item *tmp=value->new_item();
    if (tmp)
    {
      func->arguments()[1] = tmp;
      func->update_used_tables();
      if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
	  && and_father != cond && !left_item->const_item())
      {
	cond->marker=1;
	COND_CMP *tmp2;
	if ((tmp2=new COND_CMP(and_father,func)))
	  save_list->push_back(tmp2);
      }
      func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
				       func->arguments()[1]->result_type()));
    }
  }
3059
  else if (left_item->eq(field,0) && right_item != value)
unknown's avatar
unknown committed
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090
  {
    Item *tmp=value->new_item();
    if (tmp)
    {
      func->arguments()[0] = value = tmp;
      func->update_used_tables();
      if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
	  && and_father != cond && !right_item->const_item())
      {
	func->arguments()[0] = func->arguments()[1]; // For easy check
	func->arguments()[1] = value;
	cond->marker=1;
	COND_CMP *tmp2;
	if ((tmp2=new COND_CMP(and_father,func)))
	  save_list->push_back(tmp2);
      }
      func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
				       func->arguments()[1]->result_type()));
    }
  }
}


static void
propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
			 COND *cond)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= ((Item_cond*) cond)->functype() ==
      Item_func::COND_AND_FUNC;
unknown's avatar
unknown committed
3091
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
unknown's avatar
unknown committed
3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118
    Item *item;
    I_List<COND_CMP> save;
    while ((item=li++))
    {
      propagate_cond_constants(&save,and_level ? cond : item, item);
    }
    if (and_level)
    {						// Handle other found items
      I_List_iterator<COND_CMP> cond_itr(save);
      COND_CMP *cond_cmp;
      while ((cond_cmp=cond_itr++))
	if (!cond_cmp->cmp_func->arguments()[0]->const_item())
	  change_cond_ref_to_const(&save,cond_cmp->and_level,
				   cond_cmp->and_level,
				   cond_cmp->cmp_func->arguments()[0],
				   cond_cmp->cmp_func->arguments()[1]);
    }
  }
  else if (and_level != cond && !cond->marker)		// In a AND group
  {
    if (cond->type() == Item::FUNC_ITEM &&
	(((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
	 ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC))
    {
      Item_func_eq *func=(Item_func_eq*) cond;
      bool left_const= func->arguments()[0]->const_item();
      bool right_const=func->arguments()[1]->const_item();
3119 3120 3121
      if (!(left_const && right_const) &&
	  (func->arguments()[0]->result_type() ==
	   (func->arguments()[1]->result_type())))
unknown's avatar
unknown committed
3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158
      {
	if (right_const)
	{
	  func->arguments()[1]=resolve_const_item(func->arguments()[1],
						  func->arguments()[0]);
	  func->update_used_tables();
	  change_cond_ref_to_const(save_list,and_level,and_level,
				   func->arguments()[0],
				   func->arguments()[1]);
	}
	else if (left_const)
	{
	  func->arguments()[0]=resolve_const_item(func->arguments()[0],
						  func->arguments()[1]);
	  func->update_used_tables();
	  change_cond_ref_to_const(save_list,and_level,and_level,
				   func->arguments()[1],
				   func->arguments()[0]);
	}
      }
    }
  }
}


static COND *
optimize_cond(COND *conds,Item::cond_result *cond_value)
{
  if (!conds)
  {
    *cond_value= Item::COND_TRUE;
    return conds;
  }
  /* change field = field to field = const for each found field = const */
  DBUG_EXECUTE("where",print_where(conds,"original"););
  propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
  /*
3159 3160
    Remove all instances of item == item
    Remove all and-levels where CONST item != CONST item
unknown's avatar
unknown committed
3161 3162 3163 3164 3165 3166 3167 3168 3169
  */
  DBUG_EXECUTE("where",print_where(conds,"after const change"););
  conds=remove_eq_conds(conds,cond_value) ;
  DBUG_EXECUTE("info",print_where(conds,"after remove"););
  return conds;
}


/*
3170 3171 3172 3173 3174
  Remove const and eq items. Return new item, or NULL if no condition
  cond_value is set to according:
  COND_OK    query is possible (field = constant)
  COND_TRUE  always true	( 1 = 1 )
  COND_FALSE always false	( 1 = 2 )
unknown's avatar
unknown committed
3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244
*/

static COND *
remove_eq_conds(COND *cond,Item::cond_result *cond_value)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= ((Item_cond*) cond)->functype()
      == Item_func::COND_AND_FUNC;
    List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
    Item::cond_result tmp_cond_value;

    *cond_value=Item::COND_UNDEF;
    Item *item;
    while ((item=li++))
    {
      Item *new_item=remove_eq_conds(item,&tmp_cond_value);
      if (!new_item)
      {
#ifdef DELETE_ITEMS
	delete item;				// This may be shared
#endif
	li.remove();
      }
      else if (item != new_item)
      {
#ifdef DELETE_ITEMS
	delete item;				// This may be shared
#endif
	VOID(li.replace(new_item));
      }
      if (*cond_value == Item::COND_UNDEF)
	*cond_value=tmp_cond_value;
      switch (tmp_cond_value) {
      case Item::COND_OK:			// Not TRUE or FALSE
	if (and_level || *cond_value == Item::COND_FALSE)
	  *cond_value=tmp_cond_value;
	break;
      case Item::COND_FALSE:
	if (and_level)
	{
	  *cond_value=tmp_cond_value;
	  return (COND*) 0;			// Always false
	}
	break;
      case Item::COND_TRUE:
	if (!and_level)
	{
	  *cond_value= tmp_cond_value;
	  return (COND*) 0;			// Always true
	}
	break;
      case Item::COND_UNDEF:			// Impossible
	break; /* purecov: deadcode */
      }
    }
    if (!((Item_cond*) cond)->argument_list()->elements ||
	*cond_value != Item::COND_OK)
      return (COND*) 0;
    if (((Item_cond*) cond)->argument_list()->elements == 1)
    {						// Remove list
      item= ((Item_cond*) cond)->argument_list()->head();
      ((Item_cond*) cond)->argument_list()->empty();
      return item;
    }
  }
  else if (cond->type() == Item::FUNC_ITEM &&
	   ((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
  {
    /*
3245 3246 3247 3248 3249 3250 3251
      Handles this special case for some ODBC applications:
      The are requesting the row that was just updated with a auto_increment
      value with this construct:

      SELECT * from table_name where auto_increment_column IS NULL
      This will be changed to:
      SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
unknown's avatar
unknown committed
3252 3253 3254 3255
    */

    Item_func_isnull *func=(Item_func_isnull*) cond;
    Item **args= func->arguments();
3256
    THD *thd=current_thd;
unknown's avatar
unknown committed
3257 3258 3259 3260
    if (args[0]->type() == Item::FIELD_ITEM)
    {
      Field *field=((Item_field*) args[0])->field;
      if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
3261 3262
	  (thd->options & OPTION_AUTO_IS_NULL) &&
	  thd->insert_id())
unknown's avatar
unknown committed
3263
      {
unknown's avatar
unknown committed
3264
	query_cache_abort(&thd->net);
unknown's avatar
unknown committed
3265 3266 3267
	COND *new_cond;
	if ((new_cond= new Item_func_eq(args[0],
					new Item_int("last_insert_id()",
3268
						     thd->insert_id(),
unknown's avatar
unknown committed
3269 3270 3271
						     21))))
	{
	  cond=new_cond;
3272
	  cond->fix_fields(thd,0);
unknown's avatar
unknown committed
3273
	}
3274
	thd->insert_id(0);		// Clear for next request
unknown's avatar
unknown committed
3275 3276 3277 3278
      }
      /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
      else if (((field->type() == FIELD_TYPE_DATE) ||
		(field->type() == FIELD_TYPE_DATETIME)) &&
3279 3280
		(field->flags & NOT_NULL_FLAG) &&
	       !field->table->maybe_null)
unknown's avatar
unknown committed
3281 3282 3283 3284 3285
      {
	COND *new_cond;
	if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
	{
	  cond=new_cond;
3286
	  cond->fix_fields(thd,0);
unknown's avatar
unknown committed
3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299
	}
      }
    }
  }
  else if (cond->const_item())
  {
    *cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
    return (COND*) 0;
  }
  else if ((*cond_value= cond->eq_cmp_result()) != Item::COND_OK)
  {						// boolan compare function
    Item *left_item=	((Item_func*) cond)->arguments()[0];
    Item *right_item= ((Item_func*) cond)->arguments()[1];
3300
    if (left_item->eq(right_item,1))
unknown's avatar
unknown committed
3301 3302 3303 3304 3305 3306 3307
    {
      if (!left_item->maybe_null ||
	  ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)
	return (COND*) 0;			// Compare of identical items
    }
  }
  *cond_value=Item::COND_OK;
3308
  return cond;					// Point at next and level
unknown's avatar
unknown committed
3309 3310 3311
}

/*
3312
  Return 1 if the item is a const value in all the WHERE clause
unknown's avatar
unknown committed
3313 3314 3315 3316 3317 3318 3319 3320 3321
*/

static bool
const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= (((Item_cond*) cond)->functype()
		     == Item_func::COND_AND_FUNC);
unknown's avatar
unknown committed
3322
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
unknown's avatar
unknown committed
3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344
    Item *item;
    while ((item=li++))
    {
      bool res=const_expression_in_where(item, comp_item, const_item);
      if (res)					// Is a const value
      {
	if (and_level)
	  return 1;
      }
      else if (!and_level)
	return 0;
    }
    return and_level ? 0 : 1;
  }
  else if (cond->eq_cmp_result() != Item::COND_OK)
  {						// boolan compare function
    Item_func* func= (Item_func*) cond;
    if (func->functype() != Item_func::EQUAL_FUNC &&
	func->functype() != Item_func::EQ_FUNC)
      return 0;
    Item *left_item=	((Item_func*) cond)->arguments()[0];
    Item *right_item= ((Item_func*) cond)->arguments()[1];
3345
    if (left_item->eq(comp_item,1))
unknown's avatar
unknown committed
3346 3347 3348 3349
    {
      if (right_item->const_item())
      {
	if (*const_item)
3350
	  return right_item->eq(*const_item, 1);
unknown's avatar
unknown committed
3351 3352 3353 3354
	*const_item=right_item;
	return 1;
      }
    }
3355
    else if (right_item->eq(comp_item,1))
unknown's avatar
unknown committed
3356 3357 3358 3359
    {
      if (left_item->const_item())
      {
	if (*const_item)
3360
	  return left_item->eq(*const_item, 1);
unknown's avatar
unknown committed
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
	*const_item=left_item;
	return 1;
      }
    }
  }
  return 0;
}


/****************************************************************************
3371 3372 3373 3374
  Create a temp table according to a field list.
  Set distinct if duplicates could be removed
  Given fields field pointers are changed to point at tmp_table
  for send_fields
unknown's avatar
unknown committed
3375 3376
****************************************************************************/

unknown's avatar
unknown committed
3377
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
unknown's avatar
unknown committed
3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
			Item_result_field ***copy_func, Field **from_field,
			bool group, bool modify_item)
{
  switch (type) {
  case Item::SUM_FUNC_ITEM:
  {
    Item_sum *item_sum=(Item_sum*) item;
    bool maybe_null=item_sum->maybe_null;
    switch (item_sum->sum_func()) {
    case Item_sum::AVG_FUNC:			/* Place for sum & count */
      if (group)
	return new Field_string(sizeof(double)+sizeof(longlong),
				maybe_null, item->name,table,1);
      else
	return new Field_double(item_sum->max_length,maybe_null,
				item->name, table, item_sum->decimals);
    case Item_sum::STD_FUNC:			/* Place for sum & count */
      if (group)
	return	new Field_string(sizeof(double)*2+sizeof(longlong),
				 maybe_null, item->name,table,1);
      else
	return new Field_double(item_sum->max_length, maybe_null,
				item->name,table,item_sum->decimals);
    case Item_sum::UNIQUE_USERS_FUNC:
      return new Field_long(9,maybe_null,item->name,table,1);
    default:
      switch (item_sum->result_type()) {
      case REAL_RESULT:
	return new Field_double(item_sum->max_length,maybe_null,
				item->name,table,item_sum->decimals);
      case INT_RESULT:
	return new Field_longlong(item_sum->max_length,maybe_null,
3410
				  item->name,table,item->unsigned_flag);
unknown's avatar
unknown committed
3411 3412 3413 3414 3415 3416 3417 3418
      case STRING_RESULT:
	if (item_sum->max_length > 255)
	  return  new Field_blob(item_sum->max_length,maybe_null,
				 item->name,table,item->binary);
	return	new Field_string(item_sum->max_length,maybe_null,
				 item->name,table,item->binary);
      }
    }
unknown's avatar
unknown committed
3419
    thd->fatal_error=1;
unknown's avatar
unknown committed
3420 3421 3422 3423 3424 3425 3426
    return 0;					// Error
  }
  case Item::FIELD_ITEM:
  {
    Field *org_field=((Item_field*) item)->field,*new_field;

    *from_field=org_field;
unknown's avatar
unknown committed
3427 3428
    // The following should always be true
    if ((new_field= org_field->new_field(&thd->mem_root,table)))
unknown's avatar
unknown committed
3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448
    {
      if (modify_item)
	((Item_field*) item)->result_field= new_field;
      else
	new_field->field_name=item->name;
      if (org_field->maybe_null())
	new_field->flags&= ~NOT_NULL_FLAG;	// Because of outer join
    }
    return new_field;
  }
  case Item::PROC_ITEM:
  case Item::FUNC_ITEM:
  case Item::COND_ITEM:
  case Item::FIELD_AVG_ITEM:
  case Item::FIELD_STD_ITEM:
    /* The following can only happen with 'CREATE TABLE ... SELECT' */
  case Item::INT_ITEM:
  case Item::REAL_ITEM:
  case Item::STRING_ITEM:
  case Item::REF_ITEM:
3449
  case Item::NULL_ITEM:
unknown's avatar
unknown committed
3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461
  {
    bool maybe_null=item->maybe_null;
    Field *new_field;
    LINT_INIT(new_field);

    switch (item->result_type()) {
    case REAL_RESULT:
      new_field=new Field_double(item->max_length,maybe_null,
				 item->name,table,item->decimals);
      break;
    case INT_RESULT:
      new_field=new Field_longlong(item->max_length,maybe_null,
3462
				   item->name,table, item->unsigned_flag);
unknown's avatar
unknown committed
3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
      break;
    case STRING_RESULT:
      if (item->max_length > 255)
	new_field=  new Field_blob(item->max_length,maybe_null,
				   item->name,table,item->binary);
      else
	new_field= new Field_string(item->max_length,maybe_null,
				    item->name,table,item->binary);
      break;
    }
    if (copy_func)
      *((*copy_func)++) = (Item_result_field*) item; // Save for copy_funcs
    if (modify_item)
      ((Item_result_field*) item)->result_field=new_field;
    return new_field;
  }
  default:					// Dosen't have to be stored
    return 0;
  }
}


TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
		 ORDER *group, bool distinct, bool save_sum_fields,
3488
		 bool allow_distinct_limit, ulong select_options)
unknown's avatar
unknown committed
3489 3490 3491
{
  TABLE *table;
  uint	i,field_count,reclength,null_count,null_pack_length,
unknown's avatar
unknown committed
3492
        hidden_null_count, hidden_null_pack_length, hidden_field_count,
unknown's avatar
unknown committed
3493 3494
	blob_count,group_null_items;
  bool	using_unique_constraint=0;
unknown's avatar
unknown committed
3495
  bool  not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
unknown's avatar
unknown committed
3496 3497 3498 3499 3500 3501 3502 3503 3504
  char	*tmpname,path[FN_REFLEN];
  byte	*pos,*group_buff;
  uchar *null_flags;
  Field **reg_field,**from_field;
  Copy_field *copy=0;
  KEY *keyinfo;
  KEY_PART_INFO *key_part_info;
  Item_result_field **copy_func;
  MI_COLUMNDEF *recinfo;
3505
  uint temp_pool_slot=MY_BIT_NONE;
3506

unknown's avatar
unknown committed
3507 3508 3509 3510 3511
  DBUG_ENTER("create_tmp_table");
  DBUG_PRINT("enter",("distinct: %d  save_sum_fields: %d  allow_distinct_limit: %d  group: %d",
		      (int) distinct, (int) save_sum_fields,
		      (int) allow_distinct_limit,test(group)));

3512
  statistic_increment(created_tmp_tables, &LOCK_status);
3513

3514
  if (use_temp_pool)
unknown's avatar
unknown committed
3515
    temp_pool_slot = bitmap_set_next(&temp_pool);
3516 3517

  if (temp_pool_slot != MY_BIT_NONE) // we got a slot
3518
    sprintf(path, "%s%s_%lx_%i", mysql_tmpdir, tmp_file_prefix,
3519 3520
	    current_pid, temp_pool_slot);
  else // if we run out of slots or we are not using tempool
3521 3522 3523
    sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
            thd->thread_id, thd->tmp_table++);

unknown's avatar
unknown committed
3524 3525 3526 3527 3528
  if (group)
  {
    if (!param->quick_group)
      group=0;					// Can't use group key
    else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
3529
    {
unknown's avatar
unknown committed
3530
      (*tmp->item)->marker=4;			// Store null in key
3531 3532 3533
      if ((*tmp->item)->max_length >= MAX_CHAR_WIDTH)
	using_unique_constraint=1;
    }
unknown's avatar
unknown committed
3534 3535
    if (param->group_length >= MAX_BLOB_WIDTH)
      using_unique_constraint=1;
unknown's avatar
unknown committed
3536 3537
    if (group)
      distinct=0;				// Can't use distinct
unknown's avatar
unknown committed
3538 3539 3540
  }

  field_count=param->field_count+param->func_count+param->sum_func_count;
unknown's avatar
unknown committed
3541
  hidden_field_count=param->hidden_field_count;
unknown's avatar
unknown committed
3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556
  if (!my_multi_malloc(MYF(MY_WME),
		       &table,sizeof(*table),
		       &reg_field,sizeof(Field*)*(field_count+1),
		       &from_field,sizeof(Field*)*field_count,
		       &copy_func,sizeof(*copy_func)*(param->func_count+1),
		       &param->keyinfo,sizeof(*param->keyinfo),
		       &key_part_info,
		       sizeof(*key_part_info)*(param->group_parts+1),
		       &param->start_recinfo,
		       sizeof(*param->recinfo)*(field_count*2+4),
		       &tmpname,(uint) strlen(path)+1,
		       &group_buff,group && ! using_unique_constraint ?
		       param->group_length : 0,
		       NullS))
  {
unknown's avatar
unknown committed
3557
    bitmap_clear_bit(&temp_pool, temp_pool_slot);
unknown's avatar
unknown committed
3558 3559 3560 3561
    DBUG_RETURN(NULL); /* purecov: inspected */
  }
  if (!(param->copy_field=copy=new Copy_field[field_count]))
  {
unknown's avatar
unknown committed
3562
    bitmap_clear_bit(&temp_pool, temp_pool_slot);
unknown's avatar
unknown committed
3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579
    my_free((gptr) table,MYF(0)); /* purecov: inspected */
    DBUG_RETURN(NULL); /* purecov: inspected */
  }
  param->funcs=copy_func;
  strmov(tmpname,path);
  /* make table according to fields */

  bzero((char*) table,sizeof(*table));
  bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
  bzero((char*) from_field,sizeof(Field*)*field_count);
  table->field=reg_field;
  table->real_name=table->path=tmpname;
  table->table_name=base_name(tmpname);
  table->reginfo.lock_type=TL_WRITE;	/* Will be updated */
  table->db_stat=HA_OPEN_KEYFILE+HA_OPEN_RNDFILE;
  table->blob_ptr_size=mi_portable_sizeof_char_ptr;
  table->map=1;
unknown's avatar
unknown committed
3580
  table->tmp_table= TMP_TABLE;
unknown's avatar
unknown committed
3581
  table->db_low_byte_first=1;			// True for HEAP and MyISAM
3582 3583
  table->temp_pool_slot = temp_pool_slot;

unknown's avatar
unknown committed
3584

unknown's avatar
unknown committed
3585
  /* Calculate which type of fields we will store in the temporary table */
unknown's avatar
unknown committed
3586

unknown's avatar
unknown committed
3587 3588
  reclength=blob_count=null_count=hidden_null_count=group_null_items=0;
  param->using_indirect_summary_function=0;
unknown's avatar
unknown committed
3589

unknown's avatar
unknown committed
3590
  List_iterator_fast<Item> li(fields);
unknown's avatar
unknown committed
3591 3592 3593 3594 3595
  Item *item;
  Field **tmp_from_field=from_field;
  while ((item=li++))
  {
    Item::Type type=item->type();
unknown's avatar
unknown committed
3596
    if (not_all_columns)
unknown's avatar
unknown committed
3597
    {
unknown's avatar
unknown committed
3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609
      if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
      {
	/*
	  Mark that the we have ignored an item that refers to a summary
	  function. We need to know this if someone is going to use
	  DISTINCT on the result.
	*/
	param->using_indirect_summary_function=1;
	continue;
      }
      if (item->const_item())			// We don't have to store this
	continue;
unknown's avatar
unknown committed
3610
    }
unknown's avatar
unknown committed
3611 3612 3613 3614 3615 3616 3617 3618 3619
    if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
    {						/* Can't calc group yet */
      ((Item_sum*) item)->result_field=0;
      for (i=0 ; i < ((Item_sum*) item)->arg_count ; i++)
      {
	Item *arg= ((Item_sum*) item)->args[i];
	if (!arg->const_item())
	{
	  Field *new_field=
unknown's avatar
unknown committed
3620 3621
	    create_tmp_field(thd, table,arg,arg->type(),&copy_func,
			     tmp_from_field, group != 0,not_all_columns);
unknown's avatar
unknown committed
3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636
	  if (!new_field)
	    goto err;					// Should be OOM
	  tmp_from_field++;
	  *(reg_field++)= new_field;
	  reclength+=new_field->pack_length();
	  if (!(new_field->flags & NOT_NULL_FLAG))
	    null_count++;
	  if (new_field->flags & BLOB_FLAG)
	    blob_count++;
	  ((Item_sum*) item)->args[i]= new Item_field(new_field);
	}
      }
    }
    else
    {
unknown's avatar
unknown committed
3637
      Field *new_field=create_tmp_field(thd, table, item,type, &copy_func,
unknown's avatar
unknown committed
3638 3639
					tmp_from_field, group != 0,
					not_all_columns);
unknown's avatar
unknown committed
3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660
      if (!new_field)
      {
	if (thd->fatal_error)
	  goto err;				// Got OOM
	continue;				// Some kindf of const item
      }
      if (type == Item::SUM_FUNC_ITEM)
	((Item_sum *) item)->result_field= new_field;
      tmp_from_field++;
      reclength+=new_field->pack_length();
      if (!(new_field->flags & NOT_NULL_FLAG))
	null_count++;
      if (new_field->flags & BLOB_FLAG)
	blob_count++;
      if (item->marker == 4 && item->maybe_null)
      {
	group_null_items++;
	new_field->flags|= GROUP_FLAG;
      }
      *(reg_field++) =new_field;
    }
unknown's avatar
unknown committed
3661 3662
    if (!--hidden_field_count)
      hidden_null_count=null_count;
unknown's avatar
unknown committed
3663
  }
unknown's avatar
unknown committed
3664
  field_count= (uint) (reg_field - table->field);
unknown's avatar
unknown committed
3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686

  /* If result table is small; use a heap */
  if (blob_count || using_unique_constraint ||
      (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
      OPTION_BIG_TABLES)
  {
    table->file=get_new_handler(table,table->db_type=DB_TYPE_MYISAM);
    if (group &&
	(param->group_parts > table->file->max_key_parts() ||
	 param->group_length > table->file->max_key_length()))
      using_unique_constraint=1;
  }
  else
  {
    table->file=get_new_handler(table,table->db_type=DB_TYPE_HEAP);
  }

  if (!using_unique_constraint)
    reclength+= group_null_items;	// null flag is stored separately

  table->blob_fields=blob_count;
  if (blob_count == 0)
unknown's avatar
unknown committed
3687 3688
  {
    /* We need to ensure that first byte is not 0 for the delete link */
3689
    if (param->hidden_field_count)
unknown's avatar
unknown committed
3690 3691 3692 3693 3694 3695 3696
      hidden_null_count++;
    else
      null_count++;
  }
  hidden_null_pack_length=(hidden_null_count+7)/8;
  null_pack_length=hidden_null_count+(null_count+7)/8;
  reclength+=null_pack_length;
unknown's avatar
unknown committed
3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723
  if (!reclength)
    reclength=1;				// Dummy select

  table->fields=field_count;
  table->reclength=reclength;
  {
    uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
    table->rec_buff_length=alloc_length;
    if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
      goto err;
    table->record[1]= table->record[0]+alloc_length;
    table->record[2]= table->record[1]+alloc_length;
  }
  copy_func[0]=0;				// End marker

  recinfo=param->start_recinfo;
  null_flags=(uchar*) table->record[0];
  pos=table->record[0]+ null_pack_length;
  if (null_pack_length)
  {
    bzero((byte*) recinfo,sizeof(*recinfo));
    recinfo->type=FIELD_NORMAL;
    recinfo->length=null_pack_length;
    recinfo++;
    bfill(null_flags,null_pack_length,255);	// Set null fields
  }
  null_count= (blob_count == 0) ? 1 : 0;
unknown's avatar
unknown committed
3724
  hidden_field_count=param->hidden_field_count;
unknown's avatar
unknown committed
3725 3726 3727 3728 3729 3730 3731 3732 3733 3734
  for (i=0,reg_field=table->field; i < field_count; i++,reg_field++,recinfo++)
  {
    Field *field= *reg_field;
    uint length;
    bzero((byte*) recinfo,sizeof(*recinfo));

    if (!(field->flags & NOT_NULL_FLAG))
    {
      if (field->flags & GROUP_FLAG && !using_unique_constraint)
      {
3735 3736 3737 3738
	/*
	  We have to reserve one byte here for NULL bits,
	  as this is updated by 'end_update()'
	*/
unknown's avatar
unknown committed
3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772
	*pos++=0;				// Null is stored here
	recinfo->length=1;
	recinfo->type=FIELD_NORMAL;
	recinfo++;
	bzero((byte*) recinfo,sizeof(*recinfo));
      }
      else
      {
	recinfo->null_bit= 1 << (null_count & 7);
	recinfo->null_pos= null_count/8;
      }
      field->move_field((char*) pos,null_flags+null_count/8,
			1 << (null_count & 7));
      null_count++;
    }
    else
      field->move_field((char*) pos,(uchar*) 0,0);
    field->reset();
    if (from_field[i])
    {						/* Not a table Item */
      copy->set(field,from_field[i],save_sum_fields);
      copy++;
    }
    length=field->pack_length();
    pos+= length;

    /* Make entry for create table */
    recinfo->length=length;
    if (field->flags & BLOB_FLAG)
      recinfo->type= (int) FIELD_BLOB;
    else if (!field->zero_pack() &&
	     (field->type() == FIELD_TYPE_STRING ||
	      field->type() == FIELD_TYPE_VAR_STRING) &&
	     length >= 10 && blob_count)
unknown's avatar
unknown committed
3773
      recinfo->type=FIELD_SKIP_ENDSPACE;
unknown's avatar
unknown committed
3774 3775
    else
      recinfo->type=FIELD_NORMAL;
unknown's avatar
unknown committed
3776 3777
    if (!--hidden_field_count)
      null_count=(null_count+7) & ~7;		// move to next byte
unknown's avatar
unknown committed
3778 3779
  }

unknown's avatar
unknown committed
3780
  param->copy_field_end=copy;
unknown's avatar
unknown committed
3781 3782 3783
  param->recinfo=recinfo;
  store_record(table,2);			// Make empty default record

3784 3785 3786 3787 3788 3789
  if (tmp_table_size == ~(ulong) 0)		// No limit
    table->max_rows= ~(ha_rows) 0;
  else
    table->max_rows=(((table->db_type == DB_TYPE_HEAP) ?
		      min(tmp_table_size, max_heap_table_size) :
		      tmp_table_size)/ table->reclength);
unknown's avatar
unknown committed
3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809
  set_if_bigger(table->max_rows,1);		// For dummy start options
  keyinfo=param->keyinfo;

  if (group)
  {
    DBUG_PRINT("info",("Creating group key in temporary table"));
    table->group=group;				/* Table is grouped by key */
    param->group_buff=group_buff;
    table->keys=1;
    table->uniques= test(using_unique_constraint);
    table->key_info=keyinfo;
    keyinfo->key_part=key_part_info;
    keyinfo->flags=HA_NOSAME;
    keyinfo->usable_key_parts=keyinfo->key_parts= param->group_parts;
    keyinfo->key_length=0;
    keyinfo->rec_per_key=0;
    for (; group ; group=group->next,key_part_info++)
    {
      Field *field=(*group->item)->tmp_table_field();
      bool maybe_null=(*group->item)->maybe_null;
3810
      key_part_info->null_bit=0;
unknown's avatar
unknown committed
3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821
      key_part_info->field=  field;
      key_part_info->offset= field->offset();
      key_part_info->length= (uint16) field->pack_length();
      key_part_info->type=   (uint8) field->key_type();
      key_part_info->key_type =
	((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
	 (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT) ?
	0 : FIELDFLAG_BINARY;
      if (!using_unique_constraint)
      {
	group->buff=(char*) group_buff;
unknown's avatar
unknown committed
3822
	if (!(group->field=field->new_field(&thd->mem_root,table)))
unknown's avatar
unknown committed
3823 3824 3825 3826
	  goto err; /* purecov: inspected */
	if (maybe_null)
	{
	  /*
3827 3828 3829 3830
	    To be able to group on NULL, we reserve place in group_buff
	    for the NULL flag just before the column.
	    The field data is after this flag.
	    The NULL flag is updated by 'end_update()' and 'end_write()'
unknown's avatar
unknown committed
3831
	  */
3832 3833 3834 3835 3836
	  keyinfo->flags|= HA_NULL_ARE_EQUAL;	// def. that NULL == NULL
	  key_part_info->null_bit=field->null_bit;
	  key_part_info->null_offset= (uint) (field->null_ptr -
					      (uchar*) table->record[0]);
	  group->field->move_field((char*) ++group->buff);
3837
	  group_buff++;
unknown's avatar
unknown committed
3838 3839 3840 3841 3842 3843 3844 3845 3846
	}
	else
	  group->field->move_field((char*) group_buff);
	group_buff+= key_part_info->length;
      }
      keyinfo->key_length+=  key_part_info->length;
    }
  }

unknown's avatar
unknown committed
3847
  if (distinct)
unknown's avatar
unknown committed
3848
  {
unknown's avatar
unknown committed
3849 3850 3851 3852 3853 3854 3855
    /*
      Create an unique key or an unique constraint over all columns
      that should be in the result.  In the temporary table, there are
      'param->hidden_field_count' extra columns, whose null bits are stored
      in the first 'hidden_null_pack_length' bytes of the row.
    */
    null_pack_length-=hidden_null_pack_length;
unknown's avatar
unknown committed
3856
    keyinfo->key_parts= ((field_count-param->hidden_field_count)+
3857
			 test(null_pack_length));
unknown's avatar
unknown committed
3858
    if (allow_distinct_limit)
unknown's avatar
unknown committed
3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879
    {
      set_if_smaller(table->max_rows,thd->select_limit);
      param->end_write_records=thd->select_limit;
    }
    else
      param->end_write_records= HA_POS_ERROR;
    table->distinct=1;
    table->keys=1;
    if (blob_count)
    {
      using_unique_constraint=1;
      table->uniques=1;
    }
    if (!(key_part_info= (KEY_PART_INFO*)
	  sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO))))
      goto err;
    table->key_info=keyinfo;
    keyinfo->key_part=key_part_info;
    keyinfo->flags=HA_NOSAME;
    keyinfo->key_length=(uint16) reclength;
    keyinfo->name=(char*) "tmp";
unknown's avatar
unknown committed
3880
    if (null_pack_length)
unknown's avatar
unknown committed
3881
    {
3882
      key_part_info->null_bit=0;
unknown's avatar
unknown committed
3883 3884
      key_part_info->offset=hidden_null_pack_length;
      key_part_info->length=null_pack_length;
unknown's avatar
unknown committed
3885 3886 3887 3888 3889 3890 3891 3892 3893 3894
      key_part_info->field=new Field_string((char*) table->record[0],
					    (uint32) key_part_info->length,
					    (uchar*) 0,
					    (uint) 0,
					    Field::NONE,
					    NullS, table, (bool) 1);
      key_part_info->key_type=FIELDFLAG_BINARY;
      key_part_info->type=    HA_KEYTYPE_BINARY;
      key_part_info++;
    }
3895
    /* Create a distinct key over the columns we are going to return */
unknown's avatar
unknown committed
3896 3897
    for (i=param->hidden_field_count, reg_field=table->field + i ;
	 i < field_count;
unknown's avatar
unknown committed
3898 3899
	 i++, reg_field++, key_part_info++)
    {
3900
      key_part_info->null_bit=0;
unknown's avatar
unknown committed
3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922
      key_part_info->field=    *reg_field;
      key_part_info->offset=   (*reg_field)->offset();
      key_part_info->length=   (uint16) (*reg_field)->pack_length();
      key_part_info->type=     (uint8) (*reg_field)->key_type();
      key_part_info->key_type =
	((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
	 (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT) ?
	0 : FIELDFLAG_BINARY;
    }
  }
  if (thd->fatal_error)				// If end of memory
    goto err;					 /* purecov: inspected */
  table->db_record_offset=1;
  if (table->db_type == DB_TYPE_MYISAM)
  {
    if (create_myisam_tmp_table(table,param,select_options))
      goto err;
  }
  if (!open_tmp_table(table))
    DBUG_RETURN(table);

 err:
3923
  free_tmp_table(thd,table);                    /* purecov: inspected */
unknown's avatar
unknown committed
3924
  bitmap_clear_bit(&temp_pool, temp_pool_slot);
unknown's avatar
unknown committed
3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944
  DBUG_RETURN(NULL);				/* purecov: inspected */
}


static bool open_tmp_table(TABLE *table)
{
  int error;
  if ((error=table->file->ha_open(table->real_name,O_RDWR,HA_OPEN_TMP_TABLE)))
  {
    table->file->print_error(error,MYF(0)); /* purecov: inspected */
    table->db_stat=0;
    return(1);
  }
  /* VOID(ha_lock(table,F_WRLCK)); */		/* Single thread table */
  (void) table->file->extra(HA_EXTRA_QUICK);		/* Faster */
  return(0);
}


static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
3945
				    ulong options)
unknown's avatar
unknown committed
3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991
{
  int error;
  MI_KEYDEF keydef;
  MI_UNIQUEDEF uniquedef;
  KEY *keyinfo=param->keyinfo;

  DBUG_ENTER("create_myisam_tmp_table");
  if (table->keys)
  {						// Get keys for ni_create
    bool using_unique_constraint=0;
    MI_KEYSEG *seg= (MI_KEYSEG*) sql_calloc(sizeof(*seg) *
					    keyinfo->key_parts);
    if (!seg)
      goto err;

    if (keyinfo->key_length >= table->file->max_key_length() ||
	keyinfo->key_parts > table->file->max_key_parts() ||
	table->uniques)
    {
      /* Can't create a key; Make a unique constraint instead of a key */
      table->keys=0;
      table->uniques=1;
      using_unique_constraint=1;
      bzero((char*) &uniquedef,sizeof(uniquedef));
      uniquedef.keysegs=keyinfo->key_parts;
      uniquedef.seg=seg;
      uniquedef.null_are_equal=1;

      /* Create extra column for hash value */
      bzero((byte*) param->recinfo,sizeof(*param->recinfo));
      param->recinfo->type= FIELD_CHECK;
      param->recinfo->length=MI_UNIQUE_HASH_LENGTH;
      param->recinfo++;
      table->reclength+=MI_UNIQUE_HASH_LENGTH;
    }
    else
    {
      /* Create an unique key */
      bzero((char*) &keydef,sizeof(keydef));
      keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
      keydef.keysegs=  keyinfo->key_parts;
      keydef.seg= seg;
    }
    for (uint i=0; i < keyinfo->key_parts ; i++,seg++)
    {
      Field *field=keyinfo->key_part[i].field;
3992 3993 3994 3995
      seg->flag=     0;
      seg->language= MY_CHARSET_CURRENT;
      seg->length=   keyinfo->key_part[i].length;
      seg->start=    keyinfo->key_part[i].offset;
unknown's avatar
unknown committed
3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015
      if (field->flags & BLOB_FLAG)
      {
	seg->type=
	((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
	 HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT);
	seg->bit_start=seg->length - table->blob_ptr_size;
	seg->flag= HA_BLOB_PART;
	seg->length=0;			// Whole blob in unique constraint
      }
      else
      {
	seg->type=
	  ((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
	   HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT);
	if (!(field->flags & ZEROFILL_FLAG) &&
	    (field->type() == FIELD_TYPE_STRING ||
	     field->type() == FIELD_TYPE_VAR_STRING) &&
	    keyinfo->key_part[i].length > 4)
	  seg->flag|=HA_SPACE_PACK;
      }
4016
      if (!(field->flags & NOT_NULL_FLAG))
unknown's avatar
unknown committed
4017 4018 4019
      {
	seg->null_bit= field->null_bit;
	seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
4020 4021 4022 4023 4024 4025 4026
	/*
	  We are using a GROUP BY on something that contains NULL
	  In this case we have to tell MyISAM that two NULL should
	  on INSERT be compared as equal
	*/
	if (!using_unique_constraint)
	  keydef.flag|= HA_NULL_ARE_EQUAL;
unknown's avatar
unknown committed
4027 4028 4029 4030 4031
      }
    }
  }
  MI_CREATE_INFO create_info;
  bzero((char*) &create_info,sizeof(create_info));
4032 4033
  if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
      OPTION_BIG_TABLES)
unknown's avatar
unknown committed
4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046
    create_info.data_file_length= ~(ulonglong) 0;

  if ((error=mi_create(table->real_name,table->keys,&keydef,
		       (uint) (param->recinfo-param->start_recinfo),
		       param->start_recinfo,
		       table->uniques, &uniquedef,
		       &create_info,
		       HA_CREATE_TMP_TABLE)))
  {
    table->file->print_error(error,MYF(0));	/* purecov: inspected */
    table->db_stat=0;
    goto err;
  }
unknown's avatar
unknown committed
4047
  statistic_increment(created_tmp_disk_tables, &LOCK_status);
unknown's avatar
unknown committed
4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075
  table->db_record_offset=1;
  DBUG_RETURN(0);
 err:
  DBUG_RETURN(1);
}


void
free_tmp_table(THD *thd, TABLE *entry)
{
  const char *save_proc_info;
  DBUG_ENTER("free_tmp_table");
  DBUG_PRINT("enter",("table: %s",entry->table_name));

  save_proc_info=thd->proc_info;
  thd->proc_info="removing tmp table";
  if (entry->db_stat && entry->file)
  {
    (void) entry->file->close();
    delete entry->file;
  }
  if (!(test_flags & TEST_KEEP_TMP_TABLES) || entry->db_type == DB_TYPE_HEAP)
    (void) ha_delete_table(entry->db_type,entry->real_name);
  /* free blobs */
  for (Field **ptr=entry->field ; *ptr ; ptr++)
    delete *ptr;
  my_free((gptr) entry->record[0],MYF(0));
  free_io_cache(entry);
4076

unknown's avatar
unknown committed
4077
  bitmap_clear_bit(&temp_pool, entry->temp_pool_slot);
4078

unknown's avatar
unknown committed
4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111
  my_free((gptr) entry,MYF(0));
  thd->proc_info=save_proc_info;

  DBUG_VOID_RETURN;
}

/*
* If a HEAP table gets full, create a MyISAM table and copy all rows to this
*/

bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
			     bool ignore_last_dupp_key_error)
{
  TABLE new_table;
  const char *save_proc_info;
  THD *thd=current_thd;
  int write_err;
  DBUG_ENTER("create_myisam_from_heap");

  if (table->db_type != DB_TYPE_HEAP || error != HA_ERR_RECORD_FILE_FULL)
  {
    table->file->print_error(error,MYF(0));
    DBUG_RETURN(1);
  }
  new_table= *table;
  new_table.db_type=DB_TYPE_MYISAM;
  if (!(new_table.file=get_new_handler(&new_table,DB_TYPE_MYISAM)))
    DBUG_RETURN(1);				// End of memory

  save_proc_info=thd->proc_info;
  thd->proc_info="converting HEAP to MyISAM";

  if (create_myisam_tmp_table(&new_table,param,
4112
			      thd->lex.select_lex.options | thd->options))
unknown's avatar
unknown committed
4113 4114 4115 4116 4117
    goto err2;
  if (open_tmp_table(&new_table))
    goto err1;
  table->file->index_end();
  table->file->rnd_init();
4118 4119
  if (table->no_rows)
  {
4120 4121
    new_table.file->extra(HA_EXTRA_NO_ROWS);
    new_table.no_rows=1;
4122 4123
  }

unknown's avatar
unknown committed
4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145
  /* copy all old rows */
  while (!table->file->rnd_next(new_table.record[1]))
  {
    if ((write_err=new_table.file->write_row(new_table.record[1])))
      goto err;
  }
  /* copy row that filled HEAP table */
  if ((write_err=new_table.file->write_row(table->record[0])))
  {
    if (write_err != HA_ERR_FOUND_DUPP_KEY &&
	write_err != HA_ERR_FOUND_DUPP_UNIQUE || !ignore_last_dupp_key_error)
    goto err;
  }

  /* remove heap table and change to use myisam table */
  (void) table->file->rnd_end();
  (void) table->file->close();
  (void) table->file->delete_table(table->real_name);
  delete table->file;
  table->file=0;
  *table =new_table;
  table->file->change_table_ptr(table);
4146 4147
  thd->proc_info= (!strcmp(save_proc_info,"Copying to tmp table") ?
		   "Copying to tmp table on disk" : save_proc_info);
unknown's avatar
unknown committed
4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163
  DBUG_RETURN(0);

 err:
  DBUG_PRINT("error",("Got error: %d",write_err));
  table->file->print_error(error,MYF(0));	// Give table is full error
  (void) table->file->rnd_end();
  (void) new_table.file->close();
 err1:
  new_table.file->delete_table(new_table.real_name);
  delete new_table.file;
 err2:
  thd->proc_info=save_proc_info;
  DBUG_RETURN(1);
}


4164 4165 4166 4167 4168 4169
/****************************************************************************
  Make a join of all tables and write it on socket or to table
  Return:  0 if ok
           1 if error is sent
          -1 if error should be sent
****************************************************************************/
unknown's avatar
unknown committed
4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180

static int
do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
{
  int error;
  JOIN_TAB *join_tab;
  int (*end_select)(JOIN *, struct st_join_table *,bool);
  DBUG_ENTER("do_select");

  join->procedure=procedure;
  /*
4181
    Tell the client how many fields there are in a row
unknown's avatar
unknown committed
4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199
  */
  if (!table)
    join->result->send_fields(*fields,1);
  else
  {
    VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
    empty_record(table);
  }
  join->tmp_table=table;			/* Save for easy recursion */
  join->fields= fields;

  /* Set up select_end */
  if (table)
  {
    if (table->group && join->tmp_table_param.sum_func_count)
    {
      if (table->keys)
      {
4200
	DBUG_PRINT("info",("Using end_update"));
unknown's avatar
unknown committed
4201 4202 4203 4204
	end_select=end_update;
	table->file->index_init(0);
      }
      else
4205 4206
      {
	DBUG_PRINT("info",("Using end_unique_update"));
unknown's avatar
unknown committed
4207
	end_select=end_unique_update;
4208
      }
unknown's avatar
unknown committed
4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245
    }
    else if (join->sort_and_group)
    {
      DBUG_PRINT("info",("Using end_write_group"));
      end_select=end_write_group;
    }
    else
    {
      DBUG_PRINT("info",("Using end_write"));
      end_select=end_write;
    }
  }
  else
  {
    if (join->sort_and_group || (join->procedure &&
				 join->procedure->flags & PROC_GROUP))
      end_select=end_send_group;
    else
      end_select=end_send;
  }
  join->join_tab[join->tables-1].next_select=end_select;

  join_tab=join->join_tab+join->const_tables;
  join->send_records=0;
  if (join->tables == join->const_tables)
  {
    if (!(error=(*end_select)(join,join_tab,0)) || error == -3)
      error=(*end_select)(join,join_tab,1);
  }
  else
  {
    error=sub_select(join,join_tab,0);
    if (error >= 0)
      error=sub_select(join,join_tab,1);
    if (error == -3)
      error=0;					/* select_limit used */
  }
4246 4247

  /* Return 1 if error is sent;  -1 if error should be sent */
4248
  if (error < 0)
4249 4250 4251 4252
  {
    join->result->send_error(0,NullS);		/* purecov: inspected */
    error=1;					// Error sent
  }
4253
  else
unknown's avatar
unknown committed
4254
  {
4255 4256
    error=0;
    if (!table)					// If sending data to client
4257 4258 4259
    {
      join_free(join);				// Unlock all cursors
      if (join->result->send_eof())
4260
	error= 1;				// Don't send error
4261
    }
unknown's avatar
unknown committed
4262 4263 4264 4265 4266 4267 4268 4269 4270 4271
    DBUG_PRINT("info",("%ld records output",join->send_records));
  }
  if (table)
  {
    int old_error=error,tmp;
    if ((tmp=table->file->extra(HA_EXTRA_NO_CACHE)))
    {
      my_errno=tmp;
      error= -1;
    }
unknown's avatar
unknown committed
4272
    if ((tmp=table->file->index_end()))
unknown's avatar
unknown committed
4273 4274 4275 4276
    {
      my_errno=tmp;
      error= -1;
    }
4277
    if (error == -1)
unknown's avatar
unknown committed
4278 4279
      table->file->print_error(my_errno,MYF(0));
  }
4280
  DBUG_RETURN(error);
unknown's avatar
unknown committed
4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294
}


static int
sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
  int error;

  if (end_of_records)
  {
    if ((error=flush_cached_records(join,join_tab,FALSE)) < 0)
      return error; /* purecov: inspected */
    return sub_select(join,join_tab,end_of_records);
  }
4295 4296 4297 4298 4299
  if (join->thd->killed)		// If aborted by user
  {
    my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
    return -2;				 /* purecov: inspected */
  }
unknown's avatar
unknown committed
4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326
  if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0)
  {
    if (!store_record_in_cache(&join_tab->cache))
      return 0;					// There is more room in cache
    return flush_cached_records(join,join_tab,FALSE);
  }
  if ((error=flush_cached_records(join,join_tab,TRUE)) < 0)
    return error; /* purecov: inspected */
  return sub_select(join,join_tab,end_of_records); /* Use ordinary select */
}


static int
sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{

  join_tab->table->null_row=0;
  if (end_of_records)
    return (*join_tab->next_select)(join,join_tab+1,end_of_records);

  /* Cache variables for faster loop */
  int error;
  bool found=0;
  COND *on_expr=join_tab->on_expr, *select_cond=join_tab->select_cond;

  if (!(error=(*join_tab->read_first_record)(join_tab)))
  {
unknown's avatar
unknown committed
4327 4328 4329
    bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize;
    bool not_used_in_distinct=join_tab->not_used_in_distinct;
    ha_rows found_records=join->found_records;
unknown's avatar
unknown committed
4330 4331 4332 4333 4334 4335 4336 4337 4338
    READ_RECORD *info= &join_tab->read_record;

    do
    {
      if (join->thd->killed)			// Aborted by user
      {
	my_error(ER_SERVER_SHUTDOWN,MYF(0));	/* purecov: inspected */
	return -2;				/* purecov: inspected */
      }
4339
      join->examined_rows++;
unknown's avatar
unknown committed
4340 4341 4342 4343 4344 4345 4346
      if (!on_expr || on_expr->val_int())
      {
	found=1;
	if (not_exists_optimize)
	  break;			// Searching after not null columns
	if (!select_cond || select_cond->val_int())
	{
4347
	  if ((error=(*join_tab->next_select)(join,join_tab+1,0)) < 0)
unknown's avatar
unknown committed
4348
	    return error;
unknown's avatar
unknown committed
4349 4350
	  if (not_used_in_distinct && found_records != join->found_records)
	    return 0;
unknown's avatar
unknown committed
4351
	}
unknown's avatar
unknown committed
4352 4353
	else
	  info->file->unlock_row();
unknown's avatar
unknown committed
4354 4355 4356
      }
    } while (!(error=info->read_record(info)));
  }
4357
  if (error > 0)				// Fatal error
unknown's avatar
unknown committed
4358 4359 4360 4361 4362 4363 4364 4365
    return -1;

  if (!found && on_expr)
  {						// OUTER JOIN
    restore_record(join_tab->table,2);		// Make empty record
    mark_as_null_row(join_tab->table);		// For group by without error
    if (!select_cond || select_cond->val_int())
    {
4366
      if ((error=(*join_tab->next_select)(join,join_tab+1,0)) < 0)
unknown's avatar
unknown committed
4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442
	return error;				/* purecov: inspected */
    }
  }
  return 0;
}


static int
flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
{
  int error;
  READ_RECORD *info;

  if (!join_tab->cache.records)
    return 0;				/* Nothing to do */
  if (skipp_last)
    (void) store_record_in_cache(&join_tab->cache); // Must save this for later
  if (join_tab->use_quick == 2)
  {
    if (join_tab->select->quick)
    {					/* Used quick select last. reset it */
      delete join_tab->select->quick;
      join_tab->select->quick=0;
    }
  }
 /* read through all records */
  if ((error=join_init_read_record(join_tab)))
  {
    reset_cache(&join_tab->cache);
    join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0;
    return -error;			/* No records or error */
  }

  for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++)
  {
    tmp->status=tmp->table->status;
    tmp->table->status=0;
  }

  info= &join_tab->read_record;
  do
  {
    if (join->thd->killed)
    {
      my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
      return -2;				// Aborted by user /* purecov: inspected */
    }
    SQL_SELECT *select=join_tab->select;
    if (!error && (!join_tab->cache.select ||
		   !join_tab->cache.select->skipp_record()))
    {
      uint i;
      reset_cache(&join_tab->cache);
      for (i=(join_tab->cache.records- (skipp_last ? 1 : 0)) ; i-- > 0 ;)
      {
	read_cached_record(join_tab);
	if (!select || !select->skipp_record())
	  if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0)
	    return error; /* purecov: inspected */
      }
    }
  } while (!(error=info->read_record(info)));

  if (skipp_last)
    read_cached_record(join_tab);		// Restore current record
  reset_cache(&join_tab->cache);
  join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0;
  if (error > 0)				// Fatal error
    return -1;					/* purecov: inspected */
  for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++)
    tmp2->table->status=tmp2->status;
  return 0;
}


/*****************************************************************************
4443 4444
  The different ways to read a record
  Returns -1 if row was not found, 0 if row was found and 1 on errors
unknown's avatar
unknown committed
4445 4446
*****************************************************************************/
static int
4447
join_read_const_table(JOIN_TAB *tab, POSITION *pos)
unknown's avatar
unknown committed
4448 4449
{
  int error;
4450 4451 4452 4453 4454 4455 4456
  DBUG_ENTER("join_read_const_table");
  TABLE *table=tab->table;
  table->const_table=1;
  table->null_row=0;
  table->status=STATUS_NO_RECORD;
  
  if (tab->type == JT_SYSTEM)
unknown's avatar
unknown committed
4457
  {
4458 4459 4460 4461 4462 4463 4464
    if ((error=join_read_system(tab)))
    {						// Info for DESCRIBE
      tab->info="const row not found";
      /* Mark for EXPLAIN that the row was not found */
      pos->records_read=0.0;
      if (!table->outer_join || error > 0)
	DBUG_RETURN(error);
unknown's avatar
unknown committed
4465
    }
4466 4467 4468 4469
  }
  else
  {
    if ((error=join_read_const(tab)))
unknown's avatar
unknown committed
4470
    {
4471 4472 4473 4474 4475
      tab->info="unique row not found";
      /* Mark for EXPLAIN that the row was not found */
      pos->records_read=0.0;
      if (!table->outer_join || error > 0)
	DBUG_RETURN(error);
unknown's avatar
unknown committed
4476 4477
    }
  }
4478 4479 4480 4481 4482 4483 4484
  if (tab->on_expr && !table->null_row)
  {
    if ((table->null_row= test(tab->on_expr->val_int() == 0)))
      empty_record(table);
    }
  if (!table->null_row)
    table->maybe_null=0;
unknown's avatar
unknown committed
4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495
  DBUG_RETURN(0);
}


static int
join_read_system(JOIN_TAB *tab)
{
  TABLE *table= tab->table;
  int error;
  if (table->status & STATUS_GARBAGE)		// If first read
  {
4496 4497
    if ((error=table->file->read_first_row(table->record[0],
					   table->primary_key)))
unknown's avatar
unknown committed
4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538
    {
      if (error != HA_ERR_END_OF_FILE)
      {
	table->file->print_error(error,MYF(0));
	return 1;
      }
      table->null_row=1;			// This is ok.
      empty_record(table);			// Make empty record
      return -1;
    }
    store_record(table,1);
  }
  else if (!table->status)			// Only happens with left join
    restore_record(table,1);			// restore old record
  table->null_row=0;
  return table->status ? -1 : 0;
}


static int
join_read_const(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;
  if (table->status & STATUS_GARBAGE)		// If first read
  {
    if (cp_buffer_from_ref(&tab->ref))
      error=HA_ERR_KEY_NOT_FOUND;
    else
    {
      error=table->file->index_read_idx(table->record[0],tab->ref.key,
					(byte*) tab->ref.key_buff,
					tab->ref.key_length,HA_READ_KEY_EXACT);
    }
    if (error)
    {
      table->null_row=1;
      empty_record(table);
      if (error != HA_ERR_KEY_NOT_FOUND)
      {
	sql_print_error("read_const: Got error %d when reading table %s",
unknown's avatar
unknown committed
4539
			error, table->path);
unknown's avatar
unknown committed
4540 4541 4542 4543 4544 4545 4546
	table->file->print_error(error,MYF(0));
	return 1;
      }
      return -1;
    }
    store_record(table,1);
  }
unknown's avatar
unknown committed
4547 4548 4549
  else if (!(table->status & ~STATUS_NULL_ROW))	// Only happens with left join
  {
    table->status=0;
unknown's avatar
unknown committed
4550
    restore_record(table,1);			// restore old record
unknown's avatar
unknown committed
4551
  }
unknown's avatar
unknown committed
4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563
  table->null_row=0;
  return table->status ? -1 : 0;
}


static int
join_read_key(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;

  if (cmp_buffer_with_ref(tab) ||
4564
      (table->status & (STATUS_GARBAGE | STATUS_NO_PARENT | STATUS_NULL_ROW)))
unknown's avatar
unknown committed
4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576
  {
    if (tab->ref.key_err)
    {
      table->status=STATUS_NOT_FOUND;
      return -1;
    }
    error=table->file->index_read(table->record[0],
				  tab->ref.key_buff,
				  tab->ref.key_length,HA_READ_KEY_EXACT);
    if (error && error != HA_ERR_KEY_NOT_FOUND)
    {
      sql_print_error("read_key: Got error %d when reading table '%s'",error,
unknown's avatar
unknown committed
4577
		      table->path);
unknown's avatar
unknown committed
4578 4579 4580 4581
      table->file->print_error(error,MYF(0));
      return 1;
    }
  }
4582
  table->null_row=0;
unknown's avatar
unknown committed
4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601
  return table->status ? -1 : 0;
}


static int
join_read_always_key(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;

  if (cp_buffer_from_ref(&tab->ref))
    return -1;
  if ((error=table->file->index_read(table->record[0],
				     tab->ref.key_buff,
				     tab->ref.key_length,HA_READ_KEY_EXACT)))
  {
    if (error != HA_ERR_KEY_NOT_FOUND)
    {
      sql_print_error("read_const: Got error %d when reading table %s",error,
unknown's avatar
unknown committed
4602
		      table->path);
unknown's avatar
unknown committed
4603 4604 4605 4606 4607 4608 4609 4610
      table->file->print_error(error,MYF(0));
      return 1;
    }
    return -1; /* purecov: inspected */
  }
  return 0;
}

4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639
/*
  This function is used when optimizing away ORDER BY in 
  SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
*/
  
static int
join_read_last_key(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;

  if (cp_buffer_from_ref(&tab->ref))
    return -1;
  if ((error=table->file->index_read_last(table->record[0],
					  tab->ref.key_buff,
					  tab->ref.key_length)))
  {
    if (error != HA_ERR_KEY_NOT_FOUND)
    {
      sql_print_error("read_const: Got error %d when reading table %s",error,
		      table->path);
      table->file->print_error(error,MYF(0));
      return 1;
    }
    return -1; /* purecov: inspected */
  }
  return 0;
}

unknown's avatar
unknown committed
4640 4641 4642 4643 4644 4645 4646 4647 4648 4649

	/* ARGSUSED */
static int
join_no_more_records(READ_RECORD *info __attribute__((unused)))
{
  return -1;
}


static int
4650
join_read_next_same(READ_RECORD *info)
unknown's avatar
unknown committed
4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662
{
  int error;
  TABLE *table= info->table;
  JOIN_TAB *tab=table->reginfo.join_tab;

  if ((error=table->file->index_next_same(table->record[0],
					  tab->ref.key_buff,
					  tab->ref.key_length)))
  {
    if (error != HA_ERR_END_OF_FILE)
    {
      sql_print_error("read_next: Got error %d when reading table %s",error,
unknown's avatar
unknown committed
4663
		      table->path);
unknown's avatar
unknown committed
4664 4665 4666 4667 4668 4669 4670 4671 4672
      table->file->print_error(error,MYF(0));
      return 1;
    }
    table->status= STATUS_GARBAGE;
    return -1;
  }
  return 0;
}

4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698
static int
join_read_prev_same(READ_RECORD *info)
{
  int error;
  TABLE *table= info->table;
  JOIN_TAB *tab=table->reginfo.join_tab;

  if ((error=table->file->index_prev(table->record[0])))
  {
    if (error != HA_ERR_END_OF_FILE)
    {
      sql_print_error("read_next: Got error %d when reading table %s",error,
		      table->path);
      table->file->print_error(error,MYF(0));
      error= 1;
    }
    else
    {
      table->status= STATUS_GARBAGE;
      error= -1;
    }
  }
  else if (key_cmp(table, tab->ref.key_buff, tab->ref.key,
		   tab->ref.key_length))
  {
    table->status=STATUS_NOT_FOUND;
4699
    error= -1;
4700 4701 4702 4703
  }
  return error;
}

unknown's avatar
unknown committed
4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727

static int
join_init_quick_read_record(JOIN_TAB *tab)
{
  if (test_if_quick_select(tab) == -1)
    return -1;					/* No possible records */
  return join_init_read_record(tab);
}


static int
test_if_quick_select(JOIN_TAB *tab)
{
  delete tab->select->quick;
  tab->select->quick=0;
  return tab->select->test_quick_select(tab->keys,(table_map) 0,HA_POS_ERROR);
}


static int
join_init_read_record(JOIN_TAB *tab)
{
  if (tab->select && tab->select->quick)
    tab->select->quick->reset();
4728 4729
  init_read_record(&tab->read_record, tab->join->thd, tab->table,
		   tab->select,1,1);
unknown's avatar
unknown committed
4730 4731 4732 4733
  return (*tab->read_record.read_record)(&tab->read_record);
}

static int
4734
join_read_first(JOIN_TAB *tab)
unknown's avatar
unknown committed
4735 4736 4737
{
  int error;
  TABLE *table=tab->table;
unknown's avatar
unknown committed
4738 4739
  if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
      !table->no_keyread)
unknown's avatar
unknown committed
4740 4741 4742 4743 4744
  {
    table->key_read=1;
    table->file->extra(HA_EXTRA_KEYREAD);
  }
  tab->table->status=0;
4745
  tab->read_record.read_record=join_read_next;
unknown's avatar
unknown committed
4746 4747 4748 4749 4750 4751 4752 4753 4754
  tab->read_record.table=table;
  tab->read_record.file=table->file;
  tab->read_record.index=tab->index;
  tab->read_record.record=table->record[0];
  error=tab->table->file->index_first(tab->table->record[0]);
  if (error)
  {
    if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
    {
unknown's avatar
unknown committed
4755 4756
      sql_print_error("read_first_with_key: Got error %d when reading table",
		      error);
unknown's avatar
unknown committed
4757 4758 4759 4760 4761 4762 4763 4764
      table->file->print_error(error,MYF(0));
      return 1;
    }
    return -1;
  }
  return 0;
}

4765

unknown's avatar
unknown committed
4766
static int
4767
join_read_next(READ_RECORD *info)
unknown's avatar
unknown committed
4768 4769 4770 4771 4772 4773 4774
{
  int error=info->file->index_next(info->record);
  if (error)
  {
    if (error != HA_ERR_END_OF_FILE)
    {
      sql_print_error("read_next_with_key: Got error %d when reading table %s",
unknown's avatar
unknown committed
4775
		      error, info->table->path);
unknown's avatar
unknown committed
4776 4777 4778 4779 4780 4781 4782 4783 4784
      info->file->print_error(error,MYF(0));
      return 1;
    }
    return -1;
  }
  return 0;
}

static int
4785
join_read_last(JOIN_TAB *tab)
unknown's avatar
unknown committed
4786 4787 4788 4789 4790 4791 4792 4793 4794
{
  TABLE *table=tab->table;
  int error;
  if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)))
  {
    table->key_read=1;
    table->file->extra(HA_EXTRA_KEYREAD);
  }
  tab->table->status=0;
4795
  tab->read_record.read_record=join_read_prev;
unknown's avatar
unknown committed
4796 4797 4798 4799 4800 4801 4802 4803 4804
  tab->read_record.table=table;
  tab->read_record.file=table->file;
  tab->read_record.index=tab->index;
  tab->read_record.record=table->record[0];
  error=tab->table->file->index_last(tab->table->record[0]);
  if (error)
  {
    if (error != HA_ERR_END_OF_FILE)
    {
unknown's avatar
unknown committed
4805
      sql_print_error("read_last_with_key: Got error %d when reading table",
unknown's avatar
unknown committed
4806
		      error, table->path);
unknown's avatar
unknown committed
4807 4808 4809 4810 4811 4812 4813 4814
      table->file->print_error(error,MYF(0));
      return 1;
    }
    return -1;
  }
  return 0;
}

4815

unknown's avatar
unknown committed
4816
static int
4817
join_read_prev(READ_RECORD *info)
unknown's avatar
unknown committed
4818 4819 4820 4821 4822 4823 4824
{
  int error=info->file->index_prev(info->record);
  if (error)
  {
    if (error != HA_ERR_END_OF_FILE)
    {
      sql_print_error("read_prev_with_key: Got error %d when reading table: %s",
unknown's avatar
unknown committed
4825
		      error,info->table->path);
unknown's avatar
unknown committed
4826 4827 4828 4829 4830 4831 4832 4833
      info->file->print_error(error,MYF(0));
      return 1;
    }
    return -1;
  }
  return 0;
}

4834

unknown's avatar
unknown committed
4835 4836 4837 4838 4839 4840
static int
join_ft_read_first(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;

unknown's avatar
unknown committed
4841
#if NOT_USED_YET
unknown's avatar
unknown committed
4842
  if (cp_buffer_from_ref(&tab->ref))       // as ft-key doesn't use store_key's
unknown's avatar
unknown committed
4843
    return -1;                             // see also FT_SELECT::init()
unknown's avatar
unknown committed
4844
#endif
4845
  table->file->ft_init();
unknown's avatar
unknown committed
4846 4847 4848 4849 4850 4851

  error=table->file->ft_read(table->record[0]);
  if (error)
  {
    if (error != HA_ERR_END_OF_FILE)
    {
4852
      sql_print_error("ft_read_first: Got error %d when reading table %s",
unknown's avatar
unknown committed
4853
                      error, table->path);
unknown's avatar
unknown committed
4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870
      table->file->print_error(error,MYF(0));
      return 1;
    }
    return -1;
  }
  return 0;
}

static int
join_ft_read_next(READ_RECORD *info)
{
  int error=info->file->ft_read(info->table->record[0]);
  if (error)
  {
    if (error != HA_ERR_END_OF_FILE)
    {
      sql_print_error("ft_read_next: Got error %d when reading table %s",
unknown's avatar
unknown committed
4871
                      error, info->table->path);
unknown's avatar
unknown committed
4872 4873 4874 4875 4876 4877 4878 4879 4880 4881
      info->file->print_error(error,MYF(0));
      return 1;
    }
    return -1;
  }
  return 0;
}


/*****************************************************************************
4882 4883 4884
  The different end of select functions
  These functions returns < 0 when end is reached, 0 on ok and > 0 if a
  fatal error (like table corruption) was detected
unknown's avatar
unknown committed
4885 4886
*****************************************************************************/

4887
/* ARGSUSED */
unknown's avatar
unknown committed
4888 4889 4890 4891 4892 4893 4894 4895
static int
end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	 bool end_of_records)
{
  DBUG_ENTER("end_send");
  if (!end_of_records)
  {
    int error;
4896
    if (join->having && join->having->val_int() == 0)
unknown's avatar
unknown committed
4897
      DBUG_RETURN(0);				// Didn't match having
4898
    error=0;
unknown's avatar
unknown committed
4899 4900
    if (join->procedure)
      error=join->procedure->send_row(*join->fields);
4901
    else if (join->do_send_rows)
unknown's avatar
unknown committed
4902 4903 4904
      error=join->result->send_data(*join->fields);
    if (error)
      DBUG_RETURN(-1); /* purecov: inspected */
4905 4906 4907 4908
    if (++join->send_records >= join->thd->select_limit && join->do_send_rows)
    {
      if (join->select_options & OPTION_FOUND_ROWS)
      {
4909
	JOIN_TAB *jt=join->join_tab;
4910
	if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group
4911
	    && !join->send_group_parts && !join->having && !jt->select_cond &&
4912
	    !(jt->select && jt->select->quick) &&
4913
	    !(jt->table->file->table_flags() & HA_NOT_EXACT_COUNT))
4914
	{
4915
	  /* Join over all rows in table;  Return number of found rows */
4916 4917
	  TABLE *table=jt->table;

4918
	  join->select_options ^= OPTION_FOUND_ROWS;
4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929
	  if (table->record_pointers ||
	      (table->io_cache && my_b_inited(table->io_cache)))
	  {
	    /* Using filesort */
	    join->send_records= table->found_records;
	  }
	  else
	  {
	    table->file->info(HA_STATUS_VARIABLE);
	    join->send_records = table->file->records;
	  }
4930 4931 4932 4933 4934 4935 4936
	}
	else 
	{
	  join->do_send_rows=0;
	  join->thd->select_limit = HA_POS_ERROR;
	  DBUG_RETURN(0);
	}
4937
      }
unknown's avatar
unknown committed
4938
      DBUG_RETURN(-3);				// Abort nicely
4939
    }
unknown's avatar
unknown committed
4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966
  }
  else
  {
    if (join->procedure && join->procedure->end_of_records())
      DBUG_RETURN(-1);
  }
  DBUG_RETURN(0);
}


	/* ARGSUSED */
static int
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	       bool end_of_records)
{
  int idx= -1;
  DBUG_ENTER("end_send_group");

  if (!join->first_record || end_of_records ||
      (idx=test_if_group_changed(join->group_fields)) >= 0)
  {
    if (join->first_record || (end_of_records && !join->group))
    {
      if (join->procedure)
	join->procedure->end_group();
      if (idx < (int) join->send_group_parts)
      {
4967
	int error=0;
unknown's avatar
unknown committed
4968 4969
	if (join->procedure)
	{
4970
	  if (join->having && join->having->val_int() == 0)
unknown's avatar
unknown committed
4971
	    error= -1;				// Didn't satisfy having
4972
 	  else if (join->do_send_rows)
unknown's avatar
unknown committed
4973 4974 4975 4976 4977 4978 4979
	    error=join->procedure->send_row(*join->fields) ? 1 : 0;
	  if (end_of_records && join->procedure->end_of_records())
	    error= 1;				// Fatal error
	}
	else
	{
	  if (!join->first_record)
4980 4981
	  {
	    /* No matching rows for group function */
unknown's avatar
unknown committed
4982
	    clear_tables(join);
4983 4984
	    copy_fields(&join->tmp_table_param);
	  }
4985
	  if (join->having && join->having->val_int() == 0)
unknown's avatar
unknown committed
4986
	    error= -1;				// Didn't satisfy having
4987
	  else if (join->do_send_rows)
unknown's avatar
unknown committed
4988 4989 4990 4991
	    error=join->result->send_data(*join->fields) ? 1 : 0;
	}
	if (error > 0)
	  DBUG_RETURN(-1);			/* purecov: inspected */
4992 4993 4994 4995 4996
	if (end_of_records)
	{
	  join->send_records++;
	  DBUG_RETURN(0);
	}
4997 4998 4999 5000 5001 5002 5003 5004
	if (!error && ++join->send_records >= join->thd->select_limit &&
	    join->do_send_rows)
	{
	  if (!(join->select_options & OPTION_FOUND_ROWS))
	    DBUG_RETURN(-3);				// Abort nicely
	  join->do_send_rows=0;
	  join->thd->select_limit = HA_POS_ERROR;
        }
unknown's avatar
unknown committed
5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049
      }
    }
    else
    {
      if (end_of_records)
	DBUG_RETURN(0);
      join->first_record=1;
      VOID(test_if_group_changed(join->group_fields));
    }
    if (idx < (int) join->send_group_parts)
    {
      copy_fields(&join->tmp_table_param);
      init_sum_functions(join->sum_funcs);
      if (join->procedure)
	join->procedure->add();
      DBUG_RETURN(0);
    }
  }
  if (update_sum_func(join->sum_funcs))
    DBUG_RETURN(-1);
  if (join->procedure)
    join->procedure->add();
  DBUG_RETURN(0);
}


	/* ARGSUSED */
static int
end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	  bool end_of_records)
{
  TABLE *table=join->tmp_table;
  int error;
  DBUG_ENTER("end_write");

  if (join->thd->killed)			// Aborted by user
  {
    my_error(ER_SERVER_SHUTDOWN,MYF(0));	/* purecov: inspected */
    DBUG_RETURN(-2);				/* purecov: inspected */
  }
  if (!end_of_records)
  {
    copy_fields(&join->tmp_table_param);
    copy_funcs(join->tmp_table_param.funcs);

5050
#ifdef TO_BE_DELETED
unknown's avatar
unknown committed
5051 5052 5053 5054 5055 5056 5057 5058 5059 5060
    if (!table->uniques)			// If not unique handling
    {
      /* Copy null values from group to row */
      ORDER   *group;
      for (group=table->group ; group ; group=group->next)
      {
	Item *item= *group->item;
	if (item->maybe_null)
	{
	  Field *field=item->tmp_table_field();
5061
	  field->ptr[-1]= (byte) (field->is_null() ? 1 : 0);
unknown's avatar
unknown committed
5062 5063 5064
	}
      }
    }
5065
#endif
unknown's avatar
unknown committed
5066 5067
    if (!join->having || join->having->val_int())
    {
unknown's avatar
unknown committed
5068
      join->found_records++;
unknown's avatar
unknown committed
5069 5070
      if ((error=table->file->write_row(table->record[0])))
      {
unknown's avatar
unknown committed
5071 5072 5073 5074 5075 5076
	if (error == HA_ERR_FOUND_DUPP_KEY ||
	    error == HA_ERR_FOUND_DUPP_UNIQUE)
	  goto end;
	if (create_myisam_from_heap(table, &join->tmp_table_param, error,1))
	  DBUG_RETURN(1);			// Not a table_is_full error
	table->uniques=0;			// To ensure rows are the same
5077
      }
unknown's avatar
unknown committed
5078
      if (++join->send_records >= join->tmp_table_param.end_write_records &&
5079 5080 5081 5082 5083 5084 5085
	  join->do_send_rows)
      {
	if (!(join->select_options & OPTION_FOUND_ROWS))
	  DBUG_RETURN(-3);
	join->do_send_rows=0;
	join->thd->select_limit = HA_POS_ERROR;
	DBUG_RETURN(0);
unknown's avatar
unknown committed
5086 5087 5088
      }
    }
  }
unknown's avatar
unknown committed
5089
end:
unknown's avatar
unknown committed
5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112
  DBUG_RETURN(0);
}

/* Group by searching after group record and updating it if possible */
/* ARGSUSED */

static int
end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	   bool end_of_records)
{
  TABLE *table=join->tmp_table;
  ORDER   *group;
  int	  error;
  DBUG_ENTER("end_update");

  if (end_of_records)
    DBUG_RETURN(0);
  if (join->thd->killed)			// Aborted by user
  {
    my_error(ER_SERVER_SHUTDOWN,MYF(0));	/* purecov: inspected */
    DBUG_RETURN(-2);				/* purecov: inspected */
  }

unknown's avatar
unknown committed
5113
  join->found_records++;
unknown's avatar
unknown committed
5114 5115 5116 5117 5118 5119
  copy_fields(&join->tmp_table_param);		// Groups are copied twice.
  /* Make a key of group index */
  for (group=table->group ; group ; group=group->next)
  {
    Item *item= *group->item;
    item->save_org_in_field(group->field);
5120
    /* Store in the used key if the field was 0 */
unknown's avatar
unknown committed
5121
    if (item->maybe_null)
5122
      group->buff[-1]=item->null_value ? 1 : 0;
unknown's avatar
unknown committed
5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234
  }
  // table->file->index_init(0);
  if (!table->file->index_read(table->record[1],
			       join->tmp_table_param.group_buff,0,
			       HA_READ_KEY_EXACT))
  {						/* Update old record */
    restore_record(table,1);
    update_tmptable_sum_func(join->sum_funcs,table);
    if ((error=table->file->update_row(table->record[1],
				       table->record[0])))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(-1);				/* purecov: inspected */
    }
    DBUG_RETURN(0);
  }

  /* The null bits are already set */
  KEY_PART_INFO *key_part;
  for (group=table->group,key_part=table->key_info[0].key_part;
       group ;
       group=group->next,key_part++)
    memcpy(table->record[0]+key_part->offset, group->buff, key_part->length);

  init_tmptable_sum_functions(join->sum_funcs);
  copy_funcs(join->tmp_table_param.funcs);
  if ((error=table->file->write_row(table->record[0])))
  {
    if (create_myisam_from_heap(table, &join->tmp_table_param, error, 0))
      DBUG_RETURN(-1);				// Not a table_is_full error
    /* Change method to update rows */
    table->file->index_init(0);
    join->join_tab[join->tables-1].next_select=end_unique_update;
  }
  join->send_records++;
  DBUG_RETURN(0);
}

/* Like end_update, but this is done with unique constraints instead of keys */

static int
end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
		  bool end_of_records)
{
  TABLE *table=join->tmp_table;
  int	  error;
  DBUG_ENTER("end_unique_update");

  if (end_of_records)
    DBUG_RETURN(0);
  if (join->thd->killed)			// Aborted by user
  {
    my_error(ER_SERVER_SHUTDOWN,MYF(0));	/* purecov: inspected */
    DBUG_RETURN(-2);				/* purecov: inspected */
  }

  init_tmptable_sum_functions(join->sum_funcs);
  copy_fields(&join->tmp_table_param);		// Groups are copied twice.
  copy_funcs(join->tmp_table_param.funcs);

  if (!(error=table->file->write_row(table->record[0])))
    join->send_records++;			// New group
  else
  {
    if ((int) table->file->get_dup_key(error) < 0)
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(-1);				/* purecov: inspected */
    }
    if (table->file->rnd_pos(table->record[1],table->file->dupp_ref))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(-1);				/* purecov: inspected */
    }
    restore_record(table,1);
    update_tmptable_sum_func(join->sum_funcs,table);
    if ((error=table->file->update_row(table->record[1],
				       table->record[0])))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(-1);				/* purecov: inspected */
    }
  }
  DBUG_RETURN(0);
}


	/* ARGSUSED */
static int
end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
		bool end_of_records)
{
  TABLE *table=join->tmp_table;
  int	  error;
  int	  idx= -1;
  DBUG_ENTER("end_write_group");

  if (join->thd->killed)
  {						// Aborted by user
    my_error(ER_SERVER_SHUTDOWN,MYF(0));	/* purecov: inspected */
    DBUG_RETURN(-2);				/* purecov: inspected */
  }
  if (!join->first_record || end_of_records ||
      (idx=test_if_group_changed(join->group_fields)) >= 0)
  {
    if (join->first_record || (end_of_records && !join->group))
    {
      if (join->procedure)
	join->procedure->end_group();
      if (idx < (int) join->send_group_parts)
      {
	if (!join->first_record)
5235 5236
	{
	  /* No matching rows for group function */
unknown's avatar
unknown committed
5237
	  clear_tables(join);
5238 5239
	  copy_fields(&join->tmp_table_param);
	}
unknown's avatar
unknown committed
5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279
	copy_sum_funcs(join->sum_funcs);
	if (!join->having || join->having->val_int())
	{
	  if ((error=table->file->write_row(table->record[0])))
	  {
	    if (create_myisam_from_heap(table, &join->tmp_table_param,
					error, 0))
	      DBUG_RETURN(1);			// Not a table_is_full error
	  }
	  else
	    join->send_records++;
	}
	if (end_of_records)
	  DBUG_RETURN(0);
      }
    }
    else
    {
      join->first_record=1;
      VOID(test_if_group_changed(join->group_fields));
    }
    if (idx < (int) join->send_group_parts)
    {
      copy_fields(&join->tmp_table_param);
      copy_funcs(join->tmp_table_param.funcs);
      init_sum_functions(join->sum_funcs);
      if (join->procedure)
	join->procedure->add();
      DBUG_RETURN(0);
    }
  }
  if (update_sum_func(join->sum_funcs))
    DBUG_RETURN(-1);
  if (join->procedure)
    join->procedure->add();
  DBUG_RETURN(0);
}


/*****************************************************************************
5280 5281 5282 5283 5284
  Remove calculation with tables that aren't yet read. Remove also tests
  against fields that are read through key where the table is not a
  outer join table.
  We can't remove tests that are made against columns which are stored
  in sorted order.
unknown's avatar
unknown committed
5285 5286 5287 5288 5289 5290 5291
*****************************************************************************/

/* Return 1 if right_item is used removable reference key on left_item */

static bool test_if_ref(Item_field *left_item,Item *right_item)
{
  Field *field=left_item->field;
5292 5293
  // No need to change const test. We also have to keep tests on LEFT JOIN
  if (!field->table->const_table && !field->table->maybe_null)
unknown's avatar
unknown committed
5294 5295
  {
    Item *ref_item=part_of_refkey(field->table,field);
5296
    if (ref_item && ref_item->eq(right_item,1))
unknown's avatar
unknown committed
5297 5298
    {
      if (right_item->type() == Item::FIELD_ITEM)
5299 5300
	return (field->eq_def(((Item_field *) right_item)->field));
      if (right_item->const_item() && !(right_item->is_null()))
unknown's avatar
unknown committed
5301
      {
5302 5303 5304 5305
	/*
	  We can remove binary fields and numerical fields except float,
	  as float comparison isn't 100 % secure
	*/
unknown's avatar
unknown committed
5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368
	if (field->binary() &&
	    (field->type() != FIELD_TYPE_FLOAT || field->decimals() == 0))
	{
	  return !store_val_in_field(field,right_item);
	}
      }
    }
  }
  return 0;					// keep test
}


static COND *
make_cond_for_table(COND *cond,table_map tables,table_map used_table)
{
  if (used_table && !(cond->used_tables() & used_table))
    return (COND*) 0;				// Already checked
  if (cond->type() == Item::COND_ITEM)
  {
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      Item_cond_and *new_cond=new Item_cond_and;
      if (!new_cond)
	return (COND*) 0;			// OOM /* purecov: inspected */
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item=li++))
      {
	Item *fix=make_cond_for_table(item,tables,used_table);
	if (fix)
	  new_cond->argument_list()->push_back(fix);
      }
      switch (new_cond->argument_list()->elements) {
      case 0:
	return (COND*) 0;			// Always true
      case 1:
	return new_cond->argument_list()->head();
      default:
	new_cond->used_tables_cache=((Item_cond*) cond)->used_tables_cache &
	  tables;
	return new_cond;
      }
    }
    else
    {						// Or list
      Item_cond_or *new_cond=new Item_cond_or;
      if (!new_cond)
	return (COND*) 0;			// OOM /* purecov: inspected */
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item=li++))
      {
	Item *fix=make_cond_for_table(item,tables,0L);
	if (!fix)
	  return (COND*) 0;			// Always true
	new_cond->argument_list()->push_back(fix);
      }
      new_cond->used_tables_cache=((Item_cond_or*) cond)->used_tables_cache;
      return new_cond;
    }
  }

  /*
5369 5370 5371
    Because the following test takes a while and it can be done
    table_count times, we mark each item that we have examined with the result
    of the test
unknown's avatar
unknown committed
5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418
  */

  if (cond->marker == 3 || (cond->used_tables() & ~tables))
    return (COND*) 0;				// Can't check this yet
  if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK)
    return cond;				// Not boolean op

  if (((Item_func*) cond)->functype() == Item_func::EQ_FUNC)
  {
    Item *left_item=	((Item_func*) cond)->arguments()[0];
    Item *right_item= ((Item_func*) cond)->arguments()[1];
    if (left_item->type() == Item::FIELD_ITEM &&
	test_if_ref((Item_field*) left_item,right_item))
    {
      cond->marker=3;			// Checked when read
      return (COND*) 0;
    }
    if (right_item->type() == Item::FIELD_ITEM &&
	test_if_ref((Item_field*) right_item,left_item))
    {
      cond->marker=3;			// Checked when read
      return (COND*) 0;
    }
  }
  cond->marker=2;
  return cond;
}

static Item *
part_of_refkey(TABLE *table,Field *field)
{
  uint ref_parts=table->reginfo.join_tab->ref.key_parts;
  if (ref_parts)
  {
    KEY_PART_INFO *key_part=
      table->key_info[table->reginfo.join_tab->ref.key].key_part;

    for (uint part=0 ; part < ref_parts ; part++,key_part++)
      if (field->eq(key_part->field) &&
	  !(key_part->key_part_flag & HA_PART_KEY))
	return table->reginfo.join_tab->ref.items[part];
  }
  return (Item*) 0;
}


/*****************************************************************************
5419 5420 5421 5422 5423
  Test if one can use the key to resolve ORDER BY
  Returns: 1 if key is ok.
	   0 if key can't be used
	  -1 if reverse key can be used
          used_key_parts is set to key parts used if length != 0
unknown's avatar
unknown committed
5424 5425
*****************************************************************************/

unknown's avatar
unknown committed
5426 5427
static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
				uint *used_key_parts)
unknown's avatar
unknown committed
5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458
{
  KEY_PART_INFO *key_part,*key_part_end;
  key_part=table->key_info[idx].key_part;
  key_part_end=key_part+table->key_info[idx].key_parts;
  key_part_map const_key_parts=table->const_key_parts[idx];
  int reverse=0;

  for (; order ; order=order->next, const_key_parts>>=1)
  {
    Field *field=((Item_field*) (*order->item))->field;
    int flag;

    /*
      Skip key parts that are constants in the WHERE clause.
      These are already skipped in the ORDER BY by const_expression_in_where()
    */
    while (const_key_parts & 1)
    {
      key_part++; const_key_parts>>=1;
    }
    if (key_part == key_part_end || key_part->field != field)
      return 0;

    /* set flag to 1 if we can use read-next on key, else to -1 */
    flag=(order->asc == !(key_part->key_part_flag & HA_REVERSE_SORT))
      ? 1 : -1;
    if (reverse && flag != reverse)
      return 0;
    reverse=flag;				// Remember if reverse
    key_part++;
  }
unknown's avatar
unknown committed
5459
  *used_key_parts= (uint) (key_part - table->key_info[idx].key_part);
unknown's avatar
unknown committed
5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481
  return reverse;
}

static uint find_shortest_key(TABLE *table, key_map usable_keys)
{
  uint min_length= (uint) ~0;
  uint best= MAX_KEY;
  for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
  {
    if (usable_keys & 1)
    {
      if (table->key_info[nr].key_length < min_length)
      {
	min_length=table->key_info[nr].key_length;
	best=nr;
      }
    }
  }
  return best;
}


5482 5483 5484 5485 5486 5487 5488 5489 5490 5491
/*
  Test if we can skip the ORDER BY by using an index.

  If we can use an index, the JOIN_TAB / tab->select struct
  is changed to use the index.

  Return:
     0 We have to use filesort to do the sorting
     1 We can use an index.
*/
unknown's avatar
unknown committed
5492 5493

static bool
5494 5495
test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
			bool no_changes)
unknown's avatar
unknown committed
5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511
{
  int ref_key;
  TABLE *table=tab->table;
  SQL_SELECT *select=tab->select;
  key_map usable_keys;
  DBUG_ENTER("test_if_skip_sort_order");

  /* Check which keys can be used to resolve ORDER BY */
  usable_keys= ~(key_map) 0;
  for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
  {
    if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
    {
      usable_keys=0;
      break;
    }
5512
    usable_keys&=((Item_field*) (*tmp_order->item))->field->part_of_sortkey;
unknown's avatar
unknown committed
5513 5514 5515 5516 5517 5518 5519 5520 5521 5522
  }

  ref_key= -1;
  if (tab->ref.key >= 0)			// Constant range in WHERE
    ref_key=tab->ref.key;
  else if (select && select->quick)		// Range found by opt_range
    ref_key=select->quick->index;

  if (ref_key >= 0)
  {
5523 5524 5525
    /*
      We come here when there is a REF key.
    */
5526
    int order_direction;
unknown's avatar
unknown committed
5527
    uint used_key_parts;
unknown's avatar
unknown committed
5528 5529
    /* Check if we get the rows in requested sorted order by using the key */
    if ((usable_keys & ((key_map) 1 << ref_key)) &&
unknown's avatar
unknown committed
5530 5531
	(order_direction = test_if_order_by_key(order,table,ref_key,
						&used_key_parts)))
5532
    {
5533
      if (order_direction == -1)		// If ORDER BY ... DESC
5534
      {
unknown's avatar
unknown committed
5535 5536
	if (select && select->quick)
	{
5537 5538 5539 5540 5541
	  /*
	    Don't reverse the sort order, if it's already done.
	    (In some cases test_if_order_by_key() can be called multiple times
	  */
	  if (!select->quick->reverse_sorted())
unknown's avatar
unknown committed
5542
	  {
5543 5544 5545 5546 5547 5548 5549 5550 5551
	    // ORDER BY range_key DESC
	    QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
							 used_key_parts);
	    if (!tmp || tmp->error)
	    {
	      delete tmp;
	      DBUG_RETURN(0);		// Reverse sort not supported
	    }
	    select->quick=tmp;
unknown's avatar
unknown committed
5552 5553 5554 5555 5556 5557 5558
	  }
	  DBUG_RETURN(1);
	}
	if (tab->ref.key_parts < used_key_parts)
	{
	  /*
	    SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
5559 5560 5561

	    Use a traversal function that starts by reading the last row
	    with key part (A) and then traverse the index backwards.
unknown's avatar
unknown committed
5562
	  */
5563
	  if (table->file->table_flags() & HA_NOT_READ_PREFIX_LAST)
5564 5565 5566 5567
	    DBUG_RETURN(1);
	  tab->read_first_record=       join_read_last_key;
	  tab->read_record.read_record= join_read_prev_same;
	  /* fall through */
unknown's avatar
unknown committed
5568
	}
5569
      }
unknown's avatar
unknown committed
5570
      DBUG_RETURN(1);			/* No need to sort */
5571
    }
unknown's avatar
unknown committed
5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585
  }
  else
  {
    /* check if we can use a key to resolve the group */
    /* Tables using JT_NEXT are handled here */
    uint nr;
    key_map keys=usable_keys;

    /*
      If not used with LIMIT, only use keys if the whole query can be
      resolved with a key;  This is because filesort() is usually faster than
      retrieving all rows through an index.
    */
    if (select_limit >= table->file->records)
unknown's avatar
unknown committed
5586
      keys&= (table->used_keys | table->file->keys_to_use_for_scanning());
unknown's avatar
unknown committed
5587 5588 5589

    for (nr=0; keys ; keys>>=1, nr++)
    {
unknown's avatar
unknown committed
5590
      uint not_used;
unknown's avatar
unknown committed
5591 5592 5593
      if (keys & 1)
      {
	int flag;
unknown's avatar
unknown committed
5594
	if ((flag=test_if_order_by_key(order, table, nr, &not_used)))
unknown's avatar
unknown committed
5595
	{
5596 5597 5598
	  if (!no_changes)
	  {
	    tab->index=nr;
5599 5600
	    tab->read_first_record=  (flag > 0 ? join_read_first:
				      join_read_last);
5601 5602
	    table->file->index_init(nr);
	    tab->type=JT_NEXT;	// Read with index_first(), index_next()
unknown's avatar
unknown committed
5603 5604 5605 5606 5607
	    if (table->used_keys & ((key_map) 1 << nr))
	    {
	      table->key_read=1;
	      table->file->extra(HA_EXTRA_KEYREAD);
	    }
5608
	  }
unknown's avatar
unknown committed
5609 5610 5611 5612 5613 5614 5615 5616
	  DBUG_RETURN(1);
	}
      }
    }
  }
  DBUG_RETURN(0);				// Can't use index.
}

unknown's avatar
unknown committed
5617 5618 5619 5620 5621 5622 5623 5624

/*****************************************************************************
  If not selecting by given key, create an index how records should be read
  return: 0  ok
	  -1 some fatal error
	   1  no records
*****************************************************************************/

unknown's avatar
unknown committed
5625 5626 5627 5628 5629
static int
create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
{
  SORT_FIELD *sortorder;
  uint length;
5630
  ha_rows examined_rows;
unknown's avatar
unknown committed
5631 5632 5633 5634
  TABLE *table=tab->table;
  SQL_SELECT *select=tab->select;
  DBUG_ENTER("create_sort_index");

5635
  if (test_if_skip_sort_order(tab,order,select_limit,0))
unknown's avatar
unknown committed
5636 5637 5638 5639 5640
    DBUG_RETURN(0);
  if (!(sortorder=make_unireg_sortorder(order,&length)))
    goto err;				/* purecov: inspected */
  /* It's not fatal if the following alloc fails */
  table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
5641
					MYF(MY_WME | MY_ZEROFILL));
unknown's avatar
unknown committed
5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663
  table->status=0;				// May be wrong if quick_select

  // If table has a range, move it to select
  if (select && !select->quick && tab->ref.key >= 0)
  {
    if (tab->quick)
    {
      select->quick=tab->quick;
      tab->quick=0;
      /* We can only use 'Only index' if quick key is same as ref_key */
      if (table->key_read && (uint) tab->ref.key != select->quick->index)
      {
	table->key_read=0;
	table->file->extra(HA_EXTRA_NO_KEYREAD);
      }
    }
    else
    {
      /*
	We have a ref on a const;  Change this to a range that filesort
	can use.
      */
unknown's avatar
unknown committed
5664
      if (!(select->quick=get_ft_or_quick_select_for_ref(table, tab)))
unknown's avatar
unknown committed
5665 5666 5667
	goto err;
    }
  }
5668 5669 5670
  if (table->tmp_table)
    table->file->info(HA_STATUS_VARIABLE);	// Get record count
  table->found_records=filesort(table,sortorder,length,
5671
				select, 0L, select_limit, &examined_rows);
5672
  tab->records=table->found_records;		// For SQL_CALC_ROWS
unknown's avatar
unknown committed
5673 5674 5675 5676 5677
  delete select;				// filesort did select
  tab->select=0;
  tab->select_cond=0;
  tab->type=JT_ALL;				// Read with normal read_record
  tab->read_first_record= join_init_read_record;
5678
  tab->join->examined_rows+=examined_rows;
unknown's avatar
unknown committed
5679 5680 5681 5682 5683 5684 5685 5686 5687 5688
  if (table->key_read)				// Restore if we used indexes
  {
    table->key_read=0;
    table->file->extra(HA_EXTRA_NO_KEYREAD);
  }
  DBUG_RETURN(table->found_records == HA_POS_ERROR);
err:
  DBUG_RETURN(-1);
}

5689
/*
5690
  Add the HAVING criteria to table->select
5691 5692
*/

unknown's avatar
unknown committed
5693
#ifdef NOT_YET
5694 5695 5696 5697 5698 5699
static bool fix_having(JOIN *join, Item **having)
{
  (*having)->update_used_tables();	// Some tables may have been const
  JOIN_TAB *table=&join->join_tab[join->const_tables];
  table_map used_tables= join->const_table_map | table->table->map;

unknown's avatar
unknown committed
5700
  DBUG_EXECUTE("where",print_where(*having,"having"););
5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720
  Item* sort_table_cond=make_cond_for_table(*having,used_tables,used_tables);
  if (sort_table_cond)
  {
    if (!table->select)
      if (!(table->select=new SQL_SELECT))
	return 1;
    if (!table->select->cond)
      table->select->cond=sort_table_cond;
    else					// This should never happen
      if (!(table->select->cond=new Item_cond_and(table->select->cond,
						  sort_table_cond)))
	return 1;
    table->select_cond=table->select->cond;
    DBUG_EXECUTE("where",print_where(table->select_cond,
				     "select and having"););
    *having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
    DBUG_EXECUTE("where",print_where(*having,"having after make_cond"););
  }
  return 0;
}
unknown's avatar
unknown committed
5721
#endif
5722 5723


unknown's avatar
unknown committed
5724
/*****************************************************************************
5725 5726 5727 5728 5729
  Remove duplicates from tmp table
  This should be recoded to add a unique index to the table and remove
  duplicates
  Table is a locked single thread table
  fields is the number of fields to check (from the end)
unknown's avatar
unknown committed
5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
*****************************************************************************/

static bool compare_record(TABLE *table, Field **ptr)
{
  for (; *ptr ; ptr++)
  {
    if ((*ptr)->cmp_offset(table->rec_buff_length))
      return 1;
  }
  return 0;
}

static bool copy_blobs(Field **ptr)
{
  for (; *ptr ; ptr++)
  {
    if ((*ptr)->flags & BLOB_FLAG)
      if (((Field_blob *) (*ptr))->copy())
	return 1;				// Error
  }
  return 0;
}

static void free_blobs(Field **ptr)
{
  for (; *ptr ; ptr++)
  {
    if ((*ptr)->flags & BLOB_FLAG)
      ((Field_blob *) (*ptr))->free();
  }
}


static int
5764
remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
unknown's avatar
unknown committed
5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777
{
  int error;
  ulong reclength,offset;
  uint field_count;
  DBUG_ENTER("remove_duplicates");

  entry->reginfo.lock_type=TL_WRITE;

  /* Calculate how many saved fields there is in list */
  field_count=0;
  List_iterator<Item> it(fields);
  Item *item;
  while ((item=it++))
unknown's avatar
unknown committed
5778 5779
  {
    if (item->tmp_table_field() && ! item->const_item())
unknown's avatar
unknown committed
5780
      field_count++;
unknown's avatar
unknown committed
5781
  }
unknown's avatar
unknown committed
5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799

  if (!field_count)
  {						// only const items
    join->thd->select_limit=1;			// Only send first row
    DBUG_RETURN(0);
  }
  Field **first_field=entry->field+entry->fields - field_count;
  offset=entry->field[entry->fields - field_count]->offset();
  reclength=entry->reclength-offset;

  free_io_cache(entry);				// Safety
  entry->file->info(HA_STATUS_VARIABLE);
  if (entry->db_type == DB_TYPE_HEAP ||
      (!entry->blob_fields &&
       ((ALIGN_SIZE(reclength) +sizeof(HASH_LINK)) * entry->file->records <
	sortbuff_size)))
    error=remove_dup_with_hash_index(join->thd, entry,
				     field_count, first_field,
5800
				     reclength, having);
unknown's avatar
unknown committed
5801
  else
5802 5803
    error=remove_dup_with_compare(join->thd, entry, first_field, offset,
				  having);
unknown's avatar
unknown committed
5804 5805 5806 5807 5808 5809 5810

  free_blobs(first_field);
  DBUG_RETURN(error);
}


static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
5811
				   ulong offset, Item *having)
unknown's avatar
unknown committed
5812 5813 5814
{
  handler *file=table->file;
  char *org_record,*new_record;
unknown's avatar
unknown committed
5815
  byte *record;
unknown's avatar
unknown committed
5816 5817 5818 5819
  int error;
  ulong reclength=table->reclength-offset;
  DBUG_ENTER("remove_dup_with_compare");

5820
  org_record=(char*) (record=table->record[0])+offset;
unknown's avatar
unknown committed
5821 5822 5823
  new_record=(char*) table->record[1]+offset;

  file->rnd_init();
5824
  error=file->rnd_next(record);
unknown's avatar
unknown committed
5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840
  for (;;)
  {
    if (thd->killed)
    {
      my_error(ER_SERVER_SHUTDOWN,MYF(0));
      error=0;
      goto err;
    }
    if (error)
    {
      if (error == HA_ERR_RECORD_DELETED)
	continue;
      if (error == HA_ERR_END_OF_FILE)
	break;
      goto err;
    }
5841 5842 5843 5844
    if (having && !having->val_int())
    {
      if ((error=file->delete_row(record)))
	goto err;
5845
      error=file->rnd_next(record);
5846 5847
      continue;
    }
unknown's avatar
unknown committed
5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859
    if (copy_blobs(first_field))
    {
      my_error(ER_OUT_OF_SORTMEMORY,MYF(0));
      error=0;
      goto err;
    }
    memcpy(new_record,org_record,reclength);

    /* Read through rest of file and mark duplicated rows deleted */
    bool found=0;
    for (;;)
    {
5860
      if ((error=file->rnd_next(record)))
unknown's avatar
unknown committed
5861 5862 5863 5864 5865 5866 5867 5868 5869
      {
	if (error == HA_ERR_RECORD_DELETED)
	  continue;
	if (error == HA_ERR_END_OF_FILE)
	  break;
	goto err;
      }
      if (compare_record(table, first_field) == 0)
      {
5870
	if ((error=file->delete_row(record)))
unknown's avatar
unknown committed
5871 5872 5873 5874 5875
	  goto err;
      }
      else if (!found)
      {
	found=1;
5876
	file->position(record);	// Remember position
unknown's avatar
unknown committed
5877 5878 5879 5880 5881
      }
    }
    if (!found)
      break;					// End of file
    /* Restart search on next row */
5882
    error=file->restart_rnd_next(record,file->ref);
unknown's avatar
unknown committed
5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902
  }

  file->extra(HA_EXTRA_NO_CACHE);
  DBUG_RETURN(0);
err:
  file->extra(HA_EXTRA_NO_CACHE);
  if (error)
    file->print_error(error,MYF(0));
  DBUG_RETURN(1);
}


/*
  Generate a hash index for each row to quickly find duplicate rows
  Note that this will not work on tables with blobs!
*/

static int remove_dup_with_hash_index(THD *thd, TABLE *table,
				      uint field_count,
				      Field **first_field,
5903 5904
				      ulong key_length,
				      Item *having)
unknown's avatar
unknown committed
5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951
{
  byte *key_buffer, *key_pos, *record=table->record[0];
  int error;
  handler *file=table->file;
  ulong extra_length=ALIGN_SIZE(key_length)-key_length;
  uint *field_lengths,*field_length;
  HASH hash;
  DBUG_ENTER("remove_dup_with_hash_index");

  if (!my_multi_malloc(MYF(MY_WME),
		       &key_buffer,
		       (uint) ((key_length + extra_length) *
			       (long) file->records),
		       &field_lengths,
		       (uint) (field_count*sizeof(*field_lengths)),
		       NullS))
    DBUG_RETURN(1);
  if (hash_init(&hash, (uint) file->records, 0, key_length,
		(hash_get_key) 0, 0, 0))
  {
    my_free((char*) key_buffer,MYF(0));
    DBUG_RETURN(1);
  }
  {
    Field **ptr;
    for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
      (*field_length++)= (*ptr)->pack_length();
  }

  file->rnd_init();
  key_pos=key_buffer;
  for (;;)
  {
    if (thd->killed)
    {
      my_error(ER_SERVER_SHUTDOWN,MYF(0));
      error=0;
      goto err;
    }
    if ((error=file->rnd_next(record)))
    {
      if (error == HA_ERR_RECORD_DELETED)
	continue;
      if (error == HA_ERR_END_OF_FILE)
	break;
      goto err;
    }
5952 5953 5954 5955 5956
    if (having && !having->val_int())
    {
      if ((error=file->delete_row(record)))
	goto err;
      continue;
5957
    }
unknown's avatar
unknown committed
5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972

    /* copy fields to key buffer */
    field_length=field_lengths;
    for (Field **ptr= first_field ; *ptr ; ptr++)
    {
      (*ptr)->sort_string((char*) key_pos,*field_length);
      key_pos+= *field_length++;
    }
    /* Check if it exists before */
    if (hash_search(&hash,key_pos-key_length,key_length))
    {
      /* Duplicated found ; Remove the row */
      if ((error=file->delete_row(record)))
	goto err;
    }
5973 5974
    else
      (void) hash_insert(&hash, key_pos-key_length);
unknown's avatar
unknown committed
5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993
    key_pos+=extra_length;
  }
  my_free((char*) key_buffer,MYF(0));
  hash_free(&hash);
  file->extra(HA_EXTRA_NO_CACHE);
  (void) file->rnd_end();
  DBUG_RETURN(0);

err:
  my_free((char*) key_buffer,MYF(0));
  hash_free(&hash);
  file->extra(HA_EXTRA_NO_CACHE);
  (void) file->rnd_end();
  if (error)
    file->print_error(error,MYF(0));
  DBUG_RETURN(1);
}


unknown's avatar
unknown committed
5994
SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
unknown's avatar
unknown committed
5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028
{
  uint count;
  SORT_FIELD *sort,*pos;
  DBUG_ENTER("make_unireg_sortorder");

  count=0;
  for (ORDER *tmp = order; tmp; tmp=tmp->next)
    count++;
  pos=sort=(SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
  if (!pos)
    return 0;

  for (;order;order=order->next,pos++)
  {
    pos->field=0; pos->item=0;
    if (order->item[0]->type() == Item::FIELD_ITEM)
      pos->field= ((Item_field*) (*order->item))->field;
    else if (order->item[0]->type() == Item::SUM_FUNC_ITEM &&
	     !order->item[0]->const_item())
      pos->field= ((Item_sum*) order->item[0])->tmp_table_field();
    else if (order->item[0]->type() == Item::COPY_STR_ITEM)
    {						// Blob patch
      pos->item= ((Item_copy_string*) (*order->item))->item;
    }
    else
      pos->item= *order->item;
    pos->reverse=! order->asc;
  }
  *length=count;
  DBUG_RETURN(sort);
}


/*****************************************************************************
6029 6030 6031 6032
  Fill join cache with packed records
  Records are stored in tab->cache.buffer and last record in
  last record is stored with pointers to blobs to support very big
  records
unknown's avatar
unknown committed
6033 6034 6035 6036 6037 6038 6039 6040 6041
******************************************************************************/

static int
join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{
  reg1 uint i;
  uint length,blobs,size;
  CACHE_FIELD *copy,**blob_ptr;
  JOIN_CACHE  *cache;
6042
  JOIN_TAB *join_tab;
unknown's avatar
unknown committed
6043 6044 6045 6046 6047
  DBUG_ENTER("join_init_cache");

  cache= &tables[table_count].cache;
  cache->fields=blobs=0;

6048 6049
  join_tab=tables;
  for (i=0 ; i < table_count ; i++,join_tab++)
unknown's avatar
unknown committed
6050
  {
6051 6052 6053 6054
    if (!join_tab->used_fieldlength)		/* Not calced yet */
      calc_used_field_length(thd, join_tab);
    cache->fields+=join_tab->used_fields;
    blobs+=join_tab->used_blobs;
unknown's avatar
unknown committed
6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093
  }
  if (!(cache->field=(CACHE_FIELD*)
	sql_alloc(sizeof(CACHE_FIELD)*(cache->fields+table_count*2)+(blobs+1)*
		  sizeof(CACHE_FIELD*))))
  {
    my_free((gptr) cache->buff,MYF(0));		/* purecov: inspected */
    cache->buff=0;				/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  copy=cache->field;
  blob_ptr=cache->blob_ptr=(CACHE_FIELD**)
    (cache->field+cache->fields+table_count*2);

  length=0;
  for (i=0 ; i < table_count ; i++)
  {
    uint null_fields=0,used_fields;

    Field **f_ptr,*field;
    for (f_ptr=tables[i].table->field,used_fields=tables[i].used_fields ;
	 used_fields ;
	 f_ptr++)
    {
      field= *f_ptr;
      if (field->query_id == thd->query_id)
      {
	used_fields--;
	length+=field->fill_cache_field(copy);
	if (copy->blob_field)
	  (*blob_ptr++)=copy;
	if (field->maybe_null())
	  null_fields++;
	copy++;
      }
    }
    /* Copy null bits from table */
    if (null_fields && tables[i].table->null_fields)
    {						/* must copy null bits */
      copy->str=(char*) tables[i].table->null_flags;
6094
      copy->length=tables[i].table->null_bytes;
unknown's avatar
unknown committed
6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158
      copy->strip=0;
      copy->blob_field=0;
      length+=copy->length;
      copy++;
      cache->fields++;
    }
    /* If outer join table, copy null_row flag */
    if (tables[i].table->maybe_null)
    {
      copy->str= (char*) &tables[i].table->null_row;
      copy->length=sizeof(tables[i].table->null_row);
      copy->strip=0;
      copy->blob_field=0;
      length+=copy->length;
      copy++;
      cache->fields++;
    }
  }

  cache->records=0; cache->ptr_record= (uint) ~0;
  cache->length=length+blobs*sizeof(char*);
  cache->blobs=blobs;
  *blob_ptr=0;					/* End sequentel */
  size=max(join_buff_size,cache->length);
  if (!(cache->buff=(uchar*) my_malloc(size,MYF(0))))
    DBUG_RETURN(1);				/* Don't use cache */ /* purecov: inspected */
  cache->end=cache->buff+size;
  reset_cache(cache);
  DBUG_RETURN(0);
}


static ulong
used_blob_length(CACHE_FIELD **ptr)
{
  uint length,blob_length;
  for (length=0 ; *ptr ; ptr++)
  {
    (*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length();
    length+=blob_length;
    (*ptr)->blob_field->get_ptr(&(*ptr)->str);
  }
  return length;
}


static bool
store_record_in_cache(JOIN_CACHE *cache)
{
  ulong length;
  uchar *pos;
  CACHE_FIELD *copy,*end_field;
  bool last_record;

  pos=cache->pos;
  end_field=cache->field+cache->fields;

  length=cache->length;
  if (cache->blobs)
    length+=used_blob_length(cache->blob_ptr);
  if ((last_record=(length+cache->length > (uint) (cache->end - pos))))
    cache->ptr_record=cache->records;

  /*
6159
    There is room in cache. Put record there
unknown's avatar
unknown committed
6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284
  */
  cache->records++;
  for (copy=cache->field ; copy < end_field; copy++)
  {
    if (copy->blob_field)
    {
      if (last_record)
      {
	copy->blob_field->get_image((char*) pos,copy->length+sizeof(char*));
	pos+=copy->length+sizeof(char*);
      }
      else
      {
	copy->blob_field->get_image((char*) pos,copy->length); // blob length
	memcpy(pos+copy->length,copy->str,copy->blob_length);  // Blob data
	pos+=copy->length+copy->blob_length;
      }
    }
    else
    {
      if (copy->strip)
      {
	char *str,*end;
	for (str=copy->str,end= str+copy->length;
	     end > str && end[-1] == ' ' ;
	     end--) ;
	length=(uint) (end-str);
	memcpy(pos+1,str,length);
	*pos=(uchar) length;
	pos+=length+1;
      }
      else
      {
	memcpy(pos,copy->str,copy->length);
	pos+=copy->length;
      }
    }
  }
  cache->pos=pos;
  return last_record || (uint) (cache->end -pos) < cache->length;
}


static void
reset_cache(JOIN_CACHE *cache)
{
  cache->record_nr=0;
  cache->pos=cache->buff;
}


static void
read_cached_record(JOIN_TAB *tab)
{
  uchar *pos;
  uint length;
  bool last_record;
  CACHE_FIELD *copy,*end_field;

  last_record=tab->cache.record_nr++ == tab->cache.ptr_record;
  pos=tab->cache.pos;

  for (copy=tab->cache.field,end_field=copy+tab->cache.fields ;
       copy < end_field;
       copy++)
  {
    if (copy->blob_field)
    {
      if (last_record)
      {
	copy->blob_field->set_image((char*) pos,copy->length+sizeof(char*));
	pos+=copy->length+sizeof(char*);
      }
      else
      {
	copy->blob_field->set_ptr((char*) pos,(char*) pos+copy->length);
	pos+=copy->length+copy->blob_field->get_length();
      }
    }
    else
    {
      if (copy->strip)
      {
	memcpy(copy->str,pos+1,length=(uint) *pos);
	memset(copy->str+length,' ',copy->length-length);
	pos+=1+length;
      }
      else
      {
	memcpy(copy->str,pos,copy->length);
	pos+=copy->length;
      }
    }
  }
  tab->cache.pos=pos;
  return;
}


static bool
cmp_buffer_with_ref(JOIN_TAB *tab)
{
  bool diff;
  if (!(diff=tab->ref.key_err))
  {
    memcpy(tab->ref.key_buff2, tab->ref.key_buff, tab->ref.key_length);
  }
  if ((tab->ref.key_err=cp_buffer_from_ref(&tab->ref)) || diff)
    return 1;
  return memcmp(tab->ref.key_buff2, tab->ref.key_buff, tab->ref.key_length)
    != 0;
}


bool
cp_buffer_from_ref(TABLE_REF *ref)
{
  for (store_key **copy=ref->key_copy ; *copy ; copy++)
    if ((*copy)->copy())
      return 1;					// Something went wrong
  return 0;
}


/*****************************************************************************
6285
  Group and order functions
unknown's avatar
unknown committed
6286 6287 6288
*****************************************************************************/

/*
6289 6290 6291
  Find order/group item in requested columns and change the item to point at
  it. If item doesn't exists, add it first in the field list
  Return 0 if ok.
unknown's avatar
unknown committed
6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335
*/

static int
find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
		   List<Item> &all_fields)
{
  if ((*order->item)->type() == Item::INT_ITEM)
  {						/* Order by position */
    Item *item=0;
    List_iterator<Item> li(fields);

    for (uint count= (uint) ((Item_int*) (*order->item))->value ;
	 count-- && (item=li++) ;) ;
    if (!item)
    {
      my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
		      MYF(0),(*order->item)->full_name(),
	       thd->where);
      return 1;
    }
    order->item=li.ref();
    order->in_field_list=1;
    return 0;
  }
  const char *save_where=thd->where;
  thd->where=0;					// No error if not found
  Item **item=find_item_in_list(*order->item,fields);
  thd->where=save_where;
  if (item)
  {
    order->item=item;				// use it
    order->in_field_list=1;
    return 0;
  }
  order->in_field_list=0;
  if ((*order->item)->fix_fields(thd,tables) || thd->fatal_error)
    return 1;					// Wrong field
  all_fields.push_front(*order->item);		// Add new field to field list
  order->item=(Item**) all_fields.head_ref();
  return 0;
}


/*
6336 6337
  Change order to point at item in select list. If item isn't a number
  and doesn't exits in the select list, add it the the field list.
unknown's avatar
unknown committed
6338 6339
*/

unknown's avatar
unknown committed
6340
int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields,
unknown's avatar
unknown committed
6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360
	     List<Item> &all_fields, ORDER *order)
{
  thd->where="order clause";
  for (; order; order=order->next)
  {
    if (find_order_in_list(thd,tables,order,fields,all_fields))
      return 1;
  }
  return 0;
}


static int
setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
	    List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
{
  *hidden_group_fields=0;
  if (!order)
    return 0;				/* Everything is ok */

6361
  if (thd->sql_mode & MODE_ONLY_FULL_GROUP_BY)
unknown's avatar
unknown committed
6362 6363 6364 6365 6366 6367 6368 6369 6370
  {
    Item *item;
    List_iterator<Item> li(fields);
    while ((item=li++))
      item->marker=0;			/* Marker that field is not used */
  }
  uint org_fields=all_fields.elements;

  thd->where="group statement";
6371
  for (; order; order=order->next)
unknown's avatar
unknown committed
6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382
  {
    if (find_order_in_list(thd,tables,order,fields,all_fields))
      return 1;
    (*order->item)->marker=1;		/* Mark found */
    if ((*order->item)->with_sum_func)
    {
      my_printf_error(ER_WRONG_GROUP_FIELD, ER(ER_WRONG_GROUP_FIELD),MYF(0),
		      (*order->item)->full_name());
      return 1;
    }
  }
6383
  if (thd->sql_mode & MODE_ONLY_FULL_GROUP_BY)
unknown's avatar
unknown committed
6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405
  {
    /* Don't allow one to use fields that is not used in GROUP BY */
    Item *item;
    List_iterator<Item> li(fields);

    while ((item=li++))
    {
      if (item->type() != Item::SUM_FUNC_ITEM && !item->marker)
      {
	my_printf_error(ER_WRONG_FIELD_WITH_GROUP,
			ER(ER_WRONG_FIELD_WITH_GROUP),
			MYF(0),item->full_name());
	return 1;
      }
    }
  }
  if (org_fields != all_fields.elements)
    *hidden_group_fields=1;			// group fields is not used
  return 0;
}

/*
6406
  Add fields with aren't used at start of field list. Return FALSE if ok
unknown's avatar
unknown committed
6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417
*/

static bool
setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
		 List<Item> &all_fields, ORDER *new_field)
{
  Item	  **item;
  DBUG_ENTER("setup_new_fields");

  thd->set_query_id=1;				// Not really needed, but...
  thd->where=0;					// Don't give error
6418
  for (; new_field ; new_field=new_field->next)
unknown's avatar
unknown committed
6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435
  {
    if ((item=find_item_in_list(*new_field->item,fields)))
      new_field->item=item;			/* Change to shared Item */
    else
    {
      thd->where="procedure list";
      if ((*new_field->item)->fix_fields(thd,tables))
	DBUG_RETURN(1); /* purecov: inspected */
      thd->where=0;
      all_fields.push_front(*new_field->item);
      new_field->item=all_fields.head_ref();
    }
  }
  DBUG_RETURN(0);
}

/*
6436 6437 6438
  Create a group by that consist of all non const fields. Try to use
  the fields in the order given by 'order' to allow one to optimize
  away 'order by'.
unknown's avatar
unknown committed
6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486
*/

static ORDER *
create_distinct_group(ORDER *order_list,List<Item> &fields)
{
  List_iterator<Item> li(fields);
  Item *item;
  ORDER *order,*group,**prev;

  while ((item=li++))
    item->marker=0;			/* Marker that field is not used */

  prev= &group;  group=0;
  for (order=order_list ; order; order=order->next)
  {
    if (order->in_field_list)
    {
      ORDER *ord=(ORDER*) sql_memdup(order,sizeof(ORDER));
      if (!ord)
	return 0;
      *prev=ord;
      prev= &ord->next;
      (*ord->item)->marker=1;
    }
  }

  li.rewind();
  while ((item=li++))
  {
    if (item->const_item() || item->with_sum_func)
      continue;
    if (!item->marker)
    {
      ORDER *ord=(ORDER*) sql_calloc(sizeof(ORDER));
      if (!ord)
	return 0;
      ord->item=li.ref();
      ord->asc=1;
      *prev=ord;
      prev= &ord->next;
    }
  }
  *prev=0;
  return group;
}


/*****************************************************************************
6487
  Update join with count of the different type of fields
unknown's avatar
unknown committed
6488 6489 6490
*****************************************************************************/

void
unknown's avatar
unknown committed
6491 6492
count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
		  bool reset_with_sum_func)
unknown's avatar
unknown committed
6493 6494 6495 6496
{
  List_iterator<Item> li(fields);
  Item *field;

6497
  param->field_count=param->sum_func_count=param->func_count=
unknown's avatar
unknown committed
6498
    param->hidden_field_count=0;
unknown's avatar
unknown committed
6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523
  param->quick_group=1;
  while ((field=li++))
  {
    Item::Type type=field->type();
    if (type == Item::FIELD_ITEM)
      param->field_count++;
    else if (type == Item::SUM_FUNC_ITEM)
    {
      if (! field->const_item())
      {
	Item_sum *sum_item=(Item_sum*) field;
	if (!sum_item->quick_group)
	  param->quick_group=0;			// UDF SUM function
	param->sum_func_count++;

	for (uint i=0 ; i < sum_item->arg_count ; i++)
	{
	  if (sum_item->args[0]->type() == Item::FIELD_ITEM)
	    param->field_count++;
	  else
	    param->func_count++;
	}
      }
    }
    else
unknown's avatar
unknown committed
6524
    {
unknown's avatar
unknown committed
6525
      param->func_count++;
unknown's avatar
unknown committed
6526 6527 6528
      if (reset_with_sum_func)
	field->with_sum_func=0;
    }
unknown's avatar
unknown committed
6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543
  }
}


/*
  Return 1 if second is a subpart of first argument
  If first parts has different direction, change it to second part
  (group is sorted like order)
*/

static bool
test_if_subpart(ORDER *a,ORDER *b)
{
  for (; a && b; a=a->next,b=b->next)
  {
6544
    if ((*a->item)->eq(*b->item,1))
unknown's avatar
unknown committed
6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570
      a->asc=b->asc;
    else
      return 0;
  }
  return test(!b);
}

/*
  Return table number if there is only one table in sort order
  and group and order is compatible
  else return 0;
*/

static TABLE *
get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
{
  table_map map= (table_map) 0;
  DBUG_ENTER("get_sort_by_table");

  if (!a)
    a=b;					// Only one need to be given
  else if (!b)
    b=a;

  for (; a && b; a=a->next,b=b->next)
  {
6571
    if (!(*a->item)->eq(*b->item,1))
unknown's avatar
unknown committed
6572 6573 6574 6575 6576 6577
      DBUG_RETURN(0);
    map|=a->item[0]->used_tables();
  }
  if (!map || (map & RAND_TABLE_BIT))
    DBUG_RETURN(0);

6578
  for (; !(map & tables->table->map) ; tables=tables->next) ;
unknown's avatar
unknown committed
6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590
  if (map != tables->table->map)
    DBUG_RETURN(0);				// More than one table
  DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
  DBUG_RETURN(tables->table);
}


	/* calc how big buffer we need for comparing group entries */

static void
calc_group_buffer(JOIN *join,ORDER *group)
{
6591 6592
  uint key_length=0, parts=0, null_parts=0;

unknown's avatar
unknown committed
6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612
  if (group)
    join->group= 1;
  for (; group ; group=group->next)
  {
    Field *field=(*group->item)->tmp_table_field();
    if (field)
    {
      if (field->type() == FIELD_TYPE_BLOB)
	key_length+=MAX_BLOB_WIDTH;		// Can't be used as a key
      else
	key_length+=field->pack_length();
    }
    else if ((*group->item)->result_type() == REAL_RESULT)
      key_length+=sizeof(double);
    else if ((*group->item)->result_type() == INT_RESULT)
      key_length+=sizeof(longlong);
    else
      key_length+=(*group->item)->max_length;
    parts++;
    if ((*group->item)->maybe_null)
6613
      null_parts++;
unknown's avatar
unknown committed
6614
  }
6615
  join->tmp_table_param.group_length=key_length+null_parts;
unknown's avatar
unknown committed
6616
  join->tmp_table_param.group_parts=parts;
6617
  join->tmp_table_param.group_null_parts=null_parts;
unknown's avatar
unknown committed
6618 6619 6620 6621
}


/*
6622 6623
  Get a list of buffers for saveing last group
  Groups are saved in reverse order for easyer check loop
unknown's avatar
unknown committed
6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660
*/

static bool
alloc_group_fields(JOIN *join,ORDER *group)
{
  if (group)
  {
    for (; group ; group=group->next)
    {
      Item_buff *tmp=new_Item_buff(*group->item);
      if (!tmp || join->group_fields.push_front(tmp))
	return TRUE;
    }
  }
  join->sort_and_group=1;			/* Mark for do_select */
  return FALSE;
}


static int
test_if_group_changed(List<Item_buff> &list)
{
  List_iterator<Item_buff> li(list);
  int idx= -1,i;
  Item_buff *buff;

  for (i=(int) list.elements-1 ; (buff=li++) ; i--)
  {
    if (buff->cmp())
      idx=i;
  }
  return idx;
}



/*
6661 6662 6663 6664
  Setup copy_fields to save fields at start of new group
  Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups.
  Change old item_field to use a new field with points at saved fieldvalue
  This function is only called before use of send_fields
unknown's avatar
unknown committed
6665 6666 6667
*/

bool
unknown's avatar
unknown committed
6668
setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
unknown's avatar
unknown committed
6669 6670 6671 6672 6673 6674 6675
{
  Item *pos;
  List_iterator<Item> li(fields);
  Copy_field *copy;
  DBUG_ENTER("setup_copy_fields");

  if (!(copy=param->copy_field= new Copy_field[param->field_count]))
6676
    goto err2;
unknown's avatar
unknown committed
6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695

  param->copy_funcs.empty();
  while ((pos=li++))
  {
    if (pos->type() == Item::FIELD_ITEM)
    {
      Item_field *item=(Item_field*) pos;
      if (item->field->flags & BLOB_FLAG)
      {
	if (!(pos=new Item_copy_string(pos)))
	  goto err;
	VOID(li.replace(pos));
	if (param->copy_funcs.push_back(pos))
	  goto err;
	continue;
      }

      /* set up save buffer and change result_field to point at saved value */
      Field *field= item->field;
unknown's avatar
unknown committed
6696
      item->result_field=field->new_field(&thd->mem_root,field->table);
unknown's avatar
unknown committed
6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720
      char *tmp=(char*) sql_alloc(field->pack_length()+1);
      if (!tmp)
	goto err;
      copy->set(tmp, item->result_field);
      item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
      copy++;
    }
    else if ((pos->type() == Item::FUNC_ITEM ||
	      pos->type() == Item::COND_ITEM) &&
	     !pos->with_sum_func)
    {						// Save for send fields
      /* TODO:
	 In most cases this result will be sent to the user.
	 This should be changed to use copy_int or copy_real depending
	 on how the value is to be used: In some cases this may be an
	 argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
      */
      if (!(pos=new Item_copy_string(pos)))
	goto err;
      VOID(li.replace(pos));
      if (param->copy_funcs.push_back(pos))
	goto err;
    }
  }
unknown's avatar
unknown committed
6721
  param->copy_field_end= copy;
unknown's avatar
unknown committed
6722 6723 6724
  DBUG_RETURN(0);

 err:
6725
  delete [] param->copy_field;			// This is never 0
unknown's avatar
unknown committed
6726
  param->copy_field=0;
6727
err2:
unknown's avatar
unknown committed
6728 6729 6730 6731 6732
  DBUG_RETURN(TRUE);
}


/*
6733
  Copy fields and null values between two tables
unknown's avatar
unknown committed
6734 6735 6736 6737 6738 6739
*/

void
copy_fields(TMP_TABLE_PARAM *param)
{
  Copy_field *ptr=param->copy_field;
unknown's avatar
unknown committed
6740
  Copy_field *end=param->copy_field_end;
unknown's avatar
unknown committed
6741

6742
  for (; ptr != end; ptr++)
unknown's avatar
unknown committed
6743 6744
    (*ptr->do_copy)(ptr);

unknown's avatar
unknown committed
6745 6746
  List_iterator_fast<Item> &it=param->copy_funcs_it;
  it.rewind();
unknown's avatar
unknown committed
6747 6748 6749 6750 6751 6752 6753
  Item_copy_string *item;
  while ((item = (Item_copy_string*) it++))
    item->copy();
}


/*****************************************************************************
6754
  Make an array of pointer to sum_functions to speed up sum_func calculation
unknown's avatar
unknown committed
6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785
*****************************************************************************/

static bool
make_sum_func_list(JOIN *join,List<Item> &fields)
{
  DBUG_ENTER("make_sum_func_list");
  Item_sum **func =
    (Item_sum**) sql_alloc(sizeof(Item_sum*)*
			   (join->tmp_table_param.sum_func_count+1));
  if (!func)
    DBUG_RETURN(TRUE);
  List_iterator<Item> it(fields);
  join->sum_funcs=func;

  Item *field;
  while ((field=it++))
  {
    if (field->type() == Item::SUM_FUNC_ITEM && !field->const_item())
    {
      *func++=(Item_sum*) field;
      /* let COUNT(DISTINCT) create the temporary table */
      if (((Item_sum*) field)->setup(join->thd))
	DBUG_RETURN(TRUE);
    }
  }
  *func=0;					// End marker
  DBUG_RETURN(FALSE);
}


/*
6786
  Change all funcs and sum_funcs to fields in tmp table
unknown's avatar
unknown committed
6787 6788 6789
*/

static bool
6790
change_to_use_tmp_fields(List<Item> &items)
unknown's avatar
unknown committed
6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835
{
  List_iterator<Item> it(items);
  Item *item_field,*item;

  while ((item=it++))
  {
    Field *field;
    if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
      continue;
    if (item->type() == Item::FIELD_ITEM)
    {
      ((Item_field*) item)->field=
	((Item_field*) item)->result_field;
    }
    else if ((field=item->tmp_table_field()))
    {
      if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
	item_field=((Item_sum*) item)->result_item(field);
      else
	item_field=(Item*) new Item_field(field);
      if (!item_field)
	return TRUE;				// Fatal error
      item_field->name=item->name;		/*lint -e613 */
#ifndef DBUG_OFF
      if (_db_on_ && !item_field->name)
      {
	char buff[256];
	String str(buff,sizeof(buff));
	str.length(0);
	item->print(&str);
	item_field->name=sql_strmake(str.ptr(),str.length());
      }
#endif
#ifdef DELETE_ITEMS
      delete it.replace(item_field);		/*lint -e613 */
#else
      (void) it.replace(item_field);		/*lint -e613 */
#endif
    }
  }
  return FALSE;
}


/*
6836 6837
  Change all sum_func refs to fields to point at fields in tmp table
  Change all funcs to be fields in tmp table
unknown's avatar
unknown committed
6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892
*/

static bool
change_refs_to_tmp_fields(THD *thd,List<Item> &items)
{
  List_iterator<Item> it(items);
  Item *item;

  while ((item= it++))
  {
    if (item->type() == Item::SUM_FUNC_ITEM)
    {
      if (!item->const_item())
      {
	Item_sum *sum_item= (Item_sum*) item;
	if (sum_item->result_field)		// If not a const sum func
	{
	  Field *result_field=sum_item->result_field;
	  for (uint i=0 ; i < sum_item->arg_count ; i++)
	  {
	    Item *arg= sum_item->args[i];
	    if (!arg->const_item())
	    {
	      if (arg->type() == Item::FIELD_ITEM)
		((Item_field*) arg)->field= result_field++;
	      else
		sum_item->args[i]= new Item_field(result_field++);
	    }
	  }
	}
      }
    }
    else if (item->with_sum_func)
      continue;
    else if ((item->type() == Item::FUNC_ITEM ||
	      item->type() == Item::COND_ITEM) &&
	     !item->const_item())
    {						/* All funcs are stored */
#ifdef DELETE_ITEMS
      delete it.replace(new Item_field(((Item_func*) item)->result_field));
#else
      (void) it.replace(new Item_field(((Item_func*) item)->result_field));
#endif
    }
    else if (item->type() == Item::FIELD_ITEM)	/* Change refs */
    {
      ((Item_field*)item)->field=((Item_field*) item)->result_field;
    }
  }
  return thd->fatal_error;
}



/******************************************************************************
6893
  Code for calculating functions
unknown's avatar
unknown committed
6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960
******************************************************************************/

static void
init_tmptable_sum_functions(Item_sum **func_ptr)
{
  Item_sum *func;
  while ((func= *(func_ptr++)))
    func->reset_field();
}


	/* Update record 0 in tmp_table from record 1 */

static void
update_tmptable_sum_func(Item_sum **func_ptr,
			 TABLE *tmp_table __attribute__((unused)))
{
  Item_sum *func;
  while ((func= *(func_ptr++)))
    func->update_field(0);
}


	/* Copy result of sum functions to record in tmp_table */

static void
copy_sum_funcs(Item_sum **func_ptr)
{
  Item_sum *func;
  for (; (func = *func_ptr) ; func_ptr++)
    (void) func->save_in_field(func->result_field);
  return;
}


static void
init_sum_functions(Item_sum **func_ptr)
{
  Item_sum *func;
  for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
    func->reset();
}


static bool
update_sum_func(Item_sum **func_ptr)
{
  Item_sum *func;
  for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
    if (func->add())
      return 1;
  return 0;
}

	/* Copy result of functions to record in tmp_table */

void
copy_funcs(Item_result_field **func_ptr)
{
  Item_result_field *func;
  for (; (func = *func_ptr) ; func_ptr++)
    (void) func->save_in_field(func->result_field);
  return;
}


/*****************************************************************************
6961 6962
  Create a condition for a const reference and add this to the
  currenct select for the table
unknown's avatar
unknown committed
6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984
*****************************************************************************/

static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
{
  DBUG_ENTER("add_ref_to_table_cond");
  if (!join_tab->ref.key_parts)
    DBUG_RETURN(FALSE);

  Item_cond_and *cond=new Item_cond_and();
  TABLE *table=join_tab->table;
  int error;
  if (!cond)
    DBUG_RETURN(TRUE);

  for (uint i=0 ; i < join_tab->ref.key_parts ; i++)
  {
    Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].fieldnr-1];
    Item *value=join_tab->ref.items[i];
    cond->add(new Item_func_equal(new Item_field(field),value));
  }
  if (thd->fatal_error)
    DBUG_RETURN(TRUE);
6985 6986 6987 6988 6989

  /*
    Here we pass 0 as the first argument to fix_fields that don't need
    to do any stack checking (This is already done in the initial fix_fields).
  */
unknown's avatar
unknown committed
6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002
  cond->fix_fields((THD *) 0,(TABLE_LIST *) 0);
  if (join_tab->select)
  {
    error=(int) cond->add(join_tab->select->cond);
    join_tab->select_cond=join_tab->select->cond=cond;
  }
  else if ((join_tab->select=make_select(join_tab->table, 0, 0, cond,&error)))
    join_tab->select_cond=cond;

  DBUG_RETURN(error ? TRUE : FALSE);
}

/****************************************************************************
7003
  Send a description about what how the select will be done to stdout
unknown's avatar
unknown committed
7004 7005
****************************************************************************/

unknown's avatar
unknown committed
7006
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
unknown's avatar
unknown committed
7007
			    bool distinct,const char *message)
unknown's avatar
unknown committed
7008 7009 7010
{
  List<Item> field_list;
  Item *item;
7011
  List<Item> item_list;
unknown's avatar
unknown committed
7012
  THD *thd=join->thd;
7013
  MYSQL_LOCK *save_lock;
unknown's avatar
unknown committed
7014
  SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
7015
  select_result *result=join->result;
unknown's avatar
unknown committed
7016
  DBUG_ENTER("select_describe");
unknown's avatar
unknown committed
7017

7018
  /* Don't log this into the slow query log */
unknown's avatar
unknown committed
7019
  select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
7020
  thd->offset_limit=0;
7021
  if (thd->lex.select == select_lex)
unknown's avatar
unknown committed
7022 7023 7024 7025
  {
    field_list.push_back(new Item_empty_string("table",NAME_LEN));
    field_list.push_back(new Item_empty_string("type",10));
    field_list.push_back(item=new Item_empty_string("possible_keys",
unknown's avatar
unknown committed
7026
						  NAME_LEN*MAX_KEY));
unknown's avatar
unknown committed
7027 7028 7029 7030 7031 7032 7033 7034 7035 7036
    item->maybe_null=1;
    field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
    item->maybe_null=1;
    field_list.push_back(item=new Item_int("key_len",0,3));
    item->maybe_null=1;
    field_list.push_back(item=new Item_empty_string("ref",
						    NAME_LEN*MAX_REF_PARTS));
    item->maybe_null=1;
    field_list.push_back(new Item_real("rows",0.0,0,10));
    field_list.push_back(new Item_empty_string("Extra",255));
7037
    if (result->send_fields(field_list,1))
unknown's avatar
unknown committed
7038 7039
      return;
  }
7040

unknown's avatar
unknown committed
7041
  if (message)
unknown's avatar
unknown committed
7042
  {
7043 7044 7045 7046 7047 7048 7049 7050 7051 7052
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_empty_string("",0));
    item_list.push_back(new Item_string(message,strlen(message)));
    if (result->send_data(item_list))
      result->send_error(0,NullS);
unknown's avatar
unknown committed
7053 7054 7055 7056 7057
  }
  else
  {
    table_map used_tables=0;
    for (uint i=0 ; i < join->tables ; i++)
unknown's avatar
unknown committed
7058
    {
unknown's avatar
unknown committed
7059 7060
      JOIN_TAB *tab=join->join_tab+i;
      TABLE *table=tab->table;
7061 7062 7063 7064 7065
      char buff[512],*buff_ptr=buff;
      char buff1[512], buff2[512], bufff[512];
      String tmp1(buff1,sizeof(buff1));
      String tmp2(buff2,sizeof(buff2));
      item_list.empty();
unknown's avatar
unknown committed
7066 7067
      if (tab->type == JT_ALL && tab->select && tab->select->quick)
	tab->type= JT_RANGE;
7068 7069 7070
      item_list.push_back(new Item_string(table->table_name,strlen(table->table_name)));
      item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type])));
      tmp1.length(0); tmp2.length(0);
unknown's avatar
unknown committed
7071 7072 7073
      key_map bits;
      uint j;
      for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
unknown's avatar
unknown committed
7074
      {
unknown's avatar
unknown committed
7075 7076
	if (bits & 1)
	{
7077 7078 7079
	  if (tmp1.length())
	    tmp1.append(',');
	  tmp1.append(table->key_info[j].name);
unknown's avatar
unknown committed
7080
	}
unknown's avatar
unknown committed
7081
      }
7082 7083
      if (tmp1.length())
	item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length()));
unknown's avatar
unknown committed
7084
      else
7085
	item_list.push_back(new Item_null());
unknown's avatar
unknown committed
7086
      if (tab->ref.key_parts)
unknown's avatar
unknown committed
7087
      {
7088 7089 7090
	item_list.push_back(new Item_string(table->key_info[tab->ref.key].name,
					    strlen(table->key_info[tab->ref.key].name)));
	item_list.push_back(new Item_int((int32) tab->ref.key_length));
unknown's avatar
unknown committed
7091 7092
	for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
	{
7093 7094 7095
	  if (tmp2.length())
	    tmp2.append(',');
	  tmp2.append((*ref)->name());
unknown's avatar
unknown committed
7096
	}
7097
	item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length()));
unknown's avatar
unknown committed
7098 7099 7100
      }
      else if (tab->type == JT_NEXT)
      {
7101
	item_list.push_back(new Item_string(table->key_info[tab->index].name,strlen(table->key_info[tab->index].name)));
7102
	item_list.push_back(new Item_int((int32) table->key_info[tab->index].key_length));
7103
	item_list.push_back(new Item_null());
unknown's avatar
unknown committed
7104 7105 7106
      }
      else if (tab->select && tab->select->quick)
      {
7107
	item_list.push_back(new Item_string(table->key_info[tab->select->quick->index].name,strlen(table->key_info[tab->select->quick->index].name)));
7108
	item_list.push_back(new Item_int((int32) tab->select->quick->max_used_key_length));
7109
	item_list.push_back(new Item_null());
unknown's avatar
unknown committed
7110 7111 7112
      }
      else
      {
7113 7114 7115
	item_list.push_back(new Item_null());
	item_list.push_back(new Item_null());
	item_list.push_back(new Item_null());
unknown's avatar
unknown committed
7116
      }
7117 7118
      sprintf(bufff,"%.0f",join->best_positions[i].records_read);
      item_list.push_back(new Item_string(bufff,strlen(bufff)));
unknown's avatar
unknown committed
7119 7120 7121 7122 7123 7124
      my_bool key_read=table->key_read;
      if (tab->type == JT_NEXT &&
	  ((table->used_keys & ((key_map) 1 << tab->index))))
	key_read=1;
      
      if (tab->info)
7125
	item_list.push_back(new Item_string(tab->info,strlen(tab->info)));
unknown's avatar
unknown committed
7126
      else if (tab->select)
unknown's avatar
unknown committed
7127
      {
unknown's avatar
unknown committed
7128 7129 7130 7131 7132 7133 7134 7135
	if (tab->use_quick == 2)
	{
	  sprintf(buff_ptr,"range checked for each record (index map: %u)",
		  tab->keys);
	  buff_ptr=strend(buff_ptr);
	}
	else
	  buff_ptr=strmov(buff_ptr,"where used");
unknown's avatar
unknown committed
7136
      }
unknown's avatar
unknown committed
7137
      if (key_read)
unknown's avatar
unknown committed
7138
      {
unknown's avatar
unknown committed
7139 7140 7141 7142 7143
	if (buff != buff_ptr)
	{
	  buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
	}
	buff_ptr=strmov(buff_ptr,"Using index");
unknown's avatar
unknown committed
7144
      }
unknown's avatar
unknown committed
7145
      if (table->reginfo.not_exists_optimize)
unknown's avatar
unknown committed
7146
      {
unknown's avatar
unknown committed
7147 7148 7149 7150 7151
	if (buff != buff_ptr)
	{
	  buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
	}
	buff_ptr=strmov(buff_ptr,"Not exists");
unknown's avatar
unknown committed
7152
      }
unknown's avatar
unknown committed
7153
      if (need_tmp_table)
unknown's avatar
unknown committed
7154
      {
unknown's avatar
unknown committed
7155 7156 7157 7158 7159 7160
	need_tmp_table=0;
	if (buff != buff_ptr)
	{
	  buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
	}
	buff_ptr=strmov(buff_ptr,"Using temporary");
unknown's avatar
unknown committed
7161
      }
unknown's avatar
unknown committed
7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178
      if (need_order)
      {
	need_order=0;
	if (buff != buff_ptr)
	{
	  buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
	}
	buff_ptr=strmov(buff_ptr,"Using filesort");
      }
      if (distinct & test_all_bits(used_tables,thd->used_tables))
      {
	if (buff != buff_ptr)
	{
	  buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
	}
	buff_ptr=strmov(buff_ptr,"Distinct");
      }
7179
      item_list.push_back(new Item_string(buff,(uint) (buff_ptr - buff)));
unknown's avatar
unknown committed
7180 7181
      // For next iteration
      used_tables|=table->map;
7182 7183
      if (result->send_data(item_list))
	result->send_error(0,NullS);
unknown's avatar
unknown committed
7184
    }
unknown's avatar
unknown committed
7185
  }
unknown's avatar
unknown committed
7186
  if (!join->thd->lex.select->next)
7187 7188 7189 7190 7191 7192
  {
    save_lock=thd->lock;
    thd->lock=(MYSQL_LOCK *)0;
    result->send_eof();
    thd->lock=save_lock;
  }
unknown's avatar
unknown committed
7193 7194 7195 7196
  DBUG_VOID_RETURN;
}


7197
static void describe_info(THD *thd, const char *info)
unknown's avatar
unknown committed
7198 7199 7200 7201
{
  List<Item> field_list;
  String *packet= &thd->packet;

7202
  /* Don't log this into the slow query log */
7203
  thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
unknown's avatar
unknown committed
7204 7205 7206 7207 7208 7209 7210 7211
  field_list.push_back(new Item_empty_string("Comment",80));
  if (send_fields(thd,field_list,1))
    return; /* purecov: inspected */
  packet->length(0);
  net_store_data(packet,info);
  if (!my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
    send_eof(&thd->net);
}