~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/session.cc

  • Committer: Monty Taylor
  • Date: 2010-09-26 21:24:38 UTC
  • mto: (1796.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1797.
  • Revision ID: mordred@inaugust.com-20100926212438-iq8smt4jt6887oo3
Made some TOC structure changes. Added stubs for a couple of command line
programs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 */
23
23
 
24
24
#include "config.h"
25
 
#include "drizzled/session.h"
26
 
#include "drizzled/session/cache.h"
 
25
#include <drizzled/session.h>
 
26
#include "drizzled/session_list.h"
27
27
#include <sys/stat.h>
28
 
#include "drizzled/error.h"
29
 
#include "drizzled/gettext.h"
30
 
#include "drizzled/query_id.h"
31
 
#include "drizzled/data_home.h"
32
 
#include "drizzled/sql_base.h"
33
 
#include "drizzled/lock.h"
34
 
#include "drizzled/item/cache.h"
35
 
#include "drizzled/item/float.h"
36
 
#include "drizzled/item/return_int.h"
37
 
#include "drizzled/item/empty_string.h"
38
 
#include "drizzled/show.h"
39
 
#include "drizzled/plugin/client.h"
 
28
#include <drizzled/error.h>
 
29
#include <drizzled/gettext.h>
 
30
#include <drizzled/query_id.h>
 
31
#include <drizzled/data_home.h>
 
32
#include <drizzled/sql_base.h>
 
33
#include <drizzled/lock.h>
 
34
#include <drizzled/item/cache.h>
 
35
#include <drizzled/item/float.h>
 
36
#include <drizzled/item/return_int.h>
 
37
#include <drizzled/item/empty_string.h>
 
38
#include <drizzled/show.h>
 
39
#include <drizzled/plugin/client.h>
40
40
#include "drizzled/plugin/scheduler.h"
41
41
#include "drizzled/plugin/authentication.h"
42
42
#include "drizzled/plugin/logging.h"
43
43
#include "drizzled/plugin/transactional_storage_engine.h"
44
 
#include "drizzled/plugin/query_rewrite.h"
45
44
#include "drizzled/probes.h"
46
45
#include "drizzled/table_proto.h"
47
46
#include "drizzled/db.h"
49
48
#include "drizzled/transaction_services.h"
50
49
#include "drizzled/drizzled.h"
51
50
 
52
 
#include "drizzled/identifier.h"
53
 
 
54
 
#include "drizzled/table/instance.h"
 
51
#include "drizzled/table_share_instance.h"
55
52
 
56
53
#include "plugin/myisam/myisam.h"
57
54
#include "drizzled/internal/iocache.h"
58
55
#include "drizzled/internal/thread_var.h"
59
56
#include "drizzled/plugin/event_observer.h"
60
57
 
61
 
#include "drizzled/util/functors.h"
62
 
 
63
 
#include "drizzled/display.h"
64
 
 
65
58
#include <fcntl.h>
66
59
#include <algorithm>
67
60
#include <climits>
68
 
#include <boost/filesystem.hpp>
69
 
 
70
 
#include "drizzled/util/backtrace.h"
 
61
#include "boost/filesystem.hpp" 
71
62
 
72
63
using namespace std;
73
64
 
88
79
{
89
80
  return length == other.length &&
90
81
         field_name.length == other.field_name.length &&
91
 
    !my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
 
82
         !strcmp(field_name.str, other.field_name.str);
92
83
}
93
84
 
94
85
Open_tables_state::Open_tables_state(uint64_t version_arg) :
164
155
Session::Session(plugin::Client *client_arg) :
165
156
  Open_tables_state(refresh_version),
166
157
  mem_root(&main_mem_root),
167
 
  xa_id(0),
168
158
  lex(&main_lex),
169
 
  query(new std::string),
170
 
  _schema(new std::string("")),
171
 
  catalog("LOCAL"),
 
159
  query(),
172
160
  client(client_arg),
173
161
  scheduler(NULL),
174
162
  scheduler_arg(NULL),
175
163
  lock_id(&main_lock_id),
176
 
  thread_stack(NULL),
177
 
  security_ctx(identifier::User::make_shared()),
178
164
  user_time(0),
179
165
  ha_data(plugin::num_trx_monitored_objects),
180
 
  concurrent_execute_allowed(true),
181
166
  arg_of_last_insert_id_function(false),
182
167
  first_successful_insert_id_in_prev_stmt(0),
183
168
  first_successful_insert_id_in_cur_stmt(0),
184
169
  limit_found_rows(0),
185
 
  _global_read_lock(NONE),
186
 
  _killed(NOT_KILLED),
 
170
  global_read_lock(0),
187
171
  some_tables_deleted(false),
188
172
  no_errors(false),
189
173
  password(false),
199
183
  session_event_observers(NULL),
200
184
  use_usage(false)
201
185
{
 
186
  memset(process_list_info, 0, PROCESS_LIST_WIDTH);
202
187
  client->setSession(this);
203
188
 
204
189
  /*
207
192
    will be re-initialized in init_for_queries().
208
193
  */
209
194
  memory::init_sql_alloc(&main_mem_root, memory::ROOT_MIN_BLOCK_SIZE, 0);
 
195
  thread_stack= NULL;
210
196
  count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
 
197
  killed= NOT_KILLED;
211
198
  col_access= 0;
212
199
  tmp_table= 0;
213
200
  used_tables= 0;
316
303
    return;
317
304
 
318
305
  setAbort(true);
319
 
  boost_unique_lock_t scopedLock(mysys_var->mutex);
 
306
  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
320
307
  if (mysys_var->current_cond)
321
308
  {
322
309
    mysys_var->current_mutex->lock();
323
 
    mysys_var->current_cond->notify_all();
 
310
    pthread_cond_broadcast(mysys_var->current_cond->native_handle());
324
311
    mysys_var->current_mutex->unlock();
325
312
  }
326
313
}
342
329
{
343
330
  assert(cleanup_done == false);
344
331
 
345
 
  setKilled(KILL_CONNECTION);
 
332
  killed= KILL_CONNECTION;
346
333
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
347
334
  if (transaction.xid_state.xa_state == XA_PREPARED)
348
335
  {
368
355
  close_temporary_tables();
369
356
 
370
357
  if (global_read_lock)
371
 
  {
372
 
    unlockGlobalReadLock();
373
 
  }
 
358
    unlock_global_read_lock(this);
374
359
 
375
360
  cleanup_done= true;
376
361
}
381
366
 
382
367
  if (client->isConnected())
383
368
  {
384
 
    assert(security_ctx);
385
369
    if (global_system_variables.log_warnings)
386
 
    {
387
 
      errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),
388
 
                    internal::my_progname,
389
 
                    thread_id,
390
 
                    security_ctx->username().c_str());
391
 
    }
392
 
 
 
370
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),internal::my_progname,
 
371
                      thread_id,
 
372
                      (getSecurityContext().getUser().c_str() ?
 
373
                       getSecurityContext().getUser().c_str() : ""));
393
374
    disconnect(0, false);
394
375
  }
395
376
 
419
400
    delete (*iter).second;
420
401
  }
421
402
  life_properties.clear();
422
 
}
423
 
 
424
 
void Session::setClient(plugin::Client *client_arg)
425
 
{
426
 
  client= client_arg;
427
 
  client->setSession(this);
428
 
}
429
 
 
430
 
void Session::awake(Session::killed_state_t state_to_set)
431
 
{
432
 
  if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
433
 
    return;
434
 
 
 
403
 
 
404
  /* Ensure that no one is using Session */
 
405
  LOCK_delete.unlock();
 
406
}
 
407
 
 
408
void Session::awake(Session::killed_state state_to_set)
 
409
{
435
410
  this->checkSentry();
436
 
 
437
 
  setKilled(state_to_set);
438
 
  scheduler->killSession(this);
439
 
 
 
411
  safe_mutex_assert_owner(&LOCK_delete);
 
412
 
 
413
  killed= state_to_set;
440
414
  if (state_to_set != Session::KILL_QUERY)
441
415
  {
 
416
    scheduler->killSession(this);
442
417
    DRIZZLE_CONNECTION_DONE(thread_id);
443
418
  }
444
 
 
445
419
  if (mysys_var)
446
420
  {
447
 
    boost_unique_lock_t scopedLock(mysys_var->mutex);
 
421
    boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
448
422
    /*
449
423
      "
450
424
      This broadcast could be up in the air if the victim thread
468
442
    if (mysys_var->current_cond && mysys_var->current_mutex)
469
443
    {
470
444
      mysys_var->current_mutex->lock();
471
 
      mysys_var->current_cond->notify_all();
 
445
      pthread_cond_broadcast(mysys_var->current_cond->native_handle());
472
446
      mysys_var->current_mutex->unlock();
473
447
    }
474
448
  }
554
528
 
555
529
  prepareForQueries();
556
530
 
557
 
  while (not client->haveError() && getKilled() != KILL_CONNECTION)
 
531
  while (! client->haveError() && killed != KILL_CONNECTION)
558
532
  {
559
 
    if (not executeStatement())
 
533
    if (! executeStatement())
560
534
      break;
561
535
  }
562
536
 
563
537
  disconnect(0, true);
564
538
}
565
539
 
566
 
bool Session::schedule(Session::shared_ptr &arg)
 
540
bool Session::schedule()
567
541
{
568
 
  arg->scheduler= plugin::Scheduler::getScheduler();
569
 
  assert(arg->scheduler);
 
542
  scheduler= plugin::Scheduler::getScheduler();
 
543
  assert(scheduler);
570
544
 
571
545
  connection_count.increment();
572
546
 
576
550
  }
577
551
 
578
552
  current_global_counters.connections++;
579
 
  arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
580
 
 
581
 
  session::Cache::singleton().insert(arg);
582
 
 
583
 
  if (unlikely(plugin::EventObserver::connectSession(*arg)))
584
 
  {
585
 
    // We should do something about an error...
586
 
  }
587
 
 
588
 
  if (plugin::Scheduler::getScheduler()->addSession(arg))
589
 
  {
590
 
    DRIZZLE_CONNECTION_START(arg->getSessionId());
 
553
  thread_id= variables.pseudo_thread_id= global_thread_id++;
 
554
 
 
555
  LOCK_thread_count.lock();
 
556
  getSessionList().push_back(this);
 
557
  LOCK_thread_count.unlock();
 
558
 
 
559
  if (scheduler->addSession(this))
 
560
  {
 
561
    DRIZZLE_CONNECTION_START(thread_id);
591
562
    char error_message_buff[DRIZZLE_ERRMSG_SIZE];
592
563
 
593
 
    arg->setKilled(Session::KILL_CONNECTION);
 
564
    killed= Session::KILL_CONNECTION;
594
565
 
595
 
    arg->status_var.aborted_connects++;
 
566
    status_var.aborted_connects++;
596
567
 
597
568
    /* Can't use my_error() since store_globals has not been called. */
598
569
    /* TODO replace will better error message */
599
570
    snprintf(error_message_buff, sizeof(error_message_buff),
600
571
             ER(ER_CANT_CREATE_THREAD), 1);
601
 
    arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
602
 
 
 
572
    client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
603
573
    return true;
604
574
  }
605
575
 
607
577
}
608
578
 
609
579
 
610
 
/*
611
 
  Is this session viewable by the current user?
612
 
*/
613
 
bool Session::isViewable() const
614
 
{
615
 
  return plugin::Authorization::isAuthorized(current_session->user(),
616
 
                                             this,
617
 
                                             false);
618
 
}
619
 
 
620
 
 
621
 
const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
 
580
const char* Session::enter_cond(boost::condition_variable &cond, boost::mutex &mutex, const char* msg)
622
581
{
623
582
  const char* old_msg = get_proc_info();
624
583
  safe_mutex_assert_owner(mutex);
637
596
    does a Session::awake() on you).
638
597
  */
639
598
  mysys_var->current_mutex->unlock();
640
 
  boost_unique_lock_t scopedLock(mysys_var->mutex);
 
599
  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
641
600
  mysys_var->current_mutex = 0;
642
601
  mysys_var->current_cond = 0;
643
602
  this->set_proc_info(old_msg);
645
604
 
646
605
bool Session::authenticate()
647
606
{
648
 
  lex->start(this);
 
607
  lex_start(this);
649
608
  if (client->authenticate())
650
609
    return false;
651
610
 
654
613
  return true;
655
614
}
656
615
 
657
 
bool Session::checkUser(const std::string &passwd_str,
658
 
                        const std::string &in_db)
 
616
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
659
617
{
 
618
  const string passwd_str(passwd, passwd_len);
660
619
  bool is_authenticated=
661
 
    plugin::Authentication::isAuthenticated(user(), passwd_str);
 
620
    plugin::Authentication::isAuthenticated(getSecurityContext(),
 
621
                                            passwd_str);
662
622
 
663
623
  if (is_authenticated != true)
664
624
  {
668
628
  }
669
629
 
670
630
  /* Change database if necessary */
671
 
  if (not in_db.empty())
 
631
  if (in_db && in_db[0])
672
632
  {
673
633
    SchemaIdentifier identifier(in_db);
674
634
    if (mysql_change_db(this, identifier))
678
638
    }
679
639
  }
680
640
  my_ok();
681
 
  password= not passwd_str.empty();
 
641
  password= test(passwd_len);          // remember for error messages
682
642
 
683
643
  /* Ready to handle queries */
684
644
  return true;
700
660
  main_da.reset_diagnostics_area();
701
661
 
702
662
  if (client->readCommand(&l_packet, &packet_length) == false)
703
 
  {
704
663
    return false;
705
 
  }
706
664
 
707
 
  if (getKilled() == KILL_CONNECTION)
 
665
  if (killed == KILL_CONNECTION)
708
666
    return false;
709
667
 
710
668
  if (packet_length == 0)
711
669
    return true;
712
670
 
713
 
  l_command= static_cast<enum_server_command>(l_packet[0]);
 
671
  l_command= (enum enum_server_command) (unsigned char) l_packet[0];
714
672
 
715
673
  if (command >= COM_END)
716
674
    command= COM_END;                           // Wrong command
717
675
 
718
676
  assert(packet_length);
719
 
  return not dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
 
677
  return ! dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
720
678
}
721
679
 
722
680
bool Session::readAndStoreQuery(const char *in_packet, uint32_t in_packet_length)
728
686
    in_packet_length--;
729
687
  }
730
688
  const char *pos= in_packet + in_packet_length; /* Point at end null */
731
 
  while (in_packet_length > 0 && (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
 
689
  while (in_packet_length > 0 &&
 
690
         (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
732
691
  {
733
692
    pos--;
734
693
    in_packet_length--;
735
694
  }
736
695
 
737
 
  std::string *new_query= new std::string(in_packet, in_packet + in_packet_length);
738
 
  // We can not be entirely sure _schema has a value
739
 
  if (_schema)
740
 
  {
741
 
    plugin::QueryRewriter::rewriteQuery(*_schema, *new_query);
742
 
  }
743
 
  query.reset(new_query);
744
 
  _state.reset(new State(in_packet, in_packet_length));
 
696
  query.assign(in_packet, in_packet + in_packet_length);
745
697
 
746
698
  return true;
747
699
}
796
748
  }
797
749
 
798
750
  if (result == false)
799
 
  {
800
751
    my_error(killed_errno(), MYF(0));
801
 
  }
802
752
  else if ((result == true) && do_release)
803
 
  {
804
 
    setKilled(Session::KILL_CONNECTION);
805
 
  }
 
753
    killed= Session::KILL_CONNECTION;
806
754
 
807
755
  return result;
808
756
}
873
821
  where= Session::DEFAULT_WHERE;
874
822
 
875
823
  /* Reset the temporary shares we built */
876
 
  for_each(temporary_shares.begin(),
877
 
           temporary_shares.end(),
878
 
           DeletePtr());
 
824
  for (std::vector<TableShareInstance *>::iterator iter= temporary_shares.begin();
 
825
       iter != temporary_shares.end(); iter++)
 
826
  {
 
827
    delete *iter;
 
828
  }
879
829
  temporary_shares.clear();
880
830
}
881
831
 
961
911
  my_message(errcode, err, MYF(0));
962
912
  if (file > 0)
963
913
  {
964
 
    (void) cache->end_io_cache();
 
914
    (void) end_io_cache(cache);
965
915
    (void) internal::my_close(file, MYF(0));
966
 
    (void) internal::my_delete(path.file_string().c_str(), MYF(0));             // Delete file on error
 
916
    (void) internal::my_delete(path, MYF(0));           // Delete file on error
967
917
    file= -1;
968
918
  }
969
919
}
971
921
 
972
922
bool select_to_file::send_eof()
973
923
{
974
 
  int error= test(cache->end_io_cache());
 
924
  int error= test(end_io_cache(cache));
975
925
  if (internal::my_close(file, MYF(MY_WME)))
976
926
    error= 1;
977
927
  if (!error)
993
943
  /* In case of error send_eof() may be not called: close the file here. */
994
944
  if (file >= 0)
995
945
  {
996
 
    (void) cache->end_io_cache();
 
946
    (void) end_io_cache(cache);
997
947
    (void) internal::my_close(file, MYF(0));
998
948
    file= -1;
999
949
  }
1000
 
  path= "";
 
950
  path[0]= '\0';
1001
951
  row_count= 0;
1002
952
}
1003
953
 
1007
957
    cache(static_cast<internal::IO_CACHE *>(memory::sql_calloc(sizeof(internal::IO_CACHE)))),
1008
958
    row_count(0L)
1009
959
{
1010
 
  path= "";
 
960
  path[0]=0;
1011
961
}
1012
962
 
1013
963
select_to_file::~select_to_file()
1041
991
*/
1042
992
 
1043
993
 
1044
 
static int create_file(Session *session,
1045
 
                       fs::path &target_path,
1046
 
                       file_exchange *exchange,
1047
 
                       internal::IO_CACHE *cache)
 
994
static int create_file(Session *session, char *path, file_exchange *exchange, internal::IO_CACHE *cache)
1048
995
{
1049
 
  fs::path to_file(exchange->file_name);
1050
996
  int file;
1051
 
 
1052
 
  if (not to_file.has_root_directory())
 
997
  uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
 
998
 
 
999
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
 
1000
  option|= MY_REPLACE_DIR;                      // Force use of db directory
 
1001
#endif
 
1002
 
 
1003
  if (!internal::dirname_length(exchange->file_name))
1053
1004
  {
1054
 
    target_path= fs::system_complete(getDataHomeCatalog());
1055
 
    util::string::const_shared_ptr schema(session->schema());
1056
 
    if (schema and not schema->empty())
1057
 
    {
1058
 
      int count_elements= 0;
1059
 
      for (fs::path::iterator iter= to_file.begin();
1060
 
           iter != to_file.end();
1061
 
           ++iter, ++count_elements)
1062
 
      { }
1063
 
 
1064
 
      if (count_elements == 1)
1065
 
      {
1066
 
        target_path /= *schema;
1067
 
      }
1068
 
    }
1069
 
    target_path /= to_file;
 
1005
    strcpy(path, getDataHomeCatalog().c_str());
 
1006
    strncat(path, "/", 1);
 
1007
    if (! session->db.empty())
 
1008
      strncat(path, session->db.c_str(), FN_REFLEN-getDataHomeCatalog().size());
 
1009
    (void) internal::fn_format(path, exchange->file_name, path, "", option);
1070
1010
  }
1071
1011
  else
1072
 
  {
1073
 
    target_path = exchange->file_name;
1074
 
  }
 
1012
    (void) internal::fn_format(path, exchange->file_name, getDataHomeCatalog().c_str(), "", option);
1075
1013
 
1076
 
  if (not secure_file_priv.string().empty())
 
1014
  if (opt_secure_file_priv)
1077
1015
  {
1078
 
    if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
 
1016
    fs::path secure_file_path(fs::system_complete(fs::path(opt_secure_file_priv)));
 
1017
    fs::path target_path(fs::system_complete(fs::path(path)));
 
1018
    if (target_path.file_string().substr(0, secure_file_path.file_string().size()) != secure_file_path.file_string())
1079
1019
    {
1080
1020
      /* Write only allowed to dir or subdir specified by secure_file_priv */
1081
1021
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1083
1023
    }
1084
1024
  }
1085
1025
 
1086
 
  if (!access(target_path.file_string().c_str(), F_OK))
 
1026
  if (!access(path, F_OK))
1087
1027
  {
1088
1028
    my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1089
1029
    return -1;
1090
1030
  }
1091
1031
  /* Create the file world readable */
1092
 
  if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
 
1032
  if ((file= internal::my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1093
1033
    return file;
1094
1034
  (void) fchmod(file, 0666);                    // Because of umask()
1095
 
  if (cache->init_io_cache(file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
 
1035
  if (init_io_cache(cache, file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1096
1036
  {
1097
1037
    internal::my_close(file, MYF(0));
1098
 
    internal::my_delete(target_path.file_string().c_str(), MYF(0));  // Delete file on error, it was just created
 
1038
    internal::my_delete(path, MYF(0));  // Delete file on error, it was just created
1099
1039
    return -1;
1100
1040
  }
1101
1041
  return file;
1109
1049
  bool string_results= false, non_string_results= false;
1110
1050
  unit= u;
1111
1051
  if ((uint32_t) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
1112
 
  {
1113
 
    path= exchange->file_name;
1114
 
  }
 
1052
    strncpy(path,exchange->file_name,FN_REFLEN-1);
1115
1053
 
1116
1054
  /* Check if there is any blobs in data */
1117
1055
  {
1121
1059
    {
1122
1060
      if (item->max_length >= MAX_BLOB_WIDTH)
1123
1061
      {
1124
 
        blob_flag=1;
1125
 
        break;
 
1062
        blob_flag=1;
 
1063
        break;
1126
1064
      }
1127
 
 
1128
1065
      if (item->result_type() == STRING_RESULT)
1129
1066
        string_results= true;
1130
1067
      else
1175
1112
  if (unit->offset_limit_cnt)
1176
1113
  {                                             // using limit offset,count
1177
1114
    unit->offset_limit_cnt--;
1178
 
    return false;
 
1115
    return(0);
1179
1116
  }
1180
1117
  row_count++;
1181
1118
  Item *item;
1184
1121
 
1185
1122
  if (my_b_write(cache,(unsigned char*) exchange->line_start->ptr(),
1186
1123
                 exchange->line_start->length()))
1187
 
    return true;
1188
 
 
 
1124
    goto err;
1189
1125
  while ((item=li++))
1190
1126
  {
1191
1127
    Item_result result_type=item->result_type();
1196
1132
    {
1197
1133
      if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
1198
1134
                     exchange->enclosed->length()))
1199
 
        return true;
 
1135
        goto err;
1200
1136
    }
1201
1137
    if (!res)
1202
1138
    {                                           // NULL
1207
1143
          null_buff[0]=escape_char;
1208
1144
          null_buff[1]='N';
1209
1145
          if (my_b_write(cache,(unsigned char*) null_buff,2))
1210
 
            return true;
 
1146
            goto err;
1211
1147
        }
1212
1148
        else if (my_b_write(cache,(unsigned char*) "NULL",4))
1213
 
          return true;
 
1149
          goto err;
1214
1150
      }
1215
1151
      else
1216
1152
      {
1220
1156
    else
1221
1157
    {
1222
1158
      if (fixed_row_size)
1223
 
        used_length= min(res->length(), static_cast<size_t>(item->max_length));
 
1159
        used_length= min(res->length(),item->max_length);
1224
1160
      else
1225
1161
        used_length= res->length();
1226
1162
 
1301
1237
            tmp_buff[1]= *pos ? *pos : '0';
1302
1238
            if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1303
1239
                my_b_write(cache,(unsigned char*) tmp_buff,2))
1304
 
              return true;
 
1240
              goto err;
1305
1241
            start=pos+1;
1306
1242
          }
1307
1243
        }
1308
1244
        if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1309
 
          return true;
 
1245
          goto err;
1310
1246
      }
1311
1247
      else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1312
 
        return true;
 
1248
        goto err;
1313
1249
    }
1314
1250
    if (fixed_row_size)
1315
1251
    {                                           // Fill with space
1325
1261
        for (; length > sizeof(space) ; length-=sizeof(space))
1326
1262
        {
1327
1263
          if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1328
 
            return true;
 
1264
            goto err;
1329
1265
        }
1330
1266
        if (my_b_write(cache,(unsigned char*) space,length))
1331
 
          return true;
 
1267
          goto err;
1332
1268
      }
1333
1269
    }
1334
1270
    if (res && enclosed)
1335
1271
    {
1336
1272
      if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
1337
1273
                     exchange->enclosed->length()))
1338
 
        return true;
 
1274
        goto err;
1339
1275
    }
1340
1276
    if (--items_left)
1341
1277
    {
1342
1278
      if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
1343
1279
                     field_term_length))
1344
 
        return true;
 
1280
        goto err;
1345
1281
    }
1346
1282
  }
1347
1283
  if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1348
1284
                 exchange->line_term->length()))
1349
 
  {
1350
 
    return true;
1351
 
  }
1352
 
 
1353
 
  return false;
 
1285
    goto err;
 
1286
  return(0);
 
1287
err:
 
1288
  return(1);
1354
1289
}
1355
1290
 
1356
1291
 
1383
1318
  if (row_count++ > 1)
1384
1319
  {
1385
1320
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1386
 
    return 1;
 
1321
    goto err;
1387
1322
  }
1388
1323
  while ((item=li++))
1389
1324
  {
1391
1326
    if (!res)                                   // If NULL
1392
1327
    {
1393
1328
      if (my_b_write(cache,(unsigned char*) "",1))
1394
 
        return 1;
 
1329
        goto err;
1395
1330
    }
1396
1331
    else if (my_b_write(cache,(unsigned char*) res->ptr(),res->length()))
1397
1332
    {
1398
 
      my_error(ER_ERROR_ON_WRITE, MYF(0), path.file_string().c_str(), errno);
1399
 
      return 1;
 
1333
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, errno);
 
1334
      goto err;
1400
1335
    }
1401
1336
  }
1402
1337
  return(0);
 
1338
err:
 
1339
  return(1);
1403
1340
}
1404
1341
 
1405
1342
 
1457
1394
      switch (val_item->result_type())
1458
1395
      {
1459
1396
      case REAL_RESULT:
1460
 
        op= &select_max_min_finder_subselect::cmp_real;
1461
 
        break;
 
1397
        op= &select_max_min_finder_subselect::cmp_real;
 
1398
        break;
1462
1399
      case INT_RESULT:
1463
 
        op= &select_max_min_finder_subselect::cmp_int;
1464
 
        break;
 
1400
        op= &select_max_min_finder_subselect::cmp_int;
 
1401
        break;
1465
1402
      case STRING_RESULT:
1466
 
        op= &select_max_min_finder_subselect::cmp_str;
1467
 
        break;
 
1403
        op= &select_max_min_finder_subselect::cmp_str;
 
1404
        break;
1468
1405
      case DECIMAL_RESULT:
1469
1406
        op= &select_max_min_finder_subselect::cmp_decimal;
1470
1407
        break;
1471
1408
      case ROW_RESULT:
1472
1409
        // This case should never be choosen
1473
 
        assert(0);
1474
 
        op= 0;
 
1410
        assert(0);
 
1411
        op= 0;
1475
1412
      }
1476
1413
    }
1477
1414
    cache->store(val_item);
1560
1497
void Session::end_statement()
1561
1498
{
1562
1499
  /* Cleanup SQL processing state to reuse this statement in next query. */
1563
 
  lex->end();
 
1500
  lex_end(lex);
1564
1501
  query_cache_key= ""; // reset the cache key
1565
1502
  resetResultsetMessage();
1566
1503
}
1567
1504
 
1568
1505
bool Session::copy_db_to(char **p_db, size_t *p_db_length)
1569
1506
{
1570
 
  assert(_schema);
1571
 
  if (_schema and _schema->empty())
1572
 
  {
1573
 
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1574
 
    return true;
1575
 
  }
1576
 
  else if (not _schema)
1577
 
  {
1578
 
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1579
 
    return true;
1580
 
  }
1581
 
  assert(_schema);
1582
 
 
1583
 
  *p_db= strmake(_schema->c_str(), _schema->size());
1584
 
  *p_db_length= _schema->size();
1585
 
 
 
1507
  if (db.empty())
 
1508
  {
 
1509
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
 
1510
    return true;
 
1511
  }
 
1512
  *p_db= strmake(db.c_str(), db.length());
 
1513
  *p_db_length= db.length();
1586
1514
  return false;
1587
1515
}
1588
1516
 
1622
1550
}
1623
1551
 
1624
1552
 
1625
 
void Session::set_db(const std::string &new_db)
 
1553
bool Session::set_db(const std::string &new_db)
1626
1554
{
1627
1555
  /* Do not reallocate memory if current chunk is big enough. */
1628
1556
  if (new_db.length())
1629
 
  {
1630
 
    _schema.reset(new std::string(new_db));
1631
 
  }
 
1557
    db= new_db;
1632
1558
  else
1633
 
  {
1634
 
    _schema.reset(new std::string(""));
1635
 
  }
1636
 
}
1637
 
 
 
1559
    db.clear();
 
1560
 
 
1561
  return false;
 
1562
}
 
1563
 
 
1564
 
 
1565
 
 
1566
 
 
1567
/**
 
1568
  Check the killed state of a user thread
 
1569
  @param session  user thread
 
1570
  @retval 0 the user thread is active
 
1571
  @retval 1 the user thread has been killed
 
1572
*/
 
1573
int session_killed(const Session *session)
 
1574
{
 
1575
  return(session->killed);
 
1576
}
 
1577
 
 
1578
 
 
1579
const struct charset_info_st *session_charset(Session *session)
 
1580
{
 
1581
  return(session->charset());
 
1582
}
1638
1583
 
1639
1584
/**
1640
1585
  Mark transaction to rollback and mark error as fatal to a sub-statement.
1657
1602
  plugin_sessionvar_cleanup(this);
1658
1603
 
1659
1604
  /* If necessary, log any aborted or unauthorized connections */
1660
 
  if (getKilled() || client->wasAborted())
 
1605
  if (killed || client->wasAborted())
1661
1606
  {
1662
1607
    status_var.aborted_threads++;
1663
1608
  }
1664
1609
 
1665
1610
  if (client->wasAborted())
1666
1611
  {
1667
 
    if (not getKilled() && variables.log_warnings > 1)
 
1612
    if (! killed && variables.log_warnings > 1)
1668
1613
    {
 
1614
      SecurityContext *sctx= &security_ctx;
 
1615
 
1669
1616
      errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1670
1617
                  , thread_id
1671
 
                  , (_schema->empty() ? "unconnected" : _schema->c_str())
1672
 
                  , security_ctx->username().empty() == false ? security_ctx->username().c_str() : "unauthenticated"
1673
 
                  , security_ctx->address().c_str()
 
1618
                  , (db.empty() ? "unconnected" : db.c_str())
 
1619
                  , sctx->getUser().empty() == false ? sctx->getUser().c_str() : "unauthenticated"
 
1620
                  , sctx->getIp().c_str()
1674
1621
                  , (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1675
1622
    }
1676
1623
  }
1677
1624
 
1678
1625
  /* Close out our connection to the client */
1679
1626
  if (should_lock)
1680
 
    session::Cache::singleton().mutex().lock();
1681
 
 
1682
 
  setKilled(Session::KILL_CONNECTION);
1683
 
 
 
1627
    LOCK_thread_count.lock();
 
1628
  killed= Session::KILL_CONNECTION;
1684
1629
  if (client->isConnected())
1685
1630
  {
1686
1631
    if (errcode)
1690
1635
    }
1691
1636
    client->close();
1692
1637
  }
1693
 
 
1694
1638
  if (should_lock)
1695
 
  {
1696
 
    session::Cache::singleton().mutex().unlock();
1697
 
  }
 
1639
    (void) LOCK_thread_count.unlock();
1698
1640
}
1699
1641
 
1700
1642
void Session::reset_for_next_command()
1722
1664
  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
1723
1665
*/
1724
1666
 
1725
 
void Open_tables_state::close_temporary_tables()
 
1667
void Session::close_temporary_tables()
1726
1668
{
1727
1669
  Table *table;
1728
1670
  Table *tmp_next;
1742
1684
  unlink from session->temporary tables and close temporary table
1743
1685
*/
1744
1686
 
1745
 
void Open_tables_state::close_temporary_table(Table *table)
 
1687
void Session::close_temporary_table(Table *table)
1746
1688
{
1747
1689
  if (table->getPrev())
1748
1690
  {
1778
1720
  If this is needed, use close_temporary_table()
1779
1721
*/
1780
1722
 
1781
 
void Open_tables_state::nukeTable(Table *table)
 
1723
void Session::nukeTable(Table *table)
1782
1724
{
1783
1725
  plugin::StorageEngine *table_type= table->getShare()->db_type();
1784
1726
 
1809
1751
 
1810
1752
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1811
1753
{
1812
 
  return getVariable(std::string(name.str, name.length), create_if_not_exists);
1813
 
}
1814
 
 
1815
 
user_var_entry *Session::getVariable(const std::string  &name, bool create_if_not_exists)
1816
 
{
1817
 
  UserVarsRange ppp= user_vars.equal_range(name);
 
1754
  user_var_entry *entry= NULL;
 
1755
  UserVarsRange ppp= user_vars.equal_range(std::string(name.str, name.length));
1818
1756
 
1819
1757
  for (UserVars::iterator iter= ppp.first;
1820
 
       iter != ppp.second; ++iter)
 
1758
         iter != ppp.second; ++iter)
1821
1759
  {
1822
 
    return (*iter).second;
 
1760
    entry= (*iter).second;
1823
1761
  }
1824
1762
 
1825
 
  if (not create_if_not_exists)
1826
 
    return NULL;
1827
 
 
1828
 
  user_var_entry *entry= NULL;
1829
 
  entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1830
 
 
1831
 
  if (entry == NULL)
1832
 
    return NULL;
1833
 
 
1834
 
  std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1835
 
 
1836
 
  if (not returnable.second)
 
1763
  if ((entry == NULL) && create_if_not_exists)
1837
1764
  {
1838
 
    delete entry;
 
1765
    entry= new (nothrow) user_var_entry(name.str, query_id);
 
1766
 
 
1767
    if (entry == NULL)
 
1768
      return NULL;
 
1769
 
 
1770
    std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(std::string(name.str, name.length), entry));
 
1771
 
 
1772
    if (not returnable.second)
 
1773
    {
 
1774
      delete entry;
 
1775
      return NULL;
 
1776
    }
1839
1777
  }
1840
1778
 
1841
1779
  return entry;
1842
1780
}
1843
1781
 
1844
 
void Session::setVariable(const std::string &name, const std::string &value)
1845
 
{
1846
 
  user_var_entry *updateable_var= getVariable(name.c_str(), true);
1847
 
 
1848
 
  updateable_var->update_hash(false,
1849
 
                              (void*)value.c_str(),
1850
 
                              static_cast<uint32_t>(value.length()), STRING_RESULT,
1851
 
                              &my_charset_bin,
1852
 
                              DERIVATION_IMPLICIT, false);
1853
 
}
1854
 
 
1855
 
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
 
1782
void Session::mark_temp_tables_as_free_for_reuse()
1856
1783
{
1857
1784
  for (Table *table= temporary_tables ; table ; table= table->getNext())
1858
1785
  {
1859
 
    if (table->query_id == getQueryId())
 
1786
    if (table->query_id == query_id)
1860
1787
    {
1861
1788
      table->query_id= 0;
1862
1789
      table->cursor->ha_reset();
1868
1795
{
1869
1796
  for (; table ; table= table->getNext())
1870
1797
  {
1871
 
    if (table->query_id == getQueryId())
 
1798
    if (table->query_id == query_id)
1872
1799
    {
1873
1800
      table->query_id= 0;
1874
1801
      table->cursor->ha_reset();
1887
1814
*/
1888
1815
void Session::close_thread_tables()
1889
1816
{
1890
 
  clearDerivedTables();
 
1817
  if (derived_tables)
 
1818
    derived_tables= NULL; // They should all be invalid by this point
1891
1819
 
1892
1820
  /*
1893
1821
    Mark all temporary tables used by this statement as free for reuse.
1920
1848
      handled either before writing a query log event (inside
1921
1849
      binlog_query()) or when preparing a pending event.
1922
1850
     */
1923
 
    unlockTables(lock);
 
1851
    mysql_unlock_tables(this, lock);
1924
1852
    lock= 0;
1925
1853
  }
1926
1854
  /*
1927
 
    Note that we need to hold table::Cache::singleton().mutex() while changing the
 
1855
    Note that we need to hold LOCK_open while changing the
1928
1856
    open_tables list. Another thread may work on it.
1929
 
    (See: table::Cache::singleton().removeTable(), mysql_wait_completed_table())
 
1857
    (See: remove_table_from_cache(), mysql_wait_completed_table())
1930
1858
    Closing a MERGE child before the parent would be fatal if the
1931
1859
    other thread tries to abort the MERGE lock in between.
1932
1860
  */
1965
1893
    close_tables_for_reopen(&tables);
1966
1894
  }
1967
1895
  if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
1968
 
       (
 
1896
       (fill_derived_tables() &&
1969
1897
        mysql_handle_derived(lex, &mysql_derived_filling))))
1970
1898
    return true;
1971
1899
 
1972
1900
  return false;
1973
1901
}
1974
1902
 
 
1903
bool Session::openTables(TableList *tables, uint32_t flags)
 
1904
{
 
1905
  uint32_t counter;
 
1906
  bool ret= fill_derived_tables();
 
1907
  assert(ret == false);
 
1908
  if (open_tables_from_list(&tables, &counter, flags) ||
 
1909
      mysql_handle_derived(lex, &mysql_derived_prepare))
 
1910
  {
 
1911
    return true;
 
1912
  }
 
1913
  return false;
 
1914
}
 
1915
 
1975
1916
/*
1976
1917
  @note "best_effort" is used in cases were if a failure occurred on this
1977
1918
  operation it would not be surprising because we are only removing because there
1978
1919
  might be an issue (lame engines).
1979
1920
*/
1980
1921
 
1981
 
bool Open_tables_state::rm_temporary_table(const TableIdentifier &identifier, bool best_effort)
 
1922
bool Session::rm_temporary_table(TableIdentifier &identifier, bool best_effort)
1982
1923
{
1983
 
  if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
 
1924
  if (plugin::StorageEngine::dropTable(*this, identifier))
1984
1925
  {
1985
1926
    if (not best_effort)
1986
1927
    {
1987
 
      std::string path;
1988
 
      identifier.getSQLPath(path);
1989
1928
      errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
1990
 
                    path.c_str(), errno);
 
1929
                    identifier.getSQLPath().c_str(), errno);
1991
1930
    }
1992
1931
 
1993
1932
    return true;
1996
1935
  return false;
1997
1936
}
1998
1937
 
1999
 
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const TableIdentifier &identifier)
 
1938
bool Session::rm_temporary_table(plugin::StorageEngine *base, TableIdentifier &identifier)
2000
1939
{
2001
1940
  assert(base);
2002
1941
 
2003
 
  if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier))
 
1942
  if (plugin::StorageEngine::dropTable(*this, *base, identifier))
2004
1943
  {
2005
 
    std::string path;
2006
 
    identifier.getSQLPath(path);
2007
1944
    errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2008
 
                  path.c_str(), errno);
 
1945
                  identifier.getSQLPath().c_str(), errno);
2009
1946
 
2010
1947
    return true;
2011
1948
  }
2017
1954
  @note this will be removed, I am looking through Hudson to see if it is finding
2018
1955
  any tables that are missed during cleanup.
2019
1956
*/
2020
 
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
 
1957
void Session::dumpTemporaryTableNames(const char *foo)
2021
1958
{
2022
1959
  Table *table;
2023
1960
 
2041
1978
      cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2042
1979
    }
2043
1980
    else
2044
 
    {
2045
1981
      cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2046
 
    }
2047
1982
  }
2048
1983
}
2049
1984
 
2050
 
bool Session::TableMessages::storeTableMessage(const TableIdentifier &identifier, message::Table &table_message)
 
1985
bool Session::storeTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2051
1986
{
2052
1987
  table_message_cache.insert(make_pair(identifier.getPath(), table_message));
2053
1988
 
2054
1989
  return true;
2055
1990
}
2056
1991
 
2057
 
bool Session::TableMessages::removeTableMessage(const TableIdentifier &identifier)
 
1992
bool Session::removeTableMessage(const TableIdentifier &identifier)
2058
1993
{
2059
1994
  TableMessageCache::iterator iter;
2060
1995
 
2068
2003
  return true;
2069
2004
}
2070
2005
 
2071
 
bool Session::TableMessages::getTableMessage(const TableIdentifier &identifier, message::Table &table_message)
 
2006
bool Session::getTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2072
2007
{
2073
2008
  TableMessageCache::iterator iter;
2074
2009
 
2082
2017
  return true;
2083
2018
}
2084
2019
 
2085
 
bool Session::TableMessages::doesTableMessageExist(const TableIdentifier &identifier)
 
2020
bool Session::doesTableMessageExist(const TableIdentifier &identifier)
2086
2021
{
2087
2022
  TableMessageCache::iterator iter;
2088
2023
 
2096
2031
  return true;
2097
2032
}
2098
2033
 
2099
 
bool Session::TableMessages::renameTableMessage(const TableIdentifier &from, const TableIdentifier &to)
 
2034
bool Session::renameTableMessage(const TableIdentifier &from, const TableIdentifier &to)
2100
2035
{
2101
2036
  TableMessageCache::iterator iter;
2102
2037
 
2115
2050
  return true;
2116
2051
}
2117
2052
 
2118
 
table::Instance *Session::getInstanceTable()
2119
 
{
2120
 
  temporary_shares.push_back(new table::Instance()); // This will not go into the tableshare cache, so no key is used.
2121
 
 
2122
 
  table::Instance *tmp_share= temporary_shares.back();
2123
 
 
2124
 
  assert(tmp_share);
2125
 
 
2126
 
  return tmp_share;
2127
 
}
2128
 
 
2129
 
 
2130
 
/**
2131
 
  Create a reduced Table object with properly set up Field list from a
2132
 
  list of field definitions.
2133
 
 
2134
 
    The created table doesn't have a table Cursor associated with
2135
 
    it, has no keys, no group/distinct, no copy_funcs array.
2136
 
    The sole purpose of this Table object is to use the power of Field
2137
 
    class to read/write data to/from table->getInsertRecord(). Then one can store
2138
 
    the record in any container (RB tree, hash, etc).
2139
 
    The table is created in Session mem_root, so are the table's fields.
2140
 
    Consequently, if you don't BLOB fields, you don't need to free it.
2141
 
 
2142
 
  @param session         connection handle
2143
 
  @param field_list  list of column definitions
2144
 
 
2145
 
  @return
2146
 
    0 if out of memory, Table object in case of success
2147
 
*/
2148
 
table::Instance *Session::getInstanceTable(List<CreateField> &field_list)
2149
 
{
2150
 
  temporary_shares.push_back(new table::Instance(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2151
 
 
2152
 
  table::Instance *tmp_share= temporary_shares.back();
2153
 
 
2154
 
  assert(tmp_share);
2155
 
 
2156
 
  return tmp_share;
2157
 
}
2158
 
 
2159
 
namespace display  {
2160
 
 
2161
 
static const std::string NONE= "NONE";
2162
 
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2163
 
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2164
 
 
2165
 
const std::string &type(drizzled::Session::global_read_lock_t type)
2166
 
{
2167
 
  switch (type) {
2168
 
    default:
2169
 
    case Session::NONE:
2170
 
      return NONE;
2171
 
    case Session::GOT_GLOBAL_READ_LOCK:
2172
 
      return GOT_GLOBAL_READ_LOCK;
2173
 
    case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2174
 
      return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2175
 
  }
2176
 
}
2177
 
 
2178
 
size_t max_string_length(drizzled::Session::global_read_lock_t)
2179
 
{
2180
 
  return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2181
 
}
2182
 
 
2183
 
} /* namespace display */
 
2053
TableShareInstance *Session::getTemporaryShare(TableIdentifier::Type type_arg)
 
2054
{
 
2055
  temporary_shares.push_back(new TableShareInstance(type_arg)); // This will not go into the tableshare cache, so no key is used.
 
2056
 
 
2057
  TableShareInstance *tmp_share= temporary_shares.back();
 
2058
 
 
2059
  assert(tmp_share);
 
2060
 
 
2061
  return tmp_share;
 
2062
}
2184
2063
 
2185
2064
} /* namespace drizzled */