Drizzled Public API Documentation

session.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2008 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
24 #include <config.h>
25 
26 #include <boost/checked_delete.hpp>
27 #include <boost/filesystem.hpp>
28 #include <boost/ptr_container/ptr_container.hpp>
29 #include <drizzled/copy_field.h>
30 #include <drizzled/catalog/local.h>
31 #include <drizzled/diagnostics_area.h>
32 #include <drizzled/display.h>
33 #include <drizzled/drizzled.h>
34 #include <drizzled/error.h>
35 #include <drizzled/gettext.h>
36 #include <drizzled/ha_data.h>
37 #include <drizzled/identifier.h>
38 #include <drizzled/internal/iocache.h>
39 #include <drizzled/internal/thread_var.h>
40 #include <drizzled/item/cache.h>
41 #include <drizzled/item/empty_string.h>
42 #include <drizzled/item/float.h>
43 #include <drizzled/item/return_int.h>
44 #include <drizzled/item/subselect.h>
45 #include <drizzled/lock.h>
46 #include <drizzled/open_tables_state.h>
47 #include <drizzled/plugin/authentication.h>
48 #include <drizzled/plugin/authorization.h>
49 #include <drizzled/plugin/client.h>
50 #include <drizzled/plugin/event_observer.h>
51 #include <drizzled/plugin/logging.h>
52 #include <drizzled/plugin/query_rewrite.h>
53 #include <drizzled/plugin/scheduler.h>
54 #include <drizzled/plugin/transactional_storage_engine.h>
55 #include <drizzled/probes.h>
56 #include <drizzled/pthread_globals.h>
57 #include <drizzled/schema.h>
58 #include <drizzled/select_dump.h>
59 #include <drizzled/select_exists_subselect.h>
60 #include <drizzled/select_export.h>
61 #include <drizzled/select_max_min_finder_subselect.h>
62 #include <drizzled/select_singlerow_subselect.h>
63 #include <drizzled/select_subselect.h>
64 #include <drizzled/select_to_file.h>
65 #include <drizzled/session.h>
66 #include <drizzled/session/cache.h>
67 #include <drizzled/session/state.h>
68 #include <drizzled/session/table_messages.h>
69 #include <drizzled/session/times.h>
70 #include <drizzled/session/transactions.h>
71 #include <drizzled/show.h>
72 #include <drizzled/sql_base.h>
73 #include <drizzled/sql_lex.h>
74 #include <drizzled/system_variables.h>
75 #include <drizzled/statement.h>
76 #include <drizzled/statistics_variables.h>
77 #include <drizzled/table/singular.h>
78 #include <drizzled/table_proto.h>
79 #include <drizzled/tmp_table_param.h>
80 #include <drizzled/transaction_services.h>
81 #include <drizzled/user_var_entry.h>
82 #include <drizzled/util/backtrace.h>
83 #include <drizzled/util/find_ptr.h>
84 #include <drizzled/util/functors.h>
85 #include <drizzled/util/storable.h>
86 #include <plugin/myisam/myisam.h>
87 
88 #include <algorithm>
89 #include <climits>
90 #include <fcntl.h>
91 #include <sys/stat.h>
92 
93 using namespace std;
94 
95 namespace fs= boost::filesystem;
96 
97 namespace drizzled {
98 
99 const char* const Session::DEFAULT_WHERE= "field list";
100 
101 uint64_t g_refresh_version = 1;
102 
103 bool Key_part_spec::operator==(const Key_part_spec& other) const
104 {
105  return length == other.length
106  && field_name.size() == other.field_name.size()
107  && not system_charset_info->strcasecmp(field_name.data(), other.field_name.data());
108 }
109 
110 Open_tables_state::Open_tables_state(Session& session, uint64_t version_arg) :
111  version(version_arg),
112  session_(session)
113 {
114  open_tables_= temporary_tables= derived_tables= NULL;
115  extra_lock= lock= NULL;
116 }
117 
118 /*
119  The following functions form part of the C plugin API
120 */
121 int tmpfile(const char *prefix)
122 {
123  char filename[FN_REFLEN];
124  int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
125  if (fd >= 0)
126  unlink(filename);
127  return fd;
128 }
129 
130 void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
131 {
132  return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
133 }
134 
135 ResourceContext& Session::getResourceContext(const plugin::MonitoredInTransaction& monitored, size_t index)
136 {
137  return ha_data[monitored.getId()].resource_context[index];
138 }
139 
140 int64_t session_test_options(const Session *session, int64_t test_options)
141 {
142  return session->options & test_options;
143 }
144 
146 {
147 public:
148  typedef boost::unordered_map<std::string, util::Storable*, util::insensitive_hash, util::insensitive_equal_to> properties_t;
149  typedef std::map<std::string, plugin::EventObserverList*> schema_event_observers_t;
150 
151  impl_c(Session& session) :
152  open_tables(session, g_refresh_version),
153  schema(boost::make_shared<std::string>())
154  {
155  }
156 
157  ~impl_c()
158  {
159  BOOST_FOREACH(properties_t::reference it, properties)
160  delete it.second;
161  }
162 
163  Diagnostics_area diagnostics;
164  memory::Root mem_root;
165 
172  LEX lex;
173  Open_tables_state open_tables;
174  properties_t properties;
175  schema_event_observers_t schema_event_observers;
176  system_status_var status_var;
177  session::TableMessages table_message_cache;
178  util::string::mptr schema;
179  boost::shared_ptr<session::State> state;
180  boost::ptr_vector<table::Singular> temporary_shares;
181  session::Times times;
182  session::Transactions transaction;
183  drizzle_system_variables variables;
184 };
185 
186 Session::Session(plugin::Client *client_arg, catalog::Instance::shared_ptr catalog_arg) :
187  impl_(new impl_c(*this)),
188  mem(impl_->mem_root),
189  mem_root(&impl_->mem_root),
190  query(new std::string),
191  scheduler(NULL),
192  variables(impl_->variables),
193  status_var(impl_->status_var),
194  lock_id(&main_lock_id),
195  thread_stack(NULL),
196  _where(Session::DEFAULT_WHERE),
197  mysys_var(0),
198  command(COM_CONNECT),
199  ha_data(plugin::num_trx_monitored_objects),
200  query_id(0),
201  warn_query_id(0),
202  transaction(impl_->transaction),
203  open_tables(impl_->open_tables),
204  times(impl_->times),
205  first_successful_insert_id_in_prev_stmt(0),
206  first_successful_insert_id_in_cur_stmt(0),
207  limit_found_rows(0),
208  options(session_startup_options),
209  row_count_func(-1),
210  sent_row_count(0),
211  examined_row_count(0),
212  used_tables(0),
213  total_warn_count(0),
214  row_count(0),
215  thread_id(0),
216  tmp_table(0),
217  _global_read_lock(NONE),
218  count_cuted_fields(CHECK_FIELD_ERROR_FOR_NULL),
219  _killed(NOT_KILLED),
220  no_errors(false),
221  is_fatal_error(false),
222  transaction_rollback_request(false),
223  is_fatal_sub_stmt_error(0),
224  derived_tables_processing(false),
225  m_lip(NULL),
226  arg_of_last_insert_id_function(false),
227  _catalog(catalog_arg),
228  transaction_message(NULL),
229  statement_message(NULL),
230  session_event_observers(NULL),
231  xa_id(0),
232  concurrent_execute_allowed(true),
233  tablespace_op(false),
234  use_usage(false),
235  security_ctx(identifier::User::make_shared()),
236  originating_server_uuid_set(false),
237  client(client_arg)
238 {
239  client->setSession(this);
240 
241  /*
242  Pass nominal parameters to init only to ensure that
243  the destructor works OK in case of an error. The main_mem_root
244  will be re-initialized in init_for_queries().
245  */
246  mem.init(memory::ROOT_MIN_BLOCK_SIZE);
248  // Must be reset to handle error with Session's created for init of mysqld
249  lex().current_select= 0;
250  memset(&variables, 0, sizeof(variables));
251  scoreboard_index= -1;
252  originating_server_uuid= "";
253  originating_commit_id= 0;
254  cleanup_done= abort_on_warning= no_warnings_for_error= false;
255 
256  resultset= NULL;
257 
258  /* Variables with default values */
259  proc_info="login";
260 
261  plugin_sessionvar_init(this);
262  /*
263  variables= global_system_variables above has reset
264  variables.pseudo_thread_id to 0. We need to correct it here to
265  avoid temporary tables replication failure.
266  */
267  variables.pseudo_thread_id= thread_id;
268  server_status= SERVER_STATUS_AUTOCOMMIT;
269 
270  if (variables.max_join_size == HA_POS_ERROR)
271  options |= OPTION_BIG_SELECTS;
272  else
273  options &= ~OPTION_BIG_SELECTS;
274 
275  open_options=ha_open_options;
276  update_lock_default= TL_WRITE;
277  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
278  memset(warn_count, 0, sizeof(warn_count));
279  memset(&status_var, 0, sizeof(status_var));
280 
281  /* Initialize sub structures */
282  warn_root.init(WARN_ALLOC_BLOCK_SIZE);
283 
285  lock_info.init(); /* safety: will be reset after start */
286  main_lock_id.info= &lock_info;
287 
288  plugin::EventObserver::registerSessionEvents(*this);
289 }
290 
291 Diagnostics_area& Session::main_da()
292 {
293  return impl_->diagnostics;
294 }
295 
296 const LEX& Session::lex() const
297 {
298  return impl_->lex;
299 }
300 
301 LEX& Session::lex()
302 {
303  return impl_->lex;
304 }
305 
306 enum_sql_command Session::getSqlCommand() const
307 {
308  return lex().sql_command;
309 }
310 
311 session::TableMessages& Session::getMessageCache()
312 {
313  return impl_->table_message_cache;
314 }
315 
316 void statement::Statement::set_command(enum_sql_command v)
317 {
318  session().lex().sql_command= v;
319 }
320 
321 LEX& statement::Statement::lex()
322 {
323  return session().lex();
324 }
325 
326 session::Transactions& statement::Statement::transaction()
327 {
328  return session().transaction;
329 }
330 
331 void Session::add_item_to_list(Item *item)
332 {
333  lex().current_select->add_item_to_list(this, item);
334 }
335 
336 void Session::add_value_to_list(Item *value)
337 {
338  lex().value_list.push_back(value);
339 }
340 
341 void Session::add_order_to_list(Item *item, bool asc)
342 {
343  lex().current_select->add_order_to_list(this, item, asc);
344 }
345 
346 void Session::add_group_to_list(Item *item, bool asc)
347 {
348  lex().current_select->add_group_to_list(this, item, asc);
349 }
350 
352 {
353  /* This works because items are allocated with memory::sql_alloc() */
354  for (Item* next; free_list; free_list= next)
355  {
356  next= free_list->next;
357  free_list->delete_self();
358  }
359 }
360 
361 void Session::setAbort(bool arg)
362 {
363  mysys_var->abort= arg;
364 }
365 
366 void Session::lockOnSys()
367 {
368  if (not mysys_var)
369  return;
370 
371  setAbort(true);
372  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
373  if (mysys_var->current_cond)
374  {
375  mysys_var->current_mutex->lock();
376  mysys_var->current_cond->notify_all();
377  mysys_var->current_mutex->unlock();
378  }
379 }
380 
381 void Session::get_xid(DrizzleXid *xid) const
382 {
383  *xid = *(DrizzleXid *) &transaction.xid_state.xid;
384 }
385 
386 /* Do operations that may take a long time */
387 
388 void Session::cleanup()
389 {
390  assert(not cleanup_done);
391 
392  setKilled(KILL_CONNECTION);
393 
394  /* In the future, you may want to do something about XA_PREPARED here.
395  In the dim distant past there was some #ifdefed out #error here about it.
396  */
397  TransactionServices::rollbackTransaction(*this, true);
398 
399  BOOST_FOREACH(UserVars::reference iter, user_vars)
400  boost::checked_delete(iter.second);
401  user_vars.clear();
402 
403  open_tables.close_temporary_tables();
404 
405  if (global_read_lock)
406  unlockGlobalReadLock();
407 
408  cleanup_done= true;
409 }
410 
411 Session::~Session()
412 {
413  if (client and client->isConnected())
414  {
415  assert(security_ctx);
416  if (global_system_variables.log_warnings)
417  {
418  errmsg_printf(error::WARN, ER(ER_FORCING_CLOSE), internal::my_progname, thread_id, security_ctx->username().c_str());
419  }
420 
421  disconnect();
422  }
423 
424  /* Close connection */
425  if (client)
426  {
427  client->close();
428  boost::checked_delete(client);
429  client= NULL;
430  }
431 
432  if (not cleanup_done)
433  cleanup();
434 
436  plugin_sessionvar_cleanup(this);
437 
438  warn_root.free_root(MYF(0));
439  mysys_var=0; // Safety (shouldn't be needed)
440 
441  impl_->mem_root.free_root(MYF(0));
442  setCurrentMemRoot(NULL);
443  setCurrentSession(NULL);
444 
445  plugin::Logging::postEndDo(this);
446  plugin::EventObserver::deregisterSessionEvents(session_event_observers);
447 
448  BOOST_FOREACH(impl_c::schema_event_observers_t::reference it, impl_->schema_event_observers)
449  plugin::EventObserver::deregisterSchemaEvents(it.second);
450 }
451 
452 void Session::setClient(plugin::Client *client_arg)
453 {
454  client= client_arg;
455  client->setSession(this);
456 }
457 
458 void Session::awake(Session::killed_state_t state_to_set)
459 {
460  if (state_to_set == Session::KILL_QUERY && command == COM_SLEEP)
461  return;
462 
463  setKilled(state_to_set);
464  scheduler->killSession(this);
465 
466  if (state_to_set != Session::KILL_QUERY)
467  {
468  DRIZZLE_CONNECTION_DONE(thread_id);
469  }
470 
471  if (mysys_var)
472  {
473  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
474  /*
475  "
476  This broadcast could be up in the air if the victim thread
477  exits the cond in the time between read and broadcast, but that is
478  ok since all we want to do is to make the victim thread get out
479  of waiting on current_cond.
480  If we see a non-zero current_cond: it cannot be an old value (because
481  then exit_cond() should have run and it can't because we have mutex); so
482  it is the true value but maybe current_mutex is not yet non-zero (we're
483  in the middle of enter_cond() and there is a "memory order
484  inversion"). So we test the mutex too to not lock 0.
485 
486  Note that there is a small chance we fail to kill. If victim has locked
487  current_mutex, but hasn't yet entered enter_cond() (which means that
488  current_cond and current_mutex are 0), then the victim will not get
489  a signal and it may wait "forever" on the cond (until
490  we issue a second KILL or the status it's waiting for happens).
491  It's true that we have set its session->killed but it may not
492  see it immediately and so may have time to reach the cond_wait().
493  */
494  if (mysys_var->current_cond && mysys_var->current_mutex)
495  {
496  mysys_var->current_mutex->lock();
497  mysys_var->current_cond->notify_all();
498  mysys_var->current_mutex->unlock();
499  }
500  }
501 }
502 
503 /*
504  Remember the location of thread info, the structure needed for
505  memory::sql_alloc() and the structure for the net buffer
506 */
507 void Session::storeGlobals()
508 {
509  /*
510  Assert that thread_stack is initialized: it's necessary to be able
511  to track stack overrun.
512  */
513  assert(thread_stack);
514  setCurrentSession(this);
515  setCurrentMemRoot(&mem);
516 
517  mysys_var= internal::my_thread_var2().get();
518 
519  /*
520  Let mysqld define the thread id (not mysys)
521  This allows us to move Session to different threads if needed.
522  */
523  mysys_var->id= thread_id;
524 
525  /*
526  We have to call thr_lock_info_init() again here as Session may have been
527  created in another thread
528  */
529  lock_info.init();
530 }
531 
532 /*
533  Init Session for query processing.
534  This has to be called once before we call mysql_parse.
535  See also comments in session.h.
536 */
537 
539 {
540  if (variables.max_join_size == HA_POS_ERROR)
541  options |= OPTION_BIG_SELECTS;
542 
543  open_tables.version= g_refresh_version;
544  set_proc_info(NULL);
545  command= COM_SLEEP;
546  times.set_time();
547 
548  mem.reset_defaults(variables.query_alloc_block_size, variables.query_prealloc_size);
549  transaction.xid_state.xid.set_null();
550  transaction.xid_state.in_session=1;
551  if (use_usage)
552  resetUsage();
553 }
554 
555 void Session::run()
556 {
557  storeGlobals();
558  if (authenticate())
559  {
560  disconnect();
561  return;
562  }
564  while (not client->haveError() && getKilled() != KILL_CONNECTION)
565  {
566  if (not executeStatement())
567  break;
568  }
569  disconnect();
570 }
571 
572 bool Session::schedule(const shared_ptr& arg)
573 {
574  arg->scheduler= plugin::Scheduler::getScheduler();
575  assert(arg->scheduler);
576 
577  ++connection_count;
578 
579  long current_connections= connection_count;
580 
581  if (current_connections > 0 and static_cast<uint64_t>(current_connections) > current_global_counters.max_used_connections)
582  {
583  current_global_counters.max_used_connections= static_cast<uint64_t>(connection_count);
584  }
585 
586  current_global_counters.connections++;
587  arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
588 
589  session::Cache::insert(arg);
590 
591  if (unlikely(plugin::EventObserver::connectSession(*arg)))
592  {
593  // We should do something about an error...
594  }
595 
596  if (plugin::Scheduler::getScheduler()->addSession(arg))
597  {
598  DRIZZLE_CONNECTION_START(arg->getSessionId());
599  char error_message_buff[DRIZZLE_ERRMSG_SIZE];
600 
601  arg->setKilled(Session::KILL_CONNECTION);
602 
603  arg->status_var.aborted_connects++;
604 
605  /* Can't use my_error() since store_globals has not been called. */
606  /* TODO replace will better error message */
607  snprintf(error_message_buff, sizeof(error_message_buff), ER(ER_CANT_CREATE_THREAD), 1);
608  arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
609  return true;
610  }
611  return false;
612 }
613 
614 
615 /*
616  Is this session viewable by the current user?
617 */
618 bool Session::isViewable(const identifier::User& user_arg) const
619 {
620  return plugin::Authorization::isAuthorized(user_arg, *this, false);
621 }
622 
623 
624 const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
625 {
626  const char* old_msg = get_proc_info();
627  safe_mutex_assert_owner(mutex);
628  mysys_var->current_mutex = &mutex;
629  mysys_var->current_cond = &cond;
630  this->set_proc_info(msg);
631  return old_msg;
632 }
633 
634 void Session::exit_cond(const char* old_msg)
635 {
636  /*
637  Putting the mutex unlock in exit_cond() ensures that
638  mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
639  locked (if that would not be the case, you'll get a deadlock if someone
640  does a Session::awake() on you).
641  */
642  mysys_var->current_mutex->unlock();
643  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
644  mysys_var->current_mutex = 0;
645  mysys_var->current_cond = 0;
646  this->set_proc_info(old_msg);
647 }
648 
650 {
651  if (client->authenticate())
652  return false;
653 
654  status_var.aborted_connects++;
655 
656  return true;
657 }
658 
659 bool Session::checkUser(const std::string &passwd_str, const std::string &in_db)
660 {
661  if (not plugin::Authentication::isAuthenticated(*user(), passwd_str))
662  {
663  status_var.access_denied++;
664  /* isAuthenticated has pushed the error message */
665  return false;
666  }
667 
668  /* Change database if necessary */
669  if (not in_db.empty() && schema::change(*this, identifier::Schema(catalog().identifier(), in_db)))
670  return false; // change() has pushed the error message
671  my_ok();
672 
673  /* Ready to handle queries */
674  return true;
675 }
676 
678 {
679  /*
680  indicator of uninitialized lex => normal flow of errors handling
681  (see my_message_sql)
682  */
683  lex().current_select= 0;
684  clear_error();
685  main_da().reset_diagnostics_area();
686  char *l_packet= 0;
687  uint32_t packet_length;
688  if (not client->readCommand(&l_packet, packet_length))
689  return false;
690 
691  if (getKilled() == KILL_CONNECTION)
692  return false;
693 
694  if (packet_length == 0)
695  return true;
696 
697  enum_server_command l_command= static_cast<enum_server_command>(l_packet[0]);
698 
699  if (command >= COM_END)
700  command= COM_END; // Wrong command
701 
702  assert(packet_length);
703  return not dispatch_command(l_command, *this, str_ref(l_packet + 1, packet_length - 1));
704 }
705 
707 {
708  /* Remove garbage at start and end of query */
709  while (not v.empty() && charset()->isspace(v.front()))
710  v.pop_front();
711  while (not v.empty() && (v.back() == ';' || charset()->isspace(v.back())))
712  v.pop_back();
713 
714  util::string::mptr new_query= boost::make_shared<std::string>(v.data(), v.size());
715  plugin::QueryRewriter::rewriteQuery(*impl_->schema, *new_query);
716  query= new_query;
717  impl_->state= boost::make_shared<session::State>(v);
718 }
719 
720 bool Session::endTransaction(enum_mysql_completiontype completion)
721 {
722  bool do_release= 0;
723  bool result= true;
724 
725  if (transaction.xid_state.xa_state != XA_NOTR)
726  {
727  my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
728  return false;
729  }
730  switch (completion)
731  {
732  case COMMIT:
733  /*
734  * We don't use endActiveTransaction() here to ensure that this works
735  * even if there is a problem with the OPTION_AUTO_COMMIT flag
736  * (Which of course should never happen...)
737  */
738  server_status&= ~SERVER_STATUS_IN_TRANS;
740  result= false;
741  options&= ~(OPTION_BEGIN);
742  break;
743  case COMMIT_RELEASE:
744  do_release= 1; /* fall through */
745  case COMMIT_AND_CHAIN:
746  result= endActiveTransaction();
747  if (result == true && completion == COMMIT_AND_CHAIN)
748  result= startTransaction();
749  break;
750  case ROLLBACK_RELEASE:
751  do_release= 1; /* fall through */
752  case ROLLBACK:
753  case ROLLBACK_AND_CHAIN:
754  {
755  server_status&= ~SERVER_STATUS_IN_TRANS;
756  if (TransactionServices::rollbackTransaction(*this, true))
757  result= false;
758  options&= ~(OPTION_BEGIN);
759  if (result == true && (completion == ROLLBACK_AND_CHAIN))
760  result= startTransaction();
761  break;
762  }
763  default:
764  my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
765  return false;
766  }
767 
768  if (not result)
769  {
770  my_error(static_cast<drizzled::error_t>(killed_errno()), MYF(0));
771  }
772  else if (result && do_release)
773  {
774  setKilled(Session::KILL_CONNECTION);
775  }
776 
777  return result;
778 }
779 
780 bool Session::endActiveTransaction()
781 {
782  bool result= true;
783 
784  if (transaction.xid_state.xa_state != XA_NOTR)
785  {
786  my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
787  return false;
788  }
789  if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
790  {
791  server_status&= ~SERVER_STATUS_IN_TRANS;
793  result= false;
794  }
795  options&= ~(OPTION_BEGIN);
796  return result;
797 }
798 
799 bool Session::startTransaction(start_transaction_option_t opt)
800 {
801  assert(not inTransaction());
802 
803  options|= OPTION_BEGIN;
804  server_status|= SERVER_STATUS_IN_TRANS;
805 
807  return false;
808  return true;
809 }
810 
812 {
813  /*
814  Reset rand_used so that detection of calls to rand() will save random
815  seeds if needed by the slave.
816  */
818  {
819  /* set what LAST_INSERT_ID() will return */
823  }
824 
825  arg_of_last_insert_id_function= false;
826 
827  /* Free Items that were created during this execution */
828  free_items();
829 
830  /* Reset _where. */
832 
833  /* Reset the temporary shares we built */
834  impl_->temporary_shares.clear();
835 }
836 
848 {
849  if (not lex_str)
850  lex_str= new (mem) lex_string_t;
851  lex_str->assign(mem_root->strdup(str), str.size());
852  return lex_str;
853 }
854 
855 void Session::send_explain_fields(select_result *result)
856 {
857  List<Item> field_list;
858  Item *item;
859  const charset_info_st* cs= system_charset_info;
860  field_list.push_back(new Item_return_int("id",3, DRIZZLE_TYPE_LONGLONG));
861  field_list.push_back(new Item_empty_string("select_type", 19, cs));
862  field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
863  item->maybe_null= 1;
864  field_list.push_back(item= new Item_empty_string("type", 10, cs));
865  item->maybe_null= 1;
866  field_list.push_back(item= new Item_empty_string("possible_keys", NAME_CHAR_LEN*MAX_KEY, cs));
867  item->maybe_null=1;
868  field_list.push_back(item= new Item_empty_string("key", NAME_CHAR_LEN, cs));
869  item->maybe_null=1;
870  field_list.push_back(item= new Item_empty_string("key_len", MAX_KEY * (MAX_KEY_LENGTH_DECIMAL_WIDTH + 1 /* for comma */), cs));
871  item->maybe_null=1;
872  field_list.push_back(item= new Item_empty_string("ref", NAME_CHAR_LEN*MAX_REF_PARTS, cs));
873  item->maybe_null=1;
874  field_list.push_back(item= new Item_return_int("rows", 10, DRIZZLE_TYPE_LONGLONG));
875  if (lex().describe & DESCRIBE_EXTENDED)
876  {
877  field_list.push_back(item= new Item_float("filtered", 0.1234, 2, 4));
878  item->maybe_null=1;
879  }
880  item->maybe_null= 1;
881  field_list.push_back(new Item_empty_string("Extra", 255, cs));
882  result->send_fields(field_list);
883 }
884 
885 void select_result::send_error(drizzled::error_t errcode, const char *err)
886 {
887  my_message(errcode, err, MYF(0));
888 }
889 
890 /************************************************************************
891  Handling writing to file
892 ************************************************************************/
893 
894 void select_to_file::send_error(drizzled::error_t errcode,const char *err)
895 {
896  my_message(errcode, err, MYF(0));
897  if (file > 0)
898  {
899  (void) cache->end_io_cache();
900  (void) internal::my_close(file, MYF(0));
901  (void) internal::my_delete(path.file_string().c_str(), MYF(0)); // Delete file on error
902  file= -1;
903  }
904 }
905 
906 
907 bool select_to_file::send_eof()
908 {
909  int error= test(cache->end_io_cache());
910  if (internal::my_close(file, MYF(MY_WME)))
911  error= 1;
912  if (!error)
913  {
914  /*
915  In order to remember the value of affected rows for ROW_COUNT()
916  function, SELECT INTO has to have an own SQLCOM.
917  TODO: split from SQLCOM_SELECT
918  */
919  session->my_ok(row_count);
920  }
921  file= -1;
922  return error;
923 }
924 
925 
926 void select_to_file::cleanup()
927 {
928  /* In case of error send_eof() may be not called: close the file here. */
929  if (file >= 0)
930  {
931  (void) cache->end_io_cache();
932  (void) internal::my_close(file, MYF(0));
933  file= -1;
934  }
935  path= "";
936  row_count= 0;
937 }
938 
939 select_to_file::select_to_file(file_exchange *ex)
940  : exchange(ex),
941  file(-1),
942  cache(static_cast<internal::io_cache_st *>(memory::sql_calloc(sizeof(internal::io_cache_st)))),
943  row_count(0L)
944 {
945  path= "";
946 }
947 
948 select_to_file::~select_to_file()
949 {
950  cleanup();
951 }
952 
953 /***************************************************************************
954 ** Export of select to textfile
955 ***************************************************************************/
956 
957 select_export::~select_export()
958 {
959  session->sent_row_count=row_count;
960 }
961 
962 
963 /*
964  Create file with IO cache
965 
966  SYNOPSIS
967  create_file()
968  session Thread handle
969  path File name
970  exchange Excange class
971  cache IO cache
972 
973  RETURN
974  >= 0 File handle
975  -1 Error
976 */
977 
978 
979 static int create_file(Session& session,
980  fs::path &target_path,
981  file_exchange *exchange,
982  internal::io_cache_st *cache)
983 {
984  fs::path to_file(exchange->file_name);
985 
986  if (not to_file.has_root_directory())
987  {
988  target_path= fs::system_complete(catalog::local_identifier().getPath());
989  util::string::ptr schema(session.schema());
990  if (not schema->empty())
991  {
992  int count_elements= 0;
993  for (fs::path::iterator it= to_file.begin(); it != to_file.end(); it++)
994  count_elements++;
995  if (count_elements == 1)
996  target_path /= *schema;
997  }
998  target_path /= to_file;
999  }
1000  else
1001  {
1002  target_path = exchange->file_name;
1003  }
1004 
1005  if (not secure_file_priv.string().empty())
1006  {
1007  if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1008  {
1009  /* Write only allowed to dir or subdir specified by secure_file_priv */
1010  my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1011  return -1;
1012  }
1013  }
1014 
1015  if (!access(target_path.file_string().c_str(), F_OK))
1016  {
1017  my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1018  return -1;
1019  }
1020  /* Create the file world readable */
1021  int file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME));
1022  if (file < 0)
1023  return file;
1024  (void) fchmod(file, 0666); // Because of umask()
1025  if (cache->init_io_cache(file, 0, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1026  {
1027  internal::my_close(file, MYF(0));
1028  internal::my_delete(target_path.file_string().c_str(), MYF(0)); // Delete file on error, it was just created
1029  return -1;
1030  }
1031  return file;
1032 }
1033 
1034 
1035 int
1036 select_export::prepare(List<Item> &list, Select_Lex_Unit *u)
1037 {
1038  bool blob_flag=0;
1039  bool string_results= false, non_string_results= false;
1040  unit= u;
1041  if ((uint32_t) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
1042  {
1043  path= exchange->file_name;
1044  }
1045 
1046  /* Check if there is any blobs in data */
1047  {
1048  List<Item>::iterator li(list.begin());
1049  while (Item* item= li++)
1050  {
1051  if (item->max_length >= MAX_BLOB_WIDTH)
1052  {
1053  blob_flag=1;
1054  break;
1055  }
1056 
1057  if (item->result_type() == STRING_RESULT)
1058  string_results= true;
1059  else
1060  non_string_results= true;
1061  }
1062  }
1063  field_term_length=exchange->field_term->length();
1064  field_term_char= field_term_length ?
1065  (int) (unsigned char) (*exchange->field_term)[0] : INT_MAX;
1066  if (!exchange->line_term->length())
1067  exchange->line_term=exchange->field_term; // Use this if it exists
1068  field_sep_char= exchange->enclosed->length() ? (int) (unsigned char) (*exchange->enclosed)[0] : field_term_char;
1069  escape_char= exchange->escaped->length() ? (int) (unsigned char) (*exchange->escaped)[0] : -1;
1070  is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char));
1071  is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char));
1072  line_sep_char= exchange->line_term->length() ? (int) (unsigned char) (*exchange->line_term)[0] : INT_MAX;
1073  if (!field_term_length)
1074  exchange->opt_enclosed=0;
1075  if (!exchange->enclosed->length())
1076  exchange->opt_enclosed=1; // A little quicker loop
1077  fixed_row_size= (!field_term_length && !exchange->enclosed->length() &&
1078  !blob_flag);
1079  if ((is_ambiguous_field_sep && exchange->enclosed->empty() && (string_results || is_unsafe_field_sep)) ||
1080  (exchange->opt_enclosed && non_string_results && field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
1081  {
1082  my_error(ER_AMBIGUOUS_FIELD_TERM, MYF(0));
1083  return 1;
1084  }
1085 
1086  if ((file= create_file(*session, path, exchange, cache)) < 0)
1087  return 1;
1088 
1089  return 0;
1090 }
1091 
1092 bool select_export::send_data(List<Item> &items)
1093 {
1094  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
1095  bool space_inited=0;
1096  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
1097  tmp.length(0);
1098 
1099  if (unit->offset_limit_cnt)
1100  { // using limit offset,count
1101  unit->offset_limit_cnt--;
1102  return false;
1103  }
1104  row_count++;
1105  uint32_t used_length=0,items_left=items.size();
1106  List<Item>::iterator li(items.begin());
1107 
1108  if (cache->write(exchange->line_start->ptr(), exchange->line_start->length()))
1109  return true;
1110 
1111  while (Item* item=li++)
1112  {
1113  Item_result result_type=item->result_type();
1114  bool enclosed = (exchange->enclosed->length() &&
1115  (!exchange->opt_enclosed || result_type == STRING_RESULT));
1116  res=item->str_result(&tmp);
1117  if (res && enclosed)
1118  {
1119  if (cache->write(exchange->enclosed->ptr(), exchange->enclosed->length()))
1120  return true;
1121  }
1122  if (!res)
1123  { // NULL
1124  if (!fixed_row_size)
1125  {
1126  if (escape_char != -1) // Use \N syntax
1127  {
1128  null_buff[0]=escape_char;
1129  null_buff[1]='N';
1130  if (cache->write(null_buff, 2))
1131  return true;
1132  }
1133  else if (cache->write("NULL", 4))
1134  return true;
1135  }
1136  else
1137  {
1138  used_length=0; // Fill with space
1139  }
1140  }
1141  else
1142  {
1143  if (fixed_row_size)
1144  used_length= min(res->length(), static_cast<size_t>(item->max_length));
1145  else
1146  used_length= res->length();
1147 
1148  if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
1149  escape_char != -1)
1150  {
1151  char *pos, *start, *end;
1152  const charset_info_st* const res_charset= res->charset();
1153 
1154  for (start= pos= (char*) res->ptr(),end=pos+used_length; pos != end; pos++)
1155  {
1156  if (use_mb(res_charset))
1157  {
1158  if (int l= my_ismbchar(res_charset, pos, end))
1159  {
1160  pos += l - 1;
1161  continue;
1162  }
1163  }
1164 
1165  /*
1166  Special case when dumping BINARY/VARBINARY/BLOB values
1167  for the clients with character sets big5, cp932, gbk and sjis,
1168  which can have the escape character (0x5C "\" by default)
1169  as the second byte of a multi-byte sequence.
1170 
1171  If
1172  - pos[0] is a valid multi-byte head (e.g 0xEE) and
1173  - pos[1] is 0x00, which will be escaped as "\0",
1174 
1175  then we'll get "0xEE + 0x5C + 0x30" in the output file.
1176 
1177  If this file is later loaded using this sequence of commands:
1178 
1179  mysql> create table t1 (a varchar(128)) character set big5;
1180  mysql> LOAD DATA INFILE 'dump.txt' INTO Table t1;
1181 
1182  then 0x5C will be misinterpreted as the second byte
1183  of a multi-byte character "0xEE + 0x5C", instead of
1184  escape character for 0x00.
1185 
1186  To avoid this confusion, we'll escape the multi-byte
1187  head character too, so the sequence "0xEE + 0x00" will be
1188  dumped as "0x5C + 0xEE + 0x5C + 0x30".
1189 
1190  Note, in the condition below we only check if
1191  mbcharlen is equal to 2, because there are no
1192  character sets with mbmaxlen longer than 2
1193  and with escape_with_backslash_is_dangerous set.
1194  assert before the loop makes that sure.
1195  */
1196 
1197  if (needs_escaping(*pos, enclosed) &&
1198  /*
1199  Don't escape field_term_char by doubling - doubling is only
1200  valid for ENCLOSED BY characters:
1201  */
1202  (enclosed || !is_ambiguous_field_term ||
1203  (int) (unsigned char) *pos != field_term_char))
1204  {
1205  char tmp_buff[2];
1206  tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
1207  is_ambiguous_field_sep) ? field_sep_char : escape_char;
1208  tmp_buff[1]= *pos ? *pos : '0';
1209  if (cache->write(start, pos - start) || cache->write(tmp_buff, 2))
1210  return true;
1211  start=pos+1;
1212  }
1213  }
1214  if (cache->write(start, pos - start))
1215  return true;
1216  }
1217  else if (cache->write(res->ptr(), used_length))
1218  return true;
1219  }
1220  if (fixed_row_size)
1221  { // Fill with space
1222  if (item->max_length > used_length)
1223  {
1224  /* QQ: Fix by adding a my_b_fill() function */
1225  if (!space_inited)
1226  {
1227  space_inited=1;
1228  memset(space, ' ', sizeof(space));
1229  }
1230  uint32_t length=item->max_length-used_length;
1231  for (; length > sizeof(space) ; length-=sizeof(space))
1232  {
1233  if (cache->write(space, sizeof(space)))
1234  return true;
1235  }
1236  if (cache->write(space, length))
1237  return true;
1238  }
1239  }
1240  if (res && enclosed)
1241  {
1242  if (cache->write(exchange->enclosed->ptr(), exchange->enclosed->length()))
1243  return true;
1244  }
1245  if (--items_left)
1246  {
1247  if (cache->write(exchange->field_term->ptr(), field_term_length))
1248  return true;
1249  }
1250  }
1251  if (cache->write(exchange->line_term->ptr(), exchange->line_term->length()))
1252  {
1253  return true;
1254  }
1255 
1256  return false;
1257 }
1258 
1259 
1260 /***************************************************************************
1261 ** Dump of select to a binary file
1262 ***************************************************************************/
1263 
1264 
1265 int
1266 select_dump::prepare(List<Item> &, Select_Lex_Unit *u)
1267 {
1268  unit= u;
1269  return (file= create_file(*session, path, exchange, cache)) < 0;
1270 }
1271 
1272 
1273 bool select_dump::send_data(List<Item> &items)
1274 {
1275  List<Item>::iterator li(items.begin());
1276  char buff[MAX_FIELD_WIDTH];
1277  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
1278  tmp.length(0);
1279 
1280  if (unit->offset_limit_cnt)
1281  { // using limit offset,count
1282  unit->offset_limit_cnt--;
1283  return 0;
1284  }
1285  if (row_count++ > 1)
1286  {
1287  my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1288  return 1;
1289  }
1290  while (Item* item=li++)
1291  {
1292  res=item->str_result(&tmp);
1293  if (!res) // If NULL
1294  {
1295  if (cache->write("", 1))
1296  return 1;
1297  }
1298  else if (cache->write(res->ptr(), res->length()))
1299  {
1300  my_error(ER_ERROR_ON_WRITE, MYF(0), path.file_string().c_str(), errno);
1301  return 1;
1302  }
1303  }
1304  return 0;
1305 }
1306 
1307 
1308 select_subselect::select_subselect(Item_subselect *item_arg)
1309 {
1310  item= item_arg;
1311 }
1312 
1313 
1314 bool select_singlerow_subselect::send_data(List<Item> &items)
1315 {
1316  Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
1317  if (it->assigned())
1318  {
1319  my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
1320  return 1;
1321  }
1322  if (unit->offset_limit_cnt)
1323  { // Using limit offset,count
1324  unit->offset_limit_cnt--;
1325  return 0;
1326  }
1327  List<Item>::iterator li(items.begin());
1328  Item *val_item;
1329  for (uint32_t i= 0; (val_item= li++); i++)
1330  it->store(i, val_item);
1331  it->assigned(1);
1332  return 0;
1333 }
1334 
1335 
1336 void select_max_min_finder_subselect::cleanup()
1337 {
1338  cache= 0;
1339 }
1340 
1341 
1342 bool select_max_min_finder_subselect::send_data(List<Item> &items)
1343 {
1344  Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
1345  List<Item>::iterator li(items.begin());
1346  Item *val_item= li++;
1347  it->register_value();
1348  if (it->assigned())
1349  {
1350  cache->store(val_item);
1351  if ((this->*op)())
1352  it->store(0, cache);
1353  }
1354  else
1355  {
1356  if (!cache)
1357  {
1358  cache= Item_cache::get_cache(val_item);
1359  switch (val_item->result_type())
1360  {
1361  case REAL_RESULT:
1362  op= &select_max_min_finder_subselect::cmp_real;
1363  break;
1364  case INT_RESULT:
1365  op= &select_max_min_finder_subselect::cmp_int;
1366  break;
1367  case STRING_RESULT:
1368  op= &select_max_min_finder_subselect::cmp_str;
1369  break;
1370  case DECIMAL_RESULT:
1371  op= &select_max_min_finder_subselect::cmp_decimal;
1372  break;
1373  case ROW_RESULT:
1374  // This case should never be choosen
1375  assert(0);
1376  op= 0;
1377  }
1378  }
1379  cache->store(val_item);
1380  it->store(0, cache);
1381  }
1382  it->assigned(1);
1383  return 0;
1384 }
1385 
1386 bool select_max_min_finder_subselect::cmp_real()
1387 {
1388  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1389  double val1= cache->val_real(), val2= maxmin->val_real();
1390  if (fmax)
1391  return (cache->null_value && !maxmin->null_value) ||
1392  (!cache->null_value && !maxmin->null_value &&
1393  val1 > val2);
1394  return (maxmin->null_value && !cache->null_value) ||
1395  (!cache->null_value && !maxmin->null_value &&
1396  val1 < val2);
1397 }
1398 
1399 bool select_max_min_finder_subselect::cmp_int()
1400 {
1401  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1402  int64_t val1= cache->val_int(), val2= maxmin->val_int();
1403  if (fmax)
1404  return (cache->null_value && !maxmin->null_value) ||
1405  (!cache->null_value && !maxmin->null_value &&
1406  val1 > val2);
1407  return (maxmin->null_value && !cache->null_value) ||
1408  (!cache->null_value && !maxmin->null_value &&
1409  val1 < val2);
1410 }
1411 
1412 bool select_max_min_finder_subselect::cmp_decimal()
1413 {
1414  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1415  type::Decimal cval, *cvalue= cache->val_decimal(&cval);
1416  type::Decimal mval, *mvalue= maxmin->val_decimal(&mval);
1417  if (fmax)
1418  return (cache->null_value && !maxmin->null_value) ||
1419  (!cache->null_value && !maxmin->null_value &&
1420  class_decimal_cmp(cvalue, mvalue) > 0) ;
1421  return (maxmin->null_value && !cache->null_value) ||
1422  (!cache->null_value && !maxmin->null_value &&
1423  class_decimal_cmp(cvalue,mvalue) < 0);
1424 }
1425 
1426 bool select_max_min_finder_subselect::cmp_str()
1427 {
1428  String *val1, *val2, buf1, buf2;
1429  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1430  /*
1431  as far as both operand is Item_cache buf1 & buf2 will not be used,
1432  but added for safety
1433  */
1434  val1= cache->val_str(&buf1);
1435  val2= maxmin->val_str(&buf1);
1436  if (fmax)
1437  return (cache->null_value && !maxmin->null_value) ||
1438  (!cache->null_value && !maxmin->null_value &&
1439  sortcmp(val1, val2, cache->collation.collation) > 0) ;
1440  return (maxmin->null_value && !cache->null_value) ||
1441  (!cache->null_value && !maxmin->null_value &&
1442  sortcmp(val1, val2, cache->collation.collation) < 0);
1443 }
1444 
1445 bool select_exists_subselect::send_data(List<Item> &)
1446 {
1447  Item_exists_subselect *it= (Item_exists_subselect *)item;
1448  if (unit->offset_limit_cnt)
1449  { // Using limit offset,count
1450  unit->offset_limit_cnt--;
1451  return 0;
1452  }
1453  it->value= 1;
1454  it->assigned(1);
1455  return 0;
1456 }
1457 
1458 /*
1459  Don't free mem_root, as mem_root is freed in the end of dispatch_command
1460  (once for any command).
1461 */
1463 {
1464  /* Cleanup SQL processing state to reuse this statement in next query. */
1465  lex().end();
1467 }
1468 
1469 str_ref Session::copy_db_to() const
1470 {
1471  if (not impl_->schema->empty())
1472  return str_ref(mem.strdup(*impl_->schema), impl_->schema->size());
1473  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1474  return str_ref();
1475 }
1476 
1477 /****************************************************************************
1478  Tmp_Table_Param
1479 ****************************************************************************/
1480 
1481 void Tmp_Table_Param::init()
1482 {
1483  field_count= sum_func_count= func_count= hidden_field_count= 0;
1484  group_parts= group_length= group_null_parts= 0;
1485  quick_group= 1;
1486  table_charset= 0;
1487  precomputed_group_by= 0;
1488 }
1489 
1490 void Tmp_Table_Param::cleanup()
1491 {
1492  /* Fix for Intel compiler */
1493  if (copy_field)
1494  {
1495  boost::checked_array_delete(copy_field);
1496  save_copy_field= save_copy_field_end= copy_field= copy_field_end= 0;
1497  }
1498 }
1499 
1500 void Session::send_kill_message() const
1501 {
1502  drizzled::error_t err= static_cast<drizzled::error_t>(killed_errno());
1503  if (err != EE_OK)
1504  my_message(err, ER(err), MYF(0));
1505 }
1506 
1507 void Session::set_schema(const std::string& new_db)
1508 {
1509  impl_->schema = boost::make_shared<std::string>(new_db);
1510 }
1511 
1512 
1520 {
1523 }
1524 
1525 void Session::disconnect(error_t errcode)
1526 {
1527  /* Allow any plugins to cleanup their session variables */
1528  plugin_sessionvar_cleanup(this);
1529 
1530  /* If necessary, log any aborted or unauthorized connections */
1531  if (getKilled() || client->wasAborted())
1532  {
1533  status_var.aborted_threads++;
1534  }
1535 
1536  if (client->wasAborted())
1537  {
1538  if (not getKilled() && variables.log_warnings > 1)
1539  {
1540  errmsg_printf(error::WARN, ER(ER_NEW_ABORTING_CONNECTION)
1541  , thread_id
1542  , (impl_->schema->empty() ? "unconnected" : impl_->schema->c_str())
1543  , security_ctx->username().empty() ? "unauthenticated" : security_ctx->username().c_str()
1544  , security_ctx->address().c_str()
1545  , (main_da().is_error() ? main_da().message() : ER(ER_UNKNOWN_ERROR)));
1546  }
1547  }
1548 
1549  setKilled(Session::KILL_CONNECTION);
1550 
1551  if (client->isConnected())
1552  {
1553  if (errcode != EE_OK)
1554  {
1555  /*my_error(errcode, ER(errcode));*/
1556  client->sendError(errcode, ER(errcode));
1557  }
1558  client->close();
1559  }
1560 }
1561 
1563 {
1564  free_list= 0;
1565  select_number= 1;
1566 
1567  is_fatal_error= false;
1568  server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
1569  SERVER_QUERY_NO_INDEX_USED |
1570  SERVER_QUERY_NO_GOOD_INDEX_USED);
1571 
1572  clear_error();
1573  main_da().reset_diagnostics_area();
1574  total_warn_count=0; // Warnings for this query
1576 }
1577 
1578 /*
1579  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
1580 */
1581 
1582 void Open_tables_state::close_temporary_tables()
1583 {
1584  Table *table;
1585  Table *tmp_next;
1586 
1587  if (not temporary_tables)
1588  return;
1589 
1590  for (table= temporary_tables; table; table= tmp_next)
1591  {
1592  tmp_next= table->getNext();
1593  nukeTable(table);
1594  }
1595  temporary_tables= NULL;
1596 }
1597 
1598 /*
1599  unlink from session->temporary tables and close temporary table
1600 */
1601 
1602 void Open_tables_state::close_temporary_table(Table *table)
1603 {
1604  if (table->getPrev())
1605  {
1606  table->getPrev()->setNext(table->getNext());
1607  if (table->getPrev()->getNext())
1608  {
1609  table->getNext()->setPrev(table->getPrev());
1610  }
1611  }
1612  else
1613  {
1614  /* removing the item from the list */
1615  assert(table == temporary_tables);
1616  /*
1617  slave must reset its temporary list pointer to zero to exclude
1618  passing non-zero value to end_slave via rli->save_temporary_tables
1619  when no temp tables opened, see an invariant below.
1620  */
1621  temporary_tables= table->getNext();
1622  if (temporary_tables)
1623  {
1624  table->getNext()->setPrev(NULL);
1625  }
1626  }
1627  nukeTable(table);
1628 }
1629 
1630 /*
1631  Close and drop a temporary table
1632 
1633  NOTE
1634  This dosn't unlink table from session->temporary
1635  If this is needed, use close_temporary_table()
1636 */
1637 
1638 void Open_tables_state::nukeTable(Table *table)
1639 {
1640  plugin::StorageEngine& table_type= *table->getShare()->db_type();
1641  table->free_io_cache();
1642  table->delete_table();
1643  rm_temporary_table(table_type, identifier::Table(table->getShare()->getTableIdentifier().getCatalog(), table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath()));
1644  boost::checked_delete(table->getMutableShare());
1645  boost::checked_delete(table);
1646 }
1647 
1649 extern time_t flush_status_time;
1650 
1651 void Session::refresh_status()
1652 {
1653  /* Reset thread's status variables */
1654  memset(&status_var, 0, sizeof(status_var));
1655 
1656  flush_status_time= time((time_t*) 0);
1657  current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1658  current_global_counters.connections= 0;
1659 }
1660 
1661 user_var_entry* Session::getVariable(str_ref name0, bool create_if_not_exists)
1662 {
1663  if (cleanup_done)
1664  return NULL;
1665 
1666  string name(name0.data(), name0.size());
1667  if (UserVars::mapped_type* iter= find_ptr(user_vars, name))
1668  return *iter;
1669 
1670  if (not create_if_not_exists)
1671  return NULL;
1672 
1673  user_var_entry *entry= new user_var_entry(name.c_str(), query_id);
1674 
1675  std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1676 
1677  if (not returnable.second)
1678  {
1679  boost::checked_delete(entry);
1680  }
1681 
1682  return entry;
1683 }
1684 
1685 void Session::setVariable(const std::string &name, const std::string &value)
1686 {
1687  if (user_var_entry* var= getVariable(name, true))
1688  {
1689  var->update_hash(false, value, STRING_RESULT, &my_charset_bin, DERIVATION_IMPLICIT, false);
1690  }
1691 }
1692 
1694 {
1695  for (Table *table= temporary_tables ; table ; table= table->getNext())
1696  {
1697  if (table->query_id == session_.getQueryId())
1698  {
1699  table->query_id= 0;
1700  table->cursor->ha_reset();
1701  }
1702  }
1703 }
1704 
1705 /*
1706  Unlocks tables and frees derived tables.
1707  Put all normal tables used by thread in free list.
1708 
1709  It will only close/mark as free for reuse tables opened by this
1710  substatement, it will also check if we are closing tables after
1711  execution of complete query (i.e. we are on upper level) and will
1712  leave prelocked mode if needed.
1713 */
1715 {
1716  open_tables.clearDerivedTables();
1717 
1718  /*
1719  Mark all temporary tables used by this statement as free for reuse.
1720  */
1721  open_tables.mark_temp_tables_as_free_for_reuse();
1722  /*
1723  Let us commit transaction for statement. Since in 5.0 we only have
1724  one statement transaction and don't allow several nested statement
1725  transactions this call will do nothing if we are inside of stored
1726  function or trigger (i.e. statement transaction is already active and
1727  does not belong to statement for which we do close_thread_tables()).
1728  TODO: This should be fixed in later releases.
1729  */
1730  {
1731  main_da().can_overwrite_status= true;
1733  main_da().can_overwrite_status= false;
1734  transaction.stmt.reset();
1735  }
1736 
1737  if (open_tables.lock)
1738  {
1739  unlockTables(open_tables.lock);
1740  open_tables.lock= 0;
1741  }
1742  /*
1743  Note that we need to hold table::Cache::mutex() while changing the
1744  open_tables list. Another thread may work on it.
1745  (See: table::Cache::removeTable(), wait_completed_table())
1746  Closing a MERGE child before the parent would be fatal if the
1747  other thread tries to abort the MERGE lock in between.
1748  */
1749  if (open_tables.open_tables_)
1750  open_tables.close_open_tables();
1751 }
1752 
1754 {
1755  /*
1756  If table list consists only from tables from prelocking set, table list
1757  for new attempt should be empty, so we have to update list's root pointer.
1758  */
1759  if (lex().first_not_own_table() == *tables)
1760  *tables= 0;
1761  lex().chop_off_not_own_tables();
1762  for (TableList *tmp= *tables; tmp; tmp= tmp->next_global)
1763  tmp->table= 0;
1765 }
1766 
1768 {
1769  uint32_t counter;
1770  bool need_reopen;
1771 
1772  for ( ; ; )
1773  {
1774  if (open_tables_from_list(&tables, &counter))
1775  return true;
1776 
1777  if (not lock_tables(tables, counter, &need_reopen))
1778  break;
1779 
1780  if (not need_reopen)
1781  return true;
1782 
1783  close_tables_for_reopen(&tables);
1784  }
1785 
1786  return handle_derived(&lex(), &derived_prepare) || handle_derived(&lex(), &derived_filling);
1787 }
1788 
1789 /*
1790  @note "best_effort" is used in cases were if a failure occurred on this
1791  operation it would not be surprising because we are only removing because there
1792  might be an issue (lame engines).
1793 */
1794 
1795 bool Open_tables_state::rm_temporary_table(const identifier::Table &identifier, bool best_effort)
1796 {
1797  if (plugin::StorageEngine::dropTable(session_, identifier))
1798  return false;
1799  if (not best_effort)
1800  errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"), identifier.getSQLPath().c_str(), errno);
1801  return true;
1802 }
1803 
1804 bool Open_tables_state::rm_temporary_table(plugin::StorageEngine& base, const identifier::Table &identifier)
1805 {
1806  drizzled::error_t error;
1807  if (plugin::StorageEngine::dropTable(session_, base, identifier, error))
1808  return false;
1809  errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"), identifier.getSQLPath().c_str(), error);
1810  return true;
1811 }
1812 
1813 table::Singular& Session::getInstanceTable()
1814 {
1815  impl_->temporary_shares.push_back(new table::Singular); // This will not go into the tableshare cache, so no key is used.
1816  return impl_->temporary_shares.back();
1817 }
1818 
1819 
1838 table::Singular& Session::getInstanceTable(std::list<CreateField>& field_list)
1839 {
1840  impl_->temporary_shares.push_back(new table::Singular(this, field_list)); // This will not go into the tableshare cache, so no key is used.
1841  return impl_->temporary_shares.back();
1842 }
1843 
1844 void Session::clear_error(bool full)
1845 {
1846  if (main_da().is_error())
1847  main_da().reset_diagnostics_area();
1848 
1849  if (full)
1850  drizzle_reset_errors(*this, true);
1851 }
1852 
1853 void Session::clearDiagnostics()
1854 {
1855  main_da().reset_diagnostics_area();
1856 }
1857 
1871 bool Session::is_error() const
1872 {
1873  return impl_->diagnostics.is_error();
1874 }
1875 
1877 void Session::my_ok(ha_rows affected_rows, ha_rows found_rows_arg, uint64_t passed_id, const char *message)
1878 {
1879  main_da().set_ok_status(this, affected_rows, found_rows_arg, passed_id, message);
1880 }
1881 
1885 {
1886  main_da().set_eof_status(this);
1887 }
1888 
1890 {
1891  return variables.storage_engine ? variables.storage_engine : global_system_variables.storage_engine;
1892 }
1893 
1894 enum_tx_isolation Session::getTxIsolation() const
1895 {
1896  return (enum_tx_isolation)variables.tx_isolation;
1897 }
1898 
1899 drizzled::util::Storable* Session::getProperty0(const std::string& arg)
1900 {
1901  return impl_->properties[arg];
1902 }
1903 
1904 void Session::setProperty0(const std::string& arg, drizzled::util::Storable* value)
1905 {
1906  // assert(not _properties.count(arg));
1907  impl_->properties[arg]= value;
1908 }
1909 
1910 plugin::EventObserverList* Session::getSchemaObservers(const std::string &db_name)
1911 {
1912  if (impl_c::schema_event_observers_t::mapped_type* i= find_ptr(impl_->schema_event_observers, db_name))
1913  return *i;
1914  return NULL;
1915 }
1916 
1917 plugin::EventObserverList* Session::setSchemaObservers(const std::string &db_name, plugin::EventObserverList* observers)
1918 {
1919  impl_->schema_event_observers.erase(db_name);
1920  if (observers)
1921  impl_->schema_event_observers[db_name] = observers;
1922  return observers;
1923 }
1924 
1925 util::string::ptr Session::schema() const
1926 {
1927  return impl_->schema;
1928 }
1929 
1930 void Session::resetQueryString()
1931 {
1932  query.reset();
1933  impl_->state.reset();
1934 }
1935 
1936 const boost::shared_ptr<session::State>& Session::state()
1937 {
1938  return impl_->state;
1939 }
1940 
1941 const std::string& display::type(drizzled::Session::global_read_lock_t type)
1942 {
1943  static const std::string NONE= "NONE";
1944  static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
1945  static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
1946 
1947  switch (type)
1948  {
1949  default:
1950  case Session::NONE:
1951  return NONE;
1952  case Session::GOT_GLOBAL_READ_LOCK:
1953  return GOT_GLOBAL_READ_LOCK;
1954  case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
1955  return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1956  }
1957 }
1958 
1959 size_t display::max_string_length(drizzled::Session::global_read_lock_t)
1960 {
1961  return display::type(Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT).size();
1962 }
1963 
1964 } /* namespace drizzled */
bool authenticate()
Definition: session.cc:649
void my_ok(ha_rows affected_rows=0, ha_rows found_rows_arg=0, uint64_t passed_id=0, const char *message=NULL)
Definition: session.cc:1877
uint32_t row_count
Definition: session.h:447
uint32_t warn_count[(uint32_t) DRIZZLE_ERROR::WARN_LEVEL_END]
Definition: session.h:440
A set of Session members describing the current authenticated user.
Definition: user.h:34
TableList * next_global
Definition: table_list.h:110
plugin::Scheduler * scheduler
Definition: session.h:185
bool substitute_null_with_insert_id
Definition: session.h:560
void free_items()
Definition: session.cc:351
Definition: vertex.h:34
void set_proc_info(const char *info)
Definition: session.h:609
bool transaction_rollback_request
Definition: session.h:546
ha_rows examined_row_count
Definition: session.h:419
void prepareForQueries()
Definition: session.cc:538
ha_rows cuted_fields
Definition: session.h:408
bool checkUser(const std::string &passwd, const std::string &db)
Definition: session.cc:659
TODO: Rename this file - func.h is stupid.
static bool isAuthorized(const drizzled::identifier::User &user_ctx, const identifier::Schema &schema_identifier, bool send_error=true)
void end_statement()
Definition: session.cc:1462
void readAndStoreQuery(str_ref)
Definition: session.cc:706
char * thread_stack
Definition: session.h:211
int class_decimal_cmp(const type::Decimal *a, const type::Decimal *b)
Definition: decimal.h:425
Item * free_list
Definition: session.h:116
uint64_t first_successful_insert_id_in_prev_stmt
Definition: session.h:379
uint64_t first_successful_insert_id_in_cur_stmt
Definition: session.h:385
void close_thread_tables()
Definition: session.cc:1714
virtual void killSession(Session *)
Definition: scheduler.h:51
void resetResultsetMessage()
Definition: session.h:946
Definition: wakeup.h:27
memory::Root warn_root
Definition: session.h:176
ha_rows sent_row_count
Definition: session.h:414
lex_string_t * make_lex_string(lex_string_t *, str_ref)
Definition: session.cc:847
bool maybe_null
Definition: item.h:121
DRIZZLED_API int tmpfile(const char *prefix)
Definition: session.cc:121
query_id_t getQueryId() const
Definition: session.h:625
bool is_fatal_sub_stmt_error
Definition: session.h:558
void reset_defaults(size_t block_size, size_t prealloc_size)
Definition: root.cc:81
static const char *const DEFAULT_WHERE
Definition: session.h:174
void set_eof_status(Session *session)
Definition: engine.cc:41
void init(size_t block_size=ROOT_MIN_BLOCK_SIZE)
Initialize memory root.
Definition: root.cc:57
bool executeStatement()
Definition: session.cc:677
bool endTransaction(enum enum_mysql_completiontype completion)
Definition: session.cc:720
bool isViewable(const identifier::User &) const
Definition: session.cc:618
bool is_fatal_error
Definition: session.h:540
void set_ok_status(Session *session, ha_rows affected_rows_arg, ha_rows found_rows_arg, uint64_t last_insert_id_arg, const char *message)
void reset_for_next_command()
Definition: session.cc:1562
void mark_temp_tables_as_free_for_reuse()
Definition: session.cc:1693
const char * _where
Definition: session.h:270
bool no_warnings_for_error
Definition: session.h:565
time_t flush_status_time
Definition: drizzled.cc:295
UserVars user_vars
Definition: session.h:191
uint64_t options
Definition: session.h:400
plugin::StorageEngine * getDefaultStorageEngine()
Definition: session.cc:1889
enum_server_command command
Definition: session.h:322
void close_tables_for_reopen(TableList **tables)
Definition: session.cc:1753
uint32_t select_number
Definition: session.h:498
static void closeConnection(Session &)
static int commitTransaction(Session &, bool all)
void markTransactionForRollback(bool all)
Definition: session.cc:1519
memory::Root * mem_root
Definition: session.h:118
THR_LOCK_OWNER main_lock_id
Definition: session.h:204
static int notifyStartTransaction(Session *session, start_transaction_option_t options)
void free_root(myf MyFLAGS)
Deallocate everything used by alloc_root or just move used blocks to free list if called with MY_USED...
Definition: root.cc:288
drizzle_system_variables & variables
Definition: session.h:199
static int autocommitOrRollback(Session &, int error)
static void rewriteQuery(const std::string &schema, std::string &to_rewrite)
bool inTransaction() const
Definition: session.h:771
void set_schema(const std::string &)
Definition: session.cc:1507
void disconnect(enum error_t errcode=EE_OK)
Definition: session.cc:1525
char * strdup(const char *)
Duplicate a null-terminated string into memory allocated from within the specified Root...
Definition: root.cc:328
void cleanup_after_query()
Definition: session.cc:811
bool openTablesLock(TableList *)
Definition: session.cc:1767
bool is_error() const
Definition: session.cc:1871
bool dispatch_command(enum_server_command command, Session &session, str_ref packet)
Definition: sql_parse.cc:192
THR_LOCK_INFO lock_info
Definition: session.h:203