~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL 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; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
17
#ifdef USE_PRAGMA_IMPLEMENTATION
18
#pragma implementation				// gcc: Class implementation
19
#endif
20
21
#define MYSQL_SERVER 1
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
22
#include <drizzled/mysql_priv.h>
212.5.18 by Monty Taylor
Moved m_ctype, m_string and my_bitmap. Removed t_ctype.
23
#include <mystrings/m_ctype.h>
212.5.28 by Monty Taylor
Moved my_bit and my_list
24
#include <mysys/my_bit.h>
1 by brian
clean slate
25
#include <myisampack.h>
26
#include "ha_myisam.h"
27
#include <stdarg.h>
28
#include "myisamdef.h"
202.3.6 by Monty Taylor
First pass at gettexizing the error messages.
29
#include <drizzled/drizzled_error_messages.h>
1 by brian
clean slate
30
31
ulong myisam_recover_options= HA_RECOVER_NONE;
32
33
/* bits in myisam_recover_options */
34
const char *myisam_recover_names[] =
35
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS};
36
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
37
				 myisam_recover_names, NULL};
38
39
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
40
                                           "nulls_ignored", NullS};
41
TYPELIB myisam_stats_method_typelib= {
42
  array_elements(myisam_stats_method_names) - 1, "",
43
  myisam_stats_method_names, NULL};
44
45
46
/*****************************************************************************
47
** MyISAM tables
48
*****************************************************************************/
49
50
static handler *myisam_create_handler(handlerton *hton,
51
                                      TABLE_SHARE *table, 
52
                                      MEM_ROOT *mem_root)
53
{
54
  return new (mem_root) ha_myisam(hton, table);
55
}
56
57
// collect errors printed by mi_check routines
58
59
static void mi_check_print_msg(MI_CHECK *param,	const char* msg_type,
60
			       const char *fmt, va_list args)
61
{
62
  THD* thd = (THD*)param->thd;
63
  Protocol *protocol= thd->protocol;
64
  uint length, msg_length;
65
  char msgbuf[MI_MAX_MSG_BUF];
66
  char name[NAME_LEN*2+2];
67
77.1.18 by Monty Taylor
Removed my_vsnprintf and my_snprintf.
68
  msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
1 by brian
clean slate
69
  msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
70
71
  if (!thd->vio_ok())
72
  {
73
    sql_print_error(msgbuf);
74
    return;
75
  }
76
77
  if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
78
			 T_AUTO_REPAIR))
79
  {
80
    my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
81
    return;
82
  }
83
  length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
84
		 name);
85
  /*
86
    TODO: switch from protocol to push_warning here. The main reason we didn't
87
    it yet is parallel repair. Due to following trace:
88
    mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
89
90
    Also we likely need to lock mutex here (in both cases with protocol and
91
    push_warning).
92
  */
93
  protocol->prepare_for_resend();
94
  protocol->store(name, length, system_charset_info);
95
  protocol->store(param->op_name, system_charset_info);
96
  protocol->store(msg_type, system_charset_info);
97
  protocol->store(msgbuf, msg_length, system_charset_info);
98
  if (protocol->write())
99
    sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
100
		    msgbuf);
101
  return;
102
}
103
104
105
/*
106
  Convert TABLE object to MyISAM key and column definition
107
108
  SYNOPSIS
109
    table2myisam()
110
      table_arg   in     TABLE object.
111
      keydef_out  out    MyISAM key definition.
112
      recinfo_out out    MyISAM column definition.
113
      records_out out    Number of fields.
114
115
  DESCRIPTION
116
    This function will allocate and initialize MyISAM key and column
117
    definition for further use in mi_create or for a check for underlying
118
    table conformance in merge engine.
119
120
    The caller needs to free *recinfo_out after use. Since *recinfo_out
121
    and *keydef_out are allocated with a my_multi_malloc, *keydef_out
122
    is freed automatically when *recinfo_out is freed.
123
124
  RETURN VALUE
125
    0  OK
126
    !0 error code
127
*/
128
129
int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
130
                 MI_COLUMNDEF **recinfo_out, uint *records_out)
131
{
132
  uint i, j, recpos, minpos, fieldpos, temp_length, length;
133
  enum ha_base_keytype type= HA_KEYTYPE_BINARY;
134
  uchar *record;
135
  KEY *pos;
136
  MI_KEYDEF *keydef;
137
  MI_COLUMNDEF *recinfo, *recinfo_pos;
138
  HA_KEYSEG *keyseg;
139
  TABLE_SHARE *share= table_arg->s;
140
  uint options= share->db_options_in_use;
141
  if (!(my_multi_malloc(MYF(MY_WME),
142
          recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
143
          keydef_out, share->keys * sizeof(MI_KEYDEF),
144
          &keyseg,
145
          (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
146
          NullS)))
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
147
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
1 by brian
clean slate
148
  keydef= *keydef_out;
149
  recinfo= *recinfo_out;
150
  pos= table_arg->key_info;
151
  for (i= 0; i < share->keys; i++, pos++)
152
  {
249 by Brian Aker
Random key cleanup (it is a friday...)
153
    keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
154
    keydef[i].key_alg= HA_KEY_ALG_BTREE;
1 by brian
clean slate
155
    keydef[i].block_length= pos->block_size;
156
    keydef[i].seg= keyseg;
157
    keydef[i].keysegs= pos->key_parts;
158
    for (j= 0; j < pos->key_parts; j++)
159
    {
160
      Field *field= pos->key_part[j].field;
161
      type= field->key_type();
162
      keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
163
164
      if (options & HA_OPTION_PACK_KEYS ||
165
          (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
166
                         HA_SPACE_PACK_USED)))
167
      {
168
        if (pos->key_part[j].length > 8 &&
169
            (type == HA_KEYTYPE_TEXT ||
170
             type == HA_KEYTYPE_NUM ||
171
             (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
172
        {
173
          /* No blobs here */
174
          if (j == 0)
175
            keydef[i].flag|= HA_PACK_KEY;
241 by Brian Aker
First pass of CHAR removal.
176
          if ((((int) (pos->key_part[j].length - field->decimals())) >= 4))
1 by brian
clean slate
177
            keydef[i].seg[j].flag|= HA_SPACE_PACK;
178
        }
179
        else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
180
          keydef[i].flag|= HA_BINARY_PACK_KEY;
181
      }
182
      keydef[i].seg[j].type= (int) type;
183
      keydef[i].seg[j].start= pos->key_part[j].offset;
184
      keydef[i].seg[j].length= pos->key_part[j].length;
185
      keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
186
        keydef[i].seg[j].bit_length= 0;
187
      keydef[i].seg[j].bit_pos= 0;
188
      keydef[i].seg[j].language= field->charset()->number;
189
190
      if (field->null_ptr)
191
      {
192
        keydef[i].seg[j].null_bit= field->null_bit;
193
        keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
194
                                           (uchar*) table_arg->record[0]);
195
      }
196
      else
197
      {
198
        keydef[i].seg[j].null_bit= 0;
199
        keydef[i].seg[j].null_pos= 0;
200
      }
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
201
      if (field->type() == DRIZZLE_TYPE_BLOB)
1 by brian
clean slate
202
      {
203
        keydef[i].seg[j].flag|= HA_BLOB_PART;
204
        /* save number of bytes used to pack length */
205
        keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
206
                                            share->blob_ptr_size);
207
      }
208
    }
209
    keyseg+= pos->key_parts;
210
  }
211
  if (table_arg->found_next_number_field)
212
    keydef[share->next_number_index].flag|= HA_AUTO_KEY;
213
  record= table_arg->record[0];
214
  recpos= 0;
215
  recinfo_pos= recinfo;
216
  while (recpos < (uint) share->reclength)
217
  {
218
    Field **field, *found= 0;
219
    minpos= share->reclength;
220
    length= 0;
221
222
    for (field= table_arg->field; *field; field++)
223
    {
224
      if ((fieldpos= (*field)->offset(record)) >= recpos &&
225
          fieldpos <= minpos)
226
      {
227
        /* skip null fields */
228
        if (!(temp_length= (*field)->pack_length_in_rec()))
229
          continue; /* Skip null-fields */
230
        if (! found || fieldpos < minpos ||
231
            (fieldpos == minpos && temp_length < length))
232
        {
233
          minpos= fieldpos;
234
          found= *field;
235
          length= temp_length;
236
        }
237
      }
238
    }
239
    if (recpos != minpos)
240
    { // Reserved space (Null bits?)
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
241
      memset((char*) recinfo_pos, 0, sizeof(*recinfo_pos));
1 by brian
clean slate
242
      recinfo_pos->type= (int) FIELD_NORMAL;
206 by Brian Aker
Removed final uint dead types.
243
      recinfo_pos++->length= (uint16_t) (minpos - recpos);
1 by brian
clean slate
244
    }
245
    if (!found)
246
      break;
247
248
    if (found->flags & BLOB_FLAG)
249
      recinfo_pos->type= (int) FIELD_BLOB;
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
250
    else if (found->type() == DRIZZLE_TYPE_VARCHAR)
1 by brian
clean slate
251
      recinfo_pos->type= FIELD_VARCHAR;
252
    else if (!(options & HA_OPTION_PACK_RECORD))
253
      recinfo_pos->type= (int) FIELD_NORMAL;
254
    else if (found->zero_pack())
255
      recinfo_pos->type= (int) FIELD_SKIP_ZERO;
256
    else
241 by Brian Aker
First pass of CHAR removal.
257
      recinfo_pos->type= (int) ((length <= 3) ?  FIELD_NORMAL : FIELD_SKIP_PRESPACE);
1 by brian
clean slate
258
    if (found->null_ptr)
259
    {
260
      recinfo_pos->null_bit= found->null_bit;
261
      recinfo_pos->null_pos= (uint) (found->null_ptr -
262
                                     (uchar*) table_arg->record[0]);
263
    }
264
    else
265
    {
266
      recinfo_pos->null_bit= 0;
267
      recinfo_pos->null_pos= 0;
268
    }
206 by Brian Aker
Removed final uint dead types.
269
    (recinfo_pos++)->length= (uint16_t) length;
1 by brian
clean slate
270
    recpos= minpos + length;
271
  }
272
  *records_out= (uint) (recinfo_pos - recinfo);
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
273
  return(0);
1 by brian
clean slate
274
}
275
276
277
/*
278
  Check for underlying table conformance
279
280
  SYNOPSIS
281
    check_definition()
282
      t1_keyinfo       in    First table key definition
283
      t1_recinfo       in    First table record definition
284
      t1_keys          in    Number of keys in first table
285
      t1_recs          in    Number of records in first table
286
      t2_keyinfo       in    Second table key definition
287
      t2_recinfo       in    Second table record definition
288
      t2_keys          in    Number of keys in second table
289
      t2_recs          in    Number of records in second table
290
      strict           in    Strict check switch
291
292
  DESCRIPTION
293
    This function compares two MyISAM definitions. By intention it was done
294
    to compare merge table definition against underlying table definition.
295
    It may also be used to compare dot-frm and MYI definitions of MyISAM
296
    table as well to compare different MyISAM table definitions.
297
298
    For merge table it is not required that number of keys in merge table
299
    must exactly match number of keys in underlying table. When calling this
300
    function for underlying table conformance check, 'strict' flag must be
301
    set to false, and converted merge definition must be passed as t1_*.
302
303
    Otherwise 'strict' flag must be set to 1 and it is not required to pass
304
    converted dot-frm definition as t1_*.
305
306
  RETURN VALUE
307
    0 - Equal definitions.
308
    1 - Different definitions.
309
310
  TODO
311
    - compare FULLTEXT keys;
312
    - compare SPATIAL keys;
313
    - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
314
      (should be corretly detected in table2myisam).
315
*/
316
317
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
318
                     uint t1_keys, uint t1_recs,
319
                     MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
320
                     uint t2_keys, uint t2_recs, bool strict)
321
{
322
  uint i, j;
323
  if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
324
  {
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
325
    return(1);
1 by brian
clean slate
326
  }
327
  if (t1_recs != t2_recs)
328
  {
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
329
    return(1);
1 by brian
clean slate
330
  }
331
  for (i= 0; i < t1_keys; i++)
332
  {
333
    HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
334
    HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
335
    if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
336
        t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
337
    {
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
338
      return(1);
1 by brian
clean slate
339
    }
340
    for (j=  t1_keyinfo[i].keysegs; j--;)
341
    {
206 by Brian Aker
Removed final uint dead types.
342
      uint8_t t1_keysegs_j__type= t1_keysegs[j].type;
1 by brian
clean slate
343
344
      /*
345
        Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
346
        always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
347
        HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
348
        level, we can ignore a mismatch between these types.
349
      */
350
      if ((t1_keysegs[j].flag & HA_BLOB_PART) &&
351
          (t2_keysegs[j].flag & HA_BLOB_PART))
352
      {
353
        if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
354
            (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
355
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
356
        else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
357
                 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
358
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
359
      }
360
361
      if (t1_keysegs_j__type != t2_keysegs[j].type ||
362
          t1_keysegs[j].language != t2_keysegs[j].language ||
363
          t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
364
          t1_keysegs[j].length != t2_keysegs[j].length)
365
      {
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
366
        return(1);
1 by brian
clean slate
367
      }
368
    }
369
  }
370
  for (i= 0; i < t1_recs; i++)
371
  {
372
    MI_COLUMNDEF *t1_rec= &t1_recinfo[i];
373
    MI_COLUMNDEF *t2_rec= &t2_recinfo[i];
374
    /*
375
      FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create,
376
      see NOTE1 in mi_create.c
377
    */
378
    if ((t1_rec->type != t2_rec->type &&
379
         !(t1_rec->type == (int) FIELD_SKIP_ZERO &&
380
           t1_rec->length == 1 &&
381
           t2_rec->type == (int) FIELD_NORMAL)) ||
382
        t1_rec->length != t2_rec->length ||
383
        t1_rec->null_bit != t2_rec->null_bit)
384
    {
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
385
      return(1);
1 by brian
clean slate
386
    }
387
  }
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
388
  return(0);
1 by brian
clean slate
389
}
390
391
392
extern "C" {
393
394
volatile int *killed_ptr(MI_CHECK *param)
395
{
396
  /* In theory Unsafe conversion, but should be ok for now */
397
  return (int*) &(((THD *)(param->thd))->killed);
398
}
399
400
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
401
{
402
  param->error_printed|=1;
403
  param->out_flag|= O_DATA_LOST;
404
  va_list args;
405
  va_start(args, fmt);
406
  mi_check_print_msg(param, "error", fmt, args);
407
  va_end(args);
408
}
409
410
void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
411
{
412
  va_list args;
413
  va_start(args, fmt);
414
  mi_check_print_msg(param, "info", fmt, args);
415
  va_end(args);
416
}
417
418
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
419
{
420
  param->warning_printed=1;
421
  param->out_flag|= O_DATA_LOST;
422
  va_list args;
423
  va_start(args, fmt);
424
  mi_check_print_msg(param, "warning", fmt, args);
425
  va_end(args);
426
}
427
428
/**
429
  Report list of threads (and queries) accessing a table, thread_id of a
430
  thread that detected corruption, ource file name and line number where
431
  this corruption was detected, optional extra information (string).
432
433
  This function is intended to be used when table corruption is detected.
434
435
  @param[in] file      MI_INFO object.
436
  @param[in] message   Optional error message.
437
  @param[in] sfile     Name of source file.
438
  @param[in] sline     Line number in source file.
439
440
  @return void
441
*/
442
443
void _mi_report_crashed(MI_INFO *file, const char *message,
444
                        const char *sfile, uint sline)
445
{
446
  THD *cur_thd;
447
  LIST *element;
448
  char buf[1024];
449
  pthread_mutex_lock(&file->s->intern_lock);
450
  if ((cur_thd= (THD*) file->in_use.data))
451
    sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id,
452
                    sfile, sline);
453
  else
454
    sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline);
455
  if (message)
456
    sql_print_error("%s", message);
457
  for (element= file->s->in_use; element; element= list_rest(element))
458
  {
459
    THD *thd= (THD*) element->data;
460
    sql_print_error("%s", thd ? thd_security_context(thd, buf, sizeof(buf), 0)
461
                              : "Unknown thread accessing table");
462
  }
463
  pthread_mutex_unlock(&file->s->intern_lock);
464
}
465
77.1.13 by Monty Taylor
Fixed wonky linkage thing.
466
}
1 by brian
clean slate
467
468
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
469
  :handler(hton, table_arg), file(0),
470
  int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
471
                  HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
472
                  HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
473
                  HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
474
                  HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
475
                  HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
476
                  HA_NEED_READ_RANGE_BUFFER | HA_MRR_CANT_SORT),
477
   can_enable_indexes(1)
478
{}
479
480
handler *ha_myisam::clone(MEM_ROOT *mem_root)
481
{
482
  ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
483
  if (new_handler)
484
    new_handler->file->state= file->state;
485
  return new_handler;
486
}
487
488
489
static const char *ha_myisam_exts[] = {
490
  ".MYI",
491
  ".MYD",
492
  NullS
493
};
494
495
const char **ha_myisam::bas_ext() const
496
{
497
  return ha_myisam_exts;
498
}
499
500
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
501
const char *ha_myisam::index_type(uint key_number __attribute__((unused)))
1 by brian
clean slate
502
{
74 by Brian Aker
More removal of FT from MyISAM
503
  return "BTREE";
1 by brian
clean slate
504
}
505
506
/* Name is here without an extension */
507
int ha_myisam::open(const char *name, int mode, uint test_if_locked)
508
{
509
  MI_KEYDEF *keyinfo;
510
  MI_COLUMNDEF *recinfo= 0;
511
  uint recs;
512
  uint i;
513
514
  /*
515
    If the user wants to have memory mapped data files, add an
516
    open_flag. Do not memory map temporary tables because they are
517
    expected to be inserted and thus extended a lot. Memory mapping is
518
    efficient for files that keep their size, but very inefficient for
519
    growing files. Using an open_flag instead of calling mi_extra(...
520
    HA_EXTRA_MMAP ...) after mi_open() has the advantage that the
521
    mapping is not repeated for every open, but just done on the initial
522
    open, when the MyISAM share is created. Everytime the server
523
    requires to open a new instance of a table it calls this method. We
524
    will always supply HA_OPEN_MMAP for a permanent table. However, the
525
    MyISAM storage engine will ignore this flag if this is a secondary
526
    open of a table that is in use by other threads already (if the
527
    MyISAM share exists already).
528
  */
529
  if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
530
    return (my_errno ? my_errno : -1);
531
  if (!table->s->tmp_table) /* No need to perform a check for tmp table */
532
  {
533
    if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
534
    {
535
      /* purecov: begin inspected */
536
      goto err;
537
      /* purecov: end */
538
    }
539
    if (check_definition(keyinfo, recinfo, table->s->keys, recs,
540
                         file->s->keyinfo, file->s->rec,
541
                         file->s->base.keys, file->s->base.fields, true))
542
    {
543
      /* purecov: begin inspected */
544
      my_errno= HA_ERR_CRASHED;
545
      goto err;
546
      /* purecov: end */
547
    }
548
  }
549
  
550
  if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
551
    VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
552
553
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
554
  if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
555
    VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
556
  if (!table->s->db_record_offset)
557
    int_table_flags|=HA_REC_NOT_IN_SEQ;
558
  if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
559
    int_table_flags|=HA_HAS_CHECKSUM;
560
  
561
  keys_with_parts.clear_all();
562
  for (i= 0; i < table->s->keys; i++)
563
  {
564
    table->key_info[i].block_size= file->s->keyinfo[i].block_length;
565
566
    KEY_PART_INFO *kp= table->key_info[i].key_part;
567
    KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
568
    for (; kp != kp_end; kp++)
569
    {
570
      if (!kp->field->part_of_key.is_set(i))
571
      {
572
        keys_with_parts.set_bit(i);
573
        break;
574
      }
575
    }
576
  }
577
  my_errno= 0;
578
  goto end;
579
 err:
580
  this->close();
581
 end:
582
  /*
583
    Both recinfo and keydef are allocated by my_multi_malloc(), thus only
584
    recinfo must be freed.
585
  */
586
  if (recinfo)
587
    my_free((uchar*) recinfo, MYF(0));
588
  return my_errno;
589
}
590
591
int ha_myisam::close(void)
592
{
593
  MI_INFO *tmp=file;
594
  file=0;
595
  return mi_close(tmp);
596
}
597
598
int ha_myisam::write_row(uchar *buf)
599
{
600
  ha_statistic_increment(&SSV::ha_write_count);
601
602
  /* If we have a timestamp column, update it to the current time */
603
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
604
    table->timestamp_field->set_time();
605
606
  /*
607
    If we have an auto_increment column and we are writing a changed row
608
    or a new row, then update the auto_increment value in the record.
609
  */
610
  if (table->next_number_field && buf == table->record[0])
611
  {
612
    int error;
613
    if ((error= update_auto_increment()))
614
      return error;
615
  }
616
  return mi_write(file,buf);
617
}
618
619
int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
620
{
621
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
622
  int error;
623
  MI_CHECK param;
624
  MYISAM_SHARE* share = file->s;
625
  const char *old_proc_info=thd->proc_info;
626
627
  thd_proc_info(thd, "Checking table");
628
  myisamchk_init(&param);
629
  param.thd = thd;
630
  param.op_name =   "check";
631
  param.db_name=    table->s->db.str;
632
  param.table_name= table->alias;
633
  param.testflag = check_opt->flags | T_CHECK | T_SILENT;
634
  param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
635
636
  if (!(table->db_stat & HA_READ_ONLY))
637
    param.testflag|= T_STATISTICS;
638
  param.using_global_keycache = 1;
639
640
  if (!mi_is_crashed(file) &&
641
      (((param.testflag & T_CHECK_ONLY_CHANGED) &&
642
	!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
643
				  STATE_CRASHED_ON_REPAIR)) &&
644
	share->state.open_count == 0) ||
645
       ((param.testflag & T_FAST) && (share->state.open_count ==
646
				      (uint) (share->global_changed ? 1 : 0)))))
647
    return HA_ADMIN_ALREADY_DONE;
648
649
  error = chk_status(&param, file);		// Not fatal
650
  error = chk_size(&param, file);
651
  if (!error)
652
    error |= chk_del(&param, file, param.testflag);
653
  if (!error)
654
    error = chk_key(&param, file);
655
  if (!error)
656
  {
657
    if ((!(param.testflag & T_QUICK) &&
658
	 ((share->options &
659
	   (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
660
	  (param.testflag & (T_EXTEND | T_MEDIUM)))) ||
661
	mi_is_crashed(file))
662
    {
663
      uint old_testflag=param.testflag;
664
      param.testflag|=T_MEDIUM;
665
      if (!(error= init_io_cache(&param.read_cache, file->dfile,
666
                                 my_default_record_cache_size, READ_CACHE,
667
                                 share->pack.header_length, 1, MYF(MY_WME))))
668
      {
669
        error= chk_data_link(&param, file, param.testflag & T_EXTEND);
670
        end_io_cache(&(param.read_cache));
671
      }
672
      param.testflag= old_testflag;
673
    }
674
  }
675
  if (!error)
676
  {
677
    if ((share->state.changed & (STATE_CHANGED |
678
				 STATE_CRASHED_ON_REPAIR |
679
				 STATE_CRASHED | STATE_NOT_ANALYZED)) ||
680
	(param.testflag & T_STATISTICS) ||
681
	mi_is_crashed(file))
682
    {
683
      file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
684
      pthread_mutex_lock(&share->intern_lock);
685
      share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
686
			       STATE_CRASHED_ON_REPAIR);
687
      if (!(table->db_stat & HA_READ_ONLY))
688
	error=update_state_info(&param,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
689
				UPDATE_STAT);
690
      pthread_mutex_unlock(&share->intern_lock);
691
      info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
692
	   HA_STATUS_CONST);
693
    }
694
  }
695
  else if (!mi_is_crashed(file) && !thd->killed)
696
  {
697
    mi_mark_crashed(file);
698
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
699
  }
700
701
  thd_proc_info(thd, old_proc_info);
702
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
703
}
704
705
706
/*
707
  analyze the key distribution in the table
708
  As the table may be only locked for read, we have to take into account that
709
  two threads may do an analyze at the same time!
710
*/
711
77.1.9 by Monty Taylor
All of storage/ compiles clean now.
712
int ha_myisam::analyze(THD *thd,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
713
                       HA_CHECK_OPT* check_opt __attribute__((unused)))
1 by brian
clean slate
714
{
715
  int error=0;
716
  MI_CHECK param;
717
  MYISAM_SHARE* share = file->s;
718
719
  myisamchk_init(&param);
720
  param.thd = thd;
721
  param.op_name=    "analyze";
722
  param.db_name=    table->s->db.str;
723
  param.table_name= table->alias;
724
  param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
725
                   T_DONT_CHECK_CHECKSUM);
726
  param.using_global_keycache = 1;
727
  param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
728
729
  if (!(share->state.changed & STATE_NOT_ANALYZED))
730
    return HA_ADMIN_ALREADY_DONE;
731
732
  error = chk_key(&param, file);
733
  if (!error)
734
  {
735
    pthread_mutex_lock(&share->intern_lock);
736
    error=update_state_info(&param,file,UPDATE_STAT);
737
    pthread_mutex_unlock(&share->intern_lock);
738
  }
739
  else if (!mi_is_crashed(file) && !thd->killed)
740
    mi_mark_crashed(file);
741
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
742
}
743
744
745
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
746
{
747
  int error;
748
  MI_CHECK param;
749
  ha_rows start_records;
750
751
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
752
753
  myisamchk_init(&param);
754
  param.thd = thd;
755
  param.op_name=  "repair";
756
  param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
757
                   T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
758
                   (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
759
  param.sort_buffer_length=  check_opt->sort_buffer_size;
760
  start_records=file->state->records;
761
  while ((error=repair(thd,param,0)) && param.retry_repair)
762
  {
763
    param.retry_repair=0;
764
    if (test_all_bits(param.testflag,
765
		      (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
766
    {
767
      param.testflag&= ~T_RETRY_WITHOUT_QUICK;
768
      sql_print_information("Retrying repair of: '%s' without quick",
769
                            table->s->path.str);
770
      continue;
771
    }
772
    param.testflag&= ~T_QUICK;
773
    if ((param.testflag & T_REP_BY_SORT))
774
    {
775
      param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
776
      sql_print_information("Retrying repair of: '%s' with keycache",
777
                            table->s->path.str);
778
      continue;
779
    }
780
    break;
781
  }
782
  if (!error && start_records != file->state->records &&
783
      !(check_opt->flags & T_VERY_SILENT))
784
  {
785
    char llbuff[22],llbuff2[22];
786
    sql_print_information("Found %s of %s rows when repairing '%s'",
787
                          llstr(file->state->records, llbuff),
788
                          llstr(start_records, llbuff2),
789
                          table->s->path.str);
790
  }
791
  return error;
792
}
793
794
int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
795
{
796
  int error;
797
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
798
  MI_CHECK param;
799
800
  myisamchk_init(&param);
801
  param.thd = thd;
802
  param.op_name= "optimize";
803
  param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
804
                   T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
805
  param.sort_buffer_length=  check_opt->sort_buffer_size;
806
  if ((error= repair(thd,param,1)) && param.retry_repair)
807
  {
808
    sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
809
                      my_errno, param.db_name, param.table_name);
810
    param.testflag&= ~T_REP_BY_SORT;
811
    error= repair(thd,param,1);
812
  }
813
  return error;
814
}
815
816
817
int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
818
{
819
  int error=0;
820
  uint local_testflag=param.testflag;
821
  bool optimize_done= !do_optimize, statistics_done=0;
822
  const char *old_proc_info=thd->proc_info;
823
  char fixed_name[FN_REFLEN];
824
  MYISAM_SHARE* share = file->s;
825
  ha_rows rows= file->state->records;
826
827
  /*
828
    Normally this method is entered with a properly opened table. If the
829
    repair fails, it can be repeated with more elaborate options. Under
830
    special circumstances it can happen that a repair fails so that it
831
    closed the data file and cannot re-open it. In this case file->dfile
832
    is set to -1. We must not try another repair without an open data
833
    file. (Bug #25289)
834
  */
835
  if (file->dfile == -1)
836
  {
837
    sql_print_information("Retrying repair of: '%s' failed. "
838
                          "Please try REPAIR EXTENDED or myisamchk",
839
                          table->s->path.str);
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
840
    return(HA_ADMIN_FAILED);
1 by brian
clean slate
841
  }
842
843
  param.db_name=    table->s->db.str;
844
  param.table_name= table->alias;
845
  param.tmpfile_createflag = O_RDWR | O_TRUNC;
846
  param.using_global_keycache = 1;
847
  param.thd= thd;
848
  param.tmpdir= &mysql_tmpdir_list;
849
  param.out_flag= 0;
850
  strmov(fixed_name,file->filename);
851
852
  // Don't lock tables if we have used LOCK TABLE
853
  if (!thd->locked_tables && 
854
      mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
855
  {
856
    mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
857
    return(HA_ADMIN_FAILED);
1 by brian
clean slate
858
  }
859
860
  if (!do_optimize ||
861
      ((file->state->del || share->state.split != file->state->records) &&
862
       (!(param.testflag & T_QUICK) ||
863
	!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
864
  {
865
    uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
866
			mi_get_mask_all_keys_active(share->base.keys) :
867
			share->state.key_map);
868
    uint testflag=param.testflag;
869
    if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
870
	(local_testflag & T_REP_BY_SORT))
871
    {
872
      local_testflag|= T_STATISTICS;
873
      param.testflag|= T_STATISTICS;		// We get this for free
874
      statistics_done=1;
875
      if (thd->variables.myisam_repair_threads>1)
876
      {
877
        char buf[40];
878
        /* TODO: respect myisam_repair_threads variable */
77.1.18 by Monty Taylor
Removed my_vsnprintf and my_snprintf.
879
        snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
1 by brian
clean slate
880
        thd_proc_info(thd, buf);
881
        error = mi_repair_parallel(&param, file, fixed_name,
882
            param.testflag & T_QUICK);
883
        thd_proc_info(thd, "Repair done"); // to reset proc_info, as
884
                                      // it was pointing to local buffer
885
      }
886
      else
887
      {
888
        thd_proc_info(thd, "Repair by sorting");
889
        error = mi_repair_by_sort(&param, file, fixed_name,
890
            param.testflag & T_QUICK);
891
      }
892
    }
893
    else
894
    {
895
      thd_proc_info(thd, "Repair with keycache");
896
      param.testflag &= ~T_REP_BY_SORT;
897
      error=  mi_repair(&param, file, fixed_name,
898
			param.testflag & T_QUICK);
899
    }
900
    param.testflag=testflag;
901
    optimize_done=1;
902
  }
903
  if (!error)
904
  {
905
    if ((local_testflag & T_SORT_INDEX) &&
906
	(share->state.changed & STATE_NOT_SORTED_PAGES))
907
    {
908
      optimize_done=1;
909
      thd_proc_info(thd, "Sorting index");
910
      error=mi_sort_index(&param,file,fixed_name);
911
    }
912
    if (!statistics_done && (local_testflag & T_STATISTICS))
913
    {
914
      if (share->state.changed & STATE_NOT_ANALYZED)
915
      {
916
	optimize_done=1;
917
	thd_proc_info(thd, "Analyzing");
918
	error = chk_key(&param, file);
919
      }
920
      else
921
	local_testflag&= ~T_STATISTICS;		// Don't update statistics
922
    }
923
  }
924
  thd_proc_info(thd, "Saving state");
925
  if (!error)
926
  {
927
    if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file))
928
    {
929
      share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
930
			       STATE_CRASHED_ON_REPAIR);
931
      file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
932
    }
933
    /*
934
      the following 'if', thought conceptually wrong,
935
      is a useful optimization nevertheless.
936
    */
937
    if (file->state != &file->s->state.state)
938
      file->s->state.state = *file->state;
939
    if (file->s->base.auto_key)
940
      update_auto_increment_key(&param, file, 1);
941
    if (optimize_done)
942
      error = update_state_info(&param, file,
943
				UPDATE_TIME | UPDATE_OPEN_COUNT |
944
				(local_testflag &
945
				 T_STATISTICS ? UPDATE_STAT : 0));
946
    info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
947
	 HA_STATUS_CONST);
948
    if (rows != file->state->records && ! (param.testflag & T_VERY_SILENT))
949
    {
950
      char llbuff[22],llbuff2[22];
951
      mi_check_print_warning(&param,"Number of rows changed from %s to %s",
952
			     llstr(rows,llbuff),
953
			     llstr(file->state->records,llbuff2));
954
    }
955
  }
956
  else
957
  {
958
    mi_mark_crashed_on_repair(file);
959
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
960
    update_state_info(&param, file, 0);
961
  }
962
  thd_proc_info(thd, old_proc_info);
963
  if (!thd->locked_tables)
964
    mi_lock_database(file,F_UNLCK);
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
965
  return(error ? HA_ADMIN_FAILED :
1 by brian
clean slate
966
	      !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
967
}
968
969
970
/*
971
  Assign table indexes to a specific key cache.
972
*/
973
974
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
975
{
976
  KEY_CACHE *new_key_cache= check_opt->key_cache;
977
  const char *errmsg= 0;
978
  int error= HA_ADMIN_OK;
979
  uint64_t map;
980
  TABLE_LIST *table_list= table->pos_in_table_list;
981
982
  table->keys_in_use_for_query.clear_all();
983
984
  if (table_list->process_index_hints(table))
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
985
    return(HA_ADMIN_FAILED);
1 by brian
clean slate
986
  map= ~(uint64_t) 0;
987
  if (!table->keys_in_use_for_query.is_clear_all())
988
    /* use all keys if there's no list specified by the user through hints */
151 by Brian Aker
Ulonglong to uint64_t
989
    map= table->keys_in_use_for_query.to_uint64_t();
1 by brian
clean slate
990
991
  if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
992
  { 
993
    char buf[STRING_BUFFER_USUAL_SIZE];
77.1.18 by Monty Taylor
Removed my_vsnprintf and my_snprintf.
994
    snprintf(buf, sizeof(buf),
1 by brian
clean slate
995
		"Failed to flush to index file (errno: %d)", error);
996
    errmsg= buf;
997
    error= HA_ADMIN_CORRUPT;
998
  }
999
1000
  if (error != HA_ADMIN_OK)
1001
  {
1002
    /* Send error to user */
1003
    MI_CHECK param;
1004
    myisamchk_init(&param);
1005
    param.thd= thd;
1006
    param.op_name=    "assign_to_keycache";
1007
    param.db_name=    table->s->db.str;
1008
    param.table_name= table->s->table_name.str;
1009
    param.testflag= 0;
1010
    mi_check_print_error(&param, errmsg);
1011
  }
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1012
  return(error);
1 by brian
clean slate
1013
}
1014
1015
1016
/*
1017
  Disable indexes, making it persistent if requested.
1018
1019
  SYNOPSIS
1020
    disable_indexes()
1021
    mode        mode of operation:
1022
                HA_KEY_SWITCH_NONUNIQ      disable all non-unique keys
1023
                HA_KEY_SWITCH_ALL          disable all keys
1024
                HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
1025
                HA_KEY_SWITCH_ALL_SAVE     dis. all keys and make persistent
1026
1027
  IMPLEMENTATION
1028
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
1029
    HA_KEY_SWITCH_ALL_SAVE      is not implemented.
1030
1031
  RETURN
1032
    0  ok
1033
    HA_ERR_WRONG_COMMAND  mode not implemented.
1034
*/
1035
1036
int ha_myisam::disable_indexes(uint mode)
1037
{
1038
  int error;
1039
1040
  if (mode == HA_KEY_SWITCH_ALL)
1041
  {
1042
    /* call a storage engine function to switch the key map */
1043
    error= mi_disable_indexes(file);
1044
  }
1045
  else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1046
  {
1047
    mi_extra(file, HA_EXTRA_NO_KEYS, 0);
1048
    info(HA_STATUS_CONST);                        // Read new key info
1049
    error= 0;
1050
  }
1051
  else
1052
  {
1053
    /* mode not implemented */
1054
    error= HA_ERR_WRONG_COMMAND;
1055
  }
1056
  return error;
1057
}
1058
1059
1060
/*
1061
  Enable indexes, making it persistent if requested.
1062
1063
  SYNOPSIS
1064
    enable_indexes()
1065
    mode        mode of operation:
1066
                HA_KEY_SWITCH_NONUNIQ      enable all non-unique keys
1067
                HA_KEY_SWITCH_ALL          enable all keys
1068
                HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
1069
                HA_KEY_SWITCH_ALL_SAVE     en. all keys and make persistent
1070
1071
  DESCRIPTION
1072
    Enable indexes, which might have been disabled by disable_index() before.
1073
    The modes without _SAVE work only if both data and indexes are empty,
1074
    since the MyISAM repair would enable them persistently.
1075
    To be sure in these cases, call handler::delete_all_rows() before.
1076
1077
  IMPLEMENTATION
1078
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
1079
    HA_KEY_SWITCH_ALL_SAVE      is not implemented.
1080
1081
  RETURN
1082
    0  ok
1083
    !=0  Error, among others:
1084
    HA_ERR_CRASHED  data or index is non-empty. Delete all rows and retry.
1085
    HA_ERR_WRONG_COMMAND  mode not implemented.
1086
*/
1087
1088
int ha_myisam::enable_indexes(uint mode)
1089
{
1090
  int error;
1091
1092
  if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
1093
  {
1094
    /* All indexes are enabled already. */
1095
    return 0;
1096
  }
1097
1098
  if (mode == HA_KEY_SWITCH_ALL)
1099
  {
1100
    error= mi_enable_indexes(file);
1101
    /*
1102
       Do not try to repair on error,
1103
       as this could make the enabled state persistent,
1104
       but mode==HA_KEY_SWITCH_ALL forbids it.
1105
    */
1106
  }
1107
  else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1108
  {
1109
    THD *thd=current_thd;
1110
    MI_CHECK param;
1111
    const char *save_proc_info=thd->proc_info;
1112
    thd_proc_info(thd, "Creating index");
1113
    myisamchk_init(&param);
1114
    param.op_name= "recreating_index";
1115
    param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
1116
                     T_CREATE_MISSING_KEYS);
1117
    param.myf_rw&= ~MY_WAIT_IF_FULL;
1118
    param.sort_buffer_length=  thd->variables.myisam_sort_buff_size;
1119
    param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
1120
    param.tmpdir=&mysql_tmpdir_list;
1121
    if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
1122
    {
1123
      sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
1124
                        my_errno, param.db_name, param.table_name);
1125
      /* Repairing by sort failed. Now try standard repair method. */
1126
      param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
1127
      error= (repair(thd,param,0) != HA_ADMIN_OK);
1128
      /*
1129
        If the standard repair succeeded, clear all error messages which
1130
        might have been set by the first repair. They can still be seen
1131
        with SHOW WARNINGS then.
1132
      */
1133
      if (! error)
1134
        thd->clear_error();
1135
    }
1136
    info(HA_STATUS_CONST);
1137
    thd_proc_info(thd, save_proc_info);
1138
  }
1139
  else
1140
  {
1141
    /* mode not implemented */
1142
    error= HA_ERR_WRONG_COMMAND;
1143
  }
1144
  return error;
1145
}
1146
1147
1148
/*
1149
  Test if indexes are disabled.
1150
1151
1152
  SYNOPSIS
1153
    indexes_are_disabled()
1154
      no parameters
1155
1156
1157
  RETURN
1158
    0  indexes are not disabled
1159
    1  all indexes are disabled
1160
   [2  non-unique indexes are disabled - NOT YET IMPLEMENTED]
1161
*/
1162
1163
int ha_myisam::indexes_are_disabled(void)
1164
{
1165
  
1166
  return mi_indexes_are_disabled(file);
1167
}
1168
1169
1170
/*
1171
  prepare for a many-rows insert operation
1172
  e.g. - disable indexes (if they can be recreated fast) or
1173
  activate special bulk-insert optimizations
1174
1175
  SYNOPSIS
1176
    start_bulk_insert(rows)
1177
    rows        Rows to be inserted
1178
                0 if we don't know
1179
1180
  NOTICE
1181
    Do not forget to call end_bulk_insert() later!
1182
*/
1183
1184
void ha_myisam::start_bulk_insert(ha_rows rows)
1185
{
1186
  THD *thd= current_thd;
1187
  ulong size= min(thd->variables.read_buff_size,
1188
                  (ulong) (table->s->avg_row_length*rows));
1189
1190
  /* don't enable row cache if too few rows */
1191
  if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
1192
    mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
1193
1194
  can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map,
1195
                                            file->s->base.keys);
1196
1197
  if (!(specialflag & SPECIAL_SAFE_MODE))
1198
  {
1199
    /*
1200
      Only disable old index if the table was empty and we are inserting
1201
      a lot of rows.
1202
      We should not do this for only a few rows as this is slower and
1203
      we don't want to update the key statistics based of only a few rows.
1204
    */
1205
    if (file->state->records == 0 && can_enable_indexes &&
1206
        (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
1207
      mi_disable_non_unique_index(file,rows);
1208
    else
1209
    if (!file->bulk_insert &&
1210
        (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT))
1211
    {
1212
      mi_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows);
1213
    }
1214
  }
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1215
  return;
1 by brian
clean slate
1216
}
1217
1218
/*
1219
  end special bulk-insert optimizations,
1220
  which have been activated by start_bulk_insert().
1221
1222
  SYNOPSIS
1223
    end_bulk_insert()
1224
    no arguments
1225
1226
  RETURN
1227
    0     OK
1228
    != 0  Error
1229
*/
1230
1231
int ha_myisam::end_bulk_insert()
1232
{
1233
  mi_end_bulk_insert(file);
1234
  int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
1235
  return err ? err : can_enable_indexes ?
1236
                     enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0;
1237
}
1238
1239
1240
bool ha_myisam::check_and_repair(THD *thd)
1241
{
1242
  int error=0;
1243
  int marked_crashed;
1244
  char *old_query;
1245
  uint old_query_length;
1246
  HA_CHECK_OPT check_opt;
1247
1248
  check_opt.init();
1249
  check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1250
  // Don't use quick if deleted rows
1251
  if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1252
    check_opt.flags|=T_QUICK;
1253
  sql_print_warning("Checking table:   '%s'",table->s->path.str);
1254
1255
  old_query= thd->query;
1256
  old_query_length= thd->query_length;
1257
  pthread_mutex_lock(&LOCK_thread_count);
1258
  thd->query=        table->s->table_name.str;
1259
  thd->query_length= table->s->table_name.length;
1260
  pthread_mutex_unlock(&LOCK_thread_count);
1261
1262
  if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
1263
  {
1264
    sql_print_warning("Recovering table: '%s'",table->s->path.str);
1265
    check_opt.flags=
1266
      ((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1267
       (marked_crashed                             ? 0 : T_QUICK) |
1268
       (myisam_recover_options & HA_RECOVER_FORCE  ? 0 : T_SAFE_REPAIR) |
1269
       T_AUTO_REPAIR);
1270
    if (repair(thd, &check_opt))
1271
      error=1;
1272
  }
1273
  pthread_mutex_lock(&LOCK_thread_count);
1274
  thd->query= old_query;
1275
  thd->query_length= old_query_length;
1276
  pthread_mutex_unlock(&LOCK_thread_count);
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1277
  return(error);
1 by brian
clean slate
1278
}
1279
1280
bool ha_myisam::is_crashed() const
1281
{
1282
  return (file->s->state.changed & STATE_CRASHED ||
77.1.96 by Monty Taylor
Removed skip-external-locking.
1283
	  (file->s->state.open_count));
1 by brian
clean slate
1284
}
1285
1286
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
1287
{
1288
  ha_statistic_increment(&SSV::ha_update_count);
1289
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1290
    table->timestamp_field->set_time();
1291
  return mi_update(file,old_data,new_data);
1292
}
1293
1294
int ha_myisam::delete_row(const uchar *buf)
1295
{
1296
  ha_statistic_increment(&SSV::ha_delete_count);
1297
  return mi_delete(file,buf);
1298
}
1299
1300
C_MODE_START
1301
1302
my_bool index_cond_func_myisam(void *arg)
1303
{
1304
  ha_myisam *h= (ha_myisam*)arg;
1305
  /*if (h->in_range_read)*/
1306
  if (h->end_range)
1307
  {
1308
    if (h->compare_key2(h->end_range) > 0)
1309
      return 2; /* caller should return HA_ERR_END_OF_FILE already */
1310
  }
1311
  return (my_bool)h->pushed_idx_cond->val_int();
1312
}
1313
1314
C_MODE_END
1315
1316
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1317
int ha_myisam::index_init(uint idx, bool sorted __attribute__((unused)))
1 by brian
clean slate
1318
{ 
1319
  active_index=idx;
163 by Brian Aker
Merge Monty's code.
1320
  //in_range_read= false;
1 by brian
clean slate
1321
  if (pushed_idx_cond_keyno == idx)
1322
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
1323
  return 0; 
1324
}
1325
1326
1327
int ha_myisam::index_end()
1328
{
1329
  active_index=MAX_KEY;
1330
  //pushed_idx_cond_keyno= MAX_KEY;
1331
  mi_set_index_cond_func(file, NULL, 0);
163 by Brian Aker
Merge Monty's code.
1332
  in_range_check_pushed_down= false;
1 by brian
clean slate
1333
  ds_mrr.dsmrr_close();
1334
  return 0; 
1335
}
1336
1337
1338
int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1339
                              key_part_map keypart_map,
1340
                              enum ha_rkey_function find_flag)
1341
{
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1342
  assert(inited==INDEX);
1 by brian
clean slate
1343
  ha_statistic_increment(&SSV::ha_read_key_count);
1344
  int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1345
  table->status=error ? STATUS_NOT_FOUND: 0;
1346
  return error;
1347
}
1348
1349
int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
1350
                                  key_part_map keypart_map,
1351
                                  enum ha_rkey_function find_flag)
1352
{
1353
  ha_statistic_increment(&SSV::ha_read_key_count);
1354
  int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1355
  table->status=error ? STATUS_NOT_FOUND: 0;
1356
  return error;
1357
}
1358
1359
int ha_myisam::index_read_last_map(uchar *buf, const uchar *key,
1360
                                   key_part_map keypart_map)
1361
{
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1362
  assert(inited==INDEX);
1 by brian
clean slate
1363
  ha_statistic_increment(&SSV::ha_read_key_count);
1364
  int error=mi_rkey(file, buf, active_index, key, keypart_map,
1365
                    HA_READ_PREFIX_LAST);
1366
  table->status=error ? STATUS_NOT_FOUND: 0;
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1367
  return(error);
1 by brian
clean slate
1368
}
1369
1370
int ha_myisam::index_next(uchar *buf)
1371
{
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1372
  assert(inited==INDEX);
1 by brian
clean slate
1373
  ha_statistic_increment(&SSV::ha_read_next_count);
1374
  int error=mi_rnext(file,buf,active_index);
1375
  table->status=error ? STATUS_NOT_FOUND: 0;
1376
  return error;
1377
}
1378
1379
int ha_myisam::index_prev(uchar *buf)
1380
{
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1381
  assert(inited==INDEX);
1 by brian
clean slate
1382
  ha_statistic_increment(&SSV::ha_read_prev_count);
1383
  int error=mi_rprev(file,buf, active_index);
1384
  table->status=error ? STATUS_NOT_FOUND: 0;
1385
  return error;
1386
}
1387
1388
int ha_myisam::index_first(uchar *buf)
1389
{
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1390
  assert(inited==INDEX);
1 by brian
clean slate
1391
  ha_statistic_increment(&SSV::ha_read_first_count);
1392
  int error=mi_rfirst(file, buf, active_index);
1393
  table->status=error ? STATUS_NOT_FOUND: 0;
1394
  return error;
1395
}
1396
1397
int ha_myisam::index_last(uchar *buf)
1398
{
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1399
  assert(inited==INDEX);
1 by brian
clean slate
1400
  ha_statistic_increment(&SSV::ha_read_last_count);
1401
  int error=mi_rlast(file, buf, active_index);
1402
  table->status=error ? STATUS_NOT_FOUND: 0;
1403
  return error;
1404
}
1405
1406
int ha_myisam::index_next_same(uchar *buf,
1407
			       const uchar *key __attribute__((unused)),
1408
			       uint length __attribute__((unused)))
1409
{
1410
  int error;
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1411
  assert(inited==INDEX);
1 by brian
clean slate
1412
  ha_statistic_increment(&SSV::ha_read_next_count);
1413
  do
1414
  {
1415
    error= mi_rnext_same(file,buf);
1416
  } while (error == HA_ERR_RECORD_DELETED);
1417
  table->status=error ? STATUS_NOT_FOUND: 0;
1418
  return error;
1419
}
1420
1421
int ha_myisam::read_range_first(const key_range *start_key,
1422
		 	        const key_range *end_key,
1423
			        bool eq_range_arg,
1424
                                bool sorted /* ignored */)
1425
{
1426
  int res;
1427
  //if (!eq_range_arg)
163 by Brian Aker
Merge Monty's code.
1428
  //  in_range_read= true;
1 by brian
clean slate
1429
1430
  res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted);
1431
1432
  //if (res)
163 by Brian Aker
Merge Monty's code.
1433
  //  in_range_read= false;
1 by brian
clean slate
1434
  return res;
1435
}
1436
1437
1438
int ha_myisam::read_range_next()
1439
{
1440
  int res= handler::read_range_next();
1441
  //if (res)
163 by Brian Aker
Merge Monty's code.
1442
  //  in_range_read= false;
1 by brian
clean slate
1443
  return res;
1444
}
1445
1446
1447
int ha_myisam::rnd_init(bool scan)
1448
{
1449
  if (scan)
1450
    return mi_scan_init(file);
1451
  return mi_reset(file);                        // Free buffers
1452
}
1453
1454
int ha_myisam::rnd_next(uchar *buf)
1455
{
1456
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1457
  int error=mi_scan(file, buf);
1458
  table->status=error ? STATUS_NOT_FOUND: 0;
1459
  return error;
1460
}
1461
1462
int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos)
1463
{
1464
  return rnd_pos(buf,pos);
1465
}
1466
1467
int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
1468
{
1469
  ha_statistic_increment(&SSV::ha_read_rnd_count);
1470
  int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1471
  table->status=error ? STATUS_NOT_FOUND: 0;
1472
  return error;
1473
}
1474
1475
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1476
void ha_myisam::position(const uchar *record __attribute__((unused)))
1 by brian
clean slate
1477
{
1478
  my_off_t row_position= mi_position(file);
1479
  my_store_ptr(ref, ref_length, row_position);
1480
}
1481
1482
int ha_myisam::info(uint flag)
1483
{
1484
  MI_ISAMINFO misam_info;
1485
  char name_buff[FN_REFLEN];
1486
1487
  (void) mi_status(file,&misam_info,flag);
1488
  if (flag & HA_STATUS_VARIABLE)
1489
  {
1490
    stats.records=           misam_info.records;
1491
    stats.deleted=           misam_info.deleted;
1492
    stats.data_file_length=  misam_info.data_file_length;
1493
    stats.index_file_length= misam_info.index_file_length;
1494
    stats.delete_length=     misam_info.delete_length;
1495
    stats.check_time=        misam_info.check_time;
1496
    stats.mean_rec_length=   misam_info.mean_reclength;
1497
  }
1498
  if (flag & HA_STATUS_CONST)
1499
  {
1500
    TABLE_SHARE *share= table->s;
1501
    stats.max_data_file_length=  misam_info.max_data_file_length;
1502
    stats.max_index_file_length= misam_info.max_index_file_length;
1503
    stats.create_time= misam_info.create_time;
1504
    ref_length= misam_info.reflength;
1505
    share->db_options_in_use= misam_info.options;
1506
    stats.block_size= myisam_block_size;        /* record block size */
1507
1508
    /* Update share */
1509
    if (share->tmp_table == NO_TMP_TABLE)
1510
      pthread_mutex_lock(&share->mutex);
1511
    share->keys_in_use.set_prefix(share->keys);
1512
    share->keys_in_use.intersect_extended(misam_info.key_map);
1513
    share->keys_for_keyread.intersect(share->keys_in_use);
1514
    share->db_record_offset= misam_info.record_offset;
1515
    if (share->key_parts)
1516
      memcpy((char*) table->key_info[0].rec_per_key,
1517
	     (char*) misam_info.rec_per_key,
1518
	     sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1519
    if (share->tmp_table == NO_TMP_TABLE)
1520
      pthread_mutex_unlock(&share->mutex);
1521
1522
   /*
1523
     Set data_file_name and index_file_name to point at the symlink value
1524
     if table is symlinked (Ie;  Real name is not same as generated name)
1525
   */
1526
    data_file_name= index_file_name= 0;
1527
    fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1528
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1529
    if (strcmp(name_buff, misam_info.data_file_name))
1530
      data_file_name=misam_info.data_file_name;
1531
    fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1532
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1533
    if (strcmp(name_buff, misam_info.index_file_name))
1534
      index_file_name=misam_info.index_file_name;
1535
  }
1536
  if (flag & HA_STATUS_ERRKEY)
1537
  {
1538
    errkey  = misam_info.errkey;
1539
    my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
1540
  }
1541
  if (flag & HA_STATUS_TIME)
1542
    stats.update_time = misam_info.update_time;
1543
  if (flag & HA_STATUS_AUTO)
1544
    stats.auto_increment_value= misam_info.auto_increment;
1545
1546
  return 0;
1547
}
1548
1549
1550
int ha_myisam::extra(enum ha_extra_function operation)
1551
{
1552
  if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
1553
    return 0;
1554
  return mi_extra(file, operation, 0);
1555
}
1556
1557
int ha_myisam::reset(void)
1558
{
1559
  pushed_idx_cond= NULL;
1560
  pushed_idx_cond_keyno= MAX_KEY;
1561
  mi_set_index_cond_func(file, NULL, 0);
1562
  ds_mrr.dsmrr_close();
1563
  return mi_reset(file);
1564
}
1565
1566
/* To be used with WRITE_CACHE and EXTRA_CACHE */
1567
61 by Brian Aker
Conversion of handler type.
1568
int ha_myisam::extra_opt(enum ha_extra_function operation, uint32_t cache_size)
1 by brian
clean slate
1569
{
1570
  if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
1571
    return 0;
1572
  return mi_extra(file, operation, (void*) &cache_size);
1573
}
1574
1575
int ha_myisam::delete_all_rows()
1576
{
1577
  return mi_delete_all_rows(file);
1578
}
1579
1580
int ha_myisam::delete_table(const char *name)
1581
{
1582
  return mi_delete_table(name);
1583
}
1584
1585
1586
int ha_myisam::external_lock(THD *thd, int lock_type)
1587
{
1588
  file->in_use.data= thd;
1589
  return mi_lock_database(file, !table->s->tmp_table ?
1590
			  lock_type : ((lock_type == F_UNLCK) ?
1591
				       F_UNLCK : F_EXTRA_LCK));
1592
}
1593
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1594
THR_LOCK_DATA **ha_myisam::store_lock(THD *thd __attribute__((unused)),
1 by brian
clean slate
1595
				      THR_LOCK_DATA **to,
1596
				      enum thr_lock_type lock_type)
1597
{
1598
  if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1599
    file->lock.type=lock_type;
1600
  *to++= &file->lock;
1601
  return to;
1602
}
1603
1604
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1605
{
1606
  ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1607
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1608
  {
1609
    create_info->auto_increment_value= stats.auto_increment_value;
1610
  }
1611
  create_info->data_file_name=data_file_name;
1612
  create_info->index_file_name=index_file_name;
1613
}
1614
1615
1616
int ha_myisam::create(const char *name, register TABLE *table_arg,
1617
		      HA_CREATE_INFO *ha_create_info)
1618
{
1619
  int error;
249 by Brian Aker
Random key cleanup (it is a friday...)
1620
  uint create_flags= 0, records;
1 by brian
clean slate
1621
  char buff[FN_REFLEN];
1622
  MI_KEYDEF *keydef;
1623
  MI_COLUMNDEF *recinfo;
1624
  MI_CREATE_INFO create_info;
1625
  TABLE_SHARE *share= table_arg->s;
1626
  uint options= share->db_options_in_use;
1627
  if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1628
    return(error); /* purecov: inspected */
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
1629
  memset((char*) &create_info, 0, sizeof(create_info));
1 by brian
clean slate
1630
  create_info.max_rows= share->max_rows;
1631
  create_info.reloc_rows= share->min_rows;
1632
  create_info.with_auto_increment= share->next_number_key_offset == 0;
1633
  create_info.auto_increment= (ha_create_info->auto_increment_value ?
1634
                               ha_create_info->auto_increment_value -1 :
1635
                               (uint64_t) 0);
1636
  create_info.data_file_length= ((uint64_t) share->max_rows *
1637
                                 share->avg_row_length);
1638
  create_info.data_file_name= ha_create_info->data_file_name;
1639
  create_info.index_file_name= ha_create_info->index_file_name;
1640
  create_info.language= share->table_charset->number;
1641
1642
  if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1643
    create_flags|= HA_CREATE_TMP_TABLE;
1644
  if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1645
    create_flags|= HA_CREATE_KEEP_FILES;
1646
  if (options & HA_OPTION_PACK_RECORD)
1647
    create_flags|= HA_PACK_RECORD;
1648
  if (options & HA_OPTION_CHECKSUM)
1649
    create_flags|= HA_CREATE_CHECKSUM;
1650
  if (options & HA_OPTION_DELAY_KEY_WRITE)
1651
    create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1652
1653
  /* TODO: Check that the following fn_format is really needed */
1654
  error= mi_create(fn_format(buff, name, "", "",
1655
                             MY_UNPACK_FILENAME|MY_APPEND_EXT),
1656
                   share->keys, keydef,
1657
                   records, recinfo,
1658
                   0, (MI_UNIQUEDEF*) 0,
1659
                   &create_info, create_flags);
1660
  my_free((uchar*) recinfo, MYF(0));
51.1.89 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
1661
  return(error);
1 by brian
clean slate
1662
}
1663
1664
1665
int ha_myisam::rename_table(const char * from, const char * to)
1666
{
1667
  return mi_rename(from,to);
1668
}
1669
1670
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1671
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((unused)),
1672
                                   uint64_t increment __attribute__((unused)),
1673
                                   uint64_t nb_desired_values __attribute__((unused)),
1 by brian
clean slate
1674
                                   uint64_t *first_value,
1675
                                   uint64_t *nb_reserved_values)
1676
{
1677
  uint64_t nr;
1678
  int error;
1679
  uchar key[MI_MAX_KEY_LENGTH];
1680
1681
  if (!table->s->next_number_key_offset)
1682
  {						// Autoincrement at key-start
1683
    ha_myisam::info(HA_STATUS_AUTO);
1684
    *first_value= stats.auto_increment_value;
1685
    /* MyISAM has only table-level lock, so reserves to +inf */
163 by Brian Aker
Merge Monty's code.
1686
    *nb_reserved_values= UINT64_MAX;
1 by brian
clean slate
1687
    return;
1688
  }
1689
1690
  /* it's safe to call the following if bulk_insert isn't on */
1691
  mi_flush_bulk_insert(file, table->s->next_number_index);
1692
1693
  (void) extra(HA_EXTRA_KEYREAD);
1694
  key_copy(key, table->record[0],
1695
           table->key_info + table->s->next_number_index,
1696
           table->s->next_number_key_offset);
1697
  error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
1698
                 key, make_prev_keypart_map(table->s->next_number_keypart),
1699
                 HA_READ_PREFIX_LAST);
1700
  if (error)
1701
    nr= 1;
1702
  else
1703
  {
1704
    /* Get data from record[1] */
1705
    nr= ((uint64_t) table->next_number_field->
1706
         val_int_offset(table->s->rec_buff_length)+1);
1707
  }
1708
  extra(HA_EXTRA_NO_KEYREAD);
1709
  *first_value= nr;
1710
  /*
1711
    MySQL needs to call us for next row: assume we are inserting ("a",null)
1712
    here, we return 3, and next this statement will want to insert ("b",null):
1713
    there is no reason why ("b",3+1) would be the good row to insert: maybe it
1714
    already exists, maybe 3+1 is too large...
1715
  */
1716
  *nb_reserved_values= 1;
1717
}
1718
1719
1720
/*
1721
  Find out how many rows there is in the given range
1722
1723
  SYNOPSIS
1724
    records_in_range()
1725
    inx			Index to use
1726
    min_key		Start of range.  Null pointer if from first key
1727
    max_key		End of range. Null pointer if to last key
1728
1729
  NOTES
1730
    min_key.flag can have one of the following values:
1731
      HA_READ_KEY_EXACT		Include the key in the range
1732
      HA_READ_AFTER_KEY		Don't include key in range
1733
1734
    max_key.flag can have one of the following values:  
1735
      HA_READ_BEFORE_KEY	Don't include key in range
1736
      HA_READ_AFTER_KEY		Include all 'end_key' values in the range
1737
1738
  RETURN
1739
   HA_POS_ERROR		Something is wrong with the index tree.
1740
   0			There is no matching keys in the given range
1741
   number > 0		There is approximately 'number' matching rows in
1742
			the range.
1743
*/
1744
1745
ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key,
1746
                                    key_range *max_key)
1747
{
1748
  return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
1749
}
1750
1751
1752
uint ha_myisam::checksum() const
1753
{
1754
  return (uint)file->state->checksum;
1755
}
1756
1757
1758
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
1759
					   uint table_changes)
1760
{
1761
  uint options= table->s->db_options_in_use;
1762
1763
  if (info->auto_increment_value != stats.auto_increment_value ||
1764
      info->data_file_name != data_file_name ||
1765
      info->index_file_name != index_file_name ||
1766
      table_changes == IS_EQUAL_NO ||
1767
      table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1768
    return COMPATIBLE_DATA_NO;
1769
1770
  if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1771
		  HA_OPTION_DELAY_KEY_WRITE)) !=
1772
      (info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1773
			      HA_OPTION_DELAY_KEY_WRITE)))
1774
    return COMPATIBLE_DATA_NO;
1775
  return COMPATIBLE_DATA_YES;
1776
}
1777
224.2.3 by Brian Aker
Fix for memory leak in shutdown/restart of an engine (not fixed in 5.1)
1778
int myisam_deinit(void *hton __attribute__((unused)))
1 by brian
clean slate
1779
{
224.2.3 by Brian Aker
Fix for memory leak in shutdown/restart of an engine (not fixed in 5.1)
1780
  return mi_panic(HA_PANIC_CLOSE);
1 by brian
clean slate
1781
}
1782
1783
static int myisam_init(void *p)
1784
{
1785
  handlerton *myisam_hton;
1786
1787
  myisam_hton= (handlerton *)p;
1788
  myisam_hton->state= SHOW_OPTION_YES;
1789
  myisam_hton->db_type= DB_TYPE_MYISAM;
1790
  myisam_hton->create= myisam_create_handler;
1791
  myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1792
  return 0;
1793
}
1794
1795
1796
1797
/****************************************************************************
1798
 * MyISAM MRR implementation: use DS-MRR
1799
 ***************************************************************************/
1800
1801
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1802
                                     uint n_ranges, uint mode, 
1803
                                     HANDLER_BUFFER *buf)
1804
{
1805
  return ds_mrr.dsmrr_init(this, &table->key_info[active_index], 
1806
                           seq, seq_init_param, n_ranges, mode, buf);
1807
}
1808
1809
int ha_myisam::multi_range_read_next(char **range_info)
1810
{
1811
  return ds_mrr.dsmrr_next(this, range_info);
1812
}
1813
1814
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
1815
                                               void *seq_init_param, 
1816
                                               uint n_ranges, uint *bufsz,
1817
                                               uint *flags, COST_VECT *cost)
1818
{
1819
  /*
1820
    This call is here because there is no location where this->table would
1821
    already be known.
1822
    TODO: consider moving it into some per-query initialization call.
1823
  */
1824
  ds_mrr.init(this, table);
1825
  return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1826
                                 flags, cost);
1827
}
1828
1829
int ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
1830
                                     uint *bufsz, uint *flags, COST_VECT *cost)
1831
{
1832
  ds_mrr.init(this, table);
1833
  return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1834
}
1835
1836
/* MyISAM MRR implementation ends */
1837
1838
1839
/* Index condition pushdown implementation*/
1840
1841
1842
Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
1843
{
1844
  pushed_idx_cond_keyno= keyno_arg;
1845
  pushed_idx_cond= idx_cond_arg;
163 by Brian Aker
Merge Monty's code.
1846
  in_range_check_pushed_down= true;
1 by brian
clean slate
1847
  if (active_index == pushed_idx_cond_keyno)
1848
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
1849
  return NULL;
1850
}
1851
1852
1853
mysql_declare_plugin(myisam)
1854
{
1855
  MYSQL_STORAGE_ENGINE_PLUGIN,
1856
  "MyISAM",
177.4.3 by mark
ripped out more plugin ABI and API version checking, and plugin versions are now strings
1857
  "1.0",
1 by brian
clean slate
1858
  "MySQL AB",
1859
  "Default engine as of MySQL 3.23 with great performance",
1860
  PLUGIN_LICENSE_GPL,
1861
  myisam_init, /* Plugin Init */
224.2.3 by Brian Aker
Fix for memory leak in shutdown/restart of an engine (not fixed in 5.1)
1862
  myisam_deinit, /* Plugin Deinit */
1 by brian
clean slate
1863
  NULL,                       /* status variables                */
1864
  NULL,                       /* system variables                */
1865
  NULL                        /* config options                  */
1866
}
1867
mysql_declare_plugin_end;