1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Brian Aker
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; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
#include <plugin/schema_engine/schema.h>
24
#include <drizzled/schema.h>
25
#include <drizzled/sql_table.h>
26
#include <drizzled/global_charset_info.h>
27
#include <drizzled/charset.h>
28
#include <drizzled/charset_info.h>
29
#include <drizzled/cursor.h>
30
#include <drizzled/data_home.h>
32
#include <drizzled/pthread_globals.h>
34
#include <drizzled/execute.h>
36
#include <drizzled/internal/my_sys.h>
40
#include <sys/types.h>
42
#include <google/protobuf/io/zero_copy_stream.h>
43
#include <google/protobuf/io/zero_copy_stream_impl.h>
50
using namespace drizzled;
53
#define MY_DB_OPT_FILE "db.opt"
54
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
57
drizzled::plugin::StorageEngine("schema",
58
HTON_ALTER_NOT_SUPPORTED |
59
HTON_HAS_SCHEMA_DICTIONARY |
60
HTON_SKIP_STORE_LOCK |
61
HTON_TEMPORARY_NOT_SUPPORTED),
62
schema_cache_filled(false)
64
table_definition_ext= DEFAULT_FILE_EXTENSION;
73
CachedDirectory directory(getDataHomeCatalog().file_string(), CachedDirectory::DIRECTORY);
74
CachedDirectory::Entries files= directory.getEntries();
75
boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
77
for (CachedDirectory::Entries::iterator fileIter= files.begin();
78
fileIter != files.end(); fileIter++)
80
CachedDirectory::Entry *entry= *fileIter;
81
message::Schema schema_message;
83
if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
86
if (readSchemaFile(entry->filename, schema_message))
88
identifier::Schema schema_identifier(schema_message.name());
90
pair<SchemaCache::iterator, bool> ret=
91
schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
93
if (ret.second == false)
95
abort(); // If this has happened, something really bad is going down.
101
void Schema::startup(drizzled::Session &)
105
void Schema::doGetSchemaIdentifiers(identifier::Schema::vector &set_of_names)
109
for (SchemaCache::iterator iter= schema_cache.begin();
110
iter != schema_cache.end();
113
set_of_names.push_back(identifier::Schema((*iter).second->name()));
116
mutex.unlock_shared();
119
drizzled::message::schema::shared_ptr Schema::doGetSchemaDefinition(const identifier::Schema &schema_identifier)
122
SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
124
if (iter != schema_cache.end())
126
drizzled::message::schema::shared_ptr schema_message;
127
schema_message= (*iter).second;
128
mutex.unlock_shared();
130
return schema_message;
132
mutex.unlock_shared();
134
return drizzled::message::schema::shared_ptr();
138
bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
140
identifier::Schema schema_identifier(schema_message.name());
142
if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
144
sql_perror(schema_identifier.getPath().c_str());
148
if (not writeSchemaFile(schema_identifier, schema_message))
150
rmdir(schema_identifier.getPath().c_str());
156
boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
157
pair<SchemaCache::iterator, bool> ret=
158
schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
161
if (ret.second == false)
163
abort(); // If this has happened, something really bad is going down.
170
bool Schema::doDropSchema(const identifier::Schema &schema_identifier)
172
string schema_file(schema_identifier.getPath());
173
schema_file.append(1, FN_LIBCHAR);
174
schema_file.append(MY_DB_OPT_FILE);
176
if (not doGetSchemaDefinition(schema_identifier))
179
// No db.opt file, no love from us.
180
if (access(schema_file.c_str(), F_OK))
182
sql_perror(schema_file.c_str());
186
if (unlink(schema_file.c_str()))
188
sql_perror(schema_file.c_str());
192
if (rmdir(schema_identifier.getPath().c_str()))
194
sql_perror(schema_identifier.getPath().c_str());
195
//@todo If this happens, we want a report of it. For the moment I dump
196
//to stderr so I can catch it in Hudson.
197
CachedDirectory dir(schema_identifier.getPath());
201
boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
202
schema_cache.erase(schema_identifier.getPath());
207
bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
209
identifier::Schema schema_identifier(schema_message.name());
211
if (access(schema_identifier.getPath().c_str(), F_OK))
214
if (writeSchemaFile(schema_identifier, schema_message))
216
boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
217
schema_cache.erase(schema_identifier.getPath());
219
pair<SchemaCache::iterator, bool> ret=
220
schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
222
if (ret.second == false)
224
abort(); // If this has happened, something really bad is going down.
232
path is path to database, not schema file
234
@note we do the rename to make it crash safe.
236
bool Schema::writeSchemaFile(const identifier::Schema &schema_identifier, const message::Schema &db)
238
char schema_file_tmp[FN_REFLEN];
239
string schema_file(schema_identifier.getPath());
242
schema_file.append(1, FN_LIBCHAR);
243
schema_file.append(MY_DB_OPT_FILE);
245
snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
247
int fd= mkstemp(schema_file_tmp);
251
sql_perror(schema_file_tmp);
259
success= db.SerializeToFileDescriptor(fd);
268
my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
269
db.InitializationErrorString().empty() ? "unknown" : db.InitializationErrorString().c_str());
272
sql_perror(schema_file_tmp);
274
if (unlink(schema_file_tmp))
275
sql_perror(schema_file_tmp);
282
sql_perror(schema_file_tmp);
284
if (unlink(schema_file_tmp))
285
sql_perror(schema_file_tmp);
290
if (rename(schema_file_tmp, schema_file.c_str()) == -1)
292
if (unlink(schema_file_tmp))
293
sql_perror(schema_file_tmp);
302
bool Schema::readSchemaFile(const drizzled::identifier::Schema &schema_identifier, drizzled::message::Schema &schema)
304
return readSchemaFile(schema_identifier.getPath(), schema);
307
bool Schema::readSchemaFile(std::string db_opt_path, drizzled::message::Schema &schema)
310
Pass an empty file name, and the database options file name as extension
311
to avoid table name to file name encoding.
313
db_opt_path.append(1, FN_LIBCHAR);
314
db_opt_path.append(MY_DB_OPT_FILE);
316
fstream input(db_opt_path.c_str(), ios::in | ios::binary);
319
@note If parsing fails, either someone has done a "mkdir" or has deleted their opt file.
320
So what do we do? We muddle through the adventure by generating
321
one with a name in it, and the charset set to the default.
325
if (schema.ParseFromIstream(&input))
330
my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
331
schema.InitializationErrorString().empty() ? "unknown" : schema.InitializationErrorString().c_str());
335
sql_perror(db_opt_path.c_str());
341
void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
342
const drizzled::identifier::Schema&,
343
drizzled::identifier::Table::vector&)