Drizzled Public API Documentation

schema.cc
00001 /* Copyright (C) 2000-2003 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 
00017 /* create and drop of databases */
00018 #include <config.h>
00019 
00020 #include <fcntl.h>
00021 #include <sys/stat.h>
00022 #include <sys/types.h>
00023 
00024 #include <set>
00025 #include <string>
00026 #include <fstream>
00027 
00028 #include <drizzled/error.h>
00029 #include <drizzled/gettext.h>
00030 #include <drizzled/internal/m_string.h>
00031 #include <drizzled/session.h>
00032 #include <drizzled/schema.h>
00033 #include <drizzled/sql_base.h>
00034 #include <drizzled/lock.h>
00035 #include <drizzled/errmsg_print.h>
00036 #include <drizzled/transaction_services.h>
00037 #include <drizzled/message/schema.pb.h>
00038 #include <drizzled/sql_table.h>
00039 #include <drizzled/plugin/storage_engine.h>
00040 #include <drizzled/plugin/authorization.h>
00041 #include <drizzled/pthread_globals.h>
00042 #include <drizzled/charset.h>
00043 #include <drizzled/internal/my_sys.h>
00044 #include <drizzled/catalog/instance.h>
00045 #include <boost/thread/mutex.hpp>
00046 
00047 using namespace std;
00048 
00049 namespace drizzled {
00050 namespace schema {
00051 
00052 /*
00053   Create a database
00054 
00055   SYNOPSIS
00056   create_db()
00057   session   Thread handler
00058   db    Name of database to create
00059     Function assumes that this is already validated.
00060   create_info Database create options (like character set)
00061 
00062   SIDE-EFFECTS
00063    1. Report back to client that command succeeded (my_ok)
00064    2. Report errors to client
00065    3. Log event to binary log
00066 
00067   RETURN VALUES
00068   false ok
00069   true  Error
00070 
00071 */
00072 
00073 bool create(Session &session, const message::Schema &schema_message, const bool is_if_not_exists)
00074 {
00075   bool error= false;
00076 
00077   /*
00078     Do not create database if another thread is holding read lock.
00079     Wait for global read lock before acquiring session->catalog()->schemaLock().
00080     After wait_if_global_read_lock() we have protection against another
00081     global read lock. If we would acquire session->catalog()->schemaLock() first,
00082     another thread could step in and get the global read lock before we
00083     reach wait_if_global_read_lock(). If this thread tries the same as we
00084     (admin a db), it would then go and wait on session->catalog()->schemaLock()...
00085     Furthermore wait_if_global_read_lock() checks if the current thread
00086     has the global read lock and refuses the operation with
00087     ER_CANT_UPDATE_WITH_READLOCK if applicable.
00088   */
00089   if (session.wait_if_global_read_lock(false, true))
00090   {
00091     return false;
00092   }
00093 
00094   assert(schema_message.has_name());
00095   assert(schema_message.has_collation());
00096 
00097   // @todo push this lock down into the engine
00098   {
00099     boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
00100 
00101     // Check to see if it exists already.  
00102     identifier::Schema schema_identifier(schema_message.name());
00103     if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
00104     {
00105       if (not is_if_not_exists)
00106       {
00107         my_error(ER_DB_CREATE_EXISTS, schema_identifier);
00108         error= true;
00109       }
00110       else
00111       {
00112         push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
00113                             ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
00114                             schema_message.name().c_str());
00115         session.my_ok();
00116       }
00117     }
00118     else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
00119     {
00120       my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
00121       error= true;
00122     }
00123     else // Created !
00124     {
00125       TransactionServices::createSchema(session, schema_message);
00126       session.my_ok(1);
00127     }
00128   }
00129   session.startWaitingGlobalReadLock();
00130 
00131   return error;
00132 }
00133 
00134 
00135 /* db-name is already validated when we come here */
00136 
00137 bool alter(Session &session,
00138            const message::Schema &schema_message,
00139            const message::Schema &original_schema)
00140 {
00141   /*
00142     Do not alter database if another thread is holding read lock.
00143     Wait for global read lock before acquiring session->catalog()->schemaLock().
00144     After wait_if_global_read_lock() we have protection against another
00145     global read lock. If we would acquire session->catalog()->schemaLock() first,
00146     another thread could step in and get the global read lock before we
00147     reach wait_if_global_read_lock(). If this thread tries the same as we
00148     (admin a db), it would then go and wait on session->catalog()->schemaLock()...
00149     Furthermore wait_if_global_read_lock() checks if the current thread
00150     has the global read lock and refuses the operation with
00151     ER_CANT_UPDATE_WITH_READLOCK if applicable.
00152   */
00153   if ((session.wait_if_global_read_lock(false, true)))
00154     return false;
00155 
00156   bool success;
00157   {
00158     boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
00159 
00160     identifier::Schema schema_idenifier(schema_message.name());
00161     if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
00162     {
00163       my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
00164       return false;
00165     }
00166 
00167     /* Change options if current database is being altered. */
00168     success= plugin::StorageEngine::alterSchema(schema_message);
00169 
00170     if (success)
00171     {
00172       TransactionServices::alterSchema(session, original_schema, schema_message);
00173       session.my_ok(1);
00174     }
00175     else
00176     {
00177       my_error(ER_ALTER_SCHEMA, schema_idenifier);
00178     }
00179   }
00180   session.startWaitingGlobalReadLock();
00181 
00182   return success;
00183 }
00184 
00185 
00186 /*
00187   Drop all tables in a database and the database itself
00188 
00189   SYNOPSIS
00190     rm_db()
00191     session     Thread handle
00192     db      Database name in the case given by user
00193             It's already validated and set to lower case
00194                         (if needed) when we come here
00195     if_exists   Don't give error if database doesn't exists
00196     silent    Don't generate errors
00197 
00198   RETURN
00199     false ok (Database dropped)
00200     ERROR Error
00201 */
00202 
00203 bool drop(Session &session, const identifier::Schema &schema_identifier, bool if_exists)
00204 {
00205   /*
00206     Do not drop database if another thread is holding read lock.
00207     Wait for global read lock before acquiring session->catalog()->schemaLock().
00208     After wait_if_global_read_lock() we have protection against another
00209     global read lock. If we would acquire session->catalog()->schemaLock() first,
00210     another thread could step in and get the global read lock before we
00211     reach wait_if_global_read_lock(). If this thread tries the same as we
00212     (admin a db), it would then go and wait on session->catalog()->schemaLock()...
00213     Furthermore wait_if_global_read_lock() checks if the current thread
00214     has the global read lock and refuses the operation with
00215     ER_CANT_UPDATE_WITH_READLOCK if applicable.
00216   */
00217   if (session.wait_if_global_read_lock(false, true))
00218   {
00219     return true;
00220   }
00221 
00222   bool error= false;
00223   {
00224     boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
00225     if (message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier))
00226     {
00227       error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
00228     }
00229     else if (if_exists)
00230     {
00231       push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE, ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
00232                           schema_identifier.getSQLPath().c_str());
00233     }
00234     else
00235     {
00236       error= true;
00237       my_error(ER_DB_DROP_EXISTS, schema_identifier);
00238     }
00239   };
00240 
00241   /*
00242     If this database was the client's selected database, we silently
00243     change the client's selected database to nothing (to have an empty
00244     SELECT DATABASE() in the future). For this we free() session->db and set
00245     it to 0.
00246   */
00247   if (not error and schema_identifier.compare(*session.schema()))
00248     session.set_schema("");
00249 
00250   session.startWaitingGlobalReadLock();
00251 
00252   return error;
00253 }
00254 
00317 bool change(Session &session, const identifier::Schema &schema_identifier)
00318 {
00319 
00320   if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
00321   {
00322     /* Error message is set in isAuthorized */
00323     return true;
00324   }
00325 
00326   if (not check(session, schema_identifier))
00327   {
00328     my_error(ER_WRONG_DB_NAME, schema_identifier);
00329 
00330     return true;
00331   }
00332 
00333   if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
00334   {
00335     my_error(ER_BAD_DB_ERROR, schema_identifier);
00336 
00337     /* The operation failed. */
00338 
00339     return true;
00340   }
00341 
00342   session.set_schema(schema_identifier.getSchemaName());
00343 
00344   return false;
00345 }
00346 
00359 /*
00360   Check if database name is valid
00361 
00362   SYNPOSIS
00363     check()
00364     org_name    Name of database and length
00365 
00366   RETURN
00367     false error
00368     true ok
00369 */
00370 
00371 bool check(Session &session, const identifier::Schema &schema_identifier)
00372 {
00373   if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
00374     return false;
00375   return schema_identifier.isValid();
00376 }
00377 
00378 } /* namespace schema */
00379 
00380 } /* namespace drizzled */