Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
2a25b261
Commit
2a25b261
authored
Dec 20, 2003
by
konstantin@oak.local
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prepared_statement deployed instead of PREP_STMT.
parent
d37da004
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
613 additions
and
430 deletions
+613
-430
libmysqld/lib_sql.cc
libmysqld/lib_sql.cc
+0
-87
sql/mysql_priv.h
sql/mysql_priv.h
+1
-3
sql/slave.cc
sql/slave.cc
+0
-1
sql/sql_class.cc
sql/sql_class.cc
+106
-34
sql/sql_class.h
sql/sql_class.h
+167
-41
sql/sql_parse.cc
sql/sql_parse.cc
+3
-5
sql/sql_prepare.cc
sql/sql_prepare.cc
+335
-258
tests/client_test.c
tests/client_test.c
+1
-1
No files found.
libmysqld/lib_sql.cc
View file @
2a25b261
...
...
@@ -743,90 +743,3 @@ bool Protocol::convert_str(const char *from, uint length)
}
#endif
bool
setup_params_data
(
st_prep_stmt
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
thd
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
ulong
param_no
=
0
;
MYSQL_BIND
*
client_param
=
thd
->
client_params
;
DBUG_ENTER
(
"setup_params_data"
);
for
(;(
param
=
(
Item_param
*
)
param_iterator
++
);
client_param
++
)
{
setup_param_functions
(
param
,
client_param
->
buffer_type
);
if
(
!
param
->
long_data_supplied
)
{
if
(
*
client_param
->
is_null
)
param
->
maybe_null
=
param
->
null_value
=
1
;
else
{
uchar
*
buff
=
(
uchar
*
)
client_param
->
buffer
;
param
->
maybe_null
=
param
->
null_value
=
0
;
param
->
setup_param_func
(
param
,
&
buff
,
client_param
->
length
?
*
client_param
->
length
:
client_param
->
buffer_length
);
}
}
param_no
++
;
}
DBUG_RETURN
(
0
);
}
bool
setup_params_data_withlog
(
st_prep_stmt
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
thd
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
MYSQL_BIND
*
client_param
=
thd
->
client_params
;
DBUG_ENTER
(
"setup_params_data"
);
String
str
,
*
res
,
*
query
=
new
String
(
stmt
->
query
->
alloced_length
());
query
->
copy
(
*
stmt
->
query
);
ulong
param_no
=
0
;
uint32
length
=
0
;
for
(;(
param
=
(
Item_param
*
)
param_iterator
++
);
client_param
++
)
{
setup_param_functions
(
param
,
client_param
->
buffer_type
);
if
(
param
->
long_data_supplied
)
res
=
param
->
query_val_str
(
&
str
);
else
{
if
(
*
client_param
->
is_null
)
{
param
->
maybe_null
=
param
->
null_value
=
1
;
res
=
&
my_null_string
;
}
else
{
uchar
*
buff
=
(
uchar
*
)
client_param
->
buffer
;
param
->
maybe_null
=
param
->
null_value
=
0
;
param
->
setup_param_func
(
param
,
&
buff
,
client_param
->
length
?
*
client_param
->
length
:
client_param
->
buffer_length
);
res
=
param
->
query_val_str
(
&
str
);
}
}
if
(
query
->
replace
(
param
->
pos_in_query
+
length
,
1
,
*
res
))
DBUG_RETURN
(
1
);
length
+=
res
->
length
()
-
1
;
param_no
++
;
}
if
(
alloc_query
(
stmt
->
thd
,
(
char
*
)
query
->
ptr
(),
query
->
length
()
+
1
))
DBUG_RETURN
(
1
);
query
->
free
();
DBUG_RETURN
(
0
);
}
sql/mysql_priv.h
View file @
2a25b261
...
...
@@ -612,8 +612,6 @@ int mysqld_show_column_types(THD *thd);
int
mysqld_help
(
THD
*
thd
,
const
char
*
text
);
/* sql_prepare.cc */
int
compare_prep_stmt
(
void
*
not_used
,
PREP_STMT
*
stmt
,
ulong
*
key
);
void
free_prep_stmt
(
PREP_STMT
*
stmt
,
TREE_FREE
mode
,
void
*
not_used
);
bool
mysql_stmt_prepare
(
THD
*
thd
,
char
*
packet
,
uint
packet_length
);
void
mysql_stmt_execute
(
THD
*
thd
,
char
*
packet
);
void
mysql_stmt_free
(
THD
*
thd
,
char
*
packet
);
...
...
@@ -855,7 +853,7 @@ extern I_List<THD> threads;
extern
I_List
<
NAMED_LIST
>
key_caches
;
extern
MY_BITMAP
temp_pool
;
extern
String
my_empty_string
;
extern
String
my_null_string
;
extern
const
String
my_null_string
;
extern
SHOW_VAR
init_vars
[],
status_vars
[],
internal_vars
[];
extern
SHOW_COMP_OPTION
have_isam
;
extern
SHOW_COMP_OPTION
have_innodb
;
...
...
sql/slave.cc
View file @
2a25b261
...
...
@@ -3111,7 +3111,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
);
...
...
sql/sql_class.cc
View file @
2a25b261
...
...
@@ -88,21 +88,20 @@ THD::THD():user_time(0), is_fatal_error(0),
insert_id_used
(
0
),
rand_used
(
0
),
in_lock_tables
(
0
),
global_read_lock
(
0
),
bootstrap
(
0
)
{
host
=
user
=
priv_user
=
db
=
query
=
ip
=
0
;
lex
=
&
main_lex
;
host
=
user
=
priv_user
=
db
=
ip
=
0
;
host_or_ip
=
"connecting host"
;
locked
=
killed
=
some_tables_deleted
=
no_errors
=
password
=
0
;
query_start_used
=
0
;
count_cuted_fields
=
CHECK_FIELD_IGNORE
;
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
;
handler_items
=
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
;
...
...
@@ -138,7 +137,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
...
...
@@ -146,10 +144,11 @@ 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
));
bzero
((
char
*
)
&
transaction
.
mem_root
,
sizeof
(
transaction
.
mem_root
));
bzero
((
char
*
)
&
con_root
,
sizeof
(
con_root
));
bzero
((
char
*
)
&
warn_root
,
sizeof
(
warn_root
));
init_alloc_root
(
&
warn_root
,
WARN_ALLOC_BLOCK_SIZE
,
WARN_ALLOC_PREALLOC_SIZE
);
user_connect
=
(
USER_CONN
*
)
0
;
...
...
@@ -166,12 +165,6 @@ THD::THD():user_time(0), is_fatal_error(0),
else
bzero
((
char
*
)
&
user_var_events
,
sizeof
(
user_var_events
));
/* Prepared statements */
last_prepared_stmt
=
0
;
init_tree
(
&
prepared_statements
,
0
,
0
,
sizeof
(
PREP_STMT
),
(
qsort_cmp2
)
compare_prep_stmt
,
1
,
(
tree_element_free
)
free_prep_stmt
,
0
);
/* Protocol */
protocol
=
&
protocol_simple
;
// Default protocol
protocol_simple
.
init
(
this
);
...
...
@@ -189,7 +182,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
...
...
@@ -232,22 +227,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
...
...
@@ -276,7 +255,6 @@ void THD::cleanup(void)
{
DBUG_ENTER
(
"THD::cleanup"
);
ha_rollback
(
this
);
delete_tree
(
&
prepared_statements
);
if
(
locked_tables
)
{
lock
=
locked_tables
;
locked_tables
=
0
;
...
...
@@ -340,8 +318,6 @@ THD::~THD()
safeFree
(
user
);
safeFree
(
db
);
safeFree
(
ip
);
free_root
(
&
mem_root
,
MYF
(
0
));
free_root
(
&
con_root
,
MYF
(
0
));
free_root
(
&
warn_root
,
MYF
(
0
));
free_root
(
&
transaction
.
mem_root
,
MYF
(
0
));
mysys_var
=
0
;
// Safety (shouldn't be needed)
...
...
@@ -1193,6 +1169,102 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
return
0
;
}
/*
Statement functions
*/
Statement
::
Statement
(
THD
*
thd
)
:
id
(
++
thd
->
statement_id_counter
),
query_id
(
thd
->
query_id
),
set_query_id
(
1
),
allow_sum_func
(
0
),
command
(
thd
->
command
),
lex
(
&
main_lex
),
query
(
0
),
query_length
(
0
),
free_list
(
0
)
{
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
),
/* initialized later */
set_query_id
(
1
),
allow_sum_func
(
0
),
/* initialized later */
command
(
COM_SLEEP
),
/* initialized later */
lex
(
&
main_lex
),
query
(
0
),
/* these two are set */
query_length
(
0
),
/* in alloc_query() */
free_list
(
0
)
{
bzero
((
char
*
)
&
mem_root
,
sizeof
(
mem_root
));
}
Statement
::
Type
Statement
::
type
()
const
{
return
STATEMENT
;
}
void
Statement
::
set_statement
(
Statement
*
stmt
)
{
id
=
stmt
->
id
;
query_id
=
stmt
->
query_id
;
set_query_id
=
stmt
->
set_query_id
;
allow_sum_func
=
stmt
->
allow_sum_func
;
command
=
stmt
->
command
;
lex
=
stmt
->
lex
;
query
=
stmt
->
query
;
query_length
=
stmt
->
query_length
;
free_list
=
stmt
->
free_list
;
mem_root
=
stmt
->
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
;
}
static
void
delete_statement_as_hash_key
(
void
*
key
)
{
delete
(
Statement
*
)
key
;
}
C_MODE_END
Statement_map
::
Statement_map
()
:
last_found_statement
(
0
)
{
enum
{
START_HASH_SIZE
=
16
};
hash_init
(
&
st_hash
,
default_charset_info
,
START_HASH_SIZE
,
0
,
0
,
get_statement_id_as_hash_key
,
delete_statement_as_hash_key
,
MYF
(
0
));
}
bool
select_dumpvar
::
send_data
(
List
<
Item
>
&
items
)
{
List_iterator_fast
<
Item_func_set_user_var
>
li
(
vars
);
...
...
sql/sql_class.h
View file @
2a25b261
...
...
@@ -328,30 +328,6 @@ public:
};
/* This is a struct as it's allocated in tree_insert */
typedef
struct
st_prep_stmt
{
THD
*
thd
;
LEX
lex
;
Item_param
**
param
;
Item
*
free_list
;
MEM_ROOT
mem_root
;
String
*
query
;
ulong
stmt_id
;
uint
param_count
;
uint
last_errno
;
char
last_error
[
MYSQL_ERRMSG_SIZE
];
bool
error_in_prepare
,
long_data_used
;
bool
log_full_query
;
#ifndef EMBEDDED_LIBRARY
bool
(
*
setup_params
)(
st_prep_stmt
*
stmt
,
uchar
*
pos
,
uchar
*
read_pos
);
#else
bool
(
*
setup_params_data
)(
st_prep_stmt
*
stmt
);
#endif
}
PREP_STMT
;
class
delayed_insert
;
class
select_result
;
...
...
@@ -428,12 +404,158 @@ struct system_variables
};
void
free_tmp_table
(
THD
*
thd
,
TABLE
*
entry
);
class
Prepared_statement
;
/*
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
{
Statement
(
const
Statement
&
rhs
);
/* not implemented: */
Statement
&
operator
=
(
const
Statement
&
rhs
);
/* non-copyable */
public:
/* FIXME: must be private */
LEX
main_lex
;
public:
/*
Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be 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
;
public:
/* We build without RTTI, so dynamic_cast can't be used. */
enum
Type
{
STATEMENT
,
PREPARED_STATEMENT
};
/*
This constructor is called when statement is a subobject of THD:
some variables are initialized in THD::init due to locking problems
*/
Statement
();
Statement
(
THD
*
thd
);
virtual
~
Statement
();
/* Assign execution context (note: not all members) of given stmt to self */
void
set_statement
(
Statement
*
stmt
);
/* return class type */
virtual
Type
type
()
const
;
};
/*
Used to seek all existing statements in the connection
Deletes all statements in destructor.
*/
class
Statement_map
{
public:
Statement_map
();
int
insert
(
Statement
*
statement
)
{
int
rc
=
my_hash_insert
(
&
st_hash
,
(
byte
*
)
statement
);
if
(
rc
==
0
)
last_found_statement
=
statement
;
return
rc
;
}
Statement
*
find
(
ulong
id
)
{
if
(
last_found_statement
==
0
||
id
!=
last_found_statement
->
id
)
last_found_statement
=
(
Statement
*
)
hash_search
(
&
st_hash
,
(
byte
*
)
&
id
,
sizeof
(
id
));
return
last_found_statement
;
}
void
erase
(
Statement
*
statement
)
{
if
(
statement
==
last_found_statement
)
last_found_statement
=
0
;
hash_delete
(
&
st_hash
,
(
byte
*
)
statement
);
}
~
Statement_map
()
{
hash_free
(
&
st_hash
);
}
private:
HASH
st_hash
;
Statement
*
last_found_statement
;
};
/*
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
...
...
@@ -446,23 +568,25 @@ 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
con_root
;
// connection-life memory
MEM_ROOT
warn_root
;
// For warnings and errors
Protocol
*
protocol
;
// Current protocol
Protocol_simple
protocol_simple
;
// Normal protocol
Protocol_prep
protocol_prep
;
// Binary protocol
HASH
user_vars
;
// hash for user variables
TREE
prepared_statements
;
String
packet
;
// dynamic buffer for network I/O
struct
sockaddr_in
remote
;
// client socket address
struct
rand_struct
rand
;
// used for authentication
struct
system_variables
variables
;
// Changeable local variables
pthread_mutex_t
LOCK_delete
;
// Locked before thd is deleted
char
*
query
;
// Points to the current query,
/* all prepared statements and cursors of this connection */
Statement_map
stmt_map
;
/*
keeps THD state while it is used for active statement
Note, that double free_root() is safe, so we don't need to do any
special cleanup for it in THD destructor.
*/
Statement
stmt_backup
;
/*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
...
...
@@ -502,7 +626,6 @@ public:
and are still in use by this thread
*/
TABLE
*
open_tables
,
*
temporary_tables
,
*
handler_tables
,
*
derived_tables
;
// TODO: document the variables below
MYSQL_LOCK
*
lock
;
/* Current locks */
MYSQL_LOCK
*
locked_tables
;
/* Tables locked with LOCK */
/*
...
...
@@ -511,12 +634,10 @@ public:
chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
*/
ULL
*
ull
;
PREP_STMT
*
last_prepared_stmt
;
#ifndef DBUG_OFF
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
/*
...
...
@@ -549,7 +670,6 @@ public:
free_root
(
&
mem_root
,
MYF
(
MY_KEEP_PREALLOC
));
}
}
transaction
;
Item
*
free_list
,
*
handler_items
;
Field
*
dupp_field
;
#ifndef __WIN__
sigset_t
signals
,
block_signals
;
...
...
@@ -580,18 +700,25 @@ public:
USER_CONN
*
user_connect
;
CHARSET_INFO
*
db_charset
;
List
<
TABLE
>
temporary_tables_should_be_free
;
// list of temporary tables
/*
FIXME: this, and some other variables like 'count_cuted_fields'
maybe should be statement/cursor local, that is, moved to Statement
class. With current implementation warnings produced in each prepared
statement/cursor settle here.
*/
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
,
system_thread
;
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 */
...
...
@@ -604,9 +731,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
in_lock_tables
,
global_read_lock
;
bool
query_error
,
bootstrap
,
cleanup_done
;
...
...
@@ -634,7 +761,6 @@ public:
void
init
(
void
);
void
change_user
(
void
);
void
init_for_queries
();
void
cleanup
(
void
);
bool
store_globals
();
#ifdef SIGNAL_WITH_VIO_CLOSE
...
...
sql/sql_parse.cc
View file @
2a25b261
...
...
@@ -974,7 +974,6 @@ pthread_handler_decl(handle_one_connection,arg)
thd
->
proc_info
=
0
;
thd
->
set_time
();
thd
->
init_for_queries
();
while
(
!
net
->
error
&&
net
->
vio
!=
0
&&
!
thd
->
killed
)
{
if
(
do_command
(
thd
))
...
...
@@ -1055,7 +1054,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
);
...
...
@@ -1221,13 +1219,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
));
...
...
sql/sql_prepare.cc
View file @
2a25b261
...
...
@@ -71,127 +71,110 @@ Long data handling:
#include "sql_acl.h"
#include "sql_select.h" // for JOIN
#include <m_ctype.h> // for isspace()
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
#endif
#define IS_PARAM_NULL(pos, param_no) (pos[param_no/8] & (1 << (param_no & 7)))
const
String
my_null_string
(
"NULL"
,
4
,
default_charset_info
);
#define STMT_QUERY_LOG_LENGTH 8192
/******************************************************************************
Prepared_statement: statement which can contain placeholders
******************************************************************************/
#ifdef EMBEDDED_LIBRARY
#define SETUP_PARAM_FUNCTION(fn_name) \
static void fn_name(Item_param *param, uchar **pos, ulong data_len)
class
Prepared_statement
:
public
Statement
{
public:
THD
*
thd
;
Item_param
**
param
;
/* array of all placeholders */
uint
param_count
;
uint
last_errno
;
char
last_error
[
MYSQL_ERRMSG_SIZE
];
bool
error_in_prepare
,
long_data_used
;
bool
log_full_query
;
#ifndef EMBEDDED_LIBRARY
bool
(
*
setup_params
)(
Prepared_statement
*
st
,
uchar
*
pos
,
uchar
*
read_pos
);
#else
#define SETUP_PARAM_FUNCTION(fn_name) \
static void fn_name(Item_param *param, uchar **pos)
bool
(
*
setup_params_data
)(
Prepared_statement
*
st
);
#endif
public:
Prepared_statement
(
THD
*
thd_arg
);
virtual
~
Prepared_statement
();
virtual
Statement
::
Type
type
()
const
;
};
String
my_null_string
(
"NULL"
,
4
,
default_charset_info
);
/*
Find prepared statement in thd
/******************************************************************************
Implementation
******************************************************************************/
SYNOPSIS
find_prepared_statement()
thd Thread handler
stmt_id Statement id server specified to the client on prepare
RETURN VALUES
0 error. In this case the error is sent with my_error()
ptr Pointer to statement
*/
static
PREP_STMT
*
find_prepared_statement
(
THD
*
thd
,
ulong
stmt_id
,
const
char
*
when
)
inline
bool
is_param_null
(
const
uchar
*
pos
,
ulong
param_no
)
{
PREP_STMT
*
stmt
;
DBUG_ENTER
(
"find_prepared_statement"
);
DBUG_PRINT
(
"enter"
,(
"stmt_id: %d"
,
stmt_id
));
if
(
thd
->
last_prepared_stmt
&&
thd
->
last_prepared_stmt
->
stmt_id
==
stmt_id
)
DBUG_RETURN
(
thd
->
last_prepared_stmt
);
if
((
stmt
=
(
PREP_STMT
*
)
tree_search
(
&
thd
->
prepared_statements
,
&
stmt_id
,
(
void
*
)
0
)))
DBUG_RETURN
(
thd
->
last_prepared_stmt
=
stmt
);
my_error
(
ER_UNKNOWN_STMT_HANDLER
,
MYF
(
0
),
stmt_id
,
when
);
DBUG_RETURN
(
0
);
return
pos
[
param_no
/
8
]
&
(
1
<<
(
param_no
&
7
));
}
/*
Compare two prepared statements; Used to find a prepared statement
*/
enum
{
STMT_QUERY_LOG_LENGTH
=
8192
};
int
compare_prep_stmt
(
void
*
not_used
,
PREP_STMT
*
stmt
,
ulong
*
key
)
{
return
(
stmt
->
stmt_id
==
*
key
)
?
0
:
(
stmt
->
stmt_id
<
*
key
)
?
-
1
:
1
;
}
#ifdef EMBEDDED_LIBRARY
#define SETUP_PARAM_FUNCTION(fn_name) \
static void fn_name(Item_param *param, uchar **pos, ulong data_len)
#else
#define SETUP_PARAM_FUNCTION(fn_name) \
static void fn_name(Item_param *param, uchar **pos)
#endif
/*
Free prepared statement.
SYNOPSIS
standard tree_element_free function.
DESCRIPTION
We don't have to free the stmt itself as this was stored in the tree
and will be freed when the node is deleted
Seek prepared statement in statement map by id: returns zero if statement
was not found, pointer otherwise.
*/
void
free_prep_stmt
(
PREP_STMT
*
stmt
,
TREE_FREE
mode
,
void
*
not_used
)
{
my_free
((
char
*
)
stmt
->
param
,
MYF
(
MY_ALLOW_ZERO_PTR
));
if
(
stmt
->
query
)
stmt
->
query
->
free
();
free_items
(
stmt
->
free_list
);
free_root
(
&
stmt
->
mem_root
,
MYF
(
0
));
static
Prepared_statement
*
find_prepared_statement
(
THD
*
thd
,
ulong
id
,
const
char
*
where
)
{
Statement
*
stmt
=
thd
->
stmt_map
.
find
(
id
);
if
(
stmt
==
0
||
stmt
->
type
()
!=
Statement
::
PREPARED_STATEMENT
)
{
my_error
(
ER_UNKNOWN_STMT_HANDLER
,
MYF
(
0
),
id
,
where
);
send_error
(
thd
);
return
0
;
}
return
(
Prepared_statement
*
)
stmt
;
}
/*
Send prepared stmt info to client after prepare
*/
#ifndef EMBEDDED_LIBRARY
static
bool
send_prep_stmt
(
P
REP_STMT
*
stmt
,
uint
columns
)
static
bool
send_prep_stmt
(
P
repared_statement
*
stmt
,
uint
columns
)
{
NET
*
net
=
&
stmt
->
thd
->
net
;
NET
*
net
=
&
stmt
->
thd
->
net
;
char
buff
[
9
];
buff
[
0
]
=
0
;
int4store
(
buff
+
1
,
stmt
->
stmt_
id
);
int4store
(
buff
+
1
,
stmt
->
id
);
int2store
(
buff
+
5
,
columns
);
int2store
(
buff
+
7
,
stmt
->
param_count
);
/* This should be fixed to work with prepared statements
*/
/* This should be fixed to work with prepared statements */
return
(
my_net_write
(
net
,
buff
,
sizeof
(
buff
))
||
net_flush
(
net
));
}
#else
static
bool
send_prep_stmt
(
PREP_STMT
*
stmt
,
uint
columns
__attribute__
((
unused
)))
static
bool
send_prep_stmt
(
Prepared_statement
*
stmt
,
uint
columns
__attribute__
((
unused
)))
{
THD
*
thd
=
stmt
->
thd
;
thd
->
client_stmt_id
=
stmt
->
stmt_
id
;
thd
->
client_stmt_id
=
stmt
->
id
;
thd
->
client_param_count
=
stmt
->
param_count
;
thd
->
net
.
last_errno
=
0
;
return
0
;
}
#endif
/*!EMBEDDED_LIBRAYR*/
/*
Send information about all item parameters
#endif
/*!EMBEDDED_LIBRARY*/
TODO: Not yet ready
*/
static
bool
send_item_params
(
PREP_STMT
*
stmt
)
{
#if 0
char buff[1];
buff[0]=0;
if (my_net_write(&stmt->thd->net, buff, sizeof(buff)))
return 1;
send_eof(stmt->thd);
#endif
return
0
;
}
/*
Read the length of the parameter data and retun back to
...
...
@@ -418,17 +401,20 @@ void setup_param_functions(Item_param *param, uchar param_type)
and if binary/update log is set, generate the valid query.
*/
static
bool
insert_params_withlog
(
PREP_STMT
*
stmt
,
uchar
*
pos
,
uchar
*
read_pos
)
static
bool
insert_params_withlog
(
Prepared_statement
*
stmt
,
uchar
*
pos
,
uchar
*
read_pos
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
thd
->
lex
->
param_list
;
List
<
Item
>
&
params
=
stmt
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
DBUG_ENTER
(
"insert_params_withlog"
);
String
str
,
query
,
*
res
;
String
str
,
query
;
const
String
*
res
;
DBUG_ENTER
(
"insert_params_withlog"
);
if
(
query
.
copy
(
*
stmt
->
query
))
if
(
query
.
copy
(
stmt
->
query
,
stmt
->
query_length
,
default_charset_info
))
DBUG_RETURN
(
1
);
ulong
param_no
=
0
;
...
...
@@ -438,10 +424,9 @@ static bool insert_params_withlog(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
{
if
(
param
->
long_data_supplied
)
res
=
param
->
query_val_str
(
&
str
);
else
{
if
(
IS_PARAM_NULL
(
pos
,
param_no
))
if
(
is_param_null
(
pos
,
param_no
))
{
param
->
maybe_null
=
param
->
null_value
=
1
;
res
=
&
my_null_string
;
...
...
@@ -461,23 +446,26 @@ static bool insert_params_withlog(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
}
if
(
alloc_query
(
thd
,
(
char
*
)
query
.
ptr
(),
query
.
length
()
+
1
))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
0
);
}
static
bool
insert_params
(
PREP_STMT
*
stmt
,
uchar
*
pos
,
uchar
*
read_pos
)
static
bool
insert_params
(
Prepared_statement
*
stmt
,
uchar
*
pos
,
uchar
*
read_pos
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
thd
->
lex
->
param_list
;
List
<
Item
>
&
params
=
stmt
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
DBUG_ENTER
(
"insert_params"
);
ulong
param_no
=
0
;
DBUG_ENTER
(
"insert_params"
);
while
((
param
=
(
Item_param
*
)
param_iterator
++
))
{
if
(
!
param
->
long_data_supplied
)
{
if
(
IS_PARAM_NULL
(
pos
,
param_no
))
if
(
is_param_null
(
pos
,
param_no
))
param
->
maybe_null
=
param
->
null_value
=
1
;
else
{
...
...
@@ -490,17 +478,18 @@ static bool insert_params(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
DBUG_RETURN
(
0
);
}
static
bool
setup_params_data
(
P
REP_STMT
*
stmt
)
static
bool
setup_params_data
(
P
repared_statement
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
thd
->
lex
->
param_list
;
List
<
Item
>
&
params
=
stmt
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
DBUG_ENTER
(
"setup_params_data"
);
uchar
*
pos
=
(
uchar
*
)
thd
->
net
.
read_pos
+
1
+
MYSQL_STMT_HEADER
;
//skip header
uchar
*
pos
=
(
uchar
*
)
stmt
->
thd
->
net
.
read_pos
+
1
+
MYSQL_STMT_HEADER
;
//skip header
uchar
*
read_pos
=
pos
+
(
stmt
->
param_count
+
7
)
/
8
;
//skip null bits
DBUG_ENTER
(
"setup_params_data"
);
if
(
*
read_pos
++
)
//types supplied / first execute
{
/*
...
...
@@ -518,6 +507,91 @@ static bool setup_params_data(PREP_STMT *stmt)
DBUG_RETURN
(
0
);
}
#else
bool
setup_params_data
(
Prepared_statement
*
stmt
)
{
List
<
Item
>
&
params
=
stmt
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
MYSQL_BIND
*
client_param
=
stmt
->
thd
->
client_params
;
DBUG_ENTER
(
"setup_params_data"
);
for
(;(
param
=
(
Item_param
*
)
param_iterator
++
);
client_param
++
)
{
setup_param_functions
(
param
,
client_param
->
buffer_type
);
if
(
!
param
->
long_data_supplied
)
{
if
(
*
client_param
->
is_null
)
param
->
maybe_null
=
param
->
null_value
=
1
;
else
{
uchar
*
buff
=
(
uchar
*
)
client_param
->
buffer
;
param
->
maybe_null
=
param
->
null_value
=
0
;
param
->
setup_param_func
(
param
,
&
buff
,
client_param
->
length
?
*
client_param
->
length
:
client_param
->
buffer_length
);
}
}
}
DBUG_RETURN
(
0
);
}
bool
setup_params_data_withlog
(
Prepared_statement
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
stmt
->
lex
->
param_list
;
List_iterator
<
Item
>
param_iterator
(
params
);
Item_param
*
param
;
MYSQL_BIND
*
client_param
=
thd
->
client_params
;
String
str
,
query
;
const
String
*
res
;
DBUG_ENTER
(
"setup_params_data_withlog"
);
if
(
query
.
copy
(
stmt
->
query
,
stmt
->
query_length
,
default_charset_info
))
DBUG_RETURN
(
1
);
uint32
length
=
0
;
for
(;(
param
=
(
Item_param
*
)
param_iterator
++
);
client_param
++
)
{
setup_param_functions
(
param
,
client_param
->
buffer_type
);
if
(
param
->
long_data_supplied
)
res
=
param
->
query_val_str
(
&
str
);
else
{
if
(
*
client_param
->
is_null
)
{
param
->
maybe_null
=
param
->
null_value
=
1
;
res
=
&
my_null_string
;
}
else
{
uchar
*
buff
=
(
uchar
*
)
client_param
->
buffer
;
param
->
maybe_null
=
param
->
null_value
=
0
;
param
->
setup_param_func
(
param
,
&
buff
,
client_param
->
length
?
*
client_param
->
length
:
client_param
->
buffer_length
);
res
=
param
->
query_val_str
(
&
str
);
}
}
if
(
query
.
replace
(
param
->
pos_in_query
+
length
,
1
,
*
res
))
DBUG_RETURN
(
1
);
length
+=
res
->
length
()
-
1
;
}
if
(
alloc_query
(
thd
,
(
char
*
)
query
.
ptr
(),
query
.
length
()
+
1
))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
0
);
}
#endif
/*!EMBEDDED_LIBRARY*/
/*
...
...
@@ -526,7 +600,7 @@ static bool setup_params_data(PREP_STMT *stmt)
- fields count
*/
static
bool
mysql_test_insert_fields
(
P
REP_STMT
*
stmt
,
static
bool
mysql_test_insert_fields
(
P
repared_statement
*
stmt
,
TABLE_LIST
*
table_list
,
List
<
Item
>
&
fields
,
List
<
List_item
>
&
values_list
)
...
...
@@ -535,18 +609,18 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
TABLE
*
table
;
List_iterator_fast
<
List_item
>
its
(
values_list
);
List_item
*
values
;
DBUG_ENTER
(
"mysql_test_insert_fields"
);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
my_bool
update
=
(
thd
->
lex
->
value_list
.
elements
?
UPDATE_ACL
:
0
);
ulong
privilege
=
(
thd
->
lex
->
duplicates
==
DUP_REPLACE
?
my_bool
update
=
(
stmt
->
lex
->
value_list
.
elements
?
UPDATE_ACL
:
0
);
ulong
privilege
=
(
stmt
->
lex
->
duplicates
==
DUP_REPLACE
?
INSERT_ACL
|
DELETE_ACL
:
INSERT_ACL
|
update
);
if
(
check_access
(
thd
,
privilege
,
table_list
->
db
,
&
table_list
->
grant
.
privilege
,
0
,
0
)
||
(
grant_option
&&
check_grant
(
thd
,
privilege
,
table_list
,
0
,
0
)))
DBUG_RETURN
(
1
);
#endif
#endif
if
(
open_and_lock_tables
(
thd
,
table_list
))
DBUG_RETURN
(
1
);
table
=
table_list
->
table
;
...
...
@@ -574,7 +648,7 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
}
}
}
if
(
send_prep_stmt
(
stmt
,
0
)
||
send_item_params
(
stmt
)
)
if
(
send_prep_stmt
(
stmt
,
0
))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
0
);
}
...
...
@@ -589,13 +663,14 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
and return no fields information back to client.
*/
static
bool
mysql_test_upd_fields
(
PREP_STMT
*
stmt
,
TABLE_LIST
*
table_list
,
static
bool
mysql_test_upd_fields
(
Prepared_statement
*
stmt
,
TABLE_LIST
*
table_list
,
List
<
Item
>
&
fields
,
List
<
Item
>
&
values
,
COND
*
conds
)
{
THD
*
thd
=
stmt
->
thd
;
DBUG_ENTER
(
"mysql_test_upd_fields"
);
DBUG_ENTER
(
"mysql_test_upd_fields"
);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if
(
check_access
(
thd
,
UPDATE_ACL
,
table_list
->
db
,
&
table_list
->
grant
.
privilege
,
0
,
0
)
||
...
...
@@ -613,7 +688,7 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
Currently return only column list info only, and we are not
sending any info on where clause.
*/
if
(
send_prep_stmt
(
stmt
,
0
)
||
send_item_params
(
stmt
)
)
if
(
send_prep_stmt
(
stmt
,
0
))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
0
);
}
...
...
@@ -630,7 +705,9 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
And send column list fields info back to client.
*/
static
bool
mysql_test_select_fields
(
PREP_STMT
*
stmt
,
TABLE_LIST
*
tables
,
static
bool
mysql_test_select_fields
(
Prepared_statement
*
stmt
,
TABLE_LIST
*
tables
,
uint
wild_num
,
List
<
Item
>
&
fields
,
COND
*
conds
,
uint
og_num
,
ORDER
*
order
,
ORDER
*
group
,
...
...
@@ -640,8 +717,9 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
SELECT_LEX
*
select_lex
)
{
THD
*
thd
=
stmt
->
thd
;
LEX
*
lex
=
&
thd
->
main_lex
;
select_result
*
result
=
thd
->
lex
->
result
;
LEX
*
lex
=
stmt
->
lex
;
select_result
*
result
=
lex
->
result
;
DBUG_ENTER
(
"mysql_test_select_fields"
);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
...
...
@@ -663,12 +741,12 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
if
(
lex
->
describe
)
{
if
(
send_prep_stmt
(
stmt
,
0
)
||
send_item_params
(
stmt
)
)
if
(
send_prep_stmt
(
stmt
,
0
))
DBUG_RETURN
(
1
);
}
}
else
{
fix_tables_pointers
(
thd
->
lex
->
all_selects_list
);
fix_tables_pointers
(
lex
->
all_selects_list
);
if
(
!
result
&&
!
(
result
=
new
select_send
()))
{
send_error
(
thd
,
ER_OUT_OF_RESOURCES
);
...
...
@@ -683,11 +761,11 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
select_lex
,
unit
))
DBUG_RETURN
(
1
);
if
(
send_prep_stmt
(
stmt
,
fields
.
elements
)
||
thd
->
protocol_simple
.
send_fields
(
&
fields
,
0
)
||
thd
->
protocol_simple
.
send_fields
(
&
fields
,
0
)
#ifndef EMBEDDED_LIBRARY
net_flush
(
&
thd
->
net
)
||
||
net_flush
(
&
thd
->
net
)
#endif
send_item_params
(
stmt
)
)
)
DBUG_RETURN
(
1
);
join
->
cleanup
();
}
...
...
@@ -699,19 +777,18 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
Send the prepare query results back to client
*/
static
bool
send_prepare_results
(
P
REP_STMT
*
stmt
)
static
bool
send_prepare_results
(
P
repared_statement
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
LEX
*
lex
=
&
thd
->
main_lex
;
enum
enum_sql_command
sql_command
=
thd
->
lex
->
sql_command
;
LEX
*
lex
=
stmt
->
lex
;
enum
enum_sql_command
sql_command
=
lex
->
sql_command
;
DBUG_ENTER
(
"send_prepare_results"
);
DBUG_PRINT
(
"enter"
,(
"command: %d, param_count: %ld"
,
sql_command
,
lex
->
param_count
));
/* Setup prepared stmt */
stmt
->
param_count
=
lex
->
param_count
;
stmt
->
free_list
=
thd
->
free_list
;
// Save items used in stmt
thd
->
free_list
=
0
;
SELECT_LEX
*
select_lex
=
&
lex
->
select_lex
;
TABLE_LIST
*
tables
=
(
TABLE_LIST
*
)
select_lex
->
table_list
.
first
;
...
...
@@ -768,57 +845,14 @@ abort:
DBUG_RETURN
(
1
);
}
/*
Parse the prepare query
*/
static
bool
parse_prepare_query
(
PREP_STMT
*
stmt
,
char
*
packet
,
uint
length
)
{
bool
error
=
1
;
THD
*
thd
=
stmt
->
thd
;
DBUG_ENTER
(
"parse_prepare_query"
);
mysql_log
.
write
(
thd
,
COM_PREPARE
,
"%s"
,
packet
);
mysql_init_query
(
thd
);
LEX
*
lex
=
lex_start
(
thd
,
(
uchar
*
)
packet
,
length
);
lex
->
safe_to_cache_query
=
0
;
thd
->
lex
->
param_count
=
0
;
if
(
!
yyparse
((
void
*
)
thd
)
&&
!
thd
->
is_fatal_error
)
error
=
send_prepare_results
(
stmt
);
lex_end
(
lex
);
DBUG_RETURN
(
error
);
}
/*
Initialize parameter items in statement
*/
static
bool
init_param_items
(
P
REP_STMT
*
stmt
)
static
bool
init_param_items
(
P
repared_statement
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
List
<
Item
>
&
params
=
thd
->
lex
->
param_list
;
Item_param
**
to
;
uint32
length
=
thd
->
query_length
;
stmt
->
lex
=
thd
->
main_lex
;
if
(
mysql_bin_log
.
is_open
()
||
mysql_update_log
.
is_open
())
{
stmt
->
log_full_query
=
1
;
#ifndef EMBEDDED_LIBRARY
stmt
->
setup_params
=
insert_params_withlog
;
#else
stmt
->
setup_params_data
=
setup_params_data_withlog
;
#endif
}
else
#ifndef EMBEDDED_LIBRARY
stmt
->
setup_params
=
insert_params
;
// not fully qualified query
#else
stmt
->
setup_params_data
=
setup_params_data
;
#endif
if
(
!
stmt
->
param_count
)
stmt
->
param
=
(
Item_param
**
)
0
;
else
...
...
@@ -828,44 +862,12 @@ static bool init_param_items(PREP_STMT *stmt)
MYF
(
MY_WME
))))
return
1
;
if
(
stmt
->
log_full_query
)
{
length
=
thd
->
query_length
+
(
stmt
->
param_count
*
2
)
+
1
;
if
(
length
<
STMT_QUERY_LOG_LENGTH
)
length
=
STMT_QUERY_LOG_LENGTH
;
}
List_iterator
<
Item
>
param_iterator
(
params
);
List_iterator
<
Item
>
param_iterator
(
stmt
->
lex
->
param_list
);
while
((
*
(
to
++
)
=
(
Item_param
*
)
param_iterator
++
));
}
stmt
->
query
=
new
String
(
length
);
stmt
->
query
->
copy
(
thd
->
query
,
thd
->
query_length
,
default_charset_info
);
return
0
;
}
/*
Initialize stmt execution
*/
static
void
init_stmt_execute
(
PREP_STMT
*
stmt
)
{
THD
*
thd
=
stmt
->
thd
;
TABLE_LIST
*
tables
=
(
TABLE_LIST
*
)
thd
->
lex
->
select_lex
.
table_list
.
first
;
/*
TODO: When the new table structure is ready, then have a status bit
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
for
(;
tables
;
tables
=
tables
->
next
)
tables
->
table
=
0
;
//safety - nasty init
if
(
!
(
stmt
->
log_full_query
&&
stmt
->
param_count
))
{
thd
->
query
=
stmt
->
query
->
c_ptr
();
thd
->
query_length
=
stmt
->
query
->
length
();
}
}
/*
Parse the query and send the total number of parameters
...
...
@@ -877,58 +879,73 @@ static void init_stmt_execute(PREP_STMT *stmt)
If parameter markers are found in the query, then store
the information using Item_param along with maintaining a
list in lex->param_list, so that a fast and direct
retriev
e
al can be made without going through all field
retrieval can be made without going through all field
items.
*/
bool
mysql_stmt_prepare
(
THD
*
thd
,
char
*
packet
,
uint
packet_length
)
{
MEM_ROOT
thd_root
=
thd
->
mem_root
;
P
REP_STMT
stmt
;
SELECT_LEX
*
sl
;
LEX
*
lex
;
P
repared_statement
*
stmt
=
new
Prepared_statement
(
thd
)
;
DBUG_ENTER
(
"mysql_stmt_prepare"
);
bzero
((
char
*
)
&
stmt
,
sizeof
(
stmt
));
stmt
.
stmt_id
=
++
thd
->
current_stmt_id
;
init_sql_alloc
(
&
stmt
.
mem_root
,
thd
->
variables
.
query_alloc_block_size
,
thd
->
variables
.
query_prealloc_size
);
stmt
.
thd
=
thd
;
stmt
.
thd
->
mem_root
=
stmt
.
mem_root
;
if
(
stmt
==
0
)
DBUG_RETURN
(
0
);
if
(
thd
->
stmt_map
.
insert
(
stmt
))
goto
insert_stmt_err
;
if
(
alloc_query
(
stmt
.
thd
,
packet
,
packet_length
))
goto
err
;
thd
->
stmt_backup
.
set_statement
(
thd
);
thd
->
set_statement
(
stmt
)
;
if
(
parse_prepare_query
(
&
stmt
,
thd
->
query
,
thd
->
query_length
))
goto
err
;
if
(
alloc_query
(
thd
,
packet
,
packet_length
))
goto
alloc_query_err
;
mysql_log
.
write
(
thd
,
COM_PREPARE
,
"%s"
,
packet
);
lex
=
lex_start
(
thd
,
(
uchar
*
)
thd
->
query
,
thd
->
query_length
);
mysql_init_query
(
thd
);
lex
->
safe_to_cache_query
=
0
;
lex
->
param_count
=
0
;
if
(
yyparse
((
void
*
)
thd
)
||
thd
->
is_fatal_error
||
send_prepare_results
(
stmt
))
goto
yyparse_err
;
lex_end
(
lex
);
if
(
!
(
specialflag
&
SPECIAL_NO_PRIOR
))
my_pthread_setprio
(
pthread_self
(),
WAIT_PRIOR
);
// save WHERE clause pointers to avoid damaging they by optimisation
for
(
sl
=
thd
->
lex
->
all_selects_list
;
for
(
SELECT_LEX
*
sl
=
thd
->
lex
->
all_selects_list
;
sl
;
sl
=
sl
->
next_select_in_list
())
{
sl
->
prep_where
=
sl
->
where
;
}
if
(
init_param_items
(
&
stmt
))
goto
err
;
stmt
->
set_statement
(
thd
);
thd
->
set_statement
(
&
thd
->
stmt_backup
);
if
(
init_param_items
(
stmt
))
goto
init_param_err
;
stmt
->
command
=
COM_EXECUTE
;
// set it only once here
stmt
.
mem_root
=
stmt
.
thd
->
mem_root
;
tree_insert
(
&
thd
->
prepared_statements
,
(
void
*
)
&
stmt
,
0
,
(
void
*
)
0
);
thd
->
mem_root
=
thd_root
;
// restore main mem_root
DBUG_RETURN
(
0
);
err:
stmt
.
mem_root
=
stmt
.
thd
->
mem_root
;
free_prep_stmt
(
&
stmt
,
free_free
,
(
void
*
)
0
);
thd
->
mem_root
=
thd_root
;
// restore main mem_root
yyparse_err:
lex_end
(
lex
);
stmt
->
set_statement
(
thd
);
thd
->
set_statement
(
&
thd
->
stmt_backup
);
init_param_err:
alloc_query_err:
/* Statement map deletes statement on erase */
thd
->
stmt_map
.
erase
(
stmt
);
DBUG_RETURN
(
1
);
insert_stmt_err:
delete
stmt
;
DBUG_RETURN
(
1
);
}
...
...
@@ -936,7 +953,7 @@ err:
/*
Executes previously prepared query
If there is any parameters
(thd
->param_count), then replace
If there is any parameters
(stmt
->param_count), then replace
markers with the data supplied from client, and then
execute the query
*/
...
...
@@ -944,15 +961,12 @@ err:
void
mysql_stmt_execute
(
THD
*
thd
,
char
*
packet
)
{
ulong
stmt_id
=
uint4korr
(
packet
);
PREP_STMT
*
stmt
;
SELECT_LEX
*
sl
;
DBUG_ENTER
(
"mysql_stmt_execute"
);
Prepared_statement
*
stmt
;
if
(
!
(
stmt
=
find_prepared_statement
(
thd
,
stmt_id
,
"execute"
)))
{
send_error
(
thd
);
DBUG_ENTER
(
"mysql_stmt_execute"
);
if
(
!
(
stmt
=
find_prepared_statement
(
thd
,
stmt_id
,
"execute"
)))
DBUG_VOID_RETURN
;
}
/* Check if we got an error when sending long data */
if
(
stmt
->
error_in_prepare
)
...
...
@@ -961,10 +975,28 @@ void mysql_stmt_execute(THD *thd, char *packet)
DBUG_VOID_RETURN
;
}
LEX
thd_lex
=
thd
->
main_lex
;
thd
->
main_lex
=
stmt
->
lex
;
for
(
sl
=
stmt
->
lex
.
all_selects_list
;
/*
XXX: while thd->query_id is incremented for each command, stmt->query_id
holds query_id of prepare stage. Keeping old query_id seems to be more
natural, but differs from the way prepared statements work in 4.1:
*/
/* stmt->query_id= thd->query_id; */
thd
->
stmt_backup
.
set_statement
(
thd
);
thd
->
set_statement
(
stmt
);
/*
To make sure that all runtime data is stored in its own memory root and
does not interfere with data possibly present in thd->mem_root.
This root is cleaned up in the end of execution.
FIXME: to be replaced with more efficient approach, and verified why we
can not use thd->mem_root safely.
*/
init_sql_alloc
(
&
thd
->
mem_root
,
thd
->
variables
.
query_alloc_block_size
,
thd
->
variables
.
query_prealloc_size
);
for
(
SELECT_LEX
*
sl
=
stmt
->
lex
->
all_selects_list
;
sl
;
sl
=
sl
->
next_select_in_list
())
{
...
...
@@ -975,7 +1007,16 @@ void mysql_stmt_execute(THD *thd, char *packet)
sl
->
where
=
sl
->
prep_where
->
copy_andor_structure
(
thd
);
DBUG_ASSERT
(
sl
->
join
==
0
);
}
init_stmt_execute
(
stmt
);
/*
TODO: When the new table structure is ready, then have a status bit
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
for
(
TABLE_LIST
*
tables
=
(
TABLE_LIST
*
)
stmt
->
lex
->
select_lex
.
table_list
.
first
;
tables
;
tables
=
tables
->
next
)
tables
->
table
=
0
;
// safety - nasty init
#ifndef EMBEDDED_LIBRARY
if
(
stmt
->
param_count
&&
setup_params_data
(
stmt
))
...
...
@@ -1001,7 +1042,8 @@ void mysql_stmt_execute(THD *thd, char *packet)
if
(
!
(
specialflag
&
SPECIAL_NO_PRIOR
))
my_pthread_setprio
(
pthread_self
(),
WAIT_PRIOR
);
thd
->
main_lex
=
thd_lex
;
free_root
(
&
thd
->
mem_root
,
MYF
(
0
));
thd
->
set_statement
(
&
thd
->
stmt_backup
);
DBUG_VOID_RETURN
;
}
...
...
@@ -1023,14 +1065,12 @@ void mysql_stmt_execute(THD *thd, char *packet)
void
mysql_stmt_reset
(
THD
*
thd
,
char
*
packet
)
{
ulong
stmt_id
=
uint4korr
(
packet
);
PREP_STMT
*
stmt
;
Prepared_statement
*
stmt
;
DBUG_ENTER
(
"mysql_stmt_reset"
);
if
(
!
(
stmt
=
find_prepared_statement
(
thd
,
stmt_id
,
"reset"
)))
{
send_error
(
thd
);
DBUG_VOID_RETURN
;
}
stmt
->
error_in_prepare
=
0
;
Item_param
*
item
=
*
stmt
->
param
,
*
end
=
item
+
stmt
->
param_count
;
...
...
@@ -1053,15 +1093,15 @@ void mysql_stmt_reset(THD *thd, char *packet)
void
mysql_stmt_free
(
THD
*
thd
,
char
*
packet
)
{
ulong
stmt_id
=
uint4korr
(
packet
);
Prepared_statement
*
stmt
;
DBUG_ENTER
(
"mysql_stmt_free"
);
if
(
!
find_prepared_statement
(
thd
,
stmt_id
,
"close"
))
{
send_error
(
thd
);
// Not seen by the client
if
(
!
(
stmt
=
find_prepared_statement
(
thd
,
stmt_id
,
"close"
)))
DBUG_VOID_RETURN
;
}
tree_delete
(
&
thd
->
prepared_statements
,
(
void
*
)
&
stmt_id
,
(
void
*
)
0
);
thd
->
last_prepared_stmt
=
(
PREP_STMT
*
)
0
;
/* Statement map deletes statement on erase */
thd
->
stmt_map
.
erase
(
stmt
)
;
DBUG_VOID_RETURN
;
}
...
...
@@ -1087,7 +1127,8 @@ void mysql_stmt_free(THD *thd, char *packet)
void
mysql_stmt_get_longdata
(
THD
*
thd
,
char
*
pos
,
ulong
packet_length
)
{
PREP_STMT
*
stmt
;
Prepared_statement
*
stmt
;
DBUG_ENTER
(
"mysql_stmt_get_longdata"
);
#ifndef EMBEDDED_LIBRARY
...
...
@@ -1103,14 +1144,7 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
uint
param_number
=
uint2korr
(
pos
+
4
);
if
(
!
(
stmt
=
find_prepared_statement
(
thd
,
stmt_id
,
"get_longdata"
)))
{
/*
There is a chance that the client will never see this as
it doesn't expect an answer from this call...
*/
send_error
(
thd
);
DBUG_VOID_RETURN
;
}
#ifndef EMBEDDED_LIBRARY
if
(
param_number
>=
stmt
->
param_count
)
...
...
@@ -1134,3 +1168,46 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
DBUG_VOID_RETURN
;
}
Prepared_statement
::
Prepared_statement
(
THD
*
thd_arg
)
:
Statement
(
thd_arg
),
thd
(
thd_arg
),
param
(
0
),
param_count
(
0
),
last_errno
(
0
),
error_in_prepare
(
0
),
long_data_used
(
0
),
log_full_query
(
0
)
{
*
last_error
=
'\0'
;
if
(
mysql_bin_log
.
is_open
())
{
log_full_query
=
1
;
#ifndef EMBEDDED_LIBRARY
setup_params
=
insert_params_withlog
;
#else
setup_params_data
=
setup_params_data_withlog
;
#endif
}
else
#ifndef EMBEDDED_LIBRARY
setup_params
=
insert_params
;
// not fully qualified query
#else
setup_params_data
=
setup_params_data
;
#endif
}
Prepared_statement
::~
Prepared_statement
()
{
my_free
((
char
*
)
param
,
MYF
(
MY_ALLOW_ZERO_PTR
));
free_items
(
free_list
);
}
Statement
::
Type
Prepared_statement
::
type
()
const
{
return
PREPARED_STATEMENT
;
}
tests/client_test.c
View file @
2a25b261
...
...
@@ -7350,7 +7350,7 @@ static void test_fetch_column()
rc
=
mysql_query
(
mysql
,
"insert into test_column(c2) values('venu'),('mysql')"
);
myquery
(
rc
);
stmt
=
mysql_prepare
(
mysql
,
"select * from test_column
"
,
50
);
stmt
=
mysql_prepare
(
mysql
,
"select * from test_column
order by c2 desc"
,
50
);
mystmt_init
(
stmt
);
bind
[
0
].
buffer_type
=
MYSQL_TYPE_LONG
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment