~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

  • Committer: Padraig O'Sullivan
  • Date: 2010-02-10 16:26:01 UTC
  • mto: This revision was merged to the branch mainline in revision 1294.
  • Revision ID: osullivan.padraig@gmail.com-20100210162601-itx2ndl397pc1wr6
Corrected an order of initialization in a few optimizer classes

Show diffs side-by-side

added added

removed removed

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