ha_heap.cc 12.7 KB
Newer Older
1
/* Copyright (C) 2000,2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   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 */


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

#include "mysql_priv.h"
#include <myisampack.h>
#include "ha_heap.h"

/*****************************************************************************
** HEAP tables
*****************************************************************************/

const char **ha_heap::bas_ext() const
{ static const char *ext[1]= { NullS }; return ext; }


34
int ha_heap::open(const char *name, int mode, uint test_if_locked)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
35
{
36
  if (!(file= heap_open(name, mode)) && my_errno == ENOENT)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
37
  {
38 39 40
    HA_CREATE_INFO create_info;
    bzero(&create_info, sizeof(create_info));
    if (!create(name, table, &create_info))
monty@mysql.com's avatar
monty@mysql.com committed
41
    {
42
      file= heap_open(name, mode);
monty@mysql.com's avatar
monty@mysql.com committed
43 44
      implicit_emptied= 1;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
45
  }
46
  ref_length= sizeof(HEAP_PTR);
47 48 49
  if (file)
  {
    /* Initialize variables for the opened table */
50
    set_keys_for_scanning();
51
  }
52
  return (file ? 0 : 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
53 54 55 56 57 58 59
}

int ha_heap::close(void)
{
  return heap_close(file);
}

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

/*
  Compute which keys to use for scanning

  SYNOPSIS
    set_keys_for_scanning()
    no parameter

  DESCRIPTION
    Set the bitmap btree_keys, which is used when the upper layers ask
    which keys to use for scanning. For each btree index the
    corresponding bit is set.

  RETURN
    void
*/

void ha_heap::set_keys_for_scanning(void)
{
  btree_keys.clear_all();
  for (uint i= 0 ; i < table->keys ; i++)
  {
    if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE)
      btree_keys.set_bit(i);
  }
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
87 88 89
int ha_heap::write_row(byte * buf)
{
  statistic_increment(ha_write_count,&LOCK_status);
90 91
  if (table->timestamp_default_now)
    update_timestamp(buf+table->timestamp_default_now-1);
92 93
  if (table->next_number_field && buf == table->record[0])
    update_auto_increment();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
94 95 96 97 98 99
  return heap_write(file,buf);
}

int ha_heap::update_row(const byte * old_data, byte * new_data)
{
  statistic_increment(ha_update_count,&LOCK_status);
100 101
  if (table->timestamp_on_update_now)
    update_timestamp(new_data+table->timestamp_on_update_now-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
102 103 104 105 106 107 108 109 110
  return heap_update(file,old_data,new_data);
}

int ha_heap::delete_row(const byte * buf)
{
  statistic_increment(ha_delete_count,&LOCK_status);
  return heap_delete(file,buf);
}

111 112
int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
			enum ha_rkey_function find_flag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
113
{
114 115 116
  statistic_increment(ha_read_key_count, &LOCK_status);
  int error = heap_rkey(file,buf,active_index, key, key_len, find_flag);
  table->status = error ? STATUS_NOT_FOUND : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
117 118 119
  return error;
}

120 121 122 123 124 125 126 127 128
int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
{
  statistic_increment(ha_read_key_count, &LOCK_status);
  int error= heap_rkey(file, buf, active_index, key, key_len,
		       HA_READ_PREFIX_LAST);
  table->status= error ? STATUS_NOT_FOUND : 0;
  return error;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
129
int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
130
			    uint key_len, enum ha_rkey_function find_flag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
131
{
132 133 134
  statistic_increment(ha_read_key_count, &LOCK_status);
  int error = heap_rkey(file, buf, index, key, key_len, find_flag);
  table->status = error ? STATUS_NOT_FOUND : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
  return error;
}

int ha_heap::index_next(byte * buf)
{
  statistic_increment(ha_read_next_count,&LOCK_status);
  int error=heap_rnext(file,buf);
  table->status=error ? STATUS_NOT_FOUND: 0;
  return error;
}

int ha_heap::index_prev(byte * buf)
{
  statistic_increment(ha_read_prev_count,&LOCK_status);
  int error=heap_rprev(file,buf);
  table->status=error ? STATUS_NOT_FOUND: 0;
  return error;
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
153

bk@work.mysql.com's avatar
bk@work.mysql.com committed
154 155 156
int ha_heap::index_first(byte * buf)
{
  statistic_increment(ha_read_first_count,&LOCK_status);
157
  int error=heap_rfirst(file, buf, active_index);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
158 159 160 161 162 163 164
  table->status=error ? STATUS_NOT_FOUND: 0;
  return error;
}

int ha_heap::index_last(byte * buf)
{
  statistic_increment(ha_read_last_count,&LOCK_status);
165
  int error=heap_rlast(file, buf, active_index);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
  table->status=error ? STATUS_NOT_FOUND: 0;
  return error;
}

int ha_heap::rnd_init(bool scan)
{
  return scan ? heap_scan_init(file) : 0;
}

int ha_heap::rnd_next(byte *buf)
{
  statistic_increment(ha_read_rnd_next_count,&LOCK_status);
  int error=heap_scan(file, buf);
  table->status=error ? STATUS_NOT_FOUND: 0;
  return error;
}

int ha_heap::rnd_pos(byte * buf, byte *pos)
{
  int error;
  HEAP_PTR position;
  statistic_increment(ha_read_rnd_count,&LOCK_status);
  memcpy_fixed((char*) &position,pos,sizeof(HEAP_PTR));
  error=heap_rrnd(file, buf, position);
  table->status=error ? STATUS_NOT_FOUND: 0;
  return error;
}

void ha_heap::position(const byte *record)
{
  *(HEAP_PTR*) ref= heap_position(file);	// Ref is aligned
}

void ha_heap::info(uint flag)
{
  HEAPINFO info;
  (void) heap_info(file,&info,flag);

  records = info.records;
  deleted = info.deleted;
  errkey  = info.errkey;
  mean_rec_length=info.reclength;
  data_file_length=info.data_length;
  index_file_length=info.index_length;
  max_data_file_length= info.max_records* info.reclength;
  delete_length= info.deleted * info.reclength;
212 213
  if (flag & HA_STATUS_AUTO)
    auto_increment_value= info.auto_increment;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
}

int ha_heap::extra(enum ha_extra_function operation)
{
  return heap_extra(file,operation);
}

int ha_heap::delete_all_rows()
{
  heap_clear(file);
  return 0;
}

int ha_heap::external_lock(THD *thd, int lock_type)
{
  return 0;					// No external locking
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
230
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 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 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

/*
  Disable indexes.

  SYNOPSIS
    disable_indexes()
    mode        mode of operation:
                HA_KEY_SWITCH_NONUNIQ      disable all non-unique keys
                HA_KEY_SWITCH_ALL          disable all keys
                HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
                HA_KEY_SWITCH_ALL_SAVE     dis. all keys and make persistent

  DESCRIPTION
    Disable indexes and clear keys to use for scanning.

  IMPLEMENTATION
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
    HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
    HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.

  RETURN
    0  ok
    HA_ERR_WRONG_COMMAND  mode not implemented.
*/

int ha_heap::disable_indexes(uint mode)
{
  int error;

  if (mode == HA_KEY_SWITCH_ALL)
  {
    if (!(error= heap_disable_indexes(file)))
      set_keys_for_scanning();
  }
  else
  {
    /* mode not implemented */
    error= HA_ERR_WRONG_COMMAND;
  }
  return error;
}


/*
  Enable indexes.

  SYNOPSIS
    enable_indexes()
    mode        mode of operation:
                HA_KEY_SWITCH_NONUNIQ      enable all non-unique keys
                HA_KEY_SWITCH_ALL          enable all keys
                HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
                HA_KEY_SWITCH_ALL_SAVE     en. all keys and make persistent

  DESCRIPTION
    Enable indexes and set keys to use for scanning.
    The indexes might have been disabled by disable_index() before.
    The function works only if both data and indexes are empty,
    since the heap storage engine cannot repair the indexes.
    To be sure, call handler::delete_all_rows() before.

  IMPLEMENTATION
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
    HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
    HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.

  RETURN
    0  ok
    HA_ERR_CRASHED  data or index is non-empty. Delete all rows and retry.
    HA_ERR_WRONG_COMMAND  mode not implemented.
*/

int ha_heap::enable_indexes(uint mode)
{
  int error;

  if (mode == HA_KEY_SWITCH_ALL)
  {
    if (!(error= heap_enable_indexes(file)))
      set_keys_for_scanning();
  }
  else
  {
    /* mode not implemented */
    error= HA_ERR_WRONG_COMMAND;
  }
  return error;
}


/*
  Test if indexes are disabled.

  SYNOPSIS
    indexes_are_disabled()
    no parameters

  RETURN
    0  indexes are not disabled
    1  all indexes are disabled
   [2  non-unique indexes are disabled - NOT YET IMPLEMENTED]
*/

int ha_heap::indexes_are_disabled(void)
{
  return heap_indexes_are_disabled(file);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
				    THR_LOCK_DATA **to,
				    enum thr_lock_type lock_type)
{
  if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
    file->lock.type=lock_type;
  *to++= &file->lock;
  return to;
}

/*
  We have to ignore ENOENT entries as the HEAP table is created on open and
  not when doing a CREATE on the table.
*/

int ha_heap::delete_table(const char *name)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
357
  int error=heap_delete_table(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
358 359 360 361 362 363 364 365
  return error == ENOENT ? 0 : error;
}

int ha_heap::rename_table(const char * from, const char * to)
{
  return heap_rename(from,to);
}

366 367 368

ha_rows ha_heap::records_in_range(uint inx, key_range *min_key,
                                  key_range *max_key)
369
{
370 371 372 373 374 375 376 377
  KEY *key=table->key_info+inx;
  if (key->algorithm == HA_KEY_ALG_BTREE)
    return hp_rb_records_in_range(file, inx, min_key, max_key);

  if (min_key->length != max_key->length ||
      min_key->length != key->key_length ||
      min_key->flag != HA_READ_KEY_EXACT ||
      max_key->flag != HA_READ_AFTER_KEY)
serg@serg.mylan's avatar
serg@serg.mylan committed
378
    return HA_POS_ERROR;			// Can only use exact keys
379
  return 10;					// Good guess
380 381
}

382 383

int ha_heap::create(const char *name, TABLE *table_arg,
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
384
		    HA_CREATE_INFO *create_info)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
385
{
386
  uint key, parts, mem_per_row= 0;
387
  uint auto_key= 0, auto_key_type= 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
388
  ha_rows max_rows;
389 390
  HP_KEYDEF *keydef;
  HA_KEYSEG *seg;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
391
  char buff[FN_REFLEN];
392 393
  int error;

394 395
  for (key= parts= 0; key < table_arg->keys; key++)
    parts+= table_arg->key_info[key].key_parts;
396

397
  if (!(keydef= (HP_KEYDEF*) my_malloc(table_arg->keys * sizeof(HP_KEYDEF) +
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
398 399
				       parts * sizeof(HA_KEYSEG),
				       MYF(MY_WME))))
400
    return my_errno;
401 402
  seg= my_reinterpret_cast(HA_KEYSEG*) (keydef + table_arg->keys);
  for (key= 0; key < table_arg->keys; key++)
403
  {
404
    KEY *pos= table_arg->key_info+key;
405 406 407 408 409 410 411 412
    KEY_PART_INFO *key_part=     pos->key_part;
    KEY_PART_INFO *key_part_end= key_part + pos->key_parts;

    mem_per_row+= (pos->key_length + (sizeof(char*) * 2));

    keydef[key].keysegs=   (uint) pos->key_parts;
    keydef[key].flag=      (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
    keydef[key].seg=       seg;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
413 414
    keydef[key].algorithm= ((pos->algorithm == HA_KEY_ALG_UNDEF) ? 
			    HA_KEY_ALG_HASH : pos->algorithm);
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

    for (; key_part != key_part_end; key_part++, seg++)
    {
      uint flag=    key_part->key_type;
      Field *field= key_part->field;
      if (pos->algorithm == HA_KEY_ALG_BTREE)
	seg->type= field->key_type();
      else
      {
	if (!f_is_packed(flag) &&
	    f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
	    !(flag & FIELDFLAG_BINARY))
	  seg->type= (int) HA_KEYTYPE_TEXT;
	else
	  seg->type= (int) HA_KEYTYPE_BINARY;
      }
      seg->start=   (uint) key_part->offset;
      seg->length=  (uint) key_part->length;
      seg->flag =   0;
434
      seg->charset= field->charset();
435 436 437
      if (field->null_ptr)
      {
	seg->null_bit= field->null_bit;
438
	seg->null_pos= (uint) (field->null_ptr - (uchar*) table_arg->record[0]);
439 440 441 442 443 444
      }
      else
      {
	seg->null_bit= 0;
	seg->null_pos= 0;
      }
445 446 447 448 449
      if (field->flags & AUTO_INCREMENT_FLAG)
      {
	auto_key= key + 1;
	auto_key_type= field->key_type();
      }
450 451
    }
  }
452
  mem_per_row+= MY_ALIGN(table_arg->reclength + 1, sizeof(char*));
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
453 454
  max_rows = (ha_rows) (current_thd->variables.max_heap_table_size /
			mem_per_row);
455 456 457 458 459
  HP_CREATE_INFO hp_create_info;
  hp_create_info.auto_key= auto_key;
  hp_create_info.auto_key_type= auto_key_type;
  hp_create_info.auto_increment= (create_info->auto_increment_value ?
				  create_info->auto_increment_value - 1 : 0);
460
  error= heap_create(fn_format(buff,name,"","",4+2),
461 462 463 464 465
		     table_arg->keys,keydef, table_arg->reclength,
		     (ulong) ((table_arg->max_rows < max_rows &&
			       table_arg->max_rows) ? 
			      table_arg->max_rows : max_rows),
		     (ulong) table_arg->min_rows, &hp_create_info);
466 467 468 469
  my_free((gptr) keydef, MYF(0));
  if (file)
    info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
  return (error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
470
}
471

472

473 474 475 476 477 478 479 480 481 482 483 484
void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
{
  table->file->info(HA_STATUS_AUTO);
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
    create_info->auto_increment_value= auto_increment_value;
}

longlong ha_heap::get_auto_increment()
{
  ha_heap::info(HA_STATUS_AUTO);
  return auto_increment_value;
}