From 7f80ca5493b4763424260140a89588fa32dab6b7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 01:22:14 +0300 Subject: [PATCH 1/7] take into account table lock mode when opening table: try to find most suitable table, to avouid pickup table with too low locking mode or occupy table with write mode for select when it will be need for update later (BUG#9597) mysql-test/r/view.result: opening table in correct locking mode test mysql-test/t/view.test: opening table in correct locking mode test sql/sql_base.cc: take into account table lock mode when opening table: try to find most suitable table, to avouid pickup table with too low locking mode or occupy table with write mode for select when it will be need for update later --- mysql-test/r/view.result | 14 ++++++++++++++ mysql-test/t/view.test | 19 ++++++++++++++++++- sql/sql_base.cc | 34 +++++++++++++++++++++++++++++++--- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index ef40a408932..684c4950acd 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/view.test b/mysql-test/t/view.test index d296d5ebee5..8eeac41efcd 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 # - 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/sql_base.cc b/sql/sql_base.cc index 2ee1c8c24cc..7021f61a052 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, From ba7d8ad734f84c032d2352ecb05f5937855217b3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 13:21:08 +0400 Subject: [PATCH 2/7] Improve a comment. --- sql/sql_class.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 625b9c27b44..1814ce1d2aa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1162,12 +1162,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; /* From 32e157ec0bd2d7f792981910eb759197af480178 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 13:34:48 +0400 Subject: [PATCH 3/7] Added test case for bug #9565 "Wrong locking in stored procedure if a sub-sequent procedure is called" which was fixed by the same patch as bug #9597 "read lock stays when querying view from stored procedure". mysql-test/r/sp.result: Added test case for bug #9565 "Wrong locking in stored procedure if a sub-sequent procedure is called". mysql-test/t/sp.test: Added test case for bug #9565 "Wrong locking in stored procedure if a sub-sequent procedure is called". --- mysql-test/r/sp.result | 17 +++++++++++++++++ mysql-test/t/sp.test | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 74c03987a6a..345de49c21d 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/t/sp.test b/mysql-test/t/sp.test index 4df49c5f934..13de2090a84 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 From f4cd03d03f81e2cfd986e8b96af6f3b46b87ec45 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 15:50:57 +0500 Subject: [PATCH 4/7] a fix (bug #9881: ALTER TABLE gives wrong error message with sql-mode TRADITIONAL). sql/field.cc: a fix (bug #9881: ALTER TABLE gives wrong error message with sql-mode TRADITIONAL). Don't set def if NO_DEFAULT_VALUE_FLAG is set. --- mysql-test/r/strict.result | 10 ++++++++++ mysql-test/t/strict.test | 10 ++++++++++ sql/field.cc | 3 ++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index d7ad803b828..adc22cd1ac2 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/t/strict.test b/mysql-test/t/strict.test index 302acc9bef2..6ac88e4d629 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/sql/field.cc b/sql/field.cc index bb035ce5d37..71e90fb5bdf 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8487,7 +8487,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) && + !old_field->is_real_null() && ! (flags & BLOB_FLAG) && old_field->ptr && orig_field) { char buff[MAX_FIELD_WIDTH],*pos; From 0ec715a69e4347fb6a729dcbcfb8760cf7a5f945 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 16:25:31 +0500 Subject: [PATCH 5/7] NO_DEFAULT_VALUE_FLAG and BLOB_FLAG combined --- sql/field.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 71e90fb5bdf..52f260e7b2d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8487,8 +8487,8 @@ create_field::create_field(Field *old_field,Field *orig_field) else interval=0; def=0; - if (!(flags & NO_DEFAULT_VALUE_FLAG) && - !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; From 6fcb9c8e8043a2c8687324aee3cb9b88281ac51d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 14:30:47 +0200 Subject: [PATCH 6/7] Fix for bug #11037. When all rows are fetched subsequent calls to mysql_stmt_fetch return now MYSQL_NO_DATA instead of errorcode 1. libmysql/libmysql.c: fix for bug#11037 tests/mysql_client_test.c: added new testcase for bug #11037 --- libmysql/libmysql.c | 15 +++++++++--- tests/mysql_client_test.c | 48 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index f622b2d2fb2..097983cbbd3 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/tests/mysql_client_test.c b/tests/mysql_client_test.c index a056814a153..010f467c4ad 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 } }; From b5d9a7644eb3db760a794f46d2a11989fdd32012 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jul 2005 19:46:42 +0200 Subject: [PATCH 7/7] Bug#9442, moved ps ucs2 test from ps.test to ctype_ucs.test --- mysql-test/r/ctype_ucs.result | 19 +++++++++++++++++++ mysql-test/r/ps.result | 19 ------------------- mysql-test/t/ctype_ucs.test | 14 ++++++++++++++ mysql-test/t/ps.test | 13 ------------- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index dd1fb491064..4bc2ed0fdc8 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 1896db84de0..81d85306e93 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/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index f4327536795..d032c1249df 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 fa5dd0680b5..e8ea1dc373b 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