21
21
* @file Implementation of the Session class and API
26
#include <drizzled/copy_field.h>
27
#include "drizzled/session.h"
28
#include "drizzled/session/cache.h"
29
#include "drizzled/error.h"
30
#include "drizzled/gettext.h"
31
#include "drizzled/query_id.h"
32
#include "drizzled/data_home.h"
33
#include "drizzled/sql_base.h"
34
#include "drizzled/lock.h"
35
#include "drizzled/item/cache.h"
36
#include "drizzled/item/float.h"
37
#include "drizzled/item/return_int.h"
38
#include "drizzled/item/empty_string.h"
39
#include "drizzled/show.h"
40
#include "drizzled/plugin/client.h"
24
#include <drizzled/server_includes.h>
25
#include <drizzled/session.h>
27
#include <mysys/mysys_err.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>
41
40
#include "drizzled/plugin/scheduler.h"
42
41
#include "drizzled/plugin/authentication.h"
43
#include "drizzled/plugin/logging.h"
44
#include "drizzled/plugin/transactional_storage_engine.h"
45
#include "drizzled/plugin/query_rewrite.h"
46
42
#include "drizzled/probes.h"
47
43
#include "drizzled/table_proto.h"
48
#include "drizzled/db.h"
49
#include "drizzled/pthread_globals.h"
50
#include "drizzled/transaction_services.h"
51
#include "drizzled/drizzled.h"
53
#include "drizzled/identifier.h"
55
#include <drizzled/refresh_version.h>
57
#include "drizzled/table/singular.h"
59
#include "plugin/myisam/myisam.h"
60
#include "drizzled/internal/iocache.h"
61
#include "drizzled/internal/thread_var.h"
62
#include "drizzled/plugin/event_observer.h"
64
#include "drizzled/util/functors.h"
66
#include "drizzled/display.h"
68
45
#include <algorithm>
73
#include <boost/filesystem.hpp>
74
#include <boost/checked_delete.hpp>
76
#include "drizzled/util/backtrace.h"
78
47
using namespace std;
48
using namespace drizzled;
80
namespace fs=boost::filesystem;
52
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool );
53
void free_user_var(user_var_entry *entry);
85
57
The following is used to initialise Table_ident with a internal
89
61
char empty_c_string[1]= {0}; /* used for not defined db */
91
63
const char * const Session::DEFAULT_WHERE= "field list";
64
extern pthread_key_t THR_Session;
65
extern pthread_key_t THR_Mem_root;
66
extern uint32_t max_used_connections;
67
extern drizzled::atomic<uint32_t> connection_count;
69
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
71
template class List<Key>;
72
template class List_iterator<Key>;
73
template class List<Key_part_spec>;
74
template class List_iterator<Key_part_spec>;
75
template class List<AlterDrop>;
76
template class List_iterator<AlterDrop>;
77
template class List<AlterColumn>;
78
template class List_iterator<AlterColumn>;
81
/****************************************************************************
83
****************************************************************************/
84
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool )
86
*length= entry->name.length;
87
return (unsigned char*) entry->name.str;
90
void free_user_var(user_var_entry *entry)
93
95
bool Key_part_spec::operator==(const Key_part_spec& other) const
95
97
return length == other.length &&
96
98
field_name.length == other.field_name.length &&
97
!my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
99
!strcmp(field_name.str, other.field_name.str);
100
Open_tables_state::Open_tables_state(uint64_t version_arg) :
102
Open_tables_state::Open_tables_state(ulong version_arg)
103
:version(version_arg), backups_available(false)
103
open_tables= temporary_tables= derived_tables= NULL;
104
extra_lock= lock= NULL;
105
reset_open_tables_state();
108
109
The following functions form part of the C plugin API
110
int tmpfile(const char *prefix)
111
extern "C" int mysql_tmpfile(const char *prefix)
112
113
char filename[FN_REFLEN];
113
int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
114
File fd = create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
115
116
unlink(filename);
121
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
123
return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
126
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
129
return &ha_data[monitored->getId()].resource_context[index];
123
int session_tablespace_op(const Session *session)
125
return test(session->tablespace_op);
129
Set the process info field of the Session structure.
131
This function is used by plug-ins. Internally, the
132
Session::set_proc_info() function should be used.
134
@see Session::set_proc_info
137
set_session_proc_info(Session *session, const char *info)
139
session->set_proc_info(info);
143
const char *get_session_proc_info(Session *session)
145
return session->get_proc_info();
149
void **session_ha_data(const Session *session, const plugin::StorageEngine *engine)
151
return (void **) &session->ha_data[engine->slot].ha_ptr;
132
155
int64_t session_test_options(const Session *session, int64_t test_options)
134
157
return session->options & test_options;
137
Session::Session(plugin::Client *client_arg, catalog::Instance::shared_ptr catalog_arg) :
161
int session_sql_command(const Session *session)
163
return (int) session->lex->sql_command;
167
int session_tx_isolation(const Session *session)
169
return (int) session->variables.tx_isolation;
173
void session_inc_row_count(Session *session)
175
session->row_count++;
178
Session::Session(plugin::Client *client_arg)
138
180
Open_tables_state(refresh_version),
139
181
mem_root(&main_mem_root),
142
query(new std::string),
143
_schema(new std::string("")),
144
183
client(client_arg),
146
185
scheduler_arg(NULL),
147
186
lock_id(&main_lock_id),
149
security_ctx(identifier::User::make_shared()),
150
_where(Session::DEFAULT_WHERE),
151
dbug_sentry(Session_SENTRY_MAGIC),
153
command(COM_CONNECT),
155
_epoch(boost::gregorian::date(1970,1,1)),
156
_connect_time(boost::posix_time::microsec_clock::universal_time()),
158
ha_data(plugin::num_trx_monitored_objects),
161
concurrent_execute_allowed(true),
162
188
arg_of_last_insert_id_function(false),
163
189
first_successful_insert_id_in_prev_stmt(0),
164
190
first_successful_insert_id_in_cur_stmt(0),
165
191
limit_found_rows(0),
166
options(session_startup_options),
169
examined_row_count(0),
173
statement_id_counter(0),
177
_global_read_lock(NONE),
178
count_cuted_fields(CHECK_FIELD_ERROR_FOR_NULL),
180
193
some_tables_deleted(false),
181
194
no_errors(false),
183
196
is_fatal_error(false),
184
197
transaction_rollback_request(false),
185
198
is_fatal_sub_stmt_error(0),
199
derived_tables_processing(false),
186
200
tablespace_op(false),
187
derived_tables_processing(false),
190
203
transaction_message(NULL),
191
statement_message(NULL),
192
session_event_observers(NULL),
193
_catalog(catalog_arg),
204
statement_message(NULL)
206
memset(process_list_info, 0, PROCESS_LIST_WIDTH);
196
207
client->setSession(this);
200
211
the destructor works OK in case of an error. The main_mem_root
201
212
will be re-initialized in init_for_queries().
203
memory::init_sql_alloc(&main_mem_root, memory::ROOT_MIN_BLOCK_SIZE, 0);
214
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
216
count_cuted_fields= CHECK_FIELD_IGNORE;
204
221
cuted_fields= sent_row_count= row_count= 0L;
223
statement_id_counter= 0UL;
205
224
// Must be reset to handle error with Session's created for init of mysqld
206
225
lex->current_select= 0;
226
start_time=(time_t) 0;
228
utime_after_lock= 0L;
207
229
memset(&variables, 0, sizeof(variables));
208
scoreboard_index= -1;
209
cleanup_done= abort_on_warning= no_warnings_for_error= false;
211
/* query_cache init */
236
memset(ha_data, 0, sizeof(ha_data));
239
dbug_sentry=Session_SENTRY_MAGIC;
240
cleanup_done= abort_on_warning= no_warnings_for_error= false;
242
pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
215
244
/* Variables with default values */
216
245
proc_info="login";
246
where= Session::DEFAULT_WHERE;
247
command= COM_CONNECT;
218
249
plugin_sessionvar_init(this);
224
255
variables.pseudo_thread_id= thread_id;
225
256
server_status= SERVER_STATUS_AUTOCOMMIT;
257
options= session_startup_options;
227
259
if (variables.max_join_size == HA_POS_ERROR)
228
260
options |= OPTION_BIG_SELECTS;
230
262
options &= ~OPTION_BIG_SELECTS;
264
transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= false;
232
265
open_options=ha_open_options;
233
266
update_lock_default= TL_WRITE;
234
267
session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
235
268
warn_list.empty();
236
269
memset(warn_count, 0, sizeof(warn_count));
237
271
memset(&status_var, 0, sizeof(status_var));
239
273
/* Initialize sub structures */
240
memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
274
init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
275
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
276
(hash_get_key) get_var_key,
277
(hash_free_key) free_user_var, 0);
242
279
substitute_null_with_insert_id = false;
243
lock_info.init(); /* safety: will be reset after start */
280
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
244
281
thr_lock_owner_init(&main_lock_id, &lock_info);
246
283
m_internal_handler= NULL;
248
plugin::EventObserver::registerSessionEvents(*this);
251
286
void Session::free_items()
254
/* This works because items are allocated with memory::sql_alloc() */
289
/* This works because items are allocated with sql_alloc() */
255
290
for (; free_list; free_list= next)
257
292
next= free_list->next;
280
315
return false; // 'false', as per coding style
283
void Session::setAbort(bool arg)
285
mysys_var->abort= arg;
288
void Session::lockOnSys()
294
boost_unique_lock_t scopedLock(mysys_var->mutex);
295
if (mysys_var->current_cond)
297
mysys_var->current_mutex->lock();
298
mysys_var->current_cond->notify_all();
299
mysys_var->current_mutex->unlock();
303
318
void Session::pop_internal_handler()
305
320
assert(m_internal_handler != NULL);
306
321
m_internal_handler= NULL;
309
void Session::get_xid(DRIZZLE_XID *xid)
311
*xid = *(DRIZZLE_XID *) &transaction.xid_state.xid;
324
#if defined(__cplusplus)
328
void *session_alloc(Session *session, unsigned int size)
330
return session->alloc(size);
333
void *session_calloc(Session *session, unsigned int size)
335
return session->calloc(size);
338
char *session_strdup(Session *session, const char *str)
340
return session->strdup(str);
343
char *session_strmake(Session *session, const char *str, unsigned int size)
345
return session->strmake(str, size);
348
void *session_memdup(Session *session, const void* str, unsigned int size)
350
return session->memdup(str, size);
353
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
355
*xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
358
#if defined(__cplusplus)
314
362
/* Do operations that may take a long time */
328
TransactionServices &transaction_services= TransactionServices::singleton();
329
transaction_services.rollbackTransaction(*this, true);
330
377
xid_cache_delete(&transaction.xid_state);
333
for (UserVars::iterator iter= user_vars.begin();
334
iter != user_vars.end();
337
user_var_entry *entry= (*iter).second;
338
boost::checked_delete(entry);
379
hash_free(&user_vars);
343
380
close_temporary_tables();
345
382
if (global_read_lock)
347
unlockGlobalReadLock();
383
unlock_global_read_lock(this);
350
385
cleanup_done= true;
353
388
Session::~Session()
390
Session_CHECK_SENTRY(this);
391
add_to_status(&global_status_var, &status_var);
357
if (client and client->isConnected())
393
if (client->isConnected())
359
assert(security_ctx);
360
395
if (global_system_variables.log_warnings)
362
errmsg_printf(error::WARN, ER(ER_FORCING_CLOSE),
363
internal::my_progname,
365
security_ctx->username().c_str());
396
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),my_progname,
398
(security_ctx.user.c_str() ?
399
security_ctx.user.c_str() : ""));
400
disconnect(0, false);
371
403
/* Close connection */
375
boost::checked_delete(client);
379
407
if (cleanup_done == false)
382
410
plugin::StorageEngine::closeConnection(this);
383
411
plugin_sessionvar_cleanup(this);
385
warn_root.free_root(MYF(0));
413
free_root(&warn_root,MYF(0));
414
free_root(&transaction.mem_root,MYF(0));
386
415
mysys_var=0; // Safety (shouldn't be needed)
387
416
dbug_sentry= Session_SENTRY_GONE;
389
main_mem_root.free_root(MYF(0));
390
currentMemRoot().release();
391
currentSession().release();
393
plugin::Logging::postEndDo(this);
394
plugin::EventObserver::deregisterSessionEvents(*this);
397
void Session::setClient(plugin::Client *client_arg)
400
client->setSession(this);
403
void Session::awake(Session::killed_state_t state_to_set)
405
if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
410
setKilled(state_to_set);
411
scheduler->killSession(this);
418
free_root(&main_mem_root, MYF(0));
419
pthread_setspecific(THR_Session, 0);
422
/* Ensure that no one is using Session */
423
pthread_mutex_unlock(&LOCK_delete);
424
pthread_mutex_destroy(&LOCK_delete);
428
Add all status variables to another status variable array
432
to_var add to this array
433
from_var from this array
436
This function assumes that all variables are long/ulong.
437
If this assumption will change, then we have to explictely add
438
the other variables after the while loop
440
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
442
ulong *end= (ulong*) ((unsigned char*) to_var +
443
offsetof(STATUS_VAR, last_system_status_var) +
445
ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
452
Add the difference between two status variable arrays to another one.
456
to_var add to this array
457
from_var from this array
458
dec_var minus this array
461
This function assumes that all variables are long/ulong.
463
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
466
ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
467
last_system_status_var) +
469
ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
472
*(to++)+= *(from++) - *(dec++);
475
void Session::awake(Session::killed_state state_to_set)
477
Session_CHECK_SENTRY(this);
478
safe_mutex_assert_owner(&LOCK_delete);
480
killed= state_to_set;
413
481
if (state_to_set != Session::KILL_QUERY)
483
scheduler->killSession(this);
415
484
DRIZZLE_CONNECTION_DONE(thread_id);
420
boost_unique_lock_t scopedLock(mysys_var->mutex);
488
pthread_mutex_lock(&mysys_var->mutex);
423
490
This broadcast could be up in the air if the victim thread
424
491
exits the cond in the time between read and broadcast, but that is
425
492
ok since all we want to do is to make the victim thread get out
497
563
set_proc_info(NULL);
498
564
command= COM_SLEEP;
566
ha_enable_transaction(this,true);
501
mem_root->reset_root_defaults(variables.query_alloc_block_size,
502
variables.query_prealloc_size);
568
reset_root_defaults(mem_root, variables.query_alloc_block_size,
569
variables.query_prealloc_size);
570
reset_root_defaults(&transaction.mem_root,
571
variables.trans_alloc_block_size,
572
variables.trans_prealloc_size);
503
573
transaction.xid_state.xid.null();
504
574
transaction.xid_state.in_session=1;
509
577
bool Session::initGlobals()
511
579
if (storeGlobals())
513
disconnect(ER_OUT_OF_RESOURCES);
514
status_var.aborted_connects++;
581
disconnect(ER_OUT_OF_RESOURCES, true);
582
statistic_increment(aborted_connects, &LOCK_status);
522
590
if (initGlobals() || authenticate())
528
596
prepareForQueries();
530
while (not client->haveError() && getKilled() != KILL_CONNECTION)
598
while (! client->haveError() && killed != KILL_CONNECTION)
532
if (not executeStatement())
600
if (! executeStatement())
539
bool Session::schedule(Session::shared_ptr &arg)
607
bool Session::schedule()
541
arg->scheduler= plugin::Scheduler::getScheduler();
542
assert(arg->scheduler);
609
scheduler= plugin::Scheduler::getScheduler();
544
612
++connection_count;
546
long current_connections= connection_count;
548
if (current_connections > 0 and static_cast<uint64_t>(current_connections) > current_global_counters.max_used_connections)
550
current_global_counters.max_used_connections= static_cast<uint64_t>(connection_count);
553
current_global_counters.connections++;
554
arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
556
session::Cache::singleton().insert(arg);
558
if (unlikely(plugin::EventObserver::connectSession(*arg)))
560
// We should do something about an error...
563
if (plugin::Scheduler::getScheduler()->addSession(arg))
565
DRIZZLE_CONNECTION_START(arg->getSessionId());
614
if (connection_count > max_used_connections)
615
max_used_connections= connection_count;
617
thread_id= variables.pseudo_thread_id= global_thread_id++;
619
pthread_mutex_lock(&LOCK_thread_count);
620
session_list.push_back(this);
621
pthread_mutex_unlock(&LOCK_thread_count);
623
if (scheduler->addSession(this))
625
DRIZZLE_CONNECTION_START(thread_id);
566
626
char error_message_buff[DRIZZLE_ERRMSG_SIZE];
568
arg->setKilled(Session::KILL_CONNECTION);
628
killed= Session::KILL_CONNECTION;
570
arg->status_var.aborted_connects++;
630
statistic_increment(aborted_connects, &LOCK_status);
572
632
/* Can't use my_error() since store_globals has not been called. */
573
633
/* TODO replace will better error message */
574
634
snprintf(error_message_buff, sizeof(error_message_buff),
575
635
ER(ER_CANT_CREATE_THREAD), 1);
576
arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
636
client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
586
Is this session viewable by the current user?
588
bool Session::isViewable(identifier::User::const_reference user_arg) const
590
return plugin::Authorization::isAuthorized(user_arg, this, false);
594
const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
596
const char* old_msg = get_proc_info();
597
safe_mutex_assert_owner(mutex);
598
mysys_var->current_mutex = &mutex;
599
mysys_var->current_cond = &cond;
600
this->set_proc_info(msg);
604
void Session::exit_cond(const char* old_msg)
607
Putting the mutex unlock in exit_cond() ensures that
608
mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
609
locked (if that would not be the case, you'll get a deadlock if someone
610
does a Session::awake() on you).
612
mysys_var->current_mutex->unlock();
613
boost_unique_lock_t scopedLock(mysys_var->mutex);
614
mysys_var->current_mutex = 0;
615
mysys_var->current_cond = 0;
616
this->set_proc_info(old_msg);
619
643
bool Session::authenticate()
621
646
if (client->authenticate())
624
status_var.aborted_connects++;
649
statistic_increment(aborted_connects, &LOCK_status);
629
bool Session::checkUser(const std::string &passwd_str,
630
const std::string &in_db)
653
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
632
bool is_authenticated=
633
plugin::Authentication::isAuthenticated(user(), passwd_str);
655
LEX_STRING db_str= { (char *) in_db, in_db ? strlen(in_db) : 0 };
656
bool is_authenticated;
658
if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
660
my_error(ER_HANDSHAKE_ERROR, MYF(0), security_ctx.ip.c_str());
664
is_authenticated= plugin::Authentication::isAuthenticated(this, passwd);
635
666
if (is_authenticated != true)
637
status_var.access_denied++;
638
/* isAuthenticated has pushed the error message */
668
my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
669
security_ctx.user.c_str(),
670
security_ctx.ip.c_str(),
671
passwd_len ? ER(ER_YES) : ER(ER_NO));
676
security_ctx.skip_grants();
642
678
/* Change database if necessary */
643
if (not in_db.empty())
679
if (in_db && in_db[0])
645
identifier::Schema identifier(in_db);
646
if (change_db(this, identifier))
681
if (mysql_change_db(this, &db_str, false))
648
/* change_db() has pushed the error message. */
683
/* mysql_change_db() has pushed the error message. */
653
password= not passwd_str.empty();
688
password= test(passwd_len); // remember for error messages
655
690
/* Ready to handle queries */
700
730
in_packet_length--;
702
732
const char *pos= in_packet + in_packet_length; /* Point at end null */
703
while (in_packet_length > 0 && (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
733
while (in_packet_length > 0 &&
734
(pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
706
737
in_packet_length--;
709
std::string *new_query= new std::string(in_packet, in_packet + in_packet_length);
710
// We can not be entirely sure _schema has a value
713
plugin::QueryRewriter::rewriteQuery(*_schema, *new_query);
715
query.reset(new_query);
716
_state.reset(new session::State(in_packet, in_packet_length));
740
/* We must allocate some extra memory for the cached query string */
741
query_length= 0; /* Extra safety: Avoid races */
742
query= (char*) memdup_w_gap((unsigned char*) in_packet, in_packet_length, db.length() + 1);
746
query[in_packet_length]=0;
747
query_length= in_packet_length;
860
889
@return NULL on failure, or pointer to the LEX_STRING object
862
891
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
863
const std::string &str,
864
bool allocate_lex_string)
866
return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
869
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
870
const char* str, uint32_t length,
871
bool allocate_lex_string)
892
const char* str, uint32_t length,
893
bool allocate_lex_string)
873
895
if (allocate_lex_string)
874
if (!(lex_str= (LEX_STRING *)getMemRoot()->allocate(sizeof(LEX_STRING))))
896
if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
876
if (!(lex_str->str= mem_root->strmake_root(str, length)))
898
if (!(lex_str->str= strmake_root(mem_root, str, length)))
878
900
lex_str->length= length;
904
/* routings to adding tables to list of changed in transaction tables */
905
inline static void list_include(CHANGED_TableList** prev,
906
CHANGED_TableList* curr,
907
CHANGED_TableList* new_table)
912
(*prev)->next = curr;
916
/* add table to list of changed in transaction tables */
918
void Session::add_changed_table(Table *table)
920
assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
921
table->cursor->has_transactions());
922
add_changed_table(table->s->table_cache_key.str,
923
(long) table->s->table_cache_key.length);
927
void Session::add_changed_table(const char *key, long key_length)
929
CHANGED_TableList **prev_changed = &transaction.changed_tables;
930
CHANGED_TableList *curr = transaction.changed_tables;
932
for (; curr; prev_changed = &(curr->next), curr = curr->next)
934
int cmp = (long)curr->key_length - (long)key_length;
937
list_include(prev_changed, curr, changed_table_dup(key, key_length));
942
cmp = memcmp(curr->key, key, curr->key_length);
945
list_include(prev_changed, curr, changed_table_dup(key, key_length));
954
*prev_changed = changed_table_dup(key, key_length);
958
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
960
CHANGED_TableList* new_table =
961
(CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
965
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
966
ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
967
killed= KILL_CONNECTION;
971
new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
973
new_table->key_length = key_length;
974
::memcpy(new_table->key, key, key_length);
882
979
int Session::send_explain_fields(select_result *result)
884
981
List<Item> field_list;
917
1014
return (result->send_fields(field_list));
920
void select_result::send_error(drizzled::error_t errcode, const char *err)
922
my_message(errcode, err, MYF(0));
925
1017
/************************************************************************
926
1018
Handling writing to file
927
1019
************************************************************************/
929
void select_to_file::send_error(drizzled::error_t errcode,const char *err)
1021
void select_to_file::send_error(uint32_t errcode,const char *err)
931
1023
my_message(errcode, err, MYF(0));
934
(void) cache->end_io_cache();
935
(void) internal::my_close(file, MYF(0));
936
(void) internal::my_delete(path.file_string().c_str(), MYF(0)); // Delete file on error
1026
(void) end_io_cache(&cache);
1027
(void) my_close(file, MYF(0));
1028
(void) my_delete(path, MYF(0)); // Delete file on error
1014
static int create_file(Session *session,
1015
fs::path &target_path,
1016
file_exchange *exchange,
1017
internal::IO_CACHE *cache)
1103
static File create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1019
fs::path to_file(exchange->file_name);
1022
if (not to_file.has_root_directory())
1106
uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
1108
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1109
option|= MY_REPLACE_DIR; // Force use of db directory
1112
if (!dirname_length(exchange->file_name))
1024
target_path= fs::system_complete(getDataHomeCatalog());
1025
util::string::const_shared_ptr schema(session->schema());
1026
if (schema and not schema->empty())
1028
int count_elements= 0;
1029
for (fs::path::iterator iter= to_file.begin();
1030
iter != to_file.end();
1031
++iter, ++count_elements)
1034
if (count_elements == 1)
1036
target_path /= *schema;
1039
target_path /= to_file;
1114
strcpy(path, drizzle_real_data_home);
1115
if (! session->db.empty())
1116
strncat(path, session->db.c_str(), FN_REFLEN-strlen(drizzle_real_data_home)-1);
1117
(void) fn_format(path, exchange->file_name, path, "", option);
1043
target_path = exchange->file_name;
1046
if (not secure_file_priv.string().empty())
1048
if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1050
/* Write only allowed to dir or subdir specified by secure_file_priv */
1051
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1056
if (!access(target_path.file_string().c_str(), F_OK))
1120
(void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
1122
if (opt_secure_file_priv &&
1123
strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1125
/* Write only allowed to dir or subdir specified by secure_file_priv */
1126
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1130
if (!access(path, F_OK))
1058
1132
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1061
1135
/* Create the file world readable */
1062
if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1136
if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1064
1139
(void) fchmod(file, 0666); // Because of umask()
1065
if (cache->init_io_cache(file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1141
(void) chmod(path, 0666);
1143
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1067
internal::my_close(file, MYF(0));
1068
internal::my_delete(target_path.file_string().c_str(), MYF(0)); // Delete file on error, it was just created
1145
my_close(file, MYF(0));
1146
my_delete(path, MYF(0)); // Delete file on error, it was just created
1269
1350
is_ambiguous_field_sep) ?
1270
1351
field_sep_char : escape_char;
1271
1352
tmp_buff[1]= *pos ? *pos : '0';
1272
if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1273
my_b_write(cache,(unsigned char*) tmp_buff,2))
1353
if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1354
my_b_write(&cache,(unsigned char*) tmp_buff,2))
1278
if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1359
if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)))
1281
else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1362
else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
1284
1365
if (fixed_row_size)
1285
1366
{ // Fill with space
1294
1375
uint32_t length=item->max_length-used_length;
1295
1376
for (; length > sizeof(space) ; length-=sizeof(space))
1297
if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1378
if (my_b_write(&cache,(unsigned char*) space,sizeof(space)))
1300
if (my_b_write(cache,(unsigned char*) space,length))
1381
if (my_b_write(&cache,(unsigned char*) space,length))
1304
1385
if (res && enclosed)
1306
if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
1387
if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1307
1388
exchange->enclosed->length()))
1310
1391
if (--items_left)
1312
if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
1393
if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1313
1394
field_term_length))
1317
if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1398
if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
1318
1399
exchange->line_term->length()))
1480
1562
bool select_max_min_finder_subselect::cmp_decimal()
1482
1564
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1483
type::Decimal cval, *cvalue= cache->val_decimal(&cval);
1484
type::Decimal mval, *mvalue= maxmin->val_decimal(&mval);
1565
my_decimal cval, *cvalue= cache->val_decimal(&cval);
1566
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
1486
1568
return (cache->null_value && !maxmin->null_value) ||
1487
1569
(!cache->null_value && !maxmin->null_value &&
1488
class_decimal_cmp(cvalue, mvalue) > 0) ;
1570
my_decimal_cmp(cvalue, mvalue) > 0) ;
1489
1571
return (maxmin->null_value && !cache->null_value) ||
1490
1572
(!cache->null_value && !maxmin->null_value &&
1491
class_decimal_cmp(cvalue,mvalue) < 0);
1573
my_decimal_cmp(cvalue,mvalue) < 0);
1494
1576
bool select_max_min_finder_subselect::cmp_str()
1591
1663
memset(&status_var, 0, sizeof(status_var));
1595
void Session::set_db(const std::string &new_db)
1666
void Security_context::skip_grants()
1668
/* privileges for the user are unknown everything is allowed */
1672
/****************************************************************************
1673
Handling of open and locked tables states.
1675
This is used when we want to open/lock (and then close) some tables when
1676
we already have a set of tables open and locked. We use these methods for
1677
access to mysql.proc table to find definitions of stored routines.
1678
****************************************************************************/
1680
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
1682
backup->set_open_tables_state(this);
1683
reset_open_tables_state();
1684
backups_available= false;
1688
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
1691
Before we will throw away current open tables state we want
1692
to be sure that it was properly cleaned up.
1694
assert(open_tables == 0 && temporary_tables == 0 &&
1695
derived_tables == 0 &&
1697
set_open_tables_state(backup);
1701
bool Session::set_db(const char *new_db, size_t length)
1597
1703
/* Do not reallocate memory if current chunk is big enough. */
1598
if (new_db.length())
1600
_schema.reset(new std::string(new_db));
1604
_schema.reset(new std::string(""));
1714
Check the killed state of a user thread
1715
@param session user thread
1716
@retval 0 the user thread is active
1717
@retval 1 the user thread has been killed
1719
extern "C" int session_killed(const Session *session)
1721
return(session->killed);
1725
Return the session id of a user session
1726
@param pointer to Session object
1727
@return session's id
1729
extern "C" unsigned long session_get_thread_id(const Session *session)
1731
return (unsigned long) session->getSessionId();
1736
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
1737
const char *str, unsigned int size,
1738
int allocate_lex_string)
1740
return session->make_lex_string(lex_str, str, size,
1741
(bool) allocate_lex_string);
1744
const struct charset_info_st *session_charset(Session *session)
1746
return(session->charset());
1749
char **session_query(Session *session)
1751
return(&session->query);
1754
int session_non_transactional_update(const Session *session)
1756
return(session->transaction.all.modified_non_trans_table);
1759
void session_mark_transaction_to_rollback(Session *session, bool all)
1761
mark_transaction_to_rollback(session, all);
1610
1765
Mark transaction to rollback and mark error as fatal to a sub-statement.
1612
1767
@param session Thread handle
1613
1768
@param all true <=> rollback main transaction.
1615
void Session::markTransactionForRollback(bool all)
1770
void mark_transaction_to_rollback(Session *session, bool all)
1617
is_fatal_sub_stmt_error= true;
1618
transaction_rollback_request= all;
1774
session->is_fatal_sub_stmt_error= true;
1775
session->transaction_rollback_request= all;
1621
void Session::disconnect(enum error_t errcode)
1779
void Session::disconnect(uint32_t errcode, bool should_lock)
1623
1781
/* Allow any plugins to cleanup their session variables */
1624
1782
plugin_sessionvar_cleanup(this);
1626
1784
/* If necessary, log any aborted or unauthorized connections */
1627
if (getKilled() || client->wasAborted())
1629
status_var.aborted_threads++;
1785
if (killed || client->wasAborted())
1786
statistic_increment(aborted_threads, &LOCK_status);
1632
1788
if (client->wasAborted())
1634
if (not getKilled() && variables.log_warnings > 1)
1790
if (! killed && variables.log_warnings > 1)
1636
errmsg_printf(error::WARN, ER(ER_NEW_ABORTING_CONNECTION)
1792
Security_context *sctx= &security_ctx;
1794
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1638
, (_schema->empty() ? "unconnected" : _schema->c_str())
1639
, security_ctx->username().empty() == false ? security_ctx->username().c_str() : "unauthenticated"
1640
, security_ctx->address().c_str()
1796
, (db.empty() ? "unconnected" : db.c_str())
1797
, sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
1641
1799
, (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1645
setKilled(Session::KILL_CONNECTION);
1803
/* Close out our connection to the client */
1805
(void) pthread_mutex_lock(&LOCK_thread_count);
1806
killed= Session::KILL_CONNECTION;
1647
1807
if (client->isConnected())
1649
if (errcode != EE_OK)
1651
1811
/*my_error(errcode, ER(errcode));*/
1652
1812
client->sendError(errcode, ER(errcode));
1654
1814
client->close();
1817
(void) pthread_mutex_unlock(&LOCK_thread_count);
1658
1820
void Session::reset_for_next_command()
1719
1889
passing non-zero value to end_slave via rli->save_temporary_tables
1720
1890
when no temp tables opened, see an invariant below.
1722
temporary_tables= table->getNext();
1892
temporary_tables= table->next;
1723
1893
if (temporary_tables)
1725
table->getNext()->setPrev(NULL);
1894
table->next->prev= NULL;
1896
close_temporary(table);
1732
Close and drop a temporary table
1900
Close and delete a temporary table
1735
1903
This dosn't unlink table from session->temporary
1736
1904
If this is needed, use close_temporary_table()
1739
void Open_tables_state::nukeTable(Table *table)
1907
void Session::close_temporary(Table *table)
1741
plugin::StorageEngine *table_type= table->getShare()->db_type();
1909
plugin::StorageEngine *table_type= table->s->db_type();
1743
1911
table->free_io_cache();
1744
table->delete_table();
1746
identifier::Table identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1747
rm_temporary_table(table_type, identifier);
1749
boost::checked_delete(table->getMutableShare());
1751
boost::checked_delete(table);
1912
table->closefrm(false);
1914
rm_temporary_table(table_type, table->s->path.str);
1916
table->s->free_table_share();
1917
/* This makes me sad, but we're allocating it via malloc */
1754
1921
/** Clear most status variables. */
1755
1922
extern time_t flush_status_time;
1923
extern uint32_t max_used_connections;
1757
1925
void Session::refresh_status()
1927
pthread_mutex_lock(&LOCK_status);
1929
/* Add thread's status variabes to global status */
1930
add_to_status(&global_status_var, &status_var);
1759
1932
/* Reset thread's status variables */
1760
1933
memset(&status_var, 0, sizeof(status_var));
1935
/* Reset some global variables */
1936
reset_status_vars();
1938
/* Reset the counters of all key caches (default and named). */
1939
reset_key_cache_counters();
1762
1940
flush_status_time= time((time_t*) 0);
1763
current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1764
current_global_counters.connections= 0;
1941
max_used_connections= 1; /* We set it to one, because we know we exist */
1942
pthread_mutex_unlock(&LOCK_status);
1767
1945
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1769
return getVariable(std::string(name.str, name.length), create_if_not_exists);
1772
user_var_entry *Session::getVariable(const std::string &name, bool create_if_not_exists)
1777
UserVars::iterator iter= user_vars.find(name);
1778
if (iter != user_vars.end())
1779
return (*iter).second;
1781
if (not create_if_not_exists)
1784
1947
user_var_entry *entry= NULL;
1785
entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1790
std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1792
if (not returnable.second)
1949
entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
1951
if ((entry == NULL) && create_if_not_exists)
1794
boost::checked_delete(entry);
1953
if (!hash_inited(&user_vars))
1955
entry= new (nothrow) user_var_entry(name.str, query_id);
1960
if (my_hash_insert(&user_vars, (unsigned char*) entry))
1963
free((char*) entry);
1800
void Session::setVariable(const std::string &name, const std::string &value)
1802
user_var_entry *updateable_var= getVariable(name.c_str(), true);
1805
updateable_var->update_hash(false,
1806
(void*)value.c_str(),
1807
static_cast<uint32_t>(value.length()), STRING_RESULT,
1809
DERIVATION_IMPLICIT, false);
1813
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
1815
for (Table *table= temporary_tables ; table ; table= table->getNext())
1817
if (table->query_id == getQueryId())
1972
void Session::mark_temp_tables_as_free_for_reuse()
1974
for (Table *table= temporary_tables ; table ; table= table->next)
1976
if (table->query_id == query_id)
1819
1978
table->query_id= 0;
1820
1979
table->cursor->ha_reset();
1916
2101
if (open_tables_from_list(&tables, &counter))
1919
if (not lock_tables(tables, counter, &need_reopen))
2104
if (!lock_tables(tables, counter, &need_reopen))
1922
if (not need_reopen)
1925
2108
close_tables_for_reopen(&tables);
1928
if ((handle_derived(lex, &derived_prepare) || (handle_derived(lex, &derived_filling))))
1935
@note "best_effort" is used in cases were if a failure occurred on this
1936
operation it would not be surprising because we are only removing because there
1937
might be an issue (lame engines).
1940
bool Open_tables_state::rm_temporary_table(const identifier::Table &identifier, bool best_effort)
1942
if (not plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
1944
if (not best_effort)
1947
identifier.getSQLPath(path);
1948
errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"),
1949
path.c_str(), errno);
1958
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const identifier::Table &identifier)
1960
drizzled::error_t error;
2110
if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
2111
(fill_derived_tables() &&
2112
mysql_handle_derived(lex, &mysql_derived_filling))))
2118
bool Session::openTables(TableList *tables, uint32_t flags)
2121
bool ret= fill_derived_tables();
2122
assert(ret == false);
2123
if (open_tables_from_list(&tables, &counter, flags) ||
2124
mysql_handle_derived(lex, &mysql_derived_prepare))
2129
bool Session::rm_temporary_table(plugin::StorageEngine *base, char *path)
1963
if (not plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier, error))
1966
identifier.getSQLPath(path);
1967
errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"),
1968
path.c_str(), error);
1977
@note this will be removed, I am looking through Hudson to see if it is finding
1978
any tables that are missed during cleanup.
1980
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
1984
if (not temporary_tables)
1987
cerr << "Begin Run: " << foo << "\n";
1988
for (table= temporary_tables; table; table= table->getNext())
1990
bool have_proto= false;
1992
message::Table *proto= table->getShare()->getTableMessage();
1993
if (table->getShare()->getTableMessage())
1996
const char *answer= have_proto ? "true" : "false";
2000
cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2001
cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2005
cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2010
table::Singular *Session::getInstanceTable()
2012
temporary_shares.push_back(new table::Singular()); // This will not go into the tableshare cache, so no key is used.
2014
table::Singular *tmp_share= temporary_shares.back();
2023
Create a reduced Table object with properly set up Field list from a
2024
list of field definitions.
2026
The created table doesn't have a table Cursor associated with
2027
it, has no keys, no group/distinct, no copy_funcs array.
2028
The sole purpose of this Table object is to use the power of Field
2029
class to read/write data to/from table->getInsertRecord(). Then one can store
2030
the record in any container (RB tree, hash, etc).
2031
The table is created in Session mem_root, so are the table's fields.
2032
Consequently, if you don't BLOB fields, you don't need to free it.
2034
@param session connection handle
2035
@param field_list list of column definitions
2038
0 if out of memory, Table object in case of success
2040
table::Singular *Session::getInstanceTable(List<CreateField> &field_list)
2042
temporary_shares.push_back(new table::Singular(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2044
table::Singular *tmp_share= temporary_shares.back();
2053
static const std::string NONE= "NONE";
2054
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2055
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2057
const std::string &type(drizzled::Session::global_read_lock_t type)
2063
case Session::GOT_GLOBAL_READ_LOCK:
2064
return GOT_GLOBAL_READ_LOCK;
2065
case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2066
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2070
size_t max_string_length(drizzled::Session::global_read_lock_t)
2072
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2075
} /* namespace display */
2077
} /* namespace drizzled */
2135
if (delete_table_proto_file(path))
2138
if (base->doDropTable(*this, path))
2141
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),