Commit c75bb0a6 authored by konstantin@oak.local's avatar konstantin@oak.local

Second attempt: trying to add Statement context to sources.

Added classes Statement, Statement_map
Merge commit
parent 56ec2351
......@@ -3106,7 +3106,6 @@ slave_begin:
sql_print_error("Failed during slave thread initialization");
goto err;
}
thd->init_for_queries();
rli->sql_thd= thd;
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
pthread_mutex_lock(&LOCK_thread_count);
......
......@@ -86,28 +86,28 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions
****************************************************************************/
THD::THD():user_time(0), is_fatal_error(0),
THD::THD():user_time(0),
is_fatal_error(0),
last_insert_id_used(0),
insert_id_used(0), rand_used(0), in_lock_tables(0),
global_read_lock(0), bootstrap(0), spcont(NULL)
{
lex= &main_lex;
host=user=priv_user=db=query=ip=0;
host= user= priv_user= db= ip= 0;
host_or_ip= "connecting host";
locked=some_tables_deleted=no_errors=password=
query_start_used=prepare_command=0;
locked=some_tables_deleted=no_errors=password= 0;
query_start_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
db_length=query_length=col_access=0;
db_length= col_access=0;
query_error= tmp_table_used= 0;
next_insert_id=last_insert_id=0;
open_tables= temporary_tables= handler_tables= derived_tables= 0;
tmp_table=0;
lock=locked_tables=0;
used_tables=0;
cuted_fields= sent_row_count= current_stmt_id= 0L;
cuted_fields= sent_row_count= 0L;
statement_id_counter= 0UL;
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
start_time=(time_t) 0;
current_linfo = 0;
slave_thread = 0;
......@@ -141,7 +141,6 @@ THD::THD():user_time(0), is_fatal_error(0),
server_id = ::server_id;
slave_net = 0;
command=COM_CONNECT;
set_query_id=1;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access=NO_ACCESS;
#endif
......@@ -149,6 +148,9 @@ THD::THD():user_time(0), is_fatal_error(0),
*scramble= '\0';
init();
init_sql_alloc(&mem_root, // must be after init()
variables.query_alloc_block_size,
variables.query_prealloc_size);
/* Initialize sub structures */
bzero((char*) &mem_root,sizeof(mem_root));
init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
......@@ -192,7 +194,9 @@ THD::THD():user_time(0), is_fatal_error(0),
transaction.trans_log.end_of_file= max_binlog_cache_size;
}
#endif
init_sql_alloc(&transaction.mem_root,
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
/*
We need good random number initialization for new thread
Just coping global one will not work
......@@ -235,22 +239,6 @@ void THD::init(void)
}
/*
Init THD for query processing
This has to be called once before we call mysql_parse()
*/
void THD::init_for_queries()
{
init_sql_alloc(&mem_root, variables.query_alloc_block_size,
variables.query_prealloc_size);
init_sql_alloc(&transaction.mem_root,
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
}
/*
Do what's needed when one invokes change user
......@@ -351,7 +339,6 @@ THD::~THD()
safeFree(user);
safeFree(db);
safeFree(ip);
free_root(&mem_root,MYF(0));
free_root(&warn_root,MYF(0));
free_root(&transaction.mem_root,MYF(0));
mysys_var=0; // Safety (shouldn't be needed)
......@@ -1269,3 +1256,70 @@ bool select_dumpvar::send_eof()
::send_ok(thd,row_count);
return 0;
}
/*
Statement functions
*/
Statement::Statement(THD *thd)
:id(++thd->statement_id_counter),
query_id(0), /* initialized later */
set_query_id(1),
allow_sum_func(0), /* initialized later */
command(COM_SLEEP), /* reset in THD counstructor and mysql_parse */
lex(&main_lex),
query(0),
query_length(0),
free_list(0) /* reset in THD constructor */
{
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
/*
This constructor is called when statement is a subobject of THD:
Some variables are initialized in THD::init due to locking problems
This statement object will be used to
*/
Statement::Statement()
:id(0),
query_id(0),
set_query_id(1),
allow_sum_func(0),
command(COM_SLEEP),
lex(&main_lex),
query(0),
query_length(0),
free_list(0)
{
bzero((char *) &mem_root, sizeof(mem_root));
}
Statement::~Statement()
{
free_root(&mem_root, MYF(0));
}
C_MODE_START
static byte *
get_statement_id_as_hash_key(const byte *record, uint *key_length,
my_bool not_used __attribute__((unused)))
{
const Statement *statement= (const Statement *) record;
*key_length= sizeof(statement->id);
return (byte *) &((const Statement *) statement)->id;
}
C_MODE_END
Statement_map::Statement_map()
{
enum { START_HASH_SIZE = 16 };
hash_init(&st_hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_statement_id_as_hash_key, (hash_free_key) 0, MYF(0));
}
......@@ -431,12 +431,126 @@ struct system_variables
};
void free_tmp_table(THD *thd, TABLE *entry);
/*
State of a single command executed against this connection.
One connection can contain a lot of simultaneously running statements,
some of which could be:
- prepared, that is, contain placeholders,
- opened as cursors. We maintain 1 to 1 relationship between
statement and cursor - if user wants to create another cursor for his
query, we create another statement for it.
To perform some action with statement we reset THD part to the state of
that statement, do the action, and then save back modified state from THD
to the statement. It will be changed in near future, and Statement will
be used explicitly.
*/
class Statement
{
public:
/* FIXME: must be private */
LEX main_lex;
public:
/*
Uniquely identifies each statement object in scope of thread.
Can't be const at the moment because of substitute() method
*/
/* const */ ulong id;
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
ID is automatically generated from mutex-protected counter.
It's used in handler code for various purposes: to check which columns
from table are necessary for this select, to check if it's necessary to
update auto-updatable fields (like auto_increment and timestamp).
*/
ulong query_id;
/*
- if set_query_id=1, we set field->query_id for all fields. In that case
field list can not contain duplicates.
*/
bool set_query_id;
/*
This variable is used in post-parse stage to declare that sum-functions,
or functions which have sense only if GROUP BY is present, are allowed.
For example in queries
SELECT MIN(i) FROM foo
SELECT GROUP_CONCAT(a, b, MIN(i)) FROM ... GROUP BY ...
MIN(i) have no sense.
Though it's grammar-related issue, it's hard to catch it out during the
parse stage because GROUP BY clause goes in the end of query. This
variable is mainly used in setup_fields/fix_fields.
See item_sum.cc for details.
*/
bool allow_sum_func;
/*
Type of current query: COM_PREPARE, COM_QUERY, etc. Set from
first byte of the packet in do_command()
*/
enum enum_server_command command;
LEX *lex; // parse tree descriptor
/*
Points to the query associated with this statement. It's const, but
we need to declare it char * because all table handlers are written
in C and need to point to it.
*/
char *query;
uint32 query_length; // current query length
/*
List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
MEM_ROOT mem_root;
protected:
Statement();
public:
Statement(THD *thd);
virtual ~Statement();
};
/*
Used to seek all existing statements in the connection
Not responsible for statements memory.
*/
class Statement_map
{
public:
Statement_map();
int insert(Statement *statement)
{
return my_hash_insert(&st_hash, (byte *) statement);
}
Statement *seek(ulonglong id)
{
return (Statement *) hash_search(&st_hash, (byte *) &id, sizeof(id));
}
void erase(Statement *statement)
{
hash_delete(&st_hash, (byte *) statement);
}
~Statement_map() { hash_free(&st_hash); }
private:
HASH st_hash;
};
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
class THD :public ilink
class THD :public ilink,
public Statement
{
public:
#ifdef EMBEDDED_LIBRARY
......@@ -449,9 +563,6 @@ public:
ulong extra_length;
#endif
NET net; // client connection descriptor
LEX main_lex;
LEX *lex; // parse tree descriptor
MEM_ROOT mem_root; // 1 command-life memory pool
MEM_ROOT warn_root; // For warnings and errors
Protocol *protocol; // Current protocol
Protocol_simple protocol_simple; // Normal protocol
......@@ -464,7 +575,6 @@ public:
struct system_variables variables; // Changeable local variables
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
char *query; // Points to the current query,
/*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
......@@ -513,7 +623,6 @@ public:
uint dbug_sentry; // watch out for memory corruption
#endif
struct st_my_thread_var *mysys_var;
enum enum_server_command command;
uint32 server_id;
uint32 file_id; // for LOAD DATA INFILE
/*
......@@ -546,7 +655,6 @@ public:
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
}
} transaction;
Item *free_list;
Field *dupp_field;
#ifndef __WIN__
sigset_t signals,block_signals;
......@@ -580,15 +688,16 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
ulong query_id, warn_id, version, options, thread_id, col_access;
ulong current_stmt_id;
ulong warn_id, version, options, thread_id, col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
ulong rand_saved_seed1, rand_saved_seed2;
ulong row_count; // Row counter, mainly for errors and warnings
long dbug_thread_id;
pthread_t real_id;
uint current_tablenr,tmp_table;
uint server_status,open_options;
uint32 query_length;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
......@@ -601,9 +710,9 @@ public:
char scramble[SCRAMBLE_LENGTH+1];
bool slave_thread;
bool set_query_id,locked,some_tables_deleted;
bool locked, some_tables_deleted;
bool last_cuted_field;
bool no_errors, allow_sum_func, password, is_fatal_error;
bool no_errors, password, is_fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
......@@ -647,7 +756,6 @@ public:
void init(void);
void change_user(void);
void init_for_queries();
void cleanup(void);
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
......
......@@ -949,7 +949,6 @@ pthread_handler_decl(handle_one_connection,arg)
thd->command=COM_SLEEP;
thd->version=refresh_version;
thd->set_time();
thd->init_for_queries();
while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION))
{
if (do_command(thd))
......@@ -1029,7 +1028,6 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME));
buff= (char*) thd->net.buff;
thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
......@@ -1202,13 +1200,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
NET *net= &thd->net;
bool error= 0;
DBUG_ENTER("dispatch_command");
thd->command=command;
/*
Commands which will always take a long time should be marked with
this so that they will not get logged to the slow query log
*/
DBUG_ENTER("dispatch_command");
thd->command=command;
thd->slow_command=FALSE;
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
......
......@@ -904,7 +904,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
bzero((char*) &stmt, sizeof(stmt));
stmt.stmt_id= ++thd->current_stmt_id;
stmt.stmt_id= ++thd->statement_id_counter;
init_sql_alloc(&stmt.mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment