~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to sql/handler.cc

  • Committer: bk at mysql
  • Date: 2000-07-31 19:29:14 UTC
  • Revision ID: sp1r-bk@work.mysql.com-20000731192914-08846
Import changeset

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 
2
   
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; either version 2 of the License, or
 
6
   (at your option) any later version.
 
7
   
 
8
   This program is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
   GNU General Public License for more details.
 
12
   
 
13
   You should have received a copy of the GNU General Public License
 
14
   along with this program; if not, write to the Free Software
 
15
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
16
 
 
17
 
 
18
/* Handler-calling-functions */
 
19
 
 
20
#ifdef __GNUC__
 
21
#pragma implementation                          // gcc: Class implementation
 
22
#endif
 
23
 
 
24
#include "mysql_priv.h"
 
25
#include "ha_heap.h"
 
26
#include "ha_myisam.h"
 
27
#include "ha_myisammrg.h"
 
28
#ifndef NO_ISAM
 
29
#include "ha_isam.h"
 
30
#include "ha_isammrg.h"
 
31
#endif
 
32
#ifdef HAVE_BERKELEY_DB
 
33
#include "ha_berkeley.h"
 
34
#endif
 
35
#include <myisampack.h>
 
36
#include <errno.h>
 
37
 
 
38
        /* static functions defined in this file */
 
39
 
 
40
static void NEAR_F set_form_timestamp(TABLE *table, byte *record);
 
41
static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
 
42
 
 
43
ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
 
44
      ha_read_key_count, ha_read_next_count, ha_read_prev_count,
 
45
      ha_read_first_count, ha_read_last_count,
 
46
      ha_read_rnd_count, ha_read_rnd_next_count;
 
47
 
 
48
const char *ha_table_type[] = {
 
49
  "", "DIAB_ISAM","HASH","MISAM","PISAM","RMS_ISAM","HEAP", "ISAM",
 
50
  "MRG_ISAM","MYISAM", "MRG_MYISAM", "BERKELEY_DB?", "?", "?",NullS
 
51
};
 
52
 
 
53
const char *ha_row_type[] = {
 
54
  "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?"
 
55
};
 
56
 
 
57
TYPELIB ha_table_typelib= {array_elements(ha_table_type)-4,"",
 
58
                           ha_table_type+1};
 
59
 
 
60
 
 
61
        /* Use other database handler if databasehandler is not incompiled */
 
62
 
 
63
enum db_type ha_checktype(enum db_type database_type)
 
64
{
 
65
  switch (database_type) {
 
66
#ifdef HAVE_BERKELEY_DB
 
67
  case DB_TYPE_BERKELEY_DB:
 
68
    return(berkeley_skip ? DB_TYPE_MYISAM : database_type);
 
69
#endif
 
70
#ifndef NO_HASH
 
71
  case DB_TYPE_HASH:
 
72
#endif
 
73
#ifndef NO_MERGE
 
74
  case DB_TYPE_MRG_ISAM:
 
75
#endif
 
76
#ifndef NO_ISAM
 
77
  case DB_TYPE_ISAM:
 
78
#endif
 
79
  case DB_TYPE_HEAP:
 
80
  case DB_TYPE_MYISAM:
 
81
  case DB_TYPE_MRG_MYISAM:
 
82
    return (database_type);                     /* Database exists on system */
 
83
  default:
 
84
    break;
 
85
  }
 
86
  return(DB_TYPE_MYISAM);                       /* Use this as default */
 
87
} /* ha_checktype */
 
88
 
 
89
 
 
90
handler *get_new_handler(TABLE *table, enum db_type db_type)
 
91
{
 
92
  switch (db_type) {
 
93
#ifndef NO_HASH
 
94
  return new ha_hash(table);
 
95
#endif
 
96
#ifndef NO_MERGE
 
97
  case DB_TYPE_MRG_ISAM:
 
98
    return new ha_isammrg(table);
 
99
#endif
 
100
#ifndef NO_ISAM
 
101
  case DB_TYPE_ISAM:
 
102
    return new ha_isam(table);
 
103
#endif
 
104
#ifdef HAVE_BERKELEY_DB
 
105
  case DB_TYPE_BERKELEY_DB:
 
106
    return new ha_berkeley(table);
 
107
#endif
 
108
  case DB_TYPE_HEAP:
 
109
    return new ha_heap(table);
 
110
  case DB_TYPE_MYISAM:
 
111
  default:                                      // should never happen
 
112
    return new ha_myisam(table);
 
113
  case DB_TYPE_MRG_MYISAM:
 
114
    return new ha_myisammrg(table);
 
115
  }
 
116
}
 
117
 
 
118
int ha_init()
 
119
{
 
120
#ifdef HAVE_BERKELEY_DB
 
121
  if (!berkeley_skip)
 
122
  {
 
123
    int error;
 
124
    if ((error=berkeley_init()))
 
125
      return error;
 
126
  }
 
127
#endif
 
128
  return 0;
 
129
}
 
130
 
 
131
        /* close, flush or restart databases */
 
132
        /* Ignore this for other databases than ours */
 
133
 
 
134
int ha_panic(enum ha_panic_function flag)
 
135
{
 
136
  int error=0;
 
137
#ifndef NO_MERGE
 
138
  error|=mrg_panic(flag);
 
139
#endif
 
140
#ifndef NO_HASH
 
141
  error|=h_panic(flag);                 /* fix hash */
 
142
#endif
 
143
  error|=heap_panic(flag);
 
144
  error|=nisam_panic(flag);
 
145
  error|=mi_panic(flag);
 
146
  error|=myrg_panic(flag);
 
147
#ifdef HAVE_BERKELEY_DB
 
148
  if (!berkeley_skip)
 
149
    error|=berkeley_end();
 
150
#endif
 
151
  return error;
 
152
} /* ha_panic */
 
153
 
 
154
 
 
155
int ha_autocommit_or_rollback(THD *thd, int error)
 
156
{
 
157
  DBUG_ENTER("ha_autocommit_or_rollback");
 
158
#ifdef HAVE_BERKELEY_DB
 
159
  if ((thd->options & OPTION_AUTO_COMMIT) && !thd->locked_tables)
 
160
  {
 
161
    if (!error)
 
162
    {
 
163
      if (ha_commit(thd))
 
164
        error=1;
 
165
    }   
 
166
    else
 
167
      (void) ha_rollback(thd);
 
168
  }
 
169
#endif
 
170
  DBUG_RETURN(error);
 
171
}
 
172
 
 
173
int ha_commit(THD *thd)
 
174
{
 
175
  int error=0;
 
176
  DBUG_ENTER("commit");
 
177
#ifdef HAVE_BERKELEY_DB
 
178
  if (thd->transaction.bdb_tid)
 
179
  {
 
180
    int error=berkeley_commit(thd);
 
181
    if (error)
 
182
    {
 
183
      my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
 
184
      error=1;
 
185
    }
 
186
  }
 
187
#endif
 
188
  DBUG_RETURN(error);
 
189
}
 
190
 
 
191
int ha_rollback(THD *thd)
 
192
{
 
193
  int error=0;
 
194
  DBUG_ENTER("commit");
 
195
#ifdef HAVE_BERKELEY_DB
 
196
  if (thd->transaction.bdb_tid)
 
197
  {
 
198
    int error=berkeley_rollback(thd);
 
199
    if (error)
 
200
    {
 
201
      my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
 
202
      error=1;
 
203
    }
 
204
  }
 
205
#endif
 
206
  DBUG_RETURN(error);
 
207
}
 
208
 
 
209
 
 
210
bool ha_flush_logs()
 
211
{
 
212
  bool result=0;
 
213
#ifdef HAVE_BERKELEY_DB
 
214
  if (!berkeley_skip && berkeley_flush_logs())
 
215
    result=1;
 
216
#endif
 
217
  return result;
 
218
}
 
219
 
 
220
 
 
221
int ha_delete_table(enum db_type table_type, const char *path)
 
222
{
 
223
  handler *file=get_new_handler((TABLE*) 0, table_type);
 
224
  if (!file)
 
225
    return -1;
 
226
  int error=file->delete_table(path);
 
227
  delete file;
 
228
  return error;
 
229
}
 
230
    
 
231
void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
 
232
{
 
233
  switch (pack_length) {
 
234
#if SIZEOF_OFF_T > 4
 
235
  case 8: mi_int8store(buff,pos); break;
 
236
  case 7: mi_int7store(buff,pos); break;
 
237
  case 6: mi_int6store(buff,pos); break;
 
238
  case 5: mi_int5store(buff,pos); break;
 
239
#endif
 
240
  case 4: mi_int4store(buff,pos); break;
 
241
  case 3: mi_int3store(buff,pos); break;
 
242
  case 2: mi_int2store(buff,(uint) pos); break;
 
243
  case 1: buff[0]= (uchar) pos; break;
 
244
  }
 
245
  return;
 
246
}
 
247
 
 
248
my_off_t ha_get_ptr(byte *ptr, uint pack_length)
 
249
{
 
250
  my_off_t pos;
 
251
  switch (pack_length) {
 
252
#if SIZEOF_OFF_T > 4
 
253
  case 8:
 
254
    pos= (my_off_t) mi_uint8korr(ptr);
 
255
    break;
 
256
  case 7:
 
257
    pos= (my_off_t) mi_uint7korr(ptr);
 
258
    break;
 
259
  case 6:
 
260
    pos= (my_off_t) mi_uint6korr(ptr);
 
261
    break;
 
262
  case 5:
 
263
    pos= (my_off_t) mi_uint5korr(ptr);
 
264
    break;
 
265
#endif
 
266
  case 4:
 
267
    pos= (my_off_t) mi_uint4korr(ptr);
 
268
    break;
 
269
  case 3:
 
270
    pos= (my_off_t) mi_uint3korr(ptr);
 
271
    break;
 
272
  case 2:
 
273
    pos= (my_off_t) mi_uint2korr(ptr);
 
274
    break;
 
275
  case 1:
 
276
    pos= (my_off_t) mi_uint2korr(ptr);
 
277
    break;
 
278
  default:
 
279
    pos=0;                                      // Impossible
 
280
    break;
 
281
  }
 
282
 return pos;
 
283
}
 
284
 
 
285
/****************************************************************************
 
286
** General handler functions
 
287
****************************************************************************/
 
288
 
 
289
        /* Open database-handler. Try O_RDONLY if can't open as O_RDWR */
 
290
        /* Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set */
 
291
 
 
292
int handler::ha_open(const char *name, int mode, int test_if_locked)
 
293
{
 
294
  int error;
 
295
  DBUG_ENTER("handler::open");
 
296
  DBUG_PRINT("enter",("db_type: %d  db_stat: %d  mode: %d  lock_test: %d",
 
297
                      table->db_type, table->db_stat, mode, test_if_locked));
 
298
 
 
299
  if ((error=open(name,mode,test_if_locked)))
 
300
  {
 
301
    if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
 
302
        (table->db_stat & HA_TRY_READ_ONLY))
 
303
    {
 
304
      table->db_stat|=HA_READ_ONLY;
 
305
      error=open(name,O_RDONLY,test_if_locked);
 
306
    }
 
307
  }
 
308
  if (error)
 
309
  {
 
310
    my_errno=error;                     /* Safeguard */
 
311
    DBUG_PRINT("error",("error: %d  errno: %d",error,errno));
 
312
  }
 
313
  else
 
314
  {
 
315
    if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
 
316
      table->db_stat|=HA_READ_ONLY;
 
317
  }
 
318
  if (!error)
 
319
  {
 
320
    
 
321
    if (!(ref=(byte*) my_malloc(ALIGN_SIZE(ref_length)*2,MYF(0))))
 
322
    {
 
323
      close();
 
324
      error=HA_ERR_OUT_OF_MEM;
 
325
    }
 
326
    else
 
327
      dupp_ref=ref+ALIGN_SIZE(ref_length);
 
328
  }
 
329
  DBUG_RETURN(error);
 
330
}
 
331
 
 
332
int handler::check(THD* thd, HA_CHECK_OPT* check_opt)
 
333
{
 
334
  return HA_CHECK_NOT_IMPLEMENTED;
 
335
}
 
336
 
 
337
int handler::repair(THD* thd, HA_CHECK_OPT* check_opt)
 
338
{
 
339
  return HA_REPAIR_NOT_IMPLEMENTED;
 
340
}
 
341
 
 
342
int handler::optimize(THD* thd)
 
343
{
 
344
  return HA_OPTIMIZE_NOT_IMPLEMENTED;
 
345
}
 
346
 
 
347
int handler::analyze(THD* thd)
 
348
{
 
349
  return HA_ANALYZE_NOT_IMPLEMENTED;
 
350
}
 
351
 
 
352
        /* Read first row from a table */
 
353
 
 
354
int handler::rnd_first(byte * buf)
 
355
{
 
356
  register int error;
 
357
  DBUG_ENTER("handler::rnd_first");
 
358
 
 
359
  statistic_increment(ha_read_first_count,&LOCK_status);
 
360
  (void) rnd_init();
 
361
  while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
 
362
  (void) rnd_end();
 
363
  DBUG_RETURN(error);
 
364
}
 
365
 
 
366
 
 
367
/*
 
368
  The following function is only needed for tables that may be temporary tables
 
369
  during joins
 
370
*/
 
371
 
 
372
int handler::restart_rnd_next(byte *buf, byte *pos)
 
373
{
 
374
  return HA_ERR_WRONG_COMMAND;
 
375
}
 
376
 
 
377
 
 
378
        /* Set a timestamp in record */
 
379
 
 
380
void handler::update_timestamp(byte *record)
 
381
{
 
382
  long skr= (long) current_thd->query_start();
 
383
#ifdef WORDS_BIGENDIAN
 
384
  if (table->db_low_byte_first)
 
385
  {
 
386
    int4store(record,skr);
 
387
  }
 
388
  else
 
389
#endif
 
390
  longstore(record,skr);
 
391
  return;
 
392
}
 
393
 
 
394
        /* Updates field with field_type NEXT_NUMBER according to following:
 
395
        ** if field = 0 change field to the next free key in database.
 
396
        */
 
397
 
 
398
void handler::update_auto_increment()
 
399
{
 
400
  longlong nr;
 
401
  THD *thd;
 
402
  DBUG_ENTER("update_auto_increment");
 
403
  if (table->next_number_field->val_int() != 0)
 
404
    DBUG_VOID_RETURN;
 
405
  thd=current_thd;
 
406
  if ((nr=thd->next_insert_id))
 
407
    thd->next_insert_id=0;                      // Clear after use
 
408
  else
 
409
    nr=get_auto_increment();
 
410
  thd->insert_id((ulonglong) nr);
 
411
  table->next_number_field->store(nr);
 
412
  DBUG_VOID_RETURN;
 
413
}
 
414
 
 
415
 
 
416
longlong handler::get_auto_increment()
 
417
{
 
418
  longlong nr;
 
419
  int error;
 
420
  (void) extra(HA_EXTRA_KEYREAD);
 
421
  index_init(table->next_number_index);
 
422
  error=index_last(table->record[1]);
 
423
  if (error)
 
424
    nr=1;
 
425
  else
 
426
    nr=(longlong) table->next_number_field->
 
427
      val_int_offset(table->rec_buff_length)+1;
 
428
  (void) extra(HA_EXTRA_NO_KEYREAD);
 
429
  index_end();
 
430
  return nr;
 
431
}
 
432
 
 
433
        /* Print error that we got from handler function */
 
434
 
 
435
void handler::print_error(int error, myf errflag)
 
436
{
 
437
  DBUG_ENTER("print_error");
 
438
  DBUG_PRINT("enter",("error: %d",error));
 
439
 
 
440
  int textno=ER_GET_ERRNO;
 
441
  switch (error) {
 
442
  case EAGAIN:
 
443
    textno=ER_FILE_USED;
 
444
    break;
 
445
  case ENOENT:
 
446
    textno=ER_FILE_NOT_FOUND;
 
447
    break;
 
448
  case HA_ERR_KEY_NOT_FOUND:
 
449
  case HA_ERR_NO_ACTIVE_RECORD:
 
450
  case HA_ERR_END_OF_FILE:
 
451
    textno=ER_KEY_NOT_FOUND;
 
452
    break;
 
453
  case HA_ERR_WRONG_TABLE_DEF:
 
454
    textno=ER_WRONG_MRG_TABLE;
 
455
    break;
 
456
  case HA_ERR_FOUND_DUPP_KEY:
 
457
  {
 
458
    uint key_nr=get_dup_key(error);
 
459
    if ((int) key_nr >= 0)
 
460
    {
 
461
      /* Write the dupplicated key in the error message */
 
462
      char key[MAX_KEY_LENGTH];
 
463
      String str(key,sizeof(key));
 
464
      key_unpack(&str,table,(uint) key_nr);
 
465
      uint max_length=MYSQL_ERRMSG_SIZE-strlen(ER(ER_DUP_ENTRY));
 
466
      if (str.length() >= max_length)
 
467
      {
 
468
        str.length(max_length-4);
 
469
        str.append("...");
 
470
      }
 
471
      my_error(ER_DUP_ENTRY,MYF(0),str.c_ptr(),key_nr+1);
 
472
      DBUG_VOID_RETURN;
 
473
    }
 
474
    textno=ER_DUP_KEY;
 
475
    break;
 
476
  }
 
477
  case HA_ERR_FOUND_DUPP_UNIQUE:
 
478
    textno=ER_DUP_UNIQUE;
 
479
    break;
 
480
  case HA_ERR_RECORD_CHANGED:
 
481
    textno=ER_CHECKREAD;
 
482
    break;
 
483
  case HA_ERR_CRASHED:
 
484
    textno=ER_NOT_KEYFILE;
 
485
    break;
 
486
  case HA_ERR_OUT_OF_MEM:
 
487
    my_error(ER_OUT_OF_RESOURCES,errflag);
 
488
    DBUG_VOID_RETURN;
 
489
  case HA_ERR_WRONG_COMMAND:
 
490
    textno=ER_ILLEGAL_HA;
 
491
    break;
 
492
  case HA_ERR_OLD_FILE:
 
493
    textno=ER_OLD_KEYFILE;
 
494
    break;
 
495
  case HA_ERR_UNSUPPORTED:
 
496
    textno=ER_UNSUPPORTED_EXTENSION;
 
497
    break;
 
498
  case HA_ERR_RECORD_FILE_FULL:
 
499
    textno=ER_RECORD_FILE_FULL;
 
500
    break;
 
501
  default:
 
502
    {
 
503
      my_error(ER_GET_ERRNO,errflag,error);
 
504
      DBUG_VOID_RETURN;
 
505
    }
 
506
  }
 
507
  my_error(textno,errflag,table->table_name,error);
 
508
  DBUG_VOID_RETURN;
 
509
}
 
510
 
 
511
        /* Return key if error because of duplicated keys */
 
512
 
 
513
uint handler::get_dup_key(int error)
 
514
{
 
515
  DBUG_ENTER("key_error");
 
516
  table->file->errkey  = (uint) -1;
 
517
  if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
 
518
    info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
 
519
  DBUG_RETURN(table->file->errkey);
 
520
}
 
521
 
 
522
int handler::delete_table(const char *name)
 
523
{
 
524
  for (const char **ext=bas_ext(); *ext ; ext++)
 
525
  {
 
526
    if (delete_file(name,*ext,2))
 
527
      return my_errno;
 
528
  }
 
529
  return 0;
 
530
}
 
531
 
 
532
 
 
533
int handler::rename_table(const char * from, const char * to)
 
534
{
 
535
  DBUG_ENTER("handler::rename_table");
 
536
  for (const char **ext=bas_ext(); *ext ; ext++)
 
537
  {
 
538
    if (rename_file_ext(from,to,*ext))
 
539
      DBUG_RETURN(my_errno);
 
540
  }
 
541
  DBUG_RETURN(0);
 
542
}
 
543
 
 
544
 
 
545
int handler::index_next_same(byte *buf, const byte *key, uint keylen)
 
546
{
 
547
  int error;
 
548
  if (!(error=index_next(buf)))
 
549
  {
 
550
    if (key_cmp(table, key, active_index, keylen))
 
551
    {
 
552
      table->status=STATUS_NOT_FOUND;
 
553
      error=HA_ERR_END_OF_FILE;
 
554
    }
 
555
  }
 
556
  return error;
 
557
}
 
558
 
 
559
 
 
560
/*
 
561
  The following is only needed if we would like to use the database
 
562
  for internal temporary tables
 
563
*/
 
564
 
 
565
int handler::delete_all_rows()
 
566
{
 
567
  return (my_errno=HA_ERR_WRONG_COMMAND);
 
568
}
 
569
 
 
570
/****************************************************************************
 
571
** Some general functions that isn't in the handler class
 
572
****************************************************************************/
 
573
 
 
574
        /* Initiates table-file and calls apropriate database-creator */
 
575
        /* Returns 1 if something got wrong */
 
576
 
 
577
int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
 
578
                    bool update_create_info)
 
579
 
 
580
{
 
581
  int error;
 
582
  TABLE table;
 
583
  DBUG_ENTER("ha_create_table");
 
584
 
 
585
  if (openfrm(name,"",0,(uint) READ_ALL,&table))
 
586
    DBUG_RETURN(1);
 
587
  if (update_create_info)
 
588
  {
 
589
    update_create_info_from_table(create_info, &table);
 
590
    if (table.file->option_flag() & HA_DROP_BEFORE_CREATE)
 
591
      table.file->delete_table(name);           // Needed for BDB tables
 
592
  }
 
593
  error=table.file->create(name,&table,create_info);
 
594
  VOID(closefrm(&table));
 
595
  if (error)
 
596
    my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno);
 
597
  DBUG_RETURN(error != 0);
 
598
}
 
599
 
 
600
        /* Use key cacheing on all databases */
 
601
 
 
602
void ha_key_cache(void)
 
603
{
 
604
  if (keybuff_size)
 
605
    (void) init_key_cache(keybuff_size,0);
 
606
} /* ha_key_cache */
 
607
 
 
608
 
 
609
static int NEAR_F delete_file(const char *name,const char *ext,int extflag)
 
610
{
 
611
  char buff[FN_REFLEN];
 
612
  VOID(fn_format(buff,name,"",ext,extflag | 4));
 
613
  return(my_delete(buff,MYF(MY_WME)));
 
614
}