diff options
30 files changed, 594 insertions, 679 deletions
diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 4bc6c0409f3..4a815549ba9 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -176,11 +176,12 @@ SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); -ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause -SHOW WARNINGS; -Level Code Message -Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause -Note 1003 select 1 AS `1` from `test`.`t1` where <not>(<exists>(...)) +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 SUBQUERY t1 system NULL NULL NULL NULL 0 0.00 const row not found +2 SUBQUERY t system NULL NULL NULL NULL 0 0.00 const row not found +Warnings: +Note 1003 select 1 AS `1` from `test`.`t1` where 0 SET SESSION sql_mode=@old_sql_mode; DROP TABLE t1; End of 5.0 tests. diff --git a/mysql-test/r/secure_file_priv_win.result b/mysql-test/r/secure_file_priv_win.result new file mode 100644 index 00000000000..d6636aad5d4 --- /dev/null +++ b/mysql-test/r/secure_file_priv_win.result @@ -0,0 +1,38 @@ +CREATE TABLE t1 (c1 longtext); +INSERT INTO t1 values ('a'); +SELECT * FROM t1 INTO OUTFILE 'MYSQL_TMP_DIR/B11764517.tmp'; +show global variables like 'secure_file_priv'; +Variable_name Value +secure_file_priv MYSQL_TMP_DIR/ +SELECT load_file('MYSQL_TMP_DIR\\B11764517.tmp') AS x; +x +a + +SELECT load_file('MYSQL_TMP_DIR/B11764517.tmp') AS x; +x +a + +SELECT load_file('MYSQL_TMP_DIR_UCASE/B11764517.tmp') AS x; +x +a + +SELECT load_file('MYSQL_TMP_DIR_LCASE/B11764517.tmp') AS x; +x +a + +SELECT load_file('MYSQL_TMP_DIR\\..a..\\..\\..\\B11764517.tmp') AS x; +x +NULL +LOAD DATA INFILE 'MYSQL_TMP_DIR\\B11764517.tmp' INTO TABLE t1; +LOAD DATA INFILE 'MYSQL_TMP_DIR/B11764517.tmp' INTO TABLE t1; +LOAD DATA INFILE 'MYSQL_TMP_DIR_UCASE/B11764517.tmp' INTO TABLE t1; +LOAD DATA INFILE 'MYSQL_TMP_DIR_LCASE/B11764517.tmp' INTO TABLE t1; +LOAD DATA INFILE "MYSQL_TMP_DIR\\..a..\\..\\..\\B11764517.tmp" into table t1; +ERROR HY000: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement +SELECT * FROM t1 INTO OUTFILE 'MYSQL_TMP_DIR\\..a..\\..\\..\\B11764517-2.tmp'; +ERROR HY000: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement +SELECT * FROM t1 INTO OUTFILE 'MYSQL_TMP_DIR\\B11764517-2.tmp'; +SELECT * FROM t1 INTO OUTFILE 'MYSQL_TMP_DIR/B11764517-3.tmp'; +SELECT * FROM t1 INTO OUTFILE 'MYSQL_TMP_DIR_UCASE/B11764517-4.tmp'; +SELECT * FROM t1 INTO OUTFILE 'MYSQL_TMP_DIR_LCASE/B11764517-5.tmp'; +DROP TABLE t1; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index c45ada2047a..39e39f2db5e 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -567,3 +567,28 @@ DROP USER 'tester'; DROP USER 'Tester'; DROP DATABASE B48872; End of 5.0 tests. +# +# Bug#11882603 SELECT_ACL ON ANY COLUMN IN MYSQL.PROC ALLOWS TO SEE +# DEFINITION OF ANY ROUTINE. +# +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1; +CREATE PROCEDURE db1.p1() SELECT 1; +CREATE USER user2@localhost IDENTIFIED BY ''; +GRANT SELECT(db) ON mysql.proc TO user2@localhost; +# Connection con2 as user2 +# The statement below before disclosed info from body_utf8 column. +SHOW CREATE PROCEDURE db1.p1; +ERROR 42000: PROCEDURE p1 does not exist +# Check that SHOW works with SELECT grant on whole table +# Connection default +GRANT SELECT ON mysql.proc TO user2@localhost; +# Connection con2 +# This should work +SHOW CREATE PROCEDURE db1.p1; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci +# Connection default +DROP USER user2@localhost; +DROP DATABASE db1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5f86b0db132..26e8e3ad0ef 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4435,6 +4435,32 @@ pk int_key 3 3 7 3 DROP TABLE t1,t2; +# +# Bug#12329653 +# EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY +# +CREATE TABLE t1(a1 int); +INSERT INTO t1 VALUES (1),(2); +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); +1 +1 +1 +PREPARE stmt FROM +'SELECT 1 UNION ALL +SELECT 1 FROM t1 +ORDER BY +(SELECT 1 FROM t1 AS t1_0 + WHERE 1 < SOME (SELECT a1 FROM t1) +)' ; +EXECUTE stmt ; +ERROR 21000: Subquery returns more than 1 row +EXECUTE stmt ; +ERROR 21000: Subquery returns more than 1 row +SET SESSION sql_mode=@old_sql_mode; +DEALLOCATE PREPARE stmt; +DROP TABLE t1; End of 5.0 tests. CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (2,22),(1,11),(2,22); diff --git a/mysql-test/suite/innodb_plugin/r/innodb-index.result b/mysql-test/suite/innodb_plugin/r/innodb-index.result index 547d253911a..32a029bc4ca 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-index.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-index.result @@ -1,3 +1,46 @@ +set global innodb_file_per_table=on; +set global innodb_file_format='Barracuda'; +CREATE TABLE t1_purge ( +A INT, +B BLOB, C BLOB, D BLOB, E BLOB, +F BLOB, G BLOB, H BLOB, +PRIMARY KEY (B(767), C(767), D(767), E(767), A), +INDEX (A) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO t1_purge VALUES (1, +REPEAT('b', 766), REPEAT('c', 766), REPEAT('d', 766), REPEAT('e', 766), +REPEAT('f', 766), REPEAT('g', 766), REPEAT('h', 766)); +CREATE TABLE t2_purge ( +A INT PRIMARY KEY, +B BLOB, C BLOB, D BLOB, E BLOB, +F BLOB, G BLOB, H BLOB, I BLOB, +J BLOB, K BLOB, L BLOB, +INDEX (B(767))) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO t2_purge VALUES (1, +REPEAT('b', 766), REPEAT('c', 766), REPEAT('d', 766), REPEAT('e', 766), +REPEAT('f', 766), REPEAT('g', 766), REPEAT('h', 766), REPEAT('i', 766), +REPEAT('j', 766), REPEAT('k', 766), REPEAT('l', 766)); +CREATE TABLE t3_purge ( +A INT, +B VARCHAR(800), C VARCHAR(800), D VARCHAR(800), E VARCHAR(800), +F VARCHAR(800), G VARCHAR(800), H VARCHAR(800), +PRIMARY KEY (B(767), C(767), D(767), E(767), A), +INDEX (A) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO t3_purge SELECT * FROM t1_purge; +CREATE TABLE t4_purge ( +A INT PRIMARY KEY, +B VARCHAR(800), C VARCHAR(800), D VARCHAR(800), E VARCHAR(800), +F VARCHAR(800), G VARCHAR(800), H VARCHAR(800), I VARCHAR(800), +J VARCHAR(800), K VARCHAR(800), L VARCHAR(800), +INDEX (B(767))) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO t4_purge SELECT * FROM t2_purge; +DELETE FROM t1_purge; +DELETE FROM t2_purge; +DELETE FROM t3_purge; +DELETE FROM t4_purge; +set global innodb_file_per_table=0; +set global innodb_file_format=Antelope; create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak'); commit; @@ -1183,3 +1226,4 @@ a b 3 a 3 b DROP TABLE t1; +DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index d8a4a13edd7..28393553ec2 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -4,6 +4,65 @@ let $MYSQLD_DATADIR= `select @@datadir`; let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; +let $per_table=`select @@innodb_file_per_table`; +let $format=`select @@innodb_file_format`; +set global innodb_file_per_table=on; +set global innodb_file_format='Barracuda'; + +# Test an assertion failure on purge. +CREATE TABLE t1_purge ( +A INT, +B BLOB, C BLOB, D BLOB, E BLOB, +F BLOB, G BLOB, H BLOB, +PRIMARY KEY (B(767), C(767), D(767), E(767), A), +INDEX (A) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO t1_purge VALUES (1, +REPEAT('b', 766), REPEAT('c', 766), REPEAT('d', 766), REPEAT('e', 766), +REPEAT('f', 766), REPEAT('g', 766), REPEAT('h', 766)); + +CREATE TABLE t2_purge ( +A INT PRIMARY KEY, +B BLOB, C BLOB, D BLOB, E BLOB, +F BLOB, G BLOB, H BLOB, I BLOB, +J BLOB, K BLOB, L BLOB, +INDEX (B(767))) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO t2_purge VALUES (1, +REPEAT('b', 766), REPEAT('c', 766), REPEAT('d', 766), REPEAT('e', 766), +REPEAT('f', 766), REPEAT('g', 766), REPEAT('h', 766), REPEAT('i', 766), +REPEAT('j', 766), REPEAT('k', 766), REPEAT('l', 766)); + +CREATE TABLE t3_purge ( +A INT, +B VARCHAR(800), C VARCHAR(800), D VARCHAR(800), E VARCHAR(800), +F VARCHAR(800), G VARCHAR(800), H VARCHAR(800), +PRIMARY KEY (B(767), C(767), D(767), E(767), A), +INDEX (A) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO t3_purge SELECT * FROM t1_purge; + +CREATE TABLE t4_purge ( +A INT PRIMARY KEY, +B VARCHAR(800), C VARCHAR(800), D VARCHAR(800), E VARCHAR(800), +F VARCHAR(800), G VARCHAR(800), H VARCHAR(800), I VARCHAR(800), +J VARCHAR(800), K VARCHAR(800), L VARCHAR(800), +INDEX (B(767))) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO t4_purge SELECT * FROM t2_purge; + +# This would trigger the failure (Bug #12429576) +# if purge gets a chance to run before DROP TABLE t1_purge, .... +DELETE FROM t1_purge; +DELETE FROM t2_purge; +DELETE FROM t3_purge; +DELETE FROM t4_purge; + +eval set global innodb_file_per_table=$per_table; +eval set global innodb_file_format=$format; + create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak'); commit; @@ -360,8 +419,6 @@ disconnect b; drop table t1; -let $per_table=`select @@innodb_file_per_table`; -let $format=`select @@innodb_file_format`; set global innodb_file_per_table=on; set global innodb_file_format='Barracuda'; # Test creating a table that could lead to undo log overflow. @@ -557,6 +614,7 @@ disconnect a; disconnect b; DROP TABLE t1; +DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; # # restore environment to the state it was before this test execution diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index c6c30b58341..e764ee80578 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -1,5 +1,5 @@ # -# Test of different EXPLAIN's +# Test of different EXPLAINs --disable_warnings drop table if exists t1; @@ -157,11 +157,12 @@ CREATE TABLE t1 (f1 INT); SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; -# EXPLAIN EXTENDED (with subselect). used to crash. should give NOTICE. ---error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +# EXPLAIN EXTENDED (with subselect). used to crash. +# This is actually a valid query for this sql_mode, +# but it was transformed in such a way that it failed, see +# Bug#12329653 - EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); -SHOW WARNINGS; SET SESSION sql_mode=@old_sql_mode; diff --git a/mysql-test/t/secure_file_priv_win-master.opt b/mysql-test/t/secure_file_priv_win-master.opt new file mode 100644 index 00000000000..e9a43a5584d --- /dev/null +++ b/mysql-test/t/secure_file_priv_win-master.opt @@ -0,0 +1 @@ +--secure_file_priv=$MYSQL_TMP_DIR diff --git a/mysql-test/t/secure_file_priv_win.test b/mysql-test/t/secure_file_priv_win.test new file mode 100644 index 00000000000..a12510974ce --- /dev/null +++ b/mysql-test/t/secure_file_priv_win.test @@ -0,0 +1,79 @@ +# +# Bug58747 breaks secure_file_priv+not secure yet+still accesses other folders +# + +# we do the windows specific relative directory testing + +--source include/windows.inc + +CREATE TABLE t1 (c1 longtext); +INSERT INTO t1 values ('a'); + +LET $MYSQL_TMP_DIR_UCASE= `SELECT upper('$MYSQL_TMP_DIR')`; +LET $MYSQL_TMP_DIR_LCASE= `SELECT lower('$MYSQL_TMP_DIR')`; + +#create the file +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval SELECT * FROM t1 INTO OUTFILE '$MYSQL_TMP_DIR/B11764517.tmp'; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +show global variables like 'secure_file_priv'; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval SELECT load_file('$MYSQL_TMP_DIR\\\\B11764517.tmp') AS x; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval SELECT load_file('$MYSQL_TMP_DIR/B11764517.tmp') AS x; + +--replace_result $MYSQL_TMP_DIR_UCASE MYSQL_TMP_DIR_UCASE +eval SELECT load_file('$MYSQL_TMP_DIR_UCASE/B11764517.tmp') AS x; + +--replace_result $MYSQL_TMP_DIR_LCASE MYSQL_TMP_DIR_LCASE +eval SELECT load_file('$MYSQL_TMP_DIR_LCASE/B11764517.tmp') AS x; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval SELECT load_file('$MYSQL_TMP_DIR\\\\..a..\\\\..\\\\..\\\\B11764517.tmp') AS x; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval LOAD DATA INFILE '$MYSQL_TMP_DIR\\\\B11764517.tmp' INTO TABLE t1; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval LOAD DATA INFILE '$MYSQL_TMP_DIR/B11764517.tmp' INTO TABLE t1; + +--replace_result $MYSQL_TMP_DIR_UCASE MYSQL_TMP_DIR_UCASE +eval LOAD DATA INFILE '$MYSQL_TMP_DIR_UCASE/B11764517.tmp' INTO TABLE t1; + +--replace_result $MYSQL_TMP_DIR_LCASE MYSQL_TMP_DIR_LCASE +eval LOAD DATA INFILE '$MYSQL_TMP_DIR_LCASE/B11764517.tmp' INTO TABLE t1; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +--error ER_OPTION_PREVENTS_STATEMENT +eval LOAD DATA INFILE "$MYSQL_TMP_DIR\\\\..a..\\\\..\\\\..\\\\B11764517.tmp" into table t1; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +--error ER_OPTION_PREVENTS_STATEMENT +eval SELECT * FROM t1 INTO OUTFILE '$MYSQL_TMP_DIR\\\\..a..\\\\..\\\\..\\\\B11764517-2.tmp'; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval SELECT * FROM t1 INTO OUTFILE '$MYSQL_TMP_DIR\\\\B11764517-2.tmp'; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval SELECT * FROM t1 INTO OUTFILE '$MYSQL_TMP_DIR/B11764517-3.tmp'; + +--replace_result $MYSQL_TMP_DIR_UCASE MYSQL_TMP_DIR_UCASE +eval SELECT * FROM t1 INTO OUTFILE '$MYSQL_TMP_DIR_UCASE/B11764517-4.tmp'; + +--replace_result $MYSQL_TMP_DIR_LCASE MYSQL_TMP_DIR_LCASE +eval SELECT * FROM t1 INTO OUTFILE '$MYSQL_TMP_DIR_LCASE/B11764517-5.tmp'; + +--error 0,1 +--remove_file $MYSQL_TMP_DIR/B11764517.tmp; +--error 0,1 +--remove_file $MYSQL_TMP_DIR/B11764517-2.tmp; +--error 0,1 +--remove_file $MYSQL_TMP_DIR/B11764517-3.tmp; +--error 0,1 +--remove_file $MYSQL_TMP_DIR/B11764517-4.tmp; +--error 0,1 +--remove_file $MYSQL_TMP_DIR/B11764517-5.tmp; +DROP TABLE t1; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 96f82c92248..b7a99ad4103 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -926,6 +926,43 @@ DROP DATABASE B48872; --echo End of 5.0 tests. +--echo # +--echo # Bug#11882603 SELECT_ACL ON ANY COLUMN IN MYSQL.PROC ALLOWS TO SEE +--echo # DEFINITION OF ANY ROUTINE. +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +--enable_warnings + +CREATE DATABASE db1; +CREATE PROCEDURE db1.p1() SELECT 1; +CREATE USER user2@localhost IDENTIFIED BY ''; +GRANT SELECT(db) ON mysql.proc TO user2@localhost; + +--echo # Connection con2 as user2 +connect (con2, localhost, user2); +--echo # The statement below before disclosed info from body_utf8 column. +--error ER_SP_DOES_NOT_EXIST +SHOW CREATE PROCEDURE db1.p1; + +--echo # Check that SHOW works with SELECT grant on whole table +--echo # Connection default +connection default; +GRANT SELECT ON mysql.proc TO user2@localhost; + +--echo # Connection con2 +connection con2; +--echo # This should work +SHOW CREATE PROCEDURE db1.p1; + +--echo # Connection default +connection default; +disconnect con2; +DROP USER user2@localhost; +DROP DATABASE db1; + + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 94a3df21998..4c5ecbd9ee6 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3393,6 +3393,39 @@ ORDER BY outr.pk; DROP TABLE t1,t2; +--echo # +--echo # Bug#12329653 +--echo # EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY +--echo # + +CREATE TABLE t1(a1 int); +INSERT INTO t1 VALUES (1),(2); + +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; + +## First a simpler query, illustrating the transformation +## '1 < some (...)' => '1 < max(...)' +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); + +## The query which made the server crash. +PREPARE stmt FROM +'SELECT 1 UNION ALL +SELECT 1 FROM t1 +ORDER BY +(SELECT 1 FROM t1 AS t1_0 + WHERE 1 < SOME (SELECT a1 FROM t1) +)' ; + +--error ER_SUBQUERY_NO_1_ROW +EXECUTE stmt ; +--error ER_SUBQUERY_NO_1_ROW +EXECUTE stmt ; + +SET SESSION sql_mode=@old_sql_mode; + +DEALLOCATE PREPARE stmt; +DROP TABLE t1; --echo End of 5.0 tests. diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index c3f558ec32a..365817ea15b 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -146,24 +146,23 @@ int my_realpath(char *to, const char *filename, myf MyFlags) result= -1; } DBUG_RETURN(result); -#else -#ifdef _WIN32 - int ret= GetFullPathName(filename,FN_REFLEN,
- to,
- NULL); +#elif defined(_WIN32) + int ret= GetFullPathName(filename,FN_REFLEN, to, NULL); if (ret == 0 || ret > FN_REFLEN) { - if (ret > FN_REFLEN) - my_errno= ENAMETOOLONG; - else - my_errno= EACCES; + my_errno= (ret > FN_REFLEN) ? ENAMETOOLONG : GetLastError(); if (MyFlags & MY_WME) my_error(EE_REALPATH, MYF(0), filename, my_errno); - return -1; + /* + GetFullPathName didn't work : use my_load_path() which is a poor + substitute original name but will at least be able to resolve + paths that starts with '.'. + */ + my_load_path(to, filename, NullS); + return -1; } #else my_load_path(to, filename, NullS); #endif return 0; -#endif } diff --git a/sql/item.cc b/sql/item.cc index 15fd5489d32..930c5d7426e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4466,14 +4466,14 @@ mark_non_agg_field: SELECT_LEX *select_lex= cached_table ? cached_table->select_lex : context->select_lex; if (!thd->lex->in_sum_func) - select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + select_lex->set_non_agg_field_used(true); else { if (outer_fixed) thd->lex->in_sum_func->outer_fields.push_back(this); else if (thd->lex->in_sum_func->nest_level != thd->lex->current_select->nest_level) - select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + select_lex->set_non_agg_field_used(true); } } return FALSE; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 53d4ac2d0a8..10dd6c93717 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1016,6 +1016,14 @@ Item_in_subselect::single_value_transformer(JOIN *join, it.replace(item); } + DBUG_EXECUTE("where", + print_where(item, "rewrite with MIN/MAX", QT_ORDINARY);); + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + { + DBUG_ASSERT(select_lex->non_agg_field_used()); + select_lex->set_non_agg_field_used(false); + } + save_allow_sum_func= thd->lex->allow_sum_func; thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; /* diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d480fae8a4c..40ac31918be 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -247,10 +247,10 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) in_sum_func->outer_fields.push_back(field); } else - sel->full_group_by_flag|= NON_AGG_FIELD_USED; + sel->set_non_agg_field_used(true); } if (sel->nest_level > aggr_level && - (sel->full_group_by_flag & SUM_FUNC_USED) && + (sel->agg_func_used()) && !sel->group_list.elements) { my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, @@ -259,7 +259,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) } } } - aggr_sel->full_group_by_flag|= SUM_FUNC_USED; + aggr_sel->set_agg_func_used(true); update_used_tables(); thd->lex->in_sum_func= in_sum_func; return FALSE; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9d692ec5ba1..4b89a7a7961 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1476,13 +1476,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, extern Item **not_found_item; /* - A set of constants used for checking non aggregated fields and sum - functions mixture in the ONLY_FULL_GROUP_BY_MODE. -*/ -#define NON_AGG_FIELD_USED 1 -#define SUM_FUNC_USED 2 - -/* This enumeration type is used only by the function find_item_in_list to return the info on how an item has been resolved against a list of possibly aliased items. diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4c573e1ded1..d205cbf6e9c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8973,12 +8973,15 @@ fn_format_relative_to_data_home(char * to, const char *name, bool is_secure_file_path(char *path) { char buff1[FN_REFLEN], buff2[FN_REFLEN]; + size_t opt_secure_file_priv_len; /* All paths are secure if opt_secure_file_path is 0 */ if (!opt_secure_file_priv) return TRUE; + opt_secure_file_priv_len= strlen(opt_secure_file_priv); + if (strlen(path) >= FN_REFLEN) return FALSE; @@ -8996,11 +8999,24 @@ bool is_secure_file_path(char *path) return FALSE; } convert_dirname(buff2, buff1, NullS); - if (strncmp(opt_secure_file_priv, buff2, strlen(opt_secure_file_priv))) - return FALSE; + if (!lower_case_file_system) + { + if (strncmp(opt_secure_file_priv, buff2, opt_secure_file_priv_len)) + return FALSE; + } + else + { + if (files_charset_info->coll->strnncoll(files_charset_info, + (uchar *) buff2, strlen(buff2), + (uchar *) opt_secure_file_priv, + opt_secure_file_priv_len, + TRUE)) + return FALSE; + } return TRUE; } + static int fix_paths(void) { char buff[FN_REFLEN],*pos; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0ec8ce11c65..95a7eda0540 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2403,7 +2403,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) bzero((char*) &tables,sizeof(tables)); tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*) "proc"; - *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1, TRUE) || + *full_access= ((!check_table_access(thd, SELECT_ACL, &tables, 1, TRUE) && + (tables.grant.privilege & SELECT_ACL) != 0) || (!strcmp(sp->m_definer_user.str, thd->security_ctx->priv_user) && !strcmp(sp->m_definer_host.str, diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 2a2f11e7f46..44b4af74ef1 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -21,23 +21,10 @@ #include "mysql_priv.h" -#ifdef HAVE_OPENSSL -/* - Without SSL the handshake consists of one packet. This packet - has both client capabilites and scrambled password. - With SSL the handshake might consist of two packets. If the first - packet (client capabilities) has CLIENT_SSL flag set, we have to - switch to SSL and read the second packet. The scrambled password - is in the second packet and client_capabilites field will be ignored. - Maybe it is better to accept flags other than CLIENT_SSL from the - second packet? -*/ -#define SSL_HANDSHAKE_SIZE 2 -#define NORMAL_HANDSHAKE_SIZE 6 -#define MIN_HANDSHAKE_SIZE 2 -#else -#define MIN_HANDSHAKE_SIZE 6 -#endif /* HAVE_OPENSSL */ +/** Size of the header fields of an authentication packet. */ +#define AUTH_PACKET_HEADER_SIZE_PROTO_41 32 +#define AUTH_PACKET_HEADER_SIZE_PROTO_40 5 +#define AUTH_PACKET_HEADER_SIZE_CONNJ_SSL 4 #ifdef __WIN__ extern void win_install_sigabrt_handler(); @@ -822,6 +809,14 @@ static int check_connection(THD *thd) ulong pkt_len= 0; char *end; + bool packet_has_required_size= false; + char *db; + size_t db_len; + char *passwd; + size_t passwd_len; + char *user; + size_t user_len; + DBUG_PRINT("info", ("New connection received on %s", vio_description(net->vio))); #ifdef SIGNAL_WITH_VIO_CLOSE @@ -930,8 +925,7 @@ static int check_connection(THD *thd) /* At this point we write connection message and read reply */ if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0, (uchar*) buff, (size_t) (end-buff)) || - (pkt_len= my_net_read(net)) == packet_error || - pkt_len < MIN_HANDSHAKE_SIZE) + (pkt_len= my_net_read(net)) == packet_error) { inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); @@ -946,22 +940,82 @@ static int check_connection(THD *thd) if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ - thd->client_capabilities= uint2korr(net->read_pos); + uint charset_code= 0; + end= (char *)net->read_pos; + /* + In order to safely scan a head for '\0' string terminators + we must keep track of how many bytes remain in the allocated + buffer or we might read past the end of the buffer. + */ + size_t bytes_remaining_in_packet= pkt_len; + + /* + Peek ahead on the client capability packet and determine which version of + the protocol should be used. + */ + if (bytes_remaining_in_packet < 2) + goto error; + + thd->client_capabilities= uint2korr(end); + + /* + Connector/J only sends client capabilities (4 bytes) before starting SSL + negotiation so we don't have char_set and other information for client in + packet read. In that case, skip reading those information. The below code + is patch for this. + */ + if(bytes_remaining_in_packet == AUTH_PACKET_HEADER_SIZE_CONNJ_SSL && + (thd->client_capabilities & CLIENT_SSL)) + { + thd->client_capabilities= uint4korr(end); + thd->max_client_packet_length= global_system_variables.max_allowed_packet; + charset_code= default_charset_info->number; + end+= AUTH_PACKET_HEADER_SIZE_CONNJ_SSL; + bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_CONNJ_SSL; + goto skip_to_ssl; + } + + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_41; + else + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_40; + + if (!packet_has_required_size) + goto error; + if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; - thd->max_client_packet_length= uint4korr(net->read_pos+4); - DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); - if (thd_init_client_charset(thd, (uint) net->read_pos[8])) - return 1; - thd->update_charset(); - end= (char*) net->read_pos+32; + thd->client_capabilities= uint4korr(end); + thd->max_client_packet_length= uint4korr(end + 4); + charset_code= (uint)(uchar)*(end + 8); + /* + Skip 23 remaining filler bytes which have no particular meaning. + */ + end+= AUTH_PACKET_HEADER_SIZE_PROTO_41; + bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_41; } else { - thd->max_client_packet_length= uint3korr(net->read_pos+2); - end= (char*) net->read_pos+5; + thd->client_capabilities= uint2korr(end); + thd->max_client_packet_length= uint3korr(end + 2); + end+= AUTH_PACKET_HEADER_SIZE_PROTO_40; + bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_40; + /** + Old clients didn't have their own charset. Instead the assumption + was that they used what ever the server used. + */ + charset_code= default_charset_info->number; } + +skip_to_ssl: + + DBUG_PRINT("info", ("client_character_set: %u", charset_code)); + if (thd_init_client_charset(thd, charset_code)) + goto error; + thd->update_charset(); + /* Disable those bits which are not supported by the server. This is a precautionary measure, if the client lies. See Bug#27944. @@ -972,42 +1026,63 @@ static int check_connection(THD *thd) thd->variables.sql_mode|= MODE_IGNORE_SPACE; #ifdef HAVE_OPENSSL DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); + + /* + If client requested SSL then we must stop parsing, try to switch to SSL, + and wait for the client to send a new handshake packet. + The client isn't expected to send any more bytes until SSL is initialized. + */ if (thd->client_capabilities & CLIENT_SSL) { /* Do the SSL layering. */ if (!ssl_acceptor_fd) - { - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; - } + goto error; + DBUG_PRINT("info", ("IO layer change in progress...")); if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) { DBUG_PRINT("error", ("Failed to accept new SSL connection")); - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; + goto error; } + DBUG_PRINT("info", ("Reading user information over SSL layer")); - if ((pkt_len= my_net_read(net)) == packet_error || - pkt_len < NORMAL_HANDSHAKE_SIZE) + if ((pkt_len= my_net_read(net)) == packet_error) { DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", pkt_len)); - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; + goto error; } - } -#endif /* HAVE_OPENSSL */ + /* + A new packet was read and the statistics reflecting the remaining bytes + in the packet must be updated. + */ + bytes_remaining_in_packet= pkt_len; - if (end > (char *)net->read_pos + pkt_len) - { - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; + /* + After the SSL handshake is performed the client resends the handshake + packet but because of legacy reasons we chose not to parse the packet + fields a second time and instead only assert the length of the packet. + */ + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_41; + end= (char *)net->read_pos + AUTH_PACKET_HEADER_SIZE_PROTO_41; + bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_41; + } + else + { + packet_has_required_size= bytes_remaining_in_packet >= + AUTH_PACKET_HEADER_SIZE_PROTO_40; + end= (char *)net->read_pos + AUTH_PACKET_HEADER_SIZE_PROTO_40; + bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; + } + + if (!packet_has_required_size) + goto error; } +#endif /* HAVE_OPENSSL */ if (thd->client_capabilities & CLIENT_INTERACTIVE) thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; @@ -1028,29 +1103,17 @@ static int check_connection(THD *thd) else get_string= get_40_protocol_string; - /* - In order to safely scan a head for '\0' string terminators - we must keep track of how many bytes remain in the allocated - buffer or we might read past the end of the buffer. - */ - size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos); - - size_t user_len; - char *user= get_string(&end, &bytes_remaining_in_packet, &user_len); + user= get_string(&end, &bytes_remaining_in_packet, &user_len); if (user == NULL) - { - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; - } + goto error; /* Old clients send a null-terminated string as password; new clients send the size (1 byte) + string (not null-terminated). Hence in case of empty password both send '\0'. */ - size_t passwd_len= 0; - char *passwd= NULL; + passwd_len= 0; + passwd= NULL; if (thd->client_capabilities & CLIENT_SECURE_CONNECTION) { @@ -1069,24 +1132,16 @@ static int check_connection(THD *thd) } if (passwd == NULL) - { - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; - } + goto error; - size_t db_len= 0; - char *db= NULL; + db_len= 0; + db= NULL; if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) { db= get_string(&end, &bytes_remaining_in_packet, &db_len); if (db == NULL) - { - inc_host_errors(&thd->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); - return 1; - } + goto error; } char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 @@ -1134,11 +1189,14 @@ static int check_connection(THD *thd) user[user_len]= '\0'; } - if (thd->main_security_ctx.user) - x_free(thd->main_security_ctx.user); if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); + +error: + inc_host_errors(&thd->remote.sin_addr); + my_error(ER_HANDSHAKE_ERROR, MYF(0)); + return 1; } @@ -1388,3 +1446,4 @@ end_thread: } } #endif /* EMBEDDED_LIBRARY */ + diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f5c41b30659..f0289ab86ce 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1623,6 +1623,8 @@ void st_select_lex::init_query() nest_level= 0; link_next= 0; lock_option= TL_READ_DEFAULT; + m_non_agg_field_used= false; + m_agg_func_used= false; } void st_select_lex::init_select() @@ -1653,7 +1655,8 @@ void st_select_lex::init_select() non_agg_fields.empty(); cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); - full_group_by_flag= 0; + m_non_agg_field_used= false; + m_agg_func_used= false; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 07551f51a8a..b4dbbc5162e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -715,16 +715,7 @@ public: joins on the right. */ List<String> *prev_join_using; - /* - Bitmap used in the ONLY_FULL_GROUP_BY_MODE to prevent mixture of aggregate - functions and non aggregated fields when GROUP BY list is absent. - Bits: - 0 - non aggregated fields are used in this select, - defined as NON_AGG_FIELD_USED. - 1 - aggregate functions are used in this select, - defined as SUM_FUNC_USED. - */ - uint8 full_group_by_flag; + void init_query(); void init_select(); st_select_lex_unit* master_unit(); @@ -832,7 +823,22 @@ public: void clear_index_hints(void) { index_hints= NULL; } -private: + /* + For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags: + - Non-aggregated fields are used in this select. + - Aggregate functions are used in this select. + In MODE_ONLY_FULL_GROUP_BY only one of these may be true. + */ + bool non_agg_field_used() const { return m_non_agg_field_used; } + bool agg_func_used() const { return m_agg_func_used; } + + void set_non_agg_field_used(bool val) { m_non_agg_field_used= val; } + void set_agg_func_used(bool val) { m_agg_func_used= val; } + +private: + bool m_non_agg_field_used; + bool m_agg_func_used; + /* current index hint kind. used in filling up index_hints */ enum index_hint_type current_index_hint_type; index_clause_map current_index_hint_clause; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 84d355ba2b5..6a0e5fd9133 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -350,21 +350,21 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, #if !defined(__WIN__) && ! defined(__NETWARE__) MY_STAT stat_info; - if (!my_stat(name,&stat_info,MYF(MY_WME))) - DBUG_RETURN(TRUE); + if (!my_stat(name, &stat_info, MYF(MY_WME))) + DBUG_RETURN(TRUE); // if we are not in slave thread, the file must be: if (!thd->slave_thread && - !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others - (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink - ((stat_info.st_mode & S_IFREG) == S_IFREG || - (stat_info.st_mode & S_IFIFO) == S_IFIFO))) + !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others + (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink + ((stat_info.st_mode & S_IFREG) == S_IFREG || // and a regular file + (stat_info.st_mode & S_IFIFO) == S_IFIFO))) // or FIFO { - my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name); - DBUG_RETURN(TRUE); + my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name); + DBUG_RETURN(TRUE); } if ((stat_info.st_mode & S_IFIFO) == S_IFIFO) - is_fifo = 1; + is_fifo= 1; #endif if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d743c5908ca..0b103dcbda9 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -930,9 +930,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, const char *save_where; char* db_name; char db_name_string[FN_REFLEN]; - bool save_use_only_table_context; - uint8 saved_full_group_by_flag; - nesting_map saved_allow_sum_func; DBUG_ENTER("fix_fields_part_func"); if (part_info->fixed) @@ -999,23 +996,26 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, of interesting side effects, both desirable and undesirable. */ - save_use_only_table_context= thd->lex->use_only_table_context; - thd->lex->use_only_table_context= TRUE; - thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; - saved_full_group_by_flag= thd->lex->current_select->full_group_by_flag; - saved_allow_sum_func= thd->lex->allow_sum_func; - thd->lex->allow_sum_func= 0; + { + const bool save_use_only_table_context= thd->lex->use_only_table_context; + thd->lex->use_only_table_context= TRUE; + thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; + const bool save_agg_field= thd->lex->current_select->non_agg_field_used(); + const bool save_agg_func= thd->lex->current_select->agg_func_used(); + const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func; + thd->lex->allow_sum_func= 0; - error= func_expr->fix_fields(thd, (Item**)&func_expr); - - /* - Restore full_group_by_flag and allow_sum_func, - fix_fields should not affect mysql_select later, see Bug#46923. - */ - thd->lex->current_select->full_group_by_flag= saved_full_group_by_flag; - thd->lex->allow_sum_func= saved_allow_sum_func; + error= func_expr->fix_fields(thd, (Item**)&func_expr); - thd->lex->use_only_table_context= save_use_only_table_context; + /* + Restore agg_field/agg_func and allow_sum_func, + fix_fields should not affect mysql_select later, see Bug#46923. + */ + thd->lex->current_select->set_non_agg_field_used(save_agg_field); + thd->lex->current_select->set_agg_func_used(save_agg_func); + thd->lex->allow_sum_func= saved_allow_sum_func; + thd->lex->use_only_table_context= save_use_only_table_context; + } context->table_list= save_table_list; context->first_name_resolution_table= save_first_table; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 46e9ad242b3..2346f744b47 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -426,19 +426,18 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, int res; nesting_map save_allow_sum_func=thd->lex->allow_sum_func ; /* - Need to save the value, so we can turn off only the new NON_AGG_FIELD + Need to save the value, so we can turn off only any new non_agg_field_used additions coming from the WHERE */ - uint8 saved_flag= thd->lex->current_select->full_group_by_flag; + const bool saved_non_agg_field_used= + thd->lex->current_select->non_agg_field_used(); DBUG_ENTER("setup_without_group"); thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level); res= setup_conds(thd, tables, leaves, conds); /* it's not wrong to have non-aggregated columns in a WHERE */ - if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) - thd->lex->current_select->full_group_by_flag= saved_flag | - (thd->lex->current_select->full_group_by_flag & ~NON_AGG_FIELD_USED); + thd->lex->current_select->set_non_agg_field_used(saved_non_agg_field_used); thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, @@ -644,7 +643,8 @@ JOIN::prepare(Item ***rref_pointer_array, aggregate functions with implicit grouping (there is no GROUP BY). */ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && - select_lex->full_group_by_flag == (NON_AGG_FIELD_USED | SUM_FUNC_USED)) + select_lex->non_agg_field_used() && + select_lex->agg_func_used()) { my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index b348e19033b..853ae782a44 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -37,6 +37,11 @@ * row/row0row.c, row/row0vers.c, trx/trx0rec.c: Instrumentation for Bug#12612184 Race condition in row_upd_clust_rec() +2011-05-19 The InnoDB Team + + * row/row0row.c: + Fix Bug#12429576 Assertion failure on purge of column prefix index + 2011-04-07 The InnoDB Team * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc: diff --git a/storage/innodb_plugin/row/row0row.c b/storage/innodb_plugin/row/row0row.c index 4bad2cb9144..69753d15737 100644 --- a/storage/innodb_plugin/row/row0row.c +++ b/storage/innodb_plugin/row/row0row.c @@ -156,8 +156,6 @@ row_build_index_entry( each off-page column. */ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); len -= BTR_EXTERN_FIELD_REF_SIZE; - ut_a(ind_field->prefix_len <= len - || dict_index_is_clust(index)); } /* If a column prefix index, take only the prefix. */ diff --git a/storage/ndb/test/sql/BANK.sql b/storage/ndb/test/sql/BANK.sql deleted file mode 100644 index 723fa764737..00000000000 --- a/storage/ndb/test/sql/BANK.sql +++ /dev/null @@ -1,60 +0,0 @@ --- Copyright (c) 2005 MySQL AB --- Use is subject to license terms. --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; version 2 of the License. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, write to the Free Software --- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -CREATE DATABASE IF NOT EXISTS BANK default charset=latin1 default collate=latin1_bin; -USE BANK; -DROP TABLE IF EXISTS GL; -CREATE TABLE GL ( TIME BIGINT UNSIGNED NOT NULL, - ACCOUNT_TYPE INT UNSIGNED NOT NULL, - BALANCE INT UNSIGNED NOT NULL, - DEPOSIT_COUNT INT UNSIGNED NOT NULL, - DEPOSIT_SUM INT UNSIGNED NOT NULL, - WITHDRAWAL_COUNT INT UNSIGNED NOT NULL, - WITHDRAWAL_SUM INT UNSIGNED NOT NULL, - PURGED INT UNSIGNED NOT NULL, - PRIMARY KEY USING HASH (TIME,ACCOUNT_TYPE)) - ENGINE = NDB; - -DROP TABLE IF EXISTS ACCOUNT; -CREATE TABLE ACCOUNT ( ACCOUNT_ID INT UNSIGNED NOT NULL, - OWNER INT UNSIGNED NOT NULL, - BALANCE INT UNSIGNED NOT NULL, - ACCOUNT_TYPE INT UNSIGNED NOT NULL, - PRIMARY KEY USING HASH (ACCOUNT_ID)) - ENGINE = NDB; - -DROP TABLE IF EXISTS TRANSACTION; -CREATE TABLE TRANSACTION ( TRANSACTION_ID BIGINT UNSIGNED NOT NULL, - ACCOUNT INT UNSIGNED NOT NULL, - ACCOUNT_TYPE INT UNSIGNED NOT NULL, - OTHER_ACCOUNT INT UNSIGNED NOT NULL, - TRANSACTION_TYPE INT UNSIGNED NOT NULL, - TIME BIGINT UNSIGNED NOT NULL, - AMOUNT INT UNSIGNED NOT NULL, - PRIMARY KEY USING HASH (TRANSACTION_ID,ACCOUNT)) - ENGINE = NDB; - -DROP TABLE IF EXISTS SYSTEM_VALUES; -CREATE TABLE SYSTEM_VALUES ( SYSTEM_VALUES_ID INT UNSIGNED NOT NULL, - VALUE BIGINT UNSIGNED NOT NULL, - PRIMARY KEY USING HASH (SYSTEM_VALUES_ID)) - ENGINE = NDB; - -DROP TABLE IF EXISTS ACCOUNT_TYPE; -CREATE TABLE ACCOUNT_TYPE ( ACCOUNT_TYPE_ID INT UNSIGNED NOT NULL, - DESCRIPTION CHAR(64) NOT NULL, - PRIMARY KEY USING HASH (ACCOUNT_TYPE_ID)) - ENGINE = NDB; diff --git a/storage/ndb/test/sql/T1.sql b/storage/ndb/test/sql/T1.sql deleted file mode 100644 index 8163219015f..00000000000 --- a/storage/ndb/test/sql/T1.sql +++ /dev/null @@ -1,25 +0,0 @@ --- Copyright (c) 2005 MySQL AB --- Use is subject to license terms. --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; version 2 of the License. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, write to the Free Software --- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -create database if not exists TEST_DB; -use TEST_DB; -drop table if exists T1; -create table T1 (KOL1 int unsigned not null, - KOL2 int unsigned not null, - KOL3 int unsigned not null, - KOL4 int unsigned not null, - KOL5 int unsigned not null, - primary key using hash(KOL1)) engine=ndb; diff --git a/storage/ndb/test/sql/test_create_drop.pl b/storage/ndb/test/sql/test_create_drop.pl deleted file mode 100644 index eb9d5e31dc8..00000000000 --- a/storage/ndb/test/sql/test_create_drop.pl +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright (C) 2005 MySQL AB -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; version 2 -# of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this library; if not, write to the Free -# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA 02111-1307, USA - -use strict; -use IO::Socket; -use DBI; - -# mgm info -my $mgmhost = "localhost"; -my $mgmport = 38101; - -# location of ndb_x_fs -my $datadir = "c2"; -my @schemafiles = <$datadir/ndb_*_fs/D[12]/DBDICT/P0.SchemaLog>; -@schemafiles or die "no schemafiles in $datadir"; - -my $dsn; -$dsn = "dbi:mysql:test:localhost;port=38100"; - -# this works better for me -my $cnf = $ENV{MYSQL_HOME} . "/var/my.cnf"; -$dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$cnf"; - -my $dbh; -$dbh = DBI->connect($dsn, 'root', undef, { RaiseError => 0, PrintError => 0 }); -$dbh or die $DBI::errstr; - -# mgm commands - -my $mgm = undef; - -sub mgmconnect { - $mgm = IO::Socket::INET->new( - Proto => "tcp", - PeerHost => $mgmhost, - PeerPort => $mgmport); - $mgm or die "connect to mgm failed: $!"; - $mgm->autoflush(1); -}; - -mgmconnect(); -warn "connected to mgm $mgmhost $mgmport\n"; - -my $nodeinfo = {}; - -sub getnodeinfo { - $nodeinfo = {}; - $mgm->print("get status\n"); - $mgm->print("\n"); - while (defined($_ = $mgm->getline)) { - /^node\s+status/ && last; - } - while (defined($_ = $mgm->getline)) { - /^\s*$/ && last; - /^node\.(\d+)\.(\w+):\s*(\S+)/ && ($nodeinfo->{$1}{$2} = $3); - } -} - -getnodeinfo(); - -my @dbnode = (); -for my $n (keys %$nodeinfo) { - my $p = $nodeinfo->{$n}; - ($p->{type} eq 'NDB') && push(@dbnode, $n); -} -@dbnode = sort { $a <=> $b } @dbnode; -@dbnode or die "mgm error, found no db nodes"; -warn "db nodes: @dbnode\n"; - -sub restartnode { - my($n, $initialstart) = @_; - warn "restart node $n initialstart=$initialstart\n"; - $mgm->print("restart node\n"); - $mgm->print("node: $n\n"); - $mgm->print("initialstart: $initialstart\n"); - $mgm->print("\n"); - while (1) { - sleep 5; - getnodeinfo(); - my $status = $nodeinfo->{$n}{status}; - my $sp = $nodeinfo->{$n}{startphase}; - warn "node $n status: $status sp: $sp\n"; - last if $status eq 'STARTED'; - } -} - -sub restartall { - warn "restart all\n"; - $mgm->print("restart all\n"); - $mgm->print("\n"); - while (1) { - sleep 5; - getnodeinfo(); - my $ok = 1; - for my $n (@dbnode) { - my $status = $nodeinfo->{$n}{status}; - my $sp = $nodeinfo->{$n}{startphase}; - warn "node $n status: $status sp: $sp\n"; - $ok = 0 if $status ne 'STARTED'; - } - last if $ok; - } -} - -# the sql stuff - -my $maxtab = 300; -my @tab = (); - -sub create { - my($n) = @_; - my $sql = "create table t$n (a int primary key, b varchar(20), key (b)) engine=ndb"; - warn "create t$n\n"; - $dbh->do($sql) or die "$sql\n$DBI::errstr"; -} - -sub drop { - my($n) = @_; - my $sql = "drop table t$n"; - warn "drop t$n\n"; - $dbh->do($sql) or die "$sql\n$DBI::errstr"; -} - -sub dropall { - for my $n (0..($maxtab-1)) { - my $sql = "drop table if exists t$n"; - $dbh->do($sql) or die "$sql\n$DBI::errstr"; - } -} - -sub createdrop { - my $n = int(rand($maxtab)); - if (! $tab[$n]) { - create($n); - $tab[$n] = 1; - } else { - drop($n); - $tab[$n] = 0; - } -} - -sub checkschemafiles { - system("printSchemaFile -ce @schemafiles"); - $? == 0 or die "schemafiles check failed"; -} - -sub randomrestart { - my($k) = @_; - my $s = int(rand(500)); - if ($s < 2) { - my $i = $k % scalar(@dbnode); - my $n = $dbnode[$i]; - my $initialstart = ($s < 1 ? 0 : 1); - restartnode($n, $initialstart); - return 1; - } - if ($s < 3) { - restartall(); - return 1; - } - return 0; -} - -# deterministic -srand(1); - -warn "drop any old tables\n"; -dropall(); - -my $loop = 1000000; -for my $k (0..($loop-1)) { - warn "$k\n"; - createdrop(); - checkschemafiles(); - if (randomrestart($k)) { - checkschemafiles(); - } -} - -$dbh->disconnect or die $DBI::errstr; - -# vim: set sw=2: diff --git a/storage/ndb/test/sql/test_range_bounds.pl b/storage/ndb/test/sql/test_range_bounds.pl deleted file mode 100644 index 964847044de..00000000000 --- a/storage/ndb/test/sql/test_range_bounds.pl +++ /dev/null @@ -1,235 +0,0 @@ -# Copyright (C) 2005 MySQL AB -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; version 2 -# of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this library; if not, write to the Free -# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA 02111-1307, USA - -# -# test range scan bounds -# give option --all to test all cases -# set MYSQL_HOME to installation top -# - -use strict; -use integer; -use Getopt::Long; -use DBI; - -my $opt_all = 0; -my $opt_cnt = 5; -my $opt_verbose = 0; -GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt, "verbose" => \$opt_verbose) - or die "options are: --all --cnt=N --verbose"; - -my $mysql_home = $ENV{MYSQL_HOME}; -defined($mysql_home) or die "no MYSQL_HOME"; -my $dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$mysql_home/var/my.cnf"; -my $opts = { RaiseError => 0, PrintError => 0, AutoCommit => 1, }; - -my $dbh; -my $sth; -my $sql; - -$dbh = DBI->connect($dsn, "root", undef, $opts) or die $DBI::errstr; - -my $table = 't'; - -$sql = "drop table if exists $table"; -$dbh->do($sql) or die $DBI::errstr; - -sub cut ($$$) { - my($op, $key, $val) = @_; - $op = '==' if $op eq '='; - my(@w) = @$val; - eval "\@w = grep(\$_ $op $key, \@w)"; - $@ and die $@; - return [ @w ]; -} - -sub mkdummy ($) { - my ($val) = @_; - return { - 'dummy' => 1, - 'exp' => '9 = 9', - 'res' => $val, - }; -} - -sub mkone ($$$$) { - my($col, $op, $key, $val) = @_; - my $res = cut($op, $key, $val); - return { - 'exp' => "$col $op $key", - 'res' => $res, - }; -} - -sub mktwo ($$$$$$) { - my($col, $op1, $key1, $op2, $key2, $val) = @_; - my $res = cut($op2, $key2, cut($op1, $key1, $val)); - return { - 'exp' => "$col $op1 $key1 and $col $op2 $key2", - 'res' => $res, - }; -} - -sub mkall ($$$$) { - my($col, $key1, $key2, $val) = @_; - my @a = (); - my $p = mkdummy($val); - push(@a, $p) if $opt_all; - my @ops = qw(< <= = >= >); - for my $op (@ops) { - my $p = mkone($col, $op, $key1, $val); - push(@a, $p) if $opt_all || @{$p->{res}} != 0; - } - my @ops1 = $opt_all ? @ops : qw(= >= >); - my @ops2 = $opt_all ? @ops : qw(<= <); - for my $op1 (@ops1) { - for my $op2 (@ops2) { - my $p = mktwo($col, $op1, $key1, $op2, $key2, $val); - push(@a, $p) if $opt_all || @{$p->{res}} != 0; - } - } - warn scalar(@a)." cases\n" if $opt_verbose; - return \@a; -} - -my $casecnt = 0; - -sub verify ($$$) { - my($sql, $ord, $res) = @_; - warn "$sql\n" if $opt_verbose; - $sth = $dbh->prepare($sql) or die "prepare: $sql: $DBI::errstr"; - $sth->execute() or die "execute: $sql: $DBI::errstr"; - # - # BUG: execute can return success on error so check again - # - $sth->err and die "execute: $sql: $DBI::errstr"; - my @out = (); - for my $b (@{$res->[0]}) { - for my $c (@{$res->[1]}) { - for my $d (@{$res->[2]}) { - push(@out, [$b, $c, $d]); - } - } - } - if ($ord) { - @out = sort { - $ord * ($a->[0] - $b->[0]) || - $ord * ($a->[1] - $b->[1]) || - $ord * ($a->[2] - $b->[2]) || - 0 - } @out; - } - my $cnt = scalar @out; - my $n = 0; - while (1) { - my $row = $sth->fetchrow_arrayref; - $row || last; - @$row == 3 or die "bad row: $sql: @$row"; - for my $v (@$row) { - $v =~ s/^\s+|\s+$//g; - $v =~ /^\d+$/ or die "bad value: $sql: $v"; - } - if ($ord) { - my $out = $out[$n]; - $row->[0] == $out->[0] && - $row->[1] == $out->[1] && - $row->[2] == $out->[2] or - die "$sql: row $n: got row @$row != @$out"; - } - $n++; - } - $sth->err and die "fetch: $sql: $DBI::errstr"; - $n == $cnt or die "verify: $sql: got row count $n != $cnt"; - $casecnt++; -} - -for my $nn ("bcd", "") { - my %nn; - for my $x (qw(b c d)) { - $nn{$x} = $nn =~ /$x/ ? "not null" : "null"; - } - warn "create table\n"; - $sql = <<EOF; -create table $table ( - a int primary key, - b int $nn{b}, - c int $nn{c}, - d int $nn{d}, - index (b, c, d) -) engine=ndb -EOF - $dbh->do($sql) or die $DBI::errstr; - warn "insert\n"; - $sql = "insert into $table values(?, ?, ?, ?)"; - $sth = $dbh->prepare($sql) or die $DBI::errstr; - my @val = (0..($opt_cnt-1)); - my $v0 = 0; - for my $v1 (@val) { - for my $v2 (@val) { - for my $v3 (@val) { - $sth->bind_param(1, $v0) or die $DBI::errstr; - $sth->bind_param(2, $v1) or die $DBI::errstr; - $sth->bind_param(3, $v2) or die $DBI::errstr; - $sth->bind_param(4, $v3) or die $DBI::errstr; - $sth->execute or die $DBI::errstr; - $v0++; - } - } - } - warn "generate cases\n"; - my $key1 = 1; - my $key2 = 3; - my $a1 = mkall('b', $key1, $key2, \@val); - my $a2 = mkall('c', $key1, $key2, \@val); - my $a3 = mkall('d', $key1, $key2, \@val); - warn "select\n"; - for my $ord (0, +1, -1) { - my $orderby = - $ord == 0 ? "" : - $ord == +1 ? " order by b, c, d" : - $ord == -1 ? " order by b desc, c desc, d desc" : die "not here"; - for my $p1 (@$a1) { - my $res = [ $p1->{res}, \@val, \@val ]; - $sql = "select b, c, d from $table" . - " where $p1->{exp}" . - $orderby; - verify($sql, $ord, $res); - for my $p2 (@$a2) { - my $res = [ $p1->{res}, $p2->{res}, \@val ]; - $sql = "select b, c, d from $table" . - " where $p1->{exp} and $p2->{exp}" . - $orderby; - verify($sql, $ord, $res); - for my $p3 (@$a3) { - my $res = [ $p1->{res}, $p2->{res}, $p3->{res} ]; - $sql = "select b, c, d from $table" . - " where $p1->{exp} and $p2->{exp} and $p3->{exp}" . - $orderby; - verify($sql, $ord, $res); - } - } - } - } - warn "drop table\n"; - $sql = "drop table $table"; - $dbh->do($sql) or die $DBI::errstr; -} - -warn "verified $casecnt cases\n"; -warn "done\n"; - -# vim: set sw=2: |