~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

Removed reference to aio.h - we don't reference its use anywhere.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; version 2 of the License.
9
 
 *
10
 
 *  This program is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *  GNU General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU General Public License
16
 
 *  along with this program; if not, write to the Free Software
17
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
 
20
 
#include "config.h"
21
 
 
22
 
#include <fcntl.h>
23
 
#include <unistd.h>
24
 
 
25
 
#include <string>
26
 
#include <vector>
27
 
#include <set>
28
 
#include <fstream>
29
 
#include <algorithm>
30
 
#include <functional>
31
 
 
32
 
#include <google/protobuf/io/zero_copy_stream.h>
33
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
34
 
 
35
 
#include "drizzled/cached_directory.h"
36
 
 
37
 
#include <drizzled/definitions.h>
38
 
#include <drizzled/base.h>
39
 
#include <drizzled/cursor.h>
40
 
#include <drizzled/plugin/storage_engine.h>
41
 
#include <drizzled/session.h>
42
 
#include <drizzled/error.h>
43
 
#include <drizzled/gettext.h>
44
 
#include <drizzled/unireg.h>
45
 
#include <drizzled/data_home.h>
46
 
#include "drizzled/errmsg_print.h"
47
 
#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
 
 
54
 
#include <drizzled/table_proto.h>
55
 
#include <drizzled/plugin/event_observer.h>
56
 
 
57
 
#include <boost/algorithm/string/compare.hpp>
58
 
 
59
 
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
60
 
 
61
 
using namespace std;
62
 
 
63
 
namespace drizzled
64
 
{
65
 
 
66
 
namespace plugin
67
 
{
68
 
 
69
 
static EngineVector vector_of_engines;
70
 
static EngineVector vector_of_schema_engines;
71
 
 
72
 
const std::string DEFAULT_STRING("default");
73
 
const std::string UNKNOWN_STRING("UNKNOWN");
74
 
const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
75
 
 
76
 
static std::set<std::string> set_of_table_definition_ext;
77
 
 
78
 
EngineVector &StorageEngine::getSchemaEngines()
79
 
{
80
 
  return vector_of_schema_engines;
81
 
}
82
 
 
83
 
StorageEngine::StorageEngine(const string name_arg,
84
 
                             const bitset<HTON_BIT_SIZE> &flags_arg) :
85
 
  Plugin(name_arg, "StorageEngine"),
86
 
  MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
87
 
  flags(flags_arg)
88
 
{
89
 
}
90
 
 
91
 
StorageEngine::~StorageEngine()
92
 
{
93
 
}
94
 
 
95
 
void StorageEngine::setTransactionReadWrite(Session& session)
96
 
{
97
 
  TransactionContext &statement_ctx= session.transaction.stmt;
98
 
  statement_ctx.markModifiedNonTransData();
99
 
}
100
 
 
101
 
 
102
 
int StorageEngine::renameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
103
 
{
104
 
  int error;
105
 
  setTransactionReadWrite(session);
106
 
 
107
 
  if (unlikely(plugin::EventObserver::beforeRenameTable(session, from, to)))
108
 
  {
109
 
    error= ER_EVENT_OBSERVER_PLUGIN;
110
 
  }
111
 
  else
112
 
  {
113
 
    error =  doRenameTable(session, from, to);
114
 
    if (unlikely(plugin::EventObserver::afterRenameTable(session, from, to, error)))
115
 
    {
116
 
      error= ER_EVENT_OBSERVER_PLUGIN;
117
 
    }
118
 
  }
119
 
  
120
 
  return error;
121
 
}
122
 
 
123
 
/**
124
 
  Delete all files with extension from bas_ext().
125
 
 
126
 
  @param name           Base name of table
127
 
 
128
 
  @note
129
 
    We assume that the Cursor may return more extensions than
130
 
    was actually used for the file.
131
 
 
132
 
  @retval
133
 
    0   If we successfully deleted at least one file from base_ext and
134
 
    didn't get any other errors than ENOENT
135
 
  @retval
136
 
    !0  Error
137
 
*/
138
 
int StorageEngine::doDropTable(Session&, const TableIdentifier &identifier)
139
 
                               
140
 
{
141
 
  int error= 0;
142
 
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
143
 
  char buff[FN_REFLEN];
144
 
 
145
 
  for (const char **ext= bas_ext(); *ext ; ext++)
146
 
  {
147
 
    internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
148
 
                        MY_UNPACK_FILENAME|MY_APPEND_EXT);
149
 
    if (internal::my_delete_with_symlink(buff, MYF(0)))
150
 
    {
151
 
      if ((error= errno) != ENOENT)
152
 
        break;
153
 
    }
154
 
    else
155
 
    {
156
 
      enoent_or_zero= 0;                        // No error for ENOENT
157
 
    }
158
 
 
159
 
    error= enoent_or_zero;
160
 
  }
161
 
  return error;
162
 
}
163
 
 
164
 
bool StorageEngine::addPlugin(StorageEngine *engine)
165
 
{
166
 
 
167
 
  vector_of_engines.push_back(engine);
168
 
 
169
 
  if (engine->getTableDefinitionFileExtension().length())
170
 
  {
171
 
    assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
172
 
    set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
173
 
  }
174
 
 
175
 
  if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
176
 
    vector_of_schema_engines.push_back(engine);
177
 
 
178
 
  return false;
179
 
}
180
 
 
181
 
void StorageEngine::removePlugin(StorageEngine *)
182
 
{
183
 
  if (shutdown_has_begun == false)
184
 
  {
185
 
    vector_of_engines.clear();
186
 
    vector_of_schema_engines.clear();
187
 
 
188
 
    shutdown_has_begun= true;
189
 
  }
190
 
}
191
 
 
192
 
class FindEngineByName
193
 
  : public unary_function<StorageEngine *, bool>
194
 
{
195
 
  const string &predicate;
196
 
 
197
 
public:
198
 
  explicit FindEngineByName(const string &target_arg) :
199
 
    predicate(target_arg)
200
 
  {
201
 
  }
202
 
 
203
 
  result_type operator() (argument_type engine)
204
 
  {
205
 
    return boost::iequals(engine->getName(), predicate);
206
 
  }
207
 
};
208
 
 
209
 
StorageEngine *StorageEngine::findByName(const string &predicate)
210
 
{
211
 
  EngineVector::iterator iter= find_if(vector_of_engines.begin(),
212
 
                                       vector_of_engines.end(),
213
 
                                       FindEngineByName(predicate));
214
 
  if (iter != vector_of_engines.end())
215
 
  {
216
 
    StorageEngine *engine= *iter;
217
 
    if (engine->is_user_selectable())
218
 
      return engine;
219
 
  }
220
 
 
221
 
  return NULL;
222
 
}
223
 
 
224
 
StorageEngine *StorageEngine::findByName(Session& session, const string &predicate)
225
 
{
226
 
  if (boost::iequals(predicate, DEFAULT_STRING))
227
 
    return session.getDefaultStorageEngine();
228
 
 
229
 
  EngineVector::iterator iter= find_if(vector_of_engines.begin(),
230
 
                                       vector_of_engines.end(),
231
 
                                       FindEngineByName(predicate));
232
 
  if (iter != vector_of_engines.end())
233
 
  {
234
 
    StorageEngine *engine= *iter;
235
 
    if (engine->is_user_selectable())
236
 
      return engine;
237
 
  }
238
 
 
239
 
  return NULL;
240
 
}
241
 
 
242
 
class StorageEngineCloseConnection : public unary_function<StorageEngine *, void>
243
 
{
244
 
  Session *session;
245
 
public:
246
 
  StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
247
 
  /*
248
 
    there's no need to rollback here as all transactions must
249
 
    be rolled back already
250
 
  */
251
 
  inline result_type operator() (argument_type engine)
252
 
  {
253
 
    if (*session->getEngineData(engine))
254
 
      engine->close_connection(session);
255
 
  }
256
 
};
257
 
 
258
 
/**
259
 
  @note
260
 
    don't bother to rollback here, it's done already
261
 
*/
262
 
void StorageEngine::closeConnection(Session* session)
263
 
{
264
 
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
265
 
           StorageEngineCloseConnection(session));
266
 
}
267
 
 
268
 
bool StorageEngine::flushLogs(StorageEngine *engine)
269
 
{
270
 
  if (engine == NULL)
271
 
  {
272
 
    if (find_if(vector_of_engines.begin(), vector_of_engines.end(),
273
 
                mem_fun(&StorageEngine::flush_logs))
274
 
        != vector_of_engines.begin())
275
 
      return true;
276
 
  }
277
 
  else
278
 
  {
279
 
    if (engine->flush_logs())
280
 
      return true;
281
 
  }
282
 
  return false;
283
 
}
284
 
 
285
 
class StorageEngineGetTableDefinition: public unary_function<StorageEngine *,bool>
286
 
{
287
 
  Session& session;
288
 
  const TableIdentifier &identifier;
289
 
  message::Table &table_message;
290
 
  int &err;
291
 
 
292
 
public:
293
 
  StorageEngineGetTableDefinition(Session& session_arg,
294
 
                                  const TableIdentifier &identifier_arg,
295
 
                                  message::Table &table_message_arg,
296
 
                                  int &err_arg) :
297
 
    session(session_arg), 
298
 
    identifier(identifier_arg),
299
 
    table_message(table_message_arg), 
300
 
    err(err_arg) {}
301
 
 
302
 
  result_type operator() (argument_type engine)
303
 
  {
304
 
    int ret= engine->doGetTableDefinition(session, identifier, table_message);
305
 
 
306
 
    if (ret != ENOENT)
307
 
      err= ret;
308
 
 
309
 
    return err == EEXIST || err != ENOENT;
310
 
  }
311
 
};
312
 
 
313
 
class StorageEngineDoesTableExist: public unary_function<StorageEngine *, bool>
314
 
{
315
 
  Session& session;
316
 
  const TableIdentifier &identifier;
317
 
 
318
 
public:
319
 
  StorageEngineDoesTableExist(Session& session_arg, const TableIdentifier &identifier_arg) :
320
 
    session(session_arg), 
321
 
    identifier(identifier_arg) 
322
 
  { }
323
 
 
324
 
  result_type operator() (argument_type engine)
325
 
  {
326
 
    return engine->doDoesTableExist(session, identifier);
327
 
  }
328
 
};
329
 
 
330
 
/**
331
 
  Utility method which hides some of the details of getTableDefinition()
332
 
*/
333
 
bool plugin::StorageEngine::doesTableExist(Session &session,
334
 
                                           const TableIdentifier &identifier,
335
 
                                           bool include_temporary_tables)
336
 
{
337
 
  if (include_temporary_tables)
338
 
  {
339
 
    if (session.doDoesTableExist(identifier))
340
 
      return true;
341
 
  }
342
 
 
343
 
  EngineVector::iterator iter=
344
 
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
345
 
            StorageEngineDoesTableExist(session, identifier));
346
 
 
347
 
  if (iter == vector_of_engines.end())
348
 
  {
349
 
    return false;
350
 
  }
351
 
 
352
 
  return true;
353
 
}
354
 
 
355
 
bool plugin::StorageEngine::doDoesTableExist(Session&, const drizzled::TableIdentifier&)
356
 
{
357
 
  cerr << " Engine was called for doDoesTableExist() and does not implement it: " << this->getName() << "\n";
358
 
  assert(0);
359
 
  return false;
360
 
}
361
 
 
362
 
/**
363
 
  Call this function in order to give the Cursor the possiblity
364
 
  to ask engine if there are any new tables that should be written to disk
365
 
  or any dropped tables that need to be removed from disk
366
 
*/
367
 
int StorageEngine::getTableDefinition(Session& session,
368
 
                                      const TableIdentifier &identifier,
369
 
                                      message::Table &table_message,
370
 
                                      bool include_temporary_tables)
371
 
{
372
 
  int err= ENOENT;
373
 
 
374
 
  if (include_temporary_tables)
375
 
  {
376
 
    if (session.doGetTableDefinition(identifier, table_message) == EEXIST)
377
 
      return EEXIST;
378
 
  }
379
 
 
380
 
  EngineVector::iterator iter=
381
 
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
382
 
            StorageEngineGetTableDefinition(session, identifier, table_message, err));
383
 
 
384
 
  if (iter == vector_of_engines.end())
385
 
  {
386
 
    return ENOENT;
387
 
  }
388
 
 
389
 
  return err;
390
 
}
391
 
 
392
 
/**
393
 
  An interceptor to hijack the text of the error message without
394
 
  setting an error in the thread. We need the text to present it
395
 
  in the form of a warning to the user.
396
 
*/
397
 
 
398
 
class Ha_delete_table_error_handler: public Internal_error_handler
399
 
{
400
 
public:
401
 
  Ha_delete_table_error_handler() : Internal_error_handler() {}
402
 
  virtual bool handle_error(uint32_t sql_errno,
403
 
                            const char *message,
404
 
                            DRIZZLE_ERROR::enum_warning_level level,
405
 
                            Session *session);
406
 
  char buff[DRIZZLE_ERRMSG_SIZE];
407
 
};
408
 
 
409
 
 
410
 
bool
411
 
Ha_delete_table_error_handler::
412
 
handle_error(uint32_t ,
413
 
             const char *message,
414
 
             DRIZZLE_ERROR::enum_warning_level ,
415
 
             Session *)
416
 
{
417
 
  /* Grab the error message */
418
 
  strncpy(buff, message, sizeof(buff)-1);
419
 
  return true;
420
 
}
421
 
 
422
 
/**
423
 
   returns ENOENT if the file doesn't exists.
424
 
*/
425
 
int StorageEngine::dropTable(Session& session,
426
 
                             const TableIdentifier &identifier)
427
 
{
428
 
  int error= 0;
429
 
  int error_proto;
430
 
  message::Table src_proto;
431
 
  StorageEngine *engine;
432
 
 
433
 
  error_proto= StorageEngine::getTableDefinition(session, identifier, src_proto);
434
 
 
435
 
  if (error_proto == ER_CORRUPT_TABLE_DEFINITION)
436
 
  {
437
 
    string error_message;
438
 
 
439
 
    error_message.append(const_cast<TableIdentifier &>(identifier).getSQLPath());
440
 
    error_message.append(" : ");
441
 
    error_message.append(src_proto.InitializationErrorString());
442
 
 
443
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), error_message.c_str());
444
 
 
445
 
    return ER_CORRUPT_TABLE_DEFINITION;
446
 
  }
447
 
 
448
 
  engine= StorageEngine::findByName(session, src_proto.engine().name());
449
 
 
450
 
  if (not engine)
451
 
  {
452
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), const_cast<TableIdentifier &>(identifier).getSQLPath().c_str());
453
 
 
454
 
    return ER_CORRUPT_TABLE_DEFINITION;
455
 
  }
456
 
 
457
 
  error= StorageEngine::dropTable(session, *engine, identifier);
458
 
 
459
 
  if (error_proto && error == 0)
460
 
    return 0;
461
 
 
462
 
  return error;
463
 
}
464
 
 
465
 
int StorageEngine::dropTable(Session& session,
466
 
                             StorageEngine &engine,
467
 
                             const TableIdentifier &identifier)
468
 
{
469
 
  int error;
470
 
 
471
 
  engine.setTransactionReadWrite(session);
472
 
  
473
 
  if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
474
 
  {
475
 
    error= ER_EVENT_OBSERVER_PLUGIN;
476
 
  }
477
 
  else
478
 
  {
479
 
    error= engine.doDropTable(session, identifier);
480
 
    if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
481
 
    {
482
 
      error= ER_EVENT_OBSERVER_PLUGIN;
483
 
    }
484
 
  }
485
 
 
486
 
 
487
 
  return error;
488
 
}
489
 
 
490
 
 
491
 
/**
492
 
  Initiates table-file and calls appropriate database-creator.
493
 
 
494
 
  @retval
495
 
   0  ok
496
 
  @retval
497
 
   1  error
498
 
*/
499
 
int StorageEngine::createTable(Session &session,
500
 
                               const TableIdentifier &identifier,
501
 
                               message::Table& table_message)
502
 
{
503
 
  int error= 1;
504
 
  Table table;
505
 
  TableShare share(identifier);
506
 
  message::Table tmp_proto;
507
 
 
508
 
  if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
509
 
  { 
510
 
    // @note Error occured, we should probably do a little more here.
511
 
  }
512
 
  else
513
 
  {
514
 
    /* Check for legal operations against the Engine using the proto (if used) */
515
 
    if (table_message.type() == message::Table::TEMPORARY &&
516
 
        share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
517
 
    {
518
 
      error= HA_ERR_UNSUPPORTED;
519
 
    }
520
 
    else if (table_message.type() != message::Table::TEMPORARY &&
521
 
             share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
522
 
    {
523
 
      error= HA_ERR_UNSUPPORTED;
524
 
    }
525
 
    else
526
 
    {
527
 
      share.storage_engine->setTransactionReadWrite(session);
528
 
 
529
 
      error= share.storage_engine->doCreateTable(session,
530
 
                                                 table,
531
 
                                                 identifier,
532
 
                                                 table_message);
533
 
    }
534
 
 
535
 
    if (error)
536
 
    {
537
 
      my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), const_cast<TableIdentifier &>(identifier).getSQLPath().c_str(), error);
538
 
    }
539
 
 
540
 
    table.delete_table();
541
 
  }
542
 
 
543
 
  return(error != 0);
544
 
}
545
 
 
546
 
Cursor *StorageEngine::getCursor(TableShare &share)
547
 
{
548
 
  return create(share);
549
 
}
550
 
 
551
 
class AddTableIdentifier : 
552
 
  public unary_function<StorageEngine *, void>
553
 
{
554
 
  CachedDirectory &directory;
555
 
  const SchemaIdentifier &identifier;
556
 
  TableIdentifiers &set_of_identifiers;
557
 
 
558
 
public:
559
 
 
560
 
  AddTableIdentifier(CachedDirectory &directory_arg, const SchemaIdentifier &identifier_arg, TableIdentifiers &of_names) :
561
 
    directory(directory_arg),
562
 
    identifier(identifier_arg),
563
 
    set_of_identifiers(of_names)
564
 
  {
565
 
  }
566
 
 
567
 
  result_type operator() (argument_type engine)
568
 
  {
569
 
    engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
570
 
  }
571
 
};
572
 
 
573
 
 
574
 
void StorageEngine::getIdentifiers(Session &session, const SchemaIdentifier &schema_identifier, TableIdentifiers &set_of_identifiers)
575
 
{
576
 
  static SchemaIdentifier INFORMATION_SCHEMA_IDENTIFIER("information_schema");
577
 
  static SchemaIdentifier DATA_DICTIONARY_IDENTIFIER("data_dictionary");
578
 
 
579
 
  CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
580
 
 
581
 
  if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
582
 
  { }
583
 
  else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
584
 
  { }
585
 
  else
586
 
  {
587
 
    if (directory.fail())
588
 
    {
589
 
      errno= directory.getError();
590
 
      if (errno == ENOENT)
591
 
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), const_cast<SchemaIdentifier &>(schema_identifier).getSQLPath().c_str());
592
 
      else
593
 
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
594
 
      return;
595
 
    }
596
 
  }
597
 
 
598
 
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
599
 
           AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
600
 
 
601
 
  session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
602
 
}
603
 
 
604
 
class DropTable: public unary_function<TableIdentifier&, bool>
605
 
{
606
 
  Session &session;
607
 
  StorageEngine *engine;
608
 
 
609
 
public:
610
 
 
611
 
  DropTable(Session &session_arg, StorageEngine *engine_arg) :
612
 
    session(session_arg),
613
 
    engine(engine_arg)
614
 
  { }
615
 
 
616
 
  result_type operator() (argument_type identifier)
617
 
  {
618
 
    return engine->doDropTable(session, identifier) == 0;
619
 
  } 
620
 
};
621
 
 
622
 
/* This will later be converted to TableIdentifiers */
623
 
class DropTables: public unary_function<StorageEngine *, void>
624
 
{
625
 
  Session &session;
626
 
  TableIdentifiers &table_identifiers;
627
 
 
628
 
public:
629
 
 
630
 
  DropTables(Session &session_arg, TableIdentifiers &table_identifiers_arg) :
631
 
    session(session_arg),
632
 
    table_identifiers(table_identifiers_arg)
633
 
  { }
634
 
 
635
 
  result_type operator() (argument_type engine)
636
 
  {
637
 
    // True returning from DropTable means the table has been successfully
638
 
    // deleted, so it should be removed from the list of tables to drop
639
 
    table_identifiers.erase(remove_if(table_identifiers.begin(),
640
 
                                      table_identifiers.end(),
641
 
                                      DropTable(session, engine)),
642
 
                            table_identifiers.end());
643
 
  }
644
 
};
645
 
 
646
 
/*
647
 
  This only works for engines which use file based DFE.
648
 
 
649
 
  Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
650
 
*/
651
 
void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
652
 
{
653
 
  CachedDirectory dir(directory, set_of_table_definition_ext);
654
 
  TableIdentifiers table_identifiers;
655
 
 
656
 
  if (dir.fail())
657
 
  {
658
 
    errno= dir.getError();
659
 
    my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
660
 
 
661
 
    return;
662
 
  }
663
 
 
664
 
  CachedDirectory::Entries files= dir.getEntries();
665
 
 
666
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
667
 
       fileIter != files.end(); fileIter++)
668
 
  {
669
 
    size_t length;
670
 
    string path;
671
 
    CachedDirectory::Entry *entry= *fileIter;
672
 
 
673
 
    /* We remove the file extension. */
674
 
    length= entry->filename.length();
675
 
    entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
676
 
 
677
 
    path+= directory;
678
 
    path+= FN_LIBCHAR;
679
 
    path+= entry->filename;
680
 
    message::Table definition;
681
 
    if (StorageEngine::readTableFile(path, definition))
682
 
    {
683
 
      TableIdentifier identifier(definition.schema(), definition.name(), path);
684
 
      table_identifiers.push_back(identifier);
685
 
    }
686
 
  }
687
 
 
688
 
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
689
 
           DropTables(session, table_identifiers));
690
 
  
691
 
  /*
692
 
    Now we just clean up anything that might left over.
693
 
 
694
 
    We rescan because some of what might have been there should
695
 
    now be all nice and cleaned up.
696
 
  */
697
 
  set<string> all_exts= set_of_table_definition_ext;
698
 
 
699
 
  for (EngineVector::iterator iter= vector_of_engines.begin();
700
 
       iter != vector_of_engines.end() ; iter++)
701
 
  {
702
 
    for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
703
 
      all_exts.insert(*ext);
704
 
  }
705
 
 
706
 
  CachedDirectory rescan(directory, all_exts);
707
 
 
708
 
  files= rescan.getEntries();
709
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
710
 
       fileIter != files.end(); fileIter++)
711
 
  {
712
 
    string path;
713
 
    CachedDirectory::Entry *entry= *fileIter;
714
 
 
715
 
    path+= directory;
716
 
    path+= FN_LIBCHAR;
717
 
    path+= entry->filename;
718
 
 
719
 
    unlink(path.c_str());
720
 
  }
721
 
}
722
 
 
723
 
 
724
 
/**
725
 
  Print error that we got from Cursor function.
726
 
 
727
 
  @note
728
 
    In case of delete table it's only safe to use the following parts of
729
 
    the 'table' structure:
730
 
    - table->getShare()->path
731
 
    - table->alias
732
 
*/
733
 
void StorageEngine::print_error(int error, myf errflag, Table &table)
734
 
{
735
 
  print_error(error, errflag, &table);
736
 
}
737
 
 
738
 
void StorageEngine::print_error(int error, myf errflag, Table *table)
739
 
{
740
 
  int textno= ER_GET_ERRNO;
741
 
  switch (error) {
742
 
  case EACCES:
743
 
    textno=ER_OPEN_AS_READONLY;
744
 
    break;
745
 
  case EAGAIN:
746
 
    textno=ER_FILE_USED;
747
 
    break;
748
 
  case ENOENT:
749
 
    textno=ER_FILE_NOT_FOUND;
750
 
    break;
751
 
  case HA_ERR_KEY_NOT_FOUND:
752
 
  case HA_ERR_NO_ACTIVE_RECORD:
753
 
  case HA_ERR_END_OF_FILE:
754
 
    textno=ER_KEY_NOT_FOUND;
755
 
    break;
756
 
  case HA_ERR_WRONG_MRG_TABLE_DEF:
757
 
    textno=ER_WRONG_MRG_TABLE;
758
 
    break;
759
 
  case HA_ERR_FOUND_DUPP_KEY:
760
 
  {
761
 
    assert(table);
762
 
    uint32_t key_nr= table->get_dup_key(error);
763
 
    if ((int) key_nr >= 0)
764
 
    {
765
 
      const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
766
 
 
767
 
      print_keydup_error(key_nr, err_msg, *table);
768
 
 
769
 
      return;
770
 
    }
771
 
    textno=ER_DUP_KEY;
772
 
    break;
773
 
  }
774
 
  case HA_ERR_FOREIGN_DUPLICATE_KEY:
775
 
  {
776
 
    assert(table);
777
 
    uint32_t key_nr= table->get_dup_key(error);
778
 
    if ((int) key_nr >= 0)
779
 
    {
780
 
      uint32_t max_length;
781
 
 
782
 
      /* Write the key in the error message */
783
 
      char key[MAX_KEY_LENGTH];
784
 
      String str(key,sizeof(key),system_charset_info);
785
 
 
786
 
      /* Table is opened and defined at this point */
787
 
      key_unpack(&str,table,(uint32_t) key_nr);
788
 
      max_length= (DRIZZLE_ERRMSG_SIZE-
789
 
                   (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
790
 
      if (str.length() >= max_length)
791
 
      {
792
 
        str.length(max_length-4);
793
 
        str.append(STRING_WITH_LEN("..."));
794
 
      }
795
 
      my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table->getShare()->getTableName(),
796
 
        str.c_ptr(), key_nr+1);
797
 
      return;
798
 
    }
799
 
    textno= ER_DUP_KEY;
800
 
    break;
801
 
  }
802
 
  case HA_ERR_FOUND_DUPP_UNIQUE:
803
 
    textno=ER_DUP_UNIQUE;
804
 
    break;
805
 
  case HA_ERR_RECORD_CHANGED:
806
 
    textno=ER_CHECKREAD;
807
 
    break;
808
 
  case HA_ERR_CRASHED:
809
 
    textno=ER_NOT_KEYFILE;
810
 
    break;
811
 
  case HA_ERR_WRONG_IN_RECORD:
812
 
    textno= ER_CRASHED_ON_USAGE;
813
 
    break;
814
 
  case HA_ERR_CRASHED_ON_USAGE:
815
 
    textno=ER_CRASHED_ON_USAGE;
816
 
    break;
817
 
  case HA_ERR_NOT_A_TABLE:
818
 
    textno= error;
819
 
    break;
820
 
  case HA_ERR_CRASHED_ON_REPAIR:
821
 
    textno=ER_CRASHED_ON_REPAIR;
822
 
    break;
823
 
  case HA_ERR_OUT_OF_MEM:
824
 
    textno=ER_OUT_OF_RESOURCES;
825
 
    break;
826
 
  case HA_ERR_WRONG_COMMAND:
827
 
    textno=ER_ILLEGAL_HA;
828
 
    break;
829
 
  case HA_ERR_OLD_FILE:
830
 
    textno=ER_OLD_KEYFILE;
831
 
    break;
832
 
  case HA_ERR_UNSUPPORTED:
833
 
    textno=ER_UNSUPPORTED_EXTENSION;
834
 
    break;
835
 
  case HA_ERR_RECORD_FILE_FULL:
836
 
  case HA_ERR_INDEX_FILE_FULL:
837
 
    textno=ER_RECORD_FILE_FULL;
838
 
    break;
839
 
  case HA_ERR_LOCK_WAIT_TIMEOUT:
840
 
    textno=ER_LOCK_WAIT_TIMEOUT;
841
 
    break;
842
 
  case HA_ERR_LOCK_TABLE_FULL:
843
 
    textno=ER_LOCK_TABLE_FULL;
844
 
    break;
845
 
  case HA_ERR_LOCK_DEADLOCK:
846
 
    textno=ER_LOCK_DEADLOCK;
847
 
    break;
848
 
  case HA_ERR_READ_ONLY_TRANSACTION:
849
 
    textno=ER_READ_ONLY_TRANSACTION;
850
 
    break;
851
 
  case HA_ERR_CANNOT_ADD_FOREIGN:
852
 
    textno=ER_CANNOT_ADD_FOREIGN;
853
 
    break;
854
 
  case HA_ERR_ROW_IS_REFERENCED:
855
 
  {
856
 
    String str;
857
 
    get_error_message(error, &str);
858
 
    my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
859
 
    return;
860
 
  }
861
 
  case HA_ERR_NO_REFERENCED_ROW:
862
 
  {
863
 
    String str;
864
 
    get_error_message(error, &str);
865
 
    my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
866
 
    return;
867
 
  }
868
 
  case HA_ERR_TABLE_DEF_CHANGED:
869
 
    textno=ER_TABLE_DEF_CHANGED;
870
 
    break;
871
 
  case HA_ERR_NO_SUCH_TABLE:
872
 
    assert(table);
873
 
    my_error(ER_NO_SUCH_TABLE, MYF(0), table->getShare()->getSchemaName(),
874
 
             table->getShare()->getTableName());
875
 
    return;
876
 
  case HA_ERR_RBR_LOGGING_FAILED:
877
 
    textno= ER_BINLOG_ROW_LOGGING_FAILED;
878
 
    break;
879
 
  case HA_ERR_DROP_INDEX_FK:
880
 
  {
881
 
    assert(table);
882
 
    const char *ptr= "???";
883
 
    uint32_t key_nr= table->get_dup_key(error);
884
 
    if ((int) key_nr >= 0)
885
 
      ptr= table->key_info[key_nr].name;
886
 
    my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
887
 
    return;
888
 
  }
889
 
  case HA_ERR_TABLE_NEEDS_UPGRADE:
890
 
    textno=ER_TABLE_NEEDS_UPGRADE;
891
 
    break;
892
 
  case HA_ERR_TABLE_READONLY:
893
 
    textno= ER_OPEN_AS_READONLY;
894
 
    break;
895
 
  case HA_ERR_AUTOINC_READ_FAILED:
896
 
    textno= ER_AUTOINC_READ_FAILED;
897
 
    break;
898
 
  case HA_ERR_AUTOINC_ERANGE:
899
 
    textno= ER_WARN_DATA_OUT_OF_RANGE;
900
 
    break;
901
 
  case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
902
 
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
903
 
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
904
 
    return;
905
 
  default:
906
 
    {
907
 
      /* 
908
 
        The error was "unknown" to this function.
909
 
        Ask Cursor if it has got a message for this error 
910
 
      */
911
 
      bool temporary= false;
912
 
      String str;
913
 
      temporary= get_error_message(error, &str);
914
 
      if (!str.is_empty())
915
 
      {
916
 
        const char* engine_name= getName().c_str();
917
 
        if (temporary)
918
 
          my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
919
 
                   engine_name);
920
 
        else
921
 
          my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
922
 
      }
923
 
      else
924
 
      {
925
 
              my_error(ER_GET_ERRNO,errflag,error);
926
 
      }
927
 
      return;
928
 
    }
929
 
  }
930
 
  my_error(textno, errflag, table->getShare()->getTableName(), error);
931
 
}
932
 
 
933
 
 
934
 
/**
935
 
  Return an error message specific to this Cursor.
936
 
 
937
 
  @param error  error code previously returned by Cursor
938
 
  @param buf    pointer to String where to add error message
939
 
 
940
 
  @return
941
 
    Returns true if this is a temporary error
942
 
*/
943
 
bool StorageEngine::get_error_message(int , String* )
944
 
{
945
 
  return false;
946
 
}
947
 
 
948
 
 
949
 
void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
950
 
{
951
 
  /* Write the duplicated key in the error message */
952
 
  char key[MAX_KEY_LENGTH];
953
 
  String str(key,sizeof(key),system_charset_info);
954
 
 
955
 
  if (key_nr == MAX_KEY)
956
 
  {
957
 
    /* Key is unknown */
958
 
    str.copy("", 0, system_charset_info);
959
 
    my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
960
 
  }
961
 
  else
962
 
  {
963
 
    /* Table is opened and defined at this point */
964
 
    key_unpack(&str, &table, (uint32_t) key_nr);
965
 
    uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
966
 
    if (str.length() >= max_length)
967
 
    {
968
 
      str.length(max_length-4);
969
 
      str.append(STRING_WITH_LEN("..."));
970
 
    }
971
 
    my_printf_error(ER_DUP_ENTRY, msg,
972
 
                    MYF(0), str.c_ptr(), table.key_info[key_nr].name);
973
 
  }
974
 
}
975
 
 
976
 
 
977
 
int StorageEngine::deleteDefinitionFromPath(const TableIdentifier &identifier)
978
 
{
979
 
  string path(identifier.getPath());
980
 
 
981
 
  path.append(DEFAULT_DEFINITION_FILE_EXT);
982
 
 
983
 
  return internal::my_delete(path.c_str(), MYF(0));
984
 
}
985
 
 
986
 
int StorageEngine::renameDefinitionFromPath(const TableIdentifier &dest, const TableIdentifier &src)
987
 
{
988
 
  message::Table table_message;
989
 
  string src_path(src.getPath());
990
 
  string dest_path(dest.getPath());
991
 
 
992
 
  src_path.append(DEFAULT_DEFINITION_FILE_EXT);
993
 
  dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
994
 
 
995
 
  bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
996
 
 
997
 
  if (not was_read)
998
 
  {
999
 
    return ENOENT;
1000
 
  }
1001
 
 
1002
 
  dest.copyToTableMessage(table_message);
1003
 
 
1004
 
  int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
1005
 
 
1006
 
  if (not error)
1007
 
  {
1008
 
    if (unlink(src_path.c_str()))
1009
 
      perror(src_path.c_str());
1010
 
  }
1011
 
 
1012
 
  return error;
1013
 
}
1014
 
 
1015
 
int StorageEngine::writeDefinitionFromPath(const TableIdentifier &identifier, message::Table &table_message)
1016
 
{
1017
 
  char definition_file_tmp[FN_REFLEN];
1018
 
  string file_name(identifier.getPath());
1019
 
 
1020
 
  file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1021
 
 
1022
 
  snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
1023
 
 
1024
 
  int fd= mkstemp(definition_file_tmp);
1025
 
 
1026
 
  if (fd == -1)
1027
 
  {
1028
 
    perror(definition_file_tmp);
1029
 
    return errno;
1030
 
  }
1031
 
 
1032
 
  google::protobuf::io::ZeroCopyOutputStream* output=
1033
 
    new google::protobuf::io::FileOutputStream(fd);
1034
 
 
1035
 
  bool success;
1036
 
 
1037
 
  try {
1038
 
    success= table_message.SerializeToZeroCopyStream(output);
1039
 
  }
1040
 
  catch (...)
1041
 
  {
1042
 
    success= false;
1043
 
  }
1044
 
 
1045
 
  if (not success)
1046
 
  {
1047
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1048
 
             table_message.InitializationErrorString().c_str());
1049
 
    delete output;
1050
 
 
1051
 
    if (close(fd) == -1)
1052
 
      perror(definition_file_tmp);
1053
 
 
1054
 
    if (unlink(definition_file_tmp) == -1)
1055
 
      perror(definition_file_tmp);
1056
 
 
1057
 
    return ER_CORRUPT_TABLE_DEFINITION;
1058
 
  }
1059
 
 
1060
 
  delete output;
1061
 
 
1062
 
  if (close(fd) == -1)
1063
 
  {
1064
 
    int error= errno;
1065
 
    perror(definition_file_tmp);
1066
 
 
1067
 
    if (unlink(definition_file_tmp))
1068
 
      perror(definition_file_tmp);
1069
 
 
1070
 
    return error;
1071
 
  }
1072
 
 
1073
 
  if (rename(definition_file_tmp, file_name.c_str()) == -1)
1074
 
  {
1075
 
    int error= errno;
1076
 
    perror(definition_file_tmp);
1077
 
 
1078
 
    if (unlink(definition_file_tmp))
1079
 
      perror(definition_file_tmp);
1080
 
 
1081
 
    return error;
1082
 
  }
1083
 
 
1084
 
  return 0;
1085
 
}
1086
 
 
1087
 
class CanCreateTable: public unary_function<StorageEngine *, bool>
1088
 
{
1089
 
  const TableIdentifier &identifier;
1090
 
 
1091
 
public:
1092
 
  CanCreateTable(const TableIdentifier &identifier_arg) :
1093
 
    identifier(identifier_arg)
1094
 
  { }
1095
 
 
1096
 
  result_type operator() (argument_type engine)
1097
 
  {
1098
 
    return not engine->doCanCreateTable(identifier);
1099
 
  }
1100
 
};
1101
 
 
1102
 
 
1103
 
/**
1104
 
  @note on success table can be created.
1105
 
*/
1106
 
bool StorageEngine::canCreateTable(const TableIdentifier &identifier)
1107
 
{
1108
 
  EngineVector::iterator iter=
1109
 
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
1110
 
            CanCreateTable(identifier));
1111
 
 
1112
 
  if (iter == vector_of_engines.end())
1113
 
  {
1114
 
    return true;
1115
 
  }
1116
 
 
1117
 
  return false;
1118
 
}
1119
 
 
1120
 
bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
1121
 
{
1122
 
  fstream input(path.c_str(), ios::in | ios::binary);
1123
 
 
1124
 
  if (input.good())
1125
 
  {
1126
 
    try {
1127
 
      if (table_message.ParseFromIstream(&input))
1128
 
      {
1129
 
        return true;
1130
 
      }
1131
 
    }
1132
 
    catch (...)
1133
 
    {
1134
 
      my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1135
 
               table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
1136
 
    }
1137
 
  }
1138
 
  else
1139
 
  {
1140
 
    perror(path.c_str());
1141
 
  }
1142
 
 
1143
 
  return false;
1144
 
}
1145
 
 
1146
 
 
1147
 
 
1148
 
} /* namespace plugin */
1149
 
} /* namespace drizzled */