21
21
* @file Implementation of the Session class and API
25
#include "drizzled/session.h"
26
#include "drizzled/session/cache.h"
24
#include <drizzled/server_includes.h>
25
#include <drizzled/session.h>
27
26
#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"
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>
40
40
#include "drizzled/plugin/scheduler.h"
41
41
#include "drizzled/plugin/authentication.h"
42
#include "drizzled/plugin/logging.h"
43
#include "drizzled/plugin/transactional_storage_engine.h"
44
#include "drizzled/plugin/query_rewrite.h"
45
42
#include "drizzled/probes.h"
46
#include "drizzled/table_proto.h"
47
#include "drizzled/db.h"
48
#include "drizzled/pthread_globals.h"
49
#include "drizzled/transaction_services.h"
50
#include "drizzled/drizzled.h"
52
#include "drizzled/table/instance.h"
54
#include "plugin/myisam/myisam.h"
55
#include "drizzled/internal/iocache.h"
56
#include "drizzled/internal/thread_var.h"
57
#include "drizzled/plugin/event_observer.h"
59
#include "drizzled/util/functors.h"
61
#include "drizzled/display.h"
64
44
#include <algorithm>
66
#include <boost/filesystem.hpp>
68
#include "drizzled/util/backtrace.h"
70
46
using namespace std;
47
using namespace drizzled;
72
namespace fs=boost::filesystem;
51
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool );
52
void free_user_var(user_var_entry *entry);
77
56
The following is used to initialise Table_ident with a internal
81
60
char empty_c_string[1]= {0}; /* used for not defined db */
83
62
const char * const Session::DEFAULT_WHERE= "field list";
63
extern pthread_key_t THR_Session;
64
extern pthread_key_t THR_Mem_root;
65
extern uint32_t max_used_connections;
66
extern drizzled::atomic<uint32_t> connection_count;
68
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
70
template class List<Key>;
71
template class List_iterator<Key>;
72
template class List<Key_part_spec>;
73
template class List_iterator<Key_part_spec>;
74
template class List<AlterDrop>;
75
template class List_iterator<AlterDrop>;
76
template class List<AlterColumn>;
77
template class List_iterator<AlterColumn>;
80
/****************************************************************************
82
****************************************************************************/
83
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool )
85
*length= entry->name.length;
86
return (unsigned char*) entry->name.str;
89
void free_user_var(user_var_entry *entry)
85
94
bool Key_part_spec::operator==(const Key_part_spec& other) const
87
96
return length == other.length &&
88
97
field_name.length == other.field_name.length &&
89
!my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
98
!strcmp(field_name.str, other.field_name.str);
92
Open_tables_state::Open_tables_state(uint64_t version_arg) :
101
Open_tables_state::Open_tables_state(ulong version_arg)
102
:version(version_arg), backups_available(false)
95
open_tables= temporary_tables= derived_tables= NULL;
96
extra_lock= lock= NULL;
104
reset_open_tables_state();
100
108
The following functions form part of the C plugin API
102
int mysql_tmpfile(const char *prefix)
110
extern "C" int mysql_tmpfile(const char *prefix)
104
112
char filename[FN_REFLEN];
105
int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
113
File fd = create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
107
115
unlink(filename);
124
133
@see Session::set_proc_info
126
void set_session_proc_info(Session *session, const char *info)
136
set_session_proc_info(Session *session, const char *info)
128
138
session->set_proc_info(info);
131
142
const char *get_session_proc_info(Session *session)
133
144
return session->get_proc_info();
136
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
138
return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
141
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
144
return &ha_data[monitored->getId()].resource_context[index];
148
void **session_ha_data(const Session *session, const plugin::StorageEngine *engine)
150
return (void **) &session->ha_data[engine->slot].ha_ptr;
147
154
int64_t session_test_options(const Session *session, int64_t test_options)
149
156
return session->options & test_options;
152
160
int session_sql_command(const Session *session)
154
162
return (int) session->lex->sql_command;
157
enum_tx_isolation session_tx_isolation(const Session *session)
159
return (enum_tx_isolation)session->variables.tx_isolation;
162
Session::Session(plugin::Client *client_arg) :
166
int session_tx_isolation(const Session *session)
168
return (int) session->variables.tx_isolation;
172
void session_inc_row_count(Session *session)
174
session->row_count++;
177
Session::Session(plugin::Client *client_arg)
163
179
Open_tables_state(refresh_version),
164
180
mem_root(&main_mem_root),
167
query(new std::string),
168
_schema(new std::string("")),
170
183
client(client_arg),
172
185
scheduler_arg(NULL),
173
186
lock_id(&main_lock_id),
175
ha_data(plugin::num_trx_monitored_objects),
176
concurrent_execute_allowed(true),
177
188
arg_of_last_insert_id_function(false),
178
189
first_successful_insert_id_in_prev_stmt(0),
179
190
first_successful_insert_id_in_cur_stmt(0),
180
191
limit_found_rows(0),
181
_global_read_lock(NONE),
183
193
some_tables_deleted(false),
184
194
no_errors(false),
259
269
memset(&status_var, 0, sizeof(status_var));
261
271
/* Initialize sub structures */
262
memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
272
init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
273
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
274
(hash_get_key) get_var_key,
275
(hash_free_key) free_user_var, 0);
264
277
substitute_null_with_insert_id = false;
265
lock_info.init(); /* safety: will be reset after start */
278
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
266
279
thr_lock_owner_init(&main_lock_id, &lock_info);
268
281
m_internal_handler= NULL;
270
plugin::EventObserver::registerSessionEvents(*this);
273
284
void Session::free_items()
276
/* This works because items are allocated with memory::sql_alloc() */
287
/* This works because items are allocated with sql_alloc() */
277
288
for (; free_list; free_list= next)
279
290
next= free_list->next;
302
313
return false; // 'false', as per coding style
305
void Session::setAbort(bool arg)
307
mysys_var->abort= arg;
310
void Session::lockOnSys()
316
boost_unique_lock_t scopedLock(mysys_var->mutex);
317
if (mysys_var->current_cond)
319
mysys_var->current_mutex->lock();
320
mysys_var->current_cond->notify_all();
321
mysys_var->current_mutex->unlock();
325
316
void Session::pop_internal_handler()
327
318
assert(m_internal_handler != NULL);
328
319
m_internal_handler= NULL;
331
void Session::get_xid(DRIZZLE_XID *xid)
333
*xid = *(DRIZZLE_XID *) &transaction.xid_state.xid;
322
#if defined(__cplusplus)
326
void *session_alloc(Session *session, unsigned int size)
328
return session->alloc(size);
331
void *session_calloc(Session *session, unsigned int size)
333
return session->calloc(size);
336
char *session_strdup(Session *session, const char *str)
338
return session->strdup(str);
341
char *session_strmake(Session *session, const char *str, unsigned int size)
343
return session->strmake(str, size);
346
void *session_memdup(Session *session, const void* str, unsigned int size)
348
return session->memdup(str, size);
351
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
353
*xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
356
#if defined(__cplusplus)
336
360
/* Do operations that may take a long time */
350
TransactionServices &transaction_services= TransactionServices::singleton();
351
transaction_services.rollbackTransaction(this, true);
352
375
xid_cache_delete(&transaction.xid_state);
355
for (UserVars::iterator iter= user_vars.begin();
356
iter != user_vars.end();
359
user_var_entry *entry= (*iter).second;
377
hash_free(&user_vars);
365
378
close_temporary_tables();
367
380
if (global_read_lock)
369
unlockGlobalReadLock();
381
unlock_global_read_lock(this);
372
383
cleanup_done= true;
375
386
Session::~Session()
388
Session_CHECK_SENTRY(this);
389
add_to_status(&global_status_var, &status_var);
379
391
if (client->isConnected())
381
393
if (global_system_variables.log_warnings)
382
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),internal::my_progname,
394
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),my_progname,
384
(getSecurityContext().getUser().c_str() ?
385
getSecurityContext().getUser().c_str() : ""));
396
(security_ctx.user.c_str() ?
397
security_ctx.user.c_str() : ""));
386
398
disconnect(0, false);
396
408
plugin::StorageEngine::closeConnection(this);
397
409
plugin_sessionvar_cleanup(this);
399
warn_root.free_root(MYF(0));
416
free_root(&warn_root,MYF(0));
417
free_root(&transaction.mem_root,MYF(0));
400
418
mysys_var=0; // Safety (shouldn't be needed)
401
419
dbug_sentry= Session_SENTRY_GONE;
403
main_mem_root.free_root(MYF(0));
404
currentMemRoot().release();
405
currentSession().release();
407
plugin::Logging::postEndDo(this);
408
plugin::EventObserver::deregisterSessionEvents(*this);
410
for (PropertyMap::iterator iter= life_properties.begin(); iter != life_properties.end(); iter++)
412
delete (*iter).second;
414
life_properties.clear();
417
void Session::setClient(plugin::Client *client_arg)
420
client->setSession(this);
423
void Session::awake(Session::killed_state_t state_to_set)
425
if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
430
setKilled(state_to_set);
431
scheduler->killSession(this);
421
free_root(&main_mem_root, MYF(0));
422
pthread_setspecific(THR_Session, 0);
425
/* Ensure that no one is using Session */
426
pthread_mutex_unlock(&LOCK_delete);
427
pthread_mutex_destroy(&LOCK_delete);
431
Add all status variables to another status variable array
435
to_var add to this array
436
from_var from this array
439
This function assumes that all variables are long/ulong.
440
If this assumption will change, then we have to explictely add
441
the other variables after the while loop
443
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
445
ulong *end= (ulong*) ((unsigned char*) to_var +
446
offsetof(STATUS_VAR, last_system_status_var) +
448
ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
455
Add the difference between two status variable arrays to another one.
459
to_var add to this array
460
from_var from this array
461
dec_var minus this array
464
This function assumes that all variables are long/ulong.
466
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
469
ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
470
last_system_status_var) +
472
ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
475
*(to++)+= *(from++) - *(dec++);
478
void Session::awake(Session::killed_state state_to_set)
480
Session_CHECK_SENTRY(this);
481
safe_mutex_assert_owner(&LOCK_delete);
483
killed= state_to_set;
433
484
if (state_to_set != Session::KILL_QUERY)
486
scheduler->killSession(this);
435
487
DRIZZLE_CONNECTION_DONE(thread_id);
440
boost_unique_lock_t scopedLock(mysys_var->mutex);
491
pthread_mutex_lock(&mysys_var->mutex);
443
493
This broadcast could be up in the air if the victim thread
444
494
exits the cond in the time between read and broadcast, but that is
445
495
ok since all we want to do is to make the victim thread get out
548
599
prepareForQueries();
550
while (not client->haveError() && getKilled() != KILL_CONNECTION)
601
while (! client->haveError() && killed != KILL_CONNECTION)
552
if (not executeStatement())
603
if (! executeStatement())
556
607
disconnect(0, true);
559
bool Session::schedule(Session::shared_ptr &arg)
610
bool Session::schedule()
561
arg->scheduler= plugin::Scheduler::getScheduler();
562
assert(arg->scheduler);
564
connection_count.increment();
566
if (connection_count > current_global_counters.max_used_connections)
568
current_global_counters.max_used_connections= connection_count;
571
current_global_counters.connections++;
572
arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
574
session::Cache::singleton().insert(arg);
576
if (unlikely(plugin::EventObserver::connectSession(*arg)))
578
// We should do something about an error...
581
if (plugin::Scheduler::getScheduler()->addSession(arg))
583
DRIZZLE_CONNECTION_START(arg->getSessionId());
612
scheduler= plugin::Scheduler::getScheduler();
617
if (connection_count > max_used_connections)
618
max_used_connections= connection_count;
620
thread_id= variables.pseudo_thread_id= global_thread_id++;
622
pthread_mutex_lock(&LOCK_thread_count);
623
session_list.push_back(this);
624
pthread_mutex_unlock(&LOCK_thread_count);
626
if (scheduler->addSession(this))
628
DRIZZLE_CONNECTION_START(thread_id);
584
629
char error_message_buff[DRIZZLE_ERRMSG_SIZE];
586
arg->setKilled(Session::KILL_CONNECTION);
631
killed= Session::KILL_CONNECTION;
588
arg->status_var.aborted_connects++;
633
statistic_increment(aborted_connects, &LOCK_status);
590
635
/* Can't use my_error() since store_globals has not been called. */
591
636
/* TODO replace will better error message */
592
637
snprintf(error_message_buff, sizeof(error_message_buff),
593
638
ER(ER_CANT_CREATE_THREAD), 1);
594
arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
639
client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
604
Is this session viewable by the current user?
606
bool Session::isViewable() const
608
return plugin::Authorization::isAuthorized(current_session->getSecurityContext(),
614
const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
616
const char* old_msg = get_proc_info();
617
safe_mutex_assert_owner(mutex);
618
mysys_var->current_mutex = &mutex;
619
mysys_var->current_cond = &cond;
620
this->set_proc_info(msg);
624
void Session::exit_cond(const char* old_msg)
627
Putting the mutex unlock in exit_cond() ensures that
628
mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
629
locked (if that would not be the case, you'll get a deadlock if someone
630
does a Session::awake() on you).
632
mysys_var->current_mutex->unlock();
633
boost_unique_lock_t scopedLock(mysys_var->mutex);
634
mysys_var->current_mutex = 0;
635
mysys_var->current_cond = 0;
636
this->set_proc_info(old_msg);
639
646
bool Session::authenticate()
642
649
if (client->authenticate())
645
status_var.aborted_connects++;
652
statistic_increment(aborted_connects, &LOCK_status);
650
bool Session::checkUser(const std::string &passwd_str,
651
const std::string &in_db)
656
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
653
bool is_authenticated=
654
plugin::Authentication::isAuthenticated(getSecurityContext(),
658
LEX_STRING db_str= { (char *) in_db, in_db ? strlen(in_db) : 0 };
659
bool is_authenticated;
662
Clear session->db as it points to something, that will be freed when
663
connection is closed. We don't want to accidentally free a wrong
664
pointer if connect failed. Also in case of 'CHANGE USER' failure,
665
current database will be switched to 'no database selected'.
669
if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
671
my_error(ER_HANDSHAKE_ERROR, MYF(0), security_ctx.ip.c_str());
675
is_authenticated= plugin::Authentication::isAuthenticated(this, passwd);
657
677
if (is_authenticated != true)
659
status_var.access_denied++;
660
/* isAuthenticated has pushed the error message */
679
my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
680
security_ctx.user.c_str(),
681
security_ctx.ip.c_str(),
682
passwd_len ? ER(ER_YES) : ER(ER_NO));
687
security_ctx.skip_grants();
664
689
/* Change database if necessary */
665
if (not in_db.empty())
690
if (in_db && in_db[0])
667
SchemaIdentifier identifier(in_db);
668
if (mysql_change_db(this, identifier))
692
if (mysql_change_db(this, &db_str, false))
670
694
/* mysql_change_db() has pushed the error message. */
675
password= not passwd_str.empty();
699
password= test(passwd_len); // remember for error messages
677
701
/* Ready to handle queries */
884
890
@return NULL on failure, or pointer to the LEX_STRING object
886
892
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
887
const std::string &str,
888
bool allocate_lex_string)
890
return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
893
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
894
const char* str, uint32_t length,
895
bool allocate_lex_string)
893
const char* str, uint32_t length,
894
bool allocate_lex_string)
897
896
if (allocate_lex_string)
898
897
if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
900
if (!(lex_str->str= mem_root->strmake_root(str, length)))
899
if (!(lex_str->str= strmake_root(mem_root, str, length)))
902
901
lex_str->length= length;
905
/* routings to adding tables to list of changed in transaction tables */
906
inline static void list_include(CHANGED_TableList** prev,
907
CHANGED_TableList* curr,
908
CHANGED_TableList* new_table)
913
(*prev)->next = curr;
917
/* add table to list of changed in transaction tables */
919
void Session::add_changed_table(Table *table)
921
assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
922
table->file->has_transactions());
923
add_changed_table(table->s->table_cache_key.str,
924
(long) table->s->table_cache_key.length);
928
void Session::add_changed_table(const char *key, long key_length)
930
CHANGED_TableList **prev_changed = &transaction.changed_tables;
931
CHANGED_TableList *curr = transaction.changed_tables;
933
for (; curr; prev_changed = &(curr->next), curr = curr->next)
935
int cmp = (long)curr->key_length - (long)key_length;
938
list_include(prev_changed, curr, changed_table_dup(key, key_length));
943
cmp = memcmp(curr->key, key, curr->key_length);
946
list_include(prev_changed, curr, changed_table_dup(key, key_length));
955
*prev_changed = changed_table_dup(key, key_length);
959
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
961
CHANGED_TableList* new_table =
962
(CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
966
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
967
ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
968
killed= KILL_CONNECTION;
972
new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
974
new_table->key_length = key_length;
975
::memcpy(new_table->key, key, key_length);
906
980
int Session::send_explain_fields(select_result *result)
908
982
List<Item> field_list;
1038
static int create_file(Session *session,
1039
fs::path &target_path,
1040
file_exchange *exchange,
1041
internal::IO_CACHE *cache)
1104
static File create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1043
fs::path to_file(exchange->file_name);
1046
if (not to_file.has_root_directory())
1107
uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
1109
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1110
option|= MY_REPLACE_DIR; // Force use of db directory
1113
if (!dirname_length(exchange->file_name))
1048
target_path= fs::system_complete(getDataHomeCatalog());
1049
util::string::const_shared_ptr schema(session->schema());
1050
if (schema and not schema->empty())
1052
int count_elements= 0;
1053
for (fs::path::iterator iter= to_file.begin();
1054
iter != to_file.end();
1055
++iter, ++count_elements)
1058
if (count_elements == 1)
1060
target_path /= *schema;
1063
target_path /= to_file;
1115
strcpy(path, drizzle_real_data_home);
1117
strncat(path, session->db, FN_REFLEN-strlen(drizzle_real_data_home)-1);
1118
(void) fn_format(path, exchange->file_name, path, "", option);
1067
target_path = exchange->file_name;
1070
if (not secure_file_priv.string().empty())
1072
if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1074
/* Write only allowed to dir or subdir specified by secure_file_priv */
1075
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1080
if (!access(target_path.file_string().c_str(), F_OK))
1121
(void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
1123
if (opt_secure_file_priv &&
1124
strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1126
/* Write only allowed to dir or subdir specified by secure_file_priv */
1127
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1131
if (!access(path, F_OK))
1082
1133
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1085
1136
/* Create the file world readable */
1086
if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1137
if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1088
1140
(void) fchmod(file, 0666); // Because of umask()
1089
if (cache->init_io_cache(file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1142
(void) chmod(path, 0666);
1144
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1091
internal::my_close(file, MYF(0));
1092
internal::my_delete(target_path.file_string().c_str(), MYF(0)); // Delete file on error, it was just created
1146
my_close(file, MYF(0));
1147
my_delete(path, MYF(0)); // Delete file on error, it was just created
1188
1246
res=item->str_result(&tmp);
1189
1247
if (res && enclosed)
1191
if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
1192
exchange->enclosed->length()))
1249
if (my_b_write(&cache,(unsigned char*) exchange->enclosed->ptr(),
1250
exchange->enclosed->length()))
1197
1255
if (!fixed_row_size)
1199
if (escape_char != -1) // Use \N syntax
1201
null_buff[0]=escape_char;
1203
if (my_b_write(cache,(unsigned char*) null_buff,2))
1206
else if (my_b_write(cache,(unsigned char*) "NULL",4))
1257
if (escape_char != -1) // Use \N syntax
1259
null_buff[0]=escape_char;
1261
if (my_b_write(&cache,(unsigned char*) null_buff,2))
1264
else if (my_b_write(&cache,(unsigned char*) "NULL",4))
1211
used_length=0; // Fill with space
1269
used_length=0; // Fill with space
1216
1274
if (fixed_row_size)
1217
used_length= min(res->length(), static_cast<size_t>(item->max_length));
1275
used_length= min(res->length(),item->max_length);
1219
1277
used_length= res->length();
1221
1279
if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
1224
1282
char *pos, *start, *end;
1225
1283
const CHARSET_INFO * const res_charset= res->charset();
1226
1284
const CHARSET_INFO * const character_set_client= default_charset_info;
1228
1286
bool check_second_byte= (res_charset == &my_charset_bin) &&
1229
character_set_client->
1230
escape_with_backslash_is_dangerous;
1287
character_set_client->
1288
escape_with_backslash_is_dangerous;
1231
1289
assert(character_set_client->mbmaxlen == 2 ||
1232
1290
!character_set_client->escape_with_backslash_is_dangerous);
1233
for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1237
if (use_mb(res_charset))
1240
if ((l=my_ismbchar(res_charset, pos, end)))
1291
for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1295
if (use_mb(res_charset))
1298
if ((l=my_ismbchar(res_charset, pos, end)))
1248
1306
Special case when dumping BINARY/VARBINARY/BLOB values
1276
1334
assert before the loop makes that sure.
1279
if ((needs_escaping(*pos, enclosed) ||
1337
if ((NEED_ESCAPING(*pos) ||
1280
1338
(check_second_byte &&
1281
1339
my_mbcharlen(character_set_client, (unsigned char) *pos) == 2 &&
1282
1340
pos + 1 < end &&
1283
needs_escaping(pos[1], enclosed))) &&
1341
NEED_ESCAPING(pos[1]))) &&
1285
Don't escape field_term_char by doubling - doubling is only
1286
valid for ENCLOSED BY characters:
1343
Don't escape field_term_char by doubling - doubling is only
1344
valid for ENCLOSED BY characters:
1288
1346
(enclosed || !is_ambiguous_field_term ||
1289
1347
(int) (unsigned char) *pos != field_term_char))
1292
1350
tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
1293
1351
is_ambiguous_field_sep) ?
1294
field_sep_char : escape_char;
1295
tmp_buff[1]= *pos ? *pos : '0';
1296
if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1297
my_b_write(cache,(unsigned char*) tmp_buff,2))
1302
if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1352
field_sep_char : escape_char;
1353
tmp_buff[1]= *pos ? *pos : '0';
1354
if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1355
my_b_write(&cache,(unsigned char*) tmp_buff,2))
1360
if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)))
1305
else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1363
else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
1308
1366
if (fixed_row_size)
1309
1367
{ // Fill with space
1310
1368
if (item->max_length > used_length)
1312
/* QQ: Fix by adding a my_b_fill() function */
1316
memset(space, ' ', sizeof(space));
1318
uint32_t length=item->max_length-used_length;
1319
for (; length > sizeof(space) ; length-=sizeof(space))
1321
if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1324
if (my_b_write(cache,(unsigned char*) space,length))
1370
/* QQ: Fix by adding a my_b_fill() function */
1374
memset(space, ' ', sizeof(space));
1376
uint32_t length=item->max_length-used_length;
1377
for (; length > sizeof(space) ; length-=sizeof(space))
1379
if (my_b_write(&cache,(unsigned char*) space,sizeof(space)))
1382
if (my_b_write(&cache,(unsigned char*) space,length))
1328
1386
if (res && enclosed)
1330
if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
1388
if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1331
1389
exchange->enclosed->length()))
1334
1392
if (--items_left)
1336
if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
1394
if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1337
1395
field_term_length))
1341
if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1342
exchange->line_term->length()))
1399
if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
1400
exchange->line_term->length()))
1615
1664
memset(&status_var, 0, sizeof(status_var));
1619
void Session::set_db(const std::string &new_db)
1667
void Security_context::skip_grants()
1669
/* privileges for the user are unknown everything is allowed */
1673
/****************************************************************************
1674
Handling of open and locked tables states.
1676
This is used when we want to open/lock (and then close) some tables when
1677
we already have a set of tables open and locked. We use these methods for
1678
access to mysql.proc table to find definitions of stored routines.
1679
****************************************************************************/
1681
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
1683
backup->set_open_tables_state(this);
1684
reset_open_tables_state();
1685
backups_available= false;
1689
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
1692
Before we will throw away current open tables state we want
1693
to be sure that it was properly cleaned up.
1695
assert(open_tables == 0 && temporary_tables == 0 &&
1696
derived_tables == 0 &&
1698
set_open_tables_state(backup);
1702
bool Session::set_db(const char *new_db, size_t new_db_len)
1621
1704
/* Do not reallocate memory if current chunk is big enough. */
1622
if (new_db.length())
1624
_schema.reset(new std::string(new_db));
1705
if (db && new_db && db_length >= new_db_len)
1706
memcpy(db, new_db, new_db_len+1);
1628
_schema.reset(new std::string(""));
1713
db= (char *)malloc(new_db_len + 1);
1716
memcpy(db, new_db, new_db_len);
1723
db_length= db ? new_db_len : 0;
1724
return new_db && !db;
1729
Check the killed state of a user thread
1730
@param session user thread
1731
@retval 0 the user thread is active
1732
@retval 1 the user thread has been killed
1734
extern "C" int session_killed(const Session *session)
1736
return(session->killed);
1740
Return the session id of a user session
1741
@param pointer to Session object
1742
@return session's id
1744
extern "C" unsigned long session_get_thread_id(const Session *session)
1746
return (unsigned long) session->getSessionId();
1751
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
1752
const char *str, unsigned int size,
1753
int allocate_lex_string)
1755
return session->make_lex_string(lex_str, str, size,
1756
(bool) allocate_lex_string);
1759
const struct charset_info_st *session_charset(Session *session)
1761
return(session->charset());
1764
char **session_query(Session *session)
1766
return(&session->query);
1769
int session_non_transactional_update(const Session *session)
1771
return(session->transaction.all.modified_non_trans_table);
1774
void session_mark_transaction_to_rollback(Session *session, bool all)
1776
mark_transaction_to_rollback(session, all);
1634
1780
Mark transaction to rollback and mark error as fatal to a sub-statement.
1651
1797
plugin_sessionvar_cleanup(this);
1653
1799
/* If necessary, log any aborted or unauthorized connections */
1654
if (getKilled() || client->wasAborted())
1656
status_var.aborted_threads++;
1800
if (killed || client->wasAborted())
1801
statistic_increment(aborted_threads, &LOCK_status);
1659
1803
if (client->wasAborted())
1661
if (not getKilled() && variables.log_warnings > 1)
1805
if (! killed && variables.log_warnings > 1)
1663
SecurityContext *sctx= &security_ctx;
1807
Security_context *sctx= &security_ctx;
1665
1809
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1667
, (_schema->empty() ? "unconnected" : _schema->c_str())
1668
, sctx->getUser().empty() == false ? sctx->getUser().c_str() : "unauthenticated"
1669
, sctx->getIp().c_str()
1811
, (db ? db : "unconnected")
1812
, sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
1670
1814
, (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1674
1818
/* Close out our connection to the client */
1675
1819
if (should_lock)
1676
session::Cache::singleton().mutex().lock();
1678
setKilled(Session::KILL_CONNECTION);
1820
(void) pthread_mutex_lock(&LOCK_thread_count);
1821
killed= Session::KILL_CONNECTION;
1680
1822
if (client->isConnected())
1757
1905
passing non-zero value to end_slave via rli->save_temporary_tables
1758
1906
when no temp tables opened, see an invariant below.
1760
temporary_tables= table->getNext();
1908
temporary_tables= table->next;
1761
1909
if (temporary_tables)
1763
table->getNext()->setPrev(NULL);
1910
table->next->prev= NULL;
1912
close_temporary(table, free_share, delete_table);
1770
Close and drop a temporary table
1916
Close and delete a temporary table
1773
1919
This dosn't unlink table from session->temporary
1774
1920
If this is needed, use close_temporary_table()
1777
void Open_tables_state::nukeTable(Table *table)
1923
void Session::close_temporary(Table *table, bool free_share, bool delete_table)
1779
plugin::StorageEngine *table_type= table->getShare()->db_type();
1925
plugin::StorageEngine *table_type= table->s->db_type();
1781
1927
table->free_io_cache();
1782
table->delete_table();
1784
TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1785
rm_temporary_table(table_type, identifier);
1787
delete table->getMutableShare();
1789
/* This makes me sad, but we're allocating it via malloc */
1928
table->closefrm(false);
1931
rm_temporary_table(table_type, table->s->path.str);
1935
table->s->free_table_share();
1936
/* This makes me sad, but we're allocating it via malloc */
1793
1941
/** Clear most status variables. */
1794
1942
extern time_t flush_status_time;
1943
extern uint32_t max_used_connections;
1796
1945
void Session::refresh_status()
1947
pthread_mutex_lock(&LOCK_status);
1949
/* Add thread's status variabes to global status */
1950
add_to_status(&global_status_var, &status_var);
1798
1952
/* Reset thread's status variables */
1799
1953
memset(&status_var, 0, sizeof(status_var));
1955
/* Reset some global variables */
1956
reset_status_vars();
1958
/* Reset the counters of all key caches (default and named). */
1959
reset_key_cache_counters();
1801
1960
flush_status_time= time((time_t*) 0);
1802
current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1803
current_global_counters.connections= 0;
1961
max_used_connections= 1; /* We set it to one, because we know we exist */
1962
pthread_mutex_unlock(&LOCK_status);
1965
#define extra_size sizeof(double)
1806
1967
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1808
return getVariable(std::string(name.str, name.length), create_if_not_exists);
1811
user_var_entry *Session::getVariable(const std::string &name, bool create_if_not_exists)
1813
UserVarsRange ppp= user_vars.equal_range(name);
1815
for (UserVars::iterator iter= ppp.first;
1816
iter != ppp.second; ++iter)
1818
return (*iter).second;
1821
if (not create_if_not_exists)
1824
1969
user_var_entry *entry= NULL;
1825
entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1830
std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1832
if (not returnable.second)
1971
entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
1973
if ((entry == NULL) && create_if_not_exists)
1975
if (!hash_inited(&user_vars))
1977
entry= new (nothrow) user_var_entry(name.str, query_id);
1982
if (my_hash_insert(&user_vars, (unsigned char*) entry))
1985
free((char*) entry);
1840
void Session::setVariable(const std::string &name, const std::string &value)
1842
user_var_entry *updateable_var= getVariable(name.c_str(), true);
1844
updateable_var->update_hash(false,
1845
(void*)value.c_str(),
1846
static_cast<uint32_t>(value.length()), STRING_RESULT,
1848
DERIVATION_IMPLICIT, false);
1851
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
1853
for (Table *table= temporary_tables ; table ; table= table->getNext())
1994
void Session::mark_temp_tables_as_free_for_reuse()
1996
for (Table *table= temporary_tables ; table ; table= table->next)
1855
if (table->query_id == getQueryId())
1998
if (table->query_id == query_id)
1857
2000
table->query_id= 0;
1858
table->cursor->ha_reset();
2001
table->file->ha_reset();
1863
2006
void Session::mark_used_tables_as_free_for_reuse(Table *table)
1865
for (; table ; table= table->getNext())
2008
for (; table ; table= table->next)
1867
if (table->query_id == getQueryId())
2010
if (table->query_id == query_id)
1869
2012
table->query_id= 0;
1870
table->cursor->ha_reset();
2013
table->file->ha_reset();
1954
2123
if (open_tables_from_list(&tables, &counter))
1957
if (not lock_tables(tables, counter, &need_reopen))
2126
if (!lock_tables(tables, counter, &need_reopen))
1959
if (not need_reopen)
1961
2130
close_tables_for_reopen(&tables);
1963
2132
if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
2133
(fill_derived_tables() &&
1965
2134
mysql_handle_derived(lex, &mysql_derived_filling))))
1972
@note "best_effort" is used in cases were if a failure occurred on this
1973
operation it would not be surprising because we are only removing because there
1974
might be an issue (lame engines).
1977
bool Open_tables_state::rm_temporary_table(const TableIdentifier &identifier, bool best_effort)
2140
bool Session::openTables(TableList *tables, uint32_t flags)
1979
if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
1981
if (not best_effort)
1984
identifier.getSQLPath(path);
1985
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
1986
path.c_str(), errno);
2143
bool ret= fill_derived_tables();
2144
assert(ret == false);
2145
if (open_tables_from_list(&tables, &counter, flags) ||
2146
mysql_handle_derived(lex, &mysql_derived_prepare))
1995
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const TableIdentifier &identifier)
2151
bool Session::rm_temporary_table(plugin::StorageEngine *base, char *path)
1999
if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier))
2157
if (delete_table_proto_file(path))
2160
if (base->doDeleteTable(this, path))
2002
identifier.getSQLPath(path);
2003
2163
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2004
path.c_str(), errno);
2013
@note this will be removed, I am looking through Hudson to see if it is finding
2014
any tables that are missed during cleanup.
2016
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
2020
if (not temporary_tables)
2023
cerr << "Begin Run: " << foo << "\n";
2024
for (table= temporary_tables; table; table= table->getNext())
2026
bool have_proto= false;
2028
message::Table *proto= table->getShare()->getTableProto();
2029
if (table->getShare()->getTableProto())
2032
const char *answer= have_proto ? "true" : "false";
2036
cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2037
cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2041
cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2046
bool Session::TableMessages::storeTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2048
table_message_cache.insert(make_pair(identifier.getPath(), table_message));
2053
bool Session::TableMessages::removeTableMessage(const TableIdentifier &identifier)
2055
TableMessageCache::iterator iter;
2057
iter= table_message_cache.find(identifier.getPath());
2059
if (iter == table_message_cache.end())
2062
table_message_cache.erase(iter);
2067
bool Session::TableMessages::getTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2069
TableMessageCache::iterator iter;
2071
iter= table_message_cache.find(identifier.getPath());
2073
if (iter == table_message_cache.end())
2076
table_message.CopyFrom(((*iter).second));
2081
bool Session::TableMessages::doesTableMessageExist(const TableIdentifier &identifier)
2083
TableMessageCache::iterator iter;
2085
iter= table_message_cache.find(identifier.getPath());
2087
if (iter == table_message_cache.end())
2095
bool Session::TableMessages::renameTableMessage(const TableIdentifier &from, const TableIdentifier &to)
2097
TableMessageCache::iterator iter;
2099
table_message_cache[to.getPath()]= table_message_cache[from.getPath()];
2101
iter= table_message_cache.find(to.getPath());
2103
if (iter == table_message_cache.end())
2108
(*iter).second.set_schema(to.getSchemaName());
2109
(*iter).second.set_name(to.getTableName());
2114
table::Instance *Session::getInstanceTable()
2116
temporary_shares.push_back(new table::Instance()); // This will not go into the tableshare cache, so no key is used.
2118
table::Instance *tmp_share= temporary_shares.back();
2127
Create a reduced Table object with properly set up Field list from a
2128
list of field definitions.
2130
The created table doesn't have a table Cursor associated with
2131
it, has no keys, no group/distinct, no copy_funcs array.
2132
The sole purpose of this Table object is to use the power of Field
2133
class to read/write data to/from table->getInsertRecord(). Then one can store
2134
the record in any container (RB tree, hash, etc).
2135
The table is created in Session mem_root, so are the table's fields.
2136
Consequently, if you don't BLOB fields, you don't need to free it.
2138
@param session connection handle
2139
@param field_list list of column definitions
2142
0 if out of memory, Table object in case of success
2144
table::Instance *Session::getInstanceTable(List<CreateField> &field_list)
2146
temporary_shares.push_back(new table::Instance(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2148
table::Instance *tmp_share= temporary_shares.back();
2157
static const std::string NONE= "NONE";
2158
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2159
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2161
const std::string &type(drizzled::Session::global_read_lock_t type)
2167
case Session::GOT_GLOBAL_READ_LOCK:
2168
return GOT_GLOBAL_READ_LOCK;
2169
case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2170
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2174
size_t max_string_length(drizzled::Session::global_read_lock_t)
2176
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2179
} /* namespace display */
2181
} /* namespace drizzled */