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(session.catalog().identifier(),
103  schema_message.name());
104  if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
105  {
106  if (not is_if_not_exists)
107  {
108  my_error(ER_DB_CREATE_EXISTS, schema_identifier);
109  error= true;
110  }
111  else
112  {
113  push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
114  ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
115  schema_message.name().c_str());
116  session.my_ok();
117  }
118  }
119  else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
120  {
121  my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
122  error= true;
123  }
124  else // Created !
125  {
126  TransactionServices::createSchema(session, schema_message);
127  session.my_ok(1);
128  }
129  }
130  session.startWaitingGlobalReadLock();
131 
132  return error;
133 }
134 
135 
136 /* db-name is already validated when we come here */
137 
138 bool alter(Session &session,
139  const message::Schema &schema_message,
140  const message::Schema &original_schema)
141 {
142  /*
143  Do not alter database if another thread is holding read lock.
144  Wait for global read lock before acquiring session->catalog()->schemaLock().
145  After wait_if_global_read_lock() we have protection against another
146  global read lock. If we would acquire session->catalog()->schemaLock() first,
147  another thread could step in and get the global read lock before we
148  reach wait_if_global_read_lock(). If this thread tries the same as we
149  (admin a db), it would then go and wait on session->catalog()->schemaLock()...
150  Furthermore wait_if_global_read_lock() checks if the current thread
151  has the global read lock and refuses the operation with
152  ER_CANT_UPDATE_WITH_READLOCK if applicable.
153  */
154  if ((session.wait_if_global_read_lock(false, true)))
155  return false;
156 
157  bool success;
158  {
159  boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
160 
161  identifier::Schema schema_idenifier(session.catalog().identifier(),
162  schema_message.name());
163  if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
164  {
165  my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
166  return false;
167  }
168 
169  /* Change options if current database is being altered. */
170  success= plugin::StorageEngine::alterSchema(schema_message);
171 
172  if (success)
173  {
174  TransactionServices::alterSchema(session, original_schema, schema_message);
175  session.my_ok(1);
176  }
177  else
178  {
179  my_error(ER_ALTER_SCHEMA, schema_idenifier);
180  }
181  }
182  session.startWaitingGlobalReadLock();
183 
184  return success;
185 }
186 
187 
188 /*
189  Drop all tables in a database and the database itself
190 
191  SYNOPSIS
192  rm_db()
193  session Thread handle
194  db Database name in the case given by user
195  It's already validated and set to lower case
196  (if needed) when we come here
197  if_exists Don't give error if database doesn't exists
198  silent Don't generate errors
199 
200  RETURN
201  false ok (Database dropped)
202  ERROR Error
203 */
204 
205 bool drop(Session &session, const identifier::Schema &schema_identifier, bool if_exists)
206 {
207  /*
208  Do not drop database if another thread is holding read lock.
209  Wait for global read lock before acquiring session->catalog()->schemaLock().
210  After wait_if_global_read_lock() we have protection against another
211  global read lock. If we would acquire session->catalog()->schemaLock() first,
212  another thread could step in and get the global read lock before we
213  reach wait_if_global_read_lock(). If this thread tries the same as we
214  (admin a db), it would then go and wait on session->catalog()->schemaLock()...
215  Furthermore wait_if_global_read_lock() checks if the current thread
216  has the global read lock and refuses the operation with
217  ER_CANT_UPDATE_WITH_READLOCK if applicable.
218  */
219  if (session.wait_if_global_read_lock(false, true))
220  {
221  return true;
222  }
223 
224  bool error= false;
225  {
226  boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
227  if (message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier))
228  {
229  error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
230  }
231  else if (if_exists)
232  {
233  push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE, ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
234  schema_identifier.getSQLPath().c_str());
235  }
236  else
237  {
238  error= true;
239  my_error(ER_DB_DROP_EXISTS, schema_identifier);
240  }
241  };
242 
243  /*
244  If this database was the client's selected database, we silently
245  change the client's selected database to nothing (to have an empty
246  SELECT DATABASE() in the future). For this we free() session->db and set
247  it to 0.
248  */
249  if (not error and schema_identifier.compare(*session.schema()))
250  session.set_schema("");
251 
252  session.startWaitingGlobalReadLock();
253 
254  return error;
255 }
256 
319 bool change(Session &session, const identifier::Schema &schema_identifier)
320 {
321 
322  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
323  {
324  /* Error message is set in isAuthorized */
325  return true;
326  }
327 
328  if (not check(session, schema_identifier))
329  {
330  my_error(ER_WRONG_DB_NAME, schema_identifier);
331 
332  return true;
333  }
334 
335  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
336  {
337  my_error(ER_BAD_DB_ERROR, schema_identifier);
338 
339  /* The operation failed. */
340 
341  return true;
342  }
343 
344  session.set_schema(schema_identifier.getSchemaName());
345 
346  return false;
347 }
348 
361 /*
362  Check if database name is valid
363 
364  SYNPOSIS
365  check()
366  org_name Name of database and length
367 
368  RETURN
369  false error
370  true ok
371 */
372 
373 bool check(Session &session, const identifier::Schema &schema_identifier)
374 {
375  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
376  return false;
377  return schema_identifier.isValid();
378 }
379 
380 } /* namespace schema */
381 
382 } /* namespace drizzled */