~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

  • Committer: lbieber
  • Date: 2010-01-21 18:21:39 UTC
  • mto: This revision was merged to the branch mainline in revision 1277.
  • Revision ID: lbieber@orisndriz08-20100121182139-h549us3gsysyyl0e
clean up japanese tests, remove tests that no longer apply.  In test-run.pl change mysql_version_id to drizzle_version_id

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