From 63c9d97c0d11db6014b29f44216bf98dc5da2c32 Mon Sep 17 00:00:00 2001 From: "Bernt M. Johnsen" Date: Wed, 25 Feb 2009 16:53:49 +0100 Subject: [PATCH 01/12] Prepared for push (BUG#43110) --- mysql-test/t/ps.test | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 6b20fd14394..db5994d434b 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -946,8 +946,13 @@ set global max_prepared_stmt_count=3; select @@max_prepared_stmt_count; show status like 'prepared_stmt_count'; prepare stmt from "select 1"; + connect (con1,localhost,root,,); + +# Switch to connection con1 connection con1; +let $con1_id=`SELECT CONNECTION_ID()`; + prepare stmt from "select 2"; prepare stmt1 from "select 3"; --error ER_MAX_PREPARED_STMT_COUNT_REACHED @@ -957,18 +962,17 @@ connection default; prepare stmt2 from "select 4"; select @@max_prepared_stmt_count; show status like 'prepared_stmt_count'; + +# Disconnect connection con1 and switch to default connection disconnect con1; connection default; -# Wait for the connection to die: deal with a possible race + +# Wait for the connection con1 to die +let $wait_condition=SELECT COUNT(*)=0 FROM information_schema.processlist WHERE id=$con1_id; +--source include/wait_condition.inc + deallocate prepare stmt; -let $query= select variable_value from information_schema.global_status - where variable_name = 'prepared_stmt_count'; -let $count= `$query`; -if ($count) -{ ---sleep 1 - let $count= `$query`; -} + select @@max_prepared_stmt_count; show status like 'prepared_stmt_count'; # From c8e908ffcc2571b133363a9c725d6975b32131ad Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Thu, 26 Feb 2009 12:34:15 +0400 Subject: [PATCH 02/12] Fix for bug#19829:make test Failed in mysql_client_test *with --with-charset=utf8* Problem: wrong LONG TEXT field length is sent to a client when multibyte server character set used. Fix: always limit field length sent to a client to 2^32, as we store it in 4 byte slot. Note: mysql_client_test changed accordingly. --- sql/protocol.cc | 22 ++++++++++++++++------ tests/mysql_client_test.c | 15 +++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index ff58d96f59b..2309bac88a9 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -616,7 +616,8 @@ bool Protocol::send_fields(List *list, uint flags) else { /* With conversion */ - uint max_char_len; + ulonglong max_length; + uint32 field_length; int2store(pos, thd_charset->number); /* For TEXT/BLOB columns, field_length describes the maximum data @@ -627,12 +628,21 @@ bool Protocol::send_fields(List *list, uint flags) char_count * mbmaxlen, where character count is taken from the definition of the column. In other words, the maximum number of characters here is limited by the column definition. + + When one has a LONG TEXT column with a single-byte + character set, and the connection character set is multi-byte, the + client may get fields longer than UINT_MAX32, due to + -> conversion. + In that case column max length does not fit into the 4 bytes + reserved for it in the protocol. */ - max_char_len= (field.type >= (int) MYSQL_TYPE_TINY_BLOB && - field.type <= (int) MYSQL_TYPE_BLOB) ? - field.length / item->collation.collation->mbminlen : - field.length / item->collation.collation->mbmaxlen; - int4store(pos+2, max_char_len * thd_charset->mbmaxlen); + max_length= (field.type >= MYSQL_TYPE_TINY_BLOB && + field.type <= MYSQL_TYPE_BLOB) ? + field.length / item->collation.collation->mbminlen : + field.length / item->collation.collation->mbmaxlen; + max_length*= thd_charset->mbmaxlen; + field_length= (max_length > UINT_MAX32) ? UINT_MAX32 : max_length; + int4store(pos + 2, field_length); } pos[6]= field.type; int2store(pos+7,field.flags); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index f848e93a5c6..7df84c600c9 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -714,6 +714,7 @@ static void do_verify_prepare_field(MYSQL_RES *result, { MYSQL_FIELD *field; CHARSET_INFO *cs; + ulonglong expected_field_length; if (!(field= mysql_fetch_field_direct(result, no))) { @@ -722,6 +723,8 @@ static void do_verify_prepare_field(MYSQL_RES *result, } cs= get_charset(field->charsetnr, 0); DIE_UNLESS(cs); + if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) + expected_field_length= UINT_MAX32; if (!opt_silent) { fprintf(stdout, "\n field[%d]:", no); @@ -736,8 +739,8 @@ static void do_verify_prepare_field(MYSQL_RES *result, fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", field->org_table, org_table); fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); - fprintf(stdout, "\n length :`%lu`\t(expected: `%lu`)", - field->length, length * cs->mbmaxlen); + fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", + field->length, expected_field_length); fprintf(stdout, "\n maxlength:`%ld`", field->max_length); fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", @@ -773,11 +776,11 @@ static void do_verify_prepare_field(MYSQL_RES *result, as utf8. Field length is calculated as number of characters * maximum number of bytes a character can occupy. */ - if (length && field->length != length * cs->mbmaxlen) + if (length && (field->length != expected_field_length)) { - fprintf(stderr, "Expected field length: %d, got length: %d\n", - (int) (length * cs->mbmaxlen), (int) field->length); - DIE_UNLESS(field->length == length * cs->mbmaxlen); + fprintf(stderr, "Expected field length: %llu, got length: %lu\n", + expected_field_length, field->length); + DIE_UNLESS(field->length == expected_field_length); } if (def) DIE_UNLESS(strcmp(field->def, def) == 0); From 1062119af51cd0faaa370a16c06aec480d276ea0 Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Thu, 26 Feb 2009 10:57:33 +0200 Subject: [PATCH 03/12] Bug#41893: main.variables mysql-test fails if new variable like '%alloc%' is added. Started fix in 5.0 as the same issue is here. Revising queries used given what appears to be the scope of this test to only select the manipulated variables. Added tests for values that are / are not multiples of 1024 to test rounding / constraints. This behavior is not currently documented (docs bug has been opened) --- mysql-test/r/variables.result | 46 ++++++++++++++++++++++++++++++----- mysql-test/t/variables.test | 38 +++++++++++++++++++++++++---- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 376a8ffa38e..04ccf3d688c 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -236,32 +236,66 @@ set @@rand_seed1=10000000,@@rand_seed2=1000000; select ROUND(RAND(),5); ROUND(RAND(),5) 0.02887 -show variables like '%alloc%'; + +==+ Testing %alloc% system variables +== +==+ NOTE: These values *must* be a multiple of 1024 +== +==+ Other values will be rounded down to nearest multiple +== + +==+ Show initial values +== +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); Variable_name Value query_alloc_block_size 8192 query_prealloc_size 8192 range_alloc_block_size 4096 transaction_alloc_block_size 8192 transaction_prealloc_size 4096 -set @@range_alloc_block_size=1024*16; +==+ Manipulate variable values += +Testing values that are multiples of 1024 +set @@range_alloc_block_size=1024*15+1024; +set @@query_alloc_block_size=1024*15+1024*2; +set @@query_prealloc_size=1024*18-1024; +set @@transaction_alloc_block_size=1024*21-1024*1; +set @@transaction_prealloc_size=1024*21-2048; +==+ Check manipulated values ==+ +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); +Variable_name Value +query_alloc_block_size 17408 +query_prealloc_size 17408 +range_alloc_block_size 16384 +transaction_alloc_block_size 20480 +transaction_prealloc_size 19456 +==+ Manipulate variable values +== +Testing values that are not 1024 multiples +set @@range_alloc_block_size=1024*16+1023; set @@query_alloc_block_size=1024*17+2; -set @@query_prealloc_size=1024*18; +set @@query_prealloc_size=1024*18-1023; set @@transaction_alloc_block_size=1024*20-1; set @@transaction_prealloc_size=1024*21-1; select @@query_alloc_block_size; @@query_alloc_block_size 17408 -show variables like '%alloc%'; +==+ Check manipulated values ==+ +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); Variable_name Value query_alloc_block_size 17408 -query_prealloc_size 18432 +query_prealloc_size 17408 range_alloc_block_size 16384 transaction_alloc_block_size 19456 transaction_prealloc_size 20480 +==+ Set values back to the default values +== set @@range_alloc_block_size=default; set @@query_alloc_block_size=default, @@query_prealloc_size=default; set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; -show variables like '%alloc%'; +==+ Check the values not that they are reset +== +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); Variable_name Value query_alloc_block_size 8192 query_prealloc_size 8192 diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 60254ad9a1d..173be9d87c6 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -150,18 +150,46 @@ select @@timestamp>0; set @@rand_seed1=10000000,@@rand_seed2=1000000; select ROUND(RAND(),5); -show variables like '%alloc%'; -set @@range_alloc_block_size=1024*16; +--echo +--echo ==+ Testing %alloc% system variables +== +--echo ==+ NOTE: These values *must* be a multiple of 1024 +== +--echo ==+ Other values will be rounded down to nearest multiple +== +--echo +--echo ==+ Show initial values +== +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); +--echo ==+ Manipulate variable values += +--echo Testing values that are multiples of 1024 +set @@range_alloc_block_size=1024*15+1024; +set @@query_alloc_block_size=1024*15+1024*2; +set @@query_prealloc_size=1024*18-1024; +set @@transaction_alloc_block_size=1024*21-1024*1; +set @@transaction_prealloc_size=1024*21-2048; +--echo ==+ Check manipulated values ==+ +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); +--echo ==+ Manipulate variable values +== +--echo Testing values that are not 1024 multiples +set @@range_alloc_block_size=1024*16+1023; set @@query_alloc_block_size=1024*17+2; -set @@query_prealloc_size=1024*18; +set @@query_prealloc_size=1024*18-1023; set @@transaction_alloc_block_size=1024*20-1; set @@transaction_prealloc_size=1024*21-1; select @@query_alloc_block_size; -show variables like '%alloc%'; +--echo ==+ Check manipulated values ==+ +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); +--echo ==+ Set values back to the default values +== set @@range_alloc_block_size=default; set @@query_alloc_block_size=default, @@query_prealloc_size=default; set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; -show variables like '%alloc%'; +--echo ==+ Check the values not that they are reset +== +SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', +'query_alloc_block_size', 'query_prealloc_size', +'transaction_alloc_block_size', 'transaction_prealloc_size'); # # Bug #10904 Illegal mix of collations between From 49166978b18c13cae795519e728416df242b3c42 Mon Sep 17 00:00:00 2001 From: Magnus Svensson Date: Thu, 26 Feb 2009 15:01:57 +0100 Subject: [PATCH 04/12] Bug#43215 6 error codes changed from 5.1 to 6.0 --- sql/share/errmsg.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5dc75c340ea..23231eefcc2 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6154,3 +6154,18 @@ WARN_PLUGIN_BUSY ER_VARIABLE_IS_READONLY eng "%s variable '%s' is read-only. Use SET %s to assign the value" + +ER_WARN_ENGINE_TRANSACTION_ROLLBACK + eng "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted" + +ER_SLAVE_HEARTBEAT_FAILURE + eng "Unexpected master's heartbeat data: %s" +ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE + eng "The requested value for the heartbeat period %s %s" + +ER_NDB_REPLICATION_SCHEMA_ERROR + eng "Bad schema for mysql.ndb_replication table. Message: %-.64s" +ER_CONFLICT_FN_PARSE_ERROR + eng "Error in parsing conflict function. Message: %-.64s" +ER_EXCEPTIONS_WRITE_ERROR + eng "Write to exceptions table failed. Message: %-.128s"" From bc4df2f65d760cbd6e0e23e99b72dbefd712248d Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Thu, 26 Feb 2009 18:00:47 +0200 Subject: [PATCH 05/12] Bug#41893 - main.variables mysql-test fails if new variable like '%alloc%' is added. Fixed a typo in the bug fix patch. --- mysql-test/t/variables.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 173be9d87c6..424776dfda4 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -186,7 +186,7 @@ SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', set @@range_alloc_block_size=default; set @@query_alloc_block_size=default, @@query_prealloc_size=default; set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; ---echo ==+ Check the values not that they are reset +== +--echo ==+ Check the values now that they are reset +== SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', 'query_alloc_block_size', 'query_prealloc_size', 'transaction_alloc_block_size', 'transaction_prealloc_size'); From b337ac28d03e887556e41540082dfc0064c3da2e Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 26 Feb 2009 19:00:44 +0200 Subject: [PATCH 06/12] Bug #41354: Access control is bypassed when all columns of a view are selected by * wildcard Backported a part of the fix for 36086 to 5.0 --- mysql-test/r/view_grant.result | 26 ++++++++++++++++++++++ mysql-test/t/view_grant.test | 40 ++++++++++++++++++++++++++++++++++ sql/sql_acl.cc | 28 +++++++++++++++++++----- sql/sql_base.cc | 2 +- 4 files changed, 89 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 2f8462045ca..1df8ed335a7 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -919,4 +919,30 @@ c4 DROP DATABASE mysqltest1; DROP DATABASE mysqltest2; DROP USER mysqltest_u1@localhost; +CREATE DATABASE db1; +USE db1; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE VIEW v1 AS SELECT f1, f2 FROM t1; +GRANT SELECT (f1) ON t1 TO foo; +GRANT SELECT (f1) ON v1 TO foo; +USE db1; +SELECT f1 FROM t1; +f1 +SELECT f2 FROM t1; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for column 'f2' in table 't1' +SELECT * FROM t1; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1' +SELECT f1 FROM v1; +f1 +SELECT f2 FROM v1; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for column 'f2' in table 'v1' +SELECT * FROM v1; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'v1' +USE test; +REVOKE SELECT (f1) ON db1.t1 FROM foo; +REVOKE SELECT (f1) ON db1.v1 FROM foo; +DROP USER foo; +DROP VIEW db1.v1; +DROP TABLE db1.t1; +DROP DATABASE db1; End of 5.0 tests. diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index be9daacec4f..c8b31f711b5 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1185,4 +1185,44 @@ DROP DATABASE mysqltest1; DROP DATABASE mysqltest2; DROP USER mysqltest_u1@localhost; + +# +# Bug #41354: Access control is bypassed when all columns of a view are +# selected by * wildcard + +CREATE DATABASE db1; +USE db1; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE VIEW v1 AS SELECT f1, f2 FROM t1; + +GRANT SELECT (f1) ON t1 TO foo; +GRANT SELECT (f1) ON v1 TO foo; + +connect (addconfoo, localhost, foo,,); +connection addconfoo; +USE db1; + + +SELECT f1 FROM t1; +--error ER_COLUMNACCESS_DENIED_ERROR +SELECT f2 FROM t1; +--error ER_TABLEACCESS_DENIED_ERROR +SELECT * FROM t1; + +SELECT f1 FROM v1; +--error ER_COLUMNACCESS_DENIED_ERROR +SELECT f2 FROM v1; +--error ER_TABLEACCESS_DENIED_ERROR +SELECT * FROM v1; + +connection default; +USE test; +disconnect addconfoo; +REVOKE SELECT (f1) ON db1.t1 FROM foo; +REVOKE SELECT (f1) ON db1.v1 FROM foo; +DROP USER foo; +DROP VIEW db1.v1; +DROP TABLE db1.t1; +DROP DATABASE db1; + --echo End of 5.0 tests. diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 22135d376fe..c59c42d512a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3866,6 +3866,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, Security_context *sctx= thd->security_ctx; ulong want_access= want_access_arg; const char *table_name= NULL; + /* + Flag that gets set if privilege checking has to be performed on column + level. + */ + bool using_column_privileges= FALSE; if (grant_option) { @@ -3909,6 +3914,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_COLUMN *grant_column= column_hash_search(grant_table, field_name, (uint) strlen(field_name)); + if (grant_column) + using_column_privileges= TRUE; if (!grant_column || (~grant_column->rights & want_access)) goto err; } @@ -3924,12 +3931,21 @@ err: char command[128]; get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - command, - sctx->priv_user, - sctx->host_or_ip, - fields->name(), - table_name); + /* + Do not give an error message listing a column name unless the user has + privilege to see all columns. + */ + if (using_column_privileges) + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + command, sctx->priv_user, + sctx->host_or_ip, table_name); + else + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), + command, + sctx->priv_user, + sctx->host_or_ip, + fields->name(), + table_name); return 1; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 881c6a421e8..781bbc0a553 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5479,7 +5479,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Ensure that we have access rights to all fields to be inserted. */ - if (!((table && (table->grant.privilege & SELECT_ACL) || + if (!((table && !tables->view && (table->grant.privilege & SELECT_ACL) || tables->view && (tables->grant.privilege & SELECT_ACL))) && !any_privileges) { From a4002891fbdbb1e657b8c2b53b5aa02bfeef57da Mon Sep 17 00:00:00 2001 From: "Bernt M. Johnsen" Date: Thu, 26 Feb 2009 18:17:06 +0100 Subject: [PATCH 07/12] Prepared for push (BUG#42567) --- mysql-test/r/group_by.result | 12 ++++++++++++ mysql-test/t/func_group.test | 2 ++ mysql-test/t/group_by.test | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 48f97aeb428..742d4b90807 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1691,3 +1691,15 @@ FROM t1; ERROR 21000: Subquery returns more than 1 row DROP TABLE t1; SET @@sql_mode = @old_sql_mode; +SET @old_sql_mode = @@sql_mode; +SET @@sql_mode='ONLY_FULL_GROUP_BY'; +CREATE TABLE t1(i INT); +INSERT INTO t1 VALUES (1), (10); +SELECT COUNT(i) FROM t1; +COUNT(i) +2 +SELECT COUNT(i) FROM t1 WHERE i > 1; +COUNT(i) +1 +DROP TABLE t1; +SET @@sql_mode = @old_sql_mode; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index be4e9c32686..b0a3d0feb79 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -18,6 +18,8 @@ insert into t1 values (3,5,"C"); insert into t1 values (3,6,"D"); # Test of MySQL field extension with and without matching records. +#### Note: The two following statements may fail if the execution plan +#### or optimizer is changed. The result for column c is undefined. select a,c,sum(a) from t1 group by a; select a,c,sum(a) from t1 where a > 10 group by a; select sum(a) from t1 where a > 10; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index e3cf3ca856d..5b96213034a 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -1139,4 +1139,22 @@ DROP TABLE t1; SET @@sql_mode = @old_sql_mode; +# +# Bug#42567 Invalid GROUP BY error +# + +# Setup of the subtest +SET @old_sql_mode = @@sql_mode; +SET @@sql_mode='ONLY_FULL_GROUP_BY'; + +CREATE TABLE t1(i INT); +INSERT INTO t1 VALUES (1), (10); + +# The actual test +SELECT COUNT(i) FROM t1; +SELECT COUNT(i) FROM t1 WHERE i > 1; + +# Cleanup of subtest +DROP TABLE t1; +SET @@sql_mode = @old_sql_mode; From 494a7641740f20eb5c42d816b527e30a2e24114c Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 27 Feb 2009 09:41:39 +0200 Subject: [PATCH 08/12] addendum to the fix for bug #41354: fixed the error returned by SELECT * --- mysql-test/r/grant2.result | 2 +- mysql-test/t/grant2.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 95748c89103..698e602e2e6 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -433,7 +433,7 @@ USE db1; SELECT c FROM t2; ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for column 'c' in table 't2' SELECT * FROM t2; -ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for column 'c' in table 't2' +ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for table 't2' SELECT * FROM t1 JOIN t2 USING (b); ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for column 'c' in table 't2' USE test; diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 8f83c365170..2393bb1c6d8 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -615,7 +615,7 @@ connection conn1; USE db1; --error ER_COLUMNACCESS_DENIED_ERROR SELECT c FROM t2; ---error ER_COLUMNACCESS_DENIED_ERROR +--error ER_TABLEACCESS_DENIED_ERROR SELECT * FROM t2; --error ER_COLUMNACCESS_DENIED_ERROR SELECT * FROM t1 JOIN t2 USING (b); From 28e64cc32d6b97ef1f10a13d97877f4e2f3cc3db Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Fri, 27 Feb 2009 10:24:57 +0200 Subject: [PATCH 09/12] Bug#41893: main.variables mysql-test fails in new variable like '%alloc%' is added. Added ORDER BY clause to I_S query to ensure consistent order. There were differences between 5.1 and 6.0 output. Correcting it 5.1. --- mysql-test/r/variables.result | 6 +++--- mysql-test/t/variables.test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index c99d3f314c5..0b56e3c1d52 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -318,13 +318,13 @@ transaction_prealloc_size 4096 SELECT * FROM information_schema.session_variables WHERE variable_name IN ('range_alloc_block_size', 'query_alloc_block_size', 'query_prealloc_size', -'transaction_alloc_block_size', 'transaction_prealloc_size'); +'transaction_alloc_block_size', 'transaction_prealloc_size') ORDER BY 1; VARIABLE_NAME VARIABLE_VALUE +QUERY_ALLOC_BLOCK_SIZE 8192 +QUERY_PREALLOC_SIZE 8192 RANGE_ALLOC_BLOCK_SIZE 4096 TRANSACTION_ALLOC_BLOCK_SIZE 8192 TRANSACTION_PREALLOC_SIZE 4096 -QUERY_PREALLOC_SIZE 8192 -QUERY_ALLOC_BLOCK_SIZE 8192 Testing values that are multiples of 1024 set @@range_alloc_block_size=1024*15+1024; set @@query_alloc_block_size=1024*15+1024*2; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 5cfa614f94a..6cd5abc3ea2 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -188,7 +188,7 @@ SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', SELECT * FROM information_schema.session_variables WHERE variable_name IN ('range_alloc_block_size', 'query_alloc_block_size', 'query_prealloc_size', -'transaction_alloc_block_size', 'transaction_prealloc_size'); +'transaction_alloc_block_size', 'transaction_prealloc_size') ORDER BY 1; --echo Testing values that are multiples of 1024 set @@range_alloc_block_size=1024*15+1024; set @@query_alloc_block_size=1024*15+1024*2; From 29ca5d019ca35e530228486ca97f122a1ea95828 Mon Sep 17 00:00:00 2001 From: Ingo Struewing Date: Fri, 27 Feb 2009 12:20:53 +0100 Subject: [PATCH 10/12] Bug#40446 - mysql-test-run --gcov is broken Some variable values were missing and perl constructs failed. Initialized the variables and refactored the gcov functions. --- .bzrignore | 2 ++ mysql-test/lib/mtr_gcov.pl | 58 ++++++++++++++++++++---------------- mysql-test/mysql-test-run.pl | 9 ++++-- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/.bzrignore b/.bzrignore index 01ef6f2ffef..fad758b54b8 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1295,6 +1295,8 @@ mysql-test/linux_sys_vars.inc mysql-test/load_sysvars.inc mysql-test/mtr mysql-test/mysql-test-run +mysql-test/mysql-test-gcov.err +mysql-test/mysql-test-gcov.msg mysql-test/mysql-test-run-shell mysql-test/mysql-test-run.log mysql-test/mysql_test_run_new diff --git a/mysql-test/lib/mtr_gcov.pl b/mysql-test/lib/mtr_gcov.pl index 5049fdd6063..f531889b08d 100644 --- a/mysql-test/lib/mtr_gcov.pl +++ b/mysql-test/lib/mtr_gcov.pl @@ -22,40 +22,46 @@ use strict; sub gcov_prepare ($) { my ($dir)= @_; + print "Purging gcov information from '$dir'...\n"; - `find $dir -name \*.gcov \ - -or -name \*.da | xargs rm`; + system("find $dir -name \*.gcov -o -name \*.da" + . " -o -name \*.gcda | grep -v 'README.gcov\$' | xargs rm"); } -my @mysqld_src_dirs= - ( - "strings", - "mysys", - "include", - "extra", - "regex", - "isam", - "merge", - "myisam", - "myisammrg", - "heap", - "sql", - ); - +# +# Collect gcov statistics. +# Arguments: +# $dir basedir, normally source directory +# $gcov gcov utility program [path] name +# $gcov_msg message file name +# $gcov_err error file name +# sub gcov_collect ($$$) { my ($dir, $gcov, $gcov_msg, $gcov_err)= @_; + # Get current directory to return to later. my $start_dir= cwd(); - print "Collecting source coverage info...\n"; - -f $gcov_msg and unlink($gcov_msg); - -f $gcov_err and unlink($gcov_err); - foreach my $d ( @mysqld_src_dirs ) - { - chdir("$dir/$d"); - foreach my $f ( (glob("*.h"), glob("*.cc"), glob("*.c")) ) - { - `$gcov $f 2>>$gcov_err >>$gcov_msg`; + print "Collecting source coverage info using '$gcov'...\n"; + -f "$start_dir/$gcov_msg" and unlink("$start_dir/$gcov_msg"); + -f "$start_dir/$gcov_err" and unlink("$start_dir/$gcov_err"); + + my @dirs= `find "$dir" -type d -print | sort`; + #print "List of directories:\n@dirs\n"; + + foreach my $d ( @dirs ) { + my $dir_reported= 0; + chomp($d); + chdir($d) or next; + + foreach my $f ( (glob("*.h"), glob("*.cc"), glob("*.c")) ) { + $f =~ /(.*)\.[ch]c?/; + -f "$1.gcno" or next; + if (!$dir_reported) { + print "Collecting in '$d'...\n"; + $dir_reported= 1; + } + system("$gcov $f 2>>$start_dir/$gcov_err >>$start_dir/$gcov_msg"); } chdir($start_dir); } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 50617428d0f..b0b044b67f4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -163,8 +163,9 @@ our $opt_force; our $opt_mem= $ENV{'MTR_MEM'}; our $opt_gcov; -our $opt_gcov_err; -our $opt_gcov_msg; +our $opt_gcov_exe= "gcov"; +our $opt_gcov_err= "mysql-test-gcov.msg"; +our $opt_gcov_msg= "mysql-test-gcov.err"; our $glob_debugger= 0; our $opt_gdb; @@ -396,7 +397,7 @@ sub main { mtr_print_line(); if ( $opt_gcov ) { - gcov_collect($basedir, $opt_gcov, + gcov_collect($basedir, $opt_gcov_exe, $opt_gcov_msg, $opt_gcov_err); } @@ -5057,6 +5058,8 @@ Misc options to turn off. sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time + gcov Collect coverage information after the test. + The result is a gcov file per source and header file. HERE exit(1); From fb784056258043a062525c720c3f0004931f3bcd Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Fri, 27 Feb 2009 15:00:49 +0200 Subject: [PATCH 11/12] Bug#41893: Removal of trailing space noise causing Pushbuild failure. --- mysql-test/r/variables.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 04ccf3d688c..fbec38c9a9f 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -292,7 +292,7 @@ transaction_prealloc_size 20480 set @@range_alloc_block_size=default; set @@query_alloc_block_size=default, @@query_prealloc_size=default; set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; -==+ Check the values not that they are reset +== +==+ Check the values now that they are reset +== SHOW VARIABLES WHERE variable_name IN ('range_alloc_block_size', 'query_alloc_block_size', 'query_prealloc_size', 'transaction_alloc_block_size', 'transaction_prealloc_size'); From 4d2f047e954f8f78c7b84187385353f76c642f4c Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 27 Feb 2009 15:25:06 +0200 Subject: [PATCH 12/12] Bug #41610: key_infix_len can be overwritten causing some group by queries to return no rows The algorithm of determining the best key for loose index scan is doing a loop over the available indexes and selects the one that has the best cost. It retrieves the parameters of the current index into a set of variables. If the cost of using the current index is lower than the best cost so far it copies these variables into another set of variables that contain the information for the best index so far. After having checked all the indexes it uses these variables (outside of the index loop) to create the table read plan object instance. The was a single omission : the key_infix/key_infix_len variables were used outside of the loop without being preserved in the loop for the best index so far. This causes these variables to get overwritten by the next index(es) checked. Fixed by adding variables to hold the data for the current index, passing the new variables to the function that assigns values to them and copying the new variables into the existing ones when selecting a new current best index. To avoid further such problems moved the declarations of the variables used to keep information about the current index inside the loop's compound statement. --- mysql-test/r/group_min_max.result | 15 ++++++++ mysql-test/t/group_min_max.test | 23 +++++++++++++ sql/opt_range.cc | 57 +++++++++++++++++-------------- 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index f2f488650d5..58be2af1bb8 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2429,3 +2429,18 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select sql_buffer_result `test`.`t1`.`a` AS `a`,(max(`test`.`t1`.`b`) + 1) AS `max(b)+1` from `test`.`t1` where (`test`.`t1`.`a` = 0) group by `test`.`t1`.`a` drop table t1; +CREATE TABLE t1 (a int, b int, c int, d int, +KEY foo (c,d,a,b), KEY bar (c,a,b,d)); +INSERT INTO t1 VALUES (1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 1, 3), (1, 1, 1, 4); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT a,b,c+1,d FROM t1; +EXPLAIN SELECT DISTINCT c FROM t1 WHERE d=4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL foo 10 NULL 9 Using where; Using index for group-by +SELECT DISTINCT c FROM t1 WHERE d=4; +c +1 +2 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index f7aed7301fb..e124bf9e786 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -935,3 +935,26 @@ insert into t1 (a,b) select a, max(b)+1 from t1 where a = 0 group by a; select * from t1; explain extended select sql_buffer_result a, max(b)+1 from t1 where a = 0 group by a; drop table t1; + + +# +# Bug #41610: key_infix_len can be overwritten causing some group by queries +# to return no rows +# + +CREATE TABLE t1 (a int, b int, c int, d int, + KEY foo (c,d,a,b), KEY bar (c,a,b,d)); + +INSERT INTO t1 VALUES (1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 1, 3), (1, 1, 1, 4); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT a,b,c+1,d FROM t1; + +#Should be non-empty +--ordered_result +EXPLAIN SELECT DISTINCT c FROM t1 WHERE d=4; +SELECT DISTINCT c FROM t1 WHERE d=4; + +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ebebfafb5d8..018fc8a9d44 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7775,32 +7775,37 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ KEY *cur_index_info= table->key_info; KEY *cur_index_info_end= cur_index_info + table->s->keys; - KEY_PART_INFO *cur_part= NULL; - KEY_PART_INFO *end_part; /* Last part for loops. */ - /* Last index part. */ - KEY_PART_INFO *last_part= NULL; - KEY_PART_INFO *first_non_group_part= NULL; - KEY_PART_INFO *first_non_infix_part= NULL; - uint key_infix_parts= 0; - uint cur_group_key_parts= 0; - uint cur_group_prefix_len= 0; /* Cost-related variables for the best index so far. */ double best_read_cost= DBL_MAX; ha_rows best_records= 0; SEL_ARG *best_index_tree= NULL; ha_rows best_quick_prefix_records= 0; uint best_param_idx= 0; - double cur_read_cost= DBL_MAX; - ha_rows cur_records; + + const uint pk= param->table->s->primary_key; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; uint cur_param_idx=MAX_KEY; - key_map cur_used_key_parts; - uint pk= param->table->s->primary_key; for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; cur_index_info++, cur_index++) { + KEY_PART_INFO *cur_part; + KEY_PART_INFO *end_part; /* Last part for loops. */ + /* Last index part. */ + KEY_PART_INFO *last_part; + KEY_PART_INFO *first_non_group_part; + KEY_PART_INFO *first_non_infix_part; + uint key_infix_parts; + uint cur_group_key_parts= 0; + uint cur_group_prefix_len= 0; + double cur_read_cost; + ha_rows cur_records; + key_map used_key_parts_map; + uint cur_key_infix_len= 0; + byte cur_key_infix[MAX_KEY_LENGTH]; + uint cur_used_key_parts; + /* Check (B1) - if current index is covering. */ if (!table->used_keys.is_set(cur_index)) goto next_index; @@ -7879,7 +7884,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) else if (join->select_distinct) { select_items_it.rewind(); - cur_used_key_parts.clear_all(); + used_key_parts_map.clear_all(); uint max_key_part= 0; while ((item= select_items_it++)) { @@ -7890,13 +7895,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) Check if this attribute was already present in the select list. If it was present, then its corresponding key part was alredy used. */ - if (cur_used_key_parts.is_set(key_part_nr)) + if (used_key_parts_map.is_set(key_part_nr)) continue; if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) goto next_index; cur_part= cur_index_info->key_part + key_part_nr - 1; cur_group_prefix_len+= cur_part->store_length; - cur_used_key_parts.set_bit(key_part_nr); + used_key_parts_map.set_bit(key_part_nr); ++cur_group_key_parts; max_key_part= max(max_key_part,key_part_nr); } @@ -7908,7 +7913,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ ulonglong all_parts, cur_parts; all_parts= (1<> 1; + cur_parts= used_key_parts_map.to_ulonglong() >> 1; if (all_parts != cur_parts) goto next_index; } @@ -7958,7 +7963,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) &dummy); if (!get_constant_key_infix(cur_index_info, index_range_tree, first_non_group_part, min_max_arg_part, - last_part, thd, key_infix, &key_infix_len, + last_part, thd, cur_key_infix, + &cur_key_infix_len, &first_non_infix_part)) goto next_index; } @@ -8010,9 +8016,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) } /* If we got to this point, cur_index_info passes the test. */ - key_infix_parts= key_infix_len ? + key_infix_parts= cur_key_infix_len ? (first_non_infix_part - first_non_group_part) : 0; - used_key_parts= cur_group_key_parts + key_infix_parts; + cur_used_key_parts= cur_group_key_parts + key_infix_parts; /* Compute the cost of using this index. */ if (tree) @@ -8024,7 +8030,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) cur_quick_prefix_records= check_quick_select(param, cur_param_idx, cur_index_tree); } - cost_group_min_max(table, cur_index_info, used_key_parts, + cost_group_min_max(table, cur_index_info, cur_used_key_parts, cur_group_key_parts, tree, cur_index_tree, cur_quick_prefix_records, have_min, have_max, &cur_read_cost, &cur_records); @@ -8035,7 +8041,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) { - DBUG_ASSERT(tree != 0 || cur_param_idx == MAX_KEY); index_info= cur_index_info; index= cur_index; best_read_cost= cur_read_cost; @@ -8045,11 +8050,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) best_param_idx= cur_param_idx; group_key_parts= cur_group_key_parts; group_prefix_len= cur_group_prefix_len; + key_infix_len= cur_key_infix_len; + if (key_infix_len) + memcpy (key_infix, cur_key_infix, sizeof (key_infix)); + used_key_parts= cur_used_key_parts; } - next_index: - cur_group_key_parts= 0; - cur_group_prefix_len= 0; + next_index:; } if (!index_info) /* No usable index found. */ DBUG_RETURN(NULL);