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 <drizzled/error.h>
00024 #include <plugin/schema_engine/schema.h>
00025 #include <drizzled/schema.h>
00026 #include <drizzled/sql_table.h>
00027 #include <drizzled/charset.h>
00028 #include <drizzled/cursor.h>
00029 #include <drizzled/catalog/local.h>
00030
00031 #include <drizzled/pthread_globals.h>
00032
00033 #include <drizzled/execute.h>
00034
00035 #include <drizzled/internal/my_sys.h>
00036 #include <drizzled/cached_directory.h>
00037
00038 #include <fcntl.h>
00039 #include <sys/stat.h>
00040 #include <sys/types.h>
00041
00042 #include <boost/foreach.hpp>
00043 #include <google/protobuf/io/zero_copy_stream.h>
00044 #include <google/protobuf/io/zero_copy_stream_impl.h>
00045
00046 #include <iostream>
00047 #include <fstream>
00048 #include <string>
00049
00050 using namespace std;
00051 using namespace drizzled;
00052
00053 const char* MY_DB_OPT_FILE= "db.opt";
00054 const char* DEFAULT_FILE_EXTENSION= ".dfe";
00055
00056 static const char* g_schema_exts[] =
00057 {
00058 NULL
00059 };
00060
00061 Schema::Schema() :
00062 drizzled::plugin::StorageEngine("schema",
00063 HTON_ALTER_NOT_SUPPORTED |
00064 HTON_HAS_SCHEMA_DICTIONARY |
00065 HTON_SKIP_STORE_LOCK |
00066 HTON_TEMPORARY_NOT_SUPPORTED),
00067 schema_cache_filled(false)
00068 {
00069 table_definition_ext= DEFAULT_FILE_EXTENSION;
00070 }
00071
00072 void Schema::prime()
00073 {
00074 CachedDirectory directory(catalog::local_identifier().getPath(),
00075 CachedDirectory::DIRECTORY, true);
00076
00077 CachedDirectory::Entries files= directory.getEntries();
00078 boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00079
00080 BOOST_FOREACH(CachedDirectory::Entries::reference entry, files)
00081 {
00082 if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
00083 continue;
00084 message::Schema schema_message;
00085
00086 std::string filename= catalog::local_identifier().getPath();
00087 filename+= FN_LIBCHAR;
00088 filename+= entry->filename;
00089
00090 if (readSchemaFile(filename, schema_message))
00091 {
00092 identifier::Schema schema_identifier(schema_message.name());
00093
00094 pair<SchemaCache::iterator, bool> ret=
00095 schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
00096
00097 assert(ret.second);
00098 }
00099 }
00100 }
00101
00102 void Schema::doGetSchemaIdentifiers(identifier::schema::vector &set_of_names)
00103 {
00104 mutex.lock_shared();
00105 BOOST_FOREACH(SchemaCache::reference iter, schema_cache)
00106 set_of_names.push_back(identifier::Schema(iter.second->name()));
00107 mutex.unlock_shared();
00108 }
00109
00110 drizzled::message::schema::shared_ptr Schema::doGetSchemaDefinition(const identifier::Schema &schema_identifier)
00111 {
00112 mutex.lock_shared();
00113 SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
00114 if (iter != schema_cache.end())
00115 {
00116 drizzled::message::schema::shared_ptr schema_message= iter->second;
00117 mutex.unlock_shared();
00118 return schema_message;
00119 }
00120 mutex.unlock_shared();
00121 return drizzled::message::schema::shared_ptr();
00122 }
00123
00124
00125 bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
00126 {
00127 identifier::Schema schema_identifier(schema_message.name());
00128
00129 if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
00130 {
00131 sql_perror(schema_identifier.getPath().c_str());
00132 return false;
00133 }
00134
00135 if (not writeSchemaFile(schema_identifier, schema_message))
00136 {
00137 rmdir(schema_identifier.getPath().c_str());
00138
00139 return false;
00140 }
00141
00142 boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00143 pair<SchemaCache::iterator, bool> ret=
00144 schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
00145
00146 assert(ret.second);
00147 return true;
00148 }
00149
00150 bool Schema::doDropSchema(const identifier::Schema &schema_identifier)
00151 {
00152 string schema_file(schema_identifier.getPath());
00153 schema_file.append(1, FN_LIBCHAR);
00154 schema_file.append(MY_DB_OPT_FILE);
00155
00156 if (not doGetSchemaDefinition(schema_identifier))
00157 return false;
00158
00159
00160 if (access(schema_file.c_str(), F_OK))
00161 {
00162 sql_perror(schema_file.c_str());
00163 return false;
00164 }
00165
00166 if (unlink(schema_file.c_str()))
00167 {
00168 sql_perror(schema_file.c_str());
00169 return false;
00170 }
00171
00172 if (rmdir(schema_identifier.getPath().c_str()))
00173 {
00174 sql_perror(schema_identifier.getPath().c_str());
00175
00176
00177 CachedDirectory dir(schema_identifier.getPath());
00178 cerr << dir;
00179 }
00180
00181 boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00182 schema_cache.erase(schema_identifier.getPath());
00183
00184 return true;
00185 }
00186
00187 bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
00188 {
00189 identifier::Schema schema_identifier(schema_message.name());
00190
00191 if (access(schema_identifier.getPath().c_str(), F_OK))
00192 return false;
00193
00194 if (writeSchemaFile(schema_identifier, schema_message))
00195 {
00196 boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
00197 schema_cache.erase(schema_identifier.getPath());
00198
00199 pair<SchemaCache::iterator, bool> ret=
00200 schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
00201
00202 assert(ret.second);
00203 }
00204
00205 return true;
00206 }
00207
00213 bool Schema::writeSchemaFile(const identifier::Schema &schema_identifier, const message::Schema &db)
00214 {
00215 char schema_file_tmp[FN_REFLEN];
00216 string schema_file(schema_identifier.getPath());
00217
00218
00219 schema_file.append(1, FN_LIBCHAR);
00220 schema_file.append(MY_DB_OPT_FILE);
00221
00222 snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
00223
00224 int fd= mkstemp(schema_file_tmp);
00225
00226 if (fd == -1)
00227 {
00228 sql_perror(schema_file_tmp);
00229
00230 return false;
00231 }
00232
00233 bool success;
00234
00235 try {
00236 success= db.SerializeToFileDescriptor(fd);
00237 }
00238 catch (...)
00239 {
00240 success= false;
00241 }
00242
00243 if (not success)
00244 {
00245 my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
00246 db.InitializationErrorString().empty() ? "unknown" : db.InitializationErrorString().c_str());
00247
00248 if (close(fd) == -1)
00249 sql_perror(schema_file_tmp);
00250
00251 if (unlink(schema_file_tmp))
00252 sql_perror(schema_file_tmp);
00253
00254 return false;
00255 }
00256
00257 if (close(fd) == -1)
00258 {
00259 sql_perror(schema_file_tmp);
00260
00261 if (unlink(schema_file_tmp))
00262 sql_perror(schema_file_tmp);
00263
00264 return false;
00265 }
00266
00267 if (rename(schema_file_tmp, schema_file.c_str()) == -1)
00268 {
00269 if (unlink(schema_file_tmp))
00270 sql_perror(schema_file_tmp);
00271
00272 return false;
00273 }
00274
00275 return true;
00276 }
00277
00278
00279 bool Schema::readSchemaFile(const drizzled::identifier::Schema &schema_identifier, drizzled::message::Schema &schema)
00280 {
00281 return readSchemaFile(schema_identifier.getPath(), schema);
00282 }
00283
00284 bool Schema::readSchemaFile(std::string db_opt_path, drizzled::message::Schema &schema)
00285 {
00286
00287
00288
00289
00290 db_opt_path.append(1, FN_LIBCHAR);
00291 db_opt_path.append(MY_DB_OPT_FILE);
00292
00293 fstream input(db_opt_path.c_str(), ios::in | ios::binary);
00294
00300 if (input.good())
00301 {
00302 if (schema.ParseFromIstream(&input))
00303 {
00304 return true;
00305 }
00306
00307 my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
00308 schema.InitializationErrorString().empty() ? "unknown" : schema.InitializationErrorString().c_str());
00309 }
00310 else
00311 {
00312 sql_perror(db_opt_path.c_str());
00313 }
00314
00315 return false;
00316 }
00317
00318 void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
00319 const drizzled::identifier::Schema&,
00320 drizzled::identifier::table::vector&)
00321 {
00322 }
00323
00324 const char** Schema::bas_ext() const
00325 {
00326 return g_schema_exts;
00327 }