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
43
#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/identifier.h"
54
#include "drizzled/table/instance.h"
56
#include "plugin/myisam/myisam.h"
57
#include "drizzled/internal/iocache.h"
58
#include "drizzled/internal/thread_var.h"
59
#include "drizzled/plugin/event_observer.h"
61
#include "drizzled/util/functors.h"
63
#include "drizzled/display.h"
66
45
#include <algorithm>
68
#include <boost/filesystem.hpp>
70
#include "drizzled/util/backtrace.h"
72
47
using namespace std;
48
using namespace drizzled;
74
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);
79
57
The following is used to initialise Table_ident with a internal
83
61
char empty_c_string[1]= {0}; /* used for not defined db */
85
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)
87
95
bool Key_part_spec::operator==(const Key_part_spec& other) const
89
97
return length == other.length &&
90
98
field_name.length == other.field_name.length &&
91
!my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
99
!strcmp(field_name.str, other.field_name.str);
94
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)
97
open_tables= temporary_tables= derived_tables= NULL;
98
extra_lock= lock= NULL;
105
reset_open_tables_state();
102
109
The following functions form part of the C plugin API
104
int mysql_tmpfile(const char *prefix)
111
extern "C" int mysql_tmpfile(const char *prefix)
106
113
char filename[FN_REFLEN];
107
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));
109
116
unlink(filename);
126
134
@see Session::set_proc_info
128
void set_session_proc_info(Session *session, const char *info)
137
set_session_proc_info(Session *session, const char *info)
130
139
session->set_proc_info(info);
133
143
const char *get_session_proc_info(Session *session)
135
145
return session->get_proc_info();
138
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
140
return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
143
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
146
return &ha_data[monitored->getId()].resource_context[index];
149
void **session_ha_data(const Session *session, const plugin::StorageEngine *engine)
151
return (void **) &session->ha_data[engine->slot].ha_ptr;
149
155
int64_t session_test_options(const Session *session, int64_t test_options)
151
157
return session->options & test_options;
154
161
int session_sql_command(const Session *session)
156
163
return (int) session->lex->sql_command;
159
enum_tx_isolation session_tx_isolation(const Session *session)
161
return (enum_tx_isolation)session->variables.tx_isolation;
164
Session::Session(plugin::Client *client_arg) :
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)
165
180
Open_tables_state(refresh_version),
166
181
mem_root(&main_mem_root),
169
query(new std::string),
170
_schema(new std::string("")),
172
184
client(client_arg),
174
186
scheduler_arg(NULL),
175
187
lock_id(&main_lock_id),
177
security_ctx(identifier::User::make_shared()),
179
ha_data(plugin::num_trx_monitored_objects),
180
concurrent_execute_allowed(true),
181
189
arg_of_last_insert_id_function(false),
182
190
first_successful_insert_id_in_prev_stmt(0),
183
191
first_successful_insert_id_in_cur_stmt(0),
184
192
limit_found_rows(0),
185
_global_read_lock(NONE),
187
194
some_tables_deleted(false),
188
195
no_errors(false),
262
272
memset(&status_var, 0, sizeof(status_var));
264
274
/* Initialize sub structures */
265
memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
275
init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
276
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
277
(hash_get_key) get_var_key,
278
(hash_free_key) free_user_var, 0);
267
280
substitute_null_with_insert_id = false;
268
lock_info.init(); /* safety: will be reset after start */
281
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
269
282
thr_lock_owner_init(&main_lock_id, &lock_info);
271
284
m_internal_handler= NULL;
273
plugin::EventObserver::registerSessionEvents(*this);
276
287
void Session::free_items()
279
/* This works because items are allocated with memory::sql_alloc() */
290
/* This works because items are allocated with sql_alloc() */
280
291
for (; free_list; free_list= next)
282
293
next= free_list->next;
305
316
return false; // 'false', as per coding style
308
void Session::setAbort(bool arg)
310
mysys_var->abort= arg;
313
void Session::lockOnSys()
319
boost_unique_lock_t scopedLock(mysys_var->mutex);
320
if (mysys_var->current_cond)
322
mysys_var->current_mutex->lock();
323
mysys_var->current_cond->notify_all();
324
mysys_var->current_mutex->unlock();
328
319
void Session::pop_internal_handler()
330
321
assert(m_internal_handler != NULL);
331
322
m_internal_handler= NULL;
334
void Session::get_xid(DRIZZLE_XID *xid)
336
*xid = *(DRIZZLE_XID *) &transaction.xid_state.xid;
325
#if defined(__cplusplus)
329
void *session_alloc(Session *session, unsigned int size)
331
return session->alloc(size);
334
void *session_calloc(Session *session, unsigned int size)
336
return session->calloc(size);
339
char *session_strdup(Session *session, const char *str)
341
return session->strdup(str);
344
char *session_strmake(Session *session, const char *str, unsigned int size)
346
return session->strmake(str, size);
349
void *session_memdup(Session *session, const void* str, unsigned int size)
351
return session->memdup(str, size);
354
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
356
*xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
359
#if defined(__cplusplus)
339
363
/* Do operations that may take a long time */
403
411
plugin::StorageEngine::closeConnection(this);
404
412
plugin_sessionvar_cleanup(this);
406
warn_root.free_root(MYF(0));
419
free_root(&warn_root,MYF(0));
420
free_root(&transaction.mem_root,MYF(0));
407
421
mysys_var=0; // Safety (shouldn't be needed)
408
422
dbug_sentry= Session_SENTRY_GONE;
410
main_mem_root.free_root(MYF(0));
411
currentMemRoot().release();
412
currentSession().release();
414
plugin::Logging::postEndDo(this);
415
plugin::EventObserver::deregisterSessionEvents(*this);
417
for (PropertyMap::iterator iter= life_properties.begin(); iter != life_properties.end(); iter++)
419
delete (*iter).second;
421
life_properties.clear();
424
void Session::setClient(plugin::Client *client_arg)
427
client->setSession(this);
430
void Session::awake(Session::killed_state_t state_to_set)
432
if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
437
setKilled(state_to_set);
438
scheduler->killSession(this);
424
free_root(&main_mem_root, MYF(0));
425
pthread_setspecific(THR_Session, 0);
428
/* Ensure that no one is using Session */
429
pthread_mutex_unlock(&LOCK_delete);
430
pthread_mutex_destroy(&LOCK_delete);
434
Add all status variables to another status variable array
438
to_var add to this array
439
from_var from this array
442
This function assumes that all variables are long/ulong.
443
If this assumption will change, then we have to explictely add
444
the other variables after the while loop
446
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
448
ulong *end= (ulong*) ((unsigned char*) to_var +
449
offsetof(STATUS_VAR, last_system_status_var) +
451
ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
458
Add the difference between two status variable arrays to another one.
462
to_var add to this array
463
from_var from this array
464
dec_var minus this array
467
This function assumes that all variables are long/ulong.
469
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
472
ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
473
last_system_status_var) +
475
ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
478
*(to++)+= *(from++) - *(dec++);
481
void Session::awake(Session::killed_state state_to_set)
483
Session_CHECK_SENTRY(this);
484
safe_mutex_assert_owner(&LOCK_delete);
486
killed= state_to_set;
440
487
if (state_to_set != Session::KILL_QUERY)
489
scheduler->killSession(this);
442
490
DRIZZLE_CONNECTION_DONE(thread_id);
447
boost_unique_lock_t scopedLock(mysys_var->mutex);
494
pthread_mutex_lock(&mysys_var->mutex);
450
496
This broadcast could be up in the air if the victim thread
451
497
exits the cond in the time between read and broadcast, but that is
452
498
ok since all we want to do is to make the victim thread get out
555
602
prepareForQueries();
557
while (not client->haveError() && getKilled() != KILL_CONNECTION)
604
while (! client->haveError() && killed != KILL_CONNECTION)
559
if (not executeStatement())
606
if (! executeStatement())
563
610
disconnect(0, true);
566
bool Session::schedule(Session::shared_ptr &arg)
613
bool Session::schedule()
568
arg->scheduler= plugin::Scheduler::getScheduler();
569
assert(arg->scheduler);
571
connection_count.increment();
573
if (connection_count > current_global_counters.max_used_connections)
575
current_global_counters.max_used_connections= connection_count;
578
current_global_counters.connections++;
579
arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
581
session::Cache::singleton().insert(arg);
583
if (unlikely(plugin::EventObserver::connectSession(*arg)))
585
// We should do something about an error...
588
if (plugin::Scheduler::getScheduler()->addSession(arg))
590
DRIZZLE_CONNECTION_START(arg->getSessionId());
615
scheduler= plugin::Scheduler::getScheduler();
620
if (connection_count > max_used_connections)
621
max_used_connections= connection_count;
623
thread_id= variables.pseudo_thread_id= global_thread_id++;
625
pthread_mutex_lock(&LOCK_thread_count);
626
session_list.push_back(this);
627
pthread_mutex_unlock(&LOCK_thread_count);
629
if (scheduler->addSession(this))
631
DRIZZLE_CONNECTION_START(thread_id);
591
632
char error_message_buff[DRIZZLE_ERRMSG_SIZE];
593
arg->setKilled(Session::KILL_CONNECTION);
634
killed= Session::KILL_CONNECTION;
595
arg->status_var.aborted_connects++;
636
statistic_increment(aborted_connects, &LOCK_status);
597
638
/* Can't use my_error() since store_globals has not been called. */
598
639
/* TODO replace will better error message */
599
640
snprintf(error_message_buff, sizeof(error_message_buff),
600
641
ER(ER_CANT_CREATE_THREAD), 1);
601
arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
642
client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
611
Is this session viewable by the current user?
613
bool Session::isViewable() const
615
return plugin::Authorization::isAuthorized(current_session->user(),
621
const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
623
const char* old_msg = get_proc_info();
624
safe_mutex_assert_owner(mutex);
625
mysys_var->current_mutex = &mutex;
626
mysys_var->current_cond = &cond;
627
this->set_proc_info(msg);
631
void Session::exit_cond(const char* old_msg)
634
Putting the mutex unlock in exit_cond() ensures that
635
mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
636
locked (if that would not be the case, you'll get a deadlock if someone
637
does a Session::awake() on you).
639
mysys_var->current_mutex->unlock();
640
boost_unique_lock_t scopedLock(mysys_var->mutex);
641
mysys_var->current_mutex = 0;
642
mysys_var->current_cond = 0;
643
this->set_proc_info(old_msg);
646
649
bool Session::authenticate()
649
652
if (client->authenticate())
652
status_var.aborted_connects++;
655
statistic_increment(aborted_connects, &LOCK_status);
657
bool Session::checkUser(const std::string &passwd_str,
658
const std::string &in_db)
659
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
660
bool is_authenticated=
661
plugin::Authentication::isAuthenticated(user(), passwd_str);
661
LEX_STRING db_str= { (char *) in_db, in_db ? strlen(in_db) : 0 };
662
bool is_authenticated;
665
Clear session->db as it points to something, that will be freed when
666
connection is closed. We don't want to accidentally free a wrong
667
pointer if connect failed. Also in case of 'CHANGE USER' failure,
668
current database will be switched to 'no database selected'.
672
if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
674
my_error(ER_HANDSHAKE_ERROR, MYF(0), security_ctx.ip.c_str());
678
is_authenticated= plugin::Authentication::isAuthenticated(this, passwd);
663
680
if (is_authenticated != true)
665
status_var.access_denied++;
666
/* isAuthenticated has pushed the error message */
682
my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
683
security_ctx.user.c_str(),
684
security_ctx.ip.c_str(),
685
passwd_len ? ER(ER_YES) : ER(ER_NO));
690
security_ctx.skip_grants();
670
692
/* Change database if necessary */
671
if (not in_db.empty())
693
if (in_db && in_db[0])
673
SchemaIdentifier identifier(in_db);
674
if (mysql_change_db(this, identifier))
695
if (mysql_change_db(this, &db_str, false))
676
697
/* mysql_change_db() has pushed the error message. */
681
password= not passwd_str.empty();
702
password= test(passwd_len); // remember for error messages
683
704
/* Ready to handle queries */
890
893
@return NULL on failure, or pointer to the LEX_STRING object
892
895
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
893
const std::string &str,
894
bool allocate_lex_string)
896
return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
899
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
900
const char* str, uint32_t length,
901
bool allocate_lex_string)
896
const char* str, uint32_t length,
897
bool allocate_lex_string)
903
899
if (allocate_lex_string)
904
900
if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
906
if (!(lex_str->str= mem_root->strmake_root(str, length)))
902
if (!(lex_str->str= strmake_root(mem_root, str, length)))
908
904
lex_str->length= length;
908
/* routings to adding tables to list of changed in transaction tables */
909
inline static void list_include(CHANGED_TableList** prev,
910
CHANGED_TableList* curr,
911
CHANGED_TableList* new_table)
916
(*prev)->next = curr;
920
/* add table to list of changed in transaction tables */
922
void Session::add_changed_table(Table *table)
924
assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
925
table->file->has_transactions());
926
add_changed_table(table->s->table_cache_key.str,
927
(long) table->s->table_cache_key.length);
931
void Session::add_changed_table(const char *key, long key_length)
933
CHANGED_TableList **prev_changed = &transaction.changed_tables;
934
CHANGED_TableList *curr = transaction.changed_tables;
936
for (; curr; prev_changed = &(curr->next), curr = curr->next)
938
int cmp = (long)curr->key_length - (long)key_length;
941
list_include(prev_changed, curr, changed_table_dup(key, key_length));
946
cmp = memcmp(curr->key, key, curr->key_length);
949
list_include(prev_changed, curr, changed_table_dup(key, key_length));
958
*prev_changed = changed_table_dup(key, key_length);
962
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
964
CHANGED_TableList* new_table =
965
(CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
969
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
970
ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
971
killed= KILL_CONNECTION;
975
new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
977
new_table->key_length = key_length;
978
::memcpy(new_table->key, key, key_length);
912
983
int Session::send_explain_fields(select_result *result)
914
985
List<Item> field_list;
1044
static int create_file(Session *session,
1045
fs::path &target_path,
1046
file_exchange *exchange,
1047
internal::IO_CACHE *cache)
1107
static File create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1049
fs::path to_file(exchange->file_name);
1052
if (not to_file.has_root_directory())
1110
uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
1112
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1113
option|= MY_REPLACE_DIR; // Force use of db directory
1116
if (!dirname_length(exchange->file_name))
1054
target_path= fs::system_complete(getDataHomeCatalog());
1055
util::string::const_shared_ptr schema(session->schema());
1056
if (schema and not schema->empty())
1058
int count_elements= 0;
1059
for (fs::path::iterator iter= to_file.begin();
1060
iter != to_file.end();
1061
++iter, ++count_elements)
1064
if (count_elements == 1)
1066
target_path /= *schema;
1069
target_path /= to_file;
1118
strcpy(path, drizzle_real_data_home);
1120
strncat(path, session->db, FN_REFLEN-strlen(drizzle_real_data_home)-1);
1121
(void) fn_format(path, exchange->file_name, path, "", option);
1073
target_path = exchange->file_name;
1076
if (not secure_file_priv.string().empty())
1078
if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1080
/* Write only allowed to dir or subdir specified by secure_file_priv */
1081
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1086
if (!access(target_path.file_string().c_str(), F_OK))
1124
(void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
1126
if (opt_secure_file_priv &&
1127
strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1129
/* Write only allowed to dir or subdir specified by secure_file_priv */
1130
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1134
if (!access(path, F_OK))
1088
1136
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1091
1139
/* Create the file world readable */
1092
if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1140
if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1094
1143
(void) fchmod(file, 0666); // Because of umask()
1095
if (cache->init_io_cache(file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1145
(void) chmod(path, 0666);
1147
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1097
internal::my_close(file, MYF(0));
1098
internal::my_delete(target_path.file_string().c_str(), MYF(0)); // Delete file on error, it was just created
1149
my_close(file, MYF(0));
1150
my_delete(path, MYF(0)); // Delete file on error, it was just created
1194
1249
res=item->str_result(&tmp);
1195
1250
if (res && enclosed)
1197
if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
1198
exchange->enclosed->length()))
1252
if (my_b_write(&cache,(unsigned char*) exchange->enclosed->ptr(),
1253
exchange->enclosed->length()))
1203
1258
if (!fixed_row_size)
1205
if (escape_char != -1) // Use \N syntax
1207
null_buff[0]=escape_char;
1209
if (my_b_write(cache,(unsigned char*) null_buff,2))
1212
else if (my_b_write(cache,(unsigned char*) "NULL",4))
1260
if (escape_char != -1) // Use \N syntax
1262
null_buff[0]=escape_char;
1264
if (my_b_write(&cache,(unsigned char*) null_buff,2))
1267
else if (my_b_write(&cache,(unsigned char*) "NULL",4))
1217
used_length=0; // Fill with space
1272
used_length=0; // Fill with space
1222
1277
if (fixed_row_size)
1223
used_length= min(res->length(), static_cast<size_t>(item->max_length));
1278
used_length= min(res->length(),item->max_length);
1225
1280
used_length= res->length();
1227
1282
if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
1230
1285
char *pos, *start, *end;
1231
1286
const CHARSET_INFO * const res_charset= res->charset();
1232
1287
const CHARSET_INFO * const character_set_client= default_charset_info;
1234
1289
bool check_second_byte= (res_charset == &my_charset_bin) &&
1235
character_set_client->
1236
escape_with_backslash_is_dangerous;
1290
character_set_client->
1291
escape_with_backslash_is_dangerous;
1237
1292
assert(character_set_client->mbmaxlen == 2 ||
1238
1293
!character_set_client->escape_with_backslash_is_dangerous);
1239
for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1243
if (use_mb(res_charset))
1246
if ((l=my_ismbchar(res_charset, pos, end)))
1294
for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1298
if (use_mb(res_charset))
1301
if ((l=my_ismbchar(res_charset, pos, end)))
1254
1309
Special case when dumping BINARY/VARBINARY/BLOB values
1282
1337
assert before the loop makes that sure.
1285
if ((needs_escaping(*pos, enclosed) ||
1340
if ((NEED_ESCAPING(*pos) ||
1286
1341
(check_second_byte &&
1287
1342
my_mbcharlen(character_set_client, (unsigned char) *pos) == 2 &&
1288
1343
pos + 1 < end &&
1289
needs_escaping(pos[1], enclosed))) &&
1344
NEED_ESCAPING(pos[1]))) &&
1291
Don't escape field_term_char by doubling - doubling is only
1292
valid for ENCLOSED BY characters:
1346
Don't escape field_term_char by doubling - doubling is only
1347
valid for ENCLOSED BY characters:
1294
1349
(enclosed || !is_ambiguous_field_term ||
1295
1350
(int) (unsigned char) *pos != field_term_char))
1298
1353
tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
1299
1354
is_ambiguous_field_sep) ?
1300
field_sep_char : escape_char;
1301
tmp_buff[1]= *pos ? *pos : '0';
1302
if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1303
my_b_write(cache,(unsigned char*) tmp_buff,2))
1308
if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1355
field_sep_char : escape_char;
1356
tmp_buff[1]= *pos ? *pos : '0';
1357
if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1358
my_b_write(&cache,(unsigned char*) tmp_buff,2))
1363
if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)))
1311
else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1366
else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
1314
1369
if (fixed_row_size)
1315
1370
{ // Fill with space
1316
1371
if (item->max_length > used_length)
1318
/* QQ: Fix by adding a my_b_fill() function */
1322
memset(space, ' ', sizeof(space));
1324
uint32_t length=item->max_length-used_length;
1325
for (; length > sizeof(space) ; length-=sizeof(space))
1327
if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1330
if (my_b_write(cache,(unsigned char*) space,length))
1373
/* QQ: Fix by adding a my_b_fill() function */
1377
memset(space, ' ', sizeof(space));
1379
uint32_t length=item->max_length-used_length;
1380
for (; length > sizeof(space) ; length-=sizeof(space))
1382
if (my_b_write(&cache,(unsigned char*) space,sizeof(space)))
1385
if (my_b_write(&cache,(unsigned char*) space,length))
1334
1389
if (res && enclosed)
1336
if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
1391
if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1337
1392
exchange->enclosed->length()))
1340
1395
if (--items_left)
1342
if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
1397
if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1343
1398
field_term_length))
1347
if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1348
exchange->line_term->length()))
1402
if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
1403
exchange->line_term->length()))
1621
1667
memset(&status_var, 0, sizeof(status_var));
1625
void Session::set_db(const std::string &new_db)
1670
void Security_context::skip_grants()
1672
/* privileges for the user are unknown everything is allowed */
1676
/****************************************************************************
1677
Handling of open and locked tables states.
1679
This is used when we want to open/lock (and then close) some tables when
1680
we already have a set of tables open and locked. We use these methods for
1681
access to mysql.proc table to find definitions of stored routines.
1682
****************************************************************************/
1684
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
1686
backup->set_open_tables_state(this);
1687
reset_open_tables_state();
1688
backups_available= false;
1692
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
1695
Before we will throw away current open tables state we want
1696
to be sure that it was properly cleaned up.
1698
assert(open_tables == 0 && temporary_tables == 0 &&
1699
derived_tables == 0 &&
1701
set_open_tables_state(backup);
1705
bool Session::set_db(const char *new_db, size_t new_db_len)
1627
1707
/* Do not reallocate memory if current chunk is big enough. */
1628
if (new_db.length())
1630
_schema.reset(new std::string(new_db));
1708
if (db && new_db && db_length >= new_db_len)
1709
memcpy(db, new_db, new_db_len+1);
1634
_schema.reset(new std::string(""));
1716
db= (char *)malloc(new_db_len + 1);
1719
memcpy(db, new_db, new_db_len);
1726
db_length= db ? new_db_len : 0;
1727
return new_db && !db;
1732
Check the killed state of a user thread
1733
@param session user thread
1734
@retval 0 the user thread is active
1735
@retval 1 the user thread has been killed
1737
extern "C" int session_killed(const Session *session)
1739
return(session->killed);
1743
Return the session id of a user session
1744
@param pointer to Session object
1745
@return session's id
1747
extern "C" unsigned long session_get_thread_id(const Session *session)
1749
return (unsigned long) session->getSessionId();
1754
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
1755
const char *str, unsigned int size,
1756
int allocate_lex_string)
1758
return session->make_lex_string(lex_str, str, size,
1759
(bool) allocate_lex_string);
1762
const struct charset_info_st *session_charset(Session *session)
1764
return(session->charset());
1767
char **session_query(Session *session)
1769
return(&session->query);
1772
int session_non_transactional_update(const Session *session)
1774
return(session->transaction.all.modified_non_trans_table);
1777
void session_mark_transaction_to_rollback(Session *session, bool all)
1779
mark_transaction_to_rollback(session, all);
1640
1783
Mark transaction to rollback and mark error as fatal to a sub-statement.
1657
1800
plugin_sessionvar_cleanup(this);
1659
1802
/* If necessary, log any aborted or unauthorized connections */
1660
if (getKilled() || client->wasAborted())
1662
status_var.aborted_threads++;
1803
if (killed || client->wasAborted())
1804
statistic_increment(aborted_threads, &LOCK_status);
1665
1806
if (client->wasAborted())
1667
if (not getKilled() && variables.log_warnings > 1)
1808
if (! killed && variables.log_warnings > 1)
1810
Security_context *sctx= &security_ctx;
1669
1812
errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1671
, (_schema->empty() ? "unconnected" : _schema->c_str())
1672
, security_ctx->username().empty() == false ? security_ctx->username().c_str() : "unauthenticated"
1673
, security_ctx->address().c_str()
1814
, (db ? db : "unconnected")
1815
, sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
1674
1817
, (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1678
1821
/* Close out our connection to the client */
1679
1822
if (should_lock)
1680
session::Cache::singleton().mutex().lock();
1682
setKilled(Session::KILL_CONNECTION);
1823
(void) pthread_mutex_lock(&LOCK_thread_count);
1824
killed= Session::KILL_CONNECTION;
1684
1825
if (client->isConnected())
1761
1908
passing non-zero value to end_slave via rli->save_temporary_tables
1762
1909
when no temp tables opened, see an invariant below.
1764
temporary_tables= table->getNext();
1911
temporary_tables= table->next;
1765
1912
if (temporary_tables)
1767
table->getNext()->setPrev(NULL);
1913
table->next->prev= NULL;
1915
close_temporary(table, free_share, delete_table);
1774
Close and drop a temporary table
1919
Close and delete a temporary table
1777
1922
This dosn't unlink table from session->temporary
1778
1923
If this is needed, use close_temporary_table()
1781
void Open_tables_state::nukeTable(Table *table)
1926
void Session::close_temporary(Table *table, bool free_share, bool delete_table)
1783
plugin::StorageEngine *table_type= table->getShare()->db_type();
1928
plugin::StorageEngine *table_type= table->s->db_type();
1785
1930
table->free_io_cache();
1786
table->delete_table();
1788
TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1789
rm_temporary_table(table_type, identifier);
1791
delete table->getMutableShare();
1793
/* This makes me sad, but we're allocating it via malloc */
1931
table->closefrm(false);
1934
rm_temporary_table(table_type, table->s->path.str);
1938
table->s->free_table_share();
1939
/* This makes me sad, but we're allocating it via malloc */
1797
1944
/** Clear most status variables. */
1798
1945
extern time_t flush_status_time;
1946
extern uint32_t max_used_connections;
1800
1948
void Session::refresh_status()
1950
pthread_mutex_lock(&LOCK_status);
1952
/* Add thread's status variabes to global status */
1953
add_to_status(&global_status_var, &status_var);
1802
1955
/* Reset thread's status variables */
1803
1956
memset(&status_var, 0, sizeof(status_var));
1958
/* Reset some global variables */
1959
reset_status_vars();
1961
/* Reset the counters of all key caches (default and named). */
1962
reset_key_cache_counters();
1805
1963
flush_status_time= time((time_t*) 0);
1806
current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1807
current_global_counters.connections= 0;
1964
max_used_connections= 1; /* We set it to one, because we know we exist */
1965
pthread_mutex_unlock(&LOCK_status);
1968
#define extra_size sizeof(double)
1810
1970
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1812
return getVariable(std::string(name.str, name.length), create_if_not_exists);
1815
user_var_entry *Session::getVariable(const std::string &name, bool create_if_not_exists)
1817
UserVarsRange ppp= user_vars.equal_range(name);
1819
for (UserVars::iterator iter= ppp.first;
1820
iter != ppp.second; ++iter)
1822
return (*iter).second;
1825
if (not create_if_not_exists)
1828
1972
user_var_entry *entry= NULL;
1829
entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1834
std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1836
if (not returnable.second)
1974
entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
1976
if ((entry == NULL) && create_if_not_exists)
1978
if (!hash_inited(&user_vars))
1980
entry= new (nothrow) user_var_entry(name.str, query_id);
1985
if (my_hash_insert(&user_vars, (unsigned char*) entry))
1988
free((char*) entry);
1844
void Session::setVariable(const std::string &name, const std::string &value)
1846
user_var_entry *updateable_var= getVariable(name.c_str(), true);
1848
updateable_var->update_hash(false,
1849
(void*)value.c_str(),
1850
static_cast<uint32_t>(value.length()), STRING_RESULT,
1852
DERIVATION_IMPLICIT, false);
1855
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
1857
for (Table *table= temporary_tables ; table ; table= table->getNext())
1997
void Session::mark_temp_tables_as_free_for_reuse()
1999
for (Table *table= temporary_tables ; table ; table= table->next)
1859
if (table->query_id == getQueryId())
2001
if (table->query_id == query_id)
1861
2003
table->query_id= 0;
1862
table->cursor->ha_reset();
2004
table->file->ha_reset();
1867
2009
void Session::mark_used_tables_as_free_for_reuse(Table *table)
1869
for (; table ; table= table->getNext())
2011
for (; table ; table= table->next)
1871
if (table->query_id == getQueryId())
2013
if (table->query_id == query_id)
1873
2015
table->query_id= 0;
1874
table->cursor->ha_reset();
2016
table->file->ha_reset();
1958
2126
if (open_tables_from_list(&tables, &counter))
1961
if (not lock_tables(tables, counter, &need_reopen))
2129
if (!lock_tables(tables, counter, &need_reopen))
1963
if (not need_reopen)
1965
2133
close_tables_for_reopen(&tables);
1967
2135
if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
2136
(fill_derived_tables() &&
1969
2137
mysql_handle_derived(lex, &mysql_derived_filling))))
1976
@note "best_effort" is used in cases were if a failure occurred on this
1977
operation it would not be surprising because we are only removing because there
1978
might be an issue (lame engines).
1981
bool Open_tables_state::rm_temporary_table(const TableIdentifier &identifier, bool best_effort)
2143
bool Session::openTables(TableList *tables, uint32_t flags)
1983
if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
1985
if (not best_effort)
1988
identifier.getSQLPath(path);
1989
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
1990
path.c_str(), errno);
2146
bool ret= fill_derived_tables();
2147
assert(ret == false);
2148
if (open_tables_from_list(&tables, &counter, flags) ||
2149
mysql_handle_derived(lex, &mysql_derived_prepare))
1999
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const TableIdentifier &identifier)
2154
bool Session::rm_temporary_table(plugin::StorageEngine *base, char *path)
2003
if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier))
2160
if (delete_table_proto_file(path))
2163
if (base->doDeleteTable(this, path))
2006
identifier.getSQLPath(path);
2007
2166
errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2008
path.c_str(), errno);
2017
@note this will be removed, I am looking through Hudson to see if it is finding
2018
any tables that are missed during cleanup.
2020
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
2024
if (not temporary_tables)
2027
cerr << "Begin Run: " << foo << "\n";
2028
for (table= temporary_tables; table; table= table->getNext())
2030
bool have_proto= false;
2032
message::Table *proto= table->getShare()->getTableProto();
2033
if (table->getShare()->getTableProto())
2036
const char *answer= have_proto ? "true" : "false";
2040
cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2041
cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2045
cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2050
bool Session::TableMessages::storeTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2052
table_message_cache.insert(make_pair(identifier.getPath(), table_message));
2057
bool Session::TableMessages::removeTableMessage(const TableIdentifier &identifier)
2059
TableMessageCache::iterator iter;
2061
iter= table_message_cache.find(identifier.getPath());
2063
if (iter == table_message_cache.end())
2066
table_message_cache.erase(iter);
2071
bool Session::TableMessages::getTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2073
TableMessageCache::iterator iter;
2075
iter= table_message_cache.find(identifier.getPath());
2077
if (iter == table_message_cache.end())
2080
table_message.CopyFrom(((*iter).second));
2085
bool Session::TableMessages::doesTableMessageExist(const TableIdentifier &identifier)
2087
TableMessageCache::iterator iter;
2089
iter= table_message_cache.find(identifier.getPath());
2091
if (iter == table_message_cache.end())
2099
bool Session::TableMessages::renameTableMessage(const TableIdentifier &from, const TableIdentifier &to)
2101
TableMessageCache::iterator iter;
2103
table_message_cache[to.getPath()]= table_message_cache[from.getPath()];
2105
iter= table_message_cache.find(to.getPath());
2107
if (iter == table_message_cache.end())
2112
(*iter).second.set_schema(to.getSchemaName());
2113
(*iter).second.set_name(to.getTableName());
2118
table::Instance *Session::getInstanceTable()
2120
temporary_shares.push_back(new table::Instance()); // This will not go into the tableshare cache, so no key is used.
2122
table::Instance *tmp_share= temporary_shares.back();
2131
Create a reduced Table object with properly set up Field list from a
2132
list of field definitions.
2134
The created table doesn't have a table Cursor associated with
2135
it, has no keys, no group/distinct, no copy_funcs array.
2136
The sole purpose of this Table object is to use the power of Field
2137
class to read/write data to/from table->getInsertRecord(). Then one can store
2138
the record in any container (RB tree, hash, etc).
2139
The table is created in Session mem_root, so are the table's fields.
2140
Consequently, if you don't BLOB fields, you don't need to free it.
2142
@param session connection handle
2143
@param field_list list of column definitions
2146
0 if out of memory, Table object in case of success
2148
table::Instance *Session::getInstanceTable(List<CreateField> &field_list)
2150
temporary_shares.push_back(new table::Instance(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2152
table::Instance *tmp_share= temporary_shares.back();
2161
static const std::string NONE= "NONE";
2162
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2163
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2165
const std::string &type(drizzled::Session::global_read_lock_t type)
2171
case Session::GOT_GLOBAL_READ_LOCK:
2172
return GOT_GLOBAL_READ_LOCK;
2173
case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2174
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2178
size_t max_string_length(drizzled::Session::global_read_lock_t)
2180
return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2183
} /* namespace display */
2185
} /* namespace drizzled */