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/r/view_grant.result b/mysql-test/r/view_grant.result index 1d5f12320dd..1ae94926928 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -921,6 +921,32 @@ 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. DROP VIEW IF EXISTS v1; DROP TABLE IF EXISTS t1; 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; 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'; # diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index f3794a6ba73..a08d0d0e097 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1191,6 +1191,46 @@ 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/protocol.cc b/sql/protocol.cc index 4177cd0054d..16975c68a54 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -573,7 +573,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 @@ -584,12 +585,22 @@ 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 : (uint32) 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 0d32a7fc4ce..cd40c409234 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -723,6 +723,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))) { @@ -731,6 +732,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); @@ -745,8 +748,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`)", @@ -782,11 +785,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);