handler.cc 19.1 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 27 28 29 30 31 32 33 34
/* 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 */


/* Handler-calling-functions */

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

#include "mysql_priv.h"
#include "ha_heap.h"
#include "ha_myisam.h"
#include "ha_myisammrg.h"
#ifndef NO_ISAM
#include "ha_isam.h"
#include "ha_isammrg.h"
#endif
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
35 36 37
#ifdef HAVE_INNOBASE_DB
#include "ha_innobase.h"
#endif
38 39 40
#ifdef HAVE_GEMINI_DB
#include "ha_gemini.h"
#endif
unknown's avatar
unknown committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include <myisampack.h>
#include <errno.h>

	/* static functions defined in this file */

static int NEAR_F delete_file(const char *name,const char *ext,int extflag);

ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
      ha_read_key_count, ha_read_next_count, ha_read_prev_count,
      ha_read_first_count, ha_read_last_count,
      ha_read_rnd_count, ha_read_rnd_next_count;

const char *ha_table_type[] = {
  "", "DIAB_ISAM","HASH","MISAM","PISAM","RMS_ISAM","HEAP", "ISAM",
55
  "MRG_ISAM","MYISAM", "MRG_MYISAM", "BDB", "INNOBASE", "GEMINI", "?", "?",NullS
unknown's avatar
unknown committed
56 57
};

58 59 60
TYPELIB ha_table_typelib= {array_elements(ha_table_type)-4,"",
			   ha_table_type+1};

unknown's avatar
unknown committed
61 62 63 64
const char *ha_row_type[] = {
  "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?"
};

unknown's avatar
unknown committed
65
const char *tx_isolation_names[] =
66 67 68
{ "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE",
  NullS};
TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
unknown's avatar
unknown committed
69
			       tx_isolation_names};
unknown's avatar
unknown committed
70 71 72 73 74 75 76 77 78 79

	/* Use other database handler if databasehandler is not incompiled */

enum db_type ha_checktype(enum db_type database_type)
{
  switch (database_type) {
#ifdef HAVE_BERKELEY_DB
  case DB_TYPE_BERKELEY_DB:
    return(berkeley_skip ? DB_TYPE_MYISAM : database_type);
#endif
80 81
#ifdef HAVE_INNOBASE_DB
  case DB_TYPE_INNOBASE:
unknown's avatar
unknown committed
82
    return(innodb_skip ? DB_TYPE_MYISAM : database_type);
83
#endif
84 85 86 87
#ifdef HAVE_GEMINI_DB
  case DB_TYPE_GEMINI:
    return(gemini_skip ? DB_TYPE_MYISAM : database_type);
#endif
unknown's avatar
unknown committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
#ifndef NO_HASH
  case DB_TYPE_HASH:
#endif
#ifndef NO_MERGE
  case DB_TYPE_MRG_ISAM:
#endif
#ifndef NO_ISAM
  case DB_TYPE_ISAM:
#endif
  case DB_TYPE_HEAP:
  case DB_TYPE_MYISAM:
  case DB_TYPE_MRG_MYISAM:
    return (database_type);			/* Database exists on system */
  default:
    break;
  }
  return(DB_TYPE_MYISAM);			/* Use this as default */
} /* ha_checktype */


handler *get_new_handler(TABLE *table, enum db_type db_type)
{
  switch (db_type) {
#ifndef NO_HASH
  return new ha_hash(table);
#endif
#ifndef NO_MERGE
  case DB_TYPE_MRG_ISAM:
    return new ha_isammrg(table);
#endif
#ifndef NO_ISAM
  case DB_TYPE_ISAM:
    return new ha_isam(table);
#endif
#ifdef HAVE_BERKELEY_DB
  case DB_TYPE_BERKELEY_DB:
    return new ha_berkeley(table);
125 126
#endif
#ifdef HAVE_INNOBASE_DB
127
  case DB_TYPE_INNOBASE:
128
    return new ha_innobase(table);
129 130 131 132
#endif
#ifdef HAVE_GEMINI_DB
  case DB_TYPE_GEMINI:
    return new ha_gemini(table);
unknown's avatar
unknown committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
#endif
  case DB_TYPE_HEAP:
    return new ha_heap(table);
  case DB_TYPE_MYISAM:
  default:					// should never happen
    return new ha_myisam(table);
  case DB_TYPE_MRG_MYISAM:
    return new ha_myisammrg(table);
  }
}

int ha_init()
{
#ifdef HAVE_BERKELEY_DB
  if (!berkeley_skip)
  {
    int error;
    if ((error=berkeley_init()))
      return error;
152 153
    if (!berkeley_skip)				// If we couldn't use handler
      opt_using_transactions=1;
154 155
    else
      have_berkeley_db=SHOW_OPTION_DISABLED;
unknown's avatar
unknown committed
156
  }
157 158
#endif
#ifdef HAVE_INNOBASE_DB
unknown's avatar
unknown committed
159
  if (!innodb_skip)
160
  {
unknown's avatar
unknown committed
161 162
    if (innobase_init())
      return -1;
unknown's avatar
unknown committed
163
    if (!innodb_skip)				// If we couldn't use handler
164
      opt_using_transactions=1;
165
    else
unknown's avatar
unknown committed
166
      have_innodb=SHOW_OPTION_DISABLED;
167
  }
168 169 170 171 172 173 174 175
#endif
#ifdef HAVE_GEMINI_DB
  if (!gemini_skip)
  {
    if (gemini_init())
      return -1;
    if (!gemini_skip)				// If we couldn't use handler
      opt_using_transactions=1;
176
    else
177
      have_gemini=SHOW_OPTION_DISABLED;
178
  }
unknown's avatar
unknown committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
#endif
  return 0;
}

	/* close, flush or restart databases */
	/* Ignore this for other databases than ours */

int ha_panic(enum ha_panic_function flag)
{
  int error=0;
#ifndef NO_MERGE
  error|=mrg_panic(flag);
#endif
#ifndef NO_HASH
  error|=h_panic(flag);			/* fix hash */
#endif
  error|=heap_panic(flag);
  error|=nisam_panic(flag);
  error|=mi_panic(flag);
  error|=myrg_panic(flag);
#ifdef HAVE_BERKELEY_DB
  if (!berkeley_skip)
    error|=berkeley_end();
202 203
#endif
#ifdef HAVE_INNOBASE_DB
unknown's avatar
unknown committed
204
  if (!innodb_skip)
205
    error|=innobase_end();
206 207 208 209
#endif
#ifdef HAVE_GEMINI_DB
  if (!gemini_skip)
    error|=gemini_end();
unknown's avatar
unknown committed
210 211 212 213 214
#endif
  return error;
} /* ha_panic */


215 216 217
void ha_close_connection(THD* thd)
{
#ifdef HAVE_INNOBASE_DB
unknown's avatar
unknown committed
218
  if (!innodb_skip)
unknown's avatar
unknown committed
219
    innobase_close_connection(thd);
220
#endif
221 222 223 224 225 226
#ifdef HAVE_GEMINI_DB
  if (!gemini_skip && thd->gemini.context)
  {
    gemini_disconnect(thd);
  }
#endif /* HAVE_GEMINI_DB */
227 228
}

229 230 231 232 233
/*
  This is used to commit or rollback a single statement depending
  on the value of error
*/

unknown's avatar
unknown committed
234 235 236
int ha_autocommit_or_rollback(THD *thd, int error)
{
  DBUG_ENTER("ha_autocommit_or_rollback");
237
#ifdef USING_TRANSACTIONS
238
  if (opt_using_transactions)
unknown's avatar
unknown committed
239
  {
240 241 242 243 244 245 246
    if (!error)
    {
      if (ha_commit_stmt(thd))
	error=1;
    }
    else
      (void) ha_rollback_stmt(thd);
unknown's avatar
unknown committed
247
    thd->tx_isolation=thd->session_tx_isolation;
unknown's avatar
unknown committed
248 249 250 251 252
  }
#endif
  DBUG_RETURN(error);
}

253 254

int ha_commit_trans(THD *thd, THD_TRANS* trans)
unknown's avatar
unknown committed
255 256
{
  int error=0;
257
  DBUG_ENTER("ha_commit");
258
#ifdef USING_TRANSACTIONS
259
  if (opt_using_transactions)
260
  {
261 262 263 264 265 266 267 268 269
    /* Update the binary log if we have cached some queries */
    if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
	my_b_tell(&thd->transaction.trans_log))
    {
      mysql_bin_log.write(&thd->transaction.trans_log);
      reinit_io_cache(&thd->transaction.trans_log,
		      WRITE_CACHE, (my_off_t) 0, 0, 1);
      thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
    }
unknown's avatar
unknown committed
270
#ifdef HAVE_BERKELEY_DB
271
    if (trans->bdb_tid)
unknown's avatar
unknown committed
272
    {
273 274 275 276 277 278
      if ((error=berkeley_commit(thd,trans->bdb_tid)))
      {
	my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
	error=1;
      }
      trans->bdb_tid=0;
unknown's avatar
unknown committed
279
    }
280 281
#endif
#ifdef HAVE_INNOBASE_DB
282
    if (trans->innobase_tid)
283
    {
284 285 286 287 288
      if ((error=innobase_commit(thd,trans->innobase_tid)))
      {
	my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
	error=1;
      }
289
    }
290 291 292 293 294 295 296 297 298 299 300 301 302 303
#endif
#ifdef HAVE_GEMINI_DB 
    /* Commit the transaction in behalf of the commit statement
       or if we're in auto-commit mode               */
    if((trans == &thd->transaction.all) || 
        (!(thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))))
    {
      error=gemini_commit(thd);
      if (error)
      {
	my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
	error=1;
      }
    }
304
#endif
305 306
    if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
      sql_print_error("Error: Got error during commit;  Binlog is not up to date!");
unknown's avatar
unknown committed
307
    thd->tx_isolation=thd->session_tx_isolation;
308
  }
309
#endif // using transactions
unknown's avatar
unknown committed
310 311 312
  DBUG_RETURN(error);
}

313

314
int ha_rollback_trans(THD *thd, THD_TRANS *trans)
unknown's avatar
unknown committed
315 316
{
  int error=0;
317
  DBUG_ENTER("ha_rollback");
318 319
#ifdef USING_TRANSACTIONS
  if (opt_using_transactions)
unknown's avatar
unknown committed
320
  {
321 322
#ifdef HAVE_BERKELEY_DB
    if (trans->bdb_tid)
unknown's avatar
unknown committed
323
    {
324 325 326 327 328 329
      if ((error=berkeley_rollback(thd, trans->bdb_tid)))
      {
	my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
	error=1;
      }
      trans->bdb_tid=0;
unknown's avatar
unknown committed
330
    }
331 332
#endif
#ifdef HAVE_INNOBASE_DB
333
    if (trans->innobase_tid)
334
    {
335 336 337 338 339
      if ((error=innobase_rollback(thd, trans->innobase_tid)))
      {
	my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
	error=1;
      }
340
    }
341 342 343 344 345 346 347 348 349 350 351 352
#endif
#ifdef HAVE_GEMINI_DB
    if((trans == &thd->transaction.stmt) &&
       (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)))
      error = gemini_rollback_to_savepoint(thd);
    else
      error=gemini_rollback(thd);
    if (error)
    {
      my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
      error=1;
    }
unknown's avatar
unknown committed
353
#endif
354 355 356 357
    if (trans == &thd->transaction.all)
      reinit_io_cache(&thd->transaction.trans_log,
		      WRITE_CACHE, (my_off_t) 0, 0, 1);
    thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
unknown's avatar
unknown committed
358
    thd->tx_isolation=thd->session_tx_isolation;
359 360
  }
#endif /* USING_TRANSACTIONS */
unknown's avatar
unknown committed
361 362 363
  DBUG_RETURN(error);
}

unknown's avatar
unknown committed
364 365 366 367 368 369 370 371 372 373
void ha_set_spin_retries(uint retries)
{
#ifdef HAVE_GEMINI_DB
  if (!gemini_skip)
  {
    gemini_set_option_long(GEM_OPTID_SPIN_RETRIES, retries);
  }
#endif /* HAVE_GEMINI_DB */
}

unknown's avatar
unknown committed
374 375 376 377 378 379 380

bool ha_flush_logs()
{
  bool result=0;
#ifdef HAVE_BERKELEY_DB
  if (!berkeley_skip && berkeley_flush_logs())
    result=1;
381 382
#endif
#ifdef HAVE_INNOBASE_DB
unknown's avatar
unknown committed
383
  if (!innodb_skip && innobase_flush_logs())
384
    result=1;
unknown's avatar
unknown committed
385 386 387 388
#endif
  return result;
}

unknown's avatar
unknown committed
389 390 391 392
/*
  This should return ENOENT if the file doesn't exists.
  The .frm file will be deleted only if we return 0 or ENOENT
*/
unknown's avatar
unknown committed
393 394 395 396 397

int ha_delete_table(enum db_type table_type, const char *path)
{
  handler *file=get_new_handler((TABLE*) 0, table_type);
  if (!file)
unknown's avatar
unknown committed
398
    return ENOENT;
unknown's avatar
unknown committed
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
  int error=file->delete_table(path);
  delete file;
  return error;
}
    
void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
{
  switch (pack_length) {
#if SIZEOF_OFF_T > 4
  case 8: mi_int8store(buff,pos); break;
  case 7: mi_int7store(buff,pos); break;
  case 6: mi_int6store(buff,pos); break;
  case 5: mi_int5store(buff,pos); break;
#endif
  case 4: mi_int4store(buff,pos); break;
  case 3: mi_int3store(buff,pos); break;
  case 2: mi_int2store(buff,(uint) pos); break;
  case 1: buff[0]= (uchar) pos; break;
  }
  return;
}

my_off_t ha_get_ptr(byte *ptr, uint pack_length)
{
  my_off_t pos;
  switch (pack_length) {
#if SIZEOF_OFF_T > 4
  case 8:
    pos= (my_off_t) mi_uint8korr(ptr);
    break;
  case 7:
    pos= (my_off_t) mi_uint7korr(ptr);
    break;
  case 6:
    pos= (my_off_t) mi_uint6korr(ptr);
    break;
  case 5:
    pos= (my_off_t) mi_uint5korr(ptr);
    break;
#endif
  case 4:
    pos= (my_off_t) mi_uint4korr(ptr);
    break;
  case 3:
    pos= (my_off_t) mi_uint3korr(ptr);
    break;
  case 2:
    pos= (my_off_t) mi_uint2korr(ptr);
    break;
  case 1:
    pos= (my_off_t) mi_uint2korr(ptr);
    break;
  default:
    pos=0;					// Impossible
    break;
  }
 return pos;
}

/****************************************************************************
** General handler functions
****************************************************************************/

	/* Open database-handler. Try O_RDONLY if can't open as O_RDWR */
	/* Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set */

int handler::ha_open(const char *name, int mode, int test_if_locked)
{
  int error;
  DBUG_ENTER("handler::open");
unknown's avatar
unknown committed
469 470
  DBUG_PRINT("enter",("name: %s  db_type: %d  db_stat: %d  mode: %d  lock_test: %d",
		      name, table->db_type, table->db_stat, mode, test_if_locked));
unknown's avatar
unknown committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492

  if ((error=open(name,mode,test_if_locked)))
  {
    if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
	(table->db_stat & HA_TRY_READ_ONLY))
    {
      table->db_stat|=HA_READ_ONLY;
      error=open(name,O_RDONLY,test_if_locked);
    }
  }
  if (error)
  {
    my_errno=error;			/* Safeguard */
    DBUG_PRINT("error",("error: %d  errno: %d",error,errno));
  }
  else
  {
    if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
      table->db_stat|=HA_READ_ONLY;
  }
  if (!error)
  {
unknown's avatar
unknown committed
493
    if (!alloc_root_inited(&table->mem_root))	// If temporary table
494
      ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
unknown's avatar
unknown committed
495 496 497
    else
      ref=(byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2);
    if (!ref)
unknown's avatar
unknown committed
498 499 500 501 502 503 504 505 506 507 508 509
    {
      close();
      error=HA_ERR_OUT_OF_MEM;
    }
    else
      dupp_ref=ref+ALIGN_SIZE(ref_length);
  }
  DBUG_RETURN(error);
}

int handler::check(THD* thd, HA_CHECK_OPT* check_opt)
{
510
  return HA_ADMIN_NOT_IMPLEMENTED;
unknown's avatar
unknown committed
511 512
}

unknown's avatar
unknown committed
513 514 515 516 517 518 519 520 521 522
int handler::backup(THD* thd, HA_CHECK_OPT* check_opt)
{
  return HA_ADMIN_NOT_IMPLEMENTED;
}

int handler::restore(THD* thd, HA_CHECK_OPT* check_opt)
{
  return HA_ADMIN_NOT_IMPLEMENTED;
}

unknown's avatar
unknown committed
523 524
int handler::repair(THD* thd, HA_CHECK_OPT* check_opt)
{
525
  return HA_ADMIN_NOT_IMPLEMENTED;
unknown's avatar
unknown committed
526 527
}

528
int handler::optimize(THD* thd, HA_CHECK_OPT* check_opt)
unknown's avatar
unknown committed
529
{
530
  return HA_ADMIN_NOT_IMPLEMENTED;
unknown's avatar
unknown committed
531 532
}

533
int handler::analyze(THD* thd, HA_CHECK_OPT* check_opt)
unknown's avatar
unknown committed
534
{
535
  return HA_ADMIN_NOT_IMPLEMENTED;
unknown's avatar
unknown committed
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
}

	/* Read first row from a table */

int handler::rnd_first(byte * buf)
{
  register int error;
  DBUG_ENTER("handler::rnd_first");

  statistic_increment(ha_read_first_count,&LOCK_status);
  (void) rnd_init();
  while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
  (void) rnd_end();
  DBUG_RETURN(error);
}


/*
  The following function is only needed for tables that may be temporary tables
  during joins
*/

int handler::restart_rnd_next(byte *buf, byte *pos)
{
  return HA_ERR_WRONG_COMMAND;
}


	/* Set a timestamp in record */

void handler::update_timestamp(byte *record)
{
  long skr= (long) current_thd->query_start();
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(record,skr);
  }
  else
#endif
  longstore(record,skr);
  return;
}

	/* Updates field with field_type NEXT_NUMBER according to following:
	** if field = 0 change field to the next free key in database.
	*/

void handler::update_auto_increment()
{
  longlong nr;
  THD *thd;
  DBUG_ENTER("update_auto_increment");
  if (table->next_number_field->val_int() != 0)
590 591
  {
    auto_increment_column_changed=0;
unknown's avatar
unknown committed
592
    DBUG_VOID_RETURN;
593
  }
unknown's avatar
unknown committed
594 595 596 597 598 599 600
  thd=current_thd;
  if ((nr=thd->next_insert_id))
    thd->next_insert_id=0;			// Clear after use
  else
    nr=get_auto_increment();
  thd->insert_id((ulonglong) nr);
  table->next_number_field->store(nr);
601
  auto_increment_column_changed=1;
unknown's avatar
unknown committed
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
  DBUG_VOID_RETURN;
}


longlong handler::get_auto_increment()
{
  longlong nr;
  int error;
  (void) extra(HA_EXTRA_KEYREAD);
  index_init(table->next_number_index);
  error=index_last(table->record[1]);
  if (error)
    nr=1;
  else
    nr=(longlong) table->next_number_field->
      val_int_offset(table->rec_buff_length)+1;
  (void) extra(HA_EXTRA_NO_KEYREAD);
  index_end();
  return nr;
}

	/* Print error that we got from handler function */

void handler::print_error(int error, myf errflag)
{
  DBUG_ENTER("print_error");
  DBUG_PRINT("enter",("error: %d",error));

  int textno=ER_GET_ERRNO;
  switch (error) {
  case EAGAIN:
    textno=ER_FILE_USED;
    break;
  case ENOENT:
    textno=ER_FILE_NOT_FOUND;
    break;
  case HA_ERR_KEY_NOT_FOUND:
  case HA_ERR_NO_ACTIVE_RECORD:
  case HA_ERR_END_OF_FILE:
    textno=ER_KEY_NOT_FOUND;
    break;
  case HA_ERR_WRONG_TABLE_DEF:
    textno=ER_WRONG_MRG_TABLE;
    break;
  case HA_ERR_FOUND_DUPP_KEY:
  {
    uint key_nr=get_dup_key(error);
    if ((int) key_nr >= 0)
    {
      /* Write the dupplicated key in the error message */
      char key[MAX_KEY_LENGTH];
      String str(key,sizeof(key));
      key_unpack(&str,table,(uint) key_nr);
unknown's avatar
unknown committed
655
      uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_DUP_ENTRY));
unknown's avatar
unknown committed
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
      if (str.length() >= max_length)
      {
	str.length(max_length-4);
	str.append("...");
      }
      my_error(ER_DUP_ENTRY,MYF(0),str.c_ptr(),key_nr+1);
      DBUG_VOID_RETURN;
    }
    textno=ER_DUP_KEY;
    break;
  }
  case HA_ERR_FOUND_DUPP_UNIQUE:
    textno=ER_DUP_UNIQUE;
    break;
  case HA_ERR_RECORD_CHANGED:
    textno=ER_CHECKREAD;
    break;
  case HA_ERR_CRASHED:
    textno=ER_NOT_KEYFILE;
    break;
676 677 678 679 680 681
  case HA_ERR_CRASHED_ON_USAGE:
    textno=ER_CRASHED_ON_USAGE;
    break;
  case HA_ERR_CRASHED_ON_REPAIR:
    textno=ER_CRASHED_ON_REPAIR;
    break;
unknown's avatar
unknown committed
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
  case HA_ERR_OUT_OF_MEM:
    my_error(ER_OUT_OF_RESOURCES,errflag);
    DBUG_VOID_RETURN;
  case HA_ERR_WRONG_COMMAND:
    textno=ER_ILLEGAL_HA;
    break;
  case HA_ERR_OLD_FILE:
    textno=ER_OLD_KEYFILE;
    break;
  case HA_ERR_UNSUPPORTED:
    textno=ER_UNSUPPORTED_EXTENSION;
    break;
  case HA_ERR_RECORD_FILE_FULL:
    textno=ER_RECORD_FILE_FULL;
    break;
  default:
    {
      my_error(ER_GET_ERRNO,errflag,error);
      DBUG_VOID_RETURN;
    }
  }
  my_error(textno,errflag,table->table_name,error);
  DBUG_VOID_RETURN;
}

	/* Return key if error because of duplicated keys */

uint handler::get_dup_key(int error)
{
711
  DBUG_ENTER("get_dup_key");
unknown's avatar
unknown committed
712 713 714 715 716 717 718 719
  table->file->errkey  = (uint) -1;
  if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
    info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
  DBUG_RETURN(table->file->errkey);
}

int handler::delete_table(const char *name)
{
unknown's avatar
unknown committed
720
  int error=0;
unknown's avatar
unknown committed
721 722 723
  for (const char **ext=bas_ext(); *ext ; ext++)
  {
    if (delete_file(name,*ext,2))
unknown's avatar
unknown committed
724 725 726 727
    {
      if ((error=errno) != ENOENT)
	break;
    }
unknown's avatar
unknown committed
728
  }
unknown's avatar
unknown committed
729
  return error;
unknown's avatar
unknown committed
730 731 732 733 734 735 736 737 738 739 740 741 742 743
}


int handler::rename_table(const char * from, const char * to)
{
  DBUG_ENTER("handler::rename_table");
  for (const char **ext=bas_ext(); *ext ; ext++)
  {
    if (rename_file_ext(from,to,*ext))
      DBUG_RETURN(my_errno);
  }
  DBUG_RETURN(0);
}

744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
int ha_commit_rename(THD *thd)
{
  int error=0;
#ifdef HAVE_GEMINI_DB
    /* Gemini needs to commit the rename; otherwise a rollback will change
    ** the table names back internally but the physical files will still
    ** have the new names.
    */
    if (ha_commit_stmt(thd))
      error= -1;
    if (ha_commit(thd))
      error= -1;
#endif
    return error;
}
unknown's avatar
unknown committed
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799

int handler::index_next_same(byte *buf, const byte *key, uint keylen)
{
  int error;
  if (!(error=index_next(buf)))
  {
    if (key_cmp(table, key, active_index, keylen))
    {
      table->status=STATUS_NOT_FOUND;
      error=HA_ERR_END_OF_FILE;
    }
  }
  return error;
}


/*
  The following is only needed if we would like to use the database
  for internal temporary tables
*/

int handler::delete_all_rows()
{
  return (my_errno=HA_ERR_WRONG_COMMAND);
}

/****************************************************************************
** Some general functions that isn't in the handler class
****************************************************************************/

	/* Initiates table-file and calls apropriate database-creator */
	/* Returns 1 if something got wrong */

int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
		    bool update_create_info)

{
  int error;
  TABLE table;
  DBUG_ENTER("ha_create_table");

800
  if (openfrm(name,"",0,(uint) READ_ALL, 0, &table))
unknown's avatar
unknown committed
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
    DBUG_RETURN(1);
  if (update_create_info)
  {
    update_create_info_from_table(create_info, &table);
    if (table.file->option_flag() & HA_DROP_BEFORE_CREATE)
      table.file->delete_table(name);		// Needed for BDB tables
  }
  error=table.file->create(name,&table,create_info);
  VOID(closefrm(&table));
  if (error)
    my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno);
  DBUG_RETURN(error != 0);
}

	/* Use key cacheing on all databases */

void ha_key_cache(void)
{
  if (keybuff_size)
    (void) init_key_cache(keybuff_size,0);
} /* ha_key_cache */


static int NEAR_F delete_file(const char *name,const char *ext,int extflag)
{
  char buff[FN_REFLEN];
  VOID(fn_format(buff,name,"",ext,extflag | 4));
  return(my_delete(buff,MYF(MY_WME)));
}