~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

Updated an include guard thanks to a nice catch during code review from Jay. Thanks Jay!

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
18
 */
19
19
 
20
 
#include "config.h"
21
 
 
22
 
#include <fcntl.h>
23
 
#include <unistd.h>
24
 
 
 
20
#include <drizzled/server_includes.h>
 
21
 
 
22
#include CSTDINT_H
25
23
#include <string>
26
24
#include <vector>
27
25
#include <set>
28
 
#include <fstream>
29
26
#include <algorithm>
30
27
#include <functional>
31
28
 
32
29
#include <google/protobuf/io/zero_copy_stream.h>
33
30
#include <google/protobuf/io/zero_copy_stream_impl.h>
34
31
 
35
 
#include "drizzled/my_hash.h"
36
 
#include "drizzled/cached_directory.h"
 
32
#include "mysys/my_dir.h"
 
33
#include "mysys/hash.h"
 
34
#include "mysys/cached_directory.h"
37
35
 
38
36
#include <drizzled/definitions.h>
39
37
#include <drizzled/base.h>
46
44
#include <drizzled/data_home.h>
47
45
#include "drizzled/errmsg_print.h"
48
46
#include "drizzled/xid.h"
49
 
#include "drizzled/sql_table.h"
50
 
#include "drizzled/global_charset_info.h"
51
 
#include "drizzled/charset.h"
52
 
#include "drizzled/internal/my_sys.h"
53
 
#include "drizzled/db.h"
54
47
 
55
48
#include <drizzled/table_proto.h>
56
49
 
 
50
#include "drizzled/hash.h"
 
51
 
57
52
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
58
53
 
59
54
using namespace std;
61
56
namespace drizzled
62
57
{
63
58
 
64
 
namespace plugin
65
 
{
 
59
typedef hash_map<std::string, plugin::StorageEngine *> EngineMap;
 
60
typedef std::vector<plugin::StorageEngine *> EngineVector;
66
61
 
67
62
static EngineVector vector_of_engines;
68
 
static EngineVector vector_of_schema_engines;
 
63
static EngineVector vector_of_transactional_engines;
69
64
 
70
 
const std::string UNKNOWN_STRING("UNKNOWN");
71
 
const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
 
65
const std::string plugin::UNKNOWN_STRING("UNKNOWN");
 
66
const std::string plugin::DEFAULT_DEFINITION_FILE_EXT(".dfe");
72
67
 
73
68
static std::set<std::string> set_of_table_definition_ext;
74
69
 
75
 
EngineVector &StorageEngine::getSchemaEngines()
76
 
{
77
 
  return vector_of_schema_engines;
78
 
}
79
 
 
80
 
StorageEngine::StorageEngine(const string name_arg,
81
 
                             const bitset<HTON_BIT_SIZE> &flags_arg) :
82
 
  Plugin(name_arg, "StorageEngine"),
83
 
  MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
84
 
  flags(flags_arg)
85
 
{
86
 
}
87
 
 
88
 
StorageEngine::~StorageEngine()
89
 
{
90
 
}
91
 
 
92
 
void StorageEngine::setTransactionReadWrite(Session& session)
93
 
{
94
 
  TransactionContext &statement_ctx= session.transaction.stmt;
95
 
  statement_ctx.markModifiedNonTransData();
96
 
}
97
 
 
98
 
 
99
 
int StorageEngine::renameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
100
 
{
101
 
  setTransactionReadWrite(session);
102
 
 
103
 
  return doRenameTable(session, from, to);
104
 
}
 
70
plugin::StorageEngine::StorageEngine(const string name_arg,
 
71
                                     const bitset<HTON_BIT_SIZE> &flags_arg,
 
72
                                     size_t savepoint_offset_arg,
 
73
                                     bool support_2pc)
 
74
    : Plugin(name_arg, "StorageEngine"),
 
75
      two_phase_commit(support_2pc),
 
76
      enabled(true),
 
77
      flags(flags_arg),
 
78
      savepoint_offset(savepoint_alloc_size),
 
79
      orig_savepoint_offset(savepoint_offset_arg),
 
80
      slot(0)
 
81
{
 
82
  if (enabled)
 
83
  {
 
84
    savepoint_alloc_size+= orig_savepoint_offset;
 
85
    slot= total_ha++;
 
86
    if (two_phase_commit)
 
87
        total_ha_2pc++;
 
88
  }
 
89
  pthread_mutex_init(&proto_cache_mutex, NULL);
 
90
}
 
91
 
 
92
 
 
93
plugin::StorageEngine::~StorageEngine()
 
94
{
 
95
  savepoint_alloc_size-= orig_savepoint_offset;
 
96
  pthread_mutex_destroy(&proto_cache_mutex);
 
97
}
 
98
 
 
99
void plugin::StorageEngine::setTransactionReadWrite(Session& session)
 
100
{
 
101
  Ha_trx_info *ha_info= &session.ha_data[getSlot()].ha_info[0];
 
102
  /*
 
103
    When a storage engine method is called, the transaction must
 
104
    have been started, unless it's a DDL call, for which the
 
105
    storage engine starts the transaction internally, and commits
 
106
    it internally, without registering in the ha_list.
 
107
    Unfortunately here we can't know know for sure if the engine
 
108
    has registered the transaction or not, so we must check.
 
109
  */
 
110
  if (ha_info->is_started())
 
111
  {
 
112
    /*
 
113
     * table_share can be NULL in plugin::StorageEngine::dropTable().
 
114
     */
 
115
    ha_info->set_trx_read_write();
 
116
  }
 
117
}
 
118
 
 
119
 
 
120
 
 
121
int plugin::StorageEngine::doRenameTable(Session *,
 
122
                                         const char *from,
 
123
                                         const char *to)
 
124
{
 
125
  int error= 0;
 
126
  for (const char **ext= bas_ext(); *ext ; ext++)
 
127
  {
 
128
    if (rename_file_ext(from, to, *ext))
 
129
    {
 
130
      if ((error=my_errno) != ENOENT)
 
131
        break;
 
132
      error= 0;
 
133
    }
 
134
  }
 
135
  return error;
 
136
}
 
137
 
105
138
 
106
139
/**
107
140
  Delete all files with extension from bas_ext().
118
151
  @retval
119
152
    !0  Error
120
153
*/
121
 
int StorageEngine::doDropTable(Session&, TableIdentifier &identifier)
122
 
                               
 
154
int plugin::StorageEngine::doDropTable(Session&,
 
155
                                       const string table_path)
123
156
{
124
157
  int error= 0;
125
158
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
127
160
 
128
161
  for (const char **ext= bas_ext(); *ext ; ext++)
129
162
  {
130
 
    internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
131
 
                        MY_UNPACK_FILENAME|MY_APPEND_EXT);
132
 
    if (internal::my_delete_with_symlink(buff, MYF(0)))
 
163
    fn_format(buff, table_path.c_str(), "", *ext,
 
164
              MY_UNPACK_FILENAME|MY_APPEND_EXT);
 
165
    if (my_delete_with_symlink(buff, MYF(0)))
133
166
    {
134
 
      if ((error= errno) != ENOENT)
135
 
        break;
 
167
      if ((error= my_errno) != ENOENT)
 
168
        break;
136
169
    }
137
170
    else
138
 
    {
139
171
      enoent_or_zero= 0;                        // No error for ENOENT
140
 
    }
141
 
 
142
172
    error= enoent_or_zero;
143
173
  }
144
174
  return error;
145
175
}
146
176
 
147
 
bool StorageEngine::addPlugin(StorageEngine *engine)
 
177
const char *plugin::StorageEngine::checkLowercaseNames(const char *path,
 
178
                                                       char *tmp_path)
 
179
{
 
180
  if (flags.test(HTON_BIT_FILE_BASED))
 
181
    return path;
 
182
 
 
183
  /* Ensure that table Cursor get path in lower case */
 
184
  if (tmp_path != path)
 
185
    strcpy(tmp_path, path);
 
186
 
 
187
  /*
 
188
    we only should turn into lowercase database/table part
 
189
    so start the process after homedirectory
 
190
  */
 
191
  if (strstr(tmp_path, drizzle_tmpdir) == tmp_path)
 
192
    my_casedn_str(files_charset_info, tmp_path + strlen(drizzle_tmpdir));
 
193
  else
 
194
    my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
 
195
 
 
196
  return tmp_path;
 
197
}
 
198
 
 
199
 
 
200
bool plugin::StorageEngine::addPlugin(plugin::StorageEngine *engine)
148
201
{
149
202
 
150
203
  vector_of_engines.push_back(engine);
151
204
 
 
205
  if (engine->check_flag(HTON_BIT_DOES_TRANSACTIONS))
 
206
    vector_of_transactional_engines.push_back(engine);
 
207
 
152
208
  if (engine->getTableDefinitionFileExtension().length())
153
209
  {
154
210
    assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
155
211
    set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
156
212
  }
157
213
 
158
 
  if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
159
 
    vector_of_schema_engines.push_back(engine);
160
 
 
161
214
  return false;
162
215
}
163
216
 
164
 
void StorageEngine::removePlugin(StorageEngine *)
 
217
void plugin::StorageEngine::removePlugin(plugin::StorageEngine *)
165
218
{
166
219
  if (shutdown_has_begun == false)
167
220
  {
168
221
    vector_of_engines.clear();
169
 
    vector_of_schema_engines.clear();
 
222
    vector_of_transactional_engines.clear();
170
223
 
171
224
    shutdown_has_begun= true;
172
225
  }
173
226
}
174
227
 
175
228
class FindEngineByName
176
 
  : public unary_function<StorageEngine *, bool>
 
229
  : public unary_function<plugin::StorageEngine *, bool>
177
230
{
178
 
  const string &target;
179
 
 
 
231
  const string target;
180
232
public:
181
 
  explicit FindEngineByName(const string &target_arg) :
182
 
    target(target_arg)
183
 
  {
184
 
  }
 
233
  explicit FindEngineByName(const string target_arg)
 
234
    : target(target_arg)
 
235
  {}
185
236
  result_type operator() (argument_type engine)
186
237
  {
187
238
    string engine_name(engine->getName());
192
243
  }
193
244
};
194
245
 
195
 
StorageEngine *StorageEngine::findByName(const string &find_str)
 
246
plugin::StorageEngine *plugin::StorageEngine::findByName(string find_str)
196
247
{
197
 
  string search_string(find_str);
198
 
  transform(search_string.begin(), search_string.end(),
199
 
            search_string.begin(), ::tolower);
 
248
  transform(find_str.begin(), find_str.end(),
 
249
            find_str.begin(), ::tolower);
200
250
 
201
251
  
202
252
  EngineVector::iterator iter= find_if(vector_of_engines.begin(),
203
253
                                       vector_of_engines.end(),
204
 
                                       FindEngineByName(search_string));
 
254
                                       FindEngineByName(find_str));
205
255
  if (iter != vector_of_engines.end())
206
256
  {
207
257
    StorageEngine *engine= *iter;
212
262
  return NULL;
213
263
}
214
264
 
215
 
StorageEngine *StorageEngine::findByName(Session& session, const string &find_str)
 
265
plugin::StorageEngine *plugin::StorageEngine::findByName(Session& session,
 
266
                                                         string find_str)
216
267
{
217
 
  string search_string(find_str);
218
 
  transform(search_string.begin(), search_string.end(),
219
 
            search_string.begin(), ::tolower);
 
268
  
 
269
  transform(find_str.begin(), find_str.end(),
 
270
            find_str.begin(), ::tolower);
220
271
 
221
 
  if (search_string.compare("default") == 0)
 
272
  if (find_str.compare("default") == 0)
222
273
    return session.getDefaultStorageEngine();
223
274
 
224
275
  EngineVector::iterator iter= find_if(vector_of_engines.begin(),
225
276
                                       vector_of_engines.end(),
226
 
                                       FindEngineByName(search_string));
 
277
                                       FindEngineByName(find_str));
227
278
  if (iter != vector_of_engines.end())
228
279
  {
229
280
    StorageEngine *engine= *iter;
234
285
  return NULL;
235
286
}
236
287
 
237
 
class StorageEngineCloseConnection : public unary_function<StorageEngine *, void>
 
288
class StorageEngineCloseConnection
 
289
: public unary_function<plugin::StorageEngine *, void>
238
290
{
239
291
  Session *session;
240
292
public:
245
297
  */
246
298
  inline result_type operator() (argument_type engine)
247
299
  {
248
 
    if (*session->getEngineData(engine))
249
 
      engine->close_connection(session);
 
300
    if (engine->is_enabled() && 
 
301
        session_get_ha_data(session, engine))
 
302
    engine->close_connection(session);
250
303
  }
251
304
};
252
305
 
254
307
  @note
255
308
    don't bother to rollback here, it's done already
256
309
*/
257
 
void StorageEngine::closeConnection(Session* session)
 
310
void plugin::StorageEngine::closeConnection(Session* session)
258
311
{
259
312
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
260
313
           StorageEngineCloseConnection(session));
261
314
}
262
315
 
263
 
bool StorageEngine::flushLogs(StorageEngine *engine)
 
316
void plugin::StorageEngine::dropDatabase(char* path)
 
317
{
 
318
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
 
319
           bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
 
320
}
 
321
 
 
322
int plugin::StorageEngine::commitOrRollbackByXID(XID *xid, bool commit)
 
323
{
 
324
  vector<int> results;
 
325
  
 
326
  if (commit)
 
327
    transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
 
328
              bind2nd(mem_fun(&plugin::StorageEngine::commit_by_xid),xid));
 
329
  else
 
330
    transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
 
331
              bind2nd(mem_fun(&plugin::StorageEngine::rollback_by_xid),xid));
 
332
 
 
333
  if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
 
334
         == results.end())
 
335
    return 1;
 
336
  return 0;
 
337
}
 
338
 
 
339
/**
 
340
  @details
 
341
  This function should be called when MySQL sends rows of a SELECT result set
 
342
  or the EOF mark to the client. It releases a possible adaptive hash index
 
343
  S-latch held by session in InnoDB and also releases a possible InnoDB query
 
344
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
 
345
  keep them over several calls of the InnoDB Cursor interface when a join
 
346
  is executed. But when we let the control to pass to the client they have
 
347
  to be released because if the application program uses mysql_use_result(),
 
348
  it may deadlock on the S-latch if the application on another connection
 
349
  performs another SQL query. In MySQL-4.1 this is even more important because
 
350
  there a connection can have several SELECT queries open at the same time.
 
351
 
 
352
  @param session           the thread handle of the current connection
 
353
 
 
354
  @return
 
355
    always 0
 
356
*/
 
357
int plugin::StorageEngine::releaseTemporaryLatches(Session *session)
 
358
{
 
359
  for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
 
360
           bind2nd(mem_fun(&plugin::StorageEngine::release_temporary_latches),session));
 
361
  return 0;
 
362
}
 
363
 
 
364
bool plugin::StorageEngine::flushLogs(plugin::StorageEngine *engine)
264
365
{
265
366
  if (engine == NULL)
266
367
  {
267
368
    if (find_if(vector_of_engines.begin(), vector_of_engines.end(),
268
 
                mem_fun(&StorageEngine::flush_logs))
269
 
        != vector_of_engines.begin())
 
369
            mem_fun(&plugin::StorageEngine::flush_logs))
 
370
          != vector_of_engines.begin())
270
371
      return true;
271
372
  }
272
373
  else
273
374
  {
274
 
    if (engine->flush_logs())
 
375
    if ((!engine->is_enabled()) ||
 
376
        (engine->flush_logs()))
275
377
      return true;
276
378
  }
277
379
  return false;
278
380
}
279
381
 
280
 
class StorageEngineGetTableDefinition: public unary_function<StorageEngine *,bool>
 
382
/**
 
383
  recover() step of xa.
 
384
 
 
385
  @note
 
386
    there are three modes of operation:
 
387
    - automatic recover after a crash
 
388
    in this case commit_list != 0, tc_heuristic_recover==0
 
389
    all xids from commit_list are committed, others are rolled back
 
390
    - manual (heuristic) recover
 
391
    in this case commit_list==0, tc_heuristic_recover != 0
 
392
    DBA has explicitly specified that all prepared transactions should
 
393
    be committed (or rolled back).
 
394
    - no recovery (MySQL did not detect a crash)
 
395
    in this case commit_list==0, tc_heuristic_recover == 0
 
396
    there should be no prepared transactions in this case.
 
397
*/
 
398
class XARecover : unary_function<plugin::StorageEngine *, void>
 
399
{
 
400
  int trans_len, found_foreign_xids, found_my_xids;
 
401
  bool result;
 
402
  XID *trans_list;
 
403
  HASH *commit_list;
 
404
  bool dry_run;
 
405
public:
 
406
  XARecover(XID *trans_list_arg, int trans_len_arg,
 
407
            HASH *commit_list_arg, bool dry_run_arg) 
 
408
    : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
 
409
      result(false),
 
410
      trans_list(trans_list_arg), commit_list(commit_list_arg),
 
411
      dry_run(dry_run_arg)
 
412
  {}
 
413
  
 
414
  int getForeignXIDs()
 
415
  {
 
416
    return found_foreign_xids; 
 
417
  }
 
418
 
 
419
  int getMyXIDs()
 
420
  {
 
421
    return found_my_xids; 
 
422
  }
 
423
 
 
424
  result_type operator() (argument_type engine)
 
425
  {
 
426
  
 
427
    int got;
 
428
  
 
429
    if (engine->is_enabled())
 
430
    {
 
431
      while ((got= engine->recover(trans_list, trans_len)) > 0 )
 
432
      {
 
433
        errmsg_printf(ERRMSG_LVL_INFO,
 
434
                      _("Found %d prepared transaction(s) in %s"),
 
435
                      got, engine->getName().c_str());
 
436
        for (int i=0; i < got; i ++)
 
437
        {
 
438
          my_xid x=trans_list[i].get_my_xid();
 
439
          if (!x) // not "mine" - that is generated by external TM
 
440
          {
 
441
            xid_cache_insert(trans_list+i, XA_PREPARED);
 
442
            found_foreign_xids++;
 
443
            continue;
 
444
          }
 
445
          if (dry_run)
 
446
          {
 
447
            found_my_xids++;
 
448
            continue;
 
449
          }
 
450
          // recovery mode
 
451
          if (commit_list ?
 
452
              hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
 
453
              tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
 
454
          {
 
455
            engine->commit_by_xid(trans_list+i);
 
456
          }
 
457
          else
 
458
          {
 
459
            engine->rollback_by_xid(trans_list+i);
 
460
          }
 
461
        }
 
462
        if (got < trans_len)
 
463
          break;
 
464
      }
 
465
    }
 
466
  }
 
467
};
 
468
 
 
469
int plugin::StorageEngine::recover(HASH *commit_list)
 
470
{
 
471
  XID *trans_list= NULL;
 
472
  int trans_len= 0;
 
473
 
 
474
  bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
 
475
 
 
476
  /* commit_list and tc_heuristic_recover cannot be set both */
 
477
  assert(commit_list==0 || tc_heuristic_recover==0);
 
478
 
 
479
  /* if either is set, total_ha_2pc must be set too */
 
480
  if (total_ha_2pc <= 1)
 
481
    return 0;
 
482
 
 
483
 
 
484
#ifndef WILL_BE_DELETED_LATER
 
485
 
 
486
  /*
 
487
    for now, only InnoDB supports 2pc. It means we can always safely
 
488
    rollback all pending transactions, without risking inconsistent data
 
489
  */
 
490
 
 
491
  assert(total_ha_2pc == 2); // only InnoDB and binlog
 
492
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
 
493
  dry_run=false;
 
494
#endif
 
495
  for (trans_len= MAX_XID_LIST_SIZE ;
 
496
       trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
 
497
  {
 
498
    trans_list=(XID *)malloc(trans_len*sizeof(XID));
 
499
  }
 
500
  if (!trans_list)
 
501
  {
 
502
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
 
503
    return(1);
 
504
  }
 
505
 
 
506
  if (commit_list)
 
507
    errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
 
508
 
 
509
 
 
510
  XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
 
511
  for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
 
512
           recover_func);
 
513
  free(trans_list);
 
514
 
 
515
  if (recover_func.getForeignXIDs())
 
516
    errmsg_printf(ERRMSG_LVL_WARN,
 
517
                  _("Found %d prepared XA transactions"),
 
518
                  recover_func.getForeignXIDs());
 
519
  if (dry_run && recover_func.getMyXIDs())
 
520
  {
 
521
    errmsg_printf(ERRMSG_LVL_ERROR,
 
522
                  _("Found %d prepared transactions! It means that drizzled "
 
523
                    "was not shut down properly last time and critical "
 
524
                    "recovery information (last binlog or %s file) was "
 
525
                    "manually deleted after a crash. You have to start "
 
526
                    "drizzled with the --tc-heuristic-recover switch to "
 
527
                    "commit or rollback pending transactions."),
 
528
                    recover_func.getMyXIDs(), opt_tc_log_file);
 
529
    return(1);
 
530
  }
 
531
  if (commit_list)
 
532
    errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
 
533
  return(0);
 
534
}
 
535
 
 
536
int plugin::StorageEngine::startConsistentSnapshot(Session *session)
 
537
{
 
538
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
 
539
           bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
 
540
                   session));
 
541
  return 0;
 
542
}
 
543
 
 
544
class StorageEngineGetTableDefinition: public unary_function<plugin::StorageEngine *,bool>
281
545
{
282
546
  Session& session;
283
 
  TableIdentifier &identifier;
284
 
  message::Table &table_message;
285
 
  int &err;
 
547
  const char* path;
 
548
  const char *db;
 
549
  const char *table_name;
 
550
  const bool is_tmp;
 
551
  message::Table *table_proto;
 
552
  int *err;
286
553
 
287
554
public:
288
555
  StorageEngineGetTableDefinition(Session& session_arg,
289
 
                                  TableIdentifier &identifier_arg,
290
 
                                  message::Table &table_message_arg,
291
 
                                  int &err_arg) :
 
556
                                  const char* path_arg,
 
557
                                  const char *db_arg,
 
558
                                  const char *table_name_arg,
 
559
                                  const bool is_tmp_arg,
 
560
                                  message::Table *table_proto_arg,
 
561
                                  int *err_arg) :
292
562
    session(session_arg), 
293
 
    identifier(identifier_arg),
294
 
    table_message(table_message_arg), 
 
563
    path(path_arg), 
 
564
    db(db_arg),
 
565
    table_name(table_name_arg),
 
566
    is_tmp(is_tmp_arg),
 
567
    table_proto(table_proto_arg), 
295
568
    err(err_arg) {}
296
569
 
297
570
  result_type operator() (argument_type engine)
298
571
  {
299
 
    int ret= engine->doGetTableDefinition(session, identifier, table_message);
 
572
    int ret= engine->doGetTableDefinition(session,
 
573
                                          path, 
 
574
                                          db,
 
575
                                          table_name,
 
576
                                          is_tmp,
 
577
                                          table_proto);
300
578
 
301
579
    if (ret != ENOENT)
302
 
      err= ret;
303
 
 
304
 
    return err == EEXIST || err != ENOENT;
305
 
  }
306
 
};
307
 
 
308
 
class StorageEngineDoesTableExist: public unary_function<StorageEngine *, bool>
309
 
{
310
 
  Session& session;
311
 
  TableIdentifier &identifier;
312
 
 
313
 
public:
314
 
  StorageEngineDoesTableExist(Session& session_arg, TableIdentifier &identifier_arg) :
315
 
    session(session_arg), 
316
 
    identifier(identifier_arg) 
317
 
  { }
318
 
 
319
 
  result_type operator() (argument_type engine)
320
 
  {
321
 
    return engine->doDoesTableExist(session, identifier);
322
 
  }
323
 
};
324
 
 
325
 
/**
326
 
  Utility method which hides some of the details of getTableDefinition()
327
 
*/
328
 
bool plugin::StorageEngine::doesTableExist(Session &session,
329
 
                                           TableIdentifier &identifier,
330
 
                                           bool include_temporary_tables)
331
 
{
332
 
  if (include_temporary_tables)
333
 
  {
334
 
    if (session.doDoesTableExist(identifier))
335
 
      return true;
336
 
  }
337
 
 
338
 
  EngineVector::iterator iter=
339
 
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
340
 
            StorageEngineDoesTableExist(session, identifier));
341
 
 
342
 
  if (iter == vector_of_engines.end())
343
 
  {
344
 
    return false;
345
 
  }
346
 
 
347
 
  return true;
348
 
}
349
 
 
350
 
bool plugin::StorageEngine::doDoesTableExist(Session&, TableIdentifier&)
351
 
{
352
 
  cerr << " Engine was called for doDoesTableExist() and does not implement it: " << this->getName() << "\n";
353
 
  assert(0);
354
 
  return false;
 
580
      *err= ret;
 
581
 
 
582
    return *err == EEXIST;
 
583
  }
 
584
};
 
585
 
 
586
static int drizzle_read_table_proto(const char* path, message::Table* table)
 
587
{
 
588
  int fd= open(path, O_RDONLY);
 
589
 
 
590
  if (fd == -1)
 
591
    return errno;
 
592
 
 
593
  google::protobuf::io::ZeroCopyInputStream* input=
 
594
    new google::protobuf::io::FileInputStream(fd);
 
595
 
 
596
  if (table->ParseFromZeroCopyStream(input) == false)
 
597
  {
 
598
    delete input;
 
599
    close(fd);
 
600
    return -1;
 
601
  }
 
602
 
 
603
  delete input;
 
604
  close(fd);
 
605
  return 0;
355
606
}
356
607
 
357
608
/**
359
610
  to ask engine if there are any new tables that should be written to disk
360
611
  or any dropped tables that need to be removed from disk
361
612
*/
362
 
int StorageEngine::getTableDefinition(Session& session,
363
 
                                      TableIdentifier &identifier,
364
 
                                      message::Table &table_message,
365
 
                                      bool include_temporary_tables)
 
613
int plugin::StorageEngine::getTableDefinition(Session& session,
 
614
                                              TableIdentifier &identifier,
 
615
                                              message::Table *table_proto)
 
616
{
 
617
  return getTableDefinition(session,
 
618
                            identifier.getPath(), identifier.getDBName(), identifier.getTableName(), identifier.isTmp(),
 
619
                            table_proto);
 
620
}
 
621
 
 
622
int plugin::StorageEngine::getTableDefinition(Session& session,
 
623
                                              const char* path,
 
624
                                              const char *,
 
625
                                              const char *,
 
626
                                              const bool,
 
627
                                              message::Table *table_proto)
366
628
{
367
629
  int err= ENOENT;
368
630
 
369
 
  if (include_temporary_tables)
370
 
  {
371
 
    if (session.doGetTableDefinition(identifier, table_message) == EEXIST)
372
 
      return EEXIST;
373
 
  }
374
 
 
375
 
  EngineVector::iterator iter=
 
631
  vector<plugin::StorageEngine *>::iterator iter=
376
632
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
377
 
            StorageEngineGetTableDefinition(session, identifier, table_message, err));
 
633
            StorageEngineGetTableDefinition(session, path, NULL, NULL, true, table_proto, &err));
378
634
 
379
635
  if (iter == vector_of_engines.end())
380
636
  {
381
 
    return ENOENT;
 
637
    string proto_path(path);
 
638
    string file_ext(".dfe");
 
639
    proto_path.append(file_ext);
 
640
 
 
641
    int error= access(proto_path.c_str(), F_OK);
 
642
 
 
643
    if (error == 0)
 
644
      err= EEXIST;
 
645
    else
 
646
      err= errno;
 
647
 
 
648
    if (table_proto)
 
649
    {
 
650
      int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
 
651
                                                   table_proto);
 
652
 
 
653
      if (read_proto_err)
 
654
        err= read_proto_err;
 
655
    }
382
656
  }
383
657
 
384
658
  return err;
414
688
  return true;
415
689
}
416
690
 
 
691
 
417
692
/**
418
 
   returns ENOENT if the file doesn't exists.
 
693
  This should return ENOENT if the file doesn't exists.
 
694
  The .frm file will be deleted only if we return 0 or ENOENT
419
695
*/
420
 
int StorageEngine::dropTable(Session& session,
421
 
                             TableIdentifier &identifier)
 
696
int plugin::StorageEngine::dropTable(Session& session,
 
697
                                     TableIdentifier &identifier,
 
698
                                     bool generate_warning)
422
699
{
423
700
  int error= 0;
424
701
  int error_proto;
425
702
  message::Table src_proto;
426
 
  StorageEngine *engine;
427
 
 
428
 
  error_proto= StorageEngine::getTableDefinition(session, identifier, src_proto);
429
 
 
430
 
  if (error_proto == ER_CORRUPT_TABLE_DEFINITION)
431
 
  {
432
 
    string error_message;
433
 
 
434
 
    error_message.append(identifier.getSQLPath());
435
 
    error_message.append(" : ");
436
 
    error_message.append(src_proto.InitializationErrorString());
437
 
 
438
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), error_message.c_str());
439
 
 
440
 
    return ER_CORRUPT_TABLE_DEFINITION;
441
 
  }
442
 
 
443
 
  engine= StorageEngine::findByName(session, src_proto.engine().name());
444
 
 
445
 
  if (not engine)
446
 
  {
447
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), identifier.getSQLPath().c_str());
448
 
 
449
 
    return ER_CORRUPT_TABLE_DEFINITION;
450
 
  }
451
 
 
452
 
  error= StorageEngine::dropTable(session, *engine, identifier);
 
703
  plugin::StorageEngine* engine;
 
704
 
 
705
  error_proto= plugin::StorageEngine::getTableDefinition(session,
 
706
                                                         identifier,
 
707
                                                         &src_proto);
 
708
 
 
709
  engine= plugin::StorageEngine::findByName(session,
 
710
                                            src_proto.engine().name());
 
711
 
 
712
  if (engine)
 
713
  {
 
714
    engine->setTransactionReadWrite(session);
 
715
    error= engine->doDropTable(session, identifier.getPath());
 
716
  }
 
717
 
 
718
  if (error != ENOENT)
 
719
  {
 
720
    if (error == 0)
 
721
    {
 
722
      if (engine && engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
 
723
      {
 
724
        deleteDefinitionFromPath(identifier);
 
725
      }
 
726
      else
 
727
      {
 
728
        error= deleteDefinitionFromPath(identifier);
 
729
      }
 
730
    }
 
731
  }
453
732
 
454
733
  if (error_proto && error == 0)
455
734
    return 0;
456
735
 
457
 
  return error;
458
 
}
459
 
 
460
 
int StorageEngine::dropTable(Session& session,
461
 
                             StorageEngine &engine,
462
 
                             TableIdentifier &identifier)
463
 
{
464
 
  int error;
465
 
 
466
 
  engine.setTransactionReadWrite(session);
467
 
  error= engine.doDropTable(session, identifier);
468
 
 
469
 
  return error;
470
 
}
471
 
 
 
736
  if (error && generate_warning)
 
737
  {
 
738
    /*
 
739
      Because engine->print_error() use my_error() to generate the error message
 
740
      we use an internal error Cursor to intercept it and store the text
 
741
      in a temporary buffer. Later the message will be presented to user
 
742
      as a warning.
 
743
    */
 
744
    Ha_delete_table_error_handler ha_delete_table_error_handler;
 
745
 
 
746
    session.push_internal_handler(&ha_delete_table_error_handler);
 
747
    engine->print_error(error, 0);
 
748
 
 
749
    session.pop_internal_handler();
 
750
 
 
751
    /*
 
752
      XXX: should we convert *all* errors to warnings here?
 
753
      What if the error is fatal?
 
754
    */
 
755
    push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
 
756
                 ha_delete_table_error_handler.buff);
 
757
  }
 
758
 
 
759
  return error;
 
760
}
472
761
 
473
762
/**
474
763
  Initiates table-file and calls appropriate database-creator.
477
766
   0  ok
478
767
  @retval
479
768
   1  error
 
769
 
 
770
   @todo refactor to remove goto
480
771
*/
481
 
int StorageEngine::createTable(Session &session,
482
 
                               TableIdentifier &identifier,
483
 
                               bool update_create_info,
484
 
                               message::Table& table_message)
 
772
int plugin::StorageEngine::createTable(Session& session,
 
773
                                       TableIdentifier &identifier,
 
774
                                       bool update_create_info,
 
775
                                       drizzled::message::Table& table_proto, bool proto_used)
485
776
{
486
777
  int error= 1;
487
778
  Table table;
488
 
  TableShare share(identifier.getSchemaName().c_str(), 0, identifier.getTableName().c_str(), identifier.getPath().c_str());
 
779
  TableShare share(identifier.getDBName(), 0, identifier.getTableName(), identifier.getPath());
489
780
  message::Table tmp_proto;
490
781
 
491
 
  if (parse_table_proto(session, table_message, &share) || open_table_from_share(&session, &share, "", 0, 0, &table))
492
 
  { 
493
 
    // @note Error occured, we should probably do a little more here.
 
782
  if (proto_used)
 
783
  {
 
784
    if (parse_table_proto(session, table_proto, &share))
 
785
      goto err;
494
786
  }
495
787
  else
496
788
  {
497
 
    if (update_create_info)
498
 
      table.updateCreateInfo(&table_message);
499
 
 
500
 
    /* Check for legal operations against the Engine using the proto (if used) */
501
 
    if (table_message.type() == message::Table::TEMPORARY &&
 
789
    if (open_table_def(session, &share))
 
790
      goto err;
 
791
  }
 
792
 
 
793
  if (open_table_from_share(&session, &share, "", 0, (uint32_t) READ_ALL, 0,
 
794
                            &table))
 
795
    goto err;
 
796
 
 
797
  if (update_create_info)
 
798
    table.updateCreateInfo(&table_proto);
 
799
 
 
800
  /* Check for legal operations against the Engine using the proto (if used) */
 
801
  if (proto_used)
 
802
  {
 
803
    if (table_proto.type() == message::Table::TEMPORARY &&
502
804
        share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
503
805
    {
504
806
      error= HA_ERR_UNSUPPORTED;
 
807
      goto err2;
505
808
    }
506
 
    else if (table_message.type() != message::Table::TEMPORARY &&
 
809
    else if (table_proto.type() != message::Table::TEMPORARY &&
507
810
             share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
508
811
    {
509
812
      error= HA_ERR_UNSUPPORTED;
510
 
    }
511
 
    else
512
 
    {
513
 
      share.storage_engine->setTransactionReadWrite(session);
514
 
 
515
 
      error= share.storage_engine->doCreateTable(session,
516
 
                                                 table,
517
 
                                                 identifier,
518
 
                                                 table_message);
519
 
    }
520
 
 
521
 
    if (error)
522
 
    {
523
 
      my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), identifier.getSQLPath().c_str(), error);
524
 
    }
525
 
 
526
 
    table.closefrm(false);
527
 
  }
528
 
 
 
813
      goto err2;
 
814
    }
 
815
  }
 
816
 
 
817
  if (! share.storage_engine->is_enabled())
 
818
  {
 
819
    error= HA_ERR_UNSUPPORTED;
 
820
    goto err2;
 
821
  }
 
822
 
 
823
 
 
824
  {
 
825
    char name_buff[FN_REFLEN];
 
826
    const char *table_name_arg;
 
827
 
 
828
    table_name_arg= share.storage_engine->checkLowercaseNames(identifier.getPath(), name_buff);
 
829
 
 
830
    share.storage_engine->setTransactionReadWrite(session);
 
831
 
 
832
    error= share.storage_engine->doCreateTable(&session,
 
833
                                               table_name_arg,
 
834
                                               table,
 
835
                                               table_proto);
 
836
  }
 
837
 
 
838
err2:
 
839
  table.closefrm(false);
 
840
 
 
841
  if (error)
 
842
  {
 
843
    char name_buff[FN_REFLEN];
 
844
    sprintf(name_buff,"%s.%s", identifier.getDBName(), identifier.getTableName());
 
845
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
 
846
  }
 
847
err:
529
848
  share.free_table_share();
530
849
  return(error != 0);
531
850
}
532
851
 
533
 
Cursor *StorageEngine::getCursor(TableShare &share, memory::Root *alloc)
 
852
Cursor *plugin::StorageEngine::getCursor(TableShare &share, MEM_ROOT *alloc)
534
853
{
 
854
  assert(enabled);
535
855
  return create(share, alloc);
536
856
}
537
857
 
 
858
/**
 
859
  TODO -> Remove this to force all engines to implement their own file. Solves the "we only looked at dfe" problem.
 
860
*/
 
861
void plugin::StorageEngine::doGetTableNames(CachedDirectory &directory, string&, set<string>& set_of_names)
 
862
{
 
863
  CachedDirectory::Entries entries= directory.getEntries();
 
864
 
 
865
  for (CachedDirectory::Entries::iterator entry_iter= entries.begin(); 
 
866
       entry_iter != entries.end(); ++entry_iter)
 
867
  {
 
868
    CachedDirectory::Entry *entry= *entry_iter;
 
869
    string *filename= &entry->filename;
 
870
 
 
871
    assert(filename->size());
 
872
 
 
873
    const char *ext= strchr(filename->c_str(), '.');
 
874
 
 
875
    if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_DEFINITION_FILE_EXT.c_str()) ||
 
876
        is_prefix(filename->c_str(), TMP_FILE_PREFIX))
 
877
    { }
 
878
    else
 
879
    {
 
880
      char uname[NAME_LEN + 1];
 
881
      uint32_t file_name_len;
 
882
 
 
883
      file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
 
884
      // TODO: Remove need for memory copy here
 
885
      uname[file_name_len - sizeof(".dfe") + 1]= '\0'; // Subtract ending, place NULL 
 
886
      set_of_names.insert(uname);
 
887
    }
 
888
  }
 
889
}
 
890
 
538
891
class AddTableName : 
539
 
  public unary_function<StorageEngine *, void>
 
892
  public unary_function<plugin::StorageEngine *, void>
540
893
{
541
 
  CachedDirectory &directory;
542
 
  SchemaIdentifier &identifier;
543
 
  TableNameList &set_of_names;
 
894
  string db;
 
895
  CachedDirectory& directory;
 
896
  set<string>& set_of_names;
544
897
 
545
898
public:
546
899
 
547
 
  AddTableName(CachedDirectory &directory_arg, SchemaIdentifier &identifier_arg, set<string>& of_names) :
 
900
  AddTableName(CachedDirectory& directory_arg, string& database_name, set<string>& of_names) :
548
901
    directory(directory_arg),
549
 
    identifier(identifier_arg),
550
902
    set_of_names(of_names)
551
903
  {
552
 
  }
553
 
 
554
 
  result_type operator() (argument_type engine)
555
 
  {
556
 
    engine->doGetTableNames(directory, identifier, set_of_names);
557
 
  }
558
 
};
559
 
 
560
 
class AddTableIdentifier : 
561
 
  public unary_function<StorageEngine *, void>
562
 
{
563
 
  CachedDirectory &directory;
564
 
  SchemaIdentifier &identifier;
565
 
  TableIdentifiers &set_of_identifiers;
566
 
 
567
 
public:
568
 
 
569
 
  AddTableIdentifier(CachedDirectory &directory_arg, SchemaIdentifier &identifier_arg, TableIdentifiers &of_names) :
570
 
    directory(directory_arg),
571
 
    identifier(identifier_arg),
572
 
    set_of_identifiers(of_names)
573
 
  {
574
 
  }
575
 
 
576
 
  result_type operator() (argument_type engine)
577
 
  {
578
 
    engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
579
 
  }
580
 
};
581
 
 
582
 
 
583
 
static SchemaIdentifier INFORMATION_SCHEMA_IDENTIFIER("information_schema");
584
 
static SchemaIdentifier DATA_DICTIONARY_IDENTIFIER("data_dictionary");
585
 
 
586
 
void StorageEngine::getTableNames(Session &session, SchemaIdentifier &schema_identifier, TableNameList &set_of_names)
587
 
{
588
 
  CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
589
 
 
590
 
  if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
591
 
  { }
592
 
  else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
593
 
  { }
594
 
  else
595
 
  {
596
 
    if (directory.fail())
597
 
    {
598
 
      errno= directory.getError();
599
 
      if (errno == ENOENT)
600
 
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
601
 
      else
602
 
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
603
 
      return;
604
 
    }
605
 
  }
606
 
 
607
 
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
608
 
           AddTableName(directory, schema_identifier, set_of_names));
609
 
 
610
 
  session.doGetTableNames(directory, schema_identifier, set_of_names);
611
 
}
612
 
 
613
 
void StorageEngine::getTableIdentifiers(Session &session, SchemaIdentifier &schema_identifier, TableIdentifiers &set_of_identifiers)
614
 
{
615
 
  CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
616
 
 
617
 
  if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
618
 
  { }
619
 
  else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
620
 
  { }
621
 
  else
622
 
  {
623
 
    if (directory.fail())
624
 
    {
625
 
      errno= directory.getError();
626
 
      if (errno == ENOENT)
627
 
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
628
 
      else
629
 
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
630
 
      return;
631
 
    }
632
 
  }
633
 
 
634
 
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
635
 
           AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
636
 
 
637
 
  session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
 
904
    db= database_name;
 
905
  }
 
906
 
 
907
  result_type operator() (argument_type engine)
 
908
  {
 
909
    engine->doGetTableNames(directory, db, set_of_names);
 
910
  }
 
911
};
 
912
 
 
913
void plugin::StorageEngine::getTableNames(string& db, set<string>& set_of_names)
 
914
{
 
915
  char tmp_path[FN_REFLEN];
 
916
 
 
917
  build_table_filename(tmp_path, sizeof(tmp_path), db.c_str(), "", false);
 
918
 
 
919
  CachedDirectory directory(tmp_path, set_of_table_definition_ext);
 
920
 
 
921
  if (db.compare("information_schema"))
 
922
  {
 
923
    if (directory.fail())
 
924
    {
 
925
      my_errno= directory.getError();
 
926
      if (my_errno == ENOENT)
 
927
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
 
928
      else
 
929
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), my_errno);
 
930
      return;
 
931
    }
 
932
  }
 
933
 
 
934
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
 
935
           AddTableName(directory, db, set_of_names));
638
936
}
639
937
 
640
938
/* This will later be converted to TableIdentifiers */
641
 
class DropTables: public unary_function<StorageEngine *, void>
 
939
class DropTables: public unary_function<plugin::StorageEngine *, void>
642
940
{
643
941
  Session &session;
644
 
  TableIdentifierList &table_identifiers;
 
942
  set<string>& set_of_names;
645
943
 
646
944
public:
647
945
 
648
 
  DropTables(Session &session_arg, TableIdentifierList &table_identifiers_arg) :
 
946
  DropTables(Session &session_arg, set<string>& of_names) :
649
947
    session(session_arg),
650
 
    table_identifiers(table_identifiers_arg)
 
948
    set_of_names(of_names)
651
949
  { }
652
950
 
653
951
  result_type operator() (argument_type engine)
654
952
  {
655
 
    for (TableIdentifierList::iterator iter= table_identifiers.begin();
656
 
         iter != table_identifiers.end();
 
953
 
 
954
    for (set<string>::iterator iter= set_of_names.begin();
 
955
         iter != set_of_names.end();
657
956
         iter++)
658
957
    {
659
 
      int error= engine->doDropTable(session, const_cast<TableIdentifier&>(*iter));
 
958
      int error= engine->doDropTable(session, *iter);
660
959
 
661
960
      // On a return of zero we know we found and deleted the table. So we
662
961
      // remove it from our search.
663
 
      if (not error)
664
 
        table_identifiers.erase(iter);
 
962
      if (! error)
 
963
        set_of_names.erase(iter);
665
964
    }
666
965
  }
667
966
};
671
970
 
672
971
  Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
673
972
*/
674
 
void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
 
973
void plugin::StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
675
974
{
676
975
  CachedDirectory dir(directory, set_of_table_definition_ext);
677
 
  TableIdentifierList table_identifiers;
 
976
  set<string> set_of_table_names;
678
977
 
679
978
  if (dir.fail())
680
979
  {
681
 
    errno= dir.getError();
682
 
    my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
 
980
    my_errno= dir.getError();
 
981
    my_error(ER_CANT_READ_DIR, MYF(0), directory, my_errno);
683
982
 
684
983
    return;
685
984
  }
700
999
    path+= directory;
701
1000
    path+= FN_LIBCHAR;
702
1001
    path+= entry->filename;
703
 
    message::Table definition;
704
 
    if (StorageEngine::readTableFile(path, definition))
705
 
    {
706
 
      TableIdentifier identifier(definition.schema(), definition.name(), path);
707
 
      table_identifiers.push_back(identifier);
708
 
    }
 
1002
    set_of_table_names.insert(path);
709
1003
  }
710
1004
 
711
1005
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
712
 
           DropTables(session, table_identifiers));
 
1006
           DropTables(session, set_of_table_names));
713
1007
  
714
1008
  /*
715
1009
    Now we just clean up anything that might left over.
719
1013
  */
720
1014
  set<string> all_exts= set_of_table_definition_ext;
721
1015
 
722
 
  for (EngineVector::iterator iter= vector_of_engines.begin();
 
1016
  for (vector<plugin::StorageEngine *>::iterator iter= vector_of_engines.begin();
723
1017
       iter != vector_of_engines.end() ; iter++)
724
1018
  {
725
1019
    for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
753
1047
    - table->s->path
754
1048
    - table->alias
755
1049
*/
756
 
void StorageEngine::print_error(int error, myf errflag, Table &table)
 
1050
void plugin::StorageEngine::print_error(int error, myf errflag, Table &table)
757
1051
{
758
1052
  print_error(error, errflag, &table);
759
1053
}
760
1054
 
761
 
void StorageEngine::print_error(int error, myf errflag, Table *table)
 
1055
void plugin::StorageEngine::print_error(int error, myf errflag, Table *table)
762
1056
{
763
1057
  int textno= ER_GET_ERRNO;
764
1058
  switch (error) {
900
1194
    break;
901
1195
  case HA_ERR_NO_SUCH_TABLE:
902
1196
    assert(table);
903
 
    my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->getSchemaName(),
 
1197
    my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->db.str,
904
1198
             table->s->table_name.str);
905
1199
    return;
906
1200
  case HA_ERR_RBR_LOGGING_FAILED:
970
1264
  @return
971
1265
    Returns true if this is a temporary error
972
1266
*/
973
 
bool StorageEngine::get_error_message(int , String* )
 
1267
bool plugin::StorageEngine::get_error_message(int , String* )
974
1268
{
975
1269
  return false;
976
1270
}
977
1271
 
978
1272
 
979
 
void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
 
1273
void plugin::StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
980
1274
{
981
1275
  /* Write the duplicated key in the error message */
982
1276
  char key[MAX_KEY_LENGTH];
1004
1298
}
1005
1299
 
1006
1300
 
1007
 
int StorageEngine::deleteDefinitionFromPath(TableIdentifier &identifier)
 
1301
int plugin::StorageEngine::deleteDefinitionFromPath(TableIdentifier &identifier)
1008
1302
{
1009
1303
  string path(identifier.getPath());
1010
1304
 
1011
1305
  path.append(DEFAULT_DEFINITION_FILE_EXT);
1012
1306
 
1013
 
  return internal::my_delete(path.c_str(), MYF(0));
 
1307
  return my_delete(path.c_str(), MYF(0));
1014
1308
}
1015
1309
 
1016
 
int StorageEngine::renameDefinitionFromPath(TableIdentifier &dest, TableIdentifier &src)
 
1310
int plugin::StorageEngine::renameDefinitionFromPath(TableIdentifier &dest, TableIdentifier &src)
1017
1311
{
1018
 
  message::Table table_message;
1019
1312
  string src_path(src.getPath());
1020
1313
  string dest_path(dest.getPath());
1021
1314
 
1022
1315
  src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1023
1316
  dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1024
1317
 
1025
 
  bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
1026
 
 
1027
 
  if (not was_read)
1028
 
  {
1029
 
    return ENOENT;
1030
 
  }
1031
 
 
1032
 
  dest.copyToTableMessage(table_message);
1033
 
 
1034
 
  int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
1035
 
 
1036
 
  if (not error)
1037
 
  {
1038
 
    if (unlink(src_path.c_str()))
1039
 
      perror(src_path.c_str());
1040
 
  }
1041
 
 
1042
 
  return error;
 
1318
  return my_rename(src_path.c_str(), dest_path.c_str(), MYF(MY_WME));
1043
1319
}
1044
1320
 
1045
 
int StorageEngine::writeDefinitionFromPath(TableIdentifier &identifier, message::Table &table_message)
 
1321
int plugin::StorageEngine::writeDefinitionFromPath(TableIdentifier &identifier, message::Table &table_proto)
1046
1322
{
1047
 
  char definition_file_tmp[FN_REFLEN];
1048
1323
  string file_name(identifier.getPath());
1049
1324
 
1050
1325
  file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1051
1326
 
1052
 
  snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
1053
 
 
1054
 
  int fd= mkstemp(definition_file_tmp);
 
1327
  int fd= open(file_name.c_str(), O_RDWR|O_CREAT|O_TRUNC, my_umask);
1055
1328
 
1056
1329
  if (fd == -1)
1057
 
  {
1058
 
    perror(definition_file_tmp);
1059
1330
    return errno;
1060
 
  }
1061
1331
 
1062
1332
  google::protobuf::io::ZeroCopyOutputStream* output=
1063
1333
    new google::protobuf::io::FileOutputStream(fd);
1064
1334
 
1065
 
  if (not table_message.SerializeToZeroCopyStream(output))
 
1335
  if (table_proto.SerializeToZeroCopyStream(output) == false)
1066
1336
  {
1067
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1068
 
             table_message.InitializationErrorString().c_str());
1069
1337
    delete output;
1070
 
 
1071
 
    if (close(fd) == -1)
1072
 
      perror(definition_file_tmp);
1073
 
 
1074
 
    if (unlink(definition_file_tmp) == -1)
1075
 
      perror(definition_file_tmp);
1076
 
 
1077
 
    return ER_CORRUPT_TABLE_DEFINITION;
 
1338
    close(fd);
 
1339
    return errno;
1078
1340
  }
1079
1341
 
1080
1342
  delete output;
1081
 
 
1082
 
  if (close(fd) == -1)
1083
 
  {
1084
 
    int error= errno;
1085
 
    perror(definition_file_tmp);
1086
 
 
1087
 
    if (unlink(definition_file_tmp))
1088
 
      perror(definition_file_tmp);
1089
 
 
1090
 
    return error;
1091
 
  }
1092
 
 
1093
 
  if (rename(definition_file_tmp, file_name.c_str()) == -1)
1094
 
  {
1095
 
    int error= errno;
1096
 
    perror(definition_file_tmp);
1097
 
 
1098
 
    if (unlink(definition_file_tmp))
1099
 
      perror(definition_file_tmp);
1100
 
 
1101
 
    return error;
1102
 
  }
1103
 
 
 
1343
  close(fd);
1104
1344
  return 0;
1105
1345
}
1106
1346
 
1107
 
class CanCreateTable: public unary_function<StorageEngine *, bool>
1108
 
{
1109
 
  TableIdentifier &identifier;
1110
 
 
1111
 
public:
1112
 
  CanCreateTable(TableIdentifier &identifier_arg) :
1113
 
    identifier(identifier_arg)
1114
 
  { }
1115
 
 
1116
 
  result_type operator() (argument_type engine)
1117
 
  {
1118
 
    return not engine->doCanCreateTable(identifier);
1119
 
  }
1120
 
};
1121
 
 
1122
 
 
1123
 
/**
1124
 
  @note on success table can be created.
1125
 
*/
1126
 
bool StorageEngine::canCreateTable(drizzled::TableIdentifier &identifier)
1127
 
{
1128
 
  EngineVector::iterator iter=
1129
 
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
1130
 
            CanCreateTable(identifier));
1131
 
 
1132
 
  if (iter == vector_of_engines.end())
1133
 
  {
1134
 
    return true;
1135
 
  }
1136
 
 
1137
 
  return false;
1138
 
}
1139
 
 
1140
 
bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
1141
 
{
1142
 
  fstream input(path.c_str(), ios::in | ios::binary);
1143
 
 
1144
 
  if (input.good())
1145
 
  {
1146
 
    if (table_message.ParseFromIstream(&input))
1147
 
    {
1148
 
      return true;
1149
 
    }
1150
 
 
1151
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1152
 
             table_message.InitializationErrorString().c_str());
1153
 
  }
1154
 
  else
1155
 
  {
1156
 
    perror(path.c_str());
1157
 
  }
1158
 
 
1159
 
  return false;
1160
 
}
1161
 
 
1162
 
 
1163
 
 
1164
 
} /* namespace plugin */
 
1347
 
1165
1348
} /* namespace drizzled */