~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

  • Committer: Brian Aker
  • Date: 2009-10-07 16:55:53 UTC
  • mfrom: (1161.2.1 bug444827)
  • Revision ID: brian@gaz-20091007165553-9tnp7liw1k9g6gvc
Merge Padraig

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
17
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
18
 */
19
19
 
20
 
#include "config.h"
21
 
 
22
 
#include <fcntl.h>
23
 
#include <unistd.h>
24
 
 
 
20
#include <drizzled/server_includes.h>
 
21
 
 
22
#include CSTDINT_H
25
23
#include <string>
26
24
#include <vector>
27
 
#include <set>
28
 
#include <fstream>
29
25
#include <algorithm>
30
26
#include <functional>
31
27
 
32
28
#include <google/protobuf/io/zero_copy_stream.h>
33
29
#include <google/protobuf/io/zero_copy_stream_impl.h>
34
30
 
35
 
#include "drizzled/cached_directory.h"
 
31
#include "mysys/my_dir.h"
 
32
#include "mysys/hash.h"
36
33
 
37
34
#include <drizzled/definitions.h>
38
35
#include <drizzled/base.h>
39
 
#include <drizzled/cursor.h>
 
36
#include <drizzled/handler.h>
40
37
#include <drizzled/plugin/storage_engine.h>
41
38
#include <drizzled/session.h>
42
39
#include <drizzled/error.h>
43
40
#include <drizzled/gettext.h>
 
41
#include <drizzled/registry.h>
44
42
#include <drizzled/unireg.h>
45
43
#include <drizzled/data_home.h>
46
44
#include "drizzled/errmsg_print.h"
 
45
#include <drizzled/plugin/registry.h>
47
46
#include "drizzled/xid.h"
48
 
#include "drizzled/sql_table.h"
49
 
#include "drizzled/global_charset_info.h"
50
 
#include "drizzled/charset.h"
51
 
#include "drizzled/internal/my_sys.h"
52
 
#include "drizzled/db.h"
53
47
 
54
48
#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>
62
 
 
63
 
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
 
49
 
 
50
using namespace std;
 
51
 
64
52
 
65
53
namespace drizzled
66
54
{
67
55
 
68
 
namespace plugin
69
 
{
70
 
 
71
 
static EngineVector vector_of_engines;
72
 
static EngineVector vector_of_schema_engines;
73
 
 
74
 
const std::string DEFAULT_STRING("default");
75
 
const std::string UNKNOWN_STRING("UNKNOWN");
76
 
const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
77
 
 
78
 
static std::set<std::string> set_of_table_definition_ext;
79
 
 
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 identifier::Table &from, const identifier::Table &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)))
 
56
Registry<plugin::StorageEngine *> all_engines;
 
57
 
 
58
plugin::StorageEngine::StorageEngine(const string name_arg,
 
59
                                     const bitset<HTON_BIT_SIZE> &flags_arg,
 
60
                                     size_t savepoint_offset_arg,
 
61
                                     bool support_2pc)
 
62
    : name(name_arg), two_phase_commit(support_2pc), enabled(true),
 
63
      flags(flags_arg),
 
64
      savepoint_offset(savepoint_alloc_size),
 
65
      orig_savepoint_offset(savepoint_offset_arg),
 
66
      slot(0)
 
67
{
 
68
  if (enabled)
 
69
  {
 
70
    savepoint_alloc_size+= orig_savepoint_offset;
 
71
    slot= total_ha++;
 
72
    if (two_phase_commit)
 
73
        total_ha_2pc++;
 
74
  }
 
75
}
 
76
 
 
77
 
 
78
plugin::StorageEngine::~StorageEngine()
 
79
{
 
80
  savepoint_alloc_size-= orig_savepoint_offset;
 
81
}
 
82
 
 
83
void plugin::StorageEngine::setTransactionReadWrite(Session* session)
 
84
{
 
85
  Ha_trx_info *ha_info= &session->ha_data[getSlot()].ha_info[0];
 
86
  /*
 
87
    When a storage engine method is called, the transaction must
 
88
    have been started, unless it's a DDL call, for which the
 
89
    storage engine starts the transaction internally, and commits
 
90
    it internally, without registering in the ha_list.
 
91
    Unfortunately here we can't know know for sure if the engine
 
92
    has registered the transaction or not, so we must check.
 
93
  */
 
94
  if (ha_info->is_started())
 
95
  {
 
96
    /*
 
97
     * table_share can be NULL in plugin::StorageEngine::deleteTable().
 
98
     */
 
99
    ha_info->set_trx_read_write();
 
100
  }
 
101
}
 
102
 
 
103
 
 
104
 
 
105
int plugin::StorageEngine::renameTableImplementation(Session *,
 
106
                                                     const char *from,
 
107
                                                     const char *to)
 
108
{
 
109
  int error= 0;
 
110
  for (const char **ext= bas_ext(); *ext ; ext++)
 
111
  {
 
112
    if (rename_file_ext(from, to, *ext))
117
113
    {
118
 
      error= ER_EVENT_OBSERVER_PLUGIN;
 
114
      if ((error=my_errno) != ENOENT)
 
115
        break;
 
116
      error= 0;
119
117
    }
120
118
  }
121
 
  
122
119
  return error;
123
120
}
124
121
 
 
122
 
125
123
/**
126
124
  Delete all files with extension from bas_ext().
127
125
 
128
126
  @param name           Base name of table
129
127
 
130
128
  @note
131
 
    We assume that the Cursor may return more extensions than
 
129
    We assume that the handler may return more extensions than
132
130
    was actually used for the file.
133
131
 
134
132
  @retval
137
135
  @retval
138
136
    !0  Error
139
137
*/
140
 
int StorageEngine::doDropTable(Session&, const identifier::Table &identifier)
141
 
                               
 
138
int plugin::StorageEngine::deleteTableImplementation(Session *,
 
139
                                                     const string table_path)
142
140
{
143
141
  int error= 0;
144
142
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
145
143
  char buff[FN_REFLEN];
146
144
 
147
 
  for (const char **ext= bas_ext(); *ext ; ext++)
 
145
  for (const char **ext=bas_ext(); *ext ; ext++)
148
146
  {
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)))
 
147
    fn_format(buff, table_path.c_str(), "", *ext,
 
148
              MY_UNPACK_FILENAME|MY_APPEND_EXT);
 
149
    if (my_delete_with_symlink(buff, MYF(0)))
152
150
    {
153
 
      if ((error= errno) != ENOENT)
154
 
        break;
 
151
      if ((error= my_errno) != ENOENT)
 
152
        break;
155
153
    }
156
154
    else
157
 
    {
158
155
      enoent_or_zero= 0;                        // No error for ENOENT
159
 
    }
160
 
 
161
156
    error= enoent_or_zero;
162
157
  }
163
158
  return error;
164
159
}
165
160
 
166
 
bool StorageEngine::addPlugin(StorageEngine *engine)
167
 
{
168
 
 
169
 
  vector_of_engines.push_back(engine);
170
 
 
171
 
  if (engine->getTableDefinitionFileExtension().length())
 
161
const char *plugin::StorageEngine::checkLowercaseNames(const char *path,
 
162
                                                       char *tmp_path)
 
163
{
 
164
  if (flags.test(HTON_BIT_FILE_BASED))
 
165
    return path;
 
166
 
 
167
  /* Ensure that table handler get path in lower case */
 
168
  if (tmp_path != path)
 
169
    strcpy(tmp_path, path);
 
170
 
 
171
  /*
 
172
    we only should turn into lowercase database/table part
 
173
    so start the process after homedirectory
 
174
  */
 
175
  if (strstr(tmp_path, drizzle_tmpdir) == tmp_path)
 
176
    my_casedn_str(files_charset_info, tmp_path + strlen(drizzle_tmpdir));
 
177
  else
 
178
    my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
 
179
 
 
180
  return tmp_path;
 
181
}
 
182
 
 
183
 
 
184
bool plugin::StorageEngine::addPlugin(plugin::StorageEngine *engine)
 
185
{
 
186
  if (all_engines.add(engine))
172
187
  {
173
 
    assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
174
 
    set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
 
188
    errmsg_printf(ERRMSG_LVL_ERROR,
 
189
                  _("Couldn't add StorageEngine"));
 
190
    return true;
175
191
  }
176
 
 
177
 
  if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
178
 
    vector_of_schema_engines.push_back(engine);
179
 
 
180
192
  return false;
181
193
}
182
194
 
183
 
void StorageEngine::removePlugin(StorageEngine *)
184
 
{
185
 
  if (shutdown_has_begun == false)
186
 
  {
187
 
    vector_of_engines.clear();
188
 
    vector_of_schema_engines.clear();
189
 
 
190
 
    shutdown_has_begun= true;
191
 
  }
192
 
}
193
 
 
194
 
class FindEngineByName
195
 
  : public std::unary_function<StorageEngine *, bool>
196
 
{
197
 
  const std::string &predicate;
198
 
 
199
 
public:
200
 
  explicit FindEngineByName(const std::string &target_arg) :
201
 
    predicate(target_arg)
202
 
  {
203
 
  }
204
 
 
205
 
  result_type operator() (argument_type engine)
206
 
  {
207
 
    return boost::iequals(engine->getName(), predicate);
208
 
  }
209
 
};
210
 
 
211
 
StorageEngine *StorageEngine::findByName(const std::string &predicate)
212
 
{
213
 
  EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
214
 
                                            vector_of_engines.end(),
215
 
                                            FindEngineByName(predicate));
216
 
  if (iter != vector_of_engines.end())
217
 
  {
218
 
    StorageEngine *engine= *iter;
219
 
    if (engine->is_user_selectable())
220
 
      return engine;
221
 
  }
222
 
 
223
 
  return NULL;
224
 
}
225
 
 
226
 
StorageEngine *StorageEngine::findByName(Session& session, const std::string &predicate)
227
 
{
228
 
  if (boost::iequals(predicate, DEFAULT_STRING))
229
 
    return session.getDefaultStorageEngine();
230
 
 
231
 
  EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
232
 
                                            vector_of_engines.end(),
233
 
                                            FindEngineByName(predicate));
234
 
  if (iter != vector_of_engines.end())
235
 
  {
236
 
    StorageEngine *engine= *iter;
237
 
    if (engine->is_user_selectable())
238
 
      return engine;
239
 
  }
240
 
 
241
 
  return NULL;
242
 
}
243
 
 
244
 
class StorageEngineCloseConnection : public std::unary_function<StorageEngine *, void>
 
195
void plugin::StorageEngine::removePlugin(plugin::StorageEngine *engine)
 
196
{
 
197
  all_engines.remove(engine);
 
198
}
 
199
 
 
200
plugin::StorageEngine *plugin::StorageEngine::findByName(Session *session,
 
201
                                                         string find_str)
 
202
{
 
203
  
 
204
  transform(find_str.begin(), find_str.end(),
 
205
            find_str.begin(), ::tolower);
 
206
  string default_str("default");
 
207
  if (find_str == default_str)
 
208
    return ha_default_storage_engine(session);
 
209
 
 
210
  plugin::StorageEngine *engine= all_engines.find(find_str);
 
211
 
 
212
  if (engine && engine->is_user_selectable())
 
213
    return engine;
 
214
 
 
215
  return NULL;
 
216
}
 
217
 
 
218
class StorageEngineCloseConnection
 
219
  : public unary_function<plugin::StorageEngine *, void>
245
220
{
246
221
  Session *session;
247
222
public:
252
227
  */
253
228
  inline result_type operator() (argument_type engine)
254
229
  {
255
 
    if (*session->getEngineData(engine))
256
 
      engine->close_connection(session);
 
230
    if (engine->is_enabled() && 
 
231
      session_get_ha_data(session, engine))
 
232
    engine->close_connection(session);
257
233
  }
258
234
};
259
235
 
261
237
  @note
262
238
    don't bother to rollback here, it's done already
263
239
*/
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)
 
240
void plugin::StorageEngine::closeConnection(Session* session)
 
241
{
 
242
  for_each(all_engines.begin(), all_engines.end(),
 
243
           StorageEngineCloseConnection(session));
 
244
}
 
245
 
 
246
void plugin::StorageEngine::dropDatabase(char* path)
 
247
{
 
248
  for_each(all_engines.begin(), all_engines.end(),
 
249
           bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
 
250
}
 
251
 
 
252
int plugin::StorageEngine::commitOrRollbackByXID(XID *xid, bool commit)
 
253
{
 
254
  vector<int> results;
 
255
  
 
256
  if (commit)
 
257
    transform(all_engines.begin(), all_engines.end(), results.begin(),
 
258
              bind2nd(mem_fun(&plugin::StorageEngine::commit_by_xid),xid));
 
259
  else
 
260
    transform(all_engines.begin(), all_engines.end(), results.begin(),
 
261
              bind2nd(mem_fun(&plugin::StorageEngine::rollback_by_xid),xid));
 
262
 
 
263
  if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
 
264
         == results.end())
 
265
    return 1;
 
266
  return 0;
 
267
}
 
268
 
 
269
/**
 
270
  @details
 
271
  This function should be called when MySQL sends rows of a SELECT result set
 
272
  or the EOF mark to the client. It releases a possible adaptive hash index
 
273
  S-latch held by session in InnoDB and also releases a possible InnoDB query
 
274
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
 
275
  keep them over several calls of the InnoDB handler interface when a join
 
276
  is executed. But when we let the control to pass to the client they have
 
277
  to be released because if the application program uses mysql_use_result(),
 
278
  it may deadlock on the S-latch if the application on another connection
 
279
  performs another SQL query. In MySQL-4.1 this is even more important because
 
280
  there a connection can have several SELECT queries open at the same time.
 
281
 
 
282
  @param session           the thread handle of the current connection
 
283
 
 
284
  @return
 
285
    always 0
 
286
*/
 
287
int plugin::StorageEngine::releaseTemporaryLatches(Session *session)
 
288
{
 
289
  for_each(all_engines.begin(), all_engines.end(),
 
290
           bind2nd(mem_fun(&plugin::StorageEngine::release_temporary_latches),session));
 
291
  return 0;
 
292
}
 
293
 
 
294
bool plugin::StorageEngine::flushLogs(plugin::StorageEngine *engine)
271
295
{
272
296
  if (engine == NULL)
273
297
  {
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())
 
298
    if (find_if(all_engines.begin(), all_engines.end(),
 
299
            mem_fun(&plugin::StorageEngine::flush_logs))
 
300
          != all_engines.begin())
277
301
      return true;
278
302
  }
279
303
  else
280
304
  {
281
 
    if (engine->flush_logs())
 
305
    if ((!engine->is_enabled()) ||
 
306
        (engine->flush_logs()))
282
307
      return true;
283
308
  }
284
309
  return false;
285
310
}
286
311
 
287
 
class StorageEngineGetTableDefinition: public std::unary_function<StorageEngine *,bool>
288
 
{
289
 
  Session& session;
290
 
  const identifier::Table &identifier;
291
 
  message::Table &table_message;
292
 
  drizzled::error_t &err;
293
 
 
294
 
public:
295
 
  StorageEngineGetTableDefinition(Session& session_arg,
296
 
                                  const identifier::Table &identifier_arg,
297
 
                                  message::Table &table_message_arg,
298
 
                                  drizzled::error_t &err_arg) :
299
 
    session(session_arg), 
300
 
    identifier(identifier_arg),
301
 
    table_message(table_message_arg), 
302
 
    err(err_arg) {}
303
 
 
304
 
  result_type operator() (argument_type engine)
305
 
  {
306
 
    int ret= engine->doGetTableDefinition(session, identifier, table_message);
 
312
/**
 
313
  recover() step of xa.
 
314
 
 
315
  @note
 
316
    there are three modes of operation:
 
317
    - automatic recover after a crash
 
318
    in this case commit_list != 0, tc_heuristic_recover==0
 
319
    all xids from commit_list are committed, others are rolled back
 
320
    - manual (heuristic) recover
 
321
    in this case commit_list==0, tc_heuristic_recover != 0
 
322
    DBA has explicitly specified that all prepared transactions should
 
323
    be committed (or rolled back).
 
324
    - no recovery (MySQL did not detect a crash)
 
325
    in this case commit_list==0, tc_heuristic_recover == 0
 
326
    there should be no prepared transactions in this case.
 
327
*/
 
328
class XARecover : unary_function<plugin::StorageEngine *, void>
 
329
{
 
330
  int trans_len, found_foreign_xids, found_my_xids;
 
331
  bool result;
 
332
  XID *trans_list;
 
333
  HASH *commit_list;
 
334
  bool dry_run;
 
335
public:
 
336
  XARecover(XID *trans_list_arg, int trans_len_arg,
 
337
            HASH *commit_list_arg, bool dry_run_arg) 
 
338
    : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
 
339
      result(false),
 
340
      trans_list(trans_list_arg), commit_list(commit_list_arg),
 
341
      dry_run(dry_run_arg)
 
342
  {}
 
343
  
 
344
  int getForeignXIDs()
 
345
  {
 
346
    return found_foreign_xids; 
 
347
  }
 
348
 
 
349
  int getMyXIDs()
 
350
  {
 
351
    return found_my_xids; 
 
352
  }
 
353
 
 
354
  result_type operator() (argument_type engine)
 
355
  {
 
356
  
 
357
    int got;
 
358
  
 
359
    if (engine->is_enabled())
 
360
    {
 
361
      while ((got= engine->recover(trans_list, trans_len)) > 0 )
 
362
      {
 
363
        errmsg_printf(ERRMSG_LVL_INFO,
 
364
                      _("Found %d prepared transaction(s) in %s"),
 
365
                      got, engine->getName().c_str());
 
366
        for (int i=0; i < got; i ++)
 
367
        {
 
368
          my_xid x=trans_list[i].get_my_xid();
 
369
          if (!x) // not "mine" - that is generated by external TM
 
370
          {
 
371
            xid_cache_insert(trans_list+i, XA_PREPARED);
 
372
            found_foreign_xids++;
 
373
            continue;
 
374
          }
 
375
          if (dry_run)
 
376
          {
 
377
            found_my_xids++;
 
378
            continue;
 
379
          }
 
380
          // recovery mode
 
381
          if (commit_list ?
 
382
              hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
 
383
              tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
 
384
          {
 
385
            engine->commit_by_xid(trans_list+i);
 
386
          }
 
387
          else
 
388
          {
 
389
            engine->rollback_by_xid(trans_list+i);
 
390
          }
 
391
        }
 
392
        if (got < trans_len)
 
393
          break;
 
394
      }
 
395
    }
 
396
  }
 
397
};
 
398
 
 
399
int plugin::StorageEngine::recover(HASH *commit_list)
 
400
{
 
401
  XID *trans_list= NULL;
 
402
  int trans_len= 0;
 
403
 
 
404
  bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
 
405
 
 
406
  /* commit_list and tc_heuristic_recover cannot be set both */
 
407
  assert(commit_list==0 || tc_heuristic_recover==0);
 
408
 
 
409
  /* if either is set, total_ha_2pc must be set too */
 
410
  if (total_ha_2pc <= 1)
 
411
    return 0;
 
412
 
 
413
 
 
414
#ifndef WILL_BE_DELETED_LATER
 
415
 
 
416
  /*
 
417
    for now, only InnoDB supports 2pc. It means we can always safely
 
418
    rollback all pending transactions, without risking inconsistent data
 
419
  */
 
420
 
 
421
  assert(total_ha_2pc == 2); // only InnoDB and binlog
 
422
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
 
423
  dry_run=false;
 
424
#endif
 
425
  for (trans_len= MAX_XID_LIST_SIZE ;
 
426
       trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
 
427
  {
 
428
    trans_list=(XID *)malloc(trans_len*sizeof(XID));
 
429
  }
 
430
  if (!trans_list)
 
431
  {
 
432
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
 
433
    return(1);
 
434
  }
 
435
 
 
436
  if (commit_list)
 
437
    errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
 
438
 
 
439
 
 
440
  XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
 
441
  for_each(all_engines.begin(), all_engines.end(), recover_func);
 
442
  free(trans_list);
 
443
 
 
444
  if (recover_func.getForeignXIDs())
 
445
    errmsg_printf(ERRMSG_LVL_WARN,
 
446
                  _("Found %d prepared XA transactions"),
 
447
                  recover_func.getForeignXIDs());
 
448
  if (dry_run && recover_func.getMyXIDs())
 
449
  {
 
450
    errmsg_printf(ERRMSG_LVL_ERROR,
 
451
                  _("Found %d prepared transactions! It means that drizzled "
 
452
                    "was not shut down properly last time and critical "
 
453
                    "recovery information (last binlog or %s file) was "
 
454
                    "manually deleted after a crash. You have to start "
 
455
                    "drizzled with the --tc-heuristic-recover switch to "
 
456
                    "commit or rollback pending transactions."),
 
457
                    recover_func.getMyXIDs(), opt_tc_log_file);
 
458
    return(1);
 
459
  }
 
460
  if (commit_list)
 
461
    errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
 
462
  return(0);
 
463
}
 
464
 
 
465
int plugin::StorageEngine::startConsistentSnapshot(Session *session)
 
466
{
 
467
  for_each(all_engines.begin(), all_engines.end(),
 
468
           bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
 
469
                   session));
 
470
  return 0;
 
471
}
 
472
 
 
473
class StorageEngineGetTableProto: public unary_function<plugin::StorageEngine *,bool>
 
474
{
 
475
  const char* path;
 
476
  message::Table *table_proto;
 
477
  int *err;
 
478
public:
 
479
  StorageEngineGetTableProto(const char* path_arg,
 
480
                             message::Table *table_proto_arg,
 
481
                             int *err_arg)
 
482
  :path(path_arg), table_proto(table_proto_arg), err(err_arg) {}
 
483
 
 
484
  result_type operator() (argument_type engine)
 
485
  {
 
486
    int ret= engine->getTableProtoImplementation(path, table_proto);
307
487
 
308
488
    if (ret != ENOENT)
309
 
      err= static_cast<drizzled::error_t>(ret);
310
 
 
311
 
    return err == static_cast<drizzled::error_t>(EEXIST) or err != static_cast<drizzled::error_t>(ENOENT);
312
 
  }
313
 
};
314
 
 
315
 
class StorageEngineDoesTableExist: public std::unary_function<StorageEngine *, bool>
316
 
{
317
 
  Session& session;
318
 
  const identifier::Table &identifier;
319
 
 
320
 
public:
321
 
  StorageEngineDoesTableExist(Session& session_arg, const identifier::Table &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 identifier::Table &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::identifier::Table&)
358
 
{
359
 
  std::cerr << " Engine was called for doDoesTableExist() and does not implement it: " << this->getName() << "\n";
360
 
  assert(0);
361
 
  return false;
362
 
}
363
 
 
364
 
/**
365
 
  Call this function in order to give the Cursor the possiblity
 
489
      *err= ret;
 
490
 
 
491
    return *err == EEXIST;
 
492
  }
 
493
};
 
494
 
 
495
static int drizzle_read_table_proto(const char* path, message::Table* table)
 
496
{
 
497
  int fd= open(path, O_RDONLY);
 
498
 
 
499
  if (fd == -1)
 
500
    return errno;
 
501
 
 
502
  google::protobuf::io::ZeroCopyInputStream* input=
 
503
    new google::protobuf::io::FileInputStream(fd);
 
504
 
 
505
  if (table->ParseFromZeroCopyStream(input) == false)
 
506
  {
 
507
    delete input;
 
508
    close(fd);
 
509
    return -1;
 
510
  }
 
511
 
 
512
  delete input;
 
513
  close(fd);
 
514
  return 0;
 
515
}
 
516
 
 
517
/**
 
518
  Call this function in order to give the handler the possiblity
366
519
  to ask engine if there are any new tables that should be written to disk
367
520
  or any dropped tables that need to be removed from disk
368
521
*/
369
 
int StorageEngine::getTableDefinition(Session& session,
370
 
                                      const identifier::Table &identifier,
371
 
                                      message::table::shared_ptr &table_message,
372
 
                                      bool include_temporary_tables)
 
522
int plugin::StorageEngine::getTableProto(const char* path,
 
523
                                         message::Table *table_proto)
373
524
{
374
 
  drizzled::error_t err= static_cast<drizzled::error_t>(ENOENT);
 
525
  int err= ENOENT;
375
526
 
376
 
  if (include_temporary_tables)
 
527
  ::drizzled::Registry<plugin::StorageEngine *>::iterator iter=
 
528
    find_if(all_engines.begin(), all_engines.end(),
 
529
            StorageEngineGetTableProto(path, table_proto, &err));
 
530
  if (iter == all_engines.end())
377
531
  {
378
 
    Table *table= session.find_temporary_table(identifier);
379
 
    if (table)
 
532
    string proto_path(path);
 
533
    string file_ext(".dfe");
 
534
    proto_path.append(file_ext);
 
535
 
 
536
    int error= access(proto_path.c_str(), F_OK);
 
537
 
 
538
    if (error == 0)
 
539
      err= EEXIST;
 
540
    else
 
541
      err= errno;
 
542
 
 
543
    if (table_proto)
380
544
    {
381
 
      table_message.reset(new message::Table(*table->getShare()->getTableMessage()));
382
 
      return EEXIST;
 
545
      int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
 
546
                                                   table_proto);
 
547
 
 
548
      if (read_proto_err)
 
549
        err= read_proto_err;
383
550
    }
384
551
  }
385
552
 
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
553
  return err;
406
554
}
407
555
 
408
 
message::table::shared_ptr StorageEngine::getTableMessage(Session& session,
409
 
                                                          identifier::Table::const_reference identifier,
410
 
                                                          drizzled::error_t &error,
411
 
                                                          bool include_temporary_tables)
412
 
{
413
 
  error= static_cast<drizzled::error_t>(ENOENT);
414
 
 
415
 
  if (include_temporary_tables)
416
 
  {
417
 
    Table *table= session.find_temporary_table(identifier);
418
 
    if (table)
419
 
    {
420
 
      error= EE_OK;
421
 
      return message::table::shared_ptr(new message::Table(*table->getShare()->getTableMessage()));
422
 
    }
423
 
  }
424
 
 
425
 
  drizzled::message::table::shared_ptr table_ptr;
426
 
  if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
427
 
  {
428
 
    (void)table_ptr;
429
 
  }
430
 
 
431
 
  message::Table message;
432
 
  EngineVector::iterator iter=
433
 
    std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
434
 
                 StorageEngineGetTableDefinition(session, identifier, message, error));
435
 
 
436
 
  if (iter == vector_of_engines.end())
437
 
  {
438
 
    error= static_cast<drizzled::error_t>(ENOENT);
439
 
    return message::table::shared_ptr();
440
 
  }
441
 
  message::table::shared_ptr table_message(new message::Table(message));
442
 
 
443
 
  drizzled::message::Cache::singleton().insert(identifier, table_message);
444
 
 
445
 
  return table_message;
446
 
}
447
 
 
448
556
/**
449
557
  An interceptor to hijack the text of the error message without
450
558
  setting an error in the thread. We need the text to present it
455
563
{
456
564
public:
457
565
  Ha_delete_table_error_handler() : Internal_error_handler() {}
458
 
  virtual bool handle_error(drizzled::error_t sql_errno,
 
566
  virtual bool handle_error(uint32_t sql_errno,
459
567
                            const char *message,
460
568
                            DRIZZLE_ERROR::enum_warning_level level,
461
569
                            Session *session);
465
573
 
466
574
bool
467
575
Ha_delete_table_error_handler::
468
 
handle_error(drizzled::error_t ,
 
576
handle_error(uint32_t ,
469
577
             const char *message,
470
578
             DRIZZLE_ERROR::enum_warning_level ,
471
579
             Session *)
475
583
  return true;
476
584
}
477
585
 
478
 
class DropTableByIdentifier: public std::unary_function<EngineVector::value_type, bool>
 
586
 
 
587
class DeleteTableStorageEngine
 
588
  : public unary_function<plugin::StorageEngine *, void>
479
589
{
480
 
  Session::reference session;
481
 
  identifier::Table::const_reference identifier;
482
 
  drizzled::error_t &error;
483
 
 
 
590
  Session *session;
 
591
  const char *path;
 
592
  handler **file;
 
593
  int *dt_error;
484
594
public:
485
 
 
486
 
  DropTableByIdentifier(Session::reference session_arg,
487
 
                        identifier::Table::const_reference identifier_arg,
488
 
                        drizzled::error_t &error_arg) :
489
 
    session(session_arg),
490
 
    identifier(identifier_arg),
491
 
    error(error_arg)
492
 
  { }
 
595
  DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
 
596
                           handler **file_arg, int *error_arg)
 
597
    : session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
493
598
 
494
599
  result_type operator() (argument_type engine)
495
600
  {
496
 
    if (not engine->doDoesTableExist(session, identifier))
497
 
      return false;
498
 
 
499
 
    int local_error= engine->doDropTable(session, identifier);
500
 
 
501
 
 
502
 
    if (not local_error)
503
 
      return true;
504
 
 
505
 
    switch (local_error)
506
 
    {
507
 
    case HA_ERR_NO_SUCH_TABLE:
508
 
    case ENOENT:
509
 
      error= static_cast<drizzled::error_t>(HA_ERR_NO_SUCH_TABLE);
510
 
      return false;
511
 
 
512
 
    default:
513
 
      error= static_cast<drizzled::error_t>(local_error);
514
 
      return true;
515
 
    }
516
 
  } 
517
 
};
518
 
 
519
 
 
520
 
bool StorageEngine::dropTable(Session::reference session,
521
 
                              identifier::Table::const_reference identifier,
522
 
                              drizzled::error_t &error)
523
 
{
524
 
  error= EE_OK;
525
 
 
526
 
  EngineVector::const_iterator iter= std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
527
 
                                                  DropTableByIdentifier(session, identifier, error));
528
 
 
529
 
  if (error)
530
 
  {
531
 
    return false;
532
 
  }
533
 
  else if (iter == vector_of_engines.end())
534
 
  {
535
 
    error= ER_BAD_TABLE_ERROR;
536
 
    return false;
537
 
  }
538
 
 
539
 
  drizzled::message::Cache::singleton().erase(identifier);
540
 
 
541
 
  return true;
542
 
}
543
 
 
544
 
bool StorageEngine::dropTable(Session& session,
545
 
                              const identifier::Table &identifier)
546
 
{
547
 
  drizzled::error_t error;
548
 
 
549
 
  if (not dropTable(session, identifier, error))
550
 
  {
551
 
    return false;
552
 
  }
553
 
 
554
 
  return true;
555
 
}
556
 
 
557
 
bool StorageEngine::dropTable(Session::reference session,
558
 
                              StorageEngine &engine,
559
 
                              identifier::Table::const_reference identifier,
560
 
                              drizzled::error_t &error)
561
 
{
562
 
  error= EE_OK;
563
 
  engine.setTransactionReadWrite(session);
564
 
 
565
 
  assert(identifier.isTmp());
566
 
  
567
 
  if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
568
 
  {
569
 
    error= ER_EVENT_OBSERVER_PLUGIN;
570
 
  }
571
 
  else
572
 
  {
573
 
    error= static_cast<drizzled::error_t>(engine.doDropTable(session, identifier));
574
 
 
575
 
    if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
576
 
    {
577
 
      error= ER_EVENT_OBSERVER_PLUGIN;
578
 
    }
579
 
  }
580
 
 
581
 
  drizzled::message::Cache::singleton().erase(identifier);
582
 
 
583
 
  if (error)
584
 
  {
585
 
    return false;
586
 
  }
587
 
 
588
 
  return true;
 
601
    char tmp_path[FN_REFLEN];
 
602
    handler *tmp_file;
 
603
 
 
604
    if(*dt_error!=ENOENT) /* already deleted table */
 
605
      return;
 
606
 
 
607
    if (!engine)
 
608
      return;
 
609
 
 
610
    if (!engine->is_enabled())
 
611
      return;
 
612
 
 
613
    if ((tmp_file= engine->create(NULL, session->mem_root)))
 
614
      tmp_file->init();
 
615
    else
 
616
      return;
 
617
 
 
618
    path= engine->checkLowercaseNames(path, tmp_path);
 
619
    const string table_path(path);
 
620
    int tmp_error= engine->deleteTable(session, table_path);
 
621
 
 
622
    if (tmp_error != ENOENT)
 
623
    {
 
624
      if (tmp_error == 0)
 
625
      {
 
626
        if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
 
627
          delete_table_proto_file(path);
 
628
        else
 
629
          tmp_error= delete_table_proto_file(path);
 
630
      }
 
631
 
 
632
      *dt_error= tmp_error;
 
633
      if(*file)
 
634
        delete *file;
 
635
      *file= tmp_file;
 
636
      return;
 
637
    }
 
638
    else
 
639
      delete tmp_file;
 
640
 
 
641
    return;
 
642
  }
 
643
};
 
644
 
 
645
 
 
646
/**
 
647
  This should return ENOENT if the file doesn't exists.
 
648
  The .frm file will be deleted only if we return 0 or ENOENT
 
649
*/
 
650
int plugin::StorageEngine::deleteTable(Session *session, const char *path,
 
651
                                       const char *db, const char *alias,
 
652
                                       bool generate_warning)
 
653
{
 
654
  TableShare dummy_share;
 
655
  Table dummy_table;
 
656
  memset(&dummy_table, 0, sizeof(dummy_table));
 
657
  memset(&dummy_share, 0, sizeof(dummy_share));
 
658
 
 
659
  dummy_table.s= &dummy_share;
 
660
 
 
661
  int error= ENOENT;
 
662
  handler *file= NULL;
 
663
 
 
664
  for_each(all_engines.begin(), all_engines.end(),
 
665
           DeleteTableStorageEngine(session, path, &file, &error));
 
666
 
 
667
  if (error == ENOENT) /* proto may be left behind */
 
668
    error= delete_table_proto_file(path);
 
669
 
 
670
  if (error && generate_warning)
 
671
  {
 
672
    /*
 
673
      Because file->print_error() use my_error() to generate the error message
 
674
      we use an internal error handler to intercept it and store the text
 
675
      in a temporary buffer. Later the message will be presented to user
 
676
      as a warning.
 
677
    */
 
678
    Ha_delete_table_error_handler ha_delete_table_error_handler;
 
679
 
 
680
    /* Fill up strucutures that print_error may need */
 
681
    dummy_share.path.str= (char*) path;
 
682
    dummy_share.path.length= strlen(path);
 
683
    dummy_share.db.str= (char*) db;
 
684
    dummy_share.db.length= strlen(db);
 
685
    dummy_share.table_name.str= (char*) alias;
 
686
    dummy_share.table_name.length= strlen(alias);
 
687
    dummy_table.alias= alias;
 
688
 
 
689
    if(file != NULL)
 
690
    {
 
691
      file->change_table_ptr(&dummy_table, &dummy_share);
 
692
 
 
693
      session->push_internal_handler(&ha_delete_table_error_handler);
 
694
      file->print_error(error, 0);
 
695
 
 
696
      session->pop_internal_handler();
 
697
    }
 
698
    else
 
699
      error= -1; /* General form of fail. maybe bad FRM */
 
700
 
 
701
    /*
 
702
      XXX: should we convert *all* errors to warnings here?
 
703
      What if the error is fatal?
 
704
    */
 
705
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
 
706
                 ha_delete_table_error_handler.buff);
 
707
  }
 
708
 
 
709
  if(file)
 
710
    delete file;
 
711
 
 
712
  return error;
 
713
}
 
714
 
 
715
class DFETableNameIterator: public plugin::TableNameIteratorImplementation
 
716
{
 
717
private:
 
718
  MY_DIR *dirp;
 
719
  uint32_t current_entry;
 
720
 
 
721
public:
 
722
  DFETableNameIterator(const string &database)
 
723
  : plugin::TableNameIteratorImplementation(database),
 
724
    dirp(NULL),
 
725
    current_entry(-1)
 
726
    {};
 
727
 
 
728
  ~DFETableNameIterator();
 
729
 
 
730
  int next(string *name);
 
731
 
 
732
};
 
733
 
 
734
DFETableNameIterator::~DFETableNameIterator()
 
735
{
 
736
  if (dirp)
 
737
    my_dirend(dirp);
 
738
}
 
739
 
 
740
int DFETableNameIterator::next(string *name)
 
741
{
 
742
  char uname[NAME_LEN + 1];
 
743
  FILEINFO *file;
 
744
  char *ext;
 
745
  uint32_t file_name_len;
 
746
  const char *wild= NULL;
 
747
 
 
748
  if (dirp == NULL)
 
749
  {
 
750
    bool dir= false;
 
751
    char path[FN_REFLEN];
 
752
 
 
753
    build_table_filename(path, sizeof(path), db.c_str(), "", false);
 
754
 
 
755
    dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0));
 
756
 
 
757
    if (dirp == NULL)
 
758
    {
 
759
      if (my_errno == ENOENT)
 
760
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
 
761
      else
 
762
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
 
763
      return(ENOENT);
 
764
    }
 
765
    current_entry= -1;
 
766
  }
 
767
 
 
768
  while(true)
 
769
  {
 
770
    current_entry++;
 
771
 
 
772
    if (current_entry == dirp->number_off_files)
 
773
    {
 
774
      my_dirend(dirp);
 
775
      dirp= NULL;
 
776
      return -1;
 
777
    }
 
778
 
 
779
    file= dirp->dir_entry + current_entry;
 
780
 
 
781
    if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),".dfe") ||
 
782
        is_prefix(file->name, TMP_FILE_PREFIX))
 
783
      continue;
 
784
    *ext=0;
 
785
 
 
786
    file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
 
787
 
 
788
    uname[file_name_len]= '\0';
 
789
 
 
790
    if (wild && wild_compare(uname, wild, 0))
 
791
      continue;
 
792
 
 
793
    if (name)
 
794
      name->assign(uname);
 
795
 
 
796
    return 0;
 
797
  }
 
798
}
 
799
 
 
800
 
 
801
plugin::TableNameIterator::TableNameIterator(const string &db)
 
802
  : current_implementation(NULL), database(db)
 
803
{
 
804
  engine_iter= all_engines.begin();
 
805
  default_implementation= new DFETableNameIterator(database);
 
806
}
 
807
 
 
808
plugin::TableNameIterator::~TableNameIterator()
 
809
{
 
810
  delete current_implementation;
 
811
  if (current_implementation != default_implementation)
 
812
  {
 
813
    delete default_implementation;
 
814
  }
 
815
}
 
816
 
 
817
int plugin::TableNameIterator::next(string *name)
 
818
{
 
819
  int err= 0;
 
820
 
 
821
next:
 
822
  if (current_implementation == NULL)
 
823
  {
 
824
    while(current_implementation == NULL &&
 
825
          (engine_iter != all_engines.end()))
 
826
    {
 
827
      plugin::StorageEngine *engine= *engine_iter;
 
828
      current_implementation= engine->tableNameIterator(database);
 
829
      engine_iter++;
 
830
    }
 
831
 
 
832
    if (current_implementation == NULL &&
 
833
        (engine_iter == all_engines.end()))
 
834
    {
 
835
      current_implementation= default_implementation;
 
836
    }
 
837
  }
 
838
 
 
839
  err= current_implementation->next(name);
 
840
 
 
841
  if (err == -1)
 
842
  {
 
843
    if (current_implementation != default_implementation)
 
844
    {
 
845
      delete current_implementation;
 
846
      current_implementation= NULL;
 
847
      goto next;
 
848
    }
 
849
  }
 
850
 
 
851
  return err;
589
852
}
590
853
 
591
854
 
597
860
  @retval
598
861
   1  error
599
862
*/
600
 
bool StorageEngine::createTable(Session &session,
601
 
                                const identifier::Table &identifier,
602
 
                                message::Table& table_message)
603
 
{
604
 
  drizzled::error_t error= EE_OK;
605
 
 
606
 
  TableShare share(identifier);
607
 
  table::Shell table(share);
608
 
  message::Table tmp_proto;
609
 
 
610
 
  if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
611
 
  { 
612
 
    // @note Error occured, we should probably do a little more here.
613
 
    // ER_CORRUPT_TABLE_DEFINITION,ER_CORRUPT_TABLE_DEFINITION_ENUM 
614
 
    
615
 
    my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
616
 
 
617
 
    return false;
618
 
  }
619
 
  else
620
 
  {
621
 
    /* Check for legal operations against the Engine using the proto (if used) */
622
 
    if (table_message.type() == message::Table::TEMPORARY &&
623
 
        share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
624
 
    {
625
 
      error= HA_ERR_UNSUPPORTED;
626
 
    }
627
 
    else if (table_message.type() != message::Table::TEMPORARY &&
628
 
             share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
629
 
    {
630
 
      error= HA_ERR_UNSUPPORTED;
631
 
    }
632
 
    else
633
 
    {
634
 
      share.storage_engine->setTransactionReadWrite(session);
635
 
 
636
 
      error= static_cast<drizzled::error_t>(share.storage_engine->doCreateTable(session,
637
 
                                                                                table,
638
 
                                                                                identifier,
639
 
                                                                                table_message));
640
 
    }
641
 
 
642
 
    if (error == ER_TABLE_PERMISSION_DENIED)
643
 
    {
644
 
      my_error(ER_TABLE_PERMISSION_DENIED, identifier);
645
 
    }
646
 
    else if (error)
647
 
    {
648
 
      std::string path;
649
 
      identifier.getSQLPath(path);
650
 
      my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), path.c_str(), error);
651
 
    }
652
 
 
653
 
    table.delete_table();
654
 
  }
655
 
 
656
 
  return(error == EE_OK);
657
 
}
658
 
 
659
 
Cursor *StorageEngine::getCursor(Table &arg)
660
 
{
661
 
  return create(arg);
662
 
}
663
 
 
664
 
class AddTableIdentifier : 
665
 
  public std::unary_function<StorageEngine *, void>
666
 
{
667
 
  CachedDirectory &directory;
668
 
  const identifier::Schema &identifier;
669
 
  identifier::Table::vector &set_of_identifiers;
670
 
 
671
 
public:
672
 
 
673
 
  AddTableIdentifier(CachedDirectory &directory_arg, const identifier::Schema &identifier_arg, identifier::Table::vector &of_names) :
674
 
    directory(directory_arg),
675
 
    identifier(identifier_arg),
676
 
    set_of_identifiers(of_names)
677
 
  {
678
 
  }
679
 
 
680
 
  result_type operator() (argument_type engine)
681
 
  {
682
 
    engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
683
 
  }
684
 
};
685
 
 
686
 
 
687
 
void StorageEngine::getIdentifiers(Session &session, const identifier::Schema &schema_identifier, identifier::Table::vector &set_of_identifiers)
688
 
{
689
 
  CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
690
 
 
691
 
  if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
692
 
  { }
693
 
  else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
694
 
  { }
695
 
  else
696
 
  {
697
 
    if (directory.fail())
698
 
    {
699
 
      errno= directory.getError();
700
 
      if (errno == ENOENT)
701
 
      {
702
 
        std::string path;
703
 
        schema_identifier.getSQLPath(path);
704
 
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), path.c_str());
705
 
      }
706
 
      else
707
 
      {
708
 
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
709
 
      }
710
 
 
711
 
      return;
712
 
    }
713
 
  }
714
 
 
715
 
  std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
716
 
                AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
717
 
 
718
 
  session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
719
 
}
720
 
 
721
 
class DropTable: public std::unary_function<identifier::Table&, bool>
722
 
{
723
 
  Session &session;
724
 
  StorageEngine *engine;
725
 
 
726
 
public:
727
 
 
728
 
  DropTable(Session &session_arg, StorageEngine *engine_arg) :
729
 
    session(session_arg),
730
 
    engine(engine_arg)
731
 
  { }
732
 
 
733
 
  result_type operator() (argument_type identifier)
734
 
  {
735
 
    return engine->doDropTable(session, identifier) == 0;
736
 
  } 
737
 
};
738
 
 
739
 
/* This will later be converted to identifier::Tables */
740
 
class DropTables: public std::unary_function<StorageEngine *, void>
741
 
{
742
 
  Session &session;
743
 
  identifier::Table::vector &table_identifiers;
744
 
 
745
 
public:
746
 
 
747
 
  DropTables(Session &session_arg, identifier::Table::vector &table_identifiers_arg) :
748
 
    session(session_arg),
749
 
    table_identifiers(table_identifiers_arg)
750
 
  { }
751
 
 
752
 
  result_type operator() (argument_type engine)
753
 
  {
754
 
    // True returning from DropTable means the table has been successfully
755
 
    // deleted, so it should be removed from the list of tables to drop
756
 
    table_identifiers.erase(std::remove_if(table_identifiers.begin(),
757
 
                                           table_identifiers.end(),
758
 
                                           DropTable(session, engine)),
759
 
                            table_identifiers.end());
760
 
  }
761
 
};
762
 
 
763
 
/*
764
 
  This only works for engines which use file based DFE.
765
 
 
766
 
  Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
767
 
*/
768
 
void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
769
 
{
770
 
  CachedDirectory dir(directory, set_of_table_definition_ext);
771
 
  identifier::Table::vector table_identifiers;
772
 
 
773
 
  if (dir.fail())
774
 
  {
775
 
    errno= dir.getError();
776
 
    my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
777
 
 
778
 
    return;
779
 
  }
780
 
 
781
 
  CachedDirectory::Entries files= dir.getEntries();
782
 
 
783
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
784
 
       fileIter != files.end(); fileIter++)
785
 
  {
786
 
    size_t length;
787
 
    std::string path;
788
 
    CachedDirectory::Entry *entry= *fileIter;
789
 
 
790
 
    /* We remove the file extension. */
791
 
    length= entry->filename.length();
792
 
    entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
793
 
 
794
 
    path+= directory;
795
 
    path+= FN_LIBCHAR;
796
 
    path+= entry->filename;
797
 
    message::Table definition;
798
 
    if (StorageEngine::readTableFile(path, definition))
799
 
    {
800
 
      identifier::Table identifier(definition.schema(), definition.name(), path);
801
 
      table_identifiers.push_back(identifier);
802
 
    }
803
 
  }
804
 
 
805
 
  std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
806
 
                DropTables(session, table_identifiers));
807
 
 
808
 
  /*
809
 
    Now we just clean up anything that might left over.
810
 
 
811
 
    We rescan because some of what might have been there should
812
 
    now be all nice and cleaned up.
813
 
  */
814
 
  std::set<std::string> all_exts= set_of_table_definition_ext;
815
 
 
816
 
  for (EngineVector::iterator iter= vector_of_engines.begin();
817
 
       iter != vector_of_engines.end() ; iter++)
818
 
  {
819
 
    for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
820
 
      all_exts.insert(*ext);
821
 
  }
822
 
 
823
 
  CachedDirectory rescan(directory, all_exts);
824
 
 
825
 
  files= rescan.getEntries();
826
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
827
 
       fileIter != files.end(); fileIter++)
828
 
  {
829
 
    std::string path;
830
 
    CachedDirectory::Entry *entry= *fileIter;
831
 
 
832
 
    path+= directory;
833
 
    path+= FN_LIBCHAR;
834
 
    path+= entry->filename;
835
 
 
836
 
    unlink(path.c_str());
837
 
  }
838
 
}
839
 
 
840
 
 
841
 
/**
842
 
  Print error that we got from Cursor function.
843
 
 
844
 
  @note
845
 
    In case of delete table it's only safe to use the following parts of
846
 
    the 'table' structure:
847
 
    - table->getShare()->path
848
 
    - table->alias
849
 
*/
850
 
void StorageEngine::print_error(int error, myf errflag, const Table &table) const
851
 
{
852
 
  drizzled::error_t textno= ER_GET_ERRNO;
853
 
  switch (error) {
854
 
  case EACCES:
855
 
    textno=ER_OPEN_AS_READONLY;
856
 
    break;
857
 
  case EAGAIN:
858
 
    textno=ER_FILE_USED;
859
 
    break;
860
 
  case ENOENT:
861
 
    textno=ER_FILE_NOT_FOUND;
862
 
    break;
863
 
  case HA_ERR_KEY_NOT_FOUND:
864
 
  case HA_ERR_NO_ACTIVE_RECORD:
865
 
  case HA_ERR_END_OF_FILE:
866
 
    textno=ER_KEY_NOT_FOUND;
867
 
    break;
868
 
  case HA_ERR_WRONG_MRG_TABLE_DEF:
869
 
    textno=ER_WRONG_MRG_TABLE;
870
 
    break;
871
 
  case HA_ERR_FOUND_DUPP_KEY:
872
 
  {
873
 
    uint32_t key_nr= table.get_dup_key(error);
874
 
    if ((int) key_nr >= 0)
875
 
    {
876
 
      const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
877
 
 
878
 
      print_keydup_error(key_nr, err_msg, table);
879
 
 
880
 
      return;
881
 
    }
882
 
    textno=ER_DUP_KEY;
883
 
    break;
884
 
  }
885
 
  case HA_ERR_FOREIGN_DUPLICATE_KEY:
886
 
  {
887
 
    uint32_t key_nr= table.get_dup_key(error);
888
 
    if ((int) key_nr >= 0)
889
 
    {
890
 
      uint32_t max_length;
891
 
 
892
 
      /* Write the key in the error message */
893
 
      char key[MAX_KEY_LENGTH];
894
 
      String str(key,sizeof(key),system_charset_info);
895
 
 
896
 
      /* Table is opened and defined at this point */
897
 
      key_unpack(&str, &table,(uint32_t) key_nr);
898
 
      max_length= (DRIZZLE_ERRMSG_SIZE-
899
 
                   (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
900
 
      if (str.length() >= max_length)
901
 
      {
902
 
        str.length(max_length-4);
903
 
        str.append(STRING_WITH_LEN("..."));
904
 
      }
905
 
      my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
906
 
        str.c_ptr(), key_nr+1);
907
 
      return;
908
 
    }
909
 
    textno= ER_DUP_KEY;
910
 
    break;
911
 
  }
912
 
  case HA_ERR_FOUND_DUPP_UNIQUE:
913
 
    textno=ER_DUP_UNIQUE;
914
 
    break;
915
 
  case HA_ERR_RECORD_CHANGED:
916
 
    textno=ER_CHECKREAD;
917
 
    break;
918
 
  case HA_ERR_CRASHED:
919
 
    textno=ER_NOT_KEYFILE;
920
 
    break;
921
 
  case HA_ERR_WRONG_IN_RECORD:
922
 
    textno= ER_CRASHED_ON_USAGE;
923
 
    break;
924
 
  case HA_ERR_CRASHED_ON_USAGE:
925
 
    textno=ER_CRASHED_ON_USAGE;
926
 
    break;
927
 
  case HA_ERR_NOT_A_TABLE:
928
 
    textno= static_cast<drizzled::error_t>(error);
929
 
    break;
930
 
  case HA_ERR_CRASHED_ON_REPAIR:
931
 
    textno=ER_CRASHED_ON_REPAIR;
932
 
    break;
933
 
  case HA_ERR_OUT_OF_MEM:
934
 
    textno=ER_OUT_OF_RESOURCES;
935
 
    break;
936
 
  case HA_ERR_WRONG_COMMAND:
937
 
    textno=ER_ILLEGAL_HA;
938
 
    break;
939
 
  case HA_ERR_OLD_FILE:
940
 
    textno=ER_OLD_KEYFILE;
941
 
    break;
942
 
  case HA_ERR_UNSUPPORTED:
943
 
    textno=ER_UNSUPPORTED_EXTENSION;
944
 
    break;
945
 
  case HA_ERR_RECORD_FILE_FULL:
946
 
  case HA_ERR_INDEX_FILE_FULL:
947
 
    textno=ER_RECORD_FILE_FULL;
948
 
    break;
949
 
  case HA_ERR_LOCK_WAIT_TIMEOUT:
950
 
    textno=ER_LOCK_WAIT_TIMEOUT;
951
 
    break;
952
 
  case HA_ERR_LOCK_TABLE_FULL:
953
 
    textno=ER_LOCK_TABLE_FULL;
954
 
    break;
955
 
  case HA_ERR_LOCK_DEADLOCK:
956
 
    textno=ER_LOCK_DEADLOCK;
957
 
    break;
958
 
  case HA_ERR_READ_ONLY_TRANSACTION:
959
 
    textno=ER_READ_ONLY_TRANSACTION;
960
 
    break;
961
 
  case HA_ERR_CANNOT_ADD_FOREIGN:
962
 
    textno=ER_CANNOT_ADD_FOREIGN;
963
 
    break;
964
 
  case HA_ERR_ROW_IS_REFERENCED:
965
 
  {
966
 
    String str;
967
 
    get_error_message(error, &str);
968
 
    my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
969
 
    return;
970
 
  }
971
 
  case HA_ERR_NO_REFERENCED_ROW:
972
 
  {
973
 
    String str;
974
 
    get_error_message(error, &str);
975
 
    my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
976
 
    return;
977
 
  }
978
 
  case HA_ERR_TABLE_DEF_CHANGED:
979
 
    textno=ER_TABLE_DEF_CHANGED;
980
 
    break;
981
 
  case HA_ERR_NO_SUCH_TABLE:
982
 
    {
983
 
      identifier::Table identifier(table.getShare()->getSchemaName(), table.getShare()->getTableName());
984
 
      my_error(ER_TABLE_UNKNOWN, identifier);
985
 
      return;
986
 
    }
987
 
  case HA_ERR_RBR_LOGGING_FAILED:
988
 
    textno= ER_BINLOG_ROW_LOGGING_FAILED;
989
 
    break;
990
 
  case HA_ERR_DROP_INDEX_FK:
991
 
  {
992
 
    const char *ptr= "???";
993
 
    uint32_t key_nr= table.get_dup_key(error);
994
 
    if ((int) key_nr >= 0)
995
 
      ptr= table.key_info[key_nr].name;
996
 
    my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
997
 
    return;
998
 
  }
999
 
  case HA_ERR_TABLE_NEEDS_UPGRADE:
1000
 
    textno=ER_TABLE_NEEDS_UPGRADE;
1001
 
    break;
1002
 
  case HA_ERR_TABLE_READONLY:
1003
 
    textno= ER_OPEN_AS_READONLY;
1004
 
    break;
1005
 
  case HA_ERR_AUTOINC_READ_FAILED:
1006
 
    textno= ER_AUTOINC_READ_FAILED;
1007
 
    break;
1008
 
  case HA_ERR_AUTOINC_ERANGE:
1009
 
    textno= ER_WARN_DATA_OUT_OF_RANGE;
1010
 
    break;
1011
 
  case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
1012
 
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
1013
 
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
1014
 
    return;
1015
 
  default:
1016
 
    {
1017
 
      /* 
1018
 
        The error was "unknown" to this function.
1019
 
        Ask Cursor if it has got a message for this error 
1020
 
      */
1021
 
      bool temporary= false;
1022
 
      String str;
1023
 
      temporary= get_error_message(error, &str);
1024
 
      if (!str.is_empty())
1025
 
      {
1026
 
        const char* engine_name= getName().c_str();
1027
 
        if (temporary)
1028
 
          my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
1029
 
                   engine_name);
1030
 
        else
1031
 
          my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
1032
 
      }
1033
 
      else
1034
 
      {
1035
 
              my_error(ER_GET_ERRNO,errflag,error);
1036
 
      }
1037
 
      return;
1038
 
    }
1039
 
  }
1040
 
 
1041
 
  my_error(textno, errflag, table.getShare()->getTableName(), error);
1042
 
}
1043
 
 
1044
 
 
1045
 
/**
1046
 
  Return an error message specific to this Cursor.
1047
 
 
1048
 
  @param error  error code previously returned by Cursor
1049
 
  @param buf    pointer to String where to add error message
1050
 
 
1051
 
  @return
1052
 
    Returns true if this is a temporary error
1053
 
*/
1054
 
bool StorageEngine::get_error_message(int , String* ) const
1055
 
{
1056
 
  return false;
1057
 
}
1058
 
 
1059
 
 
1060
 
void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, const Table &table) const
1061
 
{
1062
 
  /* Write the duplicated key in the error message */
1063
 
  char key[MAX_KEY_LENGTH];
1064
 
  String str(key,sizeof(key),system_charset_info);
1065
 
 
1066
 
  if (key_nr == MAX_KEY)
1067
 
  {
1068
 
    /* Key is unknown */
1069
 
    str.copy("", 0, system_charset_info);
1070
 
    my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
1071
 
  }
1072
 
  else
1073
 
  {
1074
 
    /* Table is opened and defined at this point */
1075
 
    key_unpack(&str, &table, (uint32_t) key_nr);
1076
 
    uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
1077
 
    if (str.length() >= max_length)
1078
 
    {
1079
 
      str.length(max_length-4);
1080
 
      str.append(STRING_WITH_LEN("..."));
1081
 
    }
1082
 
    my_printf_error(ER_DUP_ENTRY, msg,
1083
 
                    MYF(0), str.c_ptr(), table.key_info[key_nr].name);
1084
 
  }
1085
 
}
1086
 
 
1087
 
 
1088
 
int StorageEngine::deleteDefinitionFromPath(const identifier::Table &identifier)
1089
 
{
1090
 
  std::string path(identifier.getPath());
1091
 
 
1092
 
  path.append(DEFAULT_DEFINITION_FILE_EXT);
1093
 
 
1094
 
  return internal::my_delete(path.c_str(), MYF(0));
1095
 
}
1096
 
 
1097
 
int StorageEngine::renameDefinitionFromPath(const identifier::Table &dest, const identifier::Table &src)
1098
 
{
1099
 
  message::Table table_message;
1100
 
  std::string src_path(src.getPath());
1101
 
  std::string dest_path(dest.getPath());
1102
 
 
1103
 
  src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1104
 
  dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1105
 
 
1106
 
  bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
1107
 
 
1108
 
  if (not was_read)
1109
 
  {
1110
 
    return ENOENT;
1111
 
  }
1112
 
 
1113
 
  dest.copyToTableMessage(table_message);
1114
 
 
1115
 
  int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
1116
 
 
1117
 
  if (not error)
1118
 
  {
1119
 
    if (unlink(src_path.c_str()))
1120
 
      perror(src_path.c_str());
1121
 
  }
1122
 
 
1123
 
  return error;
1124
 
}
1125
 
 
1126
 
int StorageEngine::writeDefinitionFromPath(const identifier::Table &identifier, message::Table &table_message)
1127
 
{
1128
 
  char definition_file_tmp[FN_REFLEN];
1129
 
  std::string file_name(identifier.getPath());
1130
 
 
1131
 
  file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1132
 
 
1133
 
  snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
1134
 
 
1135
 
  int fd= mkstemp(definition_file_tmp);
1136
 
 
1137
 
  if (fd == -1)
1138
 
  {
1139
 
    perror(definition_file_tmp);
1140
 
    return errno;
1141
 
  }
1142
 
 
1143
 
  google::protobuf::io::ZeroCopyOutputStream* output=
1144
 
    new google::protobuf::io::FileOutputStream(fd);
1145
 
 
1146
 
  bool success;
1147
 
 
1148
 
  try
1149
 
  {
1150
 
    success= table_message.SerializeToZeroCopyStream(output);
1151
 
  }
1152
 
  catch (...)
1153
 
  {
1154
 
    success= false;
1155
 
  }
1156
 
 
1157
 
  if (not success)
1158
 
  {
1159
 
    std::string error_message;
1160
 
    identifier.getSQLPath(error_message);
1161
 
 
1162
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1163
 
             error_message.c_str(),
1164
 
             table_message.InitializationErrorString().c_str());
1165
 
    delete output;
1166
 
 
1167
 
    if (close(fd) == -1)
1168
 
      perror(definition_file_tmp);
1169
 
 
1170
 
    if (unlink(definition_file_tmp) == -1)
1171
 
      perror(definition_file_tmp);
1172
 
 
1173
 
    return ER_CORRUPT_TABLE_DEFINITION;
1174
 
  }
1175
 
 
1176
 
  delete output;
1177
 
 
1178
 
  if (close(fd) == -1)
1179
 
  {
1180
 
    int error= errno;
1181
 
    perror(definition_file_tmp);
1182
 
 
1183
 
    if (unlink(definition_file_tmp))
1184
 
      perror(definition_file_tmp);
1185
 
 
1186
 
    return error;
1187
 
  }
1188
 
 
1189
 
  if (rename(definition_file_tmp, file_name.c_str()) == -1)
1190
 
  {
1191
 
    int error= errno;
1192
 
    perror(definition_file_tmp);
1193
 
 
1194
 
    if (unlink(definition_file_tmp))
1195
 
      perror(definition_file_tmp);
1196
 
 
1197
 
    return error;
1198
 
  }
1199
 
 
1200
 
  return 0;
1201
 
}
1202
 
 
1203
 
class CanCreateTable: public std::unary_function<StorageEngine *, bool>
1204
 
{
1205
 
  const identifier::Table &identifier;
1206
 
 
1207
 
public:
1208
 
  CanCreateTable(const identifier::Table &identifier_arg) :
1209
 
    identifier(identifier_arg)
1210
 
  { }
1211
 
 
1212
 
  result_type operator() (argument_type engine)
1213
 
  {
1214
 
    return not engine->doCanCreateTable(identifier);
1215
 
  }
1216
 
};
1217
 
 
1218
 
 
1219
 
/**
1220
 
  @note on success table can be created.
1221
 
*/
1222
 
bool StorageEngine::canCreateTable(const identifier::Table &identifier)
1223
 
{
1224
 
  EngineVector::iterator iter=
1225
 
    std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
1226
 
                 CanCreateTable(identifier));
1227
 
 
1228
 
  if (iter == vector_of_engines.end())
1229
 
  {
1230
 
    return true;
1231
 
  }
1232
 
 
1233
 
  return false;
1234
 
}
1235
 
 
1236
 
bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
1237
 
{
1238
 
  std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
1239
 
 
1240
 
  if (input.good())
1241
 
  {
1242
 
    try {
1243
 
      if (table_message.ParseFromIstream(&input))
1244
 
      {
1245
 
        return true;
1246
 
      }
1247
 
    }
1248
 
    catch (...)
1249
 
    {
1250
 
      my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1251
 
               table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
1252
 
               table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
1253
 
    }
1254
 
  }
1255
 
  else
1256
 
  {
1257
 
    perror(path.c_str());
1258
 
  }
1259
 
 
1260
 
  return false;
1261
 
}
1262
 
 
1263
 
std::ostream& operator<<(std::ostream& output, const StorageEngine &engine)
1264
 
{
1265
 
  output << "StorageEngine:(";
1266
 
  output <<  engine.getName();
1267
 
  output << ")";
1268
 
 
1269
 
  return output;
1270
 
}
1271
 
 
1272
 
} /* namespace plugin */
 
863
int plugin::StorageEngine::createTable(Session *session, const char *path,
 
864
                                       const char *db, const char *table_name,
 
865
                                       HA_CREATE_INFO *create_info,
 
866
                                       bool update_create_info,
 
867
                                       drizzled::message::Table *table_proto)
 
868
{
 
869
  int error= 1;
 
870
  Table table;
 
871
  TableShare share(db, 0, table_name, path);
 
872
  drizzled::message::Table tmp_proto;
 
873
 
 
874
  if (table_proto)
 
875
  {
 
876
    if (parse_table_proto(session, *table_proto, &share))
 
877
      goto err;
 
878
  }
 
879
  else
 
880
  {
 
881
    table_proto= &tmp_proto;
 
882
    if (open_table_def(session, &share))
 
883
      goto err;
 
884
  }
 
885
 
 
886
  if (open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0,
 
887
                            &table, OTM_CREATE))
 
888
    goto err;
 
889
 
 
890
  if (update_create_info)
 
891
    table.updateCreateInfo(create_info, table_proto);
 
892
 
 
893
  error= share.storage_engine->createTable(session, path, &table,
 
894
                                           create_info, table_proto);
 
895
  table.closefrm(false);
 
896
  if (error)
 
897
  {
 
898
    char name_buff[FN_REFLEN];
 
899
    sprintf(name_buff,"%s.%s",db,table_name);
 
900
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
 
901
  }
 
902
err:
 
903
  share.free_table_share();
 
904
  return(error != 0);
 
905
}
 
906
 
 
907
 
 
908
 
1273
909
} /* namespace drizzled */
 
910
 
 
911
 
 
912
 
 
913
handler *get_new_handler(TableShare *share, MEM_ROOT *alloc,
 
914
                         drizzled::plugin::StorageEngine *engine)
 
915
{
 
916
  handler *file;
 
917
 
 
918
  if (engine && engine->is_enabled())
 
919
  {
 
920
    if ((file= engine->create(share, alloc)))
 
921
      file->init();
 
922
    return(file);
 
923
  }
 
924
  /*
 
925
    Try the default table type
 
926
    Here the call to current_session() is ok as we call this function a lot of
 
927
    times but we enter this branch very seldom.
 
928
  */
 
929
  return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
 
930
}
 
931
 
 
932
 
 
933
/**
 
934
  Return the default storage engine plugin::StorageEngine for thread
 
935
 
 
936
  @param ha_default_storage_engine(session)
 
937
  @param session         current thread
 
938
 
 
939
  @return
 
940
    pointer to plugin::StorageEngine
 
941
*/
 
942
drizzled::plugin::StorageEngine *ha_default_storage_engine(Session *session)
 
943
{
 
944
  if (session->variables.storage_engine)
 
945
    return session->variables.storage_engine;
 
946
  return global_system_variables.storage_engine;
 
947
}