Drizzled Public API Documentation

schema.cc
1 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2010 Brian Aker
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <config.h>
22 
23 #include <drizzled/error.h>
24 #include <plugin/schema_engine/schema.h>
25 #include <drizzled/schema.h>
26 #include <drizzled/sql_table.h>
27 #include <drizzled/charset.h>
28 #include <drizzled/cursor.h>
29 #include <drizzled/data_home.h>
30 #include <drizzled/message/catalog.h>
31 
32 #include <drizzled/pthread_globals.h>
33 
34 #include <drizzled/execute.h>
35 
36 #include <drizzled/internal/my_sys.h>
38 
39 #include <fcntl.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 
43 #include <boost/foreach.hpp>
44 #include <google/protobuf/io/zero_copy_stream.h>
45 #include <google/protobuf/io/zero_copy_stream_impl.h>
46 
47 #include <iostream>
48 #include <fstream>
49 #include <string>
50 
51 using namespace std;
52 using namespace drizzled;
53 
54 const char* MY_DB_OPT_FILE= "db.opt";
55 const char* DEFAULT_FILE_EXTENSION= ".dfe"; // Deep Fried Elephant
56 
57 static const char* g_schema_exts[] =
58 {
59  NULL
60 };
61 
62 Schema::Schema() :
63  drizzled::plugin::StorageEngine("SchemaEngine",
64  HTON_ALTER_NOT_SUPPORTED |
65  HTON_HAS_SCHEMA_DICTIONARY |
66  HTON_SKIP_STORE_LOCK |
67  HTON_TEMPORARY_NOT_SUPPORTED),
68  schema_cache_filled(false)
69 {
70  table_definition_ext= DEFAULT_FILE_EXTENSION;
71 }
72 
73 void Schema::prime_catalog(identifier::Catalog &catalog_identifier)
74 {
75  CachedDirectory directory(catalog_identifier.getPath(),
76  CachedDirectory::DIRECTORY, true);
77 
78  CachedDirectory::Entries files= directory.getEntries();
79  boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
80 
81  BOOST_FOREACH(CachedDirectory::Entries::reference entry, files)
82  {
83  if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
84  continue;
85  message::Schema schema_message;
86 
87  std::string filename= catalog_identifier.getPath();
88  filename+= FN_LIBCHAR;
89  filename+= entry->filename;
90 
91  if (readSchemaFile(filename, schema_message))
92  {
93 
94  identifier::Schema schema_identifier(catalog_identifier,
95  schema_message.name());
96 
97  if (! schema_message.has_catalog())
98  {
99  schema_message.set_catalog(catalog_identifier.name());
100  }
101 
102  pair<SchemaCache::iterator, bool> ret=
103  schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
104 
105  (void)(ret);
106  assert(ret.second); // If this has happened, something really bad is going down.
107  }
108  }
109 }
110 
111 void Schema::prime()
112 {
113  drizzled::CachedDirectory directory(drizzled::getDataHome().file_string(),
114  drizzled::CachedDirectory::DIRECTORY,
115  true);
116  drizzled::CachedDirectory::Entries files= directory.getEntries();
117 
118  for (drizzled::CachedDirectory::Entries::iterator fileIter= files.begin();
119  fileIter != files.end(); fileIter++)
120  {
121  drizzled::CachedDirectory::Entry *entry= *fileIter;
122  drizzled::message::catalog::shared_ptr message;
123 
124  if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
125  {
126  continue;
127  }
128 
129  drizzled::identifier::Catalog identifier(entry->filename);
130 
131  prime_catalog(identifier);
132  }
133 }
134 
135 void Schema::doGetSchemaIdentifiers(identifier::schema::vector &set_of_names)
136 {
137  mutex.lock_shared();
138  BOOST_FOREACH(SchemaCache::reference iter, schema_cache)
139  set_of_names.push_back(identifier::Schema(identifier::Catalog(iter.second->catalog()),
140  iter.second->name()));
141  mutex.unlock_shared();
142 }
143 
144 drizzled::message::schema::shared_ptr Schema::doGetSchemaDefinition(const identifier::Schema &schema_identifier)
145 {
146  mutex.lock_shared();
147  SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
148  if (iter != schema_cache.end())
149  {
150  drizzled::message::schema::shared_ptr schema_message= iter->second;
151  mutex.unlock_shared();
152  return schema_message;
153  }
154  mutex.unlock_shared();
155  return drizzled::message::schema::shared_ptr();
156 }
157 
158 
159 bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
160 {
161  identifier::Schema schema_identifier(identifier::Catalog(schema_message.catalog()),
162  schema_message.name());
163 
164  if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
165  {
166  sql_perror(schema_identifier.getPath().c_str());
167  return false;
168  }
169 
170  if (not writeSchemaFile(schema_identifier, schema_message))
171  {
172  rmdir(schema_identifier.getPath().c_str());
173 
174  return false;
175  }
176 
177  boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
178  pair<SchemaCache::iterator, bool> ret=
179  schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
180 
181  assert(ret.second); // If this has happened, something really bad is going down.
182  return ret.second;
183 }
184 
185 bool Schema::doDropSchema(const identifier::Schema &schema_identifier)
186 {
187  string schema_file(schema_identifier.getPath());
188  schema_file.append(1, FN_LIBCHAR);
189  schema_file.append(MY_DB_OPT_FILE);
190 
191  if (not doGetSchemaDefinition(schema_identifier))
192  return false;
193 
194  // No db.opt file, no love from us.
195  if (access(schema_file.c_str(), F_OK))
196  {
197  sql_perror(schema_file.c_str());
198  return false;
199  }
200 
201  if (unlink(schema_file.c_str()))
202  {
203  sql_perror(schema_file.c_str());
204  return false;
205  }
206 
207  if (rmdir(schema_identifier.getPath().c_str()))
208  {
209  sql_perror(schema_identifier.getPath().c_str());
210  //@todo If this happens, we want a report of it. For the moment I dump
211  //to stderr so I can catch it in Hudson.
212  CachedDirectory dir(schema_identifier.getPath());
213  cerr << dir;
214  }
215 
216  boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
217  schema_cache.erase(schema_identifier.getPath());
218 
219  return true;
220 }
221 
222 bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
223 {
224  identifier::Schema schema_identifier(identifier::Catalog(schema_message.catalog()),
225  schema_message.name());
226 
227  if (access(schema_identifier.getPath().c_str(), F_OK))
228  {
229  return false;
230  }
231 
232  if (writeSchemaFile(schema_identifier, schema_message))
233  {
234  boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
235  schema_cache.erase(schema_identifier.getPath());
236 
237  pair<SchemaCache::iterator, bool> ret=
238  schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
239 
240  assert(ret.second); // If this has happened, something really bad is going down.
241  return ret.second;
242  }
243 
244  return false;
245 }
246 
252 bool Schema::writeSchemaFile(const identifier::Schema &schema_identifier, const message::Schema &db)
253 {
254  char schema_file_tmp[FN_REFLEN];
255  string schema_file(schema_identifier.getPath());
256 
257 
258  schema_file.append(1, FN_LIBCHAR);
259  schema_file.append(MY_DB_OPT_FILE);
260 
261  snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
262 
263  int fd= mkstemp(schema_file_tmp);
264 
265  if (fd == -1)
266  {
267  sql_perror(schema_file_tmp);
268 
269  return false;
270  }
271 
272  bool success;
273 
274  try {
275  success= db.SerializeToFileDescriptor(fd);
276  }
277  catch (...)
278  {
279  success= false;
280  }
281 
282  if (not success)
283  {
284  my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
285  db.InitializationErrorString().empty() ? "unknown" : db.InitializationErrorString().c_str());
286 
287  if (close(fd) == -1)
288  sql_perror(schema_file_tmp);
289 
290  if (unlink(schema_file_tmp))
291  sql_perror(schema_file_tmp);
292 
293  return false;
294  }
295 
296  if (close(fd) == -1)
297  {
298  sql_perror(schema_file_tmp);
299 
300  if (unlink(schema_file_tmp))
301  sql_perror(schema_file_tmp);
302 
303  return false;
304  }
305 
306  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
307  {
308  if (unlink(schema_file_tmp))
309  sql_perror(schema_file_tmp);
310 
311  return false;
312  }
313 
314  return true;
315 }
316 
317 
318 bool Schema::readSchemaFile(const drizzled::identifier::Schema &schema_identifier, drizzled::message::Schema &schema)
319 {
320  return readSchemaFile(schema_identifier.getPath(), schema);
321 }
322 
323 bool Schema::readSchemaFile(std::string db_opt_path, drizzled::message::Schema &schema)
324 {
325  /*
326  Pass an empty file name, and the database options file name as extension
327  to avoid table name to file name encoding.
328  */
329  db_opt_path.append(1, FN_LIBCHAR);
330  db_opt_path.append(MY_DB_OPT_FILE);
331 
332  fstream input(db_opt_path.c_str(), ios::in | ios::binary);
333 
339  if (input.good())
340  {
341  if (schema.ParseFromIstream(&input))
342  {
343  return true;
344  }
345 
346  my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
347  schema.InitializationErrorString().empty() ? "unknown" : schema.InitializationErrorString().c_str());
348  }
349  else
350  {
351  sql_perror(db_opt_path.c_str());
352  }
353 
354  return false;
355 }
356 
357 void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
359  drizzled::identifier::table::vector&)
360 {
361 }
362 
363 const char** Schema::bas_ext() const
364 {
365  return g_schema_exts;
366 }
Definition: schema.h:30
bool writeSchemaFile(const drizzled::identifier::Schema &schema_identifier, const drizzled::message::Schema &db)
Definition: schema.cc:252
const char ** bas_ext() const
Definition: schema.cc:363
Defines the interface to the CachedDirectory class.