~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

  • Committer: Brian Aker
  • Date: 2009-04-09 15:03:26 UTC
  • mfrom: (971.1.44 mordred)
  • Revision ID: brian@gaz-20090409150326-cu50yn12esijpy1c
Merge Monty

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <drizzled/session.h>
26
26
#include <drizzled/error.h>
27
27
#include <drizzled/gettext.h>
28
 
#include <map>
 
28
#include <drizzled/registry.h>
 
29
#include <drizzled/unireg.h>
 
30
#include <drizzled/data_home.h>
29
31
#include <string>
30
32
 
31
33
#include CSTDINT_H
32
34
 
33
35
using namespace std;
34
36
 
35
 
map<string, StorageEngine *> all_engines;
36
 
 
37
 
st_plugin_int *engine2plugin[MAX_HA];
38
 
 
39
 
static const LEX_STRING sys_table_aliases[]=
40
 
{
41
 
  { C_STRING_WITH_LEN("INNOBASE") },  { C_STRING_WITH_LEN("INNODB") },
42
 
  { C_STRING_WITH_LEN("HEAP") },      { C_STRING_WITH_LEN("MEMORY") },
43
 
  {NULL, 0}
44
 
};
 
37
drizzled::Registry<StorageEngine *> all_engines;
 
38
 
 
39
static void add_storage_engine(StorageEngine *engine)
 
40
{
 
41
  all_engines.add(engine);
 
42
}
 
43
 
 
44
static void remove_storage_engine(StorageEngine *engine)
 
45
{
 
46
  all_engines.remove(engine);
 
47
}
45
48
 
46
49
StorageEngine::StorageEngine(const std::string name_arg,
47
50
                             const std::bitset<HTON_BIT_SIZE> &flags_arg,
75
78
  return HA_ERR_NO_SUCH_TABLE;
76
79
}
77
80
 
78
 
static st_plugin_int *ha_default_plugin(Session *session)
79
 
{
80
 
  if (session->variables.table_plugin)
81
 
    return session->variables.table_plugin;
82
 
  return global_system_variables.table_plugin;
83
 
}
84
 
 
85
81
 
86
82
/**
87
83
  Return the default storage engine StorageEngine for thread
94
90
*/
95
91
StorageEngine *ha_default_storage_engine(Session *session)
96
92
{
97
 
  st_plugin_int *plugin= ha_default_plugin(session);
98
 
  assert(plugin);
99
 
  StorageEngine *engine= static_cast<StorageEngine *>(plugin->data);
100
 
  assert(engine);
101
 
  return engine;
 
93
  if (session->variables.storage_engine)
 
94
    return session->variables.storage_engine;
 
95
  return global_system_variables.storage_engine;
102
96
}
103
97
 
104
98
 
111
105
  @return
112
106
    pointer to storage engine plugin handle
113
107
*/
114
 
st_plugin_int *ha_resolve_by_name(Session *session, const LEX_STRING *name)
115
 
{
116
 
  const LEX_STRING *table_alias;
117
 
  st_plugin_int *plugin;
118
 
 
119
 
redo:
120
 
  /* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
121
 
  if (session && !my_charset_utf8_general_ci.coll->strnncoll(&my_charset_utf8_general_ci,
122
 
                           (const unsigned char *)name->str, name->length,
123
 
                           (const unsigned char *)STRING_WITH_LEN("DEFAULT"), 0))
124
 
    return ha_default_plugin(session);
125
 
 
126
 
  if ((plugin= plugin_lock_by_name(name, DRIZZLE_STORAGE_ENGINE_PLUGIN)))
127
 
  {
128
 
    StorageEngine *engine= static_cast<StorageEngine *>(plugin->data);
129
 
    if (engine->is_user_selectable())
130
 
      return plugin;
131
 
  }
132
 
 
133
 
  /*
134
 
    We check for the historical aliases.
135
 
  */
136
 
  for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2)
137
 
  {
138
 
    if (!my_strnncoll(&my_charset_utf8_general_ci,
139
 
                      (const unsigned char *)name->str, name->length,
140
 
                      (const unsigned char *)table_alias->str,
141
 
                      table_alias->length))
142
 
    {
143
 
      name= table_alias + 1;
144
 
      goto redo;
145
 
    }
146
 
  }
147
 
 
148
 
  return NULL;
149
 
}
150
 
 
151
 
 
152
 
st_plugin_int *ha_lock_engine(Session *, StorageEngine *engine)
153
 
{
154
 
  if (engine)
155
 
  {
156
 
    st_plugin_int *plugin= engine2plugin[engine->slot];
157
 
 
158
 
    return plugin;
159
 
  }
 
108
StorageEngine *ha_resolve_by_name(Session *session, const LEX_STRING *name)
 
109
{
 
110
 
 
111
  string find_str(name->str, name->length);
 
112
  transform(find_str.begin(), find_str.end(),
 
113
            find_str.begin(), ::tolower);
 
114
  string default_str("default");
 
115
  if (find_str == default_str)
 
116
    return ha_default_storage_engine(session);
 
117
    
 
118
 
 
119
  StorageEngine *engine= all_engines.find(find_str);
 
120
 
 
121
  if (engine && engine->is_user_selectable())
 
122
    return engine;
160
123
 
161
124
  return NULL;
162
125
}
181
144
  return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
182
145
}
183
146
 
 
147
class StorageEngineCloseConnection
 
148
  : public unary_function<StorageEngine *, void>
 
149
{
 
150
  Session *session;
 
151
public:
 
152
  StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
 
153
  /*
 
154
    there's no need to rollback here as all transactions must
 
155
    be rolled back already
 
156
  */
 
157
  inline result_type operator() (argument_type engine)
 
158
  {
 
159
    if (engine->is_enabled() && 
 
160
      session_get_ha_data(session, engine))
 
161
    engine->close_connection(session);
 
162
  }
 
163
};
 
164
 
 
165
/**
 
166
  @note
 
167
    don't bother to rollback here, it's done already
 
168
*/
 
169
void ha_close_connection(Session* session)
 
170
{
 
171
  for_each(all_engines.begin(), all_engines.end(),
 
172
           StorageEngineCloseConnection(session));
 
173
}
 
174
 
 
175
void ha_drop_database(char* path)
 
176
{
 
177
  for_each(all_engines.begin(), all_engines.end(),
 
178
           bind2nd(mem_fun(&StorageEngine::drop_database),path));
 
179
}
 
180
 
 
181
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
 
182
{
 
183
  vector<int> results;
 
184
  
 
185
  if (commit)
 
186
    transform(all_engines.begin(), all_engines.end(), results.begin(),
 
187
              bind2nd(mem_fun(&StorageEngine::commit_by_xid),xid));
 
188
  else
 
189
    transform(all_engines.begin(), all_engines.end(), results.begin(),
 
190
              bind2nd(mem_fun(&StorageEngine::rollback_by_xid),xid));
 
191
 
 
192
  if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
 
193
         == results.end())
 
194
    return 1;
 
195
  return 0;
 
196
}
 
197
 
 
198
 
 
199
/**
 
200
  @details
 
201
  This function should be called when MySQL sends rows of a SELECT result set
 
202
  or the EOF mark to the client. It releases a possible adaptive hash index
 
203
  S-latch held by session in InnoDB and also releases a possible InnoDB query
 
204
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
 
205
  keep them over several calls of the InnoDB handler interface when a join
 
206
  is executed. But when we let the control to pass to the client they have
 
207
  to be released because if the application program uses mysql_use_result(),
 
208
  it may deadlock on the S-latch if the application on another connection
 
209
  performs another SQL query. In MySQL-4.1 this is even more important because
 
210
  there a connection can have several SELECT queries open at the same time.
 
211
 
 
212
  @param session           the thread handle of the current connection
 
213
 
 
214
  @return
 
215
    always 0
 
216
*/
 
217
int ha_release_temporary_latches(Session *session)
 
218
{
 
219
  for_each(all_engines.begin(), all_engines.end(),
 
220
           bind2nd(mem_fun(&StorageEngine::release_temporary_latches),session));
 
221
  return 0;
 
222
}
 
223
 
 
224
 
 
225
bool ha_flush_logs(StorageEngine *engine)
 
226
{
 
227
  if (engine == NULL)
 
228
  {
 
229
    if (find_if(all_engines.begin(), all_engines.end(),
 
230
            mem_fun(&StorageEngine::flush_logs))
 
231
          != all_engines.begin())
 
232
      return true;
 
233
  }
 
234
  else
 
235
  {
 
236
    if ((!engine->is_enabled()) ||
 
237
        (engine->flush_logs()))
 
238
      return true;
 
239
  }
 
240
  return false;
 
241
}
 
242
 
 
243
/**
 
244
  recover() step of xa.
 
245
 
 
246
  @note
 
247
    there are three modes of operation:
 
248
    - automatic recover after a crash
 
249
    in this case commit_list != 0, tc_heuristic_recover==0
 
250
    all xids from commit_list are committed, others are rolled back
 
251
    - manual (heuristic) recover
 
252
    in this case commit_list==0, tc_heuristic_recover != 0
 
253
    DBA has explicitly specified that all prepared transactions should
 
254
    be committed (or rolled back).
 
255
    - no recovery (MySQL did not detect a crash)
 
256
    in this case commit_list==0, tc_heuristic_recover == 0
 
257
    there should be no prepared transactions in this case.
 
258
*/
 
259
class XARecover : unary_function<StorageEngine *, void>
 
260
{
 
261
  int trans_len, found_foreign_xids, found_my_xids;
 
262
  bool result;
 
263
  XID *trans_list;
 
264
  HASH *commit_list;
 
265
  bool dry_run;
 
266
public:
 
267
  XARecover(XID *trans_list_arg, int trans_len_arg,
 
268
            HASH *commit_list_arg, bool dry_run_arg) 
 
269
    : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
 
270
      trans_list(trans_list_arg), commit_list(commit_list_arg),
 
271
      dry_run(dry_run_arg)
 
272
  {}
 
273
  
 
274
  int getForeignXIDs()
 
275
  {
 
276
    return found_foreign_xids; 
 
277
  }
 
278
 
 
279
  int getMyXIDs()
 
280
  {
 
281
    return found_my_xids; 
 
282
  }
 
283
 
 
284
  result_type operator() (argument_type engine)
 
285
  {
 
286
  
 
287
    int got;
 
288
  
 
289
    if (engine->is_enabled())
 
290
    {
 
291
      while ((got= engine->recover(trans_list, trans_len)) > 0 )
 
292
      {
 
293
        errmsg_printf(ERRMSG_LVL_INFO,
 
294
                      _("Found %d prepared transaction(s) in %s"),
 
295
                      got, engine->getName().c_str());
 
296
        for (int i=0; i < got; i ++)
 
297
        {
 
298
          my_xid x=trans_list[i].get_my_xid();
 
299
          if (!x) // not "mine" - that is generated by external TM
 
300
          {
 
301
            xid_cache_insert(trans_list+i, XA_PREPARED);
 
302
            found_foreign_xids++;
 
303
            continue;
 
304
          }
 
305
          if (dry_run)
 
306
          {
 
307
            found_my_xids++;
 
308
            continue;
 
309
          }
 
310
          // recovery mode
 
311
          if (commit_list ?
 
312
              hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
 
313
              tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
 
314
          {
 
315
            engine->commit_by_xid(trans_list+i);
 
316
          }
 
317
          else
 
318
          {
 
319
            engine->rollback_by_xid(trans_list+i);
 
320
          }
 
321
        }
 
322
        if (got < trans_len)
 
323
          break;
 
324
      }
 
325
    }
 
326
  }
 
327
 
 
328
};
 
329
 
 
330
int ha_recover(HASH *commit_list)
 
331
{
 
332
  XID *trans_list= NULL;
 
333
  int trans_len= 0;
 
334
 
 
335
  bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
 
336
 
 
337
  /* commit_list and tc_heuristic_recover cannot be set both */
 
338
  assert(commit_list==0 || tc_heuristic_recover==0);
 
339
 
 
340
  /* if either is set, total_ha_2pc must be set too */
 
341
  if (total_ha_2pc <= 1)
 
342
    return 0;
 
343
 
 
344
 
 
345
#ifndef WILL_BE_DELETED_LATER
 
346
 
 
347
  /*
 
348
    for now, only InnoDB supports 2pc. It means we can always safely
 
349
    rollback all pending transactions, without risking inconsistent data
 
350
  */
 
351
 
 
352
  assert(total_ha_2pc == 2); // only InnoDB and binlog
 
353
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
 
354
  dry_run=false;
 
355
#endif
 
356
  for (trans_len= MAX_XID_LIST_SIZE ;
 
357
       trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
 
358
  {
 
359
    trans_list=(XID *)malloc(trans_len*sizeof(XID));
 
360
  }
 
361
  if (!trans_list)
 
362
  {
 
363
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
 
364
    return(1);
 
365
  }
 
366
 
 
367
  if (commit_list)
 
368
    errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
 
369
 
 
370
 
 
371
  XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
 
372
  for_each(all_engines.begin(), all_engines.end(), recover_func);
 
373
  free(trans_list);
 
374
 
 
375
  if (recover_func.getForeignXIDs())
 
376
    errmsg_printf(ERRMSG_LVL_WARN,
 
377
                  _("Found %d prepared XA transactions"),
 
378
                  recover_func.getForeignXIDs());
 
379
  if (dry_run && recover_func.getMyXIDs())
 
380
  {
 
381
    errmsg_printf(ERRMSG_LVL_ERROR,
 
382
                  _("Found %d prepared transactions! It means that drizzled "
 
383
                    "was not shut down properly last time and critical "
 
384
                    "recovery information (last binlog or %s file) was "
 
385
                    "manually deleted after a crash. You have to start "
 
386
                    "drizzled with the --tc-heuristic-recover switch to "
 
387
                    "commit or rollback pending transactions."),
 
388
                    recover_func.getMyXIDs(), opt_tc_log_file);
 
389
    return(1);
 
390
  }
 
391
  if (commit_list)
 
392
    errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
 
393
  return(0);
 
394
}
 
395
 
 
396
int ha_start_consistent_snapshot(Session *session)
 
397
{
 
398
  for_each(all_engines.begin(), all_engines.end(),
 
399
           bind2nd(mem_fun(&StorageEngine::start_consistent_snapshot),session));
 
400
  return 0;
 
401
}
 
402
 
 
403
/**
 
404
  Ask handler if the table exists in engine.
 
405
  @retval
 
406
    HA_ERR_NO_SUCH_TABLE     Table does not exist
 
407
  @retval
 
408
    HA_ERR_TABLE_EXIST       Table exists
 
409
  @retval
 
410
    \#                  Error code
 
411
*/
 
412
 
 
413
class TableExistsInStorageEngine: public unary_function<StorageEngine *,bool>
 
414
{
 
415
  Session *session;
 
416
  const char *db;
 
417
  const char *name;
 
418
public:
 
419
  TableExistsInStorageEngine(Session *session_arg,
 
420
                             const char *db_arg, const char *name_arg)
 
421
    :session(session_arg), db(db_arg), name(name_arg) {}
 
422
  result_type operator() (argument_type engine)
 
423
  {
 
424
    int ret= engine->table_exists_in_engine(session, db, name);
 
425
    return ret == HA_ERR_TABLE_EXIST;
 
426
  } 
 
427
};
 
428
 
 
429
/**
 
430
  Call this function in order to give the handler the possiblity
 
431
  to ask engine if there are any new tables that should be written to disk
 
432
  or any dropped tables that need to be removed from disk
 
433
*/
 
434
int ha_table_exists_in_engine(Session* session,
 
435
                              const char* db, const char* name,
 
436
                              StorageEngine **engine_arg)
 
437
{
 
438
  StorageEngine *engine= NULL;
 
439
 
 
440
  drizzled::Registry<StorageEngine *>::iterator iter=
 
441
    find_if(all_engines.begin(), all_engines.end(),
 
442
            TableExistsInStorageEngine(session, db, name));
 
443
  if (iter != all_engines.end()) 
 
444
  {
 
445
    engine= *iter;
 
446
  }
 
447
  else
 
448
  {
 
449
    /* Default way of knowing if a table exists. (checking .frm exists) */
 
450
 
 
451
    char path[FN_REFLEN];
 
452
    build_table_filename(path, sizeof(path),
 
453
                         db, name, "", 0);
 
454
    if (table_proto_exists(path)==EEXIST)
 
455
    {
 
456
      drizzle::Table table;
 
457
      build_table_filename(path, sizeof(path),
 
458
                           db, name, ".dfe", 0);
 
459
      if(drizzle_read_table_proto(path, &table)==0)
 
460
      {
 
461
        LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
 
462
                                 strlen(table.engine().name().c_str()) };
 
463
        engine= ha_resolve_by_name(session, &engine_name);
 
464
      }
 
465
    }
 
466
  }
 
467
 
 
468
  if(engine_arg)
 
469
    *engine_arg= engine;
 
470
 
 
471
  if (engine == NULL)
 
472
    return HA_ERR_NO_SUCH_TABLE;
 
473
  return HA_ERR_TABLE_EXIST;
 
474
}
 
475
 
 
476
 
 
477
static const char *check_lowercase_names(handler *file, const char *path,
 
478
                                         char *tmp_path)
 
479
{
 
480
  if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
 
481
    return path;
 
482
 
 
483
  /* Ensure that table handler get path in lower case */
 
484
  if (tmp_path != path)
 
485
    strcpy(tmp_path, path);
 
486
 
 
487
  /*
 
488
    we only should turn into lowercase database/table part
 
489
    so start the process after homedirectory
 
490
  */
 
491
  my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
 
492
  return tmp_path;
 
493
}
 
494
 
 
495
/**
 
496
  An interceptor to hijack the text of the error message without
 
497
  setting an error in the thread. We need the text to present it
 
498
  in the form of a warning to the user.
 
499
*/
 
500
 
 
501
class Ha_delete_table_error_handler: public Internal_error_handler
 
502
{
 
503
public:
 
504
  Ha_delete_table_error_handler() : Internal_error_handler() {}
 
505
  virtual bool handle_error(uint32_t sql_errno,
 
506
                            const char *message,
 
507
                            DRIZZLE_ERROR::enum_warning_level level,
 
508
                            Session *session);
 
509
  char buff[DRIZZLE_ERRMSG_SIZE];
 
510
};
 
511
 
 
512
 
 
513
bool
 
514
Ha_delete_table_error_handler::
 
515
handle_error(uint32_t ,
 
516
             const char *message,
 
517
             DRIZZLE_ERROR::enum_warning_level ,
 
518
             Session *)
 
519
{
 
520
  /* Grab the error message */
 
521
  strncpy(buff, message, sizeof(buff)-1);
 
522
  return true;
 
523
}
 
524
 
 
525
 
 
526
class DeleteTableStorageEngine
 
527
  : public unary_function<StorageEngine *, void>
 
528
{
 
529
  Session *session;
 
530
  const char *path;
 
531
  handler **file;
 
532
  int *dt_error;
 
533
public:
 
534
  DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
 
535
                           handler **file_arg, int *error_arg)
 
536
    : session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
 
537
 
 
538
  result_type operator() (argument_type engine)
 
539
  {
 
540
 
 
541
    handler *tmp_file;
 
542
    char tmp_path[FN_REFLEN];
 
543
 
 
544
    if(*dt_error!=ENOENT) /* already deleted table */
 
545
      return;
 
546
 
 
547
    if (!engine)
 
548
      return;
 
549
 
 
550
    if (!engine->is_enabled())
 
551
      return;
 
552
 
 
553
    if ((tmp_file= engine->create(NULL, session->mem_root)))
 
554
      tmp_file->init();
 
555
    else
 
556
      return;
 
557
 
 
558
    path= check_lowercase_names(tmp_file, path, tmp_path);
 
559
    int tmp_error= tmp_file->ha_delete_table(path);
 
560
 
 
561
    if(tmp_error!=ENOENT)
 
562
    {
 
563
      *dt_error= tmp_error;
 
564
      if(*file)
 
565
        delete *file;
 
566
      *file= tmp_file;
 
567
      return;
 
568
    }
 
569
    else
 
570
      delete tmp_file;
 
571
    
 
572
    return;
 
573
  }
 
574
};
 
575
 
 
576
/**
 
577
  This should return ENOENT if the file doesn't exists.
 
578
  The .frm file will be deleted only if we return 0 or ENOENT
 
579
*/
 
580
int ha_delete_table(Session *session, const char *path,
 
581
                    const char *db, const char *alias, bool generate_warning)
 
582
{
 
583
  TABLE_SHARE dummy_share;
 
584
  Table dummy_table;
 
585
  memset(&dummy_table, 0, sizeof(dummy_table));
 
586
  memset(&dummy_share, 0, sizeof(dummy_share));
 
587
 
 
588
  dummy_table.s= &dummy_share;
 
589
 
 
590
  int error= ENOENT;
 
591
  handler *file= NULL;
 
592
 
 
593
  for_each(all_engines.begin(), all_engines.end(),
 
594
           DeleteTableStorageEngine(session, path, &file, &error));
 
595
 
 
596
  if (error && generate_warning)
 
597
  {
 
598
    /*
 
599
      Because file->print_error() use my_error() to generate the error message
 
600
      we use an internal error handler to intercept it and store the text
 
601
      in a temporary buffer. Later the message will be presented to user
 
602
      as a warning.
 
603
    */
 
604
    Ha_delete_table_error_handler ha_delete_table_error_handler;
 
605
 
 
606
    /* Fill up strucutures that print_error may need */
 
607
    dummy_share.path.str= (char*) path;
 
608
    dummy_share.path.length= strlen(path);
 
609
    dummy_share.db.str= (char*) db;
 
610
    dummy_share.db.length= strlen(db);
 
611
    dummy_share.table_name.str= (char*) alias;
 
612
    dummy_share.table_name.length= strlen(alias);
 
613
    dummy_table.alias= alias;
 
614
 
 
615
 
 
616
    if(file != NULL)
 
617
    {
 
618
      file->change_table_ptr(&dummy_table, &dummy_share);
 
619
 
 
620
      session->push_internal_handler(&ha_delete_table_error_handler);
 
621
      file->print_error(error, 0);
 
622
 
 
623
      session->pop_internal_handler();
 
624
    }
 
625
    else
 
626
      error= -1; /* General form of fail. maybe bad FRM */
 
627
 
 
628
    /*
 
629
      XXX: should we convert *all* errors to warnings here?
 
630
      What if the error is fatal?
 
631
    */
 
632
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
 
633
                 ha_delete_table_error_handler.buff);
 
634
  }
 
635
 
 
636
  if(file)
 
637
    delete file;
 
638
 
 
639
  return error;
 
640
}
 
641
 
 
642
/**
 
643
  Initiates table-file and calls appropriate database-creator.
 
644
 
 
645
  @retval
 
646
   0  ok
 
647
  @retval
 
648
   1  error
 
649
*/
 
650
int ha_create_table(Session *session, const char *path,
 
651
                    const char *db, const char *table_name,
 
652
                    HA_CREATE_INFO *create_info,
 
653
                    bool update_create_info)
 
654
{
 
655
  int error= 1;
 
656
  Table table;
 
657
  char name_buff[FN_REFLEN];
 
658
  const char *name;
 
659
  TABLE_SHARE share;
 
660
 
 
661
  init_tmp_table_share(session, &share, db, 0, table_name, path);
 
662
  if (open_table_def(session, &share, 0) ||
 
663
      open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
 
664
                            OTM_CREATE))
 
665
    goto err;
 
666
 
 
667
  if (update_create_info)
 
668
    table.updateCreateInfo(create_info);
 
669
 
 
670
  name= check_lowercase_names(table.file, share.path.str, name_buff);
 
671
 
 
672
  error= table.file->ha_create(name, &table, create_info);
 
673
  table.closefrm(false);
 
674
  if (error)
 
675
  {
 
676
    sprintf(name_buff,"%s.%s",db,table_name);
 
677
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
 
678
  }
 
679
err:
 
680
  free_table_share(&share);
 
681
  return(error != 0);
 
682
}
 
683
 
184
684
 
185
685
int storage_engine_finalizer(st_plugin_int *plugin)
186
686
{
187
687
  StorageEngine *engine= static_cast<StorageEngine *>(plugin->data);
188
688
 
189
 
  all_engines.erase(engine->getName());
 
689
  remove_storage_engine(engine);
190
690
 
191
691
  if (engine && plugin->plugin->deinit)
192
692
    (void)plugin->plugin->deinit(engine);
197
697
 
198
698
int storage_engine_initializer(st_plugin_int *plugin)
199
699
{
200
 
  StorageEngine *engine;
201
 
 
 
700
  StorageEngine *engine= NULL;
202
701
 
203
702
  if (plugin->plugin->init)
204
703
  {
211
710
    }
212
711
  }
213
712
 
214
 
  if (engine->is_enabled())
215
 
    engine2plugin[engine->slot]= plugin;
216
 
 
217
 
  /*
218
 
    This is entirely for legacy. We will create a new "disk based" engine and a
219
 
    "memory" engine which will be configurable longterm. We should be able to
220
 
    remove partition and myisammrg.
221
 
  */
222
 
  if (strcmp(plugin->plugin->name, "MEMORY") == 0)
223
 
    heap_engine= engine;
224
 
 
225
 
  if (strcmp(plugin->plugin->name, "MyISAM") == 0)
226
 
    myisam_engine= engine;
 
713
  if (engine != NULL)
 
714
    add_storage_engine(engine);
227
715
 
228
716
  plugin->data= engine;
229
717
  plugin->isInited= true;
230
 
  all_engines[engine->getName()]= engine;
231
718
 
232
719
  return 0;
233
720
}