diff options
-rw-r--r-- | mysql-test/r/ps.result | 130 | ||||
-rw-r--r-- | mysql-test/t/ps.test | 26 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 25 | ||||
-rw-r--r-- | sql/sql_class.h | 10 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 11 |
6 files changed, 159 insertions, 45 deletions
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 9afbca9dcb1..b29185eaaea 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -108,6 +108,9 @@ set @fvar= 123.4567; prepare stmt1 from @fvar; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '123.4567' at line 1 drop table t1,t2; +deallocate prepare stmt3; +deallocate prepare stmt4; +deallocate prepare stmt5; PREPARE stmt1 FROM "select _utf8 'A' collate utf8_bin = ?"; set @var='A'; EXECUTE stmt1 USING @var; @@ -253,6 +256,7 @@ set names latin1; execute `ü`; 1234 1234 +deallocate prepare `ü`; set names default; create table t1 (a varchar(10)) charset=utf8; insert into t1 (a) values ('yahoo'); @@ -781,6 +785,7 @@ EXECUTE b12651; 1 DROP VIEW b12651_V1; DROP TABLE b12651_T1, b12651_T2; +DEALLOCATE PREPARE b12651; prepare stmt from "select @@time_zone"; execute stmt; @@time_zone @@ -873,6 +878,130 @@ length(a) 10 drop table t1; deallocate prepare stmt; +create table t1 (col1 integer, col2 integer); +insert into t1 values(100,100),(101,101),(102,102),(103,103); +prepare stmt from 'select col1, col2 from t1 where (col1, col2) in ((?,?))'; +set @a=100, @b=100; +execute stmt using @a,@b; +col1 col2 +100 100 +set @a=101, @b=101; +execute stmt using @a,@b; +col1 col2 +101 101 +set @a=102, @b=102; +execute stmt using @a,@b; +col1 col2 +102 102 +set @a=102, @b=103; +execute stmt using @a,@b; +col1 col2 +deallocate prepare stmt; +drop table t1; +set @old_max_prepared_stmt_count= @@max_prepared_stmt_count; +show variables like 'max_prepared_stmt_count'; +Variable_name Value +max_prepared_stmt_count 16382 +show variables like 'prepared_stmt_count'; +Variable_name Value +prepared_stmt_count 0 +select @@max_prepared_stmt_count, @@prepared_stmt_count; +@@max_prepared_stmt_count @@prepared_stmt_count +16382 0 +set global max_prepared_stmt_count=-1; +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +0 +set global max_prepared_stmt_count=10000000000000000; +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +1048576 +set global max_prepared_stmt_count=default; +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +16382 +set @@max_prepared_stmt_count=1; +ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL +set max_prepared_stmt_count=1; +ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL +set local max_prepared_stmt_count=1; +ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL +set local prepared_stmt_count=0; +ERROR HY000: Variable 'prepared_stmt_count' is a read only variable +set @@prepared_stmt_count=0; +ERROR HY000: Variable 'prepared_stmt_count' is a read only variable +set global prepared_stmt_count=1; +ERROR HY000: Variable 'prepared_stmt_count' is a read only variable +set global max_prepared_stmt_count=1; +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +1 +set global max_prepared_stmt_count=0; +select @@max_prepared_stmt_count, @@prepared_stmt_count; +@@max_prepared_stmt_count @@prepared_stmt_count +0 0 +prepare stmt from "select 1"; +ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 0) +select @@prepared_stmt_count; +@@prepared_stmt_count +0 +set global max_prepared_stmt_count=1; +prepare stmt from "select 1"; +select @@prepared_stmt_count; +@@prepared_stmt_count +1 +prepare stmt1 from "select 1"; +ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 1) +select @@prepared_stmt_count; +@@prepared_stmt_count +1 +deallocate prepare stmt; +select @@prepared_stmt_count; +@@prepared_stmt_count +0 +prepare stmt from "select 1"; +select @@prepared_stmt_count; +@@prepared_stmt_count +1 +prepare stmt from "select 2"; +select @@prepared_stmt_count; +@@prepared_stmt_count +1 +select @@prepared_stmt_count, @@max_prepared_stmt_count; +@@prepared_stmt_count @@max_prepared_stmt_count +1 1 +set global max_prepared_stmt_count=0; +prepare stmt from "select 1"; +ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 0) +execute stmt; +ERROR HY000: Unknown prepared statement handler (stmt) given to EXECUTE +select @@prepared_stmt_count; +@@prepared_stmt_count +0 +prepare stmt from "select 1"; +ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 0) +select @@prepared_stmt_count; +@@prepared_stmt_count +0 +set global max_prepared_stmt_count=3; +select @@max_prepared_stmt_count, @@prepared_stmt_count; +@@max_prepared_stmt_count @@prepared_stmt_count +3 0 +prepare stmt from "select 1"; +prepare stmt from "select 2"; +prepare stmt1 from "select 3"; +prepare stmt2 from "select 4"; +ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 3) +prepare stmt2 from "select 4"; +ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 3) +select @@max_prepared_stmt_count, @@prepared_stmt_count; +@@max_prepared_stmt_count @@prepared_stmt_count +3 3 +deallocate prepare stmt; +select @@max_prepared_stmt_count, @@prepared_stmt_count; +@@max_prepared_stmt_count @@prepared_stmt_count +3 0 +set global max_prepared_stmt_count= @old_max_prepared_stmt_count; create table t1 (id int); prepare ins_call from "insert into t1 (id) values (1)"; execute ins_call; @@ -883,6 +1012,7 @@ drop table t1; create table t1 (a int, b int); insert into t1 (a,b) values (2,8),(1,9),(3,7); prepare stmt from "select * from t1 order by ?"; +set @a=NULL; execute stmt using @a; a b 2 8 diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 23b33156b48..1f5f17fe976 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -827,6 +827,7 @@ EXECUTE b12651; DROP VIEW b12651_V1; DROP TABLE b12651_T1, b12651_T2; +DEALLOCATE PREPARE b12651; # # Bug#9359 "Prepared statements take snapshot of system vars at PREPARE @@ -974,17 +975,17 @@ set global max_prepared_stmt_count=10000000000000000; select @@max_prepared_stmt_count; set global max_prepared_stmt_count=default; select @@max_prepared_stmt_count; ---error 1229 # ER_GLOBAL_VARIABLE +--error ER_GLOBAL_VARIABLE set @@max_prepared_stmt_count=1; ---error 1229 # ER_GLOBAL_VARIABLE +--error ER_GLOBAL_VARIABLE set max_prepared_stmt_count=1; ---error 1229 # ER_GLOBAL_VARIABLE +--error ER_GLOBAL_VARIABLE set local max_prepared_stmt_count=1; ---error 1229 # ER_GLOBAL_VARIABLE +--error ER_INCORRECT_GLOBAL_LOCAL_VAR set local prepared_stmt_count=0; ---error 1229 # ER_GLOBAL_VARIABLE +--error ER_INCORRECT_GLOBAL_LOCAL_VAR set @@prepared_stmt_count=0; ---error 1232 # ER_WRONG_TYPE_FOR_VAR +--error ER_INCORRECT_GLOBAL_LOCAL_VAR set global prepared_stmt_count=1; # set to a reasonable limit works set global max_prepared_stmt_count=1; @@ -994,13 +995,13 @@ select @@max_prepared_stmt_count; # set global max_prepared_stmt_count=0; select @@max_prepared_stmt_count, @@prepared_stmt_count; ---error 1105 # ER_UNKNOWN_ERROR +--error ER_MAX_PREPARED_STMT_COUNT_REACHED prepare stmt from "select 1"; select @@prepared_stmt_count; set global max_prepared_stmt_count=1; prepare stmt from "select 1"; select @@prepared_stmt_count; ---error 1105 # ER_UNKNOWN_ERROR +--error ER_MAX_PREPARED_STMT_COUNT_REACHED prepare stmt1 from "select 1"; select @@prepared_stmt_count; deallocate prepare stmt; @@ -1019,13 +1020,13 @@ select @@prepared_stmt_count; # select @@prepared_stmt_count, @@max_prepared_stmt_count; set global max_prepared_stmt_count=0; ---error 1105 # ER_UNKNOWN_ERROR +--error ER_MAX_PREPARED_STMT_COUNT_REACHED prepare stmt from "select 1"; # Result: the old statement is deallocated, the new is not created. --error 1243 # ER_UNKNOWN_STMT_HANDLER execute stmt; select @@prepared_stmt_count; ---error 1105 # ER_UNKNOWN_ERROR +--error ER_MAX_PREPARED_STMT_COUNT_REACHED prepare stmt from "select 1"; select @@prepared_stmt_count; # @@ -1039,10 +1040,10 @@ connect (con1,localhost,root,,); connection con1; prepare stmt from "select 2"; prepare stmt1 from "select 3"; ---error 1105 # ER_UNKNOWN_ERROR +--error ER_MAX_PREPARED_STMT_COUNT_REACHED prepare stmt2 from "select 4"; connection default; ---error 1105 # ER_UNKNOWN_ERROR +--error ER_MAX_PREPARED_STMT_COUNT_REACHED prepare stmt2 from "select 4"; select @@max_prepared_stmt_count, @@prepared_stmt_count; disconnect con1; @@ -1087,6 +1088,7 @@ insert into t1 (a,b) values (2,8),(1,9),(3,7); # Will order by index prepare stmt from "select * from t1 order by ?"; +set @a=NULL; execute stmt using @a; set @a=1; execute stmt using @a; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 37487c245a9..a1f70fca8df 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5611,3 +5611,5 @@ ER_TABLE_NEEDS_UPGRADE eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" to fix it!" ER_SP_NO_AGGREGATE 42000 eng "AGGREGATE is not supported for stored functions" +ER_MAX_PREPARED_STMT_COUNT_REACHED 42000 + eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f0ab4b5c29c..d56f10a7a30 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -421,7 +421,7 @@ THD::~THD() net_end(&net); } #endif - stmt_map.destroy(); /* close all prepared statements */ + stmt_map.reset(); /* close all prepared statements */ DBUG_ASSERT(lock_info.n_cursors == 0); if (!cleanup_done) cleanup(); @@ -1757,20 +1757,10 @@ int Statement_map::insert(THD *thd, Statement *statement) my_error(ER_OUT_OF_RESOURCES, MYF(0)); goto err_st_hash; } - if (statement->name.str) + if (statement->name.str && my_hash_insert(&names_hash, (byte*) statement)) { - /* - If there is a statement with the same name, remove it. It is ok to - remove old and fail to insert new one at the same time. - */ - Statement *old_stmt; - if ((old_stmt= find_by_name(&statement->name))) - erase(old_stmt); - if (my_hash_insert(&names_hash, (byte*) statement)) - { - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - goto err_names_hash; - } + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + goto err_names_hash; } pthread_mutex_lock(&LOCK_prepared_stmt_count); /* @@ -1783,7 +1773,8 @@ int Statement_map::insert(THD *thd, Statement *statement) if (prepared_stmt_count >= max_prepared_stmt_count) { pthread_mutex_unlock(&LOCK_prepared_stmt_count); - my_error(ER_UNKNOWN_ERROR, MYF(0)); + my_error(ER_MAX_PREPARED_STMT_COUNT_REACHED, MYF(0), + max_prepared_stmt_count); goto err_max; } prepared_stmt_count++; @@ -1817,9 +1808,8 @@ void Statement_map::erase(Statement *statement) if (statement == last_found_statement) last_found_statement= 0; if (statement->name.str) - { hash_delete(&names_hash, (byte *) statement); - } + hash_delete(&st_hash, (byte *) statement); pthread_mutex_lock(&LOCK_prepared_stmt_count); DBUG_ASSERT(prepared_stmt_count > 0); @@ -1852,7 +1842,6 @@ Statement_map::~Statement_map() hash_free(&names_hash); hash_free(&st_hash); - } bool select_dumpvar::send_data(List<Item> &items) diff --git a/sql/sql_class.h b/sql/sql_class.h index dd645fcf75e..7c74ff6fa93 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -867,16 +867,6 @@ public: } return last_found_statement; } - void erase(Statement *statement) - { - if (statement == last_found_statement) - last_found_statement= 0; - if (statement->name.str) - { - hash_delete(&names_hash, (byte *) statement); - } - hash_delete(&st_hash, (byte *) statement); - } /* Close all cursors of this connection that use tables of a storage engine that has transaction-specific state and therefore can not diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5a15e67da8e..4fa0a2dcb6e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1846,7 +1846,7 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) if (! (stmt= new Prepared_statement(thd, &thd->protocol_prep))) DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */ - if (thd->stmt_map.insert(stmt)) + if (thd->stmt_map.insert(thd, stmt)) { /* The error is set in the insert. The statement itself @@ -2029,14 +2029,15 @@ void mysql_sql_stmt_prepare(THD *thd) DBUG_VOID_RETURN; /* out of memory */ } - if (thd->stmt_map.insert(stmt)) + /* Set the name first, insert should know that this statement has a name */ + if (stmt->set_name(name)) { - /* The statement is deleted and an error is set if insert fails */ + delete stmt; DBUG_VOID_RETURN; } - if (stmt->set_name(name)) + if (thd->stmt_map.insert(thd, stmt)) { - thd->stmt_map.erase(stmt); + /* The statement is deleted and an error is set if insert fails */ DBUG_VOID_RETURN; } |