Drizzled Public API Documentation

session.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00024 #include <config.h>
00025 
00026 #include <boost/checked_delete.hpp>
00027 #include <boost/filesystem.hpp>
00028 #include <boost/ptr_container/ptr_container.hpp>
00029 #include <drizzled/copy_field.h>
00030 #include <drizzled/catalog/local.h>
00031 #include <drizzled/diagnostics_area.h>
00032 #include <drizzled/display.h>
00033 #include <drizzled/drizzled.h>
00034 #include <drizzled/error.h>
00035 #include <drizzled/gettext.h>
00036 #include <drizzled/ha_data.h>
00037 #include <drizzled/identifier.h>
00038 #include <drizzled/internal/iocache.h>
00039 #include <drizzled/internal/thread_var.h>
00040 #include <drizzled/item/cache.h>
00041 #include <drizzled/item/empty_string.h>
00042 #include <drizzled/item/float.h>
00043 #include <drizzled/item/return_int.h>
00044 #include <drizzled/item/subselect.h>
00045 #include <drizzled/lock.h>
00046 #include <drizzled/open_tables_state.h>
00047 #include <drizzled/plugin/authentication.h>
00048 #include <drizzled/plugin/authorization.h>
00049 #include <drizzled/plugin/client.h>
00050 #include <drizzled/plugin/event_observer.h>
00051 #include <drizzled/plugin/logging.h>
00052 #include <drizzled/plugin/query_rewrite.h>
00053 #include <drizzled/plugin/scheduler.h>
00054 #include <drizzled/plugin/transactional_storage_engine.h>
00055 #include <drizzled/probes.h>
00056 #include <drizzled/pthread_globals.h>
00057 #include <drizzled/schema.h>
00058 #include <drizzled/select_dump.h>
00059 #include <drizzled/select_exists_subselect.h>
00060 #include <drizzled/select_export.h>
00061 #include <drizzled/select_max_min_finder_subselect.h>
00062 #include <drizzled/select_singlerow_subselect.h>
00063 #include <drizzled/select_subselect.h>
00064 #include <drizzled/select_to_file.h>
00065 #include <drizzled/session.h>
00066 #include <drizzled/session/cache.h>
00067 #include <drizzled/session/state.h>
00068 #include <drizzled/session/table_messages.h>
00069 #include <drizzled/session/times.h>
00070 #include <drizzled/session/transactions.h>
00071 #include <drizzled/show.h>
00072 #include <drizzled/sql_base.h>
00073 #include <drizzled/sql_lex.h>
00074 #include <drizzled/system_variables.h>
00075 #include <drizzled/statement.h>
00076 #include <drizzled/statistics_variables.h>
00077 #include <drizzled/table/singular.h>
00078 #include <drizzled/table_proto.h>
00079 #include <drizzled/tmp_table_param.h>
00080 #include <drizzled/transaction_services.h>
00081 #include <drizzled/user_var_entry.h>
00082 #include <drizzled/util/backtrace.h>
00083 #include <drizzled/util/find_ptr.h>
00084 #include <drizzled/util/functors.h>
00085 #include <drizzled/util/storable.h>
00086 #include <plugin/myisam/myisam.h>
00087 
00088 #include <algorithm>
00089 #include <climits>
00090 #include <fcntl.h>
00091 #include <sys/stat.h>
00092 
00093 using namespace std;
00094 
00095 namespace fs= boost::filesystem;
00096 
00097 namespace drizzled {
00098 
00099 const char* const Session::DEFAULT_WHERE= "field list";
00100 
00101 uint64_t g_refresh_version = 1;
00102 
00103 bool Key_part_spec::operator==(const Key_part_spec& other) const
00104 {
00105   return length == other.length 
00106     && field_name.size() == other.field_name.size()
00107     && not system_charset_info->strcasecmp(field_name.data(), other.field_name.data());
00108 }
00109 
00110 Open_tables_state::Open_tables_state(Session& session, uint64_t version_arg) :
00111   version(version_arg),
00112   session_(session)
00113 {
00114   open_tables_= temporary_tables= derived_tables= NULL;
00115   extra_lock= lock= NULL;
00116 }
00117 
00118 /*
00119   The following functions form part of the C plugin API
00120 */
00121 int tmpfile(const char *prefix)
00122 {
00123   char filename[FN_REFLEN];
00124   int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
00125   if (fd >= 0)
00126     unlink(filename);
00127   return fd;
00128 }
00129 
00130 void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
00131 {
00132   return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
00133 }
00134 
00135 ResourceContext& Session::getResourceContext(const plugin::MonitoredInTransaction& monitored, size_t index)
00136 {
00137   return ha_data[monitored.getId()].resource_context[index];
00138 }
00139 
00140 int64_t session_test_options(const Session *session, int64_t test_options)
00141 {
00142   return session->options & test_options;
00143 }
00144 
00145 class Session::impl_c
00146 {
00147 public:
00148   typedef boost::unordered_map<std::string, util::Storable*, util::insensitive_hash, util::insensitive_equal_to> properties_t;
00149   typedef std::map<std::string, plugin::EventObserverList*> schema_event_observers_t;
00150 
00151   impl_c(Session& session) :
00152     open_tables(session, g_refresh_version),
00153     schema(boost::make_shared<std::string>())
00154   {
00155   }
00156 
00157   ~impl_c()
00158   {
00159     BOOST_FOREACH(properties_t::reference it, properties)
00160       delete it.second;
00161   }
00162 
00163   Diagnostics_area diagnostics;
00164   memory::Root mem_root;
00165 
00172   LEX lex;
00173   Open_tables_state open_tables;
00174   properties_t properties;
00175   schema_event_observers_t schema_event_observers;
00176   system_status_var status_var;
00177   session::TableMessages table_message_cache;
00178   util::string::mptr schema;
00179   boost::shared_ptr<session::State> state;
00180   boost::ptr_vector<table::Singular> temporary_shares;
00181   session::Times times;
00182   session::Transactions transaction;
00183   drizzle_system_variables variables;
00184 };
00185 
00186 Session::Session(plugin::Client *client_arg, catalog::Instance::shared_ptr catalog_arg) :
00187   impl_(new impl_c(*this)),
00188   mem(impl_->mem_root),
00189   mem_root(&impl_->mem_root),
00190   query(new std::string),
00191   scheduler(NULL),
00192   variables(impl_->variables),
00193   status_var(impl_->status_var),
00194   lock_id(&main_lock_id),
00195   thread_stack(NULL),
00196   _where(Session::DEFAULT_WHERE),
00197   mysys_var(0),
00198   command(COM_CONNECT),
00199   ha_data(plugin::num_trx_monitored_objects),
00200   query_id(0),
00201   warn_query_id(0),
00202   transaction(impl_->transaction),
00203   open_tables(impl_->open_tables),
00204   times(impl_->times),
00205   first_successful_insert_id_in_prev_stmt(0),
00206   first_successful_insert_id_in_cur_stmt(0),
00207   limit_found_rows(0),
00208   options(session_startup_options),
00209   row_count_func(-1),
00210   sent_row_count(0),
00211   examined_row_count(0),
00212   used_tables(0),
00213   total_warn_count(0),
00214   row_count(0),
00215   thread_id(0),
00216   tmp_table(0),
00217   _global_read_lock(NONE),
00218   count_cuted_fields(CHECK_FIELD_ERROR_FOR_NULL),
00219   _killed(NOT_KILLED),
00220   no_errors(false),
00221   is_fatal_error(false),
00222   transaction_rollback_request(false),
00223   is_fatal_sub_stmt_error(0),
00224   derived_tables_processing(false),
00225   m_lip(NULL),
00226   arg_of_last_insert_id_function(false),
00227   _catalog(catalog_arg),
00228   transaction_message(NULL),
00229   statement_message(NULL),
00230   session_event_observers(NULL),
00231   xa_id(0),
00232   concurrent_execute_allowed(true),
00233   tablespace_op(false),
00234   use_usage(false),
00235   security_ctx(identifier::User::make_shared()),
00236   originating_server_uuid_set(false),
00237   client(client_arg)
00238 {
00239   client->setSession(this);
00240 
00241   /*
00242     Pass nominal parameters to init only to ensure that
00243     the destructor works OK in case of an error. The main_mem_root
00244     will be re-initialized in init_for_queries().
00245   */
00246   mem.init(memory::ROOT_MIN_BLOCK_SIZE);
00247   cuted_fields= sent_row_count= row_count= 0L;
00248   // Must be reset to handle error with Session's created for init of mysqld
00249   lex().current_select= 0;
00250   memset(&variables, 0, sizeof(variables));
00251   scoreboard_index= -1;
00252   originating_server_uuid= "";
00253   originating_commit_id= 0;
00254   cleanup_done= abort_on_warning= no_warnings_for_error= false;
00255 
00256   resultset= NULL;
00257 
00258   /* Variables with default values */
00259   proc_info="login";
00260 
00261   plugin_sessionvar_init(this);
00262   /*
00263     variables= global_system_variables above has reset
00264     variables.pseudo_thread_id to 0. We need to correct it here to
00265     avoid temporary tables replication failure.
00266   */
00267   variables.pseudo_thread_id= thread_id;
00268   server_status= SERVER_STATUS_AUTOCOMMIT;
00269 
00270   if (variables.max_join_size == HA_POS_ERROR)
00271     options |= OPTION_BIG_SELECTS;
00272   else
00273     options &= ~OPTION_BIG_SELECTS;
00274 
00275   open_options=ha_open_options;
00276   update_lock_default= TL_WRITE;
00277   session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
00278   memset(warn_count, 0, sizeof(warn_count));
00279   memset(&status_var, 0, sizeof(status_var));
00280 
00281   /* Initialize sub structures */
00282   warn_root.init(WARN_ALLOC_BLOCK_SIZE);
00283 
00284   substitute_null_with_insert_id = false;
00285   lock_info.init(); /* safety: will be reset after start */
00286   main_lock_id.info= &lock_info;
00287 
00288   plugin::EventObserver::registerSessionEvents(*this);
00289 }
00290 
00291 Diagnostics_area& Session::main_da()
00292 {
00293   return impl_->diagnostics;
00294 }
00295 
00296 const LEX& Session::lex() const
00297 {
00298   return impl_->lex;
00299 }
00300 
00301 LEX& Session::lex()
00302 {
00303   return impl_->lex;
00304 }
00305 
00306 enum_sql_command Session::getSqlCommand() const
00307 {
00308   return lex().sql_command;
00309 }
00310 
00311 session::TableMessages& Session::getMessageCache()
00312 {
00313   return impl_->table_message_cache;
00314 }
00315 
00316 void statement::Statement::set_command(enum_sql_command v)
00317 {
00318   session().lex().sql_command= v;
00319 }
00320 
00321 LEX& statement::Statement::lex()
00322 {
00323   return session().lex();
00324 }
00325 
00326 session::Transactions& statement::Statement::transaction()
00327 {
00328   return session().transaction;
00329 }
00330 
00331 void Session::add_item_to_list(Item *item)
00332 {
00333   lex().current_select->add_item_to_list(this, item);
00334 }
00335 
00336 void Session::add_value_to_list(Item *value)
00337 {
00338   lex().value_list.push_back(value);
00339 }
00340 
00341 void Session::add_order_to_list(Item *item, bool asc)
00342 {
00343   lex().current_select->add_order_to_list(this, item, asc);
00344 }
00345 
00346 void Session::add_group_to_list(Item *item, bool asc)
00347 {
00348   lex().current_select->add_group_to_list(this, item, asc);
00349 }
00350 
00351 void Session::free_items()
00352 {
00353   /* This works because items are allocated with memory::sql_alloc() */
00354   for (Item* next; free_list; free_list= next)
00355   {
00356     next= free_list->next;
00357     free_list->delete_self();
00358   }
00359 }
00360 
00361 void Session::setAbort(bool arg)
00362 {
00363   mysys_var->abort= arg;
00364 }
00365 
00366 void Session::lockOnSys()
00367 {
00368   if (not mysys_var)
00369     return;
00370 
00371   setAbort(true);
00372   boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
00373   if (mysys_var->current_cond)
00374   {
00375     mysys_var->current_mutex->lock();
00376     mysys_var->current_cond->notify_all();
00377     mysys_var->current_mutex->unlock();
00378   }
00379 }
00380 
00381 void Session::get_xid(DrizzleXid *xid) const
00382 {
00383   *xid = *(DrizzleXid *) &transaction.xid_state.xid;
00384 }
00385 
00386 /* Do operations that may take a long time */
00387 
00388 void Session::cleanup()
00389 {
00390   assert(not cleanup_done);
00391 
00392   setKilled(KILL_CONNECTION);
00393 #ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
00394   if (transaction.xid_state.xa_state == XA_PREPARED)
00395   {
00396 #error xid_state in the cache should be replaced by the allocated value
00397   }
00398 #endif
00399   {
00400     TransactionServices::rollbackTransaction(*this, true);
00401   }
00402 
00403   BOOST_FOREACH(UserVars::reference iter, user_vars)
00404     boost::checked_delete(iter.second);
00405   user_vars.clear();
00406 
00407   open_tables.close_temporary_tables();
00408 
00409   if (global_read_lock)
00410     unlockGlobalReadLock();
00411 
00412   cleanup_done= true;
00413 }
00414 
00415 Session::~Session()
00416 {
00417   if (client and client->isConnected())
00418   {
00419     assert(security_ctx);
00420     if (global_system_variables.log_warnings)
00421     {
00422       errmsg_printf(error::WARN, ER(ER_FORCING_CLOSE), internal::my_progname, thread_id, security_ctx->username().c_str());
00423     }
00424 
00425     disconnect();
00426   }
00427 
00428   /* Close connection */
00429   if (client)
00430   {
00431     client->close();
00432     boost::checked_delete(client);
00433     client= NULL;
00434   }
00435 
00436   if (not cleanup_done)
00437     cleanup();
00438 
00439   plugin::StorageEngine::closeConnection(*this);
00440   plugin_sessionvar_cleanup(this);
00441 
00442   warn_root.free_root(MYF(0));
00443   mysys_var=0;          // Safety (shouldn't be needed)
00444 
00445   impl_->mem_root.free_root(MYF(0));
00446   setCurrentMemRoot(NULL);
00447   setCurrentSession(NULL);
00448 
00449   plugin::Logging::postEndDo(this);
00450   plugin::EventObserver::deregisterSessionEvents(session_event_observers); 
00451 
00452   BOOST_FOREACH(impl_c::schema_event_observers_t::reference it, impl_->schema_event_observers)
00453     plugin::EventObserver::deregisterSchemaEvents(it.second);
00454 }
00455 
00456 void Session::setClient(plugin::Client *client_arg)
00457 {
00458   client= client_arg;
00459   client->setSession(this);
00460 }
00461 
00462 void Session::awake(Session::killed_state_t state_to_set)
00463 {
00464   if (state_to_set == Session::KILL_QUERY && command == COM_SLEEP)
00465     return;
00466 
00467   setKilled(state_to_set);
00468   scheduler->killSession(this);
00469 
00470   if (state_to_set != Session::KILL_QUERY)
00471   {
00472     DRIZZLE_CONNECTION_DONE(thread_id);
00473   }
00474 
00475   if (mysys_var)
00476   {
00477     boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
00478     /*
00479       "
00480       This broadcast could be up in the air if the victim thread
00481       exits the cond in the time between read and broadcast, but that is
00482       ok since all we want to do is to make the victim thread get out
00483       of waiting on current_cond.
00484       If we see a non-zero current_cond: it cannot be an old value (because
00485       then exit_cond() should have run and it can't because we have mutex); so
00486       it is the true value but maybe current_mutex is not yet non-zero (we're
00487       in the middle of enter_cond() and there is a "memory order
00488       inversion"). So we test the mutex too to not lock 0.
00489 
00490       Note that there is a small chance we fail to kill. If victim has locked
00491       current_mutex, but hasn't yet entered enter_cond() (which means that
00492       current_cond and current_mutex are 0), then the victim will not get
00493       a signal and it may wait "forever" on the cond (until
00494       we issue a second KILL or the status it's waiting for happens).
00495       It's true that we have set its session->killed but it may not
00496       see it immediately and so may have time to reach the cond_wait().
00497     */
00498     if (mysys_var->current_cond && mysys_var->current_mutex)
00499     {
00500       mysys_var->current_mutex->lock();
00501       mysys_var->current_cond->notify_all();
00502       mysys_var->current_mutex->unlock();
00503     }
00504   }
00505 }
00506 
00507 /*
00508   Remember the location of thread info, the structure needed for
00509   memory::sql_alloc() and the structure for the net buffer
00510 */
00511 void Session::storeGlobals()
00512 {
00513   /*
00514     Assert that thread_stack is initialized: it's necessary to be able
00515     to track stack overrun.
00516   */
00517   assert(thread_stack);
00518   setCurrentSession(this);
00519   setCurrentMemRoot(&mem);
00520 
00521   mysys_var= internal::my_thread_var2().get();
00522 
00523   /*
00524     Let mysqld define the thread id (not mysys)
00525     This allows us to move Session to different threads if needed.
00526   */
00527   mysys_var->id= thread_id;
00528 
00529   /*
00530     We have to call thr_lock_info_init() again here as Session may have been
00531     created in another thread
00532   */
00533   lock_info.init();
00534 }
00535 
00536 /*
00537   Init Session for query processing.
00538   This has to be called once before we call mysql_parse.
00539   See also comments in session.h.
00540 */
00541 
00542 void Session::prepareForQueries()
00543 {
00544   if (variables.max_join_size == HA_POS_ERROR)
00545     options |= OPTION_BIG_SELECTS;
00546 
00547   open_tables.version= g_refresh_version;
00548   set_proc_info(NULL);
00549   command= COM_SLEEP;
00550   times.set_time();
00551 
00552   mem.reset_defaults(variables.query_alloc_block_size, variables.query_prealloc_size);
00553   transaction.xid_state.xid.set_null();
00554   transaction.xid_state.in_session=1;
00555   if (use_usage)
00556     resetUsage();
00557 }
00558 
00559 void Session::run()
00560 {
00561   storeGlobals();
00562   if (authenticate())
00563   {
00564     disconnect();
00565     return;
00566   }
00567   prepareForQueries();
00568   while (not client->haveError() && getKilled() != KILL_CONNECTION)
00569   {
00570     if (not executeStatement())
00571       break;
00572   }
00573   disconnect();
00574 }
00575 
00576 bool Session::schedule(const shared_ptr& arg)
00577 {
00578   arg->scheduler= plugin::Scheduler::getScheduler();
00579   assert(arg->scheduler);
00580 
00581   ++connection_count;
00582 
00583   long current_connections= connection_count;
00584 
00585   if (current_connections > 0 and static_cast<uint64_t>(current_connections) > current_global_counters.max_used_connections)
00586   {
00587     current_global_counters.max_used_connections= static_cast<uint64_t>(connection_count);
00588   }
00589 
00590   current_global_counters.connections++;
00591   arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
00592 
00593   session::Cache::insert(arg);
00594 
00595   if (unlikely(plugin::EventObserver::connectSession(*arg)))
00596   {
00597     // We should do something about an error...
00598   }
00599 
00600   if (plugin::Scheduler::getScheduler()->addSession(arg))
00601   {
00602     DRIZZLE_CONNECTION_START(arg->getSessionId());
00603     char error_message_buff[DRIZZLE_ERRMSG_SIZE];
00604 
00605     arg->setKilled(Session::KILL_CONNECTION);
00606 
00607     arg->status_var.aborted_connects++;
00608 
00609     /* Can't use my_error() since store_globals has not been called. */
00610     /* TODO replace will better error message */
00611     snprintf(error_message_buff, sizeof(error_message_buff), ER(ER_CANT_CREATE_THREAD), 1);
00612     arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
00613     return true;
00614   }
00615   return false;
00616 }
00617 
00618 
00619 /*
00620   Is this session viewable by the current user?
00621 */
00622 bool Session::isViewable(const identifier::User& user_arg) const
00623 {
00624   return plugin::Authorization::isAuthorized(user_arg, *this, false);
00625 }
00626 
00627 
00628 const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
00629 {
00630   const char* old_msg = get_proc_info();
00631   safe_mutex_assert_owner(mutex);
00632   mysys_var->current_mutex = &mutex;
00633   mysys_var->current_cond = &cond;
00634   this->set_proc_info(msg);
00635   return old_msg;
00636 }
00637 
00638 void Session::exit_cond(const char* old_msg)
00639 {
00640   /*
00641     Putting the mutex unlock in exit_cond() ensures that
00642     mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
00643     locked (if that would not be the case, you'll get a deadlock if someone
00644     does a Session::awake() on you).
00645   */
00646   mysys_var->current_mutex->unlock();
00647   boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
00648   mysys_var->current_mutex = 0;
00649   mysys_var->current_cond = 0;
00650   this->set_proc_info(old_msg);
00651 }
00652 
00653 bool Session::authenticate()
00654 {
00655   if (client->authenticate())
00656     return false;
00657 
00658   status_var.aborted_connects++;
00659 
00660   return true;
00661 }
00662 
00663 bool Session::checkUser(const std::string &passwd_str, const std::string &in_db)
00664 {
00665   if (not plugin::Authentication::isAuthenticated(*user(), passwd_str))
00666   {
00667     status_var.access_denied++;
00668     /* isAuthenticated has pushed the error message */
00669     return false;
00670   }
00671 
00672   /* Change database if necessary */
00673   if (not in_db.empty() && schema::change(*this, identifier::Schema(in_db)))
00674     return false; // change() has pushed the error message
00675   my_ok();
00676 
00677   /* Ready to handle queries */
00678   return true;
00679 }
00680 
00681 bool Session::executeStatement()
00682 {
00683   /*
00684     indicator of uninitialized lex => normal flow of errors handling
00685     (see my_message_sql)
00686   */
00687   lex().current_select= 0;
00688   clear_error();
00689   main_da().reset_diagnostics_area();
00690   char *l_packet= 0;
00691   uint32_t packet_length;
00692   if (not client->readCommand(&l_packet, packet_length))
00693     return false;
00694 
00695   if (getKilled() == KILL_CONNECTION)
00696     return false;
00697 
00698   if (packet_length == 0)
00699     return true;
00700 
00701   enum_server_command l_command= static_cast<enum_server_command>(l_packet[0]);
00702 
00703   if (command >= COM_END)
00704     command= COM_END;                           // Wrong command
00705 
00706   assert(packet_length);
00707   return not dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
00708 }
00709 
00710 void Session::readAndStoreQuery(const char *in_packet, uint32_t in_packet_length)
00711 {
00712   /* Remove garbage at start and end of query */
00713   while (in_packet_length > 0 && charset()->isspace(in_packet[0]))
00714   {
00715     in_packet++;
00716     in_packet_length--;
00717   }
00718   const char *pos= in_packet + in_packet_length; /* Point at end null */
00719   while (in_packet_length > 0 && (pos[-1] == ';' || charset()->isspace(pos[-1])))
00720   {
00721     pos--;
00722     in_packet_length--;
00723   }
00724 
00725   util::string::mptr new_query= boost::make_shared<std::string>(in_packet, in_packet_length);
00726   plugin::QueryRewriter::rewriteQuery(*impl_->schema, *new_query);
00727   query= new_query;
00728   impl_->state= boost::make_shared<session::State>(in_packet, in_packet_length);
00729 }
00730 
00731 bool Session::endTransaction(enum_mysql_completiontype completion)
00732 {
00733   bool do_release= 0;
00734   bool result= true;
00735 
00736   if (transaction.xid_state.xa_state != XA_NOTR)
00737   {
00738     my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
00739     return false;
00740   }
00741   switch (completion)
00742   {
00743     case COMMIT:
00744       /*
00745        * We don't use endActiveTransaction() here to ensure that this works
00746        * even if there is a problem with the OPTION_AUTO_COMMIT flag
00747        * (Which of course should never happen...)
00748        */
00749       server_status&= ~SERVER_STATUS_IN_TRANS;
00750       if (TransactionServices::commitTransaction(*this, true))
00751         result= false;
00752       options&= ~(OPTION_BEGIN);
00753       break;
00754     case COMMIT_RELEASE:
00755       do_release= 1; /* fall through */
00756     case COMMIT_AND_CHAIN:
00757       result= endActiveTransaction();
00758       if (result == true && completion == COMMIT_AND_CHAIN)
00759         result= startTransaction();
00760       break;
00761     case ROLLBACK_RELEASE:
00762       do_release= 1; /* fall through */
00763     case ROLLBACK:
00764     case ROLLBACK_AND_CHAIN:
00765     {
00766       server_status&= ~SERVER_STATUS_IN_TRANS;
00767       if (TransactionServices::rollbackTransaction(*this, true))
00768         result= false;
00769       options&= ~(OPTION_BEGIN);
00770       if (result == true && (completion == ROLLBACK_AND_CHAIN))
00771         result= startTransaction();
00772       break;
00773     }
00774     default:
00775       my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
00776       return false;
00777   }
00778 
00779   if (not result)
00780   {
00781     my_error(static_cast<drizzled::error_t>(killed_errno()), MYF(0));
00782   }
00783   else if (result && do_release)
00784   {
00785     setKilled(Session::KILL_CONNECTION);
00786   }
00787 
00788   return result;
00789 }
00790 
00791 bool Session::endActiveTransaction()
00792 {
00793   bool result= true;
00794 
00795   if (transaction.xid_state.xa_state != XA_NOTR)
00796   {
00797     my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
00798     return false;
00799   }
00800   if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
00801   {
00802     server_status&= ~SERVER_STATUS_IN_TRANS;
00803     if (TransactionServices::commitTransaction(*this, true))
00804       result= false;
00805   }
00806   options&= ~(OPTION_BEGIN);
00807   return result;
00808 }
00809 
00810 bool Session::startTransaction(start_transaction_option_t opt)
00811 {
00812   assert(not inTransaction());
00813 
00814   options|= OPTION_BEGIN;
00815   server_status|= SERVER_STATUS_IN_TRANS;
00816 
00817   if (plugin::TransactionalStorageEngine::notifyStartTransaction(this, opt))
00818     return false;
00819   return true;
00820 }
00821 
00822 void Session::cleanup_after_query()
00823 {
00824   /*
00825     Reset rand_used so that detection of calls to rand() will save random
00826     seeds if needed by the slave.
00827   */
00828   if (first_successful_insert_id_in_cur_stmt > 0)
00829   {
00830     /* set what LAST_INSERT_ID() will return */
00831     first_successful_insert_id_in_prev_stmt= first_successful_insert_id_in_cur_stmt;
00832     first_successful_insert_id_in_cur_stmt= 0;
00833     substitute_null_with_insert_id= true;
00834   }
00835 
00836   arg_of_last_insert_id_function= false;
00837 
00838   /* Free Items that were created during this execution */
00839   free_items();
00840 
00841   /* Reset _where. */
00842   _where= Session::DEFAULT_WHERE;
00843 
00844   /* Reset the temporary shares we built */
00845   impl_->temporary_shares.clear();
00846 }
00847 
00858 lex_string_t* Session::make_lex_string(lex_string_t* lex_str, str_ref str)
00859 {
00860   if (not lex_str)
00861     lex_str= new (mem) lex_string_t;
00862   lex_str->assign(mem_root->strdup(str), str.size());
00863   return lex_str;
00864 }
00865 
00866 void Session::send_explain_fields(select_result *result)
00867 {
00868   List<Item> field_list;
00869   Item *item;
00870   const charset_info_st* cs= system_charset_info;
00871   field_list.push_back(new Item_return_int("id",3, DRIZZLE_TYPE_LONGLONG));
00872   field_list.push_back(new Item_empty_string("select_type", 19, cs));
00873   field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
00874   item->maybe_null= 1;
00875   field_list.push_back(item= new Item_empty_string("type", 10, cs));
00876   item->maybe_null= 1;
00877   field_list.push_back(item= new Item_empty_string("possible_keys", NAME_CHAR_LEN*MAX_KEY, cs));
00878   item->maybe_null=1;
00879   field_list.push_back(item= new Item_empty_string("key", NAME_CHAR_LEN, cs));
00880   item->maybe_null=1;
00881   field_list.push_back(item= new Item_empty_string("key_len", MAX_KEY * (MAX_KEY_LENGTH_DECIMAL_WIDTH + 1 /* for comma */), cs));
00882   item->maybe_null=1;
00883   field_list.push_back(item= new Item_empty_string("ref", NAME_CHAR_LEN*MAX_REF_PARTS, cs));
00884   item->maybe_null=1;
00885   field_list.push_back(item= new Item_return_int("rows", 10, DRIZZLE_TYPE_LONGLONG));
00886   if (lex().describe & DESCRIBE_EXTENDED)
00887   {
00888     field_list.push_back(item= new Item_float("filtered", 0.1234, 2, 4));
00889     item->maybe_null=1;
00890   }
00891   item->maybe_null= 1;
00892   field_list.push_back(new Item_empty_string("Extra", 255, cs));
00893   result->send_fields(field_list);
00894 }
00895 
00896 void select_result::send_error(drizzled::error_t errcode, const char *err)
00897 {
00898   my_message(errcode, err, MYF(0));
00899 }
00900 
00901 /************************************************************************
00902   Handling writing to file
00903 ************************************************************************/
00904 
00905 void select_to_file::send_error(drizzled::error_t errcode,const char *err)
00906 {
00907   my_message(errcode, err, MYF(0));
00908   if (file > 0)
00909   {
00910     (void) cache->end_io_cache();
00911     (void) internal::my_close(file, MYF(0));
00912     (void) internal::my_delete(path.file_string().c_str(), MYF(0));   // Delete file on error
00913     file= -1;
00914   }
00915 }
00916 
00917 
00918 bool select_to_file::send_eof()
00919 {
00920   int error= test(cache->end_io_cache());
00921   if (internal::my_close(file, MYF(MY_WME)))
00922     error= 1;
00923   if (!error)
00924   {
00925     /*
00926       In order to remember the value of affected rows for ROW_COUNT()
00927       function, SELECT INTO has to have an own SQLCOM.
00928       TODO: split from SQLCOM_SELECT
00929     */
00930     session->my_ok(row_count);
00931   }
00932   file= -1;
00933   return error;
00934 }
00935 
00936 
00937 void select_to_file::cleanup()
00938 {
00939   /* In case of error send_eof() may be not called: close the file here. */
00940   if (file >= 0)
00941   {
00942     (void) cache->end_io_cache();
00943     (void) internal::my_close(file, MYF(0));
00944     file= -1;
00945   }
00946   path= "";
00947   row_count= 0;
00948 }
00949 
00950 select_to_file::select_to_file(file_exchange *ex)
00951   : exchange(ex),
00952     file(-1),
00953     cache(static_cast<internal::io_cache_st *>(memory::sql_calloc(sizeof(internal::io_cache_st)))),
00954     row_count(0L)
00955 {
00956   path= "";
00957 }
00958 
00959 select_to_file::~select_to_file()
00960 {
00961   cleanup();
00962 }
00963 
00964 /***************************************************************************
00965 ** Export of select to textfile
00966 ***************************************************************************/
00967 
00968 select_export::~select_export()
00969 {
00970   session->sent_row_count=row_count;
00971 }
00972 
00973 
00974 /*
00975   Create file with IO cache
00976 
00977   SYNOPSIS
00978     create_file()
00979     session     Thread handle
00980     path    File name
00981     exchange    Excange class
00982     cache   IO cache
00983 
00984   RETURN
00985     >= 0  File handle
00986    -1   Error
00987 */
00988 
00989 
00990 static int create_file(Session& session,
00991                        fs::path &target_path,
00992                        file_exchange *exchange,
00993                        internal::io_cache_st *cache)
00994 {
00995   fs::path to_file(exchange->file_name);
00996 
00997   if (not to_file.has_root_directory())
00998   {
00999     target_path= fs::system_complete(catalog::local_identifier().getPath());
01000     util::string::ptr schema(session.schema());
01001     if (not schema->empty())
01002     {
01003       int count_elements= 0;
01004       for (fs::path::iterator it= to_file.begin(); it != to_file.end(); it++)
01005         count_elements++;
01006       if (count_elements == 1)
01007         target_path /= *schema;
01008     }
01009     target_path /= to_file;
01010   }
01011   else
01012   {
01013     target_path = exchange->file_name;
01014   }
01015 
01016   if (not secure_file_priv.string().empty())
01017   {
01018     if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
01019     {
01020       /* Write only allowed to dir or subdir specified by secure_file_priv */
01021       my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
01022       return -1;
01023     }
01024   }
01025 
01026   if (!access(target_path.file_string().c_str(), F_OK))
01027   {
01028     my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
01029     return -1;
01030   }
01031   /* Create the file world readable */
01032   int file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME));
01033   if (file < 0)
01034     return file;
01035   (void) fchmod(file, 0666);      // Because of umask()
01036   if (cache->init_io_cache(file, 0, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
01037   {
01038     internal::my_close(file, MYF(0));
01039     internal::my_delete(target_path.file_string().c_str(), MYF(0));  // Delete file on error, it was just created
01040     return -1;
01041   }
01042   return file;
01043 }
01044 
01045 
01046 int
01047 select_export::prepare(List<Item> &list, Select_Lex_Unit *u)
01048 {
01049   bool blob_flag=0;
01050   bool string_results= false, non_string_results= false;
01051   unit= u;
01052   if ((uint32_t) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
01053   {
01054     path= exchange->file_name;
01055   }
01056 
01057   /* Check if there is any blobs in data */
01058   {
01059     List<Item>::iterator li(list.begin());
01060     while (Item* item= li++)
01061     {
01062       if (item->max_length >= MAX_BLOB_WIDTH)
01063       {
01064         blob_flag=1;
01065         break;
01066       }
01067 
01068       if (item->result_type() == STRING_RESULT)
01069         string_results= true;
01070       else
01071         non_string_results= true;
01072     }
01073   }
01074   field_term_length=exchange->field_term->length();
01075   field_term_char= field_term_length ?
01076                    (int) (unsigned char) (*exchange->field_term)[0] : INT_MAX;
01077   if (!exchange->line_term->length())
01078     exchange->line_term=exchange->field_term; // Use this if it exists
01079   field_sep_char= exchange->enclosed->length() ? (int) (unsigned char) (*exchange->enclosed)[0] : field_term_char;
01080   escape_char= exchange->escaped->length() ? (int) (unsigned char) (*exchange->escaped)[0] : -1;
01081   is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char));
01082   is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char));
01083   line_sep_char= exchange->line_term->length() ? (int) (unsigned char) (*exchange->line_term)[0] : INT_MAX;
01084   if (!field_term_length)
01085     exchange->opt_enclosed=0;
01086   if (!exchange->enclosed->length())
01087     exchange->opt_enclosed=1;     // A little quicker loop
01088   fixed_row_size= (!field_term_length && !exchange->enclosed->length() &&
01089        !blob_flag);
01090   if ((is_ambiguous_field_sep && exchange->enclosed->empty() && (string_results || is_unsafe_field_sep)) ||
01091       (exchange->opt_enclosed && non_string_results && field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
01092   {
01093     my_error(ER_AMBIGUOUS_FIELD_TERM, MYF(0));
01094     return 1;
01095   }
01096 
01097   if ((file= create_file(*session, path, exchange, cache)) < 0)
01098     return 1;
01099 
01100   return 0;
01101 }
01102 
01103 bool select_export::send_data(List<Item> &items)
01104 {
01105   char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
01106   bool space_inited=0;
01107   String tmp(buff,sizeof(buff),&my_charset_bin),*res;
01108   tmp.length(0);
01109 
01110   if (unit->offset_limit_cnt)
01111   {           // using limit offset,count
01112     unit->offset_limit_cnt--;
01113     return false;
01114   }
01115   row_count++;
01116   uint32_t used_length=0,items_left=items.size();
01117   List<Item>::iterator li(items.begin());
01118 
01119   if (cache->write(exchange->line_start->ptr(), exchange->line_start->length()))
01120     return true;
01121 
01122   while (Item* item=li++)
01123   {
01124     Item_result result_type=item->result_type();
01125     bool enclosed = (exchange->enclosed->length() &&
01126                      (!exchange->opt_enclosed || result_type == STRING_RESULT));
01127     res=item->str_result(&tmp);
01128     if (res && enclosed)
01129     {
01130       if (cache->write(exchange->enclosed->ptr(), exchange->enclosed->length()))
01131         return true;
01132     }
01133     if (!res)
01134     {           // NULL
01135       if (!fixed_row_size)
01136       {
01137         if (escape_char != -1)      // Use \N syntax
01138         {
01139           null_buff[0]=escape_char;
01140           null_buff[1]='N';
01141           if (cache->write(null_buff, 2))
01142             return true;
01143         }
01144         else if (cache->write("NULL", 4))
01145           return true;
01146       }
01147       else
01148       {
01149         used_length=0;        // Fill with space
01150       }
01151     }
01152     else
01153     {
01154       if (fixed_row_size)
01155         used_length= min(res->length(), static_cast<size_t>(item->max_length));
01156       else
01157         used_length= res->length();
01158 
01159       if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
01160           escape_char != -1)
01161       {
01162         char *pos, *start, *end;
01163         const charset_info_st* const res_charset= res->charset();
01164 
01165         for (start= pos= (char*) res->ptr(),end=pos+used_length; pos != end; pos++)
01166         {
01167           if (use_mb(res_charset))
01168           {
01169             if (int l= my_ismbchar(res_charset, pos, end))
01170             {
01171               pos += l - 1;
01172               continue;
01173             }
01174           }
01175 
01176           /*
01177             Special case when dumping BINARY/VARBINARY/BLOB values
01178             for the clients with character sets big5, cp932, gbk and sjis,
01179             which can have the escape character (0x5C "\" by default)
01180             as the second byte of a multi-byte sequence.
01181 
01182             If
01183             - pos[0] is a valid multi-byte head (e.g 0xEE) and
01184             - pos[1] is 0x00, which will be escaped as "\0",
01185 
01186             then we'll get "0xEE + 0x5C + 0x30" in the output file.
01187 
01188             If this file is later loaded using this sequence of commands:
01189 
01190             mysql> create table t1 (a varchar(128)) character set big5;
01191             mysql> LOAD DATA INFILE 'dump.txt' INTO Table t1;
01192 
01193             then 0x5C will be misinterpreted as the second byte
01194             of a multi-byte character "0xEE + 0x5C", instead of
01195             escape character for 0x00.
01196 
01197             To avoid this confusion, we'll escape the multi-byte
01198             head character too, so the sequence "0xEE + 0x00" will be
01199             dumped as "0x5C + 0xEE + 0x5C + 0x30".
01200 
01201             Note, in the condition below we only check if
01202             mbcharlen is equal to 2, because there are no
01203             character sets with mbmaxlen longer than 2
01204             and with escape_with_backslash_is_dangerous set.
01205             assert before the loop makes that sure.
01206           */
01207 
01208           if (needs_escaping(*pos, enclosed) &&
01209               /*
01210                 Don't escape field_term_char by doubling - doubling is only
01211                 valid for ENCLOSED BY characters:
01212               */
01213               (enclosed || !is_ambiguous_field_term ||
01214                (int) (unsigned char) *pos != field_term_char))
01215           {
01216             char tmp_buff[2];
01217             tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
01218                           is_ambiguous_field_sep) ? field_sep_char : escape_char;
01219             tmp_buff[1]= *pos ? *pos : '0';
01220             if (cache->write(start, pos - start) || cache->write(tmp_buff, 2))
01221               return true;
01222             start=pos+1;
01223           }
01224         }
01225         if (cache->write(start, pos - start))
01226           return true;
01227       }
01228       else if (cache->write(res->ptr(), used_length))
01229         return true;
01230     }
01231     if (fixed_row_size)
01232     {           // Fill with space
01233       if (item->max_length > used_length)
01234       {
01235         /* QQ:  Fix by adding a my_b_fill() function */
01236         if (!space_inited)
01237         {
01238           space_inited=1;
01239           memset(space, ' ', sizeof(space));
01240         }
01241         uint32_t length=item->max_length-used_length;
01242         for (; length > sizeof(space) ; length-=sizeof(space))
01243         {
01244           if (cache->write(space, sizeof(space)))
01245             return true;
01246         }
01247         if (cache->write(space, length))
01248           return true;
01249       }
01250     }
01251     if (res && enclosed)
01252     {
01253       if (cache->write(exchange->enclosed->ptr(), exchange->enclosed->length()))
01254         return true;
01255     }
01256     if (--items_left)
01257     {
01258       if (cache->write(exchange->field_term->ptr(), field_term_length))
01259         return true;
01260     }
01261   }
01262   if (cache->write(exchange->line_term->ptr(), exchange->line_term->length()))
01263   {
01264     return true;
01265   }
01266 
01267   return false;
01268 }
01269 
01270 
01271 /***************************************************************************
01272 ** Dump  of select to a binary file
01273 ***************************************************************************/
01274 
01275 
01276 int
01277 select_dump::prepare(List<Item> &, Select_Lex_Unit *u)
01278 {
01279   unit= u;
01280   return (file= create_file(*session, path, exchange, cache)) < 0;
01281 }
01282 
01283 
01284 bool select_dump::send_data(List<Item> &items)
01285 {
01286   List<Item>::iterator li(items.begin());
01287   char buff[MAX_FIELD_WIDTH];
01288   String tmp(buff,sizeof(buff),&my_charset_bin),*res;
01289   tmp.length(0);
01290 
01291   if (unit->offset_limit_cnt)
01292   {           // using limit offset,count
01293     unit->offset_limit_cnt--;
01294     return 0;
01295   }
01296   if (row_count++ > 1)
01297   {
01298     my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
01299     return 1;
01300   }
01301   while (Item* item=li++)
01302   {
01303     res=item->str_result(&tmp);
01304     if (!res)         // If NULL
01305     {
01306       if (cache->write("", 1))
01307         return 1;
01308     }
01309     else if (cache->write(res->ptr(), res->length()))
01310     {
01311       my_error(ER_ERROR_ON_WRITE, MYF(0), path.file_string().c_str(), errno);
01312       return 1;
01313     }
01314   }
01315   return 0;
01316 }
01317 
01318 
01319 select_subselect::select_subselect(Item_subselect *item_arg)
01320 {
01321   item= item_arg;
01322 }
01323 
01324 
01325 bool select_singlerow_subselect::send_data(List<Item> &items)
01326 {
01327   Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
01328   if (it->assigned())
01329   {
01330     my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
01331     return 1;
01332   }
01333   if (unit->offset_limit_cnt)
01334   {                 // Using limit offset,count
01335     unit->offset_limit_cnt--;
01336     return 0;
01337   }
01338   List<Item>::iterator li(items.begin());
01339   Item *val_item;
01340   for (uint32_t i= 0; (val_item= li++); i++)
01341     it->store(i, val_item);
01342   it->assigned(1);
01343   return 0;
01344 }
01345 
01346 
01347 void select_max_min_finder_subselect::cleanup()
01348 {
01349   cache= 0;
01350 }
01351 
01352 
01353 bool select_max_min_finder_subselect::send_data(List<Item> &items)
01354 {
01355   Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
01356   List<Item>::iterator li(items.begin());
01357   Item *val_item= li++;
01358   it->register_value();
01359   if (it->assigned())
01360   {
01361     cache->store(val_item);
01362     if ((this->*op)())
01363       it->store(0, cache);
01364   }
01365   else
01366   {
01367     if (!cache)
01368     {
01369       cache= Item_cache::get_cache(val_item);
01370       switch (val_item->result_type())
01371       {
01372       case REAL_RESULT:
01373         op= &select_max_min_finder_subselect::cmp_real;
01374         break;
01375       case INT_RESULT:
01376         op= &select_max_min_finder_subselect::cmp_int;
01377         break;
01378       case STRING_RESULT:
01379         op= &select_max_min_finder_subselect::cmp_str;
01380         break;
01381       case DECIMAL_RESULT:
01382         op= &select_max_min_finder_subselect::cmp_decimal;
01383         break;
01384       case ROW_RESULT:
01385         // This case should never be choosen
01386         assert(0);
01387         op= 0;
01388       }
01389     }
01390     cache->store(val_item);
01391     it->store(0, cache);
01392   }
01393   it->assigned(1);
01394   return 0;
01395 }
01396 
01397 bool select_max_min_finder_subselect::cmp_real()
01398 {
01399   Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
01400   double val1= cache->val_real(), val2= maxmin->val_real();
01401   if (fmax)
01402     return (cache->null_value && !maxmin->null_value) ||
01403       (!cache->null_value && !maxmin->null_value &&
01404        val1 > val2);
01405   return (maxmin->null_value && !cache->null_value) ||
01406     (!cache->null_value && !maxmin->null_value &&
01407      val1 < val2);
01408 }
01409 
01410 bool select_max_min_finder_subselect::cmp_int()
01411 {
01412   Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
01413   int64_t val1= cache->val_int(), val2= maxmin->val_int();
01414   if (fmax)
01415     return (cache->null_value && !maxmin->null_value) ||
01416       (!cache->null_value && !maxmin->null_value &&
01417        val1 > val2);
01418   return (maxmin->null_value && !cache->null_value) ||
01419     (!cache->null_value && !maxmin->null_value &&
01420      val1 < val2);
01421 }
01422 
01423 bool select_max_min_finder_subselect::cmp_decimal()
01424 {
01425   Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
01426   type::Decimal cval, *cvalue= cache->val_decimal(&cval);
01427   type::Decimal mval, *mvalue= maxmin->val_decimal(&mval);
01428   if (fmax)
01429     return (cache->null_value && !maxmin->null_value) ||
01430       (!cache->null_value && !maxmin->null_value &&
01431        class_decimal_cmp(cvalue, mvalue) > 0) ;
01432   return (maxmin->null_value && !cache->null_value) ||
01433     (!cache->null_value && !maxmin->null_value &&
01434      class_decimal_cmp(cvalue,mvalue) < 0);
01435 }
01436 
01437 bool select_max_min_finder_subselect::cmp_str()
01438 {
01439   String *val1, *val2, buf1, buf2;
01440   Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
01441   /*
01442     as far as both operand is Item_cache buf1 & buf2 will not be used,
01443     but added for safety
01444   */
01445   val1= cache->val_str(&buf1);
01446   val2= maxmin->val_str(&buf1);
01447   if (fmax)
01448     return (cache->null_value && !maxmin->null_value) ||
01449       (!cache->null_value && !maxmin->null_value &&
01450        sortcmp(val1, val2, cache->collation.collation) > 0) ;
01451   return (maxmin->null_value && !cache->null_value) ||
01452     (!cache->null_value && !maxmin->null_value &&
01453      sortcmp(val1, val2, cache->collation.collation) < 0);
01454 }
01455 
01456 bool select_exists_subselect::send_data(List<Item> &)
01457 {
01458   Item_exists_subselect *it= (Item_exists_subselect *)item;
01459   if (unit->offset_limit_cnt)
01460   { // Using limit offset,count
01461     unit->offset_limit_cnt--;
01462     return 0;
01463   }
01464   it->value= 1;
01465   it->assigned(1);
01466   return 0;
01467 }
01468 
01469 /*
01470   Don't free mem_root, as mem_root is freed in the end of dispatch_command
01471   (once for any command).
01472 */
01473 void Session::end_statement()
01474 {
01475   /* Cleanup SQL processing state to reuse this statement in next query. */
01476   lex().end();
01477   resetResultsetMessage();
01478 }
01479 
01480 str_ref Session::copy_db_to() const
01481 {
01482   if (not impl_->schema->empty())
01483     return str_ref(mem.strdup(*impl_->schema), impl_->schema->size());
01484   my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
01485   return str_ref();
01486 }
01487 
01488 /****************************************************************************
01489   Tmp_Table_Param
01490 ****************************************************************************/
01491 
01492 void Tmp_Table_Param::init()
01493 {
01494   field_count= sum_func_count= func_count= hidden_field_count= 0;
01495   group_parts= group_length= group_null_parts= 0;
01496   quick_group= 1;
01497   table_charset= 0;
01498   precomputed_group_by= 0;
01499 }
01500 
01501 void Tmp_Table_Param::cleanup()
01502 {
01503   /* Fix for Intel compiler */
01504   if (copy_field)
01505   {
01506     boost::checked_array_delete(copy_field);
01507     save_copy_field= save_copy_field_end= copy_field= copy_field_end= 0;
01508   }
01509 }
01510 
01511 void Session::send_kill_message() const
01512 {
01513   drizzled::error_t err= static_cast<drizzled::error_t>(killed_errno());
01514   if (err != EE_OK)
01515     my_message(err, ER(err), MYF(0));
01516 }
01517 
01518 void Session::set_schema(const std::string& new_db)
01519 {
01520   impl_->schema = boost::make_shared<std::string>(new_db);
01521 }
01522 
01523 
01530 void Session::markTransactionForRollback(bool all)
01531 {
01532   is_fatal_sub_stmt_error= true;
01533   transaction_rollback_request= all;
01534 }
01535 
01536 void Session::disconnect(error_t errcode)
01537 {
01538   /* Allow any plugins to cleanup their session variables */
01539   plugin_sessionvar_cleanup(this);
01540 
01541   /* If necessary, log any aborted or unauthorized connections */
01542   if (getKilled() || client->wasAborted())
01543   {
01544     status_var.aborted_threads++;
01545   }
01546 
01547   if (client->wasAborted())
01548   {
01549     if (not getKilled() && variables.log_warnings > 1)
01550     {
01551       errmsg_printf(error::WARN, ER(ER_NEW_ABORTING_CONNECTION)
01552                   , thread_id
01553                   , (impl_->schema->empty() ? "unconnected" : impl_->schema->c_str())
01554                   , security_ctx->username().empty() ? "unauthenticated" : security_ctx->username().c_str()
01555                   , security_ctx->address().c_str()
01556                   , (main_da().is_error() ? main_da().message() : ER(ER_UNKNOWN_ERROR)));
01557     }
01558   }
01559 
01560   setKilled(Session::KILL_CONNECTION);
01561 
01562   if (client->isConnected())
01563   {
01564     if (errcode != EE_OK)
01565     {
01566       /*my_error(errcode, ER(errcode));*/
01567       client->sendError(errcode, ER(errcode));
01568     }
01569     client->close();
01570   }
01571 }
01572 
01573 void Session::reset_for_next_command()
01574 {
01575   free_list= 0;
01576   select_number= 1;
01577 
01578   is_fatal_error= false;
01579   server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
01580                           SERVER_QUERY_NO_INDEX_USED |
01581                           SERVER_QUERY_NO_GOOD_INDEX_USED);
01582 
01583   clear_error();
01584   main_da().reset_diagnostics_area();
01585   total_warn_count=0;     // Warnings for this query
01586   sent_row_count= examined_row_count= 0;
01587 }
01588 
01589 /*
01590   Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
01591 */
01592 
01593 void Open_tables_state::close_temporary_tables()
01594 {
01595   Table *table;
01596   Table *tmp_next;
01597 
01598   if (not temporary_tables)
01599     return;
01600 
01601   for (table= temporary_tables; table; table= tmp_next)
01602   {
01603     tmp_next= table->getNext();
01604     nukeTable(table);
01605   }
01606   temporary_tables= NULL;
01607 }
01608 
01609 /*
01610   unlink from session->temporary tables and close temporary table
01611 */
01612 
01613 void Open_tables_state::close_temporary_table(Table *table)
01614 {
01615   if (table->getPrev())
01616   {
01617     table->getPrev()->setNext(table->getNext());
01618     if (table->getPrev()->getNext())
01619     {
01620       table->getNext()->setPrev(table->getPrev());
01621     }
01622   }
01623   else
01624   {
01625     /* removing the item from the list */
01626     assert(table == temporary_tables);
01627     /*
01628       slave must reset its temporary list pointer to zero to exclude
01629       passing non-zero value to end_slave via rli->save_temporary_tables
01630       when no temp tables opened, see an invariant below.
01631     */
01632     temporary_tables= table->getNext();
01633     if (temporary_tables)
01634     {
01635       table->getNext()->setPrev(NULL);
01636     }
01637   }
01638   nukeTable(table);
01639 }
01640 
01641 /*
01642   Close and drop a temporary table
01643 
01644   NOTE
01645   This dosn't unlink table from session->temporary
01646   If this is needed, use close_temporary_table()
01647 */
01648 
01649 void Open_tables_state::nukeTable(Table *table)
01650 {
01651   plugin::StorageEngine& table_type= *table->getShare()->db_type();
01652   table->free_io_cache();
01653   table->delete_table();
01654   rm_temporary_table(table_type, identifier::Table(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath()));
01655   boost::checked_delete(table->getMutableShare());
01656   boost::checked_delete(table);
01657 }
01658 
01660 extern time_t flush_status_time;
01661 
01662 void Session::refresh_status()
01663 {
01664   /* Reset thread's status variables */
01665   memset(&status_var, 0, sizeof(status_var));
01666 
01667   flush_status_time= time((time_t*) 0);
01668   current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
01669   current_global_counters.connections= 0;
01670 }
01671 
01672 user_var_entry* Session::getVariable(str_ref name0, bool create_if_not_exists)
01673 {
01674   if (cleanup_done)
01675     return NULL;
01676 
01677   string name(name0.data(), name0.size());
01678   if (UserVars::mapped_type* iter= find_ptr(user_vars, name))
01679     return *iter;
01680 
01681   if (not create_if_not_exists)
01682     return NULL;
01683 
01684   user_var_entry *entry= new user_var_entry(name.c_str(), query_id);
01685 
01686   std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
01687 
01688   if (not returnable.second)
01689   {
01690     boost::checked_delete(entry);
01691   }
01692 
01693   return entry;
01694 }
01695 
01696 void Session::setVariable(const std::string &name, const std::string &value)
01697 {
01698   if (user_var_entry* var= getVariable(name, true))
01699   {
01700     var->update_hash(false, value, STRING_RESULT, &my_charset_bin, DERIVATION_IMPLICIT, false);
01701   }
01702 }
01703 
01704 void Open_tables_state::mark_temp_tables_as_free_for_reuse()
01705 {
01706   for (Table *table= temporary_tables ; table ; table= table->getNext())
01707   {
01708     if (table->query_id == session_.getQueryId())
01709     {
01710       table->query_id= 0;
01711       table->cursor->ha_reset();
01712     }
01713   }
01714 }
01715 
01716 /*
01717   Unlocks tables and frees derived tables.
01718   Put all normal tables used by thread in free list.
01719 
01720   It will only close/mark as free for reuse tables opened by this
01721   substatement, it will also check if we are closing tables after
01722   execution of complete query (i.e. we are on upper level) and will
01723   leave prelocked mode if needed.
01724 */
01725 void Session::close_thread_tables()
01726 {
01727   open_tables.clearDerivedTables();
01728 
01729   /*
01730     Mark all temporary tables used by this statement as free for reuse.
01731   */
01732   open_tables.mark_temp_tables_as_free_for_reuse();
01733   /*
01734     Let us commit transaction for statement. Since in 5.0 we only have
01735     one statement transaction and don't allow several nested statement
01736     transactions this call will do nothing if we are inside of stored
01737     function or trigger (i.e. statement transaction is already active and
01738     does not belong to statement for which we do close_thread_tables()).
01739     TODO: This should be fixed in later releases.
01740    */
01741   {
01742     main_da().can_overwrite_status= true;
01743     TransactionServices::autocommitOrRollback(*this, is_error());
01744     main_da().can_overwrite_status= false;
01745     transaction.stmt.reset();
01746   }
01747 
01748   if (open_tables.lock)
01749   {
01750     /*
01751       For RBR we flush the pending event just before we unlock all the
01752       tables.  This means that we are at the end of a topmost
01753       statement, so we ensure that the STMT_END_F flag is set on the
01754       pending event.  For statements that are *inside* stored
01755       functions, the pending event will not be flushed: that will be
01756       handled either before writing a query log event (inside
01757       binlog_query()) or when preparing a pending event.
01758      */
01759     unlockTables(open_tables.lock);
01760     open_tables.lock= 0;
01761   }
01762   /*
01763     Note that we need to hold table::Cache::mutex() while changing the
01764     open_tables list. Another thread may work on it.
01765     (See: table::Cache::removeTable(), wait_completed_table())
01766     Closing a MERGE child before the parent would be fatal if the
01767     other thread tries to abort the MERGE lock in between.
01768   */
01769   if (open_tables.open_tables_)
01770     open_tables.close_open_tables();
01771 }
01772 
01773 void Session::close_tables_for_reopen(TableList **tables)
01774 {
01775   /*
01776     If table list consists only from tables from prelocking set, table list
01777     for new attempt should be empty, so we have to update list's root pointer.
01778   */
01779   if (lex().first_not_own_table() == *tables)
01780     *tables= 0;
01781   lex().chop_off_not_own_tables();
01782   for (TableList *tmp= *tables; tmp; tmp= tmp->next_global)
01783     tmp->table= 0;
01784   close_thread_tables();
01785 }
01786 
01787 bool Session::openTablesLock(TableList *tables)
01788 {
01789   uint32_t counter;
01790   bool need_reopen;
01791 
01792   for ( ; ; )
01793   {
01794     if (open_tables_from_list(&tables, &counter))
01795       return true;
01796 
01797     if (not lock_tables(tables, counter, &need_reopen))
01798       break;
01799 
01800     if (not need_reopen)
01801       return true;
01802 
01803     close_tables_for_reopen(&tables);
01804   }
01805 
01806   return handle_derived(&lex(), &derived_prepare) || handle_derived(&lex(), &derived_filling);
01807 }
01808 
01809 /*
01810   @note "best_effort" is used in cases were if a failure occurred on this
01811   operation it would not be surprising because we are only removing because there
01812   might be an issue (lame engines).
01813 */
01814 
01815 bool Open_tables_state::rm_temporary_table(const identifier::Table &identifier, bool best_effort)
01816 {
01817   if (plugin::StorageEngine::dropTable(session_, identifier))
01818     return false;
01819   if (not best_effort)
01820     errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"), identifier.getSQLPath().c_str(), errno);
01821   return true;
01822 }
01823 
01824 bool Open_tables_state::rm_temporary_table(plugin::StorageEngine& base, const identifier::Table &identifier)
01825 {
01826   drizzled::error_t error;
01827   if (plugin::StorageEngine::dropTable(session_, base, identifier, error))
01828     return false;
01829   errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"), identifier.getSQLPath().c_str(), error);
01830   return true;
01831 }
01832 
01833 table::Singular& Session::getInstanceTable()
01834 {
01835   impl_->temporary_shares.push_back(new table::Singular); // This will not go into the tableshare cache, so no key is used.
01836   return impl_->temporary_shares.back();
01837 }
01838 
01839 
01858 table::Singular& Session::getInstanceTable(std::list<CreateField>& field_list)
01859 {
01860   impl_->temporary_shares.push_back(new table::Singular(this, field_list)); // This will not go into the tableshare cache, so no key is used.
01861   return impl_->temporary_shares.back();
01862 }
01863 
01864 void Session::clear_error(bool full)
01865 {
01866   if (main_da().is_error())
01867     main_da().reset_diagnostics_area();
01868 
01869   if (full)
01870     drizzle_reset_errors(*this, true);
01871 }
01872 
01873 void Session::clearDiagnostics()
01874 {
01875   main_da().reset_diagnostics_area();
01876 }
01877 
01891 bool Session::is_error() const 
01892 { 
01893   return impl_->diagnostics.is_error(); 
01894 }
01895 
01897 void Session::my_ok(ha_rows affected_rows, ha_rows found_rows_arg, uint64_t passed_id, const char *message)
01898 {
01899   main_da().set_ok_status(this, affected_rows, found_rows_arg, passed_id, message);
01900 }
01901 
01904 void Session::my_eof()
01905 {
01906   main_da().set_eof_status(this);
01907 }
01908 
01909 plugin::StorageEngine* Session::getDefaultStorageEngine()
01910 {
01911   return variables.storage_engine ? variables.storage_engine : global_system_variables.storage_engine;
01912 }
01913 
01914 enum_tx_isolation Session::getTxIsolation() const
01915 {
01916   return (enum_tx_isolation)variables.tx_isolation;
01917 }
01918 
01919 drizzled::util::Storable* Session::getProperty0(const std::string& arg)
01920 {
01921   return impl_->properties[arg];
01922 }
01923 
01924 void Session::setProperty0(const std::string& arg, drizzled::util::Storable* value)
01925 {
01926   // assert(not _properties.count(arg));
01927   impl_->properties[arg]= value;
01928 }
01929 
01930 plugin::EventObserverList* Session::getSchemaObservers(const std::string &db_name)
01931 {
01932   if (impl_c::schema_event_observers_t::mapped_type* i= find_ptr(impl_->schema_event_observers, db_name))
01933     return *i;
01934   return NULL;
01935 }
01936 
01937 plugin::EventObserverList* Session::setSchemaObservers(const std::string &db_name, plugin::EventObserverList* observers)
01938 {
01939   impl_->schema_event_observers.erase(db_name);
01940   if (observers)
01941     impl_->schema_event_observers[db_name] = observers;
01942   return observers;
01943 }
01944 
01945 util::string::ptr Session::schema() const
01946 {
01947   return impl_->schema;
01948 }
01949 
01950 void Session::resetQueryString()
01951 {
01952   query.reset();
01953   impl_->state.reset();
01954 }
01955 
01956 const boost::shared_ptr<session::State>& Session::state()
01957 {
01958   return impl_->state;
01959 }
01960 
01961 const std::string& display::type(drizzled::Session::global_read_lock_t type)
01962 {
01963   static const std::string NONE= "NONE";
01964   static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
01965   static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
01966 
01967   switch (type) 
01968   {
01969     default:
01970     case Session::NONE:
01971       return NONE;
01972     case Session::GOT_GLOBAL_READ_LOCK:
01973       return GOT_GLOBAL_READ_LOCK;
01974     case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
01975       return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
01976   }
01977 }
01978 
01979 size_t display::max_string_length(drizzled::Session::global_read_lock_t)
01980 {
01981   return display::type(Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT).size();
01982 }
01983 
01984 } /* namespace drizzled */