00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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();
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();
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
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
00196
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();
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
00311
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 }