21
21
* @file Implementation of the Session class and API
26
#include <drizzled/copy_field.h>
27
#include <drizzled/data_home.h>
28
#include <drizzled/display.h>
29
#include <drizzled/drizzled.h>
25
#include <drizzled/session.h>
26
#include "drizzled/session_list.h"
28
#include "drizzled/my_error.h"
30
29
#include <drizzled/error.h>
31
30
#include <drizzled/gettext.h>
32
#include <drizzled/identifier.h>
33
#include <drizzled/internal/iocache.h>
34
#include <drizzled/internal/thread_var.h>
35
#include <drizzled/internal_error_handler.h>
31
#include <drizzled/query_id.h>
32
#include <drizzled/data_home.h>
33
#include <drizzled/sql_base.h>
34
#include <drizzled/lock.h>
36
35
#include <drizzled/item/cache.h>
37
#include <drizzled/item/empty_string.h>
38
36
#include <drizzled/item/float.h>
39
37
#include <drizzled/item/return_int.h>
40
#include <drizzled/lock.h>
41
#include <drizzled/plugin/authentication.h>
38
#include <drizzled/item/empty_string.h>
39
#include <drizzled/show.h>
42
40
#include <drizzled/plugin/client.h>
43
#include <drizzled/plugin/event_observer.h>
44
#include <drizzled/plugin/logging.h>
45
#include <drizzled/plugin/query_rewrite.h>
46
#include <drizzled/plugin/scheduler.h>
47
#include <drizzled/plugin/transactional_storage_engine.h>
48
#include <drizzled/probes.h>
49
#include <drizzled/pthread_globals.h>
50
#include <drizzled/query_id.h>
51
#include <drizzled/refresh_version.h>
52
#include <drizzled/select_dump.h>
53
#include <drizzled/select_exists_subselect.h>
54
#include <drizzled/select_export.h>
55
#include <drizzled/select_max_min_finder_subselect.h>
56
#include <drizzled/select_singlerow_subselect.h>
57
#include <drizzled/select_subselect.h>
58
#include <drizzled/select_to_file.h>
59
#include <drizzled/session.h>
60
#include <drizzled/session/cache.h>
61
#include <drizzled/show.h>
62
#include <drizzled/sql_base.h>
63
#include <drizzled/table/singular.h>
64
#include <drizzled/table_proto.h>
65
#include <drizzled/tmp_table_param.h>
66
#include <drizzled/transaction_services.h>
67
#include <drizzled/user_var_entry.h>
68
#include <drizzled/util/functors.h>
69
#include <plugin/myisam/myisam.h>
41
#include "drizzled/plugin/scheduler.h"
42
#include "drizzled/plugin/authentication.h"
43
#include "drizzled/probes.h"
44
#include "drizzled/table_proto.h"
45
#include "drizzled/db.h"
46
#include "drizzled/pthread_globals.h"
48
#include "plugin/myisam/myisam.h"
49
#include "drizzled/internal/iocache.h"
71
52
#include <algorithm>
76
#include <boost/filesystem.hpp>
77
#include <boost/checked_delete.hpp>
79
#include <drizzled/util/backtrace.h>
81
#include <drizzled/schema.h>
83
55
using namespace std;
56
using namespace drizzled;
85
namespace fs=boost::filesystem;
60
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool );
61
void free_user_var(user_var_entry *entry);
90
65
The following is used to initialise Table_ident with a internal
94
69
char empty_c_string[1]= {0}; /* used for not defined db */
96
71
const char * const Session::DEFAULT_WHERE= "field list";
72
extern pthread_key_t THR_Session;
73
extern pthread_key_t THR_Mem_root;
74
extern uint32_t max_used_connections;
75
extern drizzled::atomic<uint32_t> connection_count;
78
/****************************************************************************
80
****************************************************************************/
81
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool )
83
*length= entry->name.length;
84
return (unsigned char*) entry->name.str;
87
void free_user_var(user_var_entry *entry)
98
92
bool Key_part_spec::operator==(const Key_part_spec& other) const
100
94
return length == other.length &&
101
95
field_name.length == other.field_name.length &&
102
!my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
96
!strcmp(field_name.str, other.field_name.str);
105
Open_tables_state::Open_tables_state(uint64_t version_arg) :
99
Open_tables_state::Open_tables_state(uint64_t version_arg)
100
:version(version_arg), backups_available(false)
108
open_tables= temporary_tables= derived_tables= NULL;
109
extra_lock= lock= NULL;
102
reset_open_tables_state();
113
106
The following functions form part of the C plugin API
115
int tmpfile(const char *prefix)
108
extern "C" int mysql_tmpfile(const char *prefix)
117
110
char filename[FN_REFLEN];
118
int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
111
int fd = create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
120
113
unlink(filename);
126
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
128
return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
131
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
134
return &ha_data[monitored->getId()].resource_context[index];
120
int session_tablespace_op(const Session *session)
122
return test(session->tablespace_op);
126
Set the process info field of the Session structure.
128
This function is used by plug-ins. Internally, the
129
Session::set_proc_info() function should be used.
131
@see Session::set_proc_info
134
set_session_proc_info(Session *session, const char *info)
136
session->set_proc_info(info);
140
const char *get_session_proc_info(Session *session)
142
return session->get_proc_info();
145
void **Session::getEngineData(const plugin::StorageEngine *engine)
147
return static_cast<void **>(&ha_data[engine->slot].ha_ptr);
150
Ha_trx_info *Session::getEngineInfo(const plugin::StorageEngine *engine,
153
return &ha_data[engine->getSlot()].ha_info[index];
137
157
int64_t session_test_options(const Session *session, int64_t test_options)
139
159
return session->options & test_options;
142
Session::Session(plugin::Client *client_arg, catalog::Instance::shared_ptr catalog_arg) :
163
int session_sql_command(const Session *session)
165
return (int) session->lex->sql_command;
169
int session_tx_isolation(const Session *session)
171
return (int) session->variables.tx_isolation;
174
Session::Session(plugin::Client *client_arg)
143
176
Open_tables_state(refresh_version),
144
177
mem_root(&main_mem_root),
147
query(new std::string),
148
_schema(new std::string("")),
149
179
client(client_arg),
151
181
scheduler_arg(NULL),
152
182
lock_id(&main_lock_id),
154
security_ctx(identifier::User::make_shared()),
155
_where(Session::DEFAULT_WHERE),
156
dbug_sentry(Session_SENTRY_MAGIC),
158
command(COM_CONNECT),
160
_epoch(boost::gregorian::date(1970,1,1)),
161
_connect_time(boost::posix_time::microsec_clock::universal_time()),
163
ha_data(plugin::num_trx_monitored_objects),
166
concurrent_execute_allowed(true),
167
184
arg_of_last_insert_id_function(false),
168
185
first_successful_insert_id_in_prev_stmt(0),
169
186
first_successful_insert_id_in_cur_stmt(0),
170
187
limit_found_rows(0),
171
options(session_startup_options),
174
examined_row_count(0),
178
statement_id_counter(0),
182
_global_read_lock(NONE),
183
count_cuted_fields(CHECK_FIELD_ERROR_FOR_NULL),
185
189
some_tables_deleted(false),
186
190
no_errors(false),
188
192
is_fatal_error(false),
189
193
transaction_rollback_request(false),
190
194
is_fatal_sub_stmt_error(0),
195
derived_tables_processing(false),
191
196
tablespace_op(false),
192
derived_tables_processing(false),
195
199
transaction_message(NULL),
196
statement_message(NULL),
197
session_event_observers(NULL),
198
_catalog(catalog_arg),
200
statement_message(NULL)
202
memset(process_list_info, 0, PROCESS_LIST_WIDTH);
201
203
client->setSession(this);
206
208
will be re-initialized in init_for_queries().
208
210
memory::init_sql_alloc(&main_mem_root, memory::ROOT_MIN_BLOCK_SIZE, 0);
212
count_cuted_fields= CHECK_FIELD_IGNORE;
209
217
cuted_fields= sent_row_count= row_count= 0L;
219
statement_id_counter= 0UL;
210
220
// Must be reset to handle error with Session's created for init of mysqld
211
221
lex->current_select= 0;
222
start_time=(time_t) 0;
224
utime_after_lock= 0L;
212
225
memset(&variables, 0, sizeof(variables));
213
scoreboard_index= -1;
214
cleanup_done= abort_on_warning= no_warnings_for_error= false;
216
/* query_cache init */
232
memset(ha_data, 0, sizeof(ha_data));
235
dbug_sentry=Session_SENTRY_MAGIC;
236
cleanup_done= abort_on_warning= no_warnings_for_error= false;
238
pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
220
240
/* Variables with default values */
221
241
proc_info="login";
242
where= Session::DEFAULT_WHERE;
243
command= COM_CONNECT;
223
245
plugin_sessionvar_init(this);
229
251
variables.pseudo_thread_id= thread_id;
230
252
server_status= SERVER_STATUS_AUTOCOMMIT;
253
options= session_startup_options;
232
255
if (variables.max_join_size == HA_POS_ERROR)
233
256
options |= OPTION_BIG_SELECTS;
235
258
options &= ~OPTION_BIG_SELECTS;
260
transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= false;
237
261
open_options=ha_open_options;
238
262
update_lock_default= TL_WRITE;
239
263
session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
241
265
memset(warn_count, 0, sizeof(warn_count));
242
267
memset(&status_var, 0, sizeof(status_var));
244
269
/* Initialize sub structures */
245
270
memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
271
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
272
(hash_get_key) get_var_key,
273
(hash_free_key) free_user_var, 0);
247
275
substitute_null_with_insert_id = false;
248
lock_info.init(); /* safety: will be reset after start */
276
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
249
277
thr_lock_owner_init(&main_lock_id, &lock_info);
251
279
m_internal_handler= NULL;
253
plugin::EventObserver::registerSessionEvents(*this);
256
282
void Session::free_items()
285
311
return false; // 'false', as per coding style
288
void Session::setAbort(bool arg)
290
mysys_var->abort= arg;
293
void Session::lockOnSys()
299
boost_unique_lock_t scopedLock(mysys_var->mutex);
300
if (mysys_var->current_cond)
302
mysys_var->current_mutex->lock();
303
mysys_var->current_cond->notify_all();
304
mysys_var->current_mutex->unlock();
308
314
void Session::pop_internal_handler()
310
316
assert(m_internal_handler != NULL);
311
317
m_internal_handler= NULL;
314
void Session::get_xid(DrizzleXid *xid)
316
*xid = *(DrizzleXid *) &transaction.xid_state.xid;
320
#if defined(__cplusplus)
324
void *session_alloc(Session *session, unsigned int size)
326
return session->alloc(size);
329
void *session_calloc(Session *session, unsigned int size)
331
return session->calloc(size);
334
char *session_strdup(Session *session, const char *str)
336
return session->strdup(str);
339
char *session_strmake(Session *session, const char *str, unsigned int size)
341
return session->strmake(str, size);
344
void *session_memdup(Session *session, const void* str, unsigned int size)
346
return session->memdup(str, size);
349
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
351
*xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
354
#if defined(__cplusplus)
319
358
/* Do operations that may take a long time */
333
TransactionServices &transaction_services= TransactionServices::singleton();
334
transaction_services.rollbackTransaction(*this, true);
335
373
xid_cache_delete(&transaction.xid_state);
338
for (UserVars::iterator iter= user_vars.begin();
339
iter != user_vars.end();
342
user_var_entry *entry= (*iter).second;
343
boost::checked_delete(entry);
375
hash_free(&user_vars);
348
376
close_temporary_tables();
350
378
if (global_read_lock)
352
unlockGlobalReadLock();
379
unlock_global_read_lock(this);
355
381
cleanup_done= true;
358
384
Session::~Session()
386
Session_CHECK_SENTRY(this);
387
add_to_status(&global_status_var, &status_var);
362
if (client and client->isConnected())
389
if (client->isConnected())
364
assert(security_ctx);
365
391
if (global_system_variables.log_warnings)
367
errmsg_printf(error::WARN, ER(ER_FORCING_CLOSE),
368
internal::my_progname,
370
security_ctx->username().c_str());
392
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),my_progname,
394
(security_ctx.user.c_str() ?
395
security_ctx.user.c_str() : ""));
396
disconnect(0, false);
376
399
/* Close connection */
380
boost::checked_delete(client);
384
403
if (cleanup_done == false)
387
406
plugin::StorageEngine::closeConnection(this);
388
407
plugin_sessionvar_cleanup(this);
390
warn_root.free_root(MYF(0));
409
free_root(&warn_root,MYF(0));
410
free_root(&transaction.mem_root,MYF(0));
391
411
mysys_var=0; // Safety (shouldn't be needed)
392
412
dbug_sentry= Session_SENTRY_GONE;
394
main_mem_root.free_root(MYF(0));
395
currentMemRoot().release();
396
currentSession().release();
398
plugin::Logging::postEndDo(this);
399
plugin::EventObserver::deregisterSessionEvents(*this);
402
void Session::setClient(plugin::Client *client_arg)
405
client->setSession(this);
408
void Session::awake(Session::killed_state_t state_to_set)
410
if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
415
setKilled(state_to_set);
416
scheduler->killSession(this);
414
free_root(&main_mem_root, MYF(0));
415
pthread_setspecific(THR_Session, 0);
418
/* Ensure that no one is using Session */
419
pthread_mutex_unlock(&LOCK_delete);
420
pthread_mutex_destroy(&LOCK_delete);
424
Add all status variables to another status variable array
428
to_var add to this array
429
from_var from this array
432
This function assumes that all variables are long/ulong.
433
If this assumption will change, then we have to explictely add
434
the other variables after the while loop
436
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
438
ulong *end= (ulong*) ((unsigned char*) to_var +
439
offsetof(STATUS_VAR, last_system_status_var) +
441
ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
448
Add the difference between two status variable arrays to another one.
452
to_var add to this array
453
from_var from this array
454
dec_var minus this array
457
This function assumes that all variables are long/ulong.
459
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
462
ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
463
last_system_status_var) +
465
ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
468
*(to++)+= *(from++) - *(dec++);
471
void Session::awake(Session::killed_state state_to_set)
473
Session_CHECK_SENTRY(this);
474
safe_mutex_assert_owner(&LOCK_delete);
476
killed= state_to_set;
418
477
if (state_to_set != Session::KILL_QUERY)
479
scheduler->killSession(this);
420
480
DRIZZLE_CONNECTION_DONE(thread_id);
425
boost_unique_lock_t scopedLock(mysys_var->mutex);
484
pthread_mutex_lock(&mysys_var->mutex);
428
486
This broadcast could be up in the air if the victim thread
429
487
exits the cond in the time between read and broadcast, but that is
430
488
ok since all we want to do is to make the victim thread get out
502
559
set_proc_info(NULL);
503
560
command= COM_SLEEP;
562
ha_enable_transaction(this,true);
506
mem_root->reset_root_defaults(variables.query_alloc_block_size,
507
variables.query_prealloc_size);
564
reset_root_defaults(mem_root, variables.query_alloc_block_size,
565
variables.query_prealloc_size);
566
reset_root_defaults(&transaction.mem_root,
567
variables.trans_alloc_block_size,
568
variables.trans_prealloc_size);
508
569
transaction.xid_state.xid.null();
509
570
transaction.xid_state.in_session=1;
514
573
bool Session::initGlobals()
516
575
if (storeGlobals())
518
disconnect(ER_OUT_OF_RESOURCES);
519
status_var.aborted_connects++;
577
disconnect(ER_OUT_OF_RESOURCES, true);
578
statistic_increment(aborted_connects, &LOCK_status);
527
586
if (initGlobals() || authenticate())
533
592
prepareForQueries();
535
while (not client->haveError() && getKilled() != KILL_CONNECTION)
594
while (! client->haveError() && killed != KILL_CONNECTION)
537
if (not executeStatement())
596
if (! executeStatement())
544
bool Session::schedule(Session::shared_ptr &arg)
603
bool Session::schedule()
546
arg->scheduler= plugin::Scheduler::getScheduler();
547
assert(arg->scheduler);
551
long current_connections= connection_count;
553
if (current_connections > 0 and static_cast<uint64_t>(current_connections) > current_global_counters.max_used_connections)
555
current_global_counters.max_used_connections= static_cast<uint64_t>(connection_count);
558
current_global_counters.connections++;
559
arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
561
session::Cache::singleton().insert(arg);
563
if (unlikely(plugin::EventObserver::connectSession(*arg)))
565
// We should do something about an error...
568
if (plugin::Scheduler::getScheduler()->addSession(arg))
570
DRIZZLE_CONNECTION_START(arg->getSessionId());
605
scheduler= plugin::Scheduler::getScheduler();
608
connection_count.increment();
610
if (connection_count > max_used_connections)
611
max_used_connections= connection_count;
613
thread_id= variables.pseudo_thread_id= global_thread_id++;
615
pthread_mutex_lock(&LOCK_thread_count);
616
getSessionList().push_back(this);
617
pthread_mutex_unlock(&LOCK_thread_count);
619
if (scheduler->addSession(this))
621
DRIZZLE_CONNECTION_START(thread_id);
571
622
char error_message_buff[DRIZZLE_ERRMSG_SIZE];
573
arg->setKilled(Session::KILL_CONNECTION);
624
killed= Session::KILL_CONNECTION;
575
arg->status_var.aborted_connects++;
626
statistic_increment(aborted_connects, &LOCK_status);
577
628
/* Can't use my_error() since store_globals has not been called. */
578
629
/* TODO replace will better error message */
579
630
snprintf(error_message_buff, sizeof(error_message_buff),
580
631
ER(ER_CANT_CREATE_THREAD), 1);
581
arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
632
client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
614
657
locked (if that would not be the case, you'll get a deadlock if someone
615
658
does a Session::awake() on you).
617
mysys_var->current_mutex->unlock();
618
boost_unique_lock_t scopedLock(mysys_var->mutex);
660
pthread_mutex_unlock(mysys_var->current_mutex);
661
pthread_mutex_lock(&mysys_var->mutex);
619
662
mysys_var->current_mutex = 0;
620
663
mysys_var->current_cond = 0;
621
664
this->set_proc_info(old_msg);
665
pthread_mutex_unlock(&mysys_var->mutex);
624
668
bool Session::authenticate()
626
671
if (client->authenticate())
629
status_var.aborted_connects++;
674
statistic_increment(aborted_connects, &LOCK_status);
634
bool Session::checkUser(const std::string &passwd_str,
635
const std::string &in_db)
678
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
637
bool is_authenticated=
638
plugin::Authentication::isAuthenticated(*user(), passwd_str);
680
bool is_authenticated;
682
if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
684
my_error(ER_HANDSHAKE_ERROR, MYF(0), security_ctx.ip.c_str());
688
is_authenticated= plugin::Authentication::isAuthenticated(this, passwd);
640
690
if (is_authenticated != true)
642
status_var.access_denied++;
643
/* isAuthenticated has pushed the error message */
692
my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
693
security_ctx.user.c_str(),
694
security_ctx.ip.c_str(),
695
passwd_len ? ER(ER_YES) : ER(ER_NO));
700
security_ctx.skip_grants();
647
702
/* Change database if necessary */
648
if (not in_db.empty())
703
if (in_db && in_db[0])
650
identifier::Schema identifier(in_db);
651
if (schema::change(*this, identifier))
705
const string database_name_string(in_db);
706
NonNormalisedDatabaseName database_name(database_name_string);
707
NormalisedDatabaseName normalised_database_name(database_name);
709
if (mysql_change_db(this, normalised_database_name, false))
653
/* change_db() has pushed the error message. */
711
/* mysql_change_db() has pushed the error message. */
658
password= not passwd_str.empty();
716
password= test(passwd_len); // remember for error messages
660
718
/* Ready to handle queries */
705
758
in_packet_length--;
707
760
const char *pos= in_packet + in_packet_length; /* Point at end null */
708
while (in_packet_length > 0 && (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
761
while (in_packet_length > 0 &&
762
(pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
711
765
in_packet_length--;
714
std::string *new_query= new std::string(in_packet, in_packet + in_packet_length);
715
// We can not be entirely sure _schema has a value
718
plugin::QueryRewriter::rewriteQuery(*_schema, *new_query);
720
query.reset(new_query);
721
_state.reset(new session::State(in_packet, in_packet_length));
768
/* We must allocate some extra memory for the cached query string */
769
query_length= 0; /* Extra safety: Avoid races */
770
query= (char*) memdup_w_gap((unsigned char*) in_packet, in_packet_length, db.length() + 1);
774
query[in_packet_length]=0;
775
query_length= in_packet_length;
865
917
@return NULL on failure, or pointer to the LEX_STRING object
867
919
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
868
const std::string &str,
869
bool allocate_lex_string)
871
return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
874
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
875
const char* str, uint32_t length,
876
bool allocate_lex_string)
920
const char* str, uint32_t length,
921
bool allocate_lex_string)
878
923
if (allocate_lex_string)
879
if (!(lex_str= (LEX_STRING *)getMemRoot()->allocate(sizeof(LEX_STRING))))
924
if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
881
if (!(lex_str->str= mem_root->strmake_root(str, length)))
926
if (!(lex_str->str= strmake_root(mem_root, str, length)))
883
928
lex_str->length= length;
932
/* routings to adding tables to list of changed in transaction tables */
933
inline static void list_include(CHANGED_TableList** prev,
934
CHANGED_TableList* curr,
935
CHANGED_TableList* new_table)
940
(*prev)->next = curr;
944
/* add table to list of changed in transaction tables */
946
void Session::add_changed_table(Table *table)
948
assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
949
table->cursor->has_transactions());
950
add_changed_table(table->s->table_cache_key.str,
951
(long) table->s->table_cache_key.length);
955
void Session::add_changed_table(const char *key, long key_length)
957
CHANGED_TableList **prev_changed = &transaction.changed_tables;
958
CHANGED_TableList *curr = transaction.changed_tables;
960
for (; curr; prev_changed = &(curr->next), curr = curr->next)
962
int cmp = (long)curr->key_length - (long)key_length;
965
list_include(prev_changed, curr, changed_table_dup(key, key_length));
970
cmp = memcmp(curr->key, key, curr->key_length);
973
list_include(prev_changed, curr, changed_table_dup(key, key_length));
982
*prev_changed = changed_table_dup(key, key_length);
986
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
988
CHANGED_TableList* new_table =
989
(CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
993
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
994
ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
995
killed= KILL_CONNECTION;
999
new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
1000
new_table->next = 0;
1001
new_table->key_length = key_length;
1002
::memcpy(new_table->key, key, key_length);
887
1007
int Session::send_explain_fields(select_result *result)
889
1009
List<Item> field_list;
1019
static int create_file(Session *session,
1020
fs::path &target_path,
1021
file_exchange *exchange,
1022
internal::IO_CACHE *cache)
1139
static int create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1024
fs::path to_file(exchange->file_name);
1027
if (not to_file.has_root_directory())
1142
uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
1144
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1145
option|= MY_REPLACE_DIR; // Force use of db directory
1148
if (!dirname_length(exchange->file_name))
1029
target_path= fs::system_complete(getDataHomeCatalog());
1030
util::string::const_shared_ptr schema(session->schema());
1031
if (schema and not schema->empty())
1033
int count_elements= 0;
1034
for (fs::path::iterator iter= to_file.begin();
1035
iter != to_file.end();
1036
++iter, ++count_elements)
1039
if (count_elements == 1)
1041
target_path /= *schema;
1044
target_path /= to_file;
1150
strcpy(path, drizzle_real_data_home);
1151
if (! session->db.empty())
1152
strncat(path, session->db.c_str(), FN_REFLEN-strlen(drizzle_real_data_home)-1);
1153
(void) fn_format(path, exchange->file_name, path, "", option);
1048
target_path = exchange->file_name;
1051
if (not secure_file_priv.string().empty())
1053
if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1055
/* Write only allowed to dir or subdir specified by secure_file_priv */
1056
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1061
if (!access(target_path.file_string().c_str(), F_OK))
1156
(void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
1158
if (opt_secure_file_priv &&
1159
strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1161
/* Write only allowed to dir or subdir specified by secure_file_priv */
1162
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1166
if (!access(path, F_OK))
1063
1168
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1066
1171
/* Create the file world readable */
1067
if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1172
if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1069
1174
(void) fchmod(file, 0666); // Because of umask()
1070
if (cache->init_io_cache(file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1175
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1072
internal::my_close(file, MYF(0));
1073
internal::my_delete(target_path.file_string().c_str(), MYF(0)); // Delete file on error, it was just created
1177
my_close(file, MYF(0));
1178
my_delete(path, MYF(0)); // Delete file on error, it was just created
1485
1594
bool select_max_min_finder_subselect::cmp_decimal()
1487
1596
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1488
type::Decimal cval, *cvalue= cache->val_decimal(&cval);
1489
type::Decimal mval, *mvalue= maxmin->val_decimal(&mval);
1597
my_decimal cval, *cvalue= cache->val_decimal(&cval);
1598
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
1491
1600
return (cache->null_value && !maxmin->null_value) ||
1492
1601
(!cache->null_value && !maxmin->null_value &&
1493
class_decimal_cmp(cvalue, mvalue) > 0) ;
1602
my_decimal_cmp(cvalue, mvalue) > 0) ;
1494
1603
return (maxmin->null_value && !cache->null_value) ||
1495
1604
(!cache->null_value && !maxmin->null_value &&
1496
class_decimal_cmp(cvalue,mvalue) < 0);
1605
my_decimal_cmp(cvalue,mvalue) < 0);
1499
1608
bool select_max_min_finder_subselect::cmp_str()
1596
1695
memset(&status_var, 0, sizeof(status_var));
1600
void Session::set_db(const std::string &new_db)
1602
/* Do not reallocate memory if current chunk is big enough. */
1603
if (new_db.length())
1605
_schema.reset(new std::string(new_db));
1609
_schema.reset(new std::string(""));
1698
void Security_context::skip_grants()
1700
/* privileges for the user are unknown everything is allowed */
1704
/****************************************************************************
1705
Handling of open and locked tables states.
1707
This is used when we want to open/lock (and then close) some tables when
1708
we already have a set of tables open and locked. We use these methods for
1709
access to mysql.proc table to find definitions of stored routines.
1710
****************************************************************************/
1712
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
1714
backup->set_open_tables_state(this);
1715
reset_open_tables_state();
1716
backups_available= false;
1720
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
1723
Before we will throw away current open tables state we want
1724
to be sure that it was properly cleaned up.
1726
assert(open_tables == 0 && temporary_tables == 0 &&
1727
derived_tables == 0 &&
1729
set_open_tables_state(backup);
1733
bool Session::set_db(const NormalisedDatabaseName &new_db)
1735
db= new_db.to_string();
1740
void Session::clear_db()
1747
Check the killed state of a user thread
1748
@param session user thread
1749
@retval 0 the user thread is active
1750
@retval 1 the user thread has been killed
1752
extern "C" int session_killed(const Session *session)
1754
return(session->killed);
1758
Return the session id of a user session
1759
@param pointer to Session object
1760
@return session's id
1762
extern "C" unsigned long session_get_thread_id(const Session *session)
1764
return (unsigned long) session->getSessionId();
1768
const struct charset_info_st *session_charset(Session *session)
1770
return(session->charset());
1773
char **session_query(Session *session)
1775
return(&session->query);
1778
int session_non_transactional_update(const Session *session)
1780
return(session->transaction.all.modified_non_trans_table);
1783
void session_mark_transaction_to_rollback(Session *session, bool all)
1785
mark_transaction_to_rollback(session, all);
1615
1789
Mark transaction to rollback and mark error as fatal to a sub-statement.
1617
1791
@param session Thread handle
1618
1792
@param all true <=> rollback main transaction.
1620
void Session::markTransactionForRollback(bool all)
1794
void mark_transaction_to_rollback(Session *session, bool all)
1622
is_fatal_sub_stmt_error= true;
1623
transaction_rollback_request= all;
1798
session->is_fatal_sub_stmt_error= true;
1799
session->transaction_rollback_request= all;
1626
void Session::disconnect(enum error_t errcode)
1803
void Session::disconnect(uint32_t errcode, bool should_lock)
1628
1805
/* Allow any plugins to cleanup their session variables */
1629
1806
plugin_sessionvar_cleanup(this);
1631
1808
/* If necessary, log any aborted or unauthorized connections */
1632
if (getKilled() || client->wasAborted())
1634
status_var.aborted_threads++;
1809
if (killed || client->wasAborted())
1810
statistic_increment(aborted_threads, &LOCK_status);
1637
1812
if (client->wasAborted())
1639
if (not getKilled() && variables.log_warnings > 1)
1814
if (! killed && variables.log_warnings > 1)
1641
errmsg_printf(error::WARN, ER(ER_NEW_ABORTING_CONNECTION)
1816
Security_context *sctx= &security_ctx;
1818
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1643
, (_schema->empty() ? "unconnected" : _schema->c_str())
1644
, security_ctx->username().empty() == false ? security_ctx->username().c_str() : "unauthenticated"
1645
, security_ctx->address().c_str()
1820
, (db.empty() ? "unconnected" : db.c_str())
1821
, sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
1646
1823
, (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1650
setKilled(Session::KILL_CONNECTION);
1827
/* Close out our connection to the client */
1829
(void) pthread_mutex_lock(&LOCK_thread_count);
1830
killed= Session::KILL_CONNECTION;
1652
1831
if (client->isConnected())
1654
if (errcode != EE_OK)
1656
1835
/*my_error(errcode, ER(errcode));*/
1657
1836
client->sendError(errcode, ER(errcode));
1659
1838
client->close();
1841
(void) pthread_mutex_unlock(&LOCK_thread_count);
1663
1844
void Session::reset_for_next_command()
1724
1912
passing non-zero value to end_slave via rli->save_temporary_tables
1725
1913
when no temp tables opened, see an invariant below.
1727
temporary_tables= table->getNext();
1915
temporary_tables= table->next;
1728
1916
if (temporary_tables)
1730
table->getNext()->setPrev(NULL);
1917
table->next->prev= NULL;
1919
close_temporary(table);
1737
Close and drop a temporary table
1923
Close and delete a temporary table
1740
1926
This dosn't unlink table from session->temporary
1741
1927
If this is needed, use close_temporary_table()
1744
void Open_tables_state::nukeTable(Table *table)
1930
void Session::close_temporary(Table *table)
1746
plugin::StorageEngine *table_type= table->getShare()->db_type();
1932
plugin::StorageEngine *table_type= table->s->db_type();
1748
1934
table->free_io_cache();
1749
table->delete_table();
1751
identifier::Table identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1752
rm_temporary_table(table_type, identifier);
1754
boost::checked_delete(table->getMutableShare());
1756
boost::checked_delete(table);
1935
table->closefrm(false);
1937
rm_temporary_table(table_type, table->s->path.str);
1939
table->s->free_table_share();
1941
/* This makes me sad, but we're allocating it via malloc */
1759
1945
/** Clear most status variables. */
1760
1946
extern time_t flush_status_time;
1947
extern uint32_t max_used_connections;
1762
1949
void Session::refresh_status()
1951
pthread_mutex_lock(&LOCK_status);
1953
/* Add thread's status variabes to global status */
1954
add_to_status(&global_status_var, &status_var);
1764
1956
/* Reset thread's status variables */
1765
1957
memset(&status_var, 0, sizeof(status_var));
1959
/* Reset some global variables */
1960
reset_status_vars();
1962
/* Reset the counters of all key caches (default and named). */
1963
reset_key_cache_counters();
1767
1964
flush_status_time= time((time_t*) 0);
1768
current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1769
current_global_counters.connections= 0;
1965
max_used_connections= 1; /* We set it to one, because we know we exist */
1966
pthread_mutex_unlock(&LOCK_status);
1772
1969
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1774
return getVariable(std::string(name.str, name.length), create_if_not_exists);
1777
user_var_entry *Session::getVariable(const std::string &name, bool create_if_not_exists)
1782
UserVars::iterator iter= user_vars.find(name);
1783
if (iter != user_vars.end())
1784
return (*iter).second;
1786
if (not create_if_not_exists)
1789
1971
user_var_entry *entry= NULL;
1790
entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1795
std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1797
if (not returnable.second)
1973
entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
1975
if ((entry == NULL) && create_if_not_exists)
1799
boost::checked_delete(entry);
1977
if (!hash_inited(&user_vars))
1979
entry= new (nothrow) user_var_entry(name.str, query_id);
1984
if (my_hash_insert(&user_vars, (unsigned char*) entry))
1987
free((char*) entry);
1805
void Session::setVariable(const std::string &name, const std::string &value)
1807
user_var_entry *updateable_var= getVariable(name.c_str(), true);
1810
updateable_var->update_hash(false,
1811
(void*)value.c_str(),
1812
static_cast<uint32_t>(value.length()), STRING_RESULT,
1814
DERIVATION_IMPLICIT, false);
1818
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
1820
for (Table *table= temporary_tables ; table ; table= table->getNext())
1822
if (table->query_id == getQueryId())
1996
void Session::mark_temp_tables_as_free_for_reuse()
1998
for (Table *table= temporary_tables ; table ; table= table->next)
2000
if (table->query_id == query_id)
1824
2002
table->query_id= 0;
1825
2003
table->cursor->ha_reset();
1921
2125
if (open_tables_from_list(&tables, &counter))
1924
if (not lock_tables(tables, counter, &need_reopen))
2128
if (!lock_tables(tables, counter, &need_reopen))
1927
if (not need_reopen)
1930
2132
close_tables_for_reopen(&tables);
1933
if ((handle_derived(lex, &derived_prepare) || (handle_derived(lex, &derived_filling))))
1940
@note "best_effort" is used in cases were if a failure occurred on this
1941
operation it would not be surprising because we are only removing because there
1942
might be an issue (lame engines).
1945
bool Open_tables_state::rm_temporary_table(const identifier::Table &identifier, bool best_effort)
1947
if (not plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
1949
if (not best_effort)
1952
identifier.getSQLPath(path);
1953
errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"),
1954
path.c_str(), errno);
1963
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const identifier::Table &identifier)
1965
drizzled::error_t error;
1968
if (not plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier, error))
1971
identifier.getSQLPath(path);
1972
errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"),
1973
path.c_str(), error);
1982
@note this will be removed, I am looking through Hudson to see if it is finding
1983
any tables that are missed during cleanup.
1985
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
1989
if (not temporary_tables)
1992
cerr << "Begin Run: " << foo << "\n";
1993
for (table= temporary_tables; table; table= table->getNext())
1995
bool have_proto= false;
1997
message::Table *proto= table->getShare()->getTableMessage();
1998
if (table->getShare()->getTableMessage())
2001
const char *answer= have_proto ? "true" : "false";
2005
cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2006
cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2010
cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2015
table::Singular *Session::getInstanceTable()
2017
temporary_shares.push_back(new table::Singular()); // This will not go into the tableshare cache, so no key is used.
2019
table::Singular *tmp_share= temporary_shares.back();
2028
Create a reduced Table object with properly set up Field list from a
2029
list of field definitions.
2031
The created table doesn't have a table Cursor associated with
2032
it, has no keys, no group/distinct, no copy_funcs array.
2033
The sole purpose of this Table object is to use the power of Field
2034
class to read/write data to/from table->getInsertRecord(). Then one can store
2035
the record in any container (RB tree, hash, etc).
2036
The table is created in Session mem_root, so are the table's fields.
2037
Consequently, if you don't BLOB fields, you don't need to free it.
2039
@param session connection handle
2040
@param field_list list of column definitions
2043
0 if out of memory, Table object in case of success
2045
table::Singular *Session::getInstanceTable(List<CreateField> &field_list)
2047
temporary_shares.push_back(new table::Singular(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2049
table::Singular *tmp_share= temporary_shares.back();
2058
static const std::string NONE= "NONE";
2059
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2060
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2062
const std::string &type(drizzled::Session::global_read_lock_t type)
2068
case Session::GOT_GLOBAL_READ_LOCK:
2069
return GOT_GLOBAL_READ_LOCK;
2070
case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2071
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2075
size_t max_string_length(drizzled::Session::global_read_lock_t)
2077
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2080
} /* namespace display */
2082
} /* namespace drizzled */
2134
if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
2135
(fill_derived_tables() &&
2136
mysql_handle_derived(lex, &mysql_derived_filling))))
2142
bool Session::openTables(TableList *tables, uint32_t flags)
2145
bool ret= fill_derived_tables();
2146
assert(ret == false);
2147
if (open_tables_from_list(&tables, &counter, flags) ||
2148
mysql_handle_derived(lex, &mysql_derived_prepare))
2153
bool Session::rm_temporary_table(plugin::StorageEngine *base, TableIdentifier &identifier)
2159
if (plugin::StorageEngine::deleteDefinitionFromPath(identifier))
2162
if (base->doDropTable(*this, identifier.getPath()))
2165
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2166
identifier.getPath(), errno);
2171
bool Session::rm_temporary_table(plugin::StorageEngine *base, const char *path)
2177
if (delete_table_proto_file(path))
2180
if (base->doDropTable(*this, path))
2183
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),