sql_union.cc 7.92 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 26
/* Copyright (C) 2000 MySQL 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 */


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


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

unknown's avatar
unknown committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
int mysql_union(THD *thd, LEX *lex, select_result *result)
{
  DBUG_ENTER("mysql_union");
  SELECT_LEX_UNIT *unit= &lex->unit;
  int res= 0;
  if (!(res= unit->prepare(thd, result)))
    res= unit->exec();
  res|= unit->cleanup();
  DBUG_RETURN(res);
}


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

select_union::select_union(TABLE *table_par)
    :table(table_par)
{
  bzero((char*) &info,sizeof(info));
  /*
    We can always use DUP_IGNORE because the temporary table will only
    contain a unique key if we are using not using UNION ALL
  */
  info.handle_duplicates= DUP_IGNORE;
}

select_union::~select_union()
{
}


int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
  unit= u;
  if (save_time_stamp && list.elements != table->fields)
  {
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
	       ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
    return -1;
  }
  return 0;
}

bool select_union::send_data(List<Item> &values)
{
  if (unit->offset_limit_cnt)
  {						// using limit offset,count
    unit->offset_limit_cnt--;
    return 0;
  }
  fill_record(table->field,values);
  if ((write_record(table,&info)))
  {
unknown's avatar
unknown committed
81
    if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0))
unknown's avatar
unknown committed
82 83 84 85 86 87 88 89 90
      return 1;
  }
  return 0;
}

bool select_union::send_eof()
{
  return 0;
}
unknown's avatar
unknown committed
91

unknown's avatar
unknown committed
92
bool select_union::flush()
unknown's avatar
unknown committed
93
{
unknown's avatar
unknown committed
94 95 96 97
  int error;
  if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
  {
    table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
98
    ::send_error(thd);
unknown's avatar
unknown committed
99 100 101 102 103 104 105 106
    return 1;
  }
  return 0;
}

typedef JOIN * JOIN_P;
int st_select_lex_unit::prepare(THD *thd, select_result *result)
{
unknown's avatar
unknown committed
107 108 109 110 111
  DBUG_ENTER("st_select_lex_unit::prepare");

  if (prepared)
    DBUG_RETURN(0);
  prepared= 1;
unknown's avatar
unknown committed
112
  union_result=0;
unknown's avatar
unknown committed
113 114
  res= 0;
  found_rows_for_union= false;
unknown's avatar
unknown committed
115
  TMP_TABLE_PARAM tmp_table_param;
unknown's avatar
unknown committed
116 117
  this->thd= thd;
  this->result= result;
118
  SELECT_LEX *lex_select_save= thd->lex.select, *sl;
unknown's avatar
unknown committed
119

120
  /* Global option */
unknown's avatar
unknown committed
121
  if (((void*)(global_parameters)) == ((void*)this))
122
  {
unknown's avatar
unknown committed
123
    found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS && 
unknown's avatar
unknown committed
124
      global_parameters->select_limit;
125
    if (found_rows_for_union)
unknown's avatar
unknown committed
126
      first_select()->options ^=  OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
127
  }
unknown's avatar
unknown committed
128
  item_list.empty();
unknown's avatar
unknown committed
129 130
  {
    Item *item;
unknown's avatar
unknown committed
131 132
    List_iterator<Item> it(first_select()->item_list);
    TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first;
unknown's avatar
unknown committed
133 134 135 136

    /* Create a list of items that will be in the result set */
    while ((item= it++))
      if (item_list.push_back(item))
unknown's avatar
unknown committed
137
	goto err;
unknown's avatar
unknown committed
138
    if (setup_fields(thd,first_table,item_list,0,0,1))
unknown's avatar
unknown committed
139
      goto err;
unknown's avatar
unknown committed
140
  }
unknown's avatar
unknown committed
141

unknown's avatar
unknown committed
142
  bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
unknown's avatar
unknown committed
143
  tmp_table_param.field_count=item_list.elements;
144
  if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
unknown's avatar
unknown committed
145
				(ORDER*) 0, !union_option,
146
				1, 0,
unknown's avatar
unknown committed
147
				(first_select()->options | thd->options |
148
				 TMP_TABLE_ALL_COLUMNS),
unknown's avatar
unknown committed
149
				this)))
unknown's avatar
unknown committed
150
    goto err;
unknown's avatar
unknown committed
151 152 153 154
  table->file->extra(HA_EXTRA_WRITE_CACHE);
  table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
  bzero((char*) &result_table_list,sizeof(result_table_list));
  result_table_list.db= (char*) "";
155
  result_table_list.real_name=result_table_list.alias= (char*) "union";
unknown's avatar
unknown committed
156 157 158
  result_table_list.table=table;

  if (!(union_result=new select_union(table)))
unknown's avatar
unknown committed
159
    goto err;
unknown's avatar
unknown committed
160

unknown's avatar
unknown committed
161
  union_result->save_time_stamp=1;
162
  union_result->tmp_table_param=&tmp_table_param;
unknown's avatar
unknown committed
163 164 165

  // prepare selects
  joins.empty();
166
  for (sl= first_select(); sl; sl= sl->next_select())
unknown's avatar
unknown committed
167
  {
unknown's avatar
unknown committed
168
    JOIN *join= new JOIN(thd, sl->item_list, 
unknown's avatar
unknown committed
169
			 sl->options | thd->options | SELECT_NO_UNLOCK,
unknown's avatar
unknown committed
170 171 172 173 174 175 176 177
			 union_result);
    joins.push_back(new JOIN_P(join));
    thd->lex.select=sl;
    offset_limit_cnt= sl->offset_limit;
    select_limit_cnt= sl->select_limit+sl->offset_limit;
    if (select_limit_cnt < sl->select_limit)
      select_limit_cnt= HA_POS_ERROR;		// no limit
    if (select_limit_cnt == HA_POS_ERROR)
unknown's avatar
unknown committed
178 179
      sl->options&= ~OPTION_FOUND_ROWS;

unknown's avatar
unknown committed
180 181 182 183 184 185 186 187 188
    res= join->prepare((TABLE_LIST*) sl->table_list.first,
		       sl->where,
		       (sl->braces) ? 
		       (ORDER *)sl->order_list.first : (ORDER *) 0,
		       (ORDER*) sl->group_list.first,
		       sl->having,
		       (ORDER*) NULL,
		       sl, this, 0);
    if (res | thd->fatal_error)
unknown's avatar
unknown committed
189
      goto err;
unknown's avatar
unknown committed
190
  }
unknown's avatar
unknown committed
191
  thd->lex.select= lex_select_save;
unknown's avatar
unknown committed
192
  DBUG_RETURN(res | thd->fatal_error);
unknown's avatar
unknown committed
193 194 195
err:
  thd->lex.select= lex_select_save;
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
196 197 198 199 200
}

int st_select_lex_unit::exec()
{
  DBUG_ENTER("st_select_lex_unit::exec");
unknown's avatar
unknown committed
201 202
  SELECT_LEX *lex_select_save= thd->lex.select;

unknown's avatar
unknown committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
  if(depended || !item || !item->assigned())
  {
    if (optimized && item && item->assigned())
      item->assigned(0); // We will reinit & rexecute unit
    for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
    {
      thd->lex.select=sl;
      offset_limit_cnt= sl->offset_limit;
      select_limit_cnt= sl->select_limit+sl->offset_limit;
      if (select_limit_cnt < sl->select_limit)
	select_limit_cnt= HA_POS_ERROR;		// no limit
      if (select_limit_cnt == HA_POS_ERROR)
	sl->options&= ~OPTION_FOUND_ROWS;

      if (!optimized)
unknown's avatar
unknown committed
218
	res= sl->join->optimize();
unknown's avatar
unknown committed
219
      else
unknown's avatar
unknown committed
220
	res= sl->join->reinit();
unknown's avatar
unknown committed
221

unknown's avatar
unknown committed
222 223 224 225 226
      if (!res)
      {
	sl->join->exec();
	res= sl->join->error;
      }
unknown's avatar
unknown committed
227
      if (res)
unknown's avatar
unknown committed
228 229
      {
	thd->lex.select= lex_select_save;
unknown's avatar
unknown committed
230
	DBUG_RETURN(res);
unknown's avatar
unknown committed
231
      }
unknown's avatar
unknown committed
232 233 234 235
    }
    optimized= 1;
  }

unknown's avatar
unknown committed
236 237
  if (union_result->flush())
  {
unknown's avatar
unknown committed
238 239
    thd->lex.select= lex_select_save;
    DBUG_RETURN(1);
unknown's avatar
unknown committed
240
  }
241 242

  /* Send result to 'result' */
unknown's avatar
unknown committed
243
  thd->lex.select = first_select();
unknown's avatar
unknown committed
244 245 246 247 248
  res =-1;
  {
    /* Create a list of fields in the temporary table */
    List_iterator<Item> it(item_list);
    Field **field;
249
#if 0
unknown's avatar
unknown committed
250 251
    List<Item_func_match> ftfunc_list;
    ftfunc_list.empty();
252
#else
unknown's avatar
unknown committed
253 254 255
    List<Item_func_match> empty_list;
    empty_list.empty();
    thd->lex.select_lex.ftfunc_list= &empty_list;
256
#endif
unknown's avatar
unknown committed
257 258 259 260 261 262 263

    for (field=table->field ; *field ; field++)
    {
      (void) it++;
      (void) it.replace(new Item_field(*field));
    }
    if (!thd->fatal_error)			// Check if EOM
264
    {
unknown's avatar
unknown committed
265 266 267 268 269 270
      offset_limit_cnt= global_parameters->offset_limit;
      select_limit_cnt= global_parameters->select_limit+
	global_parameters->offset_limit;
      if (select_limit_cnt < global_parameters->select_limit)
	select_limit_cnt= HA_POS_ERROR;		// no limit
      if (select_limit_cnt == HA_POS_ERROR)
271 272 273
	thd->options&= ~OPTION_FOUND_ROWS;
      res= mysql_select(thd,&result_table_list,
			item_list, NULL,
unknown's avatar
unknown committed
274
			(ORDER*)global_parameters->order_list.first,
275
			(ORDER*) NULL, NULL, (ORDER*) NULL,
unknown's avatar
unknown committed
276
			thd->options, result, this, first_select(), 1);
277
      if (found_rows_for_union && !res)
278
	thd->limit_found_rows = (ulonglong)table->file->records;
279
    }
unknown's avatar
unknown committed
280
  }
unknown's avatar
unknown committed
281
  thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc;
unknown's avatar
unknown committed
282
  thd->lex.select= lex_select_save;
unknown's avatar
unknown committed
283 284 285
  DBUG_RETURN(res);
}

unknown's avatar
unknown committed
286
int st_select_lex_unit::cleanup()
unknown's avatar
unknown committed
287
{
unknown's avatar
unknown committed
288
  DBUG_ENTER("st_select_lex_unit::cleanup");
unknown's avatar
unknown committed
289 290 291 292 293 294
  if (union_result)
  {
    delete union_result;
    free_tmp_table(thd,table);
    table= 0; // Safety
  }
unknown's avatar
unknown committed
295 296 297
  List_iterator<JOIN*> j(joins);
  JOIN** join;
  while ((join= j++))
unknown's avatar
unknown committed
298
  {
unknown's avatar
unknown committed
299 300 301
    (*join)->cleanup(thd);
    delete *join;
    delete join;
unknown's avatar
unknown committed
302
  }
unknown's avatar
unknown committed
303 304
  joins.empty();
  DBUG_RETURN(0);
unknown's avatar
unknown committed
305
}