~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/service/storage_engine.cc

Merged in latest plugin-slot-reorg.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2009 Sun Microsystems
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; version 2 of the License.
9
 
 *
10
 
 *  This program is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *  GNU General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU General Public License
16
 
 *  along with this program; if not, write to the Free Software
17
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
 
20
 
#include "drizzled/global.h"
21
 
 
22
 
#include <vector>
23
 
#include <algorithm>
24
 
#include <functional>
25
 
 
26
 
#include <google/protobuf/io/zero_copy_stream.h>
27
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
28
 
 
29
 
#include "mysys/my_dir.h"
30
 
#include "mysys/hash.h"
31
 
 
32
 
#include "drizzled/service/storage_engine.h"
33
 
#include "drizzled/plugin/storage_engine.h"
34
 
#include "drizzled/gettext.h"
35
 
#include "drizzled/xid.h"
36
 
#include "drizzled/errmsg_print.h"
37
 
#include "drizzled/plugin/registry.h"
38
 
#include "drizzled/session.h"
39
 
 
40
 
namespace drizzled
41
 
{
42
 
namespace service
43
 
{
44
 
 
45
 
StorageEngine::StorageEngine() : all_engines() {}
46
 
StorageEngine::~StorageEngine() {}
47
 
 
48
 
void StorageEngine::add(plugin::StorageEngine *engine)
49
 
{
50
 
  all_engines.add(engine);
51
 
}
52
 
 
53
 
void StorageEngine::remove(plugin::StorageEngine *engine)
54
 
{
55
 
  all_engines.remove(engine);
56
 
}
57
 
 
58
 
plugin::StorageEngine *StorageEngine::findByName(Session *session,
59
 
                                                 std::string find_str)
60
 
{
61
 
  
62
 
  transform(find_str.begin(), find_str.end(),
63
 
            find_str.begin(), ::tolower);
64
 
  string default_str("default");
65
 
  if (find_str == default_str)
66
 
    return ha_default_storage_engine(session);
67
 
 
68
 
  plugin::StorageEngine *engine= all_engines.find(find_str);
69
 
 
70
 
  if (engine && engine->is_user_selectable())
71
 
    return engine;
72
 
 
73
 
  return NULL;
74
 
}
75
 
 
76
 
class StorageEngineCloseConnection
77
 
  : public unary_function<plugin::StorageEngine *, void>
78
 
{
79
 
  Session *session;
80
 
public:
81
 
  StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
82
 
  /*
83
 
    there's no need to rollback here as all transactions must
84
 
    be rolled back already
85
 
  */
86
 
  inline result_type operator() (argument_type engine)
87
 
  {
88
 
    if (engine->is_enabled() && 
89
 
      session_get_ha_data(session, engine))
90
 
    engine->close_connection(session);
91
 
  }
92
 
};
93
 
 
94
 
/**
95
 
  @note
96
 
    don't bother to rollback here, it's done already
97
 
*/
98
 
void StorageEngine::closeConnection(Session* session)
99
 
{
100
 
  for_each(all_engines.begin(), all_engines.end(),
101
 
           StorageEngineCloseConnection(session));
102
 
}
103
 
 
104
 
void StorageEngine::dropDatabase(char* path)
105
 
{
106
 
  for_each(all_engines.begin(), all_engines.end(),
107
 
           bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
108
 
}
109
 
 
110
 
int StorageEngine::commitOrRollbackByXID(XID *xid, bool commit)
111
 
{
112
 
  vector<int> results;
113
 
  
114
 
  if (commit)
115
 
    transform(all_engines.begin(), all_engines.end(), results.begin(),
116
 
              bind2nd(mem_fun(&plugin::StorageEngine::commit_by_xid),xid));
117
 
  else
118
 
    transform(all_engines.begin(), all_engines.end(), results.begin(),
119
 
              bind2nd(mem_fun(&plugin::StorageEngine::rollback_by_xid),xid));
120
 
 
121
 
  if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
122
 
         == results.end())
123
 
    return 1;
124
 
  return 0;
125
 
}
126
 
 
127
 
/**
128
 
  @details
129
 
  This function should be called when MySQL sends rows of a SELECT result set
130
 
  or the EOF mark to the client. It releases a possible adaptive hash index
131
 
  S-latch held by session in InnoDB and also releases a possible InnoDB query
132
 
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
133
 
  keep them over several calls of the InnoDB handler interface when a join
134
 
  is executed. But when we let the control to pass to the client they have
135
 
  to be released because if the application program uses mysql_use_result(),
136
 
  it may deadlock on the S-latch if the application on another connection
137
 
  performs another SQL query. In MySQL-4.1 this is even more important because
138
 
  there a connection can have several SELECT queries open at the same time.
139
 
 
140
 
  @param session           the thread handle of the current connection
141
 
 
142
 
  @return
143
 
    always 0
144
 
*/
145
 
int StorageEngine::releaseTemporaryLatches(Session *session)
146
 
{
147
 
  for_each(all_engines.begin(), all_engines.end(),
148
 
           bind2nd(mem_fun(&plugin::StorageEngine::release_temporary_latches),session));
149
 
  return 0;
150
 
}
151
 
 
152
 
bool StorageEngine::flushLogs(plugin::StorageEngine *engine)
153
 
{
154
 
  if (engine == NULL)
155
 
  {
156
 
    if (find_if(all_engines.begin(), all_engines.end(),
157
 
            mem_fun(&plugin::StorageEngine::flush_logs))
158
 
          != all_engines.begin())
159
 
      return true;
160
 
  }
161
 
  else
162
 
  {
163
 
    if ((!engine->is_enabled()) ||
164
 
        (engine->flush_logs()))
165
 
      return true;
166
 
  }
167
 
  return false;
168
 
}
169
 
 
170
 
/**
171
 
  recover() step of xa.
172
 
 
173
 
  @note
174
 
    there are three modes of operation:
175
 
    - automatic recover after a crash
176
 
    in this case commit_list != 0, tc_heuristic_recover==0
177
 
    all xids from commit_list are committed, others are rolled back
178
 
    - manual (heuristic) recover
179
 
    in this case commit_list==0, tc_heuristic_recover != 0
180
 
    DBA has explicitly specified that all prepared transactions should
181
 
    be committed (or rolled back).
182
 
    - no recovery (MySQL did not detect a crash)
183
 
    in this case commit_list==0, tc_heuristic_recover == 0
184
 
    there should be no prepared transactions in this case.
185
 
*/
186
 
class XARecover : unary_function<plugin::StorageEngine *, void>
187
 
{
188
 
  int trans_len, found_foreign_xids, found_my_xids;
189
 
  bool result;
190
 
  XID *trans_list;
191
 
  HASH *commit_list;
192
 
  bool dry_run;
193
 
public:
194
 
  XARecover(XID *trans_list_arg, int trans_len_arg,
195
 
            HASH *commit_list_arg, bool dry_run_arg) 
196
 
    : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
197
 
      result(false),
198
 
      trans_list(trans_list_arg), commit_list(commit_list_arg),
199
 
      dry_run(dry_run_arg)
200
 
  {}
201
 
  
202
 
  int getForeignXIDs()
203
 
  {
204
 
    return found_foreign_xids; 
205
 
  }
206
 
 
207
 
  int getMyXIDs()
208
 
  {
209
 
    return found_my_xids; 
210
 
  }
211
 
 
212
 
  result_type operator() (argument_type engine)
213
 
  {
214
 
  
215
 
    int got;
216
 
  
217
 
    if (engine->is_enabled())
218
 
    {
219
 
      while ((got= engine->recover(trans_list, trans_len)) > 0 )
220
 
      {
221
 
        errmsg_printf(ERRMSG_LVL_INFO,
222
 
                      _("Found %d prepared transaction(s) in %s"),
223
 
                      got, engine->getName().c_str());
224
 
        for (int i=0; i < got; i ++)
225
 
        {
226
 
          my_xid x=trans_list[i].get_my_xid();
227
 
          if (!x) // not "mine" - that is generated by external TM
228
 
          {
229
 
            xid_cache_insert(trans_list+i, XA_PREPARED);
230
 
            found_foreign_xids++;
231
 
            continue;
232
 
          }
233
 
          if (dry_run)
234
 
          {
235
 
            found_my_xids++;
236
 
            continue;
237
 
          }
238
 
          // recovery mode
239
 
          if (commit_list ?
240
 
              hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
241
 
              tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
242
 
          {
243
 
            engine->commit_by_xid(trans_list+i);
244
 
          }
245
 
          else
246
 
          {
247
 
            engine->rollback_by_xid(trans_list+i);
248
 
          }
249
 
        }
250
 
        if (got < trans_len)
251
 
          break;
252
 
      }
253
 
    }
254
 
  }
255
 
};
256
 
 
257
 
int StorageEngine::recover(HASH *commit_list)
258
 
{
259
 
  XID *trans_list= NULL;
260
 
  int trans_len= 0;
261
 
 
262
 
  bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
263
 
 
264
 
  /* commit_list and tc_heuristic_recover cannot be set both */
265
 
  assert(commit_list==0 || tc_heuristic_recover==0);
266
 
 
267
 
  /* if either is set, total_ha_2pc must be set too */
268
 
  if (total_ha_2pc <= 1)
269
 
    return 0;
270
 
 
271
 
 
272
 
#ifndef WILL_BE_DELETED_LATER
273
 
 
274
 
  /*
275
 
    for now, only InnoDB supports 2pc. It means we can always safely
276
 
    rollback all pending transactions, without risking inconsistent data
277
 
  */
278
 
 
279
 
  assert(total_ha_2pc == 2); // only InnoDB and binlog
280
 
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
281
 
  dry_run=false;
282
 
#endif
283
 
  for (trans_len= MAX_XID_LIST_SIZE ;
284
 
       trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
285
 
  {
286
 
    trans_list=(XID *)malloc(trans_len*sizeof(XID));
287
 
  }
288
 
  if (!trans_list)
289
 
  {
290
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
291
 
    return(1);
292
 
  }
293
 
 
294
 
  if (commit_list)
295
 
    errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
296
 
 
297
 
 
298
 
  XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
299
 
  for_each(all_engines.begin(), all_engines.end(), recover_func);
300
 
  free(trans_list);
301
 
 
302
 
  if (recover_func.getForeignXIDs())
303
 
    errmsg_printf(ERRMSG_LVL_WARN,
304
 
                  _("Found %d prepared XA transactions"),
305
 
                  recover_func.getForeignXIDs());
306
 
  if (dry_run && recover_func.getMyXIDs())
307
 
  {
308
 
    errmsg_printf(ERRMSG_LVL_ERROR,
309
 
                  _("Found %d prepared transactions! It means that drizzled "
310
 
                    "was not shut down properly last time and critical "
311
 
                    "recovery information (last binlog or %s file) was "
312
 
                    "manually deleted after a crash. You have to start "
313
 
                    "drizzled with the --tc-heuristic-recover switch to "
314
 
                    "commit or rollback pending transactions."),
315
 
                    recover_func.getMyXIDs(), opt_tc_log_file);
316
 
    return(1);
317
 
  }
318
 
  if (commit_list)
319
 
    errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
320
 
  return(0);
321
 
}
322
 
 
323
 
int StorageEngine::startConsistentSnapshot(Session *session)
324
 
{
325
 
  for_each(all_engines.begin(), all_engines.end(),
326
 
           bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
327
 
                   session));
328
 
  return 0;
329
 
}
330
 
 
331
 
class StorageEngineGetTableProto: public unary_function<plugin::StorageEngine *,bool>
332
 
{
333
 
  const char* path;
334
 
  message::Table *table_proto;
335
 
  int *err;
336
 
public:
337
 
  StorageEngineGetTableProto(const char* path_arg,
338
 
                             message::Table *table_proto_arg,
339
 
                             int *err_arg)
340
 
  :path(path_arg), table_proto(table_proto_arg), err(err_arg) {}
341
 
 
342
 
  result_type operator() (argument_type engine)
343
 
  {
344
 
    int ret= engine->getTableProtoImplementation(path, table_proto);
345
 
 
346
 
    if (ret != ENOENT)
347
 
      *err= ret;
348
 
 
349
 
    return *err == EEXIST;
350
 
  }
351
 
};
352
 
 
353
 
static int drizzle_read_table_proto(const char* path, message::Table* table)
354
 
{
355
 
  int fd= open(path, O_RDONLY);
356
 
 
357
 
  if (fd == -1)
358
 
    return errno;
359
 
 
360
 
  google::protobuf::io::ZeroCopyInputStream* input=
361
 
    new google::protobuf::io::FileInputStream(fd);
362
 
 
363
 
  if (table->ParseFromZeroCopyStream(input) == false)
364
 
  {
365
 
    delete input;
366
 
    close(fd);
367
 
    return -1;
368
 
  }
369
 
 
370
 
  delete input;
371
 
  close(fd);
372
 
  return 0;
373
 
}
374
 
 
375
 
/**
376
 
  Call this function in order to give the handler the possiblity
377
 
  to ask engine if there are any new tables that should be written to disk
378
 
  or any dropped tables that need to be removed from disk
379
 
*/
380
 
int StorageEngine::getTableProto(const char* path,
381
 
                                 message::Table *table_proto)
382
 
{
383
 
  int err= ENOENT;
384
 
 
385
 
  Registry<plugin::StorageEngine *>::iterator iter=
386
 
    find_if(all_engines.begin(), all_engines.end(),
387
 
            StorageEngineGetTableProto(path, table_proto, &err));
388
 
  if (iter == all_engines.end())
389
 
  {
390
 
    string proto_path(path);
391
 
    string file_ext(".dfe");
392
 
    proto_path.append(file_ext);
393
 
 
394
 
    int error= access(proto_path.c_str(), F_OK);
395
 
 
396
 
    if (error == 0)
397
 
      err= EEXIST;
398
 
    else
399
 
      err= errno;
400
 
 
401
 
    if (table_proto)
402
 
    {
403
 
      int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
404
 
                                                   table_proto);
405
 
 
406
 
      if (read_proto_err)
407
 
        err= read_proto_err;
408
 
    }
409
 
  }
410
 
 
411
 
  return err;
412
 
}
413
 
 
414
 
/**
415
 
  An interceptor to hijack the text of the error message without
416
 
  setting an error in the thread. We need the text to present it
417
 
  in the form of a warning to the user.
418
 
*/
419
 
 
420
 
class Ha_delete_table_error_handler: public Internal_error_handler
421
 
{
422
 
public:
423
 
  Ha_delete_table_error_handler() : Internal_error_handler() {}
424
 
  virtual bool handle_error(uint32_t sql_errno,
425
 
                            const char *message,
426
 
                            DRIZZLE_ERROR::enum_warning_level level,
427
 
                            Session *session);
428
 
  char buff[DRIZZLE_ERRMSG_SIZE];
429
 
};
430
 
 
431
 
 
432
 
bool
433
 
Ha_delete_table_error_handler::
434
 
handle_error(uint32_t ,
435
 
             const char *message,
436
 
             DRIZZLE_ERROR::enum_warning_level ,
437
 
             Session *)
438
 
{
439
 
  /* Grab the error message */
440
 
  strncpy(buff, message, sizeof(buff)-1);
441
 
  return true;
442
 
}
443
 
 
444
 
 
445
 
class DeleteTableStorageEngine
446
 
  : public unary_function<plugin::StorageEngine *, void>
447
 
{
448
 
  Session *session;
449
 
  const char *path;
450
 
  handler **file;
451
 
  int *dt_error;
452
 
public:
453
 
  DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
454
 
                           handler **file_arg, int *error_arg)
455
 
    : session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
456
 
 
457
 
  result_type operator() (argument_type engine)
458
 
  {
459
 
    char tmp_path[FN_REFLEN];
460
 
    handler *tmp_file;
461
 
 
462
 
    if(*dt_error!=ENOENT) /* already deleted table */
463
 
      return;
464
 
 
465
 
    if (!engine)
466
 
      return;
467
 
 
468
 
    if (!engine->is_enabled())
469
 
      return;
470
 
 
471
 
    if ((tmp_file= engine->create(NULL, session->mem_root)))
472
 
      tmp_file->init();
473
 
    else
474
 
      return;
475
 
 
476
 
    path= engine->checkLowercaseNames(path, tmp_path);
477
 
    const std::string table_path(path);
478
 
    int tmp_error= engine->deleteTable(session, table_path);
479
 
 
480
 
    if (tmp_error != ENOENT)
481
 
    {
482
 
      if (tmp_error == 0)
483
 
      {
484
 
        if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
485
 
          delete_table_proto_file(path);
486
 
        else
487
 
          tmp_error= delete_table_proto_file(path);
488
 
      }
489
 
 
490
 
      *dt_error= tmp_error;
491
 
      if(*file)
492
 
        delete *file;
493
 
      *file= tmp_file;
494
 
      return;
495
 
    }
496
 
    else
497
 
      delete tmp_file;
498
 
 
499
 
    return;
500
 
  }
501
 
};
502
 
 
503
 
 
504
 
/**
505
 
  This should return ENOENT if the file doesn't exists.
506
 
  The .frm file will be deleted only if we return 0 or ENOENT
507
 
*/
508
 
int StorageEngine::deleteTable(Session *session, const char *path,
509
 
                               const char *db, const char *alias,
510
 
                               bool generate_warning)
511
 
{
512
 
  TableShare dummy_share;
513
 
  Table dummy_table;
514
 
  memset(&dummy_table, 0, sizeof(dummy_table));
515
 
  memset(&dummy_share, 0, sizeof(dummy_share));
516
 
 
517
 
  dummy_table.s= &dummy_share;
518
 
 
519
 
  int error= ENOENT;
520
 
  handler *file= NULL;
521
 
 
522
 
  for_each(all_engines.begin(), all_engines.end(),
523
 
           DeleteTableStorageEngine(session, path, &file, &error));
524
 
 
525
 
  if (error == ENOENT) /* proto may be left behind */
526
 
    error= delete_table_proto_file(path);
527
 
 
528
 
  if (error && generate_warning)
529
 
  {
530
 
    /*
531
 
      Because file->print_error() use my_error() to generate the error message
532
 
      we use an internal error handler to intercept it and store the text
533
 
      in a temporary buffer. Later the message will be presented to user
534
 
      as a warning.
535
 
    */
536
 
    Ha_delete_table_error_handler ha_delete_table_error_handler;
537
 
 
538
 
    /* Fill up strucutures that print_error may need */
539
 
    dummy_share.path.str= (char*) path;
540
 
    dummy_share.path.length= strlen(path);
541
 
    dummy_share.db.str= (char*) db;
542
 
    dummy_share.db.length= strlen(db);
543
 
    dummy_share.table_name.str= (char*) alias;
544
 
    dummy_share.table_name.length= strlen(alias);
545
 
    dummy_table.alias= alias;
546
 
 
547
 
    if(file != NULL)
548
 
    {
549
 
      file->change_table_ptr(&dummy_table, &dummy_share);
550
 
 
551
 
      session->push_internal_handler(&ha_delete_table_error_handler);
552
 
      file->print_error(error, 0);
553
 
 
554
 
      session->pop_internal_handler();
555
 
    }
556
 
    else
557
 
      error= -1; /* General form of fail. maybe bad FRM */
558
 
 
559
 
    /*
560
 
      XXX: should we convert *all* errors to warnings here?
561
 
      What if the error is fatal?
562
 
    */
563
 
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
564
 
                 ha_delete_table_error_handler.buff);
565
 
  }
566
 
 
567
 
  if(file)
568
 
    delete file;
569
 
 
570
 
  return error;
571
 
}
572
 
 
573
 
class DFETableNameIterator: public plugin::TableNameIteratorImplementation
574
 
{
575
 
private:
576
 
  MY_DIR *dirp;
577
 
  uint32_t current_entry;
578
 
 
579
 
public:
580
 
  DFETableNameIterator(const std::string &database)
581
 
  : plugin::TableNameIteratorImplementation(database),
582
 
    dirp(NULL),
583
 
    current_entry(-1)
584
 
    {};
585
 
 
586
 
  ~DFETableNameIterator();
587
 
 
588
 
  int next(std::string *name);
589
 
 
590
 
};
591
 
 
592
 
DFETableNameIterator::~DFETableNameIterator()
593
 
{
594
 
  if (dirp)
595
 
    my_dirend(dirp);
596
 
}
597
 
 
598
 
int DFETableNameIterator::next(string *name)
599
 
{
600
 
  char uname[NAME_LEN + 1];
601
 
  FILEINFO *file;
602
 
  char *ext;
603
 
  uint32_t file_name_len;
604
 
  const char *wild= NULL;
605
 
 
606
 
  if (dirp == NULL)
607
 
  {
608
 
    bool dir= false;
609
 
    char path[FN_REFLEN];
610
 
 
611
 
    build_table_filename(path, sizeof(path), db.c_str(), "", false);
612
 
 
613
 
    dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0));
614
 
 
615
 
    if (dirp == NULL)
616
 
    {
617
 
      if (my_errno == ENOENT)
618
 
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
619
 
      else
620
 
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
621
 
      return(ENOENT);
622
 
    }
623
 
    current_entry= -1;
624
 
  }
625
 
 
626
 
  while(true)
627
 
  {
628
 
    current_entry++;
629
 
 
630
 
    if (current_entry == dirp->number_off_files)
631
 
    {
632
 
      my_dirend(dirp);
633
 
      dirp= NULL;
634
 
      return -1;
635
 
    }
636
 
 
637
 
    file= dirp->dir_entry + current_entry;
638
 
 
639
 
    if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),".dfe") ||
640
 
        is_prefix(file->name, TMP_FILE_PREFIX))
641
 
      continue;
642
 
    *ext=0;
643
 
 
644
 
    file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
645
 
 
646
 
    uname[file_name_len]= '\0';
647
 
 
648
 
    if (wild && wild_compare(uname, wild, 0))
649
 
      continue;
650
 
 
651
 
    if (name)
652
 
      name->assign(uname);
653
 
 
654
 
    return 0;
655
 
  }
656
 
}
657
 
 
658
 
 
659
 
TableNameIterator::TableNameIterator(const std::string &db)
660
 
  : current_implementation(NULL), database(db)
661
 
{
662
 
  plugin::Registry &plugins= plugin::Registry::singleton();
663
 
  engine_iter= plugins.storage_engine.begin();
664
 
  default_implementation= new DFETableNameIterator(database);
665
 
}
666
 
 
667
 
TableNameIterator::~TableNameIterator()
668
 
{
669
 
  delete current_implementation;
670
 
}
671
 
 
672
 
int TableNameIterator::next(std::string *name)
673
 
{
674
 
  plugin::Registry &plugins= plugin::Registry::singleton();
675
 
  int err= 0;
676
 
 
677
 
next:
678
 
  if (current_implementation == NULL)
679
 
  {
680
 
    while(current_implementation == NULL &&
681
 
          (engine_iter != plugins.storage_engine.end()))
682
 
    {
683
 
      plugin::StorageEngine *engine= *engine_iter;
684
 
      current_implementation= engine->tableNameIterator(database);
685
 
      engine_iter++;
686
 
    }
687
 
 
688
 
    if (current_implementation == NULL &&
689
 
        (engine_iter == plugins.storage_engine.end()))
690
 
    {
691
 
      current_implementation= default_implementation;
692
 
    }
693
 
  }
694
 
 
695
 
  err= current_implementation->next(name);
696
 
 
697
 
  if (err == -1)
698
 
  {
699
 
    if (current_implementation != default_implementation)
700
 
    {
701
 
      delete current_implementation;
702
 
      current_implementation= NULL;
703
 
      goto next;
704
 
    }
705
 
  }
706
 
 
707
 
  return err;
708
 
}
709
 
 
710
 
 
711
 
} /* namespace service */
712
 
} /* namespace drizzled */
713
 
 
714
 
 
715
 
 
716
 
drizzled::plugin::StorageEngine *ha_resolve_by_name(Session *session,
717
 
                                                    const std::string &find_str)
718
 
{
719
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton(); 
720
 
  return plugins.storage_engine.findByName(session, find_str);
721
 
}
722
 
 
723
 
void ha_close_connection(Session *session)
724
 
{
725
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton(); 
726
 
  plugins.storage_engine.closeConnection(session);
727
 
}
728
 
 
729
 
void ha_drop_database(char* path)
730
 
{
731
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton(); 
732
 
  plugins.storage_engine.dropDatabase(path);
733
 
}
734
 
 
735
 
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
736
 
{
737
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton();
738
 
  return plugins.storage_engine.commitOrRollbackByXID(xid, commit);
739
 
}
740
 
 
741
 
int ha_release_temporary_latches(Session *session)
742
 
{
743
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton();
744
 
  return plugins.storage_engine.releaseTemporaryLatches(session);
745
 
}
746
 
 
747
 
bool ha_flush_logs(drizzled::plugin::StorageEngine *engine)
748
 
{
749
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton();
750
 
  return plugins.storage_engine.flushLogs(engine);
751
 
}
752
 
 
753
 
int ha_recover(HASH *commit_list)
754
 
{
755
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton();
756
 
  return plugins.storage_engine.recover(commit_list);
757
 
}
758
 
 
759
 
int ha_start_consistent_snapshot(Session *session)
760
 
{
761
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton();
762
 
  return plugins.storage_engine.startConsistentSnapshot(session);
763
 
}
764
 
 
765
 
int ha_delete_table(Session *session, const char *path,
766
 
                    const char *db, const char *alias, bool generate_warning)
767
 
{
768
 
  drizzled::plugin::Registry &plugins= drizzled::plugin::Registry::singleton();
769
 
  return plugins.storage_engine.deleteTable(session, path, db,
770
 
                                            alias, generate_warning);
771
 
}
772