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