Drizzled Public API Documentation

storage_engine.cc
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 
36 #include <drizzled/definitions.h>
37 #include <drizzled/base.h>
38 #include <drizzled/cursor.h>
39 #include <drizzled/plugin/storage_engine.h>
40 #include <drizzled/session.h>
41 #include <drizzled/error.h>
42 #include <drizzled/gettext.h>
43 #include <drizzled/data_home.h>
44 #include <drizzled/errmsg_print.h>
45 #include <drizzled/xid.h>
46 #include <drizzled/sql_table.h>
47 #include <drizzled/charset.h>
48 #include <drizzled/internal/my_sys.h>
49 #include <drizzled/table_proto.h>
50 #include <drizzled/plugin/event_observer.h>
51 #include <drizzled/table/shell.h>
52 #include <drizzled/message/cache.h>
53 #include <drizzled/key.h>
54 #include <drizzled/session/transactions.h>
55 #include <drizzled/open_tables_state.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 namespace drizzled {
62 namespace plugin {
63 
64 static EngineVector g_engines;
65 static EngineVector g_schema_engines;
66 
67 const std::string DEFAULT_STRING("default");
68 const std::string UNKNOWN_STRING("UNKNOWN");
69 const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
70 
71 static std::set<std::string> set_of_table_definition_ext;
72 
73 EngineVector &StorageEngine::getSchemaEngines()
74 {
75  return g_schema_engines;
76 }
77 
78 StorageEngine::StorageEngine(const std::string &name_arg,
79  const std::bitset<HTON_BIT_SIZE> &flags_arg) :
80  Plugin(name_arg, "StorageEngine"),
81  MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
82  flags(flags_arg)
83 {
84 }
85 
86 StorageEngine::~StorageEngine()
87 {
88 }
89 
90 void StorageEngine::setTransactionReadWrite(Session& session)
91 {
92  TransactionContext &statement_ctx= session.transaction.stmt;
93  statement_ctx.markModifiedNonTransData();
94 }
95 
96 int StorageEngine::renameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
97 {
98  setTransactionReadWrite(session);
99  if (unlikely(plugin::EventObserver::beforeRenameTable(session, from, to)))
100  return ER_EVENT_OBSERVER_PLUGIN;
101  int error= doRenameTable(session, from, to);
102  if (unlikely(plugin::EventObserver::afterRenameTable(session, from, to, error)))
103  error= ER_EVENT_OBSERVER_PLUGIN;
104  return error;
105 }
106 
123 {
124  int error= 0;
125  int enoent_or_zero= ENOENT; // Error if no file was deleted
126  char buff[FN_REFLEN];
127 
128  for (const char **ext= bas_ext(); *ext ; ext++)
129  {
130  internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
131  MY_UNPACK_FILENAME|MY_APPEND_EXT);
132  if (internal::my_delete_with_symlink(buff, MYF(0)))
133  {
134  if ((error= errno) != ENOENT)
135  break;
136  }
137  else
138  {
139  enoent_or_zero= 0; // No error for ENOENT
140  }
141 
142  error= enoent_or_zero;
143  }
144  return error;
145 }
146 
147 bool StorageEngine::addPlugin(StorageEngine *engine)
148 {
149  g_engines.push_back(engine);
150 
151  if (engine->getTableDefinitionFileExtension().length())
152  {
153  assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
154  set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
155  }
156 
157  if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
158  g_schema_engines.push_back(engine);
159 
160  return false;
161 }
162 
163 void StorageEngine::removePlugin(StorageEngine *)
164 {
165  if (shutdown_has_begun)
166  return;
167  shutdown_has_begun= true;
168  g_engines.clear();
169  g_schema_engines.clear();
170 }
171 
172 StorageEngine *StorageEngine::findByName(const std::string &predicate)
173 {
174  BOOST_FOREACH(EngineVector::reference it, g_engines)
175  {
176  if (not boost::iequals(it->getName(), predicate))
177  continue;
178  if (it->is_user_selectable())
179  return it;
180  break;
181  }
182  return NULL;
183 }
184 
185 StorageEngine *StorageEngine::findByName(Session& session, const std::string &predicate)
186 {
187  if (boost::iequals(predicate, DEFAULT_STRING))
188  return session.getDefaultStorageEngine();
189  return findByName(predicate);
190 }
191 
197 {
198  BOOST_FOREACH(EngineVector::reference it, g_engines)
199  {
200  if (*session.getEngineData(it))
201  it->close_connection(&session);
202  }
203 }
204 
205 bool StorageEngine::flushLogs(StorageEngine *engine)
206 {
207  if (not engine)
208  {
209  if (std::find_if(g_engines.begin(), g_engines.end(), std::mem_fun(&StorageEngine::flush_logs))
210  != g_engines.begin()) // Shouldn't this be .end()?
211  return true;
212  }
213  else if (engine->flush_logs())
214  return true;
215  return false;
216 }
217 
218 class StorageEngineGetTableDefinition: public std::unary_function<StorageEngine *,bool>
219 {
220  Session& session;
221  const identifier::Table &identifier;
222  message::Table &table_message;
223  drizzled::error_t &err;
224 
225 public:
227  const identifier::Table &identifier_arg,
228  message::Table &table_message_arg,
229  drizzled::error_t &err_arg) :
230  session(session_arg),
231  identifier(identifier_arg),
232  table_message(table_message_arg),
233  err(err_arg) {}
234 
235  result_type operator() (argument_type engine)
236  {
237  int ret= engine->doGetTableDefinition(session, identifier, table_message);
238 
239  if (ret != ENOENT)
240  err= static_cast<drizzled::error_t>(ret);
241 
242  return err == static_cast<drizzled::error_t>(EEXIST) or err != static_cast<drizzled::error_t>(ENOENT);
243  }
244 };
245 
250  const identifier::Table &identifier,
251  bool include_temporary_tables)
252 {
253  if (include_temporary_tables && session.open_tables.doDoesTableExist(identifier))
254  return true;
255  BOOST_FOREACH(EngineVector::reference it, g_engines)
256  {
257  if (it->doDoesTableExist(session, identifier))
258  return true;
259  }
260  return false;
261 }
262 
263 bool plugin::StorageEngine::doDoesTableExist(Session&, const drizzled::identifier::Table&)
264 {
265  std::cerr << " Engine was called for doDoesTableExist() and does not implement it: " << getName() << "\n";
266  assert(0);
267  return false;
268 }
269 
270 message::table::shared_ptr StorageEngine::getTableMessage(Session& session,
271  const identifier::Table& identifier,
272  bool include_temporary_tables)
273 {
274  drizzled::error_t error= static_cast<drizzled::error_t>(ENOENT);
275  if (include_temporary_tables)
276  {
277  if (Table *table= session.open_tables.find_temporary_table(identifier))
278  {
279  return message::table::shared_ptr(new message::Table(*table->getShare()->getTableMessage()));
280  }
281  }
282 
283  drizzled::message::table::shared_ptr table_ptr;
284  if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
285  {
286  (void)table_ptr;
287  }
288 
289  message::Table message;
290  EngineVector::iterator iter= std::find_if(g_engines.begin(), g_engines.end(),
291  StorageEngineGetTableDefinition(session, identifier, message, error));
292 
293  if (iter == g_engines.end())
294  {
295  return message::table::shared_ptr();
296  }
297  message::table::shared_ptr table_message(new message::Table(message));
298 
299  drizzled::message::Cache::singleton().insert(identifier, table_message);
300 
301  return table_message;
302 }
303 
304 class DropTableByIdentifier: public std::unary_function<EngineVector::value_type, bool>
305 {
306  Session& session;
307  const identifier::Table& identifier;
308  drizzled::error_t &error;
309 
310 public:
311 
312  DropTableByIdentifier(Session& session_arg,
313  const identifier::Table& identifier_arg,
314  drizzled::error_t &error_arg) :
315  session(session_arg),
316  identifier(identifier_arg),
317  error(error_arg)
318  { }
319 
320  result_type operator() (argument_type engine)
321  {
322  if (not engine->doDoesTableExist(session, identifier))
323  return false;
324 
325  int local_error= engine->doDropTable(session, identifier);
326 
327 
328  if (not local_error)
329  return true;
330 
331  switch (local_error)
332  {
333  case HA_ERR_NO_SUCH_TABLE:
334  case ENOENT:
335  error= static_cast<drizzled::error_t>(HA_ERR_NO_SUCH_TABLE);
336  return false;
337 
338  default:
339  error= static_cast<drizzled::error_t>(local_error);
340  return true;
341  }
342  }
343 };
344 
345 
346 bool StorageEngine::dropTable(Session& session,
347  const identifier::Table& identifier,
348  drizzled::error_t &error)
349 {
350  error= EE_OK;
351 
352  EngineVector::const_iterator iter= std::find_if(g_engines.begin(), g_engines.end(),
353  DropTableByIdentifier(session, identifier, error));
354 
355  if (error)
356  {
357  return false;
358  }
359  else if (iter == g_engines.end())
360  {
361  error= ER_BAD_TABLE_ERROR;
362  return false;
363  }
364 
365  drizzled::message::Cache::singleton().erase(identifier);
366 
367  return true;
368 }
369 
370 bool StorageEngine::dropTable(Session& session,
371  const identifier::Table &identifier)
372 {
373  drizzled::error_t error;
374  return dropTable(session, identifier, error);
375 }
376 
377 bool StorageEngine::dropTable(Session& session,
378  StorageEngine &engine,
379  const identifier::Table& identifier,
380  drizzled::error_t &error)
381 {
382  error= EE_OK;
383  engine.setTransactionReadWrite(session);
384 
385  assert(identifier.isTmp());
386 
387  if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
388  {
389  error= ER_EVENT_OBSERVER_PLUGIN;
390  }
391  else
392  {
393  error= static_cast<drizzled::error_t>(engine.doDropTable(session, identifier));
394 
395  if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
396  {
397  error= ER_EVENT_OBSERVER_PLUGIN;
398  }
399  }
400  drizzled::message::Cache::singleton().erase(identifier);
401  return not error;
402 }
403 
404 
414  const identifier::Table &identifier,
415  message::Table& table_message)
416 {
417  drizzled::error_t error= EE_OK;
418 
419  TableShare share(identifier);
420  table::Shell table(share);
421  message::Table tmp_proto;
422 
423  if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
424  {
425  // @note Error occured, we should probably do a little more here.
426  // ER_CORRUPT_TABLE_DEFINITION,ER_CORRUPT_TABLE_DEFINITION_ENUM
427 
428  my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
429 
430  return false;
431  }
432  else
433  {
434  /* Check for legal operations against the Engine using the proto (if used) */
435  if (table_message.type() == message::Table::TEMPORARY &&
436  share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
437  {
438  error= HA_ERR_UNSUPPORTED;
439  }
440  else if (table_message.type() != message::Table::TEMPORARY &&
441  share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
442  {
443  error= HA_ERR_UNSUPPORTED;
444  }
445  else
446  {
447  share.storage_engine->setTransactionReadWrite(session);
448 
449  error= static_cast<drizzled::error_t>(share.storage_engine->doCreateTable(session,
450  table,
451  identifier,
452  table_message));
453  }
454 
455  if (error == ER_TABLE_PERMISSION_DENIED)
456  my_error(ER_TABLE_PERMISSION_DENIED, identifier);
457  else if (error)
458  my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), identifier.getSQLPath().c_str(), error);
459  table.delete_table();
460  }
461  return(error == EE_OK);
462 }
463 
464 Cursor *StorageEngine::getCursor(Table &arg)
465 {
466  return create(arg);
467 }
468 
469 void StorageEngine::getIdentifiers(Session &session, const identifier::Schema &schema_identifier, identifier::table::vector &set_of_identifiers)
470 {
471  CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
472 
473  if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
474  {
475  }
476  else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
477  {
478  }
479  else if (directory.fail())
480  {
481  errno= directory.getError();
482  if (errno == ENOENT)
483  my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
484  else
485  my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
486  return;
487  }
488 
489  BOOST_FOREACH(EngineVector::reference it, g_engines)
490  it->doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
491 
492  session.open_tables.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
493 }
494 
495 class DropTable: public std::unary_function<identifier::Table&, bool>
496 {
497  Session &session;
498  StorageEngine *engine;
499 
500 public:
501 
502  DropTable(Session &session_arg, StorageEngine *engine_arg) :
503  session(session_arg),
504  engine(engine_arg)
505  { }
506 
507  result_type operator() (argument_type identifier)
508  {
509  return engine->doDropTable(session, identifier) == 0;
510  }
511 };
512 
513 /*
514  This only works for engines which use file based DFE.
515 
516  Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines.
517 */
518 void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
519 {
520  CachedDirectory dir(directory, set_of_table_definition_ext);
521  identifier::table::vector table_identifiers;
522 
523  if (dir.fail())
524  {
525  errno= dir.getError();
526  my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
527 
528  return;
529  }
530 
531  CachedDirectory::Entries files= dir.getEntries();
532 
533  for (CachedDirectory::Entries::iterator fileIter= files.begin();
534  fileIter != files.end(); fileIter++)
535  {
536  size_t length;
537  std::string path;
538  CachedDirectory::Entry *entry= *fileIter;
539 
540  /* We remove the file extension. */
541  length= entry->filename.length();
542  entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
543 
544  path+= directory;
545  path+= FN_LIBCHAR;
546  path+= entry->filename;
547  message::Table definition;
548  if (StorageEngine::readTableFile(path, definition))
549  {
550  identifier::Table identifier(identifier::Catalog(definition.catalog()),
551  definition.schema(),
552  definition.name(),
553  path);
554  table_identifiers.push_back(identifier);
555  }
556  }
557 
558  BOOST_FOREACH(EngineVector::reference it, g_engines)
559  {
560  table_identifiers.erase(std::remove_if(table_identifiers.begin(), table_identifiers.end(), DropTable(session, it)),
561  table_identifiers.end());
562  }
563 
564  /*
565  Now we just clean up anything that might left over.
566 
567  We rescan because some of what might have been there should
568  now be all nice and cleaned up.
569  */
570  std::set<std::string> all_exts= set_of_table_definition_ext;
571 
572  for (EngineVector::iterator iter= g_engines.begin();
573  iter != g_engines.end() ; iter++)
574  {
575  for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
576  all_exts.insert(*ext);
577  }
578 
579  CachedDirectory rescan(directory, all_exts);
580 
581  files= rescan.getEntries();
582  for (CachedDirectory::Entries::iterator fileIter= files.begin();
583  fileIter != files.end(); fileIter++)
584  {
585  std::string path;
586  CachedDirectory::Entry *entry= *fileIter;
587 
588  path+= directory;
589  path+= FN_LIBCHAR;
590  path+= entry->filename;
591 
592  unlink(path.c_str());
593  }
594 }
595 
596 
606 void StorageEngine::print_error(int error, myf errflag, const Table &table) const
607 {
608  drizzled::error_t textno= ER_GET_ERRNO;
609  switch (error) {
610  case EACCES:
611  textno=ER_OPEN_AS_READONLY;
612  break;
613  case EAGAIN:
614  textno=ER_FILE_USED;
615  break;
616  case ENOENT:
617  textno=ER_FILE_NOT_FOUND;
618  break;
619  case HA_ERR_KEY_NOT_FOUND:
620  case HA_ERR_NO_ACTIVE_RECORD:
621  case HA_ERR_END_OF_FILE:
622  textno=ER_KEY_NOT_FOUND;
623  break;
624  case HA_ERR_WRONG_MRG_TABLE_DEF:
625  textno=ER_WRONG_MRG_TABLE;
626  break;
627  case HA_ERR_FOUND_DUPP_KEY:
628  {
629  uint32_t key_nr= table.get_dup_key(error);
630  if ((int) key_nr >= 0)
631  {
632  const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
633 
634  print_keydup_error(key_nr, err_msg, table);
635 
636  return;
637  }
638  textno=ER_DUP_KEY;
639  break;
640  }
641  case HA_ERR_FOREIGN_DUPLICATE_KEY:
642  {
643  uint32_t key_nr= table.get_dup_key(error);
644  if ((int) key_nr >= 0)
645  {
646  uint32_t max_length;
647 
648  /* Write the key in the error message */
649  char key[MAX_KEY_LENGTH];
650  String str(key,sizeof(key),system_charset_info);
651 
652  /* Table is opened and defined at this point */
653  key_unpack(&str, &table,(uint32_t) key_nr);
654  max_length= (DRIZZLE_ERRMSG_SIZE-
655  (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
656  if (str.length() >= max_length)
657  {
658  str.length(max_length-4);
659  str.append(STRING_WITH_LEN("..."));
660  }
661  my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
662  str.c_ptr(), key_nr+1);
663  return;
664  }
665  textno= ER_DUP_KEY;
666  break;
667  }
668  case HA_ERR_FOUND_DUPP_UNIQUE:
669  textno=ER_DUP_UNIQUE;
670  break;
671  case HA_ERR_RECORD_CHANGED:
672  textno=ER_CHECKREAD;
673  break;
674  case HA_ERR_CRASHED:
675  textno=ER_NOT_KEYFILE;
676  break;
677  case HA_ERR_WRONG_IN_RECORD:
678  textno= ER_CRASHED_ON_USAGE;
679  break;
680  case HA_ERR_CRASHED_ON_USAGE:
681  textno=ER_CRASHED_ON_USAGE;
682  break;
683  case HA_ERR_NOT_A_TABLE:
684  textno= static_cast<drizzled::error_t>(error);
685  break;
686  case HA_ERR_CRASHED_ON_REPAIR:
687  textno=ER_CRASHED_ON_REPAIR;
688  break;
689  case HA_ERR_OUT_OF_MEM:
690  textno=ER_OUT_OF_RESOURCES;
691  break;
692  case HA_ERR_WRONG_COMMAND:
693  textno=ER_ILLEGAL_HA;
694  break;
695  case HA_ERR_OLD_FILE:
696  textno=ER_OLD_KEYFILE;
697  break;
698  case HA_ERR_UNSUPPORTED:
699  textno=ER_UNSUPPORTED_EXTENSION;
700  break;
701  case HA_ERR_RECORD_FILE_FULL:
702  case HA_ERR_INDEX_FILE_FULL:
703  textno=ER_RECORD_FILE_FULL;
704  break;
705  case HA_ERR_LOCK_WAIT_TIMEOUT:
706  textno=ER_LOCK_WAIT_TIMEOUT;
707  break;
708  case HA_ERR_LOCK_TABLE_FULL:
709  textno=ER_LOCK_TABLE_FULL;
710  break;
711  case HA_ERR_LOCK_DEADLOCK:
712  textno=ER_LOCK_DEADLOCK;
713  break;
714  case HA_ERR_READ_ONLY_TRANSACTION:
715  textno=ER_READ_ONLY_TRANSACTION;
716  break;
717  case HA_ERR_CANNOT_ADD_FOREIGN:
718  textno=ER_CANNOT_ADD_FOREIGN;
719  break;
720  case HA_ERR_ROW_IS_REFERENCED:
721  {
722  String str;
723  get_error_message(error, &str);
724  my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_str());
725  return;
726  }
727  case HA_ERR_NO_REFERENCED_ROW:
728  {
729  String str;
730  get_error_message(error, &str);
731  my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_str());
732  return;
733  }
734  case HA_ERR_TABLE_DEF_CHANGED:
735  textno=ER_TABLE_DEF_CHANGED;
736  break;
737  case HA_ERR_NO_SUCH_TABLE:
738  {
739  my_error(ER_TABLE_UNKNOWN, table.getShare()->getTableIdentifier());
740  return;
741  }
742  case HA_ERR_LOG_ROW_FOR_REPLICATION_FAILED:
743  textno= ER_LOG_ROW_FOR_REPLICATION_FAILED;
744  break;
745  case HA_ERR_DROP_INDEX_FK:
746  {
747  const char *ptr= "???";
748  uint32_t key_nr= table.get_dup_key(error);
749  if ((int) key_nr >= 0)
750  ptr= table.key_info[key_nr].name;
751  my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
752  return;
753  }
754  case HA_ERR_TABLE_NEEDS_UPGRADE:
755  textno=ER_TABLE_NEEDS_UPGRADE;
756  break;
757  case HA_ERR_TABLE_READONLY:
758  textno= ER_OPEN_AS_READONLY;
759  break;
760  case HA_ERR_AUTOINC_READ_FAILED:
761  textno= ER_AUTOINC_READ_FAILED;
762  break;
763  case HA_ERR_AUTOINC_ERANGE:
764  textno= ER_WARN_DATA_OUT_OF_RANGE;
765  break;
766  case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
767  my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
768  return;
769  default:
770  {
771  /*
772  The error was "unknown" to this function.
773  Ask Cursor if it has got a message for this error
774  */
775  bool temporary= false;
776  String str;
777  temporary= get_error_message(error, &str);
778  if (!str.empty())
779  {
780  const char* engine_name= getName().c_str();
781  if (temporary)
782  my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine_name);
783  else
784  my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
785  }
786  else
787  {
788  my_error(ER_GET_ERRNO,errflag,error);
789  }
790  return;
791  }
792  }
793 
794  my_error(textno, errflag, table.getShare()->getTableName(), error);
795 }
796 
797 
808 {
809  return false;
810 }
811 
812 
813 void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, const Table &table) const
814 {
815  /* Write the duplicated key in the error message */
816  char key[MAX_KEY_LENGTH];
817  String str(key,sizeof(key),system_charset_info);
818 
819  if (key_nr == MAX_KEY)
820  {
821  /* Key is unknown */
822  str.copy("", 0, system_charset_info);
823  my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
824  }
825  else
826  {
827  /* Table is opened and defined at this point */
828  key_unpack(&str, &table, (uint32_t) key_nr);
829  uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
830  if (str.length() >= max_length)
831  {
832  str.length(max_length-4);
833  str.append(STRING_WITH_LEN("..."));
834  }
835  my_printf_error(ER_DUP_ENTRY, msg,
836  MYF(0), str.c_ptr(), table.key_info[key_nr].name);
837  }
838 }
839 
840 
841 int StorageEngine::deleteDefinitionFromPath(const identifier::Table &identifier)
842 {
843  std::string path(identifier.getPath());
844 
845  path.append(DEFAULT_DEFINITION_FILE_EXT);
846 
847  return internal::my_delete(path.c_str(), MYF(0));
848 }
849 
850 int StorageEngine::renameDefinitionFromPath(const identifier::Table &dest, const identifier::Table &src)
851 {
852  message::Table table_message;
853  std::string src_path(src.getPath());
854  std::string dest_path(dest.getPath());
855 
856  src_path.append(DEFAULT_DEFINITION_FILE_EXT);
857  dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
858 
859  bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
860 
861  if (not was_read)
862  {
863  return ENOENT;
864  }
865 
866  dest.copyToTableMessage(table_message);
867 
868  int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
869 
870  if (not error)
871  {
872  if (unlink(src_path.c_str()))
873  perror(src_path.c_str());
874  }
875 
876  return error;
877 }
878 
879 int StorageEngine::writeDefinitionFromPath(const identifier::Table &identifier, const message::Table &table_message)
880 {
881  char definition_file_tmp[FN_REFLEN];
882  std::string file_name(identifier.getPath());
883 
884  file_name.append(DEFAULT_DEFINITION_FILE_EXT);
885 
886  snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
887 
888  int fd= mkstemp(definition_file_tmp);
889 
890  if (fd == -1)
891  {
892  perror(definition_file_tmp);
893  return errno;
894  }
895 
896  google::protobuf::io::ZeroCopyOutputStream* output=
897  new google::protobuf::io::FileOutputStream(fd);
898 
899  bool success;
900 
901  try
902  {
903  success= table_message.SerializeToZeroCopyStream(output);
904  }
905  catch (...)
906  {
907  success= false;
908  }
909 
910  if (not success)
911  {
912  my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), identifier.getSQLPath().c_str(), table_message.InitializationErrorString().c_str());
913  delete output;
914 
915  if (close(fd) == -1)
916  perror(definition_file_tmp);
917 
918  if (unlink(definition_file_tmp) == -1)
919  perror(definition_file_tmp);
920 
921  return ER_CORRUPT_TABLE_DEFINITION;
922  }
923 
924  delete output;
925 
926  if (close(fd) == -1)
927  {
928  int error= errno;
929  perror(definition_file_tmp);
930 
931  if (unlink(definition_file_tmp))
932  perror(definition_file_tmp);
933 
934  return error;
935  }
936 
937  if (rename(definition_file_tmp, file_name.c_str()) == -1)
938  {
939  int error= errno;
940  perror(definition_file_tmp);
941 
942  if (unlink(definition_file_tmp))
943  perror(definition_file_tmp);
944 
945  return error;
946  }
947 
948  return 0;
949 }
950 
955 {
956  BOOST_FOREACH(EngineVector::reference it, g_engines)
957  {
958  if (not it->doCanCreateTable(identifier))
959  return false;
960  }
961  return true;
962 }
963 
964 bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
965 {
966  std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
967 
968  if (input.good())
969  {
970  try {
971  if (table_message.ParseFromIstream(&input))
972  {
973  return true;
974  }
975  }
976  catch (...)
977  {
978  my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
979  table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
980  table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
981  }
982  }
983  else
984  {
985  perror(path.c_str());
986  }
987 
988  return false;
989 }
990 
991 std::ostream& operator<<(std::ostream& output, const StorageEngine &engine)
992 {
993  return output << "StorageEngine:(" << engine.getName() << ")";
994 }
995 
996 } /* namespace plugin */
997 } /* namespace drizzled */
virtual void print_error(int error, myf errflag, const Table &table) const
virtual bool get_error_message(int error, String *buf) const
static bool createTable(Session &session, const identifier::Table &identifier, message::Table &table_message)
int delete_table(bool free_share=false)
Definition: table.cc:75
static bool canCreateTable(const drizzled::identifier::Table &identifier)
Defines the interface to the CachedDirectory class.
KeyInfo * key_info
Definition: table.h:141
uint32_t get_dup_key(int error) const
Definition: table.h:556
virtual const char ** bas_ext() const =0
virtual int doDropTable(Session &session, const drizzled::identifier::Table &identifier)=0
static bool doesTableExist(Session &session, const drizzled::identifier::Table &identifier, bool include_temporary_tables=true)
static void closeConnection(Session &)