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/db.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/internal/my_sys.h"
36
#include <sys/types.h>
38
#include <google/protobuf/io/zero_copy_stream.h>
39
#include <google/protobuf/io/zero_copy_stream_impl.h>
46
using namespace drizzled;
49
#define MY_DB_OPT_FILE "db.opt"
50
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
53
drizzled::plugin::StorageEngine("schema",
54
HTON_ALTER_NOT_SUPPORTED |
55
HTON_HAS_SCHEMA_DICTIONARY |
56
HTON_SKIP_STORE_LOCK |
57
HTON_TEMPORARY_NOT_SUPPORTED),
58
schema_cache_filled(false)
60
table_definition_ext= DEFAULT_FILE_EXTENSION;
69
CachedDirectory directory(getDataHomeCatalog().file_string(), CachedDirectory::DIRECTORY);
70
CachedDirectory::Entries files= directory.getEntries();
74
for (CachedDirectory::Entries::iterator fileIter= files.begin();
75
fileIter != files.end(); fileIter++)
77
CachedDirectory::Entry *entry= *fileIter;
78
message::Schema schema_message;
80
if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
83
SchemaIdentifier filename(entry->filename);
84
if (readSchemaFile(filename, schema_message))
86
SchemaIdentifier schema_identifier(schema_message.name());
88
pair<SchemaCache::iterator, bool> ret=
89
schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
91
if (ret.second == false)
93
abort(); // If this has happened, something really bad is going down.
100
void Schema::doGetSchemaIdentifiers(SchemaIdentifier::vector &set_of_names)
104
for (SchemaCache::iterator iter= schema_cache.begin();
105
iter != schema_cache.end();
108
set_of_names.push_back(SchemaIdentifier((*iter).second->name()));
111
mutex.unlock_shared();
114
bool Schema::doGetSchemaDefinition(const SchemaIdentifier &schema_identifier, message::schema::shared_ptr &schema_message)
117
SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
119
if (iter != schema_cache.end())
121
schema_message= (*iter).second;
122
mutex.unlock_shared();
125
mutex.unlock_shared();
131
bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
133
SchemaIdentifier schema_identifier(schema_message.name());
135
if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
138
if (not writeSchemaFile(schema_identifier, schema_message))
140
rmdir(schema_identifier.getPath().c_str());
147
pair<SchemaCache::iterator, bool> ret=
148
schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
151
if (ret.second == false)
153
abort(); // If this has happened, something really bad is going down.
161
bool Schema::doDropSchema(const SchemaIdentifier &schema_identifier)
163
message::schema::shared_ptr schema_message;
165
string schema_file(schema_identifier.getPath());
166
schema_file.append(1, FN_LIBCHAR);
167
schema_file.append(MY_DB_OPT_FILE);
169
if (not doGetSchemaDefinition(schema_identifier, schema_message))
172
// No db.opt file, no love from us.
173
if (access(schema_file.c_str(), F_OK))
175
perror(schema_file.c_str());
179
if (unlink(schema_file.c_str()))
181
perror(schema_file.c_str());
185
if (rmdir(schema_identifier.getPath().c_str()))
187
perror(schema_identifier.getPath().c_str());
188
//@todo If this happens, we want a report of it. For the moment I dump
189
//to stderr so I can catch it in Hudson.
190
CachedDirectory dir(schema_identifier.getPath());
195
schema_cache.erase(schema_identifier.getPath());
201
bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
203
SchemaIdentifier schema_identifier(schema_message.name());
205
if (access(schema_identifier.getPath().c_str(), F_OK))
208
if (writeSchemaFile(schema_identifier, schema_message))
212
schema_cache.erase(schema_identifier.getPath());
214
pair<SchemaCache::iterator, bool> ret=
215
schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
217
if (ret.second == false)
219
abort(); // If this has happened, something really bad is going down.
229
path is path to database, not schema file
231
@note we do the rename to make it crash safe.
233
bool Schema::writeSchemaFile(const SchemaIdentifier &schema_identifier, const message::Schema &db)
235
char schema_file_tmp[FN_REFLEN];
236
string schema_file(schema_identifier.getPath());
239
schema_file.append(1, FN_LIBCHAR);
240
schema_file.append(MY_DB_OPT_FILE);
242
snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
244
int fd= mkstemp(schema_file_tmp);
248
perror(schema_file_tmp);
256
success= db.SerializeToFileDescriptor(fd);
265
my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
266
db.InitializationErrorString().empty() ? "unknown" : db.InitializationErrorString().c_str());
269
perror(schema_file_tmp);
271
if (unlink(schema_file_tmp))
272
perror(schema_file_tmp);
279
perror(schema_file_tmp);
281
if (unlink(schema_file_tmp))
282
perror(schema_file_tmp);
287
if (rename(schema_file_tmp, schema_file.c_str()) == -1)
289
if (unlink(schema_file_tmp))
290
perror(schema_file_tmp);
299
bool Schema::readSchemaFile(const drizzled::SchemaIdentifier &schema_identifier, drizzled::message::Schema &schema)
301
string db_opt_path(schema_identifier.getPath());
304
Pass an empty file name, and the database options file name as extension
305
to avoid table name to file name encoding.
307
db_opt_path.append(1, FN_LIBCHAR);
308
db_opt_path.append(MY_DB_OPT_FILE);
310
fstream input(db_opt_path.c_str(), ios::in | ios::binary);
313
@note If parsing fails, either someone has done a "mkdir" or has deleted their opt file.
314
So what do we do? We muddle through the adventure by generating
315
one with a name in it, and the charset set to the default.
319
if (schema.ParseFromIstream(&input))
324
my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
325
schema.InitializationErrorString().empty() ? "unknown" : schema.InitializationErrorString().c_str());
329
perror(db_opt_path.c_str());
335
void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
336
const drizzled::SchemaIdentifier&,
337
drizzled::TableIdentifier::vector&)