~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/ha_myisam.cc

  • Committer: Brian Aker
  • Date: 2008-07-14 22:07:42 UTC
  • Revision ID: brian@tangent.org-20080714220742-y7fjh1mitrfcgfij
Second pass cleanup on removal of my_uint types

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
 
17
 
 
18
 
#include "config.h"
19
 
#include "drizzled/internal/my_bit.h"
20
 
#include "myisampack.h"
 
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
 
22
#include "mysql_priv.h"
 
23
#include <mysql/plugin.h>
 
24
#include <m_ctype.h>
 
25
#include <my_bit.h>
 
26
#include <myisampack.h>
21
27
#include "ha_myisam.h"
22
 
#include "myisam_priv.h"
23
 
#include "drizzled/option.h"
24
 
#include "drizzled/internal/my_bit.h"
25
 
#include "drizzled/internal/m_string.h"
26
 
#include "drizzled/util/test.h"
27
 
#include "drizzled/error.h"
28
 
#include "drizzled/errmsg_print.h"
29
 
#include "drizzled/gettext.h"
30
 
#include "drizzled/session.h"
31
 
#include "drizzled/plugin.h"
32
 
#include "drizzled/plugin/client.h"
33
 
#include "drizzled/table.h"
34
 
#include "drizzled/field/timestamp.h"
35
 
#include "drizzled/memory/multi_malloc.h"
36
 
#include "drizzled/plugin/daemon.h"
37
 
 
38
 
#include <boost/algorithm/string.hpp>
39
 
#include <boost/scoped_ptr.hpp>
40
 
 
41
 
#include <string>
42
 
#include <sstream>
43
 
#include <map>
44
 
#include <algorithm>
45
 
#include <memory>
46
 
#include <boost/program_options.hpp>
47
 
#include <drizzled/module/option_map.h>
48
 
 
49
 
namespace po= boost::program_options;
50
 
 
51
 
using namespace std;
52
 
using namespace drizzled;
53
 
 
54
 
static const string engine_name("MyISAM");
55
 
 
56
 
boost::mutex THR_LOCK_myisam;
57
 
 
58
 
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
59
 
static uint32_t myisam_key_cache_size;
60
 
static uint32_t myisam_key_cache_division_limit;
61
 
static uint32_t myisam_key_cache_age_threshold;
62
 
static uint64_t max_sort_file_size;
63
 
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
64
 
static sort_buffer_constraint sort_buffer_size;
65
 
 
66
 
void st_mi_isam_share::setKeyCache()
67
 
{
68
 
  (void)init_key_cache(&key_cache,
69
 
                       myisam_key_cache_block_size,
70
 
                       myisam_key_cache_size,
71
 
                       myisam_key_cache_division_limit, 
72
 
                       myisam_key_cache_age_threshold);
73
 
}
 
28
#include <stdarg.h>
 
29
#include "myisamdef.h"
 
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
 
74
45
 
75
46
/*****************************************************************************
76
47
** MyISAM tables
77
48
*****************************************************************************/
78
49
 
79
 
static const char *ha_myisam_exts[] = {
80
 
  ".MYI",
81
 
  ".MYD",
82
 
  NULL
83
 
};
84
 
 
85
 
class MyisamEngine : public plugin::StorageEngine
86
 
{
87
 
  MyisamEngine();
88
 
  MyisamEngine(const MyisamEngine&);
89
 
  MyisamEngine& operator=(const MyisamEngine&);
90
 
public:
91
 
  explicit MyisamEngine(string name_arg) :
92
 
    plugin::StorageEngine(name_arg,
93
 
                          HTON_CAN_INDEX_BLOBS |
94
 
                          HTON_STATS_RECORDS_IS_EXACT |
95
 
                          HTON_TEMPORARY_ONLY |
96
 
                          HTON_NULL_IN_KEY |
97
 
                          HTON_HAS_RECORDS |
98
 
                          HTON_DUPLICATE_POS |
99
 
                          HTON_AUTO_PART_KEY |
100
 
                          HTON_SKIP_STORE_LOCK)
101
 
  {
102
 
  }
103
 
 
104
 
  virtual ~MyisamEngine()
105
 
  { 
106
 
    mi_panic(HA_PANIC_CLOSE);
107
 
  }
108
 
 
109
 
  virtual Cursor *create(Table &table)
110
 
  {
111
 
    return new ha_myisam(*this, table);
112
 
  }
113
 
 
114
 
  const char **bas_ext() const {
115
 
    return ha_myisam_exts;
116
 
  }
117
 
 
118
 
  int doCreateTable(Session&,
119
 
                    Table& table_arg,
120
 
                    const TableIdentifier &identifier,
121
 
                    message::Table&);
122
 
 
123
 
  int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
124
 
 
125
 
  int doDropTable(Session&, const TableIdentifier &identifier);
126
 
 
127
 
  int doGetTableDefinition(Session& session,
128
 
                           const TableIdentifier &identifier,
129
 
                           message::Table &table_message);
130
 
 
131
 
  uint32_t max_supported_keys()          const { return MI_MAX_KEY; }
132
 
  uint32_t max_supported_key_length()    const { return MI_MAX_KEY_LENGTH; }
133
 
  uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
134
 
 
135
 
  uint32_t index_flags(enum  ha_key_alg) const
136
 
  {
137
 
    return (HA_READ_NEXT |
138
 
            HA_READ_PREV |
139
 
            HA_READ_RANGE |
140
 
            HA_READ_ORDER |
141
 
            HA_KEYREAD_ONLY);
142
 
  }
143
 
  bool doDoesTableExist(Session& session, const TableIdentifier &identifier);
144
 
 
145
 
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
146
 
                             const drizzled::SchemaIdentifier &schema_identifier,
147
 
                             drizzled::TableIdentifier::vector &set_of_identifiers);
148
 
  bool validateCreateTableOption(const std::string &key, const std::string &state)
149
 
  {
150
 
    (void)state;
151
 
    if (boost::iequals(key, "ROW_FORMAT"))
152
 
    {
153
 
      return true;
154
 
    }
155
 
 
156
 
    return false;
157
 
  }
158
 
};
159
 
 
160
 
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
161
 
                                         const drizzled::SchemaIdentifier&,
162
 
                                         drizzled::TableIdentifier::vector&)
163
 
{
164
 
}
165
 
 
166
 
bool MyisamEngine::doDoesTableExist(Session &session, const TableIdentifier &identifier)
167
 
{
168
 
  return session.getMessageCache().doesTableMessageExist(identifier);
169
 
}
170
 
 
171
 
int MyisamEngine::doGetTableDefinition(Session &session,
172
 
                                       const TableIdentifier &identifier,
173
 
                                       message::Table &table_message)
174
 
{
175
 
  if (session.getMessageCache().getTableMessage(identifier, table_message))
176
 
    return EEXIST;
177
 
  return ENOENT;
178
 
}
179
 
 
180
 
/* 
181
 
  Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
182
 
*/
183
 
 
184
 
static void mi_check_print_msg(MI_CHECK *,      const char* ,
185
 
                               const char *, va_list )
186
 
{
 
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
 
 
68
  msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
 
69
  msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
 
70
 
 
71
  DBUG_PRINT(msg_type,("message: %s",msgbuf));
 
72
 
 
73
  if (!thd->vio_ok())
 
74
  {
 
75
    sql_print_error(msgbuf);
 
76
    return;
 
77
  }
 
78
 
 
79
  if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
 
80
                         T_AUTO_REPAIR))
 
81
  {
 
82
    my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
 
83
    return;
 
84
  }
 
85
  length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
 
86
                 name);
 
87
  /*
 
88
    TODO: switch from protocol to push_warning here. The main reason we didn't
 
89
    it yet is parallel repair. Due to following trace:
 
90
    mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
 
91
 
 
92
    Also we likely need to lock mutex here (in both cases with protocol and
 
93
    push_warning).
 
94
  */
 
95
  protocol->prepare_for_resend();
 
96
  protocol->store(name, length, system_charset_info);
 
97
  protocol->store(param->op_name, system_charset_info);
 
98
  protocol->store(msg_type, system_charset_info);
 
99
  protocol->store(msgbuf, msg_length, system_charset_info);
 
100
  if (protocol->write())
 
101
    sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
 
102
                    msgbuf);
 
103
  return;
187
104
}
188
105
 
189
106
 
190
107
/*
191
 
  Convert Table object to MyISAM key and column definition
 
108
  Convert TABLE object to MyISAM key and column definition
192
109
 
193
110
  SYNOPSIS
194
111
    table2myisam()
195
 
      table_arg   in     Table object.
 
112
      table_arg   in     TABLE object.
196
113
      keydef_out  out    MyISAM key definition.
197
114
      recinfo_out out    MyISAM column definition.
198
115
      records_out out    Number of fields.
203
120
    table conformance in merge engine.
204
121
 
205
122
    The caller needs to free *recinfo_out after use. Since *recinfo_out
206
 
    and *keydef_out are allocated with a multi_malloc, *keydef_out
 
123
    and *keydef_out are allocated with a my_multi_malloc, *keydef_out
207
124
    is freed automatically when *recinfo_out is freed.
208
125
 
209
126
  RETURN VALUE
211
128
    !0 error code
212
129
*/
213
130
 
214
 
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
215
 
                        MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
 
131
int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
 
132
                 MI_COLUMNDEF **recinfo_out, uint *records_out)
216
133
{
217
 
  uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
 
134
  uint i, j, recpos, minpos, fieldpos, temp_length, length;
218
135
  enum ha_base_keytype type= HA_KEYTYPE_BINARY;
219
 
  unsigned char *record;
 
136
  uchar *record;
 
137
  KEY *pos;
220
138
  MI_KEYDEF *keydef;
221
139
  MI_COLUMNDEF *recinfo, *recinfo_pos;
222
140
  HA_KEYSEG *keyseg;
223
 
  TableShare *share= table_arg->getMutableShare();
224
 
  uint32_t options= share->db_options_in_use;
225
 
  if (!(memory::multi_malloc(false,
226
 
          recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
227
 
          keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
228
 
          &keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
229
 
          NULL)))
230
 
    return(HA_ERR_OUT_OF_MEM);
 
141
  TABLE_SHARE *share= table_arg->s;
 
142
  uint options= share->db_options_in_use;
 
143
  DBUG_ENTER("table2myisam");
 
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),
 
149
          NullS)))
 
150
    DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
231
151
  keydef= *keydef_out;
232
152
  recinfo= *recinfo_out;
233
 
  for (i= 0; i < share->sizeKeys(); i++)
 
153
  pos= table_arg->key_info;
 
154
  for (i= 0; i < share->keys; i++, pos++)
234
155
  {
235
 
    KeyInfo *pos= &table_arg->key_info[i];
236
 
    keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
237
 
    keydef[i].key_alg= HA_KEY_ALG_BTREE;
 
156
    keydef[i].flag= ((uint16) pos->flags & (HA_NOSAME | HA_FULLTEXT ));
 
157
    keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?  (HA_KEY_ALG_BTREE) : pos->algorithm;
238
158
    keydef[i].block_length= pos->block_size;
239
159
    keydef[i].seg= keyseg;
240
160
    keydef[i].keysegs= pos->key_parts;
250
170
      {
251
171
        if (pos->key_part[j].length > 8 &&
252
172
            (type == HA_KEYTYPE_TEXT ||
 
173
             type == HA_KEYTYPE_NUM ||
253
174
             (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
254
175
        {
255
176
          /* No blobs here */
256
177
          if (j == 0)
257
178
            keydef[i].flag|= HA_PACK_KEY;
258
 
          if ((((int) (pos->key_part[j].length - field->decimals())) >= 4))
 
179
          if (!(field->flags & ZEROFILL_FLAG) &&
 
180
              (field->type() == MYSQL_TYPE_STRING ||
 
181
               field->type() == MYSQL_TYPE_VAR_STRING ||
 
182
               ((int) (pos->key_part[j].length - field->decimals())) >= 4))
259
183
            keydef[i].seg[j].flag|= HA_SPACE_PACK;
260
184
        }
261
185
        else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
273
197
      {
274
198
        keydef[i].seg[j].null_bit= field->null_bit;
275
199
        keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
276
 
                                           (unsigned char*) table_arg->getInsertRecord());
 
200
                                           (uchar*) table_arg->record[0]);
277
201
      }
278
202
      else
279
203
      {
280
204
        keydef[i].seg[j].null_bit= 0;
281
205
        keydef[i].seg[j].null_pos= 0;
282
206
      }
283
 
      if (field->type() == DRIZZLE_TYPE_BLOB)
 
207
      if (field->type() == MYSQL_TYPE_BLOB)
284
208
      {
285
209
        keydef[i].seg[j].flag|= HA_BLOB_PART;
286
210
        /* save number of bytes used to pack length */
292
216
  }
293
217
  if (table_arg->found_next_number_field)
294
218
    keydef[share->next_number_index].flag|= HA_AUTO_KEY;
295
 
  record= table_arg->getInsertRecord();
 
219
  record= table_arg->record[0];
296
220
  recpos= 0;
297
221
  recinfo_pos= recinfo;
298
 
  while (recpos < (uint) share->stored_rec_length)
 
222
  while (recpos < (uint) share->reclength)
299
223
  {
300
224
    Field **field, *found= 0;
301
 
    minpos= share->getRecordLength();
 
225
    minpos= share->reclength;
302
226
    length= 0;
303
227
 
304
 
    for (field= table_arg->getFields(); *field; field++)
 
228
    for (field= table_arg->field; *field; field++)
305
229
    {
306
230
      if ((fieldpos= (*field)->offset(record)) >= recpos &&
307
231
          fieldpos <= minpos)
318
242
        }
319
243
      }
320
244
    }
 
245
    DBUG_PRINT("loop", ("found: 0x%lx  recpos: %d  minpos: %d  length: %d",
 
246
                        (long) found, recpos, minpos, length));
321
247
    if (recpos != minpos)
322
248
    { // Reserved space (Null bits?)
323
 
      memset(recinfo_pos, 0, sizeof(*recinfo_pos));
 
249
      bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
324
250
      recinfo_pos->type= (int) FIELD_NORMAL;
325
 
      recinfo_pos++->length= (uint16_t) (minpos - recpos);
 
251
      recinfo_pos++->length= (uint16) (minpos - recpos);
326
252
    }
327
253
    if (!found)
328
254
      break;
329
255
 
330
256
    if (found->flags & BLOB_FLAG)
331
257
      recinfo_pos->type= (int) FIELD_BLOB;
332
 
    else if (found->type() == DRIZZLE_TYPE_VARCHAR)
 
258
    else if (found->type() == MYSQL_TYPE_VARCHAR)
333
259
      recinfo_pos->type= FIELD_VARCHAR;
334
260
    else if (!(options & HA_OPTION_PACK_RECORD))
335
261
      recinfo_pos->type= (int) FIELD_NORMAL;
336
262
    else if (found->zero_pack())
337
263
      recinfo_pos->type= (int) FIELD_SKIP_ZERO;
338
264
    else
339
 
      recinfo_pos->type= (int) ((length <= 3) ?  FIELD_NORMAL : FIELD_SKIP_PRESPACE);
 
265
      recinfo_pos->type= (int) ((length <= 3 ||
 
266
                                 (found->flags & ZEROFILL_FLAG)) ?
 
267
                                  FIELD_NORMAL :
 
268
                                  found->type() == MYSQL_TYPE_STRING ||
 
269
                                  found->type() == MYSQL_TYPE_VAR_STRING ?
 
270
                                  FIELD_SKIP_ENDSPACE :
 
271
                                  FIELD_SKIP_PRESPACE);
340
272
    if (found->null_ptr)
341
273
    {
342
274
      recinfo_pos->null_bit= found->null_bit;
343
275
      recinfo_pos->null_pos= (uint) (found->null_ptr -
344
 
                                     (unsigned char*) table_arg->getInsertRecord());
 
276
                                     (uchar*) table_arg->record[0]);
345
277
    }
346
278
    else
347
279
    {
348
280
      recinfo_pos->null_bit= 0;
349
281
      recinfo_pos->null_pos= 0;
350
282
    }
351
 
    (recinfo_pos++)->length= (uint16_t) length;
 
283
    (recinfo_pos++)->length= (uint16) length;
352
284
    recpos= minpos + length;
 
285
    DBUG_PRINT("loop", ("length: %d  type: %d",
 
286
                        recinfo_pos[-1].length,recinfo_pos[-1].type));
353
287
  }
354
288
  *records_out= (uint) (recinfo_pos - recinfo);
355
 
  return(0);
 
289
  DBUG_RETURN(0);
356
290
}
357
291
 
358
 
int ha_myisam::reset_auto_increment(uint64_t value)
359
 
{
360
 
  file->s->state.auto_increment= value;
361
 
  return 0;
362
 
}
363
292
 
364
293
/*
365
294
  Check for underlying table conformance
401
330
      (should be corretly detected in table2myisam).
402
331
*/
403
332
 
404
 
static int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
405
 
                            uint32_t t1_keys, uint32_t t1_recs,
406
 
                            MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
407
 
                            uint32_t t2_keys, uint32_t t2_recs, bool strict)
 
333
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
 
334
                     uint t1_keys, uint t1_recs,
 
335
                     MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
 
336
                     uint t2_keys, uint t2_recs, bool strict)
408
337
{
409
 
  uint32_t i, j;
 
338
  uint i, j;
 
339
  DBUG_ENTER("check_definition");
410
340
  if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
411
341
  {
412
 
    return(1);
 
342
    DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
 
343
                         t1_keys, t2_keys));
 
344
    DBUG_RETURN(1);
413
345
  }
414
346
  if (t1_recs != t2_recs)
415
347
  {
416
 
    return(1);
 
348
    DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
 
349
                         t1_recs, t2_recs));
 
350
    DBUG_RETURN(1);
417
351
  }
418
352
  for (i= 0; i < t1_keys; i++)
419
353
  {
420
354
    HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
421
355
    HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
 
356
    if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
 
357
      continue;
 
358
    else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
 
359
             t2_keyinfo[i].flag & HA_FULLTEXT)
 
360
    {
 
361
       DBUG_PRINT("error", ("Key %d has different definition", i));
 
362
       DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
 
363
                            test(t1_keyinfo[i].flag & HA_FULLTEXT),
 
364
                            test(t2_keyinfo[i].flag & HA_FULLTEXT)));
 
365
       DBUG_RETURN(1);
 
366
    }
 
367
    if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
 
368
      continue;
 
369
    else if (t1_keyinfo[i].flag & HA_SPATIAL ||
 
370
             t2_keyinfo[i].flag & HA_SPATIAL)
 
371
    {
 
372
       DBUG_PRINT("error", ("Key %d has different definition", i));
 
373
       DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
 
374
                            test(t1_keyinfo[i].flag & HA_SPATIAL),
 
375
                            test(t2_keyinfo[i].flag & HA_SPATIAL)));
 
376
       DBUG_RETURN(1);
 
377
    }
422
378
    if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
423
379
        t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
424
380
    {
425
 
      return(1);
 
381
      DBUG_PRINT("error", ("Key %d has different definition", i));
 
382
      DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
 
383
                           t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
 
384
      DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
 
385
                           t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
 
386
      DBUG_RETURN(1);
426
387
    }
427
388
    for (j=  t1_keyinfo[i].keysegs; j--;)
428
389
    {
429
 
      uint8_t t1_keysegs_j__type= t1_keysegs[j].type;
 
390
      uint8 t1_keysegs_j__type= t1_keysegs[j].type;
430
391
 
431
392
      /*
432
393
        Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
439
400
      {
440
401
        if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
441
402
            (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
442
 
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1;
 
403
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
443
404
        else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
444
405
                 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
445
 
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1;
 
406
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
446
407
      }
447
408
 
448
409
      if (t1_keysegs_j__type != t2_keysegs[j].type ||
450
411
          t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
451
412
          t1_keysegs[j].length != t2_keysegs[j].length)
452
413
      {
453
 
        return(1);
 
414
        DBUG_PRINT("error", ("Key segment %d (key %d) has different "
 
415
                             "definition", j, i));
 
416
        DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
 
417
                             "t1_length=%d",
 
418
                             t1_keysegs[j].type, t1_keysegs[j].language,
 
419
                             t1_keysegs[j].null_bit, t1_keysegs[j].length));
 
420
        DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
 
421
                             "t2_length=%d",
 
422
                             t2_keysegs[j].type, t2_keysegs[j].language,
 
423
                             t2_keysegs[j].null_bit, t2_keysegs[j].length));
 
424
 
 
425
        DBUG_RETURN(1);
454
426
      }
455
427
    }
456
428
  }
469
441
        t1_rec->length != t2_rec->length ||
470
442
        t1_rec->null_bit != t2_rec->null_bit)
471
443
    {
472
 
      return(1);
 
444
      DBUG_PRINT("error", ("Field %d has different definition", i));
 
445
      DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d",
 
446
                           t1_rec->type, t1_rec->length, t1_rec->null_bit));
 
447
      DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d",
 
448
                           t2_rec->type, t2_rec->length, t2_rec->null_bit));
 
449
      DBUG_RETURN(1);
473
450
    }
474
451
  }
475
 
  return(0);
 
452
  DBUG_RETURN(0);
476
453
}
477
454
 
478
455
 
 
456
extern "C" {
 
457
 
479
458
volatile int *killed_ptr(MI_CHECK *param)
480
459
{
481
460
  /* In theory Unsafe conversion, but should be ok for now */
482
 
  return (int*) (((Session *)(param->session))->getKilledPtr());
 
461
  return (int*) &(((THD *)(param->thd))->killed);
483
462
}
484
463
 
485
464
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
526
505
*/
527
506
 
528
507
void _mi_report_crashed(MI_INFO *file, const char *message,
529
 
                        const char *sfile, uint32_t sline)
 
508
                        const char *sfile, uint sline)
530
509
{
531
 
  Session *cur_session;
532
 
  if ((cur_session= file->in_use))
533
 
    errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
534
 
                    cur_session->thread_id,
 
510
  THD *cur_thd;
 
511
  LIST *element;
 
512
  char buf[1024];
 
513
  pthread_mutex_lock(&file->s->intern_lock);
 
514
  if ((cur_thd= (THD*) file->in_use.data))
 
515
    sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id,
535
516
                    sfile, sline);
536
517
  else
537
 
    errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
 
518
    sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline);
538
519
  if (message)
539
 
    errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
540
 
  list<Session *>::iterator it= file->s->in_use->begin();
541
 
  while (it != file->s->in_use->end())
 
520
    sql_print_error("%s", message);
 
521
  for (element= file->s->in_use; element; element= list_rest(element))
542
522
  {
543
 
    errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
544
 
    ++it;
 
523
    THD *thd= (THD*) element->data;
 
524
    sql_print_error("%s", thd ? thd_security_context(thd, buf, sizeof(buf), 0)
 
525
                              : "Unknown thread accessing table");
545
526
  }
546
 
}
547
 
 
548
 
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
549
 
                     Table &table_arg)
550
 
  : Cursor(engine_arg, table_arg),
551
 
  file(0),
552
 
  can_enable_indexes(true),
553
 
  is_ordered(true)
554
 
{ }
555
 
 
556
 
Cursor *ha_myisam::clone(memory::Root *mem_root)
 
527
  pthread_mutex_unlock(&file->s->intern_lock);
 
528
}
 
529
 
 
530
}
 
531
 
 
532
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
 
533
  :handler(hton, table_arg), file(0),
 
534
  int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
 
535
                  HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
 
536
                  HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
 
537
                  HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
 
538
                  HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
 
539
                  HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
 
540
                  HA_NEED_READ_RANGE_BUFFER | HA_MRR_CANT_SORT),
 
541
   can_enable_indexes(1)
 
542
{}
 
543
 
 
544
handler *ha_myisam::clone(MEM_ROOT *mem_root)
557
545
{
558
 
  ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
 
546
  ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
559
547
  if (new_handler)
560
548
    new_handler->file->state= file->state;
561
549
  return new_handler;
562
550
}
563
551
 
564
 
const char *ha_myisam::index_type(uint32_t )
 
552
 
 
553
static const char *ha_myisam_exts[] = {
 
554
  ".MYI",
 
555
  ".MYD",
 
556
  NullS
 
557
};
 
558
 
 
559
const char **ha_myisam::bas_ext() const
 
560
{
 
561
  return ha_myisam_exts;
 
562
}
 
563
 
 
564
 
 
565
const char *ha_myisam::index_type(uint key_number __attribute__((__unused__)))
565
566
{
566
567
  return "BTREE";
567
568
}
568
569
 
569
570
/* Name is here without an extension */
570
 
int ha_myisam::doOpen(const drizzled::TableIdentifier &identifier, int mode, uint32_t test_if_locked)
 
571
int ha_myisam::open(const char *name, int mode, uint test_if_locked)
571
572
{
572
573
  MI_KEYDEF *keyinfo;
573
574
  MI_COLUMNDEF *recinfo= 0;
574
 
  uint32_t recs;
575
 
  uint32_t i;
 
575
  uint recs;
 
576
  uint i;
576
577
 
577
578
  /*
578
579
    If the user wants to have memory mapped data files, add an
589
590
    open of a table that is in use by other threads already (if the
590
591
    MyISAM share exists already).
591
592
  */
592
 
  if (!(file= mi_open(identifier, mode, test_if_locked)))
593
 
    return (errno ? errno : -1);
594
 
 
595
 
  if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
 
593
  if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
 
594
    return (my_errno ? my_errno : -1);
 
595
  if (!table->s->tmp_table) /* No need to perform a check for tmp table */
596
596
  {
597
 
    if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
 
597
    if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
598
598
    {
 
599
      /* purecov: begin inspected */
 
600
      DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM "
 
601
                           "key and column definition"));
599
602
      goto err;
 
603
      /* purecov: end */
600
604
    }
601
 
    if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
 
605
    if (check_definition(keyinfo, recinfo, table->s->keys, recs,
602
606
                         file->s->keyinfo, file->s->rec,
603
607
                         file->s->base.keys, file->s->base.fields, true))
604
608
    {
605
 
      errno= HA_ERR_CRASHED;
 
609
      /* purecov: begin inspected */
 
610
      my_errno= HA_ERR_CRASHED;
606
611
      goto err;
 
612
      /* purecov: end */
607
613
    }
608
614
  }
609
 
 
610
 
  assert(test_if_locked);
 
615
  
611
616
  if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
612
 
    mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
 
617
    VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
613
618
 
614
619
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
615
620
  if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
616
 
    mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
617
 
  if (!getTable()->getShare()->db_record_offset)
618
 
    is_ordered= false;
619
 
 
620
 
 
621
 
  keys_with_parts.reset();
622
 
  for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
 
621
    VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
 
622
  if (!table->s->db_record_offset)
 
623
    int_table_flags|=HA_REC_NOT_IN_SEQ;
 
624
  if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
 
625
    int_table_flags|=HA_HAS_CHECKSUM;
 
626
  
 
627
  keys_with_parts.clear_all();
 
628
  for (i= 0; i < table->s->keys; i++)
623
629
  {
624
 
    getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
 
630
    table->key_info[i].block_size= file->s->keyinfo[i].block_length;
625
631
 
626
 
    KeyPartInfo *kp= getTable()->key_info[i].key_part;
627
 
    KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
 
632
    KEY_PART_INFO *kp= table->key_info[i].key_part;
 
633
    KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
628
634
    for (; kp != kp_end; kp++)
629
635
    {
630
 
      if (!kp->field->part_of_key.test(i))
 
636
      if (!kp->field->part_of_key.is_set(i))
631
637
      {
632
 
        keys_with_parts.set(i);
 
638
        keys_with_parts.set_bit(i);
633
639
        break;
634
640
      }
635
641
    }
636
642
  }
637
 
  errno= 0;
 
643
  my_errno= 0;
638
644
  goto end;
639
645
 err:
640
646
  this->close();
641
647
 end:
642
648
  /*
643
 
    Both recinfo and keydef are allocated by multi_malloc(), thus only
 
649
    Both recinfo and keydef are allocated by my_multi_malloc(), thus only
644
650
    recinfo must be freed.
645
651
  */
646
652
  if (recinfo)
647
 
    free((unsigned char*) recinfo);
648
 
  return errno;
 
653
    my_free((uchar*) recinfo, MYF(0));
 
654
  return my_errno;
649
655
}
650
656
 
651
657
int ha_myisam::close(void)
655
661
  return mi_close(tmp);
656
662
}
657
663
 
658
 
int ha_myisam::doInsertRecord(unsigned char *buf)
 
664
int ha_myisam::write_row(uchar *buf)
659
665
{
 
666
  ha_statistic_increment(&SSV::ha_write_count);
 
667
 
 
668
  /* If we have a timestamp column, update it to the current time */
 
669
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
 
670
    table->timestamp_field->set_time();
 
671
 
660
672
  /*
661
673
    If we have an auto_increment column and we are writing a changed row
662
674
    or a new row, then update the auto_increment value in the record.
663
675
  */
664
 
  if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
 
676
  if (table->next_number_field && buf == table->record[0])
665
677
  {
666
678
    int error;
667
679
    if ((error= update_auto_increment()))
670
682
  return mi_write(file,buf);
671
683
}
672
684
 
673
 
 
674
 
int ha_myisam::repair(Session *session, MI_CHECK &param, bool do_optimize)
675
 
{
676
 
  int error=0;
677
 
  uint32_t local_testflag= param.testflag;
 
685
int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
 
686
{
 
687
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
688
  int error;
 
689
  MI_CHECK param;
 
690
  MYISAM_SHARE* share = file->s;
 
691
  const char *old_proc_info=thd->proc_info;
 
692
 
 
693
  thd_proc_info(thd, "Checking table");
 
694
  myisamchk_init(&param);
 
695
  param.thd = thd;
 
696
  param.op_name =   "check";
 
697
  param.db_name=    table->s->db.str;
 
698
  param.table_name= table->alias;
 
699
  param.testflag = check_opt->flags | T_CHECK | T_SILENT;
 
700
  param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
 
701
 
 
702
  if (!(table->db_stat & HA_READ_ONLY))
 
703
    param.testflag|= T_STATISTICS;
 
704
  param.using_global_keycache = 1;
 
705
 
 
706
  if (!mi_is_crashed(file) &&
 
707
      (((param.testflag & T_CHECK_ONLY_CHANGED) &&
 
708
        !(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
 
709
                                  STATE_CRASHED_ON_REPAIR)) &&
 
710
        share->state.open_count == 0) ||
 
711
       ((param.testflag & T_FAST) && (share->state.open_count ==
 
712
                                      (uint) (share->global_changed ? 1 : 0)))))
 
713
    return HA_ADMIN_ALREADY_DONE;
 
714
 
 
715
  error = chk_status(&param, file);             // Not fatal
 
716
  error = chk_size(&param, file);
 
717
  if (!error)
 
718
    error |= chk_del(&param, file, param.testflag);
 
719
  if (!error)
 
720
    error = chk_key(&param, file);
 
721
  if (!error)
 
722
  {
 
723
    if ((!(param.testflag & T_QUICK) &&
 
724
         ((share->options &
 
725
           (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
 
726
          (param.testflag & (T_EXTEND | T_MEDIUM)))) ||
 
727
        mi_is_crashed(file))
 
728
    {
 
729
      uint old_testflag=param.testflag;
 
730
      param.testflag|=T_MEDIUM;
 
731
      if (!(error= init_io_cache(&param.read_cache, file->dfile,
 
732
                                 my_default_record_cache_size, READ_CACHE,
 
733
                                 share->pack.header_length, 1, MYF(MY_WME))))
 
734
      {
 
735
        error= chk_data_link(&param, file, param.testflag & T_EXTEND);
 
736
        end_io_cache(&(param.read_cache));
 
737
      }
 
738
      param.testflag= old_testflag;
 
739
    }
 
740
  }
 
741
  if (!error)
 
742
  {
 
743
    if ((share->state.changed & (STATE_CHANGED |
 
744
                                 STATE_CRASHED_ON_REPAIR |
 
745
                                 STATE_CRASHED | STATE_NOT_ANALYZED)) ||
 
746
        (param.testflag & T_STATISTICS) ||
 
747
        mi_is_crashed(file))
 
748
    {
 
749
      file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
750
      pthread_mutex_lock(&share->intern_lock);
 
751
      share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
 
752
                               STATE_CRASHED_ON_REPAIR);
 
753
      if (!(table->db_stat & HA_READ_ONLY))
 
754
        error=update_state_info(&param,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
 
755
                                UPDATE_STAT);
 
756
      pthread_mutex_unlock(&share->intern_lock);
 
757
      info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
 
758
           HA_STATUS_CONST);
 
759
    }
 
760
  }
 
761
  else if (!mi_is_crashed(file) && !thd->killed)
 
762
  {
 
763
    mi_mark_crashed(file);
 
764
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
765
  }
 
766
 
 
767
  thd_proc_info(thd, old_proc_info);
 
768
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 
769
}
 
770
 
 
771
 
 
772
/*
 
773
  analyze the key distribution in the table
 
774
  As the table may be only locked for read, we have to take into account that
 
775
  two threads may do an analyze at the same time!
 
776
*/
 
777
 
 
778
int ha_myisam::analyze(THD *thd,
 
779
                       HA_CHECK_OPT* check_opt __attribute__((__unused__)))
 
780
{
 
781
  int error=0;
 
782
  MI_CHECK param;
 
783
  MYISAM_SHARE* share = file->s;
 
784
 
 
785
  myisamchk_init(&param);
 
786
  param.thd = thd;
 
787
  param.op_name=    "analyze";
 
788
  param.db_name=    table->s->db.str;
 
789
  param.table_name= table->alias;
 
790
  param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
 
791
                   T_DONT_CHECK_CHECKSUM);
 
792
  param.using_global_keycache = 1;
 
793
  param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
 
794
 
 
795
  if (!(share->state.changed & STATE_NOT_ANALYZED))
 
796
    return HA_ADMIN_ALREADY_DONE;
 
797
 
 
798
  error = chk_key(&param, file);
 
799
  if (!error)
 
800
  {
 
801
    pthread_mutex_lock(&share->intern_lock);
 
802
    error=update_state_info(&param,file,UPDATE_STAT);
 
803
    pthread_mutex_unlock(&share->intern_lock);
 
804
  }
 
805
  else if (!mi_is_crashed(file) && !thd->killed)
 
806
    mi_mark_crashed(file);
 
807
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 
808
}
 
809
 
 
810
 
 
811
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
 
812
{
 
813
  int error;
 
814
  MI_CHECK param;
 
815
  ha_rows start_records;
 
816
 
 
817
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
818
 
 
819
  myisamchk_init(&param);
 
820
  param.thd = thd;
 
821
  param.op_name=  "repair";
 
822
  param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
 
823
                   T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
 
824
                   (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
 
825
  param.sort_buffer_length=  check_opt->sort_buffer_size;
 
826
  start_records=file->state->records;
 
827
  while ((error=repair(thd,param,0)) && param.retry_repair)
 
828
  {
 
829
    param.retry_repair=0;
 
830
    if (test_all_bits(param.testflag,
 
831
                      (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
 
832
    {
 
833
      param.testflag&= ~T_RETRY_WITHOUT_QUICK;
 
834
      sql_print_information("Retrying repair of: '%s' without quick",
 
835
                            table->s->path.str);
 
836
      continue;
 
837
    }
 
838
    param.testflag&= ~T_QUICK;
 
839
    if ((param.testflag & T_REP_BY_SORT))
 
840
    {
 
841
      param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
 
842
      sql_print_information("Retrying repair of: '%s' with keycache",
 
843
                            table->s->path.str);
 
844
      continue;
 
845
    }
 
846
    break;
 
847
  }
 
848
  if (!error && start_records != file->state->records &&
 
849
      !(check_opt->flags & T_VERY_SILENT))
 
850
  {
 
851
    char llbuff[22],llbuff2[22];
 
852
    sql_print_information("Found %s of %s rows when repairing '%s'",
 
853
                          llstr(file->state->records, llbuff),
 
854
                          llstr(start_records, llbuff2),
 
855
                          table->s->path.str);
 
856
  }
 
857
  return error;
 
858
}
 
859
 
 
860
int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
 
861
{
 
862
  int error;
 
863
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
864
  MI_CHECK param;
 
865
 
 
866
  myisamchk_init(&param);
 
867
  param.thd = thd;
 
868
  param.op_name= "optimize";
 
869
  param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
 
870
                   T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
 
871
  param.sort_buffer_length=  check_opt->sort_buffer_size;
 
872
  if ((error= repair(thd,param,1)) && param.retry_repair)
 
873
  {
 
874
    sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
 
875
                      my_errno, param.db_name, param.table_name);
 
876
    param.testflag&= ~T_REP_BY_SORT;
 
877
    error= repair(thd,param,1);
 
878
  }
 
879
  return error;
 
880
}
 
881
 
 
882
 
 
883
int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
 
884
{
 
885
  int error=0;
 
886
  uint local_testflag=param.testflag;
678
887
  bool optimize_done= !do_optimize, statistics_done=0;
679
 
  const char *old_proc_info= session->get_proc_info();
 
888
  const char *old_proc_info=thd->proc_info;
680
889
  char fixed_name[FN_REFLEN];
681
890
  MYISAM_SHARE* share = file->s;
682
891
  ha_rows rows= file->state->records;
 
892
  DBUG_ENTER("ha_myisam::repair");
683
893
 
684
894
  /*
685
895
    Normally this method is entered with a properly opened table. If the
691
901
  */
692
902
  if (file->dfile == -1)
693
903
  {
694
 
    errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' failed. "
 
904
    sql_print_information("Retrying repair of: '%s' failed. "
695
905
                          "Please try REPAIR EXTENDED or myisamchk",
696
 
                          getTable()->getShare()->getPath());
697
 
    return(HA_ADMIN_FAILED);
 
906
                          table->s->path.str);
 
907
    DBUG_RETURN(HA_ADMIN_FAILED);
698
908
  }
699
909
 
700
 
  param.db_name=    getTable()->getShare()->getSchemaName();
701
 
  param.table_name= getTable()->getAlias();
 
910
  param.db_name=    table->s->db.str;
 
911
  param.table_name= table->alias;
702
912
  param.tmpfile_createflag = O_RDWR | O_TRUNC;
703
913
  param.using_global_keycache = 1;
704
 
  param.session= session;
 
914
  param.thd= thd;
 
915
  param.tmpdir= &mysql_tmpdir_list;
705
916
  param.out_flag= 0;
706
 
  param.sort_buffer_length= static_cast<size_t>(sort_buffer_size);
707
 
  strcpy(fixed_name,file->filename);
 
917
  strmov(fixed_name,file->filename);
708
918
 
709
 
  // Don't lock tables if we have used LOCK Table
710
 
  if (mi_lock_database(file, getTable()->getShare()->getType() ? F_EXTRA_LCK : F_WRLCK))
 
919
  // Don't lock tables if we have used LOCK TABLE
 
920
  if (!thd->locked_tables && 
 
921
      mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
711
922
  {
712
 
    mi_check_print_error(&param,ER(ER_CANT_LOCK),errno);
713
 
    return(HA_ADMIN_FAILED);
 
923
    mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
 
924
    DBUG_RETURN(HA_ADMIN_FAILED);
714
925
  }
715
926
 
716
927
  if (!do_optimize ||
721
932
    uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
722
933
                        mi_get_mask_all_keys_active(share->base.keys) :
723
934
                        share->state.key_map);
724
 
    uint32_t testflag=param.testflag;
 
935
    uint testflag=param.testflag;
725
936
    if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
726
937
        (local_testflag & T_REP_BY_SORT))
727
938
    {
728
939
      local_testflag|= T_STATISTICS;
729
940
      param.testflag|= T_STATISTICS;            // We get this for free
730
941
      statistics_done=1;
731
 
      {
732
 
        session->set_proc_info("Repair by sorting");
 
942
      if (thd->variables.myisam_repair_threads>1)
 
943
      {
 
944
        char buf[40];
 
945
        /* TODO: respect myisam_repair_threads variable */
 
946
        snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
 
947
        thd_proc_info(thd, buf);
 
948
        error = mi_repair_parallel(&param, file, fixed_name,
 
949
            param.testflag & T_QUICK);
 
950
        thd_proc_info(thd, "Repair done"); // to reset proc_info, as
 
951
                                      // it was pointing to local buffer
 
952
      }
 
953
      else
 
954
      {
 
955
        thd_proc_info(thd, "Repair by sorting");
733
956
        error = mi_repair_by_sort(&param, file, fixed_name,
734
957
            param.testflag & T_QUICK);
735
958
      }
736
959
    }
737
960
    else
738
961
    {
739
 
      session->set_proc_info("Repair with keycache");
 
962
      thd_proc_info(thd, "Repair with keycache");
740
963
      param.testflag &= ~T_REP_BY_SORT;
741
964
      error=  mi_repair(&param, file, fixed_name,
742
965
                        param.testflag & T_QUICK);
750
973
        (share->state.changed & STATE_NOT_SORTED_PAGES))
751
974
    {
752
975
      optimize_done=1;
753
 
      session->set_proc_info("Sorting index");
 
976
      thd_proc_info(thd, "Sorting index");
754
977
      error=mi_sort_index(&param,file,fixed_name);
755
978
    }
756
979
    if (!statistics_done && (local_testflag & T_STATISTICS))
758
981
      if (share->state.changed & STATE_NOT_ANALYZED)
759
982
      {
760
983
        optimize_done=1;
761
 
        session->set_proc_info("Analyzing");
 
984
        thd_proc_info(thd, "Analyzing");
762
985
        error = chk_key(&param, file);
763
986
      }
764
987
      else
765
988
        local_testflag&= ~T_STATISTICS;         // Don't update statistics
766
989
    }
767
990
  }
768
 
  session->set_proc_info("Saving state");
 
991
  thd_proc_info(thd, "Saving state");
769
992
  if (!error)
770
993
  {
771
994
    if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file))
793
1016
    {
794
1017
      char llbuff[22],llbuff2[22];
795
1018
      mi_check_print_warning(&param,"Number of rows changed from %s to %s",
796
 
                             internal::llstr(rows,llbuff),
797
 
                             internal::llstr(file->state->records,llbuff2));
 
1019
                             llstr(rows,llbuff),
 
1020
                             llstr(file->state->records,llbuff2));
798
1021
    }
799
1022
  }
800
1023
  else
803
1026
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
804
1027
    update_state_info(&param, file, 0);
805
1028
  }
806
 
  session->set_proc_info(old_proc_info);
807
 
  mi_lock_database(file,F_UNLCK);
808
 
 
809
 
  return(error ? HA_ADMIN_FAILED :
 
1029
  thd_proc_info(thd, old_proc_info);
 
1030
  if (!thd->locked_tables)
 
1031
    mi_lock_database(file,F_UNLCK);
 
1032
  DBUG_RETURN(error ? HA_ADMIN_FAILED :
810
1033
              !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
811
1034
}
812
1035
 
813
1036
 
814
1037
/*
 
1038
  Assign table indexes to a specific key cache.
 
1039
*/
 
1040
 
 
1041
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
 
1042
{
 
1043
  KEY_CACHE *new_key_cache= check_opt->key_cache;
 
1044
  const char *errmsg= 0;
 
1045
  int error= HA_ADMIN_OK;
 
1046
  uint64_t map;
 
1047
  TABLE_LIST *table_list= table->pos_in_table_list;
 
1048
  DBUG_ENTER("ha_myisam::assign_to_keycache");
 
1049
 
 
1050
  table->keys_in_use_for_query.clear_all();
 
1051
 
 
1052
  if (table_list->process_index_hints(table))
 
1053
    DBUG_RETURN(HA_ADMIN_FAILED);
 
1054
  map= ~(uint64_t) 0;
 
1055
  if (!table->keys_in_use_for_query.is_clear_all())
 
1056
    /* use all keys if there's no list specified by the user through hints */
 
1057
    map= table->keys_in_use_for_query.to_uint64_t();
 
1058
 
 
1059
  if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
 
1060
  { 
 
1061
    char buf[STRING_BUFFER_USUAL_SIZE];
 
1062
    snprintf(buf, sizeof(buf),
 
1063
                "Failed to flush to index file (errno: %d)", error);
 
1064
    errmsg= buf;
 
1065
    error= HA_ADMIN_CORRUPT;
 
1066
  }
 
1067
 
 
1068
  if (error != HA_ADMIN_OK)
 
1069
  {
 
1070
    /* Send error to user */
 
1071
    MI_CHECK param;
 
1072
    myisamchk_init(&param);
 
1073
    param.thd= thd;
 
1074
    param.op_name=    "assign_to_keycache";
 
1075
    param.db_name=    table->s->db.str;
 
1076
    param.table_name= table->s->table_name.str;
 
1077
    param.testflag= 0;
 
1078
    mi_check_print_error(&param, errmsg);
 
1079
  }
 
1080
  DBUG_RETURN(error);
 
1081
}
 
1082
 
 
1083
 
 
1084
/*
815
1085
  Disable indexes, making it persistent if requested.
816
1086
 
817
1087
  SYNOPSIS
831
1101
    HA_ERR_WRONG_COMMAND  mode not implemented.
832
1102
*/
833
1103
 
834
 
int ha_myisam::disable_indexes(uint32_t mode)
 
1104
int ha_myisam::disable_indexes(uint mode)
835
1105
{
836
1106
  int error;
837
1107
 
870
1140
    Enable indexes, which might have been disabled by disable_index() before.
871
1141
    The modes without _SAVE work only if both data and indexes are empty,
872
1142
    since the MyISAM repair would enable them persistently.
873
 
    To be sure in these cases, call Cursor::delete_all_rows() before.
 
1143
    To be sure in these cases, call handler::delete_all_rows() before.
874
1144
 
875
1145
  IMPLEMENTATION
876
1146
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
883
1153
    HA_ERR_WRONG_COMMAND  mode not implemented.
884
1154
*/
885
1155
 
886
 
int ha_myisam::enable_indexes(uint32_t mode)
 
1156
int ha_myisam::enable_indexes(uint mode)
887
1157
{
888
1158
  int error;
889
1159
 
904
1174
  }
905
1175
  else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
906
1176
  {
907
 
    Session *session= getTable()->in_use;
908
 
    boost::scoped_ptr<MI_CHECK> param_ap(new MI_CHECK);
909
 
    MI_CHECK &param= *param_ap.get();
910
 
    const char *save_proc_info= session->get_proc_info();
911
 
    session->set_proc_info("Creating index");
 
1177
    THD *thd=current_thd;
 
1178
    MI_CHECK param;
 
1179
    const char *save_proc_info=thd->proc_info;
 
1180
    thd_proc_info(thd, "Creating index");
912
1181
    myisamchk_init(&param);
913
1182
    param.op_name= "recreating_index";
914
1183
    param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
915
1184
                     T_CREATE_MISSING_KEYS);
916
1185
    param.myf_rw&= ~MY_WAIT_IF_FULL;
917
 
    param.sort_buffer_length=  static_cast<size_t>(sort_buffer_size);
918
 
    param.stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
919
 
    if ((error= (repair(session,param,0) != HA_ADMIN_OK)) && param.retry_repair)
 
1186
    param.sort_buffer_length=  thd->variables.myisam_sort_buff_size;
 
1187
    param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
 
1188
    param.tmpdir=&mysql_tmpdir_list;
 
1189
    if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
920
1190
    {
921
 
      errmsg_printf(ERRMSG_LVL_WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
922
 
                        errno, param.db_name, param.table_name);
 
1191
      sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
 
1192
                        my_errno, param.db_name, param.table_name);
923
1193
      /* Repairing by sort failed. Now try standard repair method. */
924
1194
      param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
925
 
      error= (repair(session,param,0) != HA_ADMIN_OK);
 
1195
      error= (repair(thd,param,0) != HA_ADMIN_OK);
926
1196
      /*
927
1197
        If the standard repair succeeded, clear all error messages which
928
1198
        might have been set by the first repair. They can still be seen
929
1199
        with SHOW WARNINGS then.
930
1200
      */
931
1201
      if (! error)
932
 
        session->clear_error();
 
1202
        thd->clear_error();
933
1203
    }
934
1204
    info(HA_STATUS_CONST);
935
 
    session->set_proc_info(save_proc_info);
 
1205
    thd_proc_info(thd, save_proc_info);
936
1206
  }
937
1207
  else
938
1208
  {
960
1230
 
961
1231
int ha_myisam::indexes_are_disabled(void)
962
1232
{
963
 
 
 
1233
  
964
1234
  return mi_indexes_are_disabled(file);
965
1235
}
966
1236
 
981
1251
 
982
1252
void ha_myisam::start_bulk_insert(ha_rows rows)
983
1253
{
984
 
  Session *session= getTable()->in_use;
985
 
  ulong size= session->variables.read_buff_size;
 
1254
  DBUG_ENTER("ha_myisam::start_bulk_insert");
 
1255
  THD *thd= current_thd;
 
1256
  ulong size= min(thd->variables.read_buff_size,
 
1257
                  (ulong) (table->s->avg_row_length*rows));
 
1258
  DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
 
1259
                     (ulong) rows, size));
986
1260
 
987
1261
  /* don't enable row cache if too few rows */
988
1262
  if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
991
1265
  can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map,
992
1266
                                            file->s->base.keys);
993
1267
 
994
 
  /*
995
 
    Only disable old index if the table was empty and we are inserting
996
 
    a lot of rows.
997
 
    We should not do this for only a few rows as this is slower and
998
 
    we don't want to update the key statistics based of only a few rows.
999
 
  */
1000
 
  if (file->state->records == 0 && can_enable_indexes &&
1001
 
      (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
1002
 
    mi_disable_non_unique_index(file,rows);
1003
 
  else
 
1268
  if (!(specialflag & SPECIAL_SAFE_MODE))
 
1269
  {
 
1270
    /*
 
1271
      Only disable old index if the table was empty and we are inserting
 
1272
      a lot of rows.
 
1273
      We should not do this for only a few rows as this is slower and
 
1274
      we don't want to update the key statistics based of only a few rows.
 
1275
    */
 
1276
    if (file->state->records == 0 && can_enable_indexes &&
 
1277
        (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
 
1278
      mi_disable_non_unique_index(file,rows);
 
1279
    else
1004
1280
    if (!file->bulk_insert &&
1005
1281
        (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT))
1006
1282
    {
1007
 
      mi_init_bulk_insert(file,
1008
 
                          (size_t)session->variables.bulk_insert_buff_size,
1009
 
                          rows);
 
1283
      mi_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows);
1010
1284
    }
 
1285
  }
 
1286
  DBUG_VOID_RETURN;
1011
1287
}
1012
1288
 
1013
1289
/*
1032
1308
}
1033
1309
 
1034
1310
 
1035
 
 
1036
 
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1037
 
{
 
1311
bool ha_myisam::check_and_repair(THD *thd)
 
1312
{
 
1313
  int error=0;
 
1314
  int marked_crashed;
 
1315
  char *old_query;
 
1316
  uint old_query_length;
 
1317
  HA_CHECK_OPT check_opt;
 
1318
  DBUG_ENTER("ha_myisam::check_and_repair");
 
1319
 
 
1320
  check_opt.init();
 
1321
  check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
 
1322
  // Don't use quick if deleted rows
 
1323
  if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
 
1324
    check_opt.flags|=T_QUICK;
 
1325
  sql_print_warning("Checking table:   '%s'",table->s->path.str);
 
1326
 
 
1327
  old_query= thd->query;
 
1328
  old_query_length= thd->query_length;
 
1329
  pthread_mutex_lock(&LOCK_thread_count);
 
1330
  thd->query=        table->s->table_name.str;
 
1331
  thd->query_length= table->s->table_name.length;
 
1332
  pthread_mutex_unlock(&LOCK_thread_count);
 
1333
 
 
1334
  if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
 
1335
  {
 
1336
    sql_print_warning("Recovering table: '%s'",table->s->path.str);
 
1337
    check_opt.flags=
 
1338
      ((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
 
1339
       (marked_crashed                             ? 0 : T_QUICK) |
 
1340
       (myisam_recover_options & HA_RECOVER_FORCE  ? 0 : T_SAFE_REPAIR) |
 
1341
       T_AUTO_REPAIR);
 
1342
    if (repair(thd, &check_opt))
 
1343
      error=1;
 
1344
  }
 
1345
  pthread_mutex_lock(&LOCK_thread_count);
 
1346
  thd->query= old_query;
 
1347
  thd->query_length= old_query_length;
 
1348
  pthread_mutex_unlock(&LOCK_thread_count);
 
1349
  DBUG_RETURN(error);
 
1350
}
 
1351
 
 
1352
bool ha_myisam::is_crashed() const
 
1353
{
 
1354
  return (file->s->state.changed & STATE_CRASHED ||
 
1355
          (my_disable_locking && file->s->state.open_count));
 
1356
}
 
1357
 
 
1358
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
 
1359
{
 
1360
  ha_statistic_increment(&SSV::ha_update_count);
 
1361
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
1362
    table->timestamp_field->set_time();
1038
1363
  return mi_update(file,old_data,new_data);
1039
1364
}
1040
1365
 
1041
 
int ha_myisam::doDeleteRecord(const unsigned char *buf)
 
1366
int ha_myisam::delete_row(const uchar *buf)
1042
1367
{
 
1368
  ha_statistic_increment(&SSV::ha_delete_count);
1043
1369
  return mi_delete(file,buf);
1044
1370
}
1045
1371
 
 
1372
C_MODE_START
1046
1373
 
1047
 
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
 
1374
my_bool index_cond_func_myisam(void *arg)
1048
1375
{
 
1376
  ha_myisam *h= (ha_myisam*)arg;
 
1377
  /*if (h->in_range_read)*/
 
1378
  if (h->end_range)
 
1379
  {
 
1380
    if (h->compare_key2(h->end_range) > 0)
 
1381
      return 2; /* caller should return HA_ERR_END_OF_FILE already */
 
1382
  }
 
1383
  return (my_bool)h->pushed_idx_cond->val_int();
 
1384
}
 
1385
 
 
1386
C_MODE_END
 
1387
 
 
1388
 
 
1389
int ha_myisam::index_init(uint idx, bool sorted __attribute__((__unused__)))
 
1390
1049
1391
  active_index=idx;
1050
 
  //in_range_read= false;
1051
 
  return 0;
 
1392
  //in_range_read= FALSE;
 
1393
  if (pushed_idx_cond_keyno == idx)
 
1394
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
 
1395
  return 0; 
1052
1396
}
1053
1397
 
1054
1398
 
1055
 
int ha_myisam::doEndIndexScan()
 
1399
int ha_myisam::index_end()
1056
1400
{
1057
1401
  active_index=MAX_KEY;
1058
 
  return 0;
 
1402
  //pushed_idx_cond_keyno= MAX_KEY;
 
1403
  mi_set_index_cond_func(file, NULL, 0);
 
1404
  in_range_check_pushed_down= FALSE;
 
1405
  ds_mrr.dsmrr_close();
 
1406
  return 0; 
1059
1407
}
1060
1408
 
1061
1409
 
1062
 
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
 
1410
int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1063
1411
                              key_part_map keypart_map,
1064
1412
                              enum ha_rkey_function find_flag)
1065
1413
{
1066
 
  assert(inited==INDEX);
1067
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1414
  DBUG_ASSERT(inited==INDEX);
 
1415
  ha_statistic_increment(&SSV::ha_read_key_count);
1068
1416
  int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1069
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1417
  table->status=error ? STATUS_NOT_FOUND: 0;
1070
1418
  return error;
1071
1419
}
1072
1420
 
1073
 
int ha_myisam::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
 
1421
int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
1074
1422
                                  key_part_map keypart_map,
1075
1423
                                  enum ha_rkey_function find_flag)
1076
1424
{
1077
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1425
  ha_statistic_increment(&SSV::ha_read_key_count);
1078
1426
  int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1079
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1427
  table->status=error ? STATUS_NOT_FOUND: 0;
1080
1428
  return error;
1081
1429
}
1082
1430
 
1083
 
int ha_myisam::index_read_last_map(unsigned char *buf, const unsigned char *key,
 
1431
int ha_myisam::index_read_last_map(uchar *buf, const uchar *key,
1084
1432
                                   key_part_map keypart_map)
1085
1433
{
1086
 
  assert(inited==INDEX);
1087
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1434
  DBUG_ENTER("ha_myisam::index_read_last");
 
1435
  DBUG_ASSERT(inited==INDEX);
 
1436
  ha_statistic_increment(&SSV::ha_read_key_count);
1088
1437
  int error=mi_rkey(file, buf, active_index, key, keypart_map,
1089
1438
                    HA_READ_PREFIX_LAST);
1090
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
1091
 
  return(error);
 
1439
  table->status=error ? STATUS_NOT_FOUND: 0;
 
1440
  DBUG_RETURN(error);
1092
1441
}
1093
1442
 
1094
 
int ha_myisam::index_next(unsigned char *buf)
 
1443
int ha_myisam::index_next(uchar *buf)
1095
1444
{
1096
 
  assert(inited==INDEX);
1097
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1445
  DBUG_ASSERT(inited==INDEX);
 
1446
  ha_statistic_increment(&SSV::ha_read_next_count);
1098
1447
  int error=mi_rnext(file,buf,active_index);
1099
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1448
  table->status=error ? STATUS_NOT_FOUND: 0;
1100
1449
  return error;
1101
1450
}
1102
1451
 
1103
 
int ha_myisam::index_prev(unsigned char *buf)
 
1452
int ha_myisam::index_prev(uchar *buf)
1104
1453
{
1105
 
  assert(inited==INDEX);
1106
 
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
 
1454
  DBUG_ASSERT(inited==INDEX);
 
1455
  ha_statistic_increment(&SSV::ha_read_prev_count);
1107
1456
  int error=mi_rprev(file,buf, active_index);
1108
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1457
  table->status=error ? STATUS_NOT_FOUND: 0;
1109
1458
  return error;
1110
1459
}
1111
1460
 
1112
 
int ha_myisam::index_first(unsigned char *buf)
 
1461
int ha_myisam::index_first(uchar *buf)
1113
1462
{
1114
 
  assert(inited==INDEX);
1115
 
  ha_statistic_increment(&system_status_var::ha_read_first_count);
 
1463
  DBUG_ASSERT(inited==INDEX);
 
1464
  ha_statistic_increment(&SSV::ha_read_first_count);
1116
1465
  int error=mi_rfirst(file, buf, active_index);
1117
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1466
  table->status=error ? STATUS_NOT_FOUND: 0;
1118
1467
  return error;
1119
1468
}
1120
1469
 
1121
 
int ha_myisam::index_last(unsigned char *buf)
 
1470
int ha_myisam::index_last(uchar *buf)
1122
1471
{
1123
 
  assert(inited==INDEX);
1124
 
  ha_statistic_increment(&system_status_var::ha_read_last_count);
 
1472
  DBUG_ASSERT(inited==INDEX);
 
1473
  ha_statistic_increment(&SSV::ha_read_last_count);
1125
1474
  int error=mi_rlast(file, buf, active_index);
1126
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1475
  table->status=error ? STATUS_NOT_FOUND: 0;
1127
1476
  return error;
1128
1477
}
1129
1478
 
1130
 
int ha_myisam::index_next_same(unsigned char *buf,
1131
 
                               const unsigned char *,
1132
 
                               uint32_t )
 
1479
int ha_myisam::index_next_same(uchar *buf,
 
1480
                               const uchar *key __attribute__((unused)),
 
1481
                               uint length __attribute__((unused)))
1133
1482
{
1134
1483
  int error;
1135
 
  assert(inited==INDEX);
1136
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1484
  DBUG_ASSERT(inited==INDEX);
 
1485
  ha_statistic_increment(&SSV::ha_read_next_count);
1137
1486
  do
1138
1487
  {
1139
1488
    error= mi_rnext_same(file,buf);
1140
1489
  } while (error == HA_ERR_RECORD_DELETED);
1141
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1490
  table->status=error ? STATUS_NOT_FOUND: 0;
1142
1491
  return error;
1143
1492
}
1144
1493
 
1149
1498
{
1150
1499
  int res;
1151
1500
  //if (!eq_range_arg)
1152
 
  //  in_range_read= true;
 
1501
  //  in_range_read= TRUE;
1153
1502
 
1154
 
  res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
 
1503
  res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted);
1155
1504
 
1156
1505
  //if (res)
1157
 
  //  in_range_read= false;
 
1506
  //  in_range_read= FALSE;
1158
1507
  return res;
1159
1508
}
1160
1509
 
1161
1510
 
1162
1511
int ha_myisam::read_range_next()
1163
1512
{
1164
 
  int res= Cursor::read_range_next();
 
1513
  int res= handler::read_range_next();
1165
1514
  //if (res)
1166
 
  //  in_range_read= false;
 
1515
  //  in_range_read= FALSE;
1167
1516
  return res;
1168
1517
}
1169
1518
 
1170
1519
 
1171
 
int ha_myisam::doStartTableScan(bool scan)
 
1520
int ha_myisam::rnd_init(bool scan)
1172
1521
{
1173
1522
  if (scan)
1174
1523
    return mi_scan_init(file);
1175
1524
  return mi_reset(file);                        // Free buffers
1176
1525
}
1177
1526
 
1178
 
int ha_myisam::rnd_next(unsigned char *buf)
 
1527
int ha_myisam::rnd_next(uchar *buf)
1179
1528
{
1180
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
1529
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1181
1530
  int error=mi_scan(file, buf);
1182
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
1183
 
  return error;
1184
 
}
1185
 
 
1186
 
int ha_myisam::rnd_pos(unsigned char *buf, unsigned char *pos)
1187
 
{
1188
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
1189
 
  int error=mi_rrnd(file, buf, internal::my_get_ptr(pos,ref_length));
1190
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
1191
 
  return error;
1192
 
}
1193
 
 
1194
 
 
1195
 
void ha_myisam::position(const unsigned char *)
1196
 
{
1197
 
  internal::my_off_t row_position= mi_position(file);
1198
 
  internal::my_store_ptr(ref, ref_length, row_position);
1199
 
}
1200
 
 
1201
 
int ha_myisam::info(uint32_t flag)
 
1531
  table->status=error ? STATUS_NOT_FOUND: 0;
 
1532
  return error;
 
1533
}
 
1534
 
 
1535
int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos)
 
1536
{
 
1537
  return rnd_pos(buf,pos);
 
1538
}
 
1539
 
 
1540
int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
 
1541
{
 
1542
  ha_statistic_increment(&SSV::ha_read_rnd_count);
 
1543
  int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
 
1544
  table->status=error ? STATUS_NOT_FOUND: 0;
 
1545
  return error;
 
1546
}
 
1547
 
 
1548
 
 
1549
void ha_myisam::position(const uchar *record __attribute__((__unused__)))
 
1550
{
 
1551
  my_off_t row_position= mi_position(file);
 
1552
  my_store_ptr(ref, ref_length, row_position);
 
1553
}
 
1554
 
 
1555
int ha_myisam::info(uint flag)
1202
1556
{
1203
1557
  MI_ISAMINFO misam_info;
1204
1558
  char name_buff[FN_REFLEN];
1216
1570
  }
1217
1571
  if (flag & HA_STATUS_CONST)
1218
1572
  {
1219
 
    TableShare *share= getTable()->getMutableShare();
 
1573
    TABLE_SHARE *share= table->s;
1220
1574
    stats.max_data_file_length=  misam_info.max_data_file_length;
1221
1575
    stats.max_index_file_length= misam_info.max_index_file_length;
1222
1576
    stats.create_time= misam_info.create_time;
1223
1577
    ref_length= misam_info.reflength;
1224
1578
    share->db_options_in_use= misam_info.options;
1225
 
    stats.block_size= myisam_key_cache_block_size;        /* record block size */
 
1579
    stats.block_size= myisam_block_size;        /* record block size */
1226
1580
 
1227
 
    set_prefix(share->keys_in_use, share->sizeKeys());
1228
 
    /*
1229
 
     * Due to bug 394932 (32-bit solaris build failure), we need
1230
 
     * to convert the uint64_t key_map member of the misam_info
1231
 
     * structure in to a std::bitset so that we can logically and
1232
 
     * it with the share->key_in_use key_map.
1233
 
     */
1234
 
    ostringstream ostr;
1235
 
    string binary_key_map;
1236
 
    uint64_t num= misam_info.key_map;
1237
 
    /*
1238
 
     * Convert the uint64_t to a binary
1239
 
     * string representation of it.
1240
 
     */
1241
 
    while (num > 0)
1242
 
    {
1243
 
      uint64_t bin_digit= num % 2;
1244
 
      ostr << bin_digit;
1245
 
      num/= 2;
1246
 
    }
1247
 
    binary_key_map.append(ostr.str());
1248
 
    /*
1249
 
     * Now we have the binary string representation of the
1250
 
     * flags, we need to fill that string representation out
1251
 
     * with the appropriate number of bits. This is needed
1252
 
     * since key_map is declared as a std::bitset of a certain bit
1253
 
     * width that depends on the MAX_INDEXES variable. 
1254
 
     */
1255
 
    if (MAX_INDEXES <= 64)
1256
 
    {
1257
 
      size_t len= 72 - binary_key_map.length();
1258
 
      string all_zeros(len, '0');
1259
 
      binary_key_map.insert(binary_key_map.begin(),
1260
 
                            all_zeros.begin(),
1261
 
                            all_zeros.end());
1262
 
    }
1263
 
    else
1264
 
    {
1265
 
      size_t len= (MAX_INDEXES + 7) / 8 * 8;
1266
 
      string all_zeros(len, '0');
1267
 
      binary_key_map.insert(binary_key_map.begin(),
1268
 
                            all_zeros.begin(),
1269
 
                            all_zeros.end());
1270
 
    }
1271
 
    key_map tmp_map(binary_key_map);
1272
 
    share->keys_in_use&= tmp_map;
1273
 
    share->keys_for_keyread&= share->keys_in_use;
 
1581
    /* Update share */
 
1582
    if (share->tmp_table == NO_TMP_TABLE)
 
1583
      pthread_mutex_lock(&share->mutex);
 
1584
    share->keys_in_use.set_prefix(share->keys);
 
1585
    share->keys_in_use.intersect_extended(misam_info.key_map);
 
1586
    share->keys_for_keyread.intersect(share->keys_in_use);
1274
1587
    share->db_record_offset= misam_info.record_offset;
1275
1588
    if (share->key_parts)
1276
 
      memcpy(getTable()->key_info[0].rec_per_key,
1277
 
             misam_info.rec_per_key,
1278
 
             sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1279
 
    assert(share->getType() != message::Table::STANDARD);
 
1589
      memcpy((char*) table->key_info[0].rec_per_key,
 
1590
             (char*) misam_info.rec_per_key,
 
1591
             sizeof(table->key_info[0].rec_per_key)*share->key_parts);
 
1592
    if (share->tmp_table == NO_TMP_TABLE)
 
1593
      pthread_mutex_unlock(&share->mutex);
1280
1594
 
1281
1595
   /*
1282
1596
     Set data_file_name and index_file_name to point at the symlink value
1283
1597
     if table is symlinked (Ie;  Real name is not same as generated name)
1284
1598
   */
1285
1599
    data_file_name= index_file_name= 0;
1286
 
    internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
 
1600
    fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1287
1601
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1288
1602
    if (strcmp(name_buff, misam_info.data_file_name))
1289
1603
      data_file_name=misam_info.data_file_name;
1290
 
    internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
 
1604
    fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1291
1605
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1292
1606
    if (strcmp(name_buff, misam_info.index_file_name))
1293
1607
      index_file_name=misam_info.index_file_name;
1295
1609
  if (flag & HA_STATUS_ERRKEY)
1296
1610
  {
1297
1611
    errkey  = misam_info.errkey;
1298
 
    internal::my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
 
1612
    my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
1299
1613
  }
1300
1614
  if (flag & HA_STATUS_TIME)
1301
1615
    stats.update_time = misam_info.update_time;
1308
1622
 
1309
1623
int ha_myisam::extra(enum ha_extra_function operation)
1310
1624
{
 
1625
  if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
 
1626
    return 0;
1311
1627
  return mi_extra(file, operation, 0);
1312
1628
}
1313
1629
 
1314
1630
int ha_myisam::reset(void)
1315
1631
{
 
1632
  pushed_idx_cond= NULL;
 
1633
  pushed_idx_cond_keyno= MAX_KEY;
 
1634
  mi_set_index_cond_func(file, NULL, 0);
 
1635
  ds_mrr.dsmrr_close();
1316
1636
  return mi_reset(file);
1317
1637
}
1318
1638
 
1320
1640
 
1321
1641
int ha_myisam::extra_opt(enum ha_extra_function operation, uint32_t cache_size)
1322
1642
{
 
1643
  if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
 
1644
    return 0;
1323
1645
  return mi_extra(file, operation, (void*) &cache_size);
1324
1646
}
1325
1647
 
1328
1650
  return mi_delete_all_rows(file);
1329
1651
}
1330
1652
 
1331
 
int MyisamEngine::doDropTable(Session &session,
1332
 
                              const TableIdentifier &identifier)
 
1653
int ha_myisam::delete_table(const char *name)
1333
1654
{
1334
 
  session.getMessageCache().removeTableMessage(identifier);
1335
 
 
1336
 
  return mi_delete_table(identifier.getPath().c_str());
 
1655
  return mi_delete_table(name);
1337
1656
}
1338
1657
 
1339
1658
 
1340
 
int ha_myisam::external_lock(Session *session, int lock_type)
 
1659
int ha_myisam::external_lock(THD *thd, int lock_type)
1341
1660
{
1342
 
  file->in_use= session;
1343
 
  return mi_lock_database(file, !getTable()->getShare()->getType() ?
 
1661
  file->in_use.data= thd;
 
1662
  return mi_lock_database(file, !table->s->tmp_table ?
1344
1663
                          lock_type : ((lock_type == F_UNLCK) ?
1345
1664
                                       F_UNLCK : F_EXTRA_LCK));
1346
1665
}
1347
1666
 
1348
 
int MyisamEngine::doCreateTable(Session &session,
1349
 
                                Table& table_arg,
1350
 
                                const TableIdentifier &identifier,
1351
 
                                message::Table& create_proto)
 
1667
THR_LOCK_DATA **ha_myisam::store_lock(THD *thd __attribute__((__unused__)),
 
1668
                                      THR_LOCK_DATA **to,
 
1669
                                      enum thr_lock_type lock_type)
 
1670
{
 
1671
  if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
 
1672
    file->lock.type=lock_type;
 
1673
  *to++= &file->lock;
 
1674
  return to;
 
1675
}
 
1676
 
 
1677
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
 
1678
{
 
1679
  ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
 
1680
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
 
1681
  {
 
1682
    create_info->auto_increment_value= stats.auto_increment_value;
 
1683
  }
 
1684
  create_info->data_file_name=data_file_name;
 
1685
  create_info->index_file_name=index_file_name;
 
1686
}
 
1687
 
 
1688
 
 
1689
int ha_myisam::create(const char *name, register TABLE *table_arg,
 
1690
                      HA_CREATE_INFO *ha_create_info)
1352
1691
{
1353
1692
  int error;
1354
 
  uint32_t create_flags= 0, create_records;
 
1693
  uint create_flags= 0, records, i;
1355
1694
  char buff[FN_REFLEN];
1356
1695
  MI_KEYDEF *keydef;
1357
1696
  MI_COLUMNDEF *recinfo;
1358
1697
  MI_CREATE_INFO create_info;
1359
 
  TableShare *share= table_arg.getMutableShare();
1360
 
  uint32_t options= share->db_options_in_use;
1361
 
  if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1362
 
    return(error);
1363
 
  memset(&create_info, 0, sizeof(create_info));
1364
 
  create_info.max_rows= create_proto.options().max_rows();
1365
 
  create_info.reloc_rows= create_proto.options().min_rows();
 
1698
  TABLE_SHARE *share= table_arg->s;
 
1699
  uint options= share->db_options_in_use;
 
1700
  DBUG_ENTER("ha_myisam::create");
 
1701
  for (i= 0; i < share->keys; i++)
 
1702
  {
 
1703
    if (table_arg->key_info[i].flags & HA_USES_PARSER)
 
1704
    {
 
1705
      create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
 
1706
      break;
 
1707
    }
 
1708
  }
 
1709
  if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
 
1710
    DBUG_RETURN(error); /* purecov: inspected */
 
1711
  bzero((char*) &create_info, sizeof(create_info));
 
1712
  create_info.max_rows= share->max_rows;
 
1713
  create_info.reloc_rows= share->min_rows;
1366
1714
  create_info.with_auto_increment= share->next_number_key_offset == 0;
1367
 
  create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1368
 
                               create_proto.options().auto_increment_value() -1 :
 
1715
  create_info.auto_increment= (ha_create_info->auto_increment_value ?
 
1716
                               ha_create_info->auto_increment_value -1 :
1369
1717
                               (uint64_t) 0);
1370
 
  create_info.data_file_length= (create_proto.options().max_rows() *
1371
 
                                 create_proto.options().avg_row_length());
1372
 
  create_info.data_file_name= NULL;
1373
 
  create_info.index_file_name=  NULL;
 
1718
  create_info.data_file_length= ((uint64_t) share->max_rows *
 
1719
                                 share->avg_row_length);
 
1720
  create_info.data_file_name= ha_create_info->data_file_name;
 
1721
  create_info.index_file_name= ha_create_info->index_file_name;
1374
1722
  create_info.language= share->table_charset->number;
1375
1723
 
1376
 
  if (create_proto.type() == message::Table::TEMPORARY)
 
1724
  if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1377
1725
    create_flags|= HA_CREATE_TMP_TABLE;
 
1726
  if (ha_create_info->options & HA_CREATE_KEEP_FILES)
 
1727
    create_flags|= HA_CREATE_KEEP_FILES;
1378
1728
  if (options & HA_OPTION_PACK_RECORD)
1379
1729
    create_flags|= HA_PACK_RECORD;
 
1730
  if (options & HA_OPTION_CHECKSUM)
 
1731
    create_flags|= HA_CREATE_CHECKSUM;
 
1732
  if (options & HA_OPTION_DELAY_KEY_WRITE)
 
1733
    create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1380
1734
 
1381
 
  /* TODO: Check that the following internal::fn_format is really needed */
1382
 
  error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1383
 
                                       MY_UNPACK_FILENAME|MY_APPEND_EXT),
1384
 
                   share->sizeKeys(), keydef,
1385
 
                   create_records, recinfo,
 
1735
  /* TODO: Check that the following fn_format is really needed */
 
1736
  error= mi_create(fn_format(buff, name, "", "",
 
1737
                             MY_UNPACK_FILENAME|MY_APPEND_EXT),
 
1738
                   share->keys, keydef,
 
1739
                   records, recinfo,
1386
1740
                   0, (MI_UNIQUEDEF*) 0,
1387
1741
                   &create_info, create_flags);
1388
 
  free((unsigned char*) recinfo);
1389
 
 
1390
 
  session.getMessageCache().storeTableMessage(identifier, create_proto);
1391
 
 
1392
 
  return error;
 
1742
  my_free((uchar*) recinfo, MYF(0));
 
1743
  DBUG_RETURN(error);
1393
1744
}
1394
1745
 
1395
1746
 
1396
 
int MyisamEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
 
1747
int ha_myisam::rename_table(const char * from, const char * to)
1397
1748
{
1398
 
  session.getMessageCache().renameTableMessage(from, to);
1399
 
 
1400
 
  return mi_rename(from.getPath().c_str(), to.getPath().c_str());
 
1749
  return mi_rename(from,to);
1401
1750
}
1402
1751
 
1403
1752
 
1404
 
void ha_myisam::get_auto_increment(uint64_t ,
1405
 
                                   uint64_t ,
1406
 
                                   uint64_t ,
 
1753
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((__unused__)),
 
1754
                                   uint64_t increment __attribute__((__unused__)),
 
1755
                                   uint64_t nb_desired_values __attribute__((__unused__)),
1407
1756
                                   uint64_t *first_value,
1408
1757
                                   uint64_t *nb_reserved_values)
1409
1758
{
1410
1759
  uint64_t nr;
1411
1760
  int error;
1412
 
  unsigned char key[MI_MAX_KEY_LENGTH];
 
1761
  uchar key[MI_MAX_KEY_LENGTH];
1413
1762
 
1414
 
  if (!getTable()->getShare()->next_number_key_offset)
 
1763
  if (!table->s->next_number_key_offset)
1415
1764
  {                                             // Autoincrement at key-start
1416
1765
    ha_myisam::info(HA_STATUS_AUTO);
1417
1766
    *first_value= stats.auto_increment_value;
1418
1767
    /* MyISAM has only table-level lock, so reserves to +inf */
1419
 
    *nb_reserved_values= UINT64_MAX;
 
1768
    *nb_reserved_values= ULONGLONG_MAX;
1420
1769
    return;
1421
1770
  }
1422
1771
 
1423
1772
  /* it's safe to call the following if bulk_insert isn't on */
1424
 
  mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
 
1773
  mi_flush_bulk_insert(file, table->s->next_number_index);
1425
1774
 
1426
1775
  (void) extra(HA_EXTRA_KEYREAD);
1427
 
  key_copy(key, getTable()->getInsertRecord(),
1428
 
           &getTable()->key_info[getTable()->getShare()->next_number_index],
1429
 
           getTable()->getShare()->next_number_key_offset);
1430
 
  error= mi_rkey(file, getTable()->getUpdateRecord(), (int) getTable()->getShare()->next_number_index,
1431
 
                 key, make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
 
1776
  key_copy(key, table->record[0],
 
1777
           table->key_info + table->s->next_number_index,
 
1778
           table->s->next_number_key_offset);
 
1779
  error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
 
1780
                 key, make_prev_keypart_map(table->s->next_number_keypart),
1432
1781
                 HA_READ_PREFIX_LAST);
1433
1782
  if (error)
1434
1783
    nr= 1;
1435
1784
  else
1436
1785
  {
1437
 
    /* Get data from getUpdateRecord() */
1438
 
    nr= ((uint64_t) getTable()->next_number_field->
1439
 
         val_int_offset(getTable()->getShare()->rec_buff_length)+1);
 
1786
    /* Get data from record[1] */
 
1787
    nr= ((uint64_t) table->next_number_field->
 
1788
         val_int_offset(table->s->rec_buff_length)+1);
1440
1789
  }
1441
1790
  extra(HA_EXTRA_NO_KEYREAD);
1442
1791
  *first_value= nr;
1464
1813
      HA_READ_KEY_EXACT         Include the key in the range
1465
1814
      HA_READ_AFTER_KEY         Don't include key in range
1466
1815
 
1467
 
    max_key.flag can have one of the following values:
 
1816
    max_key.flag can have one of the following values:  
1468
1817
      HA_READ_BEFORE_KEY        Don't include key in range
1469
1818
      HA_READ_AFTER_KEY         Include all 'end_key' values in the range
1470
1819
 
1475
1824
                        the range.
1476
1825
*/
1477
1826
 
1478
 
ha_rows ha_myisam::records_in_range(uint32_t inx, key_range *min_key,
 
1827
ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key,
1479
1828
                                    key_range *max_key)
1480
1829
{
1481
1830
  return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
1482
1831
}
1483
1832
 
1484
1833
 
1485
 
uint32_t ha_myisam::checksum() const
 
1834
uint ha_myisam::checksum() const
1486
1835
{
1487
1836
  return (uint)file->state->checksum;
1488
1837
}
1489
1838
 
1490
 
static int myisam_init(module::Context &context)
1491
 
1492
 
  context.add(new MyisamEngine(engine_name));
1493
 
  context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
1494
 
                                                                 sort_buffer_size));
1495
 
  context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
1496
 
                                                    &max_sort_file_size,
1497
 
                                                    context.getOptions()["max-sort-file-size"].as<uint64_t>()));
1498
 
 
 
1839
 
 
1840
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
 
1841
                                           uint table_changes)
 
1842
{
 
1843
  uint options= table->s->db_options_in_use;
 
1844
 
 
1845
  if (info->auto_increment_value != stats.auto_increment_value ||
 
1846
      info->data_file_name != data_file_name ||
 
1847
      info->index_file_name != index_file_name ||
 
1848
      table_changes == IS_EQUAL_NO ||
 
1849
      table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
 
1850
    return COMPATIBLE_DATA_NO;
 
1851
 
 
1852
  if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
 
1853
                  HA_OPTION_DELAY_KEY_WRITE)) !=
 
1854
      (info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
 
1855
                              HA_OPTION_DELAY_KEY_WRITE)))
 
1856
    return COMPATIBLE_DATA_NO;
 
1857
  return COMPATIBLE_DATA_YES;
 
1858
}
 
1859
 
 
1860
int myisam_panic(handlerton *hton __attribute__((__unused__)), ha_panic_function flag)
 
1861
{
 
1862
  return mi_panic(flag);
 
1863
}
 
1864
 
 
1865
static int myisam_init(void *p)
 
1866
{
 
1867
  handlerton *myisam_hton;
 
1868
 
 
1869
  myisam_hton= (handlerton *)p;
 
1870
  myisam_hton->state= SHOW_OPTION_YES;
 
1871
  myisam_hton->db_type= DB_TYPE_MYISAM;
 
1872
  myisam_hton->create= myisam_create_handler;
 
1873
  myisam_hton->panic= myisam_panic;
 
1874
  myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1499
1875
  return 0;
1500
1876
}
1501
1877
 
1502
1878
 
1503
 
static void init_options(drizzled::module::option_context &context)
1504
 
{
1505
 
  context("max-sort-file-size",
1506
 
          po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
1507
 
          N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
1508
 
  context("sort-buffer-size",
1509
 
          po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
1510
 
          N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
1511
 
}
1512
 
 
1513
 
 
1514
 
DRIZZLE_DECLARE_PLUGIN
1515
 
{
1516
 
  DRIZZLE_VERSION_ID,
 
1879
 
 
1880
/****************************************************************************
 
1881
 * MyISAM MRR implementation: use DS-MRR
 
1882
 ***************************************************************************/
 
1883
 
 
1884
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
 
1885
                                     uint n_ranges, uint mode, 
 
1886
                                     HANDLER_BUFFER *buf)
 
1887
{
 
1888
  return ds_mrr.dsmrr_init(this, &table->key_info[active_index], 
 
1889
                           seq, seq_init_param, n_ranges, mode, buf);
 
1890
}
 
1891
 
 
1892
int ha_myisam::multi_range_read_next(char **range_info)
 
1893
{
 
1894
  return ds_mrr.dsmrr_next(this, range_info);
 
1895
}
 
1896
 
 
1897
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
 
1898
                                               void *seq_init_param, 
 
1899
                                               uint n_ranges, uint *bufsz,
 
1900
                                               uint *flags, COST_VECT *cost)
 
1901
{
 
1902
  /*
 
1903
    This call is here because there is no location where this->table would
 
1904
    already be known.
 
1905
    TODO: consider moving it into some per-query initialization call.
 
1906
  */
 
1907
  ds_mrr.init(this, table);
 
1908
  return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
 
1909
                                 flags, cost);
 
1910
}
 
1911
 
 
1912
int ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
 
1913
                                     uint *bufsz, uint *flags, COST_VECT *cost)
 
1914
{
 
1915
  ds_mrr.init(this, table);
 
1916
  return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
 
1917
}
 
1918
 
 
1919
/* MyISAM MRR implementation ends */
 
1920
 
 
1921
 
 
1922
/* Index condition pushdown implementation*/
 
1923
 
 
1924
 
 
1925
Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
 
1926
{
 
1927
  pushed_idx_cond_keyno= keyno_arg;
 
1928
  pushed_idx_cond= idx_cond_arg;
 
1929
  in_range_check_pushed_down= TRUE;
 
1930
  if (active_index == pushed_idx_cond_keyno)
 
1931
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
 
1932
  return NULL;
 
1933
}
 
1934
 
 
1935
 
 
1936
struct st_mysql_storage_engine myisam_storage_engine=
 
1937
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
 
1938
 
 
1939
mysql_declare_plugin(myisam)
 
1940
{
 
1941
  MYSQL_STORAGE_ENGINE_PLUGIN,
 
1942
  &myisam_storage_engine,
1517
1943
  "MyISAM",
1518
 
  "2.0",
1519
1944
  "MySQL AB",
1520
1945
  "Default engine as of MySQL 3.23 with great performance",
1521
1946
  PLUGIN_LICENSE_GPL,
1522
1947
  myisam_init, /* Plugin Init */
1523
 
  NULL,           /* system variables */
1524
 
  init_options                        /* config options                  */
1525
 
}
1526
 
DRIZZLE_DECLARE_PLUGIN_END;
 
1948
  NULL, /* Plugin Deinit */
 
1949
  0x0100, /* 1.0 */
 
1950
  NULL,                       /* status variables                */
 
1951
  NULL,                       /* system variables                */
 
1952
  NULL                        /* config options                  */
 
1953
}
 
1954
mysql_declare_plugin_end;
 
1955
 
 
1956
 
 
1957
#ifdef HAVE_QUERY_CACHE
 
1958
/**
 
1959
  @brief Register a named table with a call back function to the query cache.
 
1960
 
 
1961
  @param thd The thread handle
 
1962
  @param table_key A pointer to the table name in the table cache
 
1963
  @param key_length The length of the table name
 
1964
  @param[out] engine_callback The pointer to the storage engine call back
 
1965
    function, currently 0
 
1966
  @param[out] engine_data Engine data will be set to 0.
 
1967
 
 
1968
  @note Despite the name of this function, it is used to check each statement
 
1969
    before it is cached and not to register a table or callback function.
 
1970
 
 
1971
  @see handler::register_query_cache_table
 
1972
 
 
1973
  @return The error code. The engine_data and engine_callback will be set to 0.
 
1974
    @retval TRUE Success
 
1975
    @retval FALSE An error occured
 
1976
*/
 
1977
 
 
1978
my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name,
 
1979
                                              uint table_name_len,
 
1980
                                              qc_engine_callback
 
1981
                                              *engine_callback,
 
1982
                                              uint64_t *engine_data)
 
1983
{
 
1984
  DBUG_ENTER("ha_myisam::register_query_cache_table");
 
1985
  /*
 
1986
    No call back function is needed to determine if a cached statement
 
1987
    is valid or not.
 
1988
  */
 
1989
  *engine_callback= 0;
 
1990
 
 
1991
  /*
 
1992
    No engine data is needed.
 
1993
  */
 
1994
  *engine_data= 0;
 
1995
 
 
1996
  if (file->s->concurrent_insert)
 
1997
  {
 
1998
    /*
 
1999
      If a concurrent INSERT has happened just before the currently
 
2000
      processed SELECT statement, the total size of the table is
 
2001
      unknown.
 
2002
 
 
2003
      To determine if the table size is known, the current thread's snap
 
2004
      shot of the table size with the actual table size are compared.
 
2005
 
 
2006
      If the table size is unknown the SELECT statement can't be cached.
 
2007
 
 
2008
      When concurrent inserts are disabled at table open, mi_open()
 
2009
      does not assign a get_status() function. In this case the local
 
2010
      ("current") status is never updated. We would wrongly think that
 
2011
      we cannot cache the statement.
 
2012
    */
 
2013
    uint64_t actual_data_file_length;
 
2014
    uint64_t current_data_file_length;
 
2015
 
 
2016
    /*
 
2017
      POSIX visibility rules specify that "2. Whatever memory values a
 
2018
      thread can see when it unlocks a mutex <...> can also be seen by any
 
2019
      thread that later locks the same mutex". In this particular case,
 
2020
      concurrent insert thread had modified the data_file_length in
 
2021
      MYISAM_SHARE before it has unlocked (or even locked)
 
2022
      structure_guard_mutex. So, here we're guaranteed to see at least that
 
2023
      value after we've locked the same mutex. We can see a later value
 
2024
      (modified by some other thread) though, but it's ok, as we only want
 
2025
      to know if the variable was changed, the actual new value doesn't matter
 
2026
    */
 
2027
    actual_data_file_length= file->s->state.state.data_file_length;
 
2028
    current_data_file_length= file->save_state.data_file_length;
 
2029
 
 
2030
    if (current_data_file_length != actual_data_file_length)
 
2031
    {
 
2032
      /* Don't cache current statement. */
 
2033
      DBUG_RETURN(FALSE);
 
2034
    }
 
2035
  }
 
2036
 
 
2037
  /* It is ok to try to cache current statement. */
 
2038
  DBUG_RETURN(TRUE);
 
2039
}
 
2040
#endif