Manual merge from the mysql-5.1-bugteam.
This commit is contained in:
commit
a460914482
@ -198,10 +198,6 @@ test-bt-fast:
|
|||||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||||
@PERL@ ./mysql-test-run.pl --force --comment=stress --suite=stress $(EXP)
|
@PERL@ ./mysql-test-run.pl --force --comment=stress --suite=stress $(EXP)
|
||||||
|
|
||||||
test-bt-fast:
|
|
||||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
|
||||||
@PERL@ ./mysql-test-run.pl --force --comment=ps --ps-protocol --report-features
|
|
||||||
|
|
||||||
test-bt-debug:
|
test-bt-debug:
|
||||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||||
@PERL@ ./mysql-test-run.pl --comment=debug --force --timer \
|
@PERL@ ./mysql-test-run.pl --comment=debug --force --timer \
|
||||||
|
@ -601,15 +601,15 @@ dnl ---------------------------------------------------------------------------
|
|||||||
|
|
||||||
dnl MYSQL_NEEDS_MYSYS_NEW
|
dnl MYSQL_NEEDS_MYSYS_NEW
|
||||||
AC_DEFUN([MYSQL_NEEDS_MYSYS_NEW],
|
AC_DEFUN([MYSQL_NEEDS_MYSYS_NEW],
|
||||||
[AC_CACHE_CHECK([needs mysys_new helpers], mysql_use_mysys_new,
|
[AC_CACHE_CHECK([needs mysys_new helpers], mysql_cv_use_mysys_new,
|
||||||
[
|
[
|
||||||
AC_LANG_PUSH(C++)
|
AC_LANG_PUSH(C++)
|
||||||
AC_TRY_LINK([], [
|
AC_TRY_LINK([], [
|
||||||
class A { public: int b; }; A *a=new A; a->b=10; delete a;
|
class A { public: int b; }; A *a=new A; a->b=10; delete a;
|
||||||
], mysql_use_mysys_new=no, mysql_use_mysys_new=yes)
|
], mysql_cv_use_mysys_new=no, mysql_cv_use_mysys_new=yes)
|
||||||
AC_LANG_POP(C++)
|
AC_LANG_POP(C++)
|
||||||
])
|
])
|
||||||
if test "$mysql_use_mysys_new" = "yes"
|
if test "$mysql_cv_use_mysys_new" = "yes"
|
||||||
then
|
then
|
||||||
AC_DEFINE([USE_MYSYS_NEW], [1], [Needs to use mysys_new helpers])
|
AC_DEFINE([USE_MYSYS_NEW], [1], [Needs to use mysys_new helpers])
|
||||||
fi
|
fi
|
||||||
|
@ -13,6 +13,12 @@ AC_CANONICAL_SYSTEM
|
|||||||
AM_INIT_AUTOMAKE(mysql, 5.5.0-beta)
|
AM_INIT_AUTOMAKE(mysql, 5.5.0-beta)
|
||||||
AM_CONFIG_HEADER([include/config.h:config.h.in])
|
AM_CONFIG_HEADER([include/config.h:config.h.in])
|
||||||
|
|
||||||
|
# Request support for automake silent-rules if available.
|
||||||
|
# Default to verbose output. One can use the configure-time
|
||||||
|
# option --enable-silent-rules or make V=1 to activate
|
||||||
|
# silent rules.
|
||||||
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])])
|
||||||
|
|
||||||
PROTOCOL_VERSION=10
|
PROTOCOL_VERSION=10
|
||||||
DOT_FRM_VERSION=6
|
DOT_FRM_VERSION=6
|
||||||
# See the libtool docs for information on how to do shared lib versions.
|
# See the libtool docs for information on how to do shared lib versions.
|
||||||
|
@ -185,6 +185,14 @@ INSERT INTO global_suppressions VALUES
|
|||||||
("Master server does not support or not configured semi-sync replication, fallback to asynchronous"),
|
("Master server does not support or not configured semi-sync replication, fallback to asynchronous"),
|
||||||
(": The MySQL server is running with the --secure-backup-file-priv option so it cannot execute this statement"),
|
(": The MySQL server is running with the --secure-backup-file-priv option so it cannot execute this statement"),
|
||||||
("Slave: Unknown table 't1' Error_code: 1051"),
|
("Slave: Unknown table 't1' Error_code: 1051"),
|
||||||
|
/*
|
||||||
|
Transient network failures that cause warnings on reconnect.
|
||||||
|
BUG#47743 and BUG#47983.
|
||||||
|
*/
|
||||||
|
("Slave I/O: Get master SERVER_ID failed with error:.*"),
|
||||||
|
("Slave I/O: Get master clock failed with error:.*"),
|
||||||
|
("Slave I/O: Get master COLLATION_SERVER failed with error:.*"),
|
||||||
|
("Slave I/O: Get master TIME_ZONE failed with error:.*"),
|
||||||
|
|
||||||
("THE_LAST_SUPPRESSION")||
|
("THE_LAST_SUPPRESSION")||
|
||||||
|
|
||||||
|
@ -551,3 +551,42 @@ EXECUTE s;
|
|||||||
MATCH (col) AGAINST('findme')
|
MATCH (col) AGAINST('findme')
|
||||||
DEALLOCATE PREPARE s;
|
DEALLOCATE PREPARE s;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Bug #47930: MATCH IN BOOLEAN MODE returns too many results
|
||||||
|
# inside subquery
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a int);
|
||||||
|
INSERT INTO t1 VALUES (1), (2);
|
||||||
|
CREATE TABLE t2 (a int, b2 char(10), FULLTEXT KEY b2 (b2));
|
||||||
|
INSERT INTO t2 VALUES (1,'Scargill');
|
||||||
|
CREATE TABLE t3 (a int, b int);
|
||||||
|
INSERT INTO t3 VALUES (1,1), (2,1);
|
||||||
|
# t2 should use full text index
|
||||||
|
EXPLAIN
|
||||||
|
SELECT count(*) FROM t1 WHERE
|
||||||
|
not exists(
|
||||||
|
SELECT 1 FROM t2, t3
|
||||||
|
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||||
|
);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 DEPENDENT SUBQUERY t2 fulltext b2 b2 0 1 Using where
|
||||||
|
2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
# should return 0
|
||||||
|
SELECT count(*) FROM t1 WHERE
|
||||||
|
not exists(
|
||||||
|
SELECT 1 FROM t2, t3
|
||||||
|
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||||
|
);
|
||||||
|
count(*)
|
||||||
|
0
|
||||||
|
# should return 0
|
||||||
|
SELECT count(*) FROM t1 WHERE
|
||||||
|
not exists(
|
||||||
|
SELECT 1 FROM t2 IGNORE INDEX (b2), t3
|
||||||
|
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||||
|
);
|
||||||
|
count(*)
|
||||||
|
0
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
End of 5.1 tests
|
||||||
|
@ -2251,4 +2251,26 @@ c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
|
|||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Bug #46175: NULL read_view and consistent read assertion
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(a CHAR(13),KEY(a)) ENGINE=innodb;
|
||||||
|
CREATE TABLE t2(b DATETIME,KEY(b)) ENGINE=innodb;
|
||||||
|
INSERT INTO t1 VALUES (),();
|
||||||
|
INSERT INTO t2 VALUES (),();
|
||||||
|
CREATE OR REPLACE VIEW v1 AS SELECT 1 FROM t2
|
||||||
|
WHERE b =(SELECT a FROM t1 LIMIT 1);
|
||||||
|
CREATE PROCEDURE p1(num INT)
|
||||||
|
BEGIN
|
||||||
|
DECLARE i INT DEFAULT 0;
|
||||||
|
REPEAT
|
||||||
|
SHOW CREATE VIEW v1;
|
||||||
|
SET i:=i+1;
|
||||||
|
UNTIL i>num END REPEAT;
|
||||||
|
END|
|
||||||
|
# Should not crash
|
||||||
|
# Should not crash
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1,t2;
|
||||||
End of 5.1 tests
|
End of 5.1 tests
|
||||||
|
@ -753,4 +753,16 @@ b
|
|||||||
100
|
100
|
||||||
NULL
|
NULL
|
||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
|
#
|
||||||
|
# Bug #48475: DISTINCT is ignored with GROUP BY WITH ROLLUP
|
||||||
|
# and only const tables
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
CREATE TABLE t2 (b INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
|
||||||
|
b
|
||||||
|
1
|
||||||
|
NULL
|
||||||
|
DROP TABLE t1, t2;
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
|
@ -1444,6 +1444,27 @@ FROM t3;
|
|||||||
2
|
2
|
||||||
NULL
|
NULL
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
#
|
||||||
|
# Bug #42760: Select doesn't return desired results when we have null
|
||||||
|
# values
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
a INT,
|
||||||
|
c INT,
|
||||||
|
UNIQUE KEY a_c (a,c),
|
||||||
|
KEY (a));
|
||||||
|
INSERT INTO t1 VALUES (1, 10), (2, NULL);
|
||||||
|
# Must use ref-or-null on the a_c index
|
||||||
|
EXPLAIN
|
||||||
|
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref_or_null a_c,a a_c 10 const,const 1 Using where
|
||||||
|
# Must return 1 row
|
||||||
|
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
|
||||||
|
col
|
||||||
|
1
|
||||||
|
DROP TABLE t1;
|
||||||
|
End of 5.0 tests
|
||||||
CREATE TABLE t2 (a varchar(32), b int(11), c float, d double,
|
CREATE TABLE t2 (a varchar(32), b int(11), c float, d double,
|
||||||
UNIQUE KEY a (a,b,c), KEY b (b), KEY c (c));
|
UNIQUE KEY a (a,b,c), KEY b (b), KEY c (c));
|
||||||
CREATE TABLE t1 (a varchar(32), b char(3), UNIQUE KEY a (a,b), KEY b (b));
|
CREATE TABLE t1 (a varchar(32), b char(3), UNIQUE KEY a (a,b), KEY b (b));
|
||||||
|
@ -4427,6 +4427,20 @@ ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1))
|
|||||||
INTO @var0;
|
INTO @var0;
|
||||||
ERROR 21000: Subquery returns more than 1 row
|
ERROR 21000: Subquery returns more than 1 row
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Bug #48458: simple query tries to allocate enormous amount of
|
||||||
|
# memory
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(a INT NOT NULL, b YEAR);
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
Warnings:
|
||||||
|
Warning 1364 Field 'a' doesn't have a default value
|
||||||
|
CREATE TABLE t2(c INT);
|
||||||
|
# Should not err out because of out-of-memory
|
||||||
|
SELECT 1 FROM t2 JOIN t1 ON 1=1
|
||||||
|
WHERE a != '1' AND NOT a >= b OR NOT ROW(b,a )<> ROW(a,a);
|
||||||
|
1
|
||||||
|
DROP TABLE t1,t2;
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
create table t1(a INT, KEY (a));
|
create table t1(a INT, KEY (a));
|
||||||
INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
|
INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
|
||||||
|
@ -484,3 +484,44 @@ PREPARE s FROM
|
|||||||
EXECUTE s;
|
EXECUTE s;
|
||||||
DEALLOCATE PREPARE s;
|
DEALLOCATE PREPARE s;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #47930: MATCH IN BOOLEAN MODE returns too many results
|
||||||
|
--echo # inside subquery
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a int);
|
||||||
|
INSERT INTO t1 VALUES (1), (2);
|
||||||
|
|
||||||
|
CREATE TABLE t2 (a int, b2 char(10), FULLTEXT KEY b2 (b2));
|
||||||
|
INSERT INTO t2 VALUES (1,'Scargill');
|
||||||
|
|
||||||
|
CREATE TABLE t3 (a int, b int);
|
||||||
|
INSERT INTO t3 VALUES (1,1), (2,1);
|
||||||
|
|
||||||
|
--echo # t2 should use full text index
|
||||||
|
EXPLAIN
|
||||||
|
SELECT count(*) FROM t1 WHERE
|
||||||
|
not exists(
|
||||||
|
SELECT 1 FROM t2, t3
|
||||||
|
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
--echo # should return 0
|
||||||
|
SELECT count(*) FROM t1 WHERE
|
||||||
|
not exists(
|
||||||
|
SELECT 1 FROM t2, t3
|
||||||
|
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
--echo # should return 0
|
||||||
|
SELECT count(*) FROM t1 WHERE
|
||||||
|
not exists(
|
||||||
|
SELECT 1 FROM t2 IGNORE INDEX (b2), t3
|
||||||
|
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
|
||||||
|
--echo End of 5.1 tests
|
||||||
|
@ -489,5 +489,51 @@ EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND
|
|||||||
c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
|
c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #46175: NULL read_view and consistent read assertion
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1(a CHAR(13),KEY(a)) ENGINE=innodb;
|
||||||
|
CREATE TABLE t2(b DATETIME,KEY(b)) ENGINE=innodb;
|
||||||
|
INSERT INTO t1 VALUES (),();
|
||||||
|
INSERT INTO t2 VALUES (),();
|
||||||
|
CREATE OR REPLACE VIEW v1 AS SELECT 1 FROM t2
|
||||||
|
WHERE b =(SELECT a FROM t1 LIMIT 1);
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
--disable_result_log
|
||||||
|
CONNECT (con1, localhost, root,,);
|
||||||
|
--enable_query_log
|
||||||
|
--enable_result_log
|
||||||
|
CONNECTION default;
|
||||||
|
|
||||||
|
DELIMITER |;
|
||||||
|
CREATE PROCEDURE p1(num INT)
|
||||||
|
BEGIN
|
||||||
|
DECLARE i INT DEFAULT 0;
|
||||||
|
REPEAT
|
||||||
|
SHOW CREATE VIEW v1;
|
||||||
|
SET i:=i+1;
|
||||||
|
UNTIL i>num END REPEAT;
|
||||||
|
END|
|
||||||
|
DELIMITER ;|
|
||||||
|
|
||||||
|
--echo # Should not crash
|
||||||
|
--disable_query_log
|
||||||
|
--disable_result_log
|
||||||
|
--send CALL p1(1000)
|
||||||
|
CONNECTION con1;
|
||||||
|
--echo # Should not crash
|
||||||
|
CALL p1(1000);
|
||||||
|
|
||||||
|
CONNECTION default;
|
||||||
|
--reap
|
||||||
|
--enable_query_log
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
DISCONNECT con1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
--echo End of 5.1 tests
|
--echo End of 5.1 tests
|
||||||
|
@ -390,4 +390,17 @@ SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
|
|||||||
|
|
||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #48475: DISTINCT is ignored with GROUP BY WITH ROLLUP
|
||||||
|
--echo # and only const tables
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
CREATE TABLE t2 (b INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
|
||||||
|
SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
|
||||||
|
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--echo End of 5.0 tests
|
||||||
|
@ -867,6 +867,31 @@ SELECT
|
|||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #42760: Select doesn't return desired results when we have null
|
||||||
|
--echo # values
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
a INT,
|
||||||
|
c INT,
|
||||||
|
UNIQUE KEY a_c (a,c),
|
||||||
|
KEY (a));
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (1, 10), (2, NULL);
|
||||||
|
|
||||||
|
--echo # Must use ref-or-null on the a_c index
|
||||||
|
EXPLAIN
|
||||||
|
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
|
||||||
|
--echo # Must return 1 row
|
||||||
|
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo End of 5.0 tests
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bug #35206: select query result different if the key is indexed or not
|
# Bug #35206: select query result different if the key is indexed or not
|
||||||
#
|
#
|
||||||
|
@ -3772,6 +3772,19 @@ INTO @var0;
|
|||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #48458: simple query tries to allocate enormous amount of
|
||||||
|
--echo # memory
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1(a INT NOT NULL, b YEAR);
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
CREATE TABLE t2(c INT);
|
||||||
|
--echo # Should not err out because of out-of-memory
|
||||||
|
SELECT 1 FROM t2 JOIN t1 ON 1=1
|
||||||
|
WHERE a != '1' AND NOT a >= b OR NOT ROW(b,a )<> ROW(a,a);
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--echo End of 5.0 tests
|
||||||
|
|
||||||
|
@ -413,17 +413,17 @@ invalid value '%s'",
|
|||||||
else if (optp->arg_type == OPT_ARG &&
|
else if (optp->arg_type == OPT_ARG &&
|
||||||
(((optp->var_type & GET_TYPE_MASK) == GET_BOOL) ||
|
(((optp->var_type & GET_TYPE_MASK) == GET_BOOL) ||
|
||||||
(optp->var_type & GET_TYPE_MASK) == GET_ENUM))
|
(optp->var_type & GET_TYPE_MASK) == GET_ENUM))
|
||||||
{
|
{
|
||||||
if (optend == disabled_my_option)
|
if (optend == disabled_my_option)
|
||||||
*((my_bool*) value)= (my_bool) 0;
|
init_one_value(optp, value, 0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!optend) /* No argument -> enable option */
|
if (!optend) /* No argument -> enable option */
|
||||||
*((my_bool*) value)= (my_bool) 1;
|
init_one_value(optp, value, 1);
|
||||||
else
|
else
|
||||||
argument= optend;
|
argument= optend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (optp->arg_type == REQUIRED_ARG && !optend)
|
else if (optp->arg_type == REQUIRED_ARG && !optend)
|
||||||
{
|
{
|
||||||
/* Check if there are more arguments after this one */
|
/* Check if there are more arguments after this one */
|
||||||
|
@ -17,17 +17,42 @@
|
|||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
use Fcntl;
|
use Fcntl;
|
||||||
|
use File::Spec;
|
||||||
|
use if $^O eq 'MSWin32', 'Term::ReadKey' => qw/ReadMode/;
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
my $config = ".my.cnf.$$";
|
my $config = ".my.cnf.$$";
|
||||||
my $command = ".mysql.$$";
|
my $command = ".mysql.$$";
|
||||||
my $hadpass = 0;
|
my $hadpass = 0;
|
||||||
|
my $mysql; # How to call the mysql client
|
||||||
# FIXME
|
|
||||||
# trap "interrupt" 2
|
|
||||||
|
|
||||||
my $rootpass = "";
|
my $rootpass = "";
|
||||||
|
|
||||||
|
|
||||||
|
$SIG{QUIT} = $SIG{INT} = sub {
|
||||||
|
print "\nAborting!\n\n";
|
||||||
|
echo_on();
|
||||||
|
cleanup();
|
||||||
|
exit 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
END {
|
||||||
|
# Remove temporary files, even if exiting via die(), etc.
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub read_without_echo {
|
||||||
|
my ($prompt) = @_;
|
||||||
|
print $prompt;
|
||||||
|
echo_off();
|
||||||
|
my $answer = <STDIN>;
|
||||||
|
echo_on();
|
||||||
|
print "\n";
|
||||||
|
chomp($answer);
|
||||||
|
return $answer;
|
||||||
|
}
|
||||||
|
|
||||||
sub echo_on {
|
sub echo_on {
|
||||||
if ($^O eq 'MSWin32') {
|
if ($^O eq 'MSWin32') {
|
||||||
ReadMode('normal');
|
ReadMode('normal');
|
||||||
@ -55,6 +80,25 @@ sub write_file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub prepare {
|
sub prepare {
|
||||||
|
# Locate the mysql client; look in current directory first, then
|
||||||
|
# in path
|
||||||
|
our $SAVEERR; # Suppress Perl warning message
|
||||||
|
open SAVEERR, ">& STDERR";
|
||||||
|
close STDERR;
|
||||||
|
for my $m (File::Spec->catfile('bin', 'mysql'), 'mysql') {
|
||||||
|
# mysql --version should always work
|
||||||
|
qx($m --no-defaults --version);
|
||||||
|
next unless $? == 0;
|
||||||
|
|
||||||
|
$mysql = $m;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
open STDERR, ">& SAVEERR";
|
||||||
|
|
||||||
|
die "Can't find a 'mysql' client in PATH or ./bin\n"
|
||||||
|
unless $mysql;
|
||||||
|
|
||||||
|
# Create safe files to avoid leaking info to other users
|
||||||
foreach my $file ( $config, $command ) {
|
foreach my $file ( $config, $command ) {
|
||||||
next if -f $file; # Already exists
|
next if -f $file; # Already exists
|
||||||
local *FILE;
|
local *FILE;
|
||||||
@ -64,30 +108,50 @@ sub prepare {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Simple escape mechanism (\-escape any ' and \), suitable for two contexts:
|
||||||
|
# - single-quoted SQL strings
|
||||||
|
# - single-quoted option values on the right hand side of = in my.cnf
|
||||||
|
#
|
||||||
|
# These two contexts don't handle escapes identically. SQL strings allow
|
||||||
|
# quoting any character (\C => C, for any C), but my.cnf parsing allows
|
||||||
|
# quoting only \, ' or ". For example, password='a\b' quotes a 3-character
|
||||||
|
# string in my.cnf, but a 2-character string in SQL.
|
||||||
|
#
|
||||||
|
# This simple escape works correctly in both places.
|
||||||
|
sub basic_single_escape {
|
||||||
|
my ($str) = @_;
|
||||||
|
# Inside a character class, \ is not special; this escapes both \ and '
|
||||||
|
$str =~ s/([\'])/\\$1/g;
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
sub do_query {
|
sub do_query {
|
||||||
my $query = shift;
|
my $query = shift;
|
||||||
write_file($command, $query);
|
write_file($command, $query);
|
||||||
system("mysql --defaults-file=$config < $command");
|
my $rv = system("$mysql --defaults-file=$config < $command");
|
||||||
return $?;
|
# system() returns -1 if exec fails (e.g., command not found, etc.); die
|
||||||
|
# in this case because nothing is going to work
|
||||||
|
die "Failed to execute mysql client '$mysql'\n" if $rv == -1;
|
||||||
|
# Return true if query executed OK, or false if there was some problem
|
||||||
|
# (for example, SQL error or wrong password)
|
||||||
|
return ($rv == 0 ? 1 : undef);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub make_config {
|
sub make_config {
|
||||||
my $password = shift;
|
my $password = shift;
|
||||||
|
|
||||||
|
my $esc_pass = basic_single_escape($rootpass);
|
||||||
write_file($config,
|
write_file($config,
|
||||||
"# mysql_secure_installation config file",
|
"# mysql_secure_installation config file",
|
||||||
"[mysql]",
|
"[mysql]",
|
||||||
"user=root",
|
"user=root",
|
||||||
"password=$rootpass");
|
"password='$esc_pass'");
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_root_password {
|
sub get_root_password {
|
||||||
my $status = 1;
|
my $attempts = 3;
|
||||||
while ( $status == 1 ) {
|
for (;;) {
|
||||||
echo_off();
|
my $password = read_without_echo("Enter current password for root (enter for none): ");
|
||||||
print "Enter current password for root (enter for none): ";
|
|
||||||
my $password = <STDIN>;
|
|
||||||
echo_on();
|
|
||||||
if ( $password ) {
|
if ( $password ) {
|
||||||
$hadpass = 1;
|
$hadpass = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -95,64 +159,56 @@ sub get_root_password {
|
|||||||
}
|
}
|
||||||
$rootpass = $password;
|
$rootpass = $password;
|
||||||
make_config($rootpass);
|
make_config($rootpass);
|
||||||
do_query("");
|
last if do_query("");
|
||||||
$status = $?;
|
|
||||||
|
die "Unable to connect to the server as root user, giving up.\n"
|
||||||
|
if --$attempts == 0;
|
||||||
}
|
}
|
||||||
print "OK, successfully used password, moving on...\n\n";
|
print "OK, successfully used password, moving on...\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_root_password {
|
sub set_root_password {
|
||||||
echo_off();
|
my $password1;
|
||||||
print "New password: ";
|
for (;;) {
|
||||||
my $password1 = <STDIN>;
|
$password1 = read_without_echo("New password: ");
|
||||||
print "\nRe-enter new password: ";
|
|
||||||
my $password2 = <STDIN>;
|
|
||||||
print "\n";
|
|
||||||
echo_on();
|
|
||||||
|
|
||||||
if ( $password1 eq $password2 ) {
|
if ( !$password1 ) {
|
||||||
print "Sorry, passwords do not match.\n\n";
|
print "Sorry, you can't use an empty password here.\n\n";
|
||||||
return 1;
|
next;
|
||||||
}
|
|
||||||
|
|
||||||
if ( !$password1 ) {
|
|
||||||
print "Sorry, you can't use an empty password here.\n\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_query("UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';");
|
|
||||||
if ( $? == 0 ) {
|
|
||||||
print "Password updated successfully!\n";
|
|
||||||
print "Reloading privilege tables..\n";
|
|
||||||
if ( !reload_privilege_tables() ) {
|
|
||||||
exit 1;
|
|
||||||
}
|
}
|
||||||
print "\n";
|
|
||||||
$rootpass = $password1;
|
my $password2 = read_without_echo("Re-enter new password: ");
|
||||||
make_config($rootpass);
|
|
||||||
} else {
|
if ( $password1 ne $password2 ) {
|
||||||
print "Password update failed!\n";
|
print "Sorry, passwords do not match.\n\n";
|
||||||
exit 1;
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
my $esc_pass = basic_single_escape($password1);
|
||||||
|
do_query("UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';")
|
||||||
|
or die "Password update failed!\n";
|
||||||
|
|
||||||
|
print "Password updated successfully!\n";
|
||||||
|
print "Reloading privilege tables..\n";
|
||||||
|
reload_privilege_tables()
|
||||||
|
or die "Can not continue.\n";
|
||||||
|
|
||||||
|
print "\n";
|
||||||
|
$rootpass = $password1;
|
||||||
|
make_config($rootpass);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub remove_anonymous_users {
|
sub remove_anonymous_users {
|
||||||
do_query("DELETE FROM mysql.user WHERE User='';");
|
do_query("DELETE FROM mysql.user WHERE User='';")
|
||||||
if ( $? == 0 ) {
|
or die print " ... Failed!\n";
|
||||||
print " ... Success!\n";
|
print " ... Success!\n";
|
||||||
} else {
|
|
||||||
print " ... Failed!\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub remove_remote_root {
|
sub remove_remote_root {
|
||||||
do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';");
|
if (do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';")) {
|
||||||
if ( $? == 0 ) {
|
|
||||||
print " ... Success!\n";
|
print " ... Success!\n";
|
||||||
} else {
|
} else {
|
||||||
print " ... Failed!\n";
|
print " ... Failed!\n";
|
||||||
@ -161,44 +217,31 @@ sub remove_remote_root {
|
|||||||
|
|
||||||
sub remove_test_database {
|
sub remove_test_database {
|
||||||
print " - Dropping test database...\n";
|
print " - Dropping test database...\n";
|
||||||
do_query("DROP DATABASE test;");
|
if (do_query("DROP DATABASE test;")) {
|
||||||
if ( $? == 0 ) {
|
|
||||||
print " ... Success!\n";
|
print " ... Success!\n";
|
||||||
} else {
|
} else {
|
||||||
print " ... Failed! Not critical, keep moving...\n";
|
print " ... Failed! Not critical, keep moving...\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
print " - Removing privileges on test database...\n";
|
print " - Removing privileges on test database...\n";
|
||||||
do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'");
|
if (do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'")) {
|
||||||
if ( $? == 0 ) {
|
|
||||||
print " ... Success!\n";
|
print " ... Success!\n";
|
||||||
} else {
|
} else {
|
||||||
print " ... Failed! Not critical, keep moving...\n";
|
print " ... Failed! Not critical, keep moving...\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub reload_privilege_tables {
|
sub reload_privilege_tables {
|
||||||
do_query("FLUSH PRIVILEGES;");
|
if (do_query("FLUSH PRIVILEGES;")) {
|
||||||
if ( $? == 0 ) {
|
|
||||||
print " ... Success!\n";
|
print " ... Success!\n";
|
||||||
return 0;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
print " ... Failed!\n";
|
print " ... Failed!\n";
|
||||||
return 1;
|
return undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub interrupt {
|
|
||||||
print "\nAborting!\n\n";
|
|
||||||
cleanup();
|
|
||||||
echo_on();
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub cleanup {
|
sub cleanup {
|
||||||
print "Cleaning up...\n";
|
|
||||||
unlink($config,$command);
|
unlink($config,$command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,11 +285,7 @@ my $reply = <STDIN>;
|
|||||||
if ( $reply =~ /n/i ) {
|
if ( $reply =~ /n/i ) {
|
||||||
print " ... skipping.\n";
|
print " ... skipping.\n";
|
||||||
} else {
|
} else {
|
||||||
my $status = 1;
|
set_root_password();
|
||||||
while ( $status == 1 ) {
|
|
||||||
set_root_password();
|
|
||||||
$status = $?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
print "\n";
|
print "\n";
|
||||||
|
|
||||||
@ -334,8 +373,6 @@ if ( $reply =~ /n/i ) {
|
|||||||
}
|
}
|
||||||
print "\n";
|
print "\n";
|
||||||
|
|
||||||
cleanup();
|
|
||||||
|
|
||||||
print <<HERE;
|
print <<HERE;
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,16 +38,39 @@ prepare() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_query() {
|
do_query() {
|
||||||
echo $1 >$command
|
echo "$1" >$command
|
||||||
|
#sed 's,^,> ,' < $command # Debugging
|
||||||
mysql --defaults-file=$config <$command
|
mysql --defaults-file=$config <$command
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Simple escape mechanism (\-escape any ' and \), suitable for two contexts:
|
||||||
|
# - single-quoted SQL strings
|
||||||
|
# - single-quoted option values on the right hand side of = in my.cnf
|
||||||
|
#
|
||||||
|
# These two contexts don't handle escapes identically. SQL strings allow
|
||||||
|
# quoting any character (\C => C, for any C), but my.cnf parsing allows
|
||||||
|
# quoting only \, ' or ". For example, password='a\b' quotes a 3-character
|
||||||
|
# string in my.cnf, but a 2-character string in SQL.
|
||||||
|
#
|
||||||
|
# This simple escape works correctly in both places.
|
||||||
|
basic_single_escape () {
|
||||||
|
# The quoting on this sed command is a bit complex. Single-quoted strings
|
||||||
|
# don't allow *any* escape mechanism, so they cannot contain a single
|
||||||
|
# quote. The string sed gets (as argv[1]) is: s/\(['\]\)/\\\1/g
|
||||||
|
#
|
||||||
|
# Inside a character class, \ and ' are not special, so the ['\] character
|
||||||
|
# class is balanced and contains two characters.
|
||||||
|
echo "$1" | sed 's/\(['"'"'\]\)/\\\1/g'
|
||||||
|
}
|
||||||
|
|
||||||
make_config() {
|
make_config() {
|
||||||
echo "# mysql_secure_installation config file" >$config
|
echo "# mysql_secure_installation config file" >$config
|
||||||
echo "[mysql]" >>$config
|
echo "[mysql]" >>$config
|
||||||
echo "user=root" >>$config
|
echo "user=root" >>$config
|
||||||
echo "password=$rootpass" >>$config
|
esc_pass=`basic_single_escape "$rootpass"`
|
||||||
|
echo "password='$esc_pass'" >>$config
|
||||||
|
#sed 's,^,> ,' < $config # Debugging
|
||||||
}
|
}
|
||||||
|
|
||||||
get_root_password() {
|
get_root_password() {
|
||||||
@ -94,13 +117,12 @@ set_root_password() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
do_query "UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';"
|
esc_pass=`basic_single_escape "$password1"`
|
||||||
|
do_query "UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';"
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Password updated successfully!"
|
echo "Password updated successfully!"
|
||||||
echo "Reloading privilege tables.."
|
echo "Reloading privilege tables.."
|
||||||
if ! reload_privilege_tables; then
|
reload_privilege_tables || exit 1
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo
|
echo
|
||||||
rootpass=$password1
|
rootpass=$password1
|
||||||
make_config
|
make_config
|
||||||
|
131
sql/item.cc
131
sql/item.cc
@ -6940,7 +6940,22 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
|
|||||||
|
|
||||||
Item_cache* Item_cache::get_cache(const Item *item)
|
Item_cache* Item_cache::get_cache(const Item *item)
|
||||||
{
|
{
|
||||||
switch (item->result_type()) {
|
return get_cache(item, item->result_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get a cache item of given type.
|
||||||
|
|
||||||
|
@param item value to be cached
|
||||||
|
@param type required type of cache
|
||||||
|
|
||||||
|
@return cache item
|
||||||
|
*/
|
||||||
|
|
||||||
|
Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
case INT_RESULT:
|
case INT_RESULT:
|
||||||
return new Item_cache_int();
|
return new Item_cache_int();
|
||||||
case REAL_RESULT:
|
case REAL_RESULT:
|
||||||
@ -6958,6 +6973,12 @@ Item_cache* Item_cache::get_cache(const Item *item)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item_cache::store(Item *item)
|
||||||
|
{
|
||||||
|
if (item)
|
||||||
|
example= item;
|
||||||
|
value_cached= FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void Item_cache::print(String *str, enum_query_type query_type)
|
void Item_cache::print(String *str, enum_query_type query_type)
|
||||||
{
|
{
|
||||||
@ -6969,17 +6990,19 @@ void Item_cache::print(String *str, enum_query_type query_type)
|
|||||||
str->append(')');
|
str->append(')');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item_cache_int::cache_value()
|
||||||
void Item_cache_int::store(Item *item)
|
|
||||||
{
|
{
|
||||||
value= item->val_int_result();
|
value_cached= TRUE;
|
||||||
null_value= item->null_value;
|
value= example->val_int_result();
|
||||||
unsigned_flag= item->unsigned_flag;
|
null_value= example->null_value;
|
||||||
|
unsigned_flag= example->unsigned_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_cache_int::store(Item *item, longlong val_arg)
|
void Item_cache_int::store(Item *item, longlong val_arg)
|
||||||
{
|
{
|
||||||
|
/* An explicit values is given, save it. */
|
||||||
|
value_cached= TRUE;
|
||||||
value= val_arg;
|
value= val_arg;
|
||||||
null_value= item->null_value;
|
null_value= item->null_value;
|
||||||
unsigned_flag= item->unsigned_flag;
|
unsigned_flag= item->unsigned_flag;
|
||||||
@ -6989,6 +7012,8 @@ void Item_cache_int::store(Item *item, longlong val_arg)
|
|||||||
String *Item_cache_int::val_str(String *str)
|
String *Item_cache_int::val_str(String *str)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
str->set(value, default_charset());
|
str->set(value, default_charset());
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -6997,21 +7022,49 @@ String *Item_cache_int::val_str(String *str)
|
|||||||
my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
|
my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
|
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
|
||||||
return decimal_val;
|
return decimal_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Item_cache_int::val_real()
|
||||||
void Item_cache_real::store(Item *item)
|
|
||||||
{
|
{
|
||||||
value= item->val_result();
|
DBUG_ASSERT(fixed == 1);
|
||||||
null_value= item->null_value;
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
|
return (double) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
longlong Item_cache_int::val_int()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_cache_real::cache_value()
|
||||||
|
{
|
||||||
|
value_cached= TRUE;
|
||||||
|
value= example->val_result();
|
||||||
|
null_value= example->null_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Item_cache_real::val_real()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
longlong Item_cache_real::val_int()
|
longlong Item_cache_real::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
return (longlong) rint(value);
|
return (longlong) rint(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7019,6 +7072,8 @@ longlong Item_cache_real::val_int()
|
|||||||
String* Item_cache_real::val_str(String *str)
|
String* Item_cache_real::val_str(String *str)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
str->set_real(value, decimals, default_charset());
|
str->set_real(value, decimals, default_charset());
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -7027,15 +7082,18 @@ String* Item_cache_real::val_str(String *str)
|
|||||||
my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
|
my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
||||||
return decimal_val;
|
return decimal_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_cache_decimal::store(Item *item)
|
void Item_cache_decimal::cache_value()
|
||||||
{
|
{
|
||||||
my_decimal *val= item->val_decimal_result(&decimal_value);
|
value_cached= TRUE;
|
||||||
if (!(null_value= item->null_value) && val != &decimal_value)
|
my_decimal *val= example->val_decimal_result(&decimal_value);
|
||||||
|
if (!(null_value= example->null_value) && val != &decimal_value)
|
||||||
my_decimal2decimal(val, &decimal_value);
|
my_decimal2decimal(val, &decimal_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7043,6 +7101,8 @@ double Item_cache_decimal::val_real()
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
double res;
|
double res;
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
|
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -7051,6 +7111,8 @@ longlong Item_cache_decimal::val_int()
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
longlong res;
|
longlong res;
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
|
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -7058,6 +7120,8 @@ longlong Item_cache_decimal::val_int()
|
|||||||
String* Item_cache_decimal::val_str(String *str)
|
String* Item_cache_decimal::val_str(String *str)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
|
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
|
||||||
&decimal_value);
|
&decimal_value);
|
||||||
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
|
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
|
||||||
@ -7067,15 +7131,18 @@ String* Item_cache_decimal::val_str(String *str)
|
|||||||
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
|
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
return &decimal_value;
|
return &decimal_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_cache_str::store(Item *item)
|
void Item_cache_str::cache_value()
|
||||||
{
|
{
|
||||||
value_buff.set(buffer, sizeof(buffer), item->collation.collation);
|
value_cached= TRUE;
|
||||||
value= item->str_result(&value_buff);
|
value_buff.set(buffer, sizeof(buffer), example->collation.collation);
|
||||||
if ((null_value= item->null_value))
|
value= example->str_result(&value_buff);
|
||||||
|
if ((null_value= example->null_value))
|
||||||
value= 0;
|
value= 0;
|
||||||
else if (value != &value_buff)
|
else if (value != &value_buff)
|
||||||
{
|
{
|
||||||
@ -7097,6 +7164,8 @@ double Item_cache_str::val_real()
|
|||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
int err_not_used;
|
int err_not_used;
|
||||||
char *end_not_used;
|
char *end_not_used;
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
if (value)
|
if (value)
|
||||||
return my_strntod(value->charset(), (char*) value->ptr(),
|
return my_strntod(value->charset(), (char*) value->ptr(),
|
||||||
value->length(), &end_not_used, &err_not_used);
|
value->length(), &end_not_used, &err_not_used);
|
||||||
@ -7108,6 +7177,8 @@ longlong Item_cache_str::val_int()
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
int err;
|
int err;
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
if (value)
|
if (value)
|
||||||
return my_strntoll(value->charset(), value->ptr(),
|
return my_strntoll(value->charset(), value->ptr(),
|
||||||
value->length(), 10, (char**) 0, &err);
|
value->length(), 10, (char**) 0, &err);
|
||||||
@ -7115,9 +7186,21 @@ longlong Item_cache_str::val_int()
|
|||||||
return (longlong)0;
|
return (longlong)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String* Item_cache_str::val_str(String *str)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
|
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
if (value)
|
if (value)
|
||||||
string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
||||||
else
|
else
|
||||||
@ -7128,6 +7211,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
|
|||||||
|
|
||||||
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
|
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
|
||||||
{
|
{
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value();
|
||||||
int res= Item_cache::save_in_field(field, no_conversions);
|
int res= Item_cache::save_in_field(field, no_conversions);
|
||||||
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
|
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
|
||||||
value->length() < field->field_length) ? 1 : res;
|
value->length() < field->field_length) ? 1 : res;
|
||||||
@ -7162,11 +7247,19 @@ bool Item_cache_row::setup(Item * item)
|
|||||||
|
|
||||||
void Item_cache_row::store(Item * item)
|
void Item_cache_row::store(Item * item)
|
||||||
{
|
{
|
||||||
|
for (uint i= 0; i < item_count; i++)
|
||||||
|
values[i]->store(item->element_index(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_cache_row::cache_value()
|
||||||
|
{
|
||||||
|
value_cached= TRUE;
|
||||||
null_value= 0;
|
null_value= 0;
|
||||||
item->bring_value();
|
example->bring_value();
|
||||||
for (uint i= 0; i < item_count; i++)
|
for (uint i= 0; i < item_count; i++)
|
||||||
{
|
{
|
||||||
values[i]->store(item->element_index(i));
|
values[i]->cache_value();
|
||||||
null_value|= values[i]->null_value;
|
null_value|= values[i]->null_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
sql/item.h
48
sql/item.h
@ -1024,7 +1024,11 @@ class sp_head;
|
|||||||
|
|
||||||
class Item_basic_constant :public Item
|
class Item_basic_constant :public Item
|
||||||
{
|
{
|
||||||
|
table_map used_table_map;
|
||||||
public:
|
public:
|
||||||
|
Item_basic_constant(): Item(), used_table_map(0) {};
|
||||||
|
void set_used_tables(table_map map) { used_table_map= map; }
|
||||||
|
table_map used_tables() const { return used_table_map; }
|
||||||
/* to prevent drop fixed flag (no need parent cleanup call) */
|
/* to prevent drop fixed flag (no need parent cleanup call) */
|
||||||
void cleanup()
|
void cleanup()
|
||||||
{
|
{
|
||||||
@ -2889,15 +2893,25 @@ protected:
|
|||||||
*/
|
*/
|
||||||
Field *cached_field;
|
Field *cached_field;
|
||||||
enum enum_field_types cached_field_type;
|
enum enum_field_types cached_field_type;
|
||||||
|
/*
|
||||||
|
TRUE <=> cache holds value of the last stored item (i.e actual value).
|
||||||
|
store() stores item to be cached and sets this flag to FALSE.
|
||||||
|
On the first call of val_xxx function if this flag is set to FALSE the
|
||||||
|
cache_value() will be called to actually cache value of saved item.
|
||||||
|
cache_value() will set this flag to TRUE.
|
||||||
|
*/
|
||||||
|
bool value_cached;
|
||||||
public:
|
public:
|
||||||
Item_cache():
|
Item_cache():
|
||||||
example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING)
|
example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING),
|
||||||
|
value_cached(0)
|
||||||
{
|
{
|
||||||
fixed= 1;
|
fixed= 1;
|
||||||
null_value= 1;
|
null_value= 1;
|
||||||
}
|
}
|
||||||
Item_cache(enum_field_types field_type_arg):
|
Item_cache(enum_field_types field_type_arg):
|
||||||
example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg)
|
example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg),
|
||||||
|
value_cached(0)
|
||||||
{
|
{
|
||||||
fixed= 1;
|
fixed= 1;
|
||||||
null_value= 1;
|
null_value= 1;
|
||||||
@ -2917,10 +2931,10 @@ public:
|
|||||||
cached_field= ((Item_field *)item)->field;
|
cached_field= ((Item_field *)item)->field;
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
virtual void store(Item *)= 0;
|
|
||||||
enum Type type() const { return CACHE_ITEM; }
|
enum Type type() const { return CACHE_ITEM; }
|
||||||
enum_field_types field_type() const { return cached_field_type; }
|
enum_field_types field_type() const { return cached_field_type; }
|
||||||
static Item_cache* get_cache(const Item *item);
|
static Item_cache* get_cache(const Item *item);
|
||||||
|
static Item_cache* get_cache(const Item* item, const Item_result type);
|
||||||
table_map used_tables() const { return used_table_map; }
|
table_map used_tables() const { return used_table_map; }
|
||||||
virtual void keep_array() {}
|
virtual void keep_array() {}
|
||||||
virtual void print(String *str, enum_query_type query_type);
|
virtual void print(String *str, enum_query_type query_type);
|
||||||
@ -2932,6 +2946,8 @@ public:
|
|||||||
{
|
{
|
||||||
return this == item;
|
return this == item;
|
||||||
}
|
}
|
||||||
|
virtual void store(Item *item);
|
||||||
|
virtual void cache_value()= 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2940,18 +2956,19 @@ class Item_cache_int: public Item_cache
|
|||||||
protected:
|
protected:
|
||||||
longlong value;
|
longlong value;
|
||||||
public:
|
public:
|
||||||
Item_cache_int(): Item_cache(), value(0) {}
|
Item_cache_int(): Item_cache(),
|
||||||
|
value(0) {}
|
||||||
Item_cache_int(enum_field_types field_type_arg):
|
Item_cache_int(enum_field_types field_type_arg):
|
||||||
Item_cache(field_type_arg), value(0) {}
|
Item_cache(field_type_arg), value(0) {}
|
||||||
|
|
||||||
void store(Item *item);
|
|
||||||
void store(Item *item, longlong val_arg);
|
void store(Item *item, longlong val_arg);
|
||||||
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
|
double val_real();
|
||||||
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
|
longlong val_int();
|
||||||
String* val_str(String *str);
|
String* val_str(String *str);
|
||||||
my_decimal *val_decimal(my_decimal *);
|
my_decimal *val_decimal(my_decimal *);
|
||||||
enum Item_result result_type() const { return INT_RESULT; }
|
enum Item_result result_type() const { return INT_RESULT; }
|
||||||
bool result_as_longlong() { return TRUE; }
|
bool result_as_longlong() { return TRUE; }
|
||||||
|
void cache_value();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2959,14 +2976,15 @@ class Item_cache_real: public Item_cache
|
|||||||
{
|
{
|
||||||
double value;
|
double value;
|
||||||
public:
|
public:
|
||||||
Item_cache_real(): Item_cache(), value(0) {}
|
Item_cache_real(): Item_cache(),
|
||||||
|
value(0) {}
|
||||||
|
|
||||||
void store(Item *item);
|
double val_real();
|
||||||
double val_real() { DBUG_ASSERT(fixed == 1); return value; }
|
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
String* val_str(String *str);
|
String* val_str(String *str);
|
||||||
my_decimal *val_decimal(my_decimal *);
|
my_decimal *val_decimal(my_decimal *);
|
||||||
enum Item_result result_type() const { return REAL_RESULT; }
|
enum Item_result result_type() const { return REAL_RESULT; }
|
||||||
|
void cache_value();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2977,12 +2995,12 @@ protected:
|
|||||||
public:
|
public:
|
||||||
Item_cache_decimal(): Item_cache() {}
|
Item_cache_decimal(): Item_cache() {}
|
||||||
|
|
||||||
void store(Item *item);
|
|
||||||
double val_real();
|
double val_real();
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
String* val_str(String *str);
|
String* val_str(String *str);
|
||||||
my_decimal *val_decimal(my_decimal *);
|
my_decimal *val_decimal(my_decimal *);
|
||||||
enum Item_result result_type() const { return DECIMAL_RESULT; }
|
enum Item_result result_type() const { return DECIMAL_RESULT; }
|
||||||
|
void cache_value();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3000,14 +3018,14 @@ public:
|
|||||||
MYSQL_TYPE_VARCHAR &&
|
MYSQL_TYPE_VARCHAR &&
|
||||||
!((const Item_field *) item)->field->has_charset())
|
!((const Item_field *) item)->field->has_charset())
|
||||||
{}
|
{}
|
||||||
void store(Item *item);
|
|
||||||
double val_real();
|
double val_real();
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; }
|
String* val_str(String *);
|
||||||
my_decimal *val_decimal(my_decimal *);
|
my_decimal *val_decimal(my_decimal *);
|
||||||
enum Item_result result_type() const { return STRING_RESULT; }
|
enum Item_result result_type() const { return STRING_RESULT; }
|
||||||
CHARSET_INFO *charset() const { return value->charset(); };
|
CHARSET_INFO *charset() const { return value->charset(); };
|
||||||
int save_in_field(Field *field, bool no_conversions);
|
int save_in_field(Field *field, bool no_conversions);
|
||||||
|
void cache_value();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_cache_row: public Item_cache
|
class Item_cache_row: public Item_cache
|
||||||
@ -3017,7 +3035,8 @@ class Item_cache_row: public Item_cache
|
|||||||
bool save_array;
|
bool save_array;
|
||||||
public:
|
public:
|
||||||
Item_cache_row()
|
Item_cache_row()
|
||||||
:Item_cache(), values(0), item_count(2), save_array(0) {}
|
:Item_cache(), values(0), item_count(2),
|
||||||
|
save_array(0) {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
'allocate' used only in row transformer, to preallocate space for row
|
'allocate' used only in row transformer, to preallocate space for row
|
||||||
@ -3075,6 +3094,7 @@ public:
|
|||||||
values= 0;
|
values= 0;
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
void cache_value();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -785,15 +785,21 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
|
|||||||
|
|
||||||
if (cmp_type != CMP_DATE_DFLT)
|
if (cmp_type != CMP_DATE_DFLT)
|
||||||
{
|
{
|
||||||
|
THD *thd= current_thd;
|
||||||
/*
|
/*
|
||||||
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
|
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
|
||||||
for the current thread but it still may change during the execution.
|
for the current thread but it still may change during the execution.
|
||||||
|
Don't use cache while in the context analysis mode only (i.e. for
|
||||||
|
EXPLAIN/CREATE VIEW and similar queries). Cache is useless in such
|
||||||
|
cases and can cause problems. For example evaluating subqueries can
|
||||||
|
confuse storage engines since in context analysis mode tables
|
||||||
|
aren't locked.
|
||||||
*/
|
*/
|
||||||
if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() &&
|
if (!thd->is_context_analysis_only() &&
|
||||||
|
cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() &&
|
||||||
(str_arg->type() != Item::FUNC_ITEM ||
|
(str_arg->type() != Item::FUNC_ITEM ||
|
||||||
((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
|
((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
|
||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
|
||||||
ulonglong value;
|
ulonglong value;
|
||||||
bool error;
|
bool error;
|
||||||
String tmp, *str_val= 0;
|
String tmp, *str_val= 0;
|
||||||
@ -881,13 +887,13 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||||||
{
|
{
|
||||||
enum enum_date_cmp_type cmp_type;
|
enum enum_date_cmp_type cmp_type;
|
||||||
ulonglong const_value= (ulonglong)-1;
|
ulonglong const_value= (ulonglong)-1;
|
||||||
|
thd= current_thd;
|
||||||
|
owner= owner_arg;
|
||||||
a= a1;
|
a= a1;
|
||||||
b= a2;
|
b= a2;
|
||||||
|
|
||||||
if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
|
if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
|
||||||
{
|
{
|
||||||
thd= current_thd;
|
|
||||||
owner= owner_arg;
|
|
||||||
a_type= (*a)->field_type();
|
a_type= (*a)->field_type();
|
||||||
b_type= (*b)->field_type();
|
b_type= (*b)->field_type();
|
||||||
a_cache= 0;
|
a_cache= 0;
|
||||||
@ -895,6 +901,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||||||
|
|
||||||
if (const_value != (ulonglong)-1)
|
if (const_value != (ulonglong)-1)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
cache_converted_constant can't be used here because it can't
|
||||||
|
correctly convert a DATETIME value from string to int representation.
|
||||||
|
*/
|
||||||
Item_cache_int *cache= new Item_cache_int();
|
Item_cache_int *cache= new Item_cache_int();
|
||||||
/* Mark the cache as non-const to prevent re-caching. */
|
/* Mark the cache as non-const to prevent re-caching. */
|
||||||
cache->set_used_tables(1);
|
cache->set_used_tables(1);
|
||||||
@ -920,8 +930,6 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||||||
(*b)->field_type() == MYSQL_TYPE_TIME)
|
(*b)->field_type() == MYSQL_TYPE_TIME)
|
||||||
{
|
{
|
||||||
/* Compare TIME values as integers. */
|
/* Compare TIME values as integers. */
|
||||||
thd= current_thd;
|
|
||||||
owner= owner_arg;
|
|
||||||
a_cache= 0;
|
a_cache= 0;
|
||||||
b_cache= 0;
|
b_cache= 0;
|
||||||
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
|
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
|
||||||
@ -940,10 +948,46 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a= cache_converted_constant(thd, a, &a_cache, type);
|
||||||
|
b= cache_converted_constant(thd, b, &b_cache, type);
|
||||||
return set_compare_func(owner_arg, type);
|
return set_compare_func(owner_arg, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convert and cache a constant.
|
||||||
|
|
||||||
|
@param value [in] An item to cache
|
||||||
|
@param cache_item [out] Placeholder for the cache item
|
||||||
|
@param type [in] Comparison type
|
||||||
|
|
||||||
|
@details
|
||||||
|
When given item is a constant and its type differs from comparison type
|
||||||
|
then cache its value to avoid type conversion of this constant on each
|
||||||
|
evaluation. In this case the value is cached and the reference to the cache
|
||||||
|
is returned.
|
||||||
|
Original value is returned otherwise.
|
||||||
|
|
||||||
|
@return cache item or original value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value,
|
||||||
|
Item **cache_item,
|
||||||
|
Item_result type)
|
||||||
|
{
|
||||||
|
/* Don't need cache if doing context analysis only. */
|
||||||
|
if (!thd->is_context_analysis_only() &&
|
||||||
|
(*value)->const_item() && type != (*value)->result_type())
|
||||||
|
{
|
||||||
|
Item_cache *cache= Item_cache::get_cache(*value, type);
|
||||||
|
cache->store(*value);
|
||||||
|
*cache_item= cache;
|
||||||
|
return cache_item;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
|
void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
|
||||||
{
|
{
|
||||||
thd= current_thd;
|
thd= current_thd;
|
||||||
@ -1582,6 +1626,7 @@ longlong Item_in_optimizer::val_int()
|
|||||||
bool tmp;
|
bool tmp;
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
cache->store(args[0]);
|
cache->store(args[0]);
|
||||||
|
cache->cache_value();
|
||||||
|
|
||||||
if (cache->null_value)
|
if (cache->null_value)
|
||||||
{
|
{
|
||||||
|
@ -94,6 +94,8 @@ public:
|
|||||||
ulonglong *const_val_arg);
|
ulonglong *const_val_arg);
|
||||||
|
|
||||||
void set_datetime_cmp_func(Item **a1, Item **b1);
|
void set_datetime_cmp_func(Item **a1, Item **b1);
|
||||||
|
Item** cache_converted_constant(THD *thd, Item **value, Item **cache,
|
||||||
|
Item_result type);
|
||||||
static arg_cmp_func comparator_matrix [5][2];
|
static arg_cmp_func comparator_matrix [5][2];
|
||||||
|
|
||||||
friend class Item_func;
|
friend class Item_func;
|
||||||
|
@ -480,6 +480,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
|
|||||||
void Item_singlerow_subselect::store(uint i, Item *item)
|
void Item_singlerow_subselect::store(uint i, Item *item)
|
||||||
{
|
{
|
||||||
row[i]->store(item);
|
row[i]->store(item);
|
||||||
|
row[i]->cache_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Item_result Item_singlerow_subselect::result_type() const
|
enum Item_result Item_singlerow_subselect::result_type() const
|
||||||
@ -1831,6 +1832,7 @@ void subselect_engine::set_row(List<Item> &item_list, Item_cache **row)
|
|||||||
if (!(row[i]= Item_cache::get_cache(sel_item)))
|
if (!(row[i]= Item_cache::get_cache(sel_item)))
|
||||||
return;
|
return;
|
||||||
row[i]->setup(sel_item);
|
row[i]->setup(sel_item);
|
||||||
|
row[i]->store(sel_item);
|
||||||
}
|
}
|
||||||
if (item_list.elements > 1)
|
if (item_list.elements > 1)
|
||||||
res_type= ROW_RESULT;
|
res_type= ROW_RESULT;
|
||||||
|
@ -941,14 +941,16 @@ static Item *create_comparator(MY_XPATH *xpath,
|
|||||||
in a loop through all of the nodes in the node set.
|
in a loop through all of the nodes in the node set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item *fake= new Item_string("", 0, xpath->cs);
|
Item_string *fake= new Item_string("", 0, xpath->cs);
|
||||||
|
/* Don't cache fake because its value will be changed during comparison.*/
|
||||||
|
fake->set_used_tables(RAND_TABLE_BIT);
|
||||||
Item_nodeset_func *nodeset;
|
Item_nodeset_func *nodeset;
|
||||||
Item *scalar, *comp;
|
Item *scalar, *comp;
|
||||||
if (a->type() == Item::XPATH_NODESET)
|
if (a->type() == Item::XPATH_NODESET)
|
||||||
{
|
{
|
||||||
nodeset= (Item_nodeset_func*) a;
|
nodeset= (Item_nodeset_func*) a;
|
||||||
scalar= b;
|
scalar= b;
|
||||||
comp= eq_func(oper, fake, scalar);
|
comp= eq_func(oper, (Item*)fake, scalar);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3966,6 +3966,27 @@ server.");
|
|||||||
|
|
||||||
if (opt_bin_log)
|
if (opt_bin_log)
|
||||||
{
|
{
|
||||||
|
/* Reports an error and aborts, if the --log-bin's path
|
||||||
|
is a directory.*/
|
||||||
|
if (opt_bin_logname &&
|
||||||
|
opt_bin_logname[strlen(opt_bin_logname) - 1] == FN_LIBCHAR)
|
||||||
|
{
|
||||||
|
sql_print_error("Path '%s' is a directory name, please specify \
|
||||||
|
a file name for --log-bin option", opt_bin_logname);
|
||||||
|
unireg_abort(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reports an error and aborts, if the --log-bin-index's path
|
||||||
|
is a directory.*/
|
||||||
|
if (opt_binlog_index_name &&
|
||||||
|
opt_binlog_index_name[strlen(opt_binlog_index_name) - 1]
|
||||||
|
== FN_LIBCHAR)
|
||||||
|
{
|
||||||
|
sql_print_error("Path '%s' is a directory name, please specify \
|
||||||
|
a file name for --log-bin-index option", opt_binlog_index_name);
|
||||||
|
unireg_abort(1);
|
||||||
|
}
|
||||||
|
|
||||||
char buf[FN_REFLEN];
|
char buf[FN_REFLEN];
|
||||||
const char *ln;
|
const char *ln;
|
||||||
ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf);
|
ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf);
|
||||||
@ -8736,14 +8757,8 @@ static int fix_paths(void)
|
|||||||
pos[0]= FN_LIBCHAR;
|
pos[0]= FN_LIBCHAR;
|
||||||
pos[1]= 0;
|
pos[1]= 0;
|
||||||
}
|
}
|
||||||
convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
|
|
||||||
my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0));
|
|
||||||
mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home);
|
|
||||||
if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR)
|
|
||||||
--mysql_unpacked_real_data_home_len;
|
|
||||||
|
|
||||||
|
|
||||||
convert_dirname(language,language,NullS);
|
convert_dirname(language,language,NullS);
|
||||||
|
convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
|
||||||
(void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
|
(void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
|
||||||
(void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
|
(void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
|
||||||
(void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home);
|
(void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home);
|
||||||
@ -8751,6 +8766,12 @@ static int fix_paths(void)
|
|||||||
get_relative_path(PLUGINDIR), mysql_home);
|
get_relative_path(PLUGINDIR), mysql_home);
|
||||||
opt_plugin_dir_ptr= opt_plugin_dir;
|
opt_plugin_dir_ptr= opt_plugin_dir;
|
||||||
|
|
||||||
|
my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0));
|
||||||
|
mysql_unpacked_real_data_home_len=
|
||||||
|
(int) strlen(mysql_unpacked_real_data_home);
|
||||||
|
if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR)
|
||||||
|
--mysql_unpacked_real_data_home_len;
|
||||||
|
|
||||||
char *sharedir=get_relative_path(SHAREDIR);
|
char *sharedir=get_relative_path(SHAREDIR);
|
||||||
if (test_if_hard_path(sharedir))
|
if (test_if_hard_path(sharedir))
|
||||||
strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */
|
strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */
|
||||||
|
@ -132,6 +132,29 @@ int init_relay_log_info(Relay_log_info* rli,
|
|||||||
rli->relay_log.max_size (and mysql_bin_log.max_size).
|
rli->relay_log.max_size (and mysql_bin_log.max_size).
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
/* Reports an error and returns, if the --relay-log's path
|
||||||
|
is a directory.*/
|
||||||
|
if (opt_relay_logname &&
|
||||||
|
opt_relay_logname[strlen(opt_relay_logname) - 1] == FN_LIBCHAR)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&rli->data_lock);
|
||||||
|
sql_print_error("Path '%s' is a directory name, please specify \
|
||||||
|
a file name for --relay-log option", opt_relay_logname);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reports an error and returns, if the --relay-log-index's path
|
||||||
|
is a directory.*/
|
||||||
|
if (opt_relaylog_index_name &&
|
||||||
|
opt_relaylog_index_name[strlen(opt_relaylog_index_name) - 1]
|
||||||
|
== FN_LIBCHAR)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&rli->data_lock);
|
||||||
|
sql_print_error("Path '%s' is a directory name, please specify \
|
||||||
|
a file name for --relay-log-index option", opt_relaylog_index_name);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
char buf[FN_REFLEN];
|
char buf[FN_REFLEN];
|
||||||
const char *ln;
|
const char *ln;
|
||||||
static bool name_warning_sent= 0;
|
static bool name_warning_sent= 0;
|
||||||
|
@ -617,7 +617,7 @@ sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_case_expr_holders[case_expr_id]->store(case_expr_item);
|
m_case_expr_holders[case_expr_id]->store(case_expr_item);
|
||||||
|
m_case_expr_holders[case_expr_id]->cache_value();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,14 +985,20 @@ JOIN::optimize()
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields())
|
if (rollup.state != ROLLUP::STATE_NONE)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("error", ("Error: rollup_process_fields() failed"));
|
if (rollup_process_const_fields())
|
||||||
DBUG_RETURN(1);
|
{
|
||||||
|
DBUG_PRINT("error", ("Error: rollup_process_fields() failed"));
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Remove distinct if only const tables */
|
||||||
|
select_distinct= select_distinct && (const_tables != tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove distinct if only const tables */
|
|
||||||
select_distinct= select_distinct && (const_tables != tables);
|
|
||||||
thd_proc_info(thd, "preparing");
|
thd_proc_info(thd, "preparing");
|
||||||
if (result->initialize_tables(this))
|
if (result->initialize_tables(this))
|
||||||
{
|
{
|
||||||
@ -1291,11 +1297,14 @@ JOIN::optimize()
|
|||||||
- We are using an ORDER BY or GROUP BY on fields not in the first table
|
- We are using an ORDER BY or GROUP BY on fields not in the first table
|
||||||
- We are using different ORDER BY and GROUP BY orders
|
- We are using different ORDER BY and GROUP BY orders
|
||||||
- The user wants us to buffer the result.
|
- The user wants us to buffer the result.
|
||||||
|
When the WITH ROLLUP modifier is present, we cannot skip temporary table
|
||||||
|
creation for the DISTINCT clause just because there are only const tables.
|
||||||
*/
|
*/
|
||||||
need_tmp= (const_tables != tables &&
|
need_tmp= ((const_tables != tables &&
|
||||||
((select_distinct || !simple_order || !simple_group) ||
|
((select_distinct || !simple_order || !simple_group) ||
|
||||||
(group_list && order) ||
|
(group_list && order) ||
|
||||||
test(select_options & OPTION_BUFFER_RESULT)));
|
test(select_options & OPTION_BUFFER_RESULT))) ||
|
||||||
|
rollup.state != ROLLUP::STATE_NONE && select_distinct);
|
||||||
|
|
||||||
// No cache for MATCH
|
// No cache for MATCH
|
||||||
make_join_readinfo(this,
|
make_join_readinfo(this,
|
||||||
@ -6481,6 +6490,56 @@ void rr_unlock_row(st_join_table *tab)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Pick the appropriate access method functions
|
||||||
|
|
||||||
|
Sets the functions for the selected table access method
|
||||||
|
|
||||||
|
@param tab Table reference to put access method
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
pick_table_access_method(JOIN_TAB *tab)
|
||||||
|
{
|
||||||
|
switch (tab->type)
|
||||||
|
{
|
||||||
|
case JT_REF:
|
||||||
|
tab->read_first_record= join_read_always_key;
|
||||||
|
tab->read_record.read_record= join_read_next_same;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JT_REF_OR_NULL:
|
||||||
|
tab->read_first_record= join_read_always_key_or_null;
|
||||||
|
tab->read_record.read_record= join_read_next_same_or_null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JT_CONST:
|
||||||
|
tab->read_first_record= join_read_const;
|
||||||
|
tab->read_record.read_record= join_no_more_records;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JT_EQ_REF:
|
||||||
|
tab->read_first_record= join_read_key;
|
||||||
|
tab->read_record.read_record= join_no_more_records;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JT_FT:
|
||||||
|
tab->read_first_record= join_ft_read_first;
|
||||||
|
tab->read_record.read_record= join_ft_read_next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JT_SYSTEM:
|
||||||
|
tab->read_first_record= join_read_system;
|
||||||
|
tab->read_record.read_record= join_no_more_records;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* keep gcc happy */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
make_join_readinfo(JOIN *join, ulonglong options)
|
make_join_readinfo(JOIN *join, ulonglong options)
|
||||||
{
|
{
|
||||||
@ -6515,45 +6574,15 @@ make_join_readinfo(JOIN *join, ulonglong options)
|
|||||||
|
|
||||||
tab->sorted= sorted;
|
tab->sorted= sorted;
|
||||||
sorted= 0; // only first must be sorted
|
sorted= 0; // only first must be sorted
|
||||||
|
table->status=STATUS_NO_RECORD;
|
||||||
|
pick_table_access_method (tab);
|
||||||
|
|
||||||
switch (tab->type) {
|
switch (tab->type) {
|
||||||
case JT_SYSTEM: // Only happens with left join
|
|
||||||
table->status=STATUS_NO_RECORD;
|
|
||||||
tab->read_first_record= join_read_system;
|
|
||||||
tab->read_record.read_record= join_no_more_records;
|
|
||||||
break;
|
|
||||||
case JT_CONST: // Only happens with left join
|
|
||||||
table->status=STATUS_NO_RECORD;
|
|
||||||
tab->read_first_record= join_read_const;
|
|
||||||
tab->read_record.read_record= join_no_more_records;
|
|
||||||
if (table->covering_keys.is_set(tab->ref.key) &&
|
|
||||||
!table->no_keyread)
|
|
||||||
{
|
|
||||||
table->key_read=1;
|
|
||||||
table->file->extra(HA_EXTRA_KEYREAD);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JT_EQ_REF:
|
case JT_EQ_REF:
|
||||||
table->status=STATUS_NO_RECORD;
|
|
||||||
if (tab->select)
|
|
||||||
{
|
|
||||||
delete tab->select->quick;
|
|
||||||
tab->select->quick=0;
|
|
||||||
}
|
|
||||||
delete tab->quick;
|
|
||||||
tab->quick=0;
|
|
||||||
tab->read_first_record= join_read_key;
|
|
||||||
tab->read_record.unlock_row= join_read_key_unlock_row;
|
tab->read_record.unlock_row= join_read_key_unlock_row;
|
||||||
tab->read_record.read_record= join_no_more_records;
|
/* fall through */
|
||||||
if (table->covering_keys.is_set(tab->ref.key) &&
|
|
||||||
!table->no_keyread)
|
|
||||||
{
|
|
||||||
table->key_read=1;
|
|
||||||
table->file->extra(HA_EXTRA_KEYREAD);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JT_REF_OR_NULL:
|
case JT_REF_OR_NULL:
|
||||||
case JT_REF:
|
case JT_REF:
|
||||||
table->status=STATUS_NO_RECORD;
|
|
||||||
if (tab->select)
|
if (tab->select)
|
||||||
{
|
{
|
||||||
delete tab->select->quick;
|
delete tab->select->quick;
|
||||||
@ -6561,34 +6590,20 @@ make_join_readinfo(JOIN *join, ulonglong options)
|
|||||||
}
|
}
|
||||||
delete tab->quick;
|
delete tab->quick;
|
||||||
tab->quick=0;
|
tab->quick=0;
|
||||||
|
/* fall through */
|
||||||
|
case JT_CONST: // Only happens with left join
|
||||||
if (table->covering_keys.is_set(tab->ref.key) &&
|
if (table->covering_keys.is_set(tab->ref.key) &&
|
||||||
!table->no_keyread)
|
!table->no_keyread)
|
||||||
{
|
{
|
||||||
table->key_read=1;
|
table->key_read=1;
|
||||||
table->file->extra(HA_EXTRA_KEYREAD);
|
table->file->extra(HA_EXTRA_KEYREAD);
|
||||||
}
|
}
|
||||||
if (tab->type == JT_REF)
|
|
||||||
{
|
|
||||||
tab->read_first_record= join_read_always_key;
|
|
||||||
tab->read_record.read_record= join_read_next_same;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tab->read_first_record= join_read_always_key_or_null;
|
|
||||||
tab->read_record.read_record= join_read_next_same_or_null;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JT_FT:
|
|
||||||
table->status=STATUS_NO_RECORD;
|
|
||||||
tab->read_first_record= join_ft_read_first;
|
|
||||||
tab->read_record.read_record= join_ft_read_next;
|
|
||||||
break;
|
break;
|
||||||
case JT_ALL:
|
case JT_ALL:
|
||||||
/*
|
/*
|
||||||
If previous table use cache
|
If previous table use cache
|
||||||
If the incoming data set is already sorted don't use cache.
|
If the incoming data set is already sorted don't use cache.
|
||||||
*/
|
*/
|
||||||
table->status=STATUS_NO_RECORD;
|
|
||||||
if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
|
if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
|
||||||
tab->use_quick != 2 && !tab->first_inner && !ordered_set)
|
tab->use_quick != 2 && !tab->first_inner && !ordered_set)
|
||||||
{
|
{
|
||||||
@ -6668,6 +6683,9 @@ make_join_readinfo(JOIN *join, ulonglong options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case JT_FT:
|
||||||
|
case JT_SYSTEM:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */
|
DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */
|
||||||
break; /* purecov: deadcode */
|
break; /* purecov: deadcode */
|
||||||
@ -7819,12 +7837,12 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
|
|||||||
{
|
{
|
||||||
item_equal->fix_length_and_dec();
|
item_equal->fix_length_and_dec();
|
||||||
item_equal->update_used_tables();
|
item_equal->update_used_tables();
|
||||||
|
set_if_bigger(thd->lex->current_select->max_equal_elems,
|
||||||
|
item_equal->members());
|
||||||
|
return item_equal;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
item_equal= (Item_equal *) eq_list.pop();
|
return eq_list.pop();
|
||||||
set_if_bigger(thd->lex->current_select->max_equal_elems,
|
|
||||||
item_equal->members());
|
|
||||||
return item_equal;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -13189,6 +13207,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
if (create_ref_for_key(tab->join, tab, keyuse,
|
if (create_ref_for_key(tab->join, tab, keyuse,
|
||||||
tab->join->const_table_map))
|
tab->join->const_table_map))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
pick_table_access_method(tab);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -475,8 +475,7 @@ static void _ftb_init_index_search(FT_INFO *ftb)
|
|||||||
int i;
|
int i;
|
||||||
FTB_WORD *ftbw;
|
FTB_WORD *ftbw;
|
||||||
|
|
||||||
if ((ftb->state != READY && ftb->state !=INDEX_DONE) ||
|
if (ftb->state == UNINITIALIZED || ftb->keynr == NO_SUCH_KEY)
|
||||||
ftb->keynr == NO_SUCH_KEY)
|
|
||||||
return;
|
return;
|
||||||
ftb->state=INDEX_SEARCH;
|
ftb->state=INDEX_SEARCH;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user