Drizzled Public API Documentation

schema.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Brian Aker
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <plugin/schema_engine/schema.h>
00024 #include <drizzled/schema.h>
00025 #include <drizzled/sql_table.h>
00026 #include <drizzled/global_charset_info.h>
00027 #include <drizzled/charset.h>
00028 #include <drizzled/charset_info.h>
00029 #include <drizzled/cursor.h>
00030 #include <drizzled/data_home.h>
00031 
00032 #include <drizzled/pthread_globals.h>
00033 
00034 #include <drizzled/execute.h>
00035 
00036 #include <drizzled/internal/my_sys.h>
00037 
00038 #include <fcntl.h>
00039 #include <sys/stat.h>
00040 #include <sys/types.h>
00041 
00042 #include <google/protobuf/io/zero_copy_stream.h>
00043 #include <google/protobuf/io/zero_copy_stream_impl.h>
00044 
00045 #include <iostream>
00046 #include <fstream>
00047 #include <string>
00048 
00049 using namespace std;
00050 using namespace drizzled;
00051 
00052 
00053 #define MY_DB_OPT_FILE "db.opt"
00054 #define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
00055 
00056 Schema::Schema():
00057   drizzled::plugin::StorageEngine("schema",
00058                                   HTON_ALTER_NOT_SUPPORTED |
00059                                   HTON_HAS_SCHEMA_DICTIONARY |
00060                                   HTON_SKIP_STORE_LOCK |
00061                                   HTON_TEMPORARY_NOT_SUPPORTED),
00062   schema_cache_filled(false)
00063 {
00064   table_definition_ext= DEFAULT_FILE_EXTENSION;
00065 }
00066 
00067 Schema::~Schema()
00068 {
00069 }
00070 
00071 void Schema::prime()
00072 {
00073   CachedDirectory directory(getDataHomeCatalog().file_string(), CachedDirectory::DIRECTORY);
00074   CachedDirectory::Entries files= directory.getEntries();
00075   boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00076 
00077   for (CachedDirectory::Entries::iterator fileIter= files.begin();
00078        fileIter != files.end(); fileIter++)
00079   {
00080     CachedDirectory::Entry *entry= *fileIter;
00081     message::Schema schema_message;
00082 
00083     if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
00084       continue;
00085 
00086     if (readSchemaFile(entry->filename, schema_message))
00087     {
00088       identifier::Schema schema_identifier(schema_message.name());
00089 
00090       pair<SchemaCache::iterator, bool> ret=
00091         schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
00092 
00093       if (ret.second == false)
00094       {
00095         abort(); // If this has happened, something really bad is going down.
00096       }
00097     }
00098   }
00099 }
00100 
00101 void Schema::startup(drizzled::Session &)
00102 {
00103 }
00104 
00105 void Schema::doGetSchemaIdentifiers(identifier::Schema::vector &set_of_names)
00106 {
00107   mutex.lock_shared();
00108   {
00109     for (SchemaCache::iterator iter= schema_cache.begin();
00110          iter != schema_cache.end();
00111          iter++)
00112     {
00113       set_of_names.push_back(identifier::Schema(iter->second->name()));
00114     }
00115   }
00116   mutex.unlock_shared();
00117 }
00118 
00119 drizzled::message::schema::shared_ptr Schema::doGetSchemaDefinition(const identifier::Schema &schema_identifier)
00120 {
00121   mutex.lock_shared();
00122   SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
00123 
00124   if (iter != schema_cache.end())
00125   {
00126     drizzled::message::schema::shared_ptr schema_message;
00127     schema_message= iter->second;
00128     mutex.unlock_shared();
00129 
00130     return schema_message;
00131   }
00132   mutex.unlock_shared();
00133 
00134   return drizzled::message::schema::shared_ptr();
00135 }
00136 
00137 
00138 bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
00139 {
00140   identifier::Schema schema_identifier(schema_message.name());
00141 
00142   if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
00143   {
00144     sql_perror(schema_identifier.getPath().c_str());
00145     return false;
00146   }
00147 
00148   if (not writeSchemaFile(schema_identifier, schema_message))
00149   {
00150     rmdir(schema_identifier.getPath().c_str());
00151 
00152     return false;
00153   }
00154 
00155   {
00156     boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00157     pair<SchemaCache::iterator, bool> ret=
00158       schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
00159 
00160 
00161     if (ret.second == false)
00162     {
00163       abort(); // If this has happened, something really bad is going down.
00164     }
00165   }
00166 
00167   return true;
00168 }
00169 
00170 bool Schema::doDropSchema(const identifier::Schema &schema_identifier)
00171 {
00172   string schema_file(schema_identifier.getPath());
00173   schema_file.append(1, FN_LIBCHAR);
00174   schema_file.append(MY_DB_OPT_FILE);
00175 
00176   if (not doGetSchemaDefinition(schema_identifier))
00177     return false;
00178 
00179   // No db.opt file, no love from us.
00180   if (access(schema_file.c_str(), F_OK))
00181   {
00182     sql_perror(schema_file.c_str());
00183     return false;
00184   }
00185 
00186   if (unlink(schema_file.c_str()))
00187   {
00188     sql_perror(schema_file.c_str());
00189     return false;
00190   }
00191 
00192   if (rmdir(schema_identifier.getPath().c_str()))
00193   {
00194     sql_perror(schema_identifier.getPath().c_str());
00195     //@todo If this happens, we want a report of it. For the moment I dump
00196     //to stderr so I can catch it in Hudson.
00197     CachedDirectory dir(schema_identifier.getPath());
00198     cerr << dir;
00199   }
00200 
00201   boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00202   schema_cache.erase(schema_identifier.getPath());
00203 
00204   return true;
00205 }
00206 
00207 bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
00208 {
00209   identifier::Schema schema_identifier(schema_message.name());
00210 
00211   if (access(schema_identifier.getPath().c_str(), F_OK))
00212     return false;
00213 
00214   if (writeSchemaFile(schema_identifier, schema_message))
00215   {
00216     boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00217     schema_cache.erase(schema_identifier.getPath());
00218 
00219     pair<SchemaCache::iterator, bool> ret=
00220       schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
00221 
00222     if (ret.second == false)
00223     {
00224       abort(); // If this has happened, something really bad is going down.
00225     }
00226   }
00227 
00228   return true;
00229 }
00230 
00236 bool Schema::writeSchemaFile(const identifier::Schema &schema_identifier, const message::Schema &db)
00237 {
00238   char schema_file_tmp[FN_REFLEN];
00239   string schema_file(schema_identifier.getPath());
00240 
00241 
00242   schema_file.append(1, FN_LIBCHAR);
00243   schema_file.append(MY_DB_OPT_FILE);
00244 
00245   snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
00246 
00247   int fd= mkstemp(schema_file_tmp);
00248 
00249   if (fd == -1)
00250   {
00251     sql_perror(schema_file_tmp);
00252 
00253     return false;
00254   }
00255 
00256   bool success;
00257 
00258   try {
00259     success= db.SerializeToFileDescriptor(fd);
00260   }
00261   catch (...)
00262   {
00263     success= false;
00264   }
00265 
00266   if (not success)
00267   {
00268     my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
00269              db.InitializationErrorString().empty() ? "unknown" :  db.InitializationErrorString().c_str());
00270 
00271     if (close(fd) == -1)
00272       sql_perror(schema_file_tmp);
00273 
00274     if (unlink(schema_file_tmp))
00275       sql_perror(schema_file_tmp);
00276 
00277     return false;
00278   }
00279 
00280   if (close(fd) == -1)
00281   {
00282     sql_perror(schema_file_tmp);
00283 
00284     if (unlink(schema_file_tmp))
00285       sql_perror(schema_file_tmp);
00286 
00287     return false;
00288   }
00289 
00290   if (rename(schema_file_tmp, schema_file.c_str()) == -1)
00291   {
00292     if (unlink(schema_file_tmp))
00293       sql_perror(schema_file_tmp);
00294 
00295     return false;
00296   }
00297 
00298   return true;
00299 }
00300 
00301 
00302 bool Schema::readSchemaFile(const drizzled::identifier::Schema &schema_identifier, drizzled::message::Schema &schema)
00303 {
00304   return readSchemaFile(schema_identifier.getPath(), schema); 
00305 }
00306 
00307 bool Schema::readSchemaFile(std::string db_opt_path, drizzled::message::Schema &schema)
00308 {
00309   /*
00310     Pass an empty file name, and the database options file name as extension
00311     to avoid table name to file name encoding.
00312   */
00313   db_opt_path.append(1, FN_LIBCHAR);
00314   db_opt_path.append(MY_DB_OPT_FILE);
00315 
00316   fstream input(db_opt_path.c_str(), ios::in | ios::binary);
00317 
00323   if (input.good())
00324   {
00325     if (schema.ParseFromIstream(&input))
00326     {
00327       return true;
00328     }
00329 
00330     my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
00331              schema.InitializationErrorString().empty() ? "unknown" :  schema.InitializationErrorString().c_str());
00332   }
00333   else
00334   {
00335     sql_perror(db_opt_path.c_str());
00336   }
00337 
00338   return false;
00339 }
00340 
00341 void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
00342                                    const drizzled::identifier::Schema&,
00343                                    drizzled::identifier::Table::vector&)
00344 {
00345 }