summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorkonstantin@oak.local <>2003-11-27 20:51:53 +0300
committerkonstantin@oak.local <>2003-11-27 20:51:53 +0300
commitc75bb0a654db5ce8ecb7b3a952890b100fef31e1 (patch)
treea1161b4b2f69bc0ec5235db502853d986c76a4a7 /sql
parent56ec2351a0a3ddf7aee6b2580c7c56fa21a2e033 (diff)
downloadmariadb-git-c75bb0a654db5ce8ecb7b3a952890b100fef31e1.tar.gz
Second attempt: trying to add Statement context to sources.
Added classes Statement, Statement_map Merge commit
Diffstat (limited to 'sql')
-rw-r--r--sql/slave.cc1
-rw-r--r--sql/sql_class.cc108
-rw-r--r--sql/sql_class.h134
-rw-r--r--sql/sql_parse.cc8
-rw-r--r--sql/sql_prepare.cc2
5 files changed, 206 insertions, 47 deletions
diff --git a/sql/slave.cc b/sql/slave.cc
index c531d3cc4f7..a10d0488eed 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -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);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index e2d1069975b..539c864d5ee 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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
@@ -236,22 +240,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
SYNOPSIS
@@ -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));
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f9d74f8b4da..211232e85ea 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -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
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7afc268b270..ea34fdd6ac5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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));
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 9721b77e38a..4791dd94bd6 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -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);