Drizzled Public API Documentation

schema_engine.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; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 
22 #include <drizzled/session.h>
23 #include <drizzled/sql_base.h>
24 #include <drizzled/charset.h>
25 #include <drizzled/transaction_services.h>
26 #include <drizzled/open_tables_state.h>
27 #include <drizzled/table/cache.h>
28 #include <drizzled/plugin/storage_engine.h>
29 #include <drizzled/plugin/authorization.h>
30 
31 namespace drizzled {
32 namespace plugin {
33 
35  public std::unary_function<StorageEngine *, void>
36 {
37  identifier::schema::vector &schemas;
38 
39 public:
40 
41  AddSchemaNames(identifier::schema::vector &of_names) :
42  schemas(of_names)
43  {
44  }
45 
46  result_type operator() (argument_type engine)
47  {
48  engine->doGetSchemaIdentifiers(schemas);
49  }
50 };
51 
52 void StorageEngine::getIdentifiers(Session &session, identifier::schema::vector &schemas)
53 {
54  // Add hook here for engines to register schema.
55  std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
56  AddSchemaNames(schemas));
57 
58  plugin::Authorization::pruneSchemaNames(*session.user(), schemas);
59 }
60 
61 class StorageEngineGetSchemaDefinition: public std::unary_function<StorageEngine *, bool>
62 {
63  const identifier::Schema &identifier;
64  message::schema::shared_ptr &schema_proto;
65 
66 public:
68  message::schema::shared_ptr &schema_proto_arg) :
69  identifier(identifier_arg),
70  schema_proto(schema_proto_arg)
71  {
72  }
73 
74  result_type operator() (argument_type engine)
75  {
76  schema_proto= engine->doGetSchemaDefinition(identifier);
77  return schema_proto;
78  }
79 };
80 
81 /*
82  Return value is "if parsed"
83 */
84 message::schema::shared_ptr StorageEngine::getSchemaDefinition(const drizzled::identifier::Table &identifier)
85 {
86  identifier::Schema schema_identifier= identifier;
87  return StorageEngine::getSchemaDefinition(schema_identifier);
88 }
89 
90 message::schema::shared_ptr StorageEngine::getSchemaDefinition(const identifier::Schema &identifier)
91 {
92  message::schema::shared_ptr proto;
93 
94  EngineVector::iterator iter=
95  std::find_if(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
96  StorageEngineGetSchemaDefinition(identifier, proto));
97 
98  if (iter != StorageEngine::getSchemaEngines().end())
99  {
100  return proto;
101  }
102 
103  return message::schema::shared_ptr();
104 }
105 
106 bool StorageEngine::doesSchemaExist(const identifier::Schema &identifier)
107 {
108  message::schema::shared_ptr proto;
109 
110  return StorageEngine::getSchemaDefinition(identifier);
111 }
112 
113 
114 const charset_info_st *StorageEngine::getSchemaCollation(const identifier::Schema &identifier)
115 {
116  message::schema::shared_ptr schmema_proto= StorageEngine::getSchemaDefinition(identifier);
117  if (not schmema_proto || not schmema_proto->has_collation())
118  return default_charset_info;
119  const std::string buffer= schmema_proto->collation();
120  if (const charset_info_st* cs= get_charset_by_name(buffer.c_str()))
121  return cs;
122  errmsg_printf(error::ERROR, _("Error while loading database options: '%s':"), identifier.getSQLPath().c_str());
123  errmsg_printf(error::ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
124  return default_charset_info;
125 }
126 
128  public std::unary_function<StorageEngine *, void>
129 {
130  const drizzled::message::Schema &schema_message;
131  uint64_t &success_count;
132 
133 public:
134 
135  CreateSchema(const drizzled::message::Schema &arg, uint64_t &success_count_arg) :
136  schema_message(arg),
137  success_count(success_count_arg)
138  {
139  }
140 
141  result_type operator() (argument_type engine)
142  {
143  // @todo eomeday check that at least one engine said "true"
144  bool success= engine->doCreateSchema(schema_message);
145 
146  if (success)
147  {
148  success_count++;
149  TransactionServices::allocateNewTransactionId();
150  }
151  }
152 };
153 
154 bool StorageEngine::createSchema(const drizzled::message::Schema &schema_message)
155 {
156  // Add hook here for engines to register schema.
157  uint64_t success_count= 0;
158  std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
159  CreateSchema(schema_message, success_count));
160 
161  if (success_count)
162  {
163  TransactionServices::allocateNewTransactionId();
164  }
165 
166  return (bool)success_count;
167 }
168 
169 class DropSchema :
170  public std::unary_function<StorageEngine *, void>
171 {
172  uint64_t &success_count;
173  const identifier::Schema &identifier;
174 
175 public:
176 
177  DropSchema(const identifier::Schema &arg, uint64_t &count_arg) :
178  success_count(count_arg),
179  identifier(arg)
180  {
181  }
182 
183  result_type operator() (argument_type engine)
184  {
185  // @todo someday check that at least one engine said "true"
186  bool success= engine->doDropSchema(identifier);
187 
188  if (success)
189  {
190  success_count++;
191  TransactionServices::allocateNewTransactionId();
192  }
193  }
194 };
195 
196 static bool drop_all_tables_in_schema(Session& session,
197  const identifier::Schema& identifier,
198  identifier::table::vector &dropped_tables,
199  uint64_t &deleted)
200 {
201  plugin::StorageEngine::getIdentifiers(session, identifier, dropped_tables);
202 
203  for (identifier::table::vector::iterator it= dropped_tables.begin(); it != dropped_tables.end(); it++)
204  {
205  boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
206 
207  message::table::shared_ptr message= StorageEngine::getTableMessage(session, *it, false);
208  if (not message)
209  {
210  my_error(ER_TABLE_DROP, *it);
211  return false;
212  }
213 
214  table::Cache::removeTable(session, *it, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
215  if (not plugin::StorageEngine::dropTable(session, *it))
216  {
217  my_error(ER_TABLE_DROP, *it);
218  return false;
219  }
220  TransactionServices::dropTable(session, *it, *message, true);
221  deleted++;
222  }
223 
224  return true;
225 }
226 
227 bool StorageEngine::dropSchema(Session& session,
228  const identifier::Schema& identifier,
229  message::schema::const_reference schema_message)
230 {
231  uint64_t deleted= 0;
232  bool error= false;
233  identifier::table::vector dropped_tables;
234 
235  do
236  {
237  // Remove all temp tables first, this prevents loss of table from
238  // shadowing (ie temp over standard table)
239  {
240  // Lets delete the temporary tables first outside of locks.
241  identifier::table::vector set_of_identifiers;
242  session.open_tables.doGetTableIdentifiers(identifier, set_of_identifiers);
243 
244  for (identifier::table::vector::iterator iter= set_of_identifiers.begin(); iter != set_of_identifiers.end(); iter++)
245  {
246  if (session.open_tables.drop_temporary_table(*iter))
247  {
248  my_error(ER_TABLE_DROP, *iter);
249  error= true;
250  break;
251  }
252  }
253  }
254 
255  /* After deleting database, remove all cache entries related to schema */
256  table::Cache::removeSchema(identifier);
257 
258  if (not drop_all_tables_in_schema(session, identifier, dropped_tables, deleted))
259  {
260  error= true;
261  my_error(ER_DROP_SCHEMA, identifier);
262  break;
263  }
264 
265  uint64_t counter= 0;
266  // Add hook here for engines to register schema.
267  std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
268  DropSchema(identifier, counter));
269 
270  if (not counter)
271  {
272  my_error(ER_DROP_SCHEMA, identifier);
273  error= true;
274 
275  break;
276  }
277  else
278  {
279  /* We've already verified that the schema does exist, so safe to log it */
280  TransactionServices::dropSchema(session, identifier, schema_message);
281  }
282  } while (0);
283 
284  if (deleted > 0)
285  {
286  session.clear_error();
287  session.server_status|= SERVER_STATUS_DB_DROPPED;
288  session.my_ok((uint32_t) deleted);
289  session.server_status&= ~SERVER_STATUS_DB_DROPPED;
290  }
291 
292 
293  return error;
294 }
295 
296 class AlterSchema :
297  public std::unary_function<StorageEngine *, void>
298 {
299  uint64_t &success_count;
300  const drizzled::message::Schema &schema_message;
301 
302 public:
303 
304  AlterSchema(const drizzled::message::Schema &arg, uint64_t &count_arg) :
305  success_count(count_arg),
306  schema_message(arg)
307  {
308  }
309 
310  result_type operator() (argument_type engine)
311  {
312  // @todo eomeday check that at least one engine said "true"
313  bool success= engine->doAlterSchema(schema_message);
314 
315 
316  if (success)
317  {
318  success_count++;
319  }
320  }
321 };
322 
323 bool StorageEngine::alterSchema(const drizzled::message::Schema &schema_message)
324 {
325  uint64_t success_count= 0;
326 
327  std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
328  AlterSchema(schema_message, success_count));
329 
330  if (success_count)
331  {
332  TransactionServices::allocateNewTransactionId();
333  }
334 
335  return success_count ? true : false;
336 }
337 
338 } /* namespace plugin */
339 } /* namespace drizzled */