diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index f622b2d2fb29aef257289698feab732182cfb3ec..097983cbbd303a139ce0b9e10fac6ad30e1a89e6 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1774,6 +1774,7 @@ static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row); static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row); static int stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row); static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row); +static int stmt_read_row_no_result_set(MYSQL_STMT *stmt, unsigned char **row); /* This function is used in mysql_stmt_store_result if @@ -2036,7 +2037,7 @@ mysql_stmt_init(MYSQL *mysql) stmt->list.data= stmt; stmt->state= MYSQL_STMT_INIT_DONE; stmt->mysql= mysql; - stmt->read_row_func= stmt_read_row_no_data; + stmt->read_row_func= stmt_read_row_no_result_set; stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS; /* The rest of statement members was bzeroed inside malloc */ @@ -2778,6 +2779,13 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) static int stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)), unsigned char **row __attribute__((unused))) +{ + return MYSQL_NO_DATA; +} + +static int +stmt_read_row_no_result_set(MYSQL_STMT *stmt __attribute__((unused)), + unsigned char **row __attribute__((unused))) { set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate); return 1; @@ -4600,7 +4608,8 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt) ((rc= stmt_fetch_row(stmt, row)) && rc != MYSQL_DATA_TRUNCATED)) { stmt->state= MYSQL_STMT_PREPARE_DONE; /* XXX: this is buggy */ - stmt->read_row_func= stmt_read_row_no_data; + stmt->read_row_func= (rc == MYSQL_NO_DATA) ? + stmt_read_row_no_data : stmt_read_row_no_result_set; } else { @@ -4937,7 +4946,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) for (; param < param_end; param++) param->long_data_used= 0; } - stmt->read_row_func= stmt_read_row_no_data; + stmt->read_row_func= stmt_read_row_no_result_set; if (mysql) { if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index dd1fb491064a915601deb34d82110584023192b7..4bc2ed0fdc80433688e1f26711e7f78a4c627a86 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -657,3 +657,22 @@ a b 1.1 1.100 2.1 2.100 DROP TABLE t1; +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +utext +lily +river +execute stmt using @param1; +utext +lily +river +select utext from t1 where utext like '%%'; +utext +lily +river +drop table t1; +deallocate prepare stmt; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 1896db84de057005054038d23766bf895e7ddd01..81d85306e93afa8b21f119517ab3d830c108428f 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -759,25 +759,6 @@ execute stmt using @a, @b; ?=? 1 deallocate prepare stmt; -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -utext -lily -river -execute stmt using @param1; -utext -lily -river -select utext from t1 where utext like '%%'; -utext -lily -river -drop table t1; -deallocate prepare stmt; create table t1 (a int); prepare stmt from "select ??"; 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 '?' at line 1 diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 74c03987a6ac126ec7434d54d28d8c37eb755ebb..345de49c21ddcc1b689b49636752e0f93122d6b7 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3062,4 +3062,21 @@ l drop procedure bug6063| drop procedure bug7088_1| drop procedure bug7088_2| +drop procedure if exists bug9565_sub| +drop procedure if exists bug9565| +create procedure bug9565_sub() +begin +select * from t1; +end| +create procedure bug9565() +begin +insert into t1 values ("one", 1); +call bug9565_sub(); +end| +call bug9565()| +id data +one 1 +delete from t1| +drop procedure bug9565_sub| +drop procedure bug9565| drop table t1,t2; diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index d7ad803b82853ff364300d00ed4bcf42fed94ae2..adc22cd1ac2c00b8d0ca483ec9aec722930fa23b 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -1235,3 +1235,13 @@ create table t1(a varchar(65537)); ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead create table t1(a varbinary(65537)); ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead +set @@sql_mode='traditional'; +create table t1(a int, b date not null); +alter table t1 modify a bigint unsigned not null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned NOT NULL, + `b` date NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index ef40a408932a19dc260cd2a7c4c377a8362d77d0..684c4950acdbb28574092b1ef4326ff135cbfaa2 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1977,3 +1977,17 @@ A B DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 ( bug_table_seq INTEGER NOT NULL); +CREATE OR REPLACE VIEW v1 AS SELECT * from t1; +DROP PROCEDURE IF EXISTS p1; +Warnings: +Note 1305 PROCEDURE p1 does not exist +CREATE PROCEDURE p1 ( ) +BEGIN +DO (SELECT @next := IFNULL(max(bug_table_seq),0) + 1 FROM v1); +INSERT INTO t1 VALUES (1); +END // +CALL p1(); +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index f4327536795be1cf6b7293ee6b661d6a2289809b..d032c1249dfb41a0ed7c58c5d794dff121fdb33d 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -427,3 +427,17 @@ INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); update t1 set b=a; SELECT * FROM t1; DROP TABLE t1; + +# +# Bug#9442 Set parameter make query fail if column character set is UCS2 +# +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +execute stmt using @param1; +select utext from t1 where utext like '%%'; +drop table t1; +deallocate prepare stmt; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index fa5dd0680b5cf91943359dc8d8f5365e3e499294..e8ea1dc373b7a6d7faafa7c410b910fa6f057fc8 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -789,19 +789,6 @@ set @b='CHRISTINE'; execute stmt using @a, @b; deallocate prepare stmt; # -# Bug#9442 Set parameter make query fail if column character set is UCS2 -# -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -execute stmt using @param1; -select utext from t1 where utext like '%%'; -drop table t1; -deallocate prepare stmt; -# # Bug#11299 "prepared statement makes wrong SQL syntax in binlog which stops # replication": check that errouneous queries with placeholders are not # allowed diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 4df49c5f93446378466251557c3b0dfd42fd05c4..13de2090a848bcd0d10ddbf4047a23881284600e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3832,6 +3832,28 @@ drop procedure bug6063| drop procedure bug7088_1| drop procedure bug7088_2| +# +# BUG#9565: "Wrong locking in stored procedure if a sub-sequent procedure +# is called". +# +--disable_warnings +drop procedure if exists bug9565_sub| +drop procedure if exists bug9565| +--enable_warnings +create procedure bug9565_sub() +begin + select * from t1; +end| +create procedure bug9565() +begin + insert into t1 values ("one", 1); + call bug9565_sub(); +end| +call bug9565()| +delete from t1| +drop procedure bug9565_sub| +drop procedure bug9565| + # # BUG#NNNN: New bug synopsis diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index 302acc9bef2268e8aea5bf623f769b5545eb89ea..6ac88e4d6297241852da0702a8a49d38ee6b4ddf 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -1093,3 +1093,13 @@ set @@sql_mode='traditional'; create table t1(a varchar(65537)); --error 1074 create table t1(a varbinary(65537)); + +# +# Bug #9881: problem with altering table +# + +set @@sql_mode='traditional'; +create table t1(a int, b date not null); +alter table t1 modify a bigint unsigned not null; +show create table t1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index d296d5ebee5ac98a1ab08a4e1e26caa708b30fd2..8eeac41efcd7aa5b4263cde09d94a5a0d1eab4a6 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1804,7 +1804,6 @@ drop table t1; # # Test for bug #11771: wrong query_id in SELECT * FROM <view> # - CREATE TABLE t1 (f1 char) ENGINE = innodb; INSERT INTO t1 VALUES ('A'); CREATE VIEW v1 AS SELECT * FROM t1; @@ -1815,3 +1814,21 @@ SELECT * FROM t1; DROP VIEW v1; DROP TABLE t1; + +# +# opening table in correct locking mode (BUG#9597) +# +CREATE TABLE t1 ( bug_table_seq INTEGER NOT NULL); +CREATE OR REPLACE VIEW v1 AS SELECT * from t1; +DROP PROCEDURE IF EXISTS p1; +delimiter //; +CREATE PROCEDURE p1 ( ) +BEGIN + DO (SELECT @next := IFNULL(max(bug_table_seq),0) + 1 FROM v1); + INSERT INTO t1 VALUES (1); +END // +delimiter ;// +CALL p1(); +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 58844db2f38eeeeb08b8b940776b8abe0a8707aa..1a3b0f704981a413b3376fb2a2a992c1709908b7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8488,7 +8488,8 @@ create_field::create_field(Field *old_field,Field *orig_field) else interval=0; def=0; - if (!old_field->is_real_null() && ! (flags & BLOB_FLAG) && + if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && + !old_field->is_real_null() && old_field->ptr && orig_field) { char buff[MAX_FIELD_WIDTH],*pos; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 367dc3bb0f62ce5fa48a1328dd0fa2676fc869a7..0013d478600486bafd6fece35e3b2b174c163e2a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1041,6 +1041,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (thd->locked_tables || thd->prelocked_mode) { // Using table locks + TABLE *best_table= 0; + int best_distance= INT_MIN, distance; for (table=thd->open_tables; table ; table=table->next) { if (table->s->key_length == key_length && @@ -1049,11 +1051,37 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->query_id != thd->query_id && /* skip tables already used by this query */ !(thd->prelocked_mode && table->query_id)) { - table->query_id= thd->query_id; - DBUG_PRINT("info",("Using locked table")); - goto reset; + distance= ((int) table->reginfo.lock_type - + (int) table_list->lock_type); + /* + Find a table that either has the exact lock type requested, + or has the best suitable lock. In case there is no locked + table that has an equal or higher lock than requested, + we still maitain the best_table to produce an error message + about wrong lock mode on the table. The best_table is changed + if bd < 0 <= d or bd < d < 0 or 0 <= d < bd. + + distance < 0 - we have not enough high lock mode + distance > 0 - we have lock mode higher then we require + distance == 0 - we have lock mode exactly which we need + */ + if (best_distance < 0 && distance > best_distance || + distance >= 0 && distance < best_distance) + { + best_distance= distance; + best_table= table; + if (best_distance == 0) + break; + } } } + if (best_table) + { + table= best_table; + table->query_id= thd->query_id; + DBUG_PRINT("info",("Using locked table")); + goto reset; + } /* is it view? (it is work around to allow to open view with locked tables, diff --git a/sql/sql_class.h b/sql/sql_class.h index 44f126d96ec8c6c7cc2aa1a22802c22b6c97d5e0..37bfd1656a82f3bb1d708671746055b67b6c892b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1170,12 +1170,22 @@ public: This is to track items changed during execution of a prepared statement/stored procedure. It's created by register_item_tree_change() in memory root of THD, and freed in - rollback_item_tree_changes(). For conventional execution it's always 0. + rollback_item_tree_changes(). For conventional execution it's always + empty. */ Item_change_list change_list; /* - Current prepared Query_arena if there one, or 0 + A permanent memory area of the statement. For conventional + execution, the parsed tree and execution runtime reside in the same + memory root. In this case current_arena points to THD. In case of + a prepared statement or a stored procedure statement, thd->mem_root + conventionally points to runtime memory, and thd->current_arena + points to the memory of the PS/SP, where the parsed tree of the + statement resides. Whenever you need to perform a permanent + transformation of a parsed tree, you should allocate new memory in + current_arena, to allow correct re-execution of PS/SP. + Note: in the parser, current_arena == thd, even for PS/SP. */ Query_arena *current_arena; /* diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index a056814a1531caf5ac37dba80659d2ebd0abba29..010f467c4ad0a02061124ebd7d851cc2e921efad 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13315,7 +13315,7 @@ static void test_bug9992() DIE_UNLESS(rc == 1); /* Got errors, as expected */ if (!opt_silent) - fprintf(stdout, "Got error, sa expected:\n [%d] %s\n", + fprintf(stdout, "Got error, as expected:\n [%d] %s\n", mysql_errno(mysql1), mysql_error(mysql1)); mysql_close(mysql1); @@ -13705,6 +13705,51 @@ static void test_bug11183() myquery(rc); } +static void test_bug11037() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text; + + myheader("test_bug11037"); + + mysql_query(mysql, "drop table if exists t1"); + + rc= mysql_query(mysql, "create table t1 (id int not null)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (1)"); + myquery(rc); + + stmt_text= "select id FROM t1"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + + /* expected error */ + rc = mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==1); + if (!opt_silent) + fprintf(stdout, "Got error, as expected:\n [%d] %s\n", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==0); + + rc = mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==MYSQL_NO_DATA); + + rc = mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -13948,6 +13993,7 @@ static struct my_tests_st my_tests[]= { { "test_bug10214", test_bug10214 }, { "test_bug9735", test_bug9735 }, { "test_bug11183", test_bug11183 }, + { "test_bug11037", test_bug11037 }, { 0, 0 } };