Drizzled Public API Documentation

schema.cc
1 /* Copyright (C) 2000-2003 MySQL AB
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
17 /* create and drop of databases */
18 #include <config.h>
19 
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 
24 #include <set>
25 #include <string>
26 #include <fstream>
27 
28 #include <drizzled/error.h>
29 #include <drizzled/gettext.h>
30 #include <drizzled/internal/m_string.h>
31 #include <drizzled/session.h>
32 #include <drizzled/schema.h>
33 #include <drizzled/sql_base.h>
34 #include <drizzled/lock.h>
35 #include <drizzled/errmsg_print.h>
36 #include <drizzled/transaction_services.h>
37 #include <drizzled/message/schema.pb.h>
38 #include <drizzled/sql_table.h>
39 #include <drizzled/plugin/storage_engine.h>
40 #include <drizzled/plugin/authorization.h>
41 #include <drizzled/pthread_globals.h>
42 #include <drizzled/charset.h>
43 #include <drizzled/internal/my_sys.h>
44 #include <drizzled/catalog/instance.h>
45 #include <boost/thread/mutex.hpp>
46 
47 using namespace std;
48 
49 namespace drizzled {
50 namespace schema {
51 
52 /*
53  Create a database
54 
55  SYNOPSIS
56  create_db()
57  session Thread handler
58  db Name of database to create
59  Function assumes that this is already validated.
60  create_info Database create options (like character set)
61 
62  SIDE-EFFECTS
63  1. Report back to client that command succeeded (my_ok)
64  2. Report errors to client
65  3. Log event to binary log
66 
67  RETURN VALUES
68  false ok
69  true Error
70 
71 */
72 
73 bool create(Session &session, const message::Schema &schema_message, const bool is_if_not_exists)
74 {
75  bool error= false;
76 
77  /*
78  Do not create database if another thread is holding read lock.
79  Wait for global read lock before acquiring session->catalog()->schemaLock().
80  After wait_if_global_read_lock() we have protection against another
81  global read lock. If we would acquire session->catalog()->schemaLock() first,
82  another thread could step in and get the global read lock before we
83  reach wait_if_global_read_lock(). If this thread tries the same as we
84  (admin a db), it would then go and wait on session->catalog()->schemaLock()...
85  Furthermore wait_if_global_read_lock() checks if the current thread
86  has the global read lock and refuses the operation with
87  ER_CANT_UPDATE_WITH_READLOCK if applicable.
88  */
89  if (session.wait_if_global_read_lock(false, true))
90  {
91  return false;
92  }
93 
94  assert(schema_message.has_name());
95  assert(schema_message.has_collation());
96 
97  // @todo push this lock down into the engine
98  {
99  boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
100 
101  // Check to see if it exists already.
102  identifier::Schema schema_identifier(schema_message.name());
103  if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
104  {
105  if (not is_if_not_exists)
106  {
107  my_error(ER_DB_CREATE_EXISTS, schema_identifier);
108  error= true;
109  }
110  else
111  {
112  push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
113  ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
114  schema_message.name().c_str());
115  session.my_ok();
116  }
117  }
118  else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
119  {
120  my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
121  error= true;
122  }
123  else // Created !
124  {
125  TransactionServices::createSchema(session, schema_message);
126  session.my_ok(1);
127  }
128  }
129  session.startWaitingGlobalReadLock();
130 
131  return error;
132 }
133 
134 
135 /* db-name is already validated when we come here */
136 
137 bool alter(Session &session,
138  const message::Schema &schema_message,
139  const message::Schema &original_schema)
140 {
141  /*
142  Do not alter database if another thread is holding read lock.
143  Wait for global read lock before acquiring session->catalog()->schemaLock().
144  After wait_if_global_read_lock() we have protection against another
145  global read lock. If we would acquire session->catalog()->schemaLock() first,
146  another thread could step in and get the global read lock before we
147  reach wait_if_global_read_lock(). If this thread tries the same as we
148  (admin a db), it would then go and wait on session->catalog()->schemaLock()...
149  Furthermore wait_if_global_read_lock() checks if the current thread
150  has the global read lock and refuses the operation with
151  ER_CANT_UPDATE_WITH_READLOCK if applicable.
152  */
153  if ((session.wait_if_global_read_lock(false, true)))
154  return false;
155 
156  bool success;
157  {
158  boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
159 
160  identifier::Schema schema_idenifier(schema_message.name());
161  if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
162  {
163  my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
164  return false;
165  }
166 
167  /* Change options if current database is being altered. */
168  success= plugin::StorageEngine::alterSchema(schema_message);
169 
170  if (success)
171  {
172  TransactionServices::alterSchema(session, original_schema, schema_message);
173  session.my_ok(1);
174  }
175  else
176  {
177  my_error(ER_ALTER_SCHEMA, schema_idenifier);
178  }
179  }
180  session.startWaitingGlobalReadLock();
181 
182  return success;
183 }
184 
185 
186 /*
187  Drop all tables in a database and the database itself
188 
189  SYNOPSIS
190  rm_db()
191  session Thread handle
192  db Database name in the case given by user
193  It's already validated and set to lower case
194  (if needed) when we come here
195  if_exists Don't give error if database doesn't exists
196  silent Don't generate errors
197 
198  RETURN
199  false ok (Database dropped)
200  ERROR Error
201 */
202 
203 bool drop(Session &session, const identifier::Schema &schema_identifier, bool if_exists)
204 {
205  /*
206  Do not drop database if another thread is holding read lock.
207  Wait for global read lock before acquiring session->catalog()->schemaLock().
208  After wait_if_global_read_lock() we have protection against another
209  global read lock. If we would acquire session->catalog()->schemaLock() first,
210  another thread could step in and get the global read lock before we
211  reach wait_if_global_read_lock(). If this thread tries the same as we
212  (admin a db), it would then go and wait on session->catalog()->schemaLock()...
213  Furthermore wait_if_global_read_lock() checks if the current thread
214  has the global read lock and refuses the operation with
215  ER_CANT_UPDATE_WITH_READLOCK if applicable.
216  */
217  if (session.wait_if_global_read_lock(false, true))
218  {
219  return true;
220  }
221 
222  bool error= false;
223  {
224  boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
225  if (message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier))
226  {
227  error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
228  }
229  else if (if_exists)
230  {
231  push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE, ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
232  schema_identifier.getSQLPath().c_str());
233  }
234  else
235  {
236  error= true;
237  my_error(ER_DB_DROP_EXISTS, schema_identifier);
238  }
239  };
240 
241  /*
242  If this database was the client's selected database, we silently
243  change the client's selected database to nothing (to have an empty
244  SELECT DATABASE() in the future). For this we free() session->db and set
245  it to 0.
246  */
247  if (not error and schema_identifier.compare(*session.schema()))
248  session.set_schema("");
249 
250  session.startWaitingGlobalReadLock();
251 
252  return error;
253 }
254 
317 bool change(Session &session, const identifier::Schema &schema_identifier)
318 {
319 
320  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
321  {
322  /* Error message is set in isAuthorized */
323  return true;
324  }
325 
326  if (not check(session, schema_identifier))
327  {
328  my_error(ER_WRONG_DB_NAME, schema_identifier);
329 
330  return true;
331  }
332 
333  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
334  {
335  my_error(ER_BAD_DB_ERROR, schema_identifier);
336 
337  /* The operation failed. */
338 
339  return true;
340  }
341 
342  session.set_schema(schema_identifier.getSchemaName());
343 
344  return false;
345 }
346 
359 /*
360  Check if database name is valid
361 
362  SYNPOSIS
363  check()
364  org_name Name of database and length
365 
366  RETURN
367  false error
368  true ok
369 */
370 
371 bool check(Session &session, const identifier::Schema &schema_identifier)
372 {
373  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
374  return false;
375  return schema_identifier.isValid();
376 }
377 
378 } /* namespace schema */
379 
380 } /* namespace drizzled */