~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

code clean move Item_func_ascii, Item_func_bit_count, Item_func_find_in_set, Item_func_ord  to functions directory

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, Inc.
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
 
 
53
 
#include <drizzled/table_proto.h>
54
 
#include <drizzled/plugin/event_observer.h>
55
 
#include <drizzled/internal_error_handler.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.
64
 
 
65
 
namespace drizzled
66
 
{
67
 
 
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)))
117
 
    {
118
 
      error= ER_EVENT_OBSERVER_PLUGIN;
119
 
    }
120
 
  }
121
 
  
122
 
  return error;
123
 
}
124
 
 
125
 
/**
126
 
  Delete all files with extension from bas_ext().
127
 
 
128
 
  @param name           Base name of table
129
 
 
130
 
  @note
131
 
    We assume that the Cursor may return more extensions than
132
 
    was actually used for the file.
133
 
 
134
 
  @retval
135
 
    0   If we successfully deleted at least one file from base_ext and
136
 
    didn't get any other errors than ENOENT
137
 
  @retval
138
 
    !0  Error
139
 
*/
140
 
int StorageEngine::doDropTable(Session&, const identifier::Table &identifier)
141
 
                               
142
 
{
143
 
  int error= 0;
144
 
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
145
 
  char buff[FN_REFLEN];
146
 
 
147
 
  for (const char **ext= bas_ext(); *ext ; ext++)
148
 
  {
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)))
152
 
    {
153
 
      if ((error= errno) != ENOENT)
154
 
        break;
155
 
    }
156
 
    else
157
 
    {
158
 
      enoent_or_zero= 0;                        // No error for ENOENT
159
 
    }
160
 
 
161
 
    error= enoent_or_zero;
162
 
  }
163
 
  return error;
164
 
}
165
 
 
166
 
bool StorageEngine::addPlugin(StorageEngine *engine)
167
 
{
168
 
 
169
 
  vector_of_engines.push_back(engine);
170
 
 
171
 
  if (engine->getTableDefinitionFileExtension().length())
172
 
  {
173
 
    assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
174
 
    set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
175
 
  }
176
 
 
177
 
  if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
178
 
    vector_of_schema_engines.push_back(engine);
179
 
 
180
 
  return false;
181
 
}
182
 
 
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>
245
 
{
246
 
  Session *session;
247
 
public:
248
 
  StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
249
 
  /*
250
 
    there's no need to rollback here as all transactions must
251
 
    be rolled back already
252
 
  */
253
 
  inline result_type operator() (argument_type engine)
254
 
  {
255
 
    if (*session->getEngineData(engine))
256
 
      engine->close_connection(session);
257
 
  }
258
 
};
259
 
 
260
 
/**
261
 
  @note
262
 
    don't bother to rollback here, it's done already
263
 
*/
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)
271
 
{
272
 
  if (engine == NULL)
273
 
  {
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())
277
 
      return true;
278
 
  }
279
 
  else
280
 
  {
281
 
    if (engine->flush_logs())
282
 
      return true;
283
 
  }
284
 
  return false;
285
 
}
286
 
 
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);
307
 
 
308
 
    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
 
message::table::shared_ptr StorageEngine::getTableMessage(Session& session,
365
 
                                                          identifier::Table::const_reference identifier,
366
 
                                                          bool include_temporary_tables)
367
 
{
368
 
  drizzled::error_t error;
369
 
  error= static_cast<drizzled::error_t>(ENOENT);
370
 
 
371
 
  if (include_temporary_tables)
372
 
  {
373
 
    Table *table= session.find_temporary_table(identifier);
374
 
    if (table)
375
 
    {
376
 
      return message::table::shared_ptr(new message::Table(*table->getShare()->getTableMessage()));
377
 
    }
378
 
  }
379
 
 
380
 
  drizzled::message::table::shared_ptr table_ptr;
381
 
  if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
382
 
  {
383
 
    (void)table_ptr;
384
 
  }
385
 
 
386
 
  message::Table message;
387
 
  EngineVector::iterator iter=
388
 
    std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
389
 
                 StorageEngineGetTableDefinition(session, identifier, message, error));
390
 
 
391
 
  if (iter == vector_of_engines.end())
392
 
  {
393
 
    return message::table::shared_ptr();
394
 
  }
395
 
  message::table::shared_ptr table_message(new message::Table(message));
396
 
 
397
 
  drizzled::message::Cache::singleton().insert(identifier, table_message);
398
 
 
399
 
  return table_message;
400
 
}
401
 
 
402
 
/**
403
 
  An interceptor to hijack the text of the error message without
404
 
  setting an error in the thread. We need the text to present it
405
 
  in the form of a warning to the user.
406
 
*/
407
 
 
408
 
class Ha_delete_table_error_handler: public Internal_error_handler
409
 
{
410
 
public:
411
 
  Ha_delete_table_error_handler() : Internal_error_handler() {}
412
 
  virtual bool handle_error(drizzled::error_t sql_errno,
413
 
                            const char *message,
414
 
                            DRIZZLE_ERROR::enum_warning_level level,
415
 
                            Session *session);
416
 
  char buff[DRIZZLE_ERRMSG_SIZE];
417
 
};
418
 
 
419
 
 
420
 
bool
421
 
Ha_delete_table_error_handler::
422
 
handle_error(drizzled::error_t ,
423
 
             const char *message,
424
 
             DRIZZLE_ERROR::enum_warning_level ,
425
 
             Session *)
426
 
{
427
 
  /* Grab the error message */
428
 
  strncpy(buff, message, sizeof(buff)-1);
429
 
  return true;
430
 
}
431
 
 
432
 
class DropTableByIdentifier: public std::unary_function<EngineVector::value_type, bool>
433
 
{
434
 
  Session::reference session;
435
 
  identifier::Table::const_reference identifier;
436
 
  drizzled::error_t &error;
437
 
 
438
 
public:
439
 
 
440
 
  DropTableByIdentifier(Session::reference session_arg,
441
 
                        identifier::Table::const_reference identifier_arg,
442
 
                        drizzled::error_t &error_arg) :
443
 
    session(session_arg),
444
 
    identifier(identifier_arg),
445
 
    error(error_arg)
446
 
  { }
447
 
 
448
 
  result_type operator() (argument_type engine)
449
 
  {
450
 
    if (not engine->doDoesTableExist(session, identifier))
451
 
      return false;
452
 
 
453
 
    int local_error= engine->doDropTable(session, identifier);
454
 
 
455
 
 
456
 
    if (not local_error)
457
 
      return true;
458
 
 
459
 
    switch (local_error)
460
 
    {
461
 
    case HA_ERR_NO_SUCH_TABLE:
462
 
    case ENOENT:
463
 
      error= static_cast<drizzled::error_t>(HA_ERR_NO_SUCH_TABLE);
464
 
      return false;
465
 
 
466
 
    default:
467
 
      error= static_cast<drizzled::error_t>(local_error);
468
 
      return true;
469
 
    }
470
 
  } 
471
 
};
472
 
 
473
 
 
474
 
bool StorageEngine::dropTable(Session::reference session,
475
 
                              identifier::Table::const_reference identifier,
476
 
                              drizzled::error_t &error)
477
 
{
478
 
  error= EE_OK;
479
 
 
480
 
  EngineVector::const_iterator iter= std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
481
 
                                                  DropTableByIdentifier(session, identifier, error));
482
 
 
483
 
  if (error)
484
 
  {
485
 
    return false;
486
 
  }
487
 
  else if (iter == vector_of_engines.end())
488
 
  {
489
 
    error= ER_BAD_TABLE_ERROR;
490
 
    return false;
491
 
  }
492
 
 
493
 
  drizzled::message::Cache::singleton().erase(identifier);
494
 
 
495
 
  return true;
496
 
}
497
 
 
498
 
bool StorageEngine::dropTable(Session& session,
499
 
                              const identifier::Table &identifier)
500
 
{
501
 
  drizzled::error_t error;
502
 
 
503
 
  if (not dropTable(session, identifier, error))
504
 
  {
505
 
    return false;
506
 
  }
507
 
 
508
 
  return true;
509
 
}
510
 
 
511
 
bool StorageEngine::dropTable(Session::reference session,
512
 
                              StorageEngine &engine,
513
 
                              identifier::Table::const_reference identifier,
514
 
                              drizzled::error_t &error)
515
 
{
516
 
  error= EE_OK;
517
 
  engine.setTransactionReadWrite(session);
518
 
 
519
 
  assert(identifier.isTmp());
520
 
  
521
 
  if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
522
 
  {
523
 
    error= ER_EVENT_OBSERVER_PLUGIN;
524
 
  }
525
 
  else
526
 
  {
527
 
    error= static_cast<drizzled::error_t>(engine.doDropTable(session, identifier));
528
 
 
529
 
    if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
530
 
    {
531
 
      error= ER_EVENT_OBSERVER_PLUGIN;
532
 
    }
533
 
  }
534
 
 
535
 
  drizzled::message::Cache::singleton().erase(identifier);
536
 
 
537
 
  if (error)
538
 
  {
539
 
    return false;
540
 
  }
541
 
 
542
 
  return true;
543
 
}
544
 
 
545
 
 
546
 
/**
547
 
  Initiates table-file and calls appropriate database-creator.
548
 
 
549
 
  @retval
550
 
   0  ok
551
 
  @retval
552
 
   1  error
553
 
*/
554
 
bool StorageEngine::createTable(Session &session,
555
 
                                const identifier::Table &identifier,
556
 
                                message::Table& table_message)
557
 
{
558
 
  drizzled::error_t error= EE_OK;
559
 
 
560
 
  TableShare share(identifier);
561
 
  table::Shell table(share);
562
 
  message::Table tmp_proto;
563
 
 
564
 
  if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
565
 
  { 
566
 
    // @note Error occured, we should probably do a little more here.
567
 
    // ER_CORRUPT_TABLE_DEFINITION,ER_CORRUPT_TABLE_DEFINITION_ENUM 
568
 
    
569
 
    my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
570
 
 
571
 
    return false;
572
 
  }
573
 
  else
574
 
  {
575
 
    /* Check for legal operations against the Engine using the proto (if used) */
576
 
    if (table_message.type() == message::Table::TEMPORARY &&
577
 
        share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
578
 
    {
579
 
      error= HA_ERR_UNSUPPORTED;
580
 
    }
581
 
    else if (table_message.type() != message::Table::TEMPORARY &&
582
 
             share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
583
 
    {
584
 
      error= HA_ERR_UNSUPPORTED;
585
 
    }
586
 
    else
587
 
    {
588
 
      share.storage_engine->setTransactionReadWrite(session);
589
 
 
590
 
      error= static_cast<drizzled::error_t>(share.storage_engine->doCreateTable(session,
591
 
                                                                                table,
592
 
                                                                                identifier,
593
 
                                                                                table_message));
594
 
    }
595
 
 
596
 
    if (error == ER_TABLE_PERMISSION_DENIED)
597
 
    {
598
 
      my_error(ER_TABLE_PERMISSION_DENIED, identifier);
599
 
    }
600
 
    else if (error)
601
 
    {
602
 
      std::string path;
603
 
      identifier.getSQLPath(path);
604
 
      my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), path.c_str(), error);
605
 
    }
606
 
 
607
 
    table.delete_table();
608
 
  }
609
 
 
610
 
  return(error == EE_OK);
611
 
}
612
 
 
613
 
Cursor *StorageEngine::getCursor(Table &arg)
614
 
{
615
 
  return create(arg);
616
 
}
617
 
 
618
 
class AddTableIdentifier : 
619
 
  public std::unary_function<StorageEngine *, void>
620
 
{
621
 
  CachedDirectory &directory;
622
 
  const identifier::Schema &identifier;
623
 
  identifier::Table::vector &set_of_identifiers;
624
 
 
625
 
public:
626
 
 
627
 
  AddTableIdentifier(CachedDirectory &directory_arg, const identifier::Schema &identifier_arg, identifier::Table::vector &of_names) :
628
 
    directory(directory_arg),
629
 
    identifier(identifier_arg),
630
 
    set_of_identifiers(of_names)
631
 
  {
632
 
  }
633
 
 
634
 
  result_type operator() (argument_type engine)
635
 
  {
636
 
    engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
637
 
  }
638
 
};
639
 
 
640
 
 
641
 
void StorageEngine::getIdentifiers(Session &session, const identifier::Schema &schema_identifier, identifier::Table::vector &set_of_identifiers)
642
 
{
643
 
  CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
644
 
 
645
 
  if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
646
 
  { }
647
 
  else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
648
 
  { }
649
 
  else
650
 
  {
651
 
    if (directory.fail())
652
 
    {
653
 
      errno= directory.getError();
654
 
      if (errno == ENOENT)
655
 
      {
656
 
        std::string path;
657
 
        schema_identifier.getSQLPath(path);
658
 
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), path.c_str());
659
 
      }
660
 
      else
661
 
      {
662
 
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
663
 
      }
664
 
 
665
 
      return;
666
 
    }
667
 
  }
668
 
 
669
 
  std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
670
 
                AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
671
 
 
672
 
  session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
673
 
}
674
 
 
675
 
class DropTable: public std::unary_function<identifier::Table&, bool>
676
 
{
677
 
  Session &session;
678
 
  StorageEngine *engine;
679
 
 
680
 
public:
681
 
 
682
 
  DropTable(Session &session_arg, StorageEngine *engine_arg) :
683
 
    session(session_arg),
684
 
    engine(engine_arg)
685
 
  { }
686
 
 
687
 
  result_type operator() (argument_type identifier)
688
 
  {
689
 
    return engine->doDropTable(session, identifier) == 0;
690
 
  } 
691
 
};
692
 
 
693
 
/* This will later be converted to identifier::Tables */
694
 
class DropTables: public std::unary_function<StorageEngine *, void>
695
 
{
696
 
  Session &session;
697
 
  identifier::Table::vector &table_identifiers;
698
 
 
699
 
public:
700
 
 
701
 
  DropTables(Session &session_arg, identifier::Table::vector &table_identifiers_arg) :
702
 
    session(session_arg),
703
 
    table_identifiers(table_identifiers_arg)
704
 
  { }
705
 
 
706
 
  result_type operator() (argument_type engine)
707
 
  {
708
 
    // True returning from DropTable means the table has been successfully
709
 
    // deleted, so it should be removed from the list of tables to drop
710
 
    table_identifiers.erase(std::remove_if(table_identifiers.begin(),
711
 
                                           table_identifiers.end(),
712
 
                                           DropTable(session, engine)),
713
 
                            table_identifiers.end());
714
 
  }
715
 
};
716
 
 
717
 
/*
718
 
  This only works for engines which use file based DFE.
719
 
 
720
 
  Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
721
 
*/
722
 
void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
723
 
{
724
 
  CachedDirectory dir(directory, set_of_table_definition_ext);
725
 
  identifier::Table::vector table_identifiers;
726
 
 
727
 
  if (dir.fail())
728
 
  {
729
 
    errno= dir.getError();
730
 
    my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
731
 
 
732
 
    return;
733
 
  }
734
 
 
735
 
  CachedDirectory::Entries files= dir.getEntries();
736
 
 
737
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
738
 
       fileIter != files.end(); fileIter++)
739
 
  {
740
 
    size_t length;
741
 
    std::string path;
742
 
    CachedDirectory::Entry *entry= *fileIter;
743
 
 
744
 
    /* We remove the file extension. */
745
 
    length= entry->filename.length();
746
 
    entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
747
 
 
748
 
    path+= directory;
749
 
    path+= FN_LIBCHAR;
750
 
    path+= entry->filename;
751
 
    message::Table definition;
752
 
    if (StorageEngine::readTableFile(path, definition))
753
 
    {
754
 
      identifier::Table identifier(definition.schema(), definition.name(), path);
755
 
      table_identifiers.push_back(identifier);
756
 
    }
757
 
  }
758
 
 
759
 
  std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
760
 
                DropTables(session, table_identifiers));
761
 
 
762
 
  /*
763
 
    Now we just clean up anything that might left over.
764
 
 
765
 
    We rescan because some of what might have been there should
766
 
    now be all nice and cleaned up.
767
 
  */
768
 
  std::set<std::string> all_exts= set_of_table_definition_ext;
769
 
 
770
 
  for (EngineVector::iterator iter= vector_of_engines.begin();
771
 
       iter != vector_of_engines.end() ; iter++)
772
 
  {
773
 
    for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
774
 
      all_exts.insert(*ext);
775
 
  }
776
 
 
777
 
  CachedDirectory rescan(directory, all_exts);
778
 
 
779
 
  files= rescan.getEntries();
780
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
781
 
       fileIter != files.end(); fileIter++)
782
 
  {
783
 
    std::string path;
784
 
    CachedDirectory::Entry *entry= *fileIter;
785
 
 
786
 
    path+= directory;
787
 
    path+= FN_LIBCHAR;
788
 
    path+= entry->filename;
789
 
 
790
 
    unlink(path.c_str());
791
 
  }
792
 
}
793
 
 
794
 
 
795
 
/**
796
 
  Print error that we got from Cursor function.
797
 
 
798
 
  @note
799
 
    In case of delete table it's only safe to use the following parts of
800
 
    the 'table' structure:
801
 
    - table->getShare()->path
802
 
    - table->alias
803
 
*/
804
 
void StorageEngine::print_error(int error, myf errflag, const Table &table) const
805
 
{
806
 
  drizzled::error_t textno= ER_GET_ERRNO;
807
 
  switch (error) {
808
 
  case EACCES:
809
 
    textno=ER_OPEN_AS_READONLY;
810
 
    break;
811
 
  case EAGAIN:
812
 
    textno=ER_FILE_USED;
813
 
    break;
814
 
  case ENOENT:
815
 
    textno=ER_FILE_NOT_FOUND;
816
 
    break;
817
 
  case HA_ERR_KEY_NOT_FOUND:
818
 
  case HA_ERR_NO_ACTIVE_RECORD:
819
 
  case HA_ERR_END_OF_FILE:
820
 
    textno=ER_KEY_NOT_FOUND;
821
 
    break;
822
 
  case HA_ERR_WRONG_MRG_TABLE_DEF:
823
 
    textno=ER_WRONG_MRG_TABLE;
824
 
    break;
825
 
  case HA_ERR_FOUND_DUPP_KEY:
826
 
  {
827
 
    uint32_t key_nr= table.get_dup_key(error);
828
 
    if ((int) key_nr >= 0)
829
 
    {
830
 
      const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
831
 
 
832
 
      print_keydup_error(key_nr, err_msg, table);
833
 
 
834
 
      return;
835
 
    }
836
 
    textno=ER_DUP_KEY;
837
 
    break;
838
 
  }
839
 
  case HA_ERR_FOREIGN_DUPLICATE_KEY:
840
 
  {
841
 
    uint32_t key_nr= table.get_dup_key(error);
842
 
    if ((int) key_nr >= 0)
843
 
    {
844
 
      uint32_t max_length;
845
 
 
846
 
      /* Write the key in the error message */
847
 
      char key[MAX_KEY_LENGTH];
848
 
      String str(key,sizeof(key),system_charset_info);
849
 
 
850
 
      /* Table is opened and defined at this point */
851
 
      key_unpack(&str, &table,(uint32_t) key_nr);
852
 
      max_length= (DRIZZLE_ERRMSG_SIZE-
853
 
                   (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
854
 
      if (str.length() >= max_length)
855
 
      {
856
 
        str.length(max_length-4);
857
 
        str.append(STRING_WITH_LEN("..."));
858
 
      }
859
 
      my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
860
 
        str.c_ptr(), key_nr+1);
861
 
      return;
862
 
    }
863
 
    textno= ER_DUP_KEY;
864
 
    break;
865
 
  }
866
 
  case HA_ERR_FOUND_DUPP_UNIQUE:
867
 
    textno=ER_DUP_UNIQUE;
868
 
    break;
869
 
  case HA_ERR_RECORD_CHANGED:
870
 
    textno=ER_CHECKREAD;
871
 
    break;
872
 
  case HA_ERR_CRASHED:
873
 
    textno=ER_NOT_KEYFILE;
874
 
    break;
875
 
  case HA_ERR_WRONG_IN_RECORD:
876
 
    textno= ER_CRASHED_ON_USAGE;
877
 
    break;
878
 
  case HA_ERR_CRASHED_ON_USAGE:
879
 
    textno=ER_CRASHED_ON_USAGE;
880
 
    break;
881
 
  case HA_ERR_NOT_A_TABLE:
882
 
    textno= static_cast<drizzled::error_t>(error);
883
 
    break;
884
 
  case HA_ERR_CRASHED_ON_REPAIR:
885
 
    textno=ER_CRASHED_ON_REPAIR;
886
 
    break;
887
 
  case HA_ERR_OUT_OF_MEM:
888
 
    textno=ER_OUT_OF_RESOURCES;
889
 
    break;
890
 
  case HA_ERR_WRONG_COMMAND:
891
 
    textno=ER_ILLEGAL_HA;
892
 
    break;
893
 
  case HA_ERR_OLD_FILE:
894
 
    textno=ER_OLD_KEYFILE;
895
 
    break;
896
 
  case HA_ERR_UNSUPPORTED:
897
 
    textno=ER_UNSUPPORTED_EXTENSION;
898
 
    break;
899
 
  case HA_ERR_RECORD_FILE_FULL:
900
 
  case HA_ERR_INDEX_FILE_FULL:
901
 
    textno=ER_RECORD_FILE_FULL;
902
 
    break;
903
 
  case HA_ERR_LOCK_WAIT_TIMEOUT:
904
 
    textno=ER_LOCK_WAIT_TIMEOUT;
905
 
    break;
906
 
  case HA_ERR_LOCK_TABLE_FULL:
907
 
    textno=ER_LOCK_TABLE_FULL;
908
 
    break;
909
 
  case HA_ERR_LOCK_DEADLOCK:
910
 
    textno=ER_LOCK_DEADLOCK;
911
 
    break;
912
 
  case HA_ERR_READ_ONLY_TRANSACTION:
913
 
    textno=ER_READ_ONLY_TRANSACTION;
914
 
    break;
915
 
  case HA_ERR_CANNOT_ADD_FOREIGN:
916
 
    textno=ER_CANNOT_ADD_FOREIGN;
917
 
    break;
918
 
  case HA_ERR_ROW_IS_REFERENCED:
919
 
  {
920
 
    String str;
921
 
    get_error_message(error, &str);
922
 
    my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
923
 
    return;
924
 
  }
925
 
  case HA_ERR_NO_REFERENCED_ROW:
926
 
  {
927
 
    String str;
928
 
    get_error_message(error, &str);
929
 
    my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
930
 
    return;
931
 
  }
932
 
  case HA_ERR_TABLE_DEF_CHANGED:
933
 
    textno=ER_TABLE_DEF_CHANGED;
934
 
    break;
935
 
  case HA_ERR_NO_SUCH_TABLE:
936
 
    {
937
 
      identifier::Table identifier(table.getShare()->getSchemaName(), table.getShare()->getTableName());
938
 
      my_error(ER_TABLE_UNKNOWN, identifier);
939
 
      return;
940
 
    }
941
 
  case HA_ERR_RBR_LOGGING_FAILED:
942
 
    textno= ER_BINLOG_ROW_LOGGING_FAILED;
943
 
    break;
944
 
  case HA_ERR_DROP_INDEX_FK:
945
 
  {
946
 
    const char *ptr= "???";
947
 
    uint32_t key_nr= table.get_dup_key(error);
948
 
    if ((int) key_nr >= 0)
949
 
      ptr= table.key_info[key_nr].name;
950
 
    my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
951
 
    return;
952
 
  }
953
 
  case HA_ERR_TABLE_NEEDS_UPGRADE:
954
 
    textno=ER_TABLE_NEEDS_UPGRADE;
955
 
    break;
956
 
  case HA_ERR_TABLE_READONLY:
957
 
    textno= ER_OPEN_AS_READONLY;
958
 
    break;
959
 
  case HA_ERR_AUTOINC_READ_FAILED:
960
 
    textno= ER_AUTOINC_READ_FAILED;
961
 
    break;
962
 
  case HA_ERR_AUTOINC_ERANGE:
963
 
    textno= ER_WARN_DATA_OUT_OF_RANGE;
964
 
    break;
965
 
  case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
966
 
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
967
 
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
968
 
    return;
969
 
  default:
970
 
    {
971
 
      /* 
972
 
        The error was "unknown" to this function.
973
 
        Ask Cursor if it has got a message for this error 
974
 
      */
975
 
      bool temporary= false;
976
 
      String str;
977
 
      temporary= get_error_message(error, &str);
978
 
      if (!str.is_empty())
979
 
      {
980
 
        const char* engine_name= getName().c_str();
981
 
        if (temporary)
982
 
          my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
983
 
                   engine_name);
984
 
        else
985
 
          my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
986
 
      }
987
 
      else
988
 
      {
989
 
              my_error(ER_GET_ERRNO,errflag,error);
990
 
      }
991
 
      return;
992
 
    }
993
 
  }
994
 
 
995
 
  my_error(textno, errflag, table.getShare()->getTableName(), error);
996
 
}
997
 
 
998
 
 
999
 
/**
1000
 
  Return an error message specific to this Cursor.
1001
 
 
1002
 
  @param error  error code previously returned by Cursor
1003
 
  @param buf    pointer to String where to add error message
1004
 
 
1005
 
  @return
1006
 
    Returns true if this is a temporary error
1007
 
*/
1008
 
bool StorageEngine::get_error_message(int , String* ) const
1009
 
{
1010
 
  return false;
1011
 
}
1012
 
 
1013
 
 
1014
 
void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, const Table &table) const
1015
 
{
1016
 
  /* Write the duplicated key in the error message */
1017
 
  char key[MAX_KEY_LENGTH];
1018
 
  String str(key,sizeof(key),system_charset_info);
1019
 
 
1020
 
  if (key_nr == MAX_KEY)
1021
 
  {
1022
 
    /* Key is unknown */
1023
 
    str.copy("", 0, system_charset_info);
1024
 
    my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
1025
 
  }
1026
 
  else
1027
 
  {
1028
 
    /* Table is opened and defined at this point */
1029
 
    key_unpack(&str, &table, (uint32_t) key_nr);
1030
 
    uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
1031
 
    if (str.length() >= max_length)
1032
 
    {
1033
 
      str.length(max_length-4);
1034
 
      str.append(STRING_WITH_LEN("..."));
1035
 
    }
1036
 
    my_printf_error(ER_DUP_ENTRY, msg,
1037
 
                    MYF(0), str.c_ptr(), table.key_info[key_nr].name);
1038
 
  }
1039
 
}
1040
 
 
1041
 
 
1042
 
int StorageEngine::deleteDefinitionFromPath(const identifier::Table &identifier)
1043
 
{
1044
 
  std::string path(identifier.getPath());
1045
 
 
1046
 
  path.append(DEFAULT_DEFINITION_FILE_EXT);
1047
 
 
1048
 
  return internal::my_delete(path.c_str(), MYF(0));
1049
 
}
1050
 
 
1051
 
int StorageEngine::renameDefinitionFromPath(const identifier::Table &dest, const identifier::Table &src)
1052
 
{
1053
 
  message::Table table_message;
1054
 
  std::string src_path(src.getPath());
1055
 
  std::string dest_path(dest.getPath());
1056
 
 
1057
 
  src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1058
 
  dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1059
 
 
1060
 
  bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
1061
 
 
1062
 
  if (not was_read)
1063
 
  {
1064
 
    return ENOENT;
1065
 
  }
1066
 
 
1067
 
  dest.copyToTableMessage(table_message);
1068
 
 
1069
 
  int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
1070
 
 
1071
 
  if (not error)
1072
 
  {
1073
 
    if (unlink(src_path.c_str()))
1074
 
      perror(src_path.c_str());
1075
 
  }
1076
 
 
1077
 
  return error;
1078
 
}
1079
 
 
1080
 
int StorageEngine::writeDefinitionFromPath(const identifier::Table &identifier, message::Table &table_message)
1081
 
{
1082
 
  char definition_file_tmp[FN_REFLEN];
1083
 
  std::string file_name(identifier.getPath());
1084
 
 
1085
 
  file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1086
 
 
1087
 
  snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
1088
 
 
1089
 
  int fd= mkstemp(definition_file_tmp);
1090
 
 
1091
 
  if (fd == -1)
1092
 
  {
1093
 
    perror(definition_file_tmp);
1094
 
    return errno;
1095
 
  }
1096
 
 
1097
 
  google::protobuf::io::ZeroCopyOutputStream* output=
1098
 
    new google::protobuf::io::FileOutputStream(fd);
1099
 
 
1100
 
  bool success;
1101
 
 
1102
 
  try
1103
 
  {
1104
 
    success= table_message.SerializeToZeroCopyStream(output);
1105
 
  }
1106
 
  catch (...)
1107
 
  {
1108
 
    success= false;
1109
 
  }
1110
 
 
1111
 
  if (not success)
1112
 
  {
1113
 
    std::string error_message;
1114
 
    identifier.getSQLPath(error_message);
1115
 
 
1116
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1117
 
             error_message.c_str(),
1118
 
             table_message.InitializationErrorString().c_str());
1119
 
    delete output;
1120
 
 
1121
 
    if (close(fd) == -1)
1122
 
      perror(definition_file_tmp);
1123
 
 
1124
 
    if (unlink(definition_file_tmp) == -1)
1125
 
      perror(definition_file_tmp);
1126
 
 
1127
 
    return ER_CORRUPT_TABLE_DEFINITION;
1128
 
  }
1129
 
 
1130
 
  delete output;
1131
 
 
1132
 
  if (close(fd) == -1)
1133
 
  {
1134
 
    int error= errno;
1135
 
    perror(definition_file_tmp);
1136
 
 
1137
 
    if (unlink(definition_file_tmp))
1138
 
      perror(definition_file_tmp);
1139
 
 
1140
 
    return error;
1141
 
  }
1142
 
 
1143
 
  if (rename(definition_file_tmp, file_name.c_str()) == -1)
1144
 
  {
1145
 
    int error= errno;
1146
 
    perror(definition_file_tmp);
1147
 
 
1148
 
    if (unlink(definition_file_tmp))
1149
 
      perror(definition_file_tmp);
1150
 
 
1151
 
    return error;
1152
 
  }
1153
 
 
1154
 
  return 0;
1155
 
}
1156
 
 
1157
 
class CanCreateTable: public std::unary_function<StorageEngine *, bool>
1158
 
{
1159
 
  const identifier::Table &identifier;
1160
 
 
1161
 
public:
1162
 
  CanCreateTable(const identifier::Table &identifier_arg) :
1163
 
    identifier(identifier_arg)
1164
 
  { }
1165
 
 
1166
 
  result_type operator() (argument_type engine)
1167
 
  {
1168
 
    return not engine->doCanCreateTable(identifier);
1169
 
  }
1170
 
};
1171
 
 
1172
 
 
1173
 
/**
1174
 
  @note on success table can be created.
1175
 
*/
1176
 
bool StorageEngine::canCreateTable(const identifier::Table &identifier)
1177
 
{
1178
 
  EngineVector::iterator iter=
1179
 
    std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
1180
 
                 CanCreateTable(identifier));
1181
 
 
1182
 
  if (iter == vector_of_engines.end())
1183
 
  {
1184
 
    return true;
1185
 
  }
1186
 
 
1187
 
  return false;
1188
 
}
1189
 
 
1190
 
bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
1191
 
{
1192
 
  std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
1193
 
 
1194
 
  if (input.good())
1195
 
  {
1196
 
    try {
1197
 
      if (table_message.ParseFromIstream(&input))
1198
 
      {
1199
 
        return true;
1200
 
      }
1201
 
    }
1202
 
    catch (...)
1203
 
    {
1204
 
      my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1205
 
               table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
1206
 
               table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
1207
 
    }
1208
 
  }
1209
 
  else
1210
 
  {
1211
 
    perror(path.c_str());
1212
 
  }
1213
 
 
1214
 
  return false;
1215
 
}
1216
 
 
1217
 
std::ostream& operator<<(std::ostream& output, const StorageEngine &engine)
1218
 
{
1219
 
  output << "StorageEngine:(";
1220
 
  output <<  engine.getName();
1221
 
  output << ")";
1222
 
 
1223
 
  return output;
1224
 
}
1225
 
 
1226
 
} /* namespace plugin */
1227
 
} /* namespace drizzled */