mirror of
https://github.com/MariaDB/server.git
synced 2025-01-22 06:44:16 +01:00
automerge
This commit is contained in:
commit
1701a145db
28 changed files with 1071 additions and 156 deletions
|
@ -601,15 +601,15 @@ dnl ---------------------------------------------------------------------------
|
|||
|
||||
dnl 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_TRY_LINK([], [
|
||||
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++)
|
||||
])
|
||||
if test "$mysql_use_mysys_new" = "yes"
|
||||
if test "$mysql_cv_use_mysys_new" = "yes"
|
||||
then
|
||||
AC_DEFINE([USE_MYSYS_NEW], [1], [Needs to use mysys_new helpers])
|
||||
fi
|
||||
|
|
|
@ -13,6 +13,12 @@ AC_CANONICAL_SYSTEM
|
|||
AM_INIT_AUTOMAKE(mysql, 5.1.41)
|
||||
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
|
||||
DOT_FRM_VERSION=6
|
||||
# See the libtool docs for information on how to do shared lib versions.
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <time.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#else
|
||||
|
|
|
@ -1631,12 +1631,14 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
|
|||
|
||||
|
||||
char * STDCALL
|
||||
mysql_odbc_escape_string(MYSQL *mysql,
|
||||
char *to, ulong to_length,
|
||||
const char *from, ulong from_length,
|
||||
void *param,
|
||||
char * (*extend_buffer)
|
||||
(void *, char *, ulong *))
|
||||
mysql_odbc_escape_string(MYSQL *mysql __attribute__((unused)),
|
||||
char *to __attribute__((unused)),
|
||||
ulong to_length __attribute__((unused)),
|
||||
const char *from __attribute__((unused)),
|
||||
ulong from_length __attribute__((unused)),
|
||||
void *param __attribute__((unused)),
|
||||
char * (*extend_buffer)(void *, char *, ulong *)
|
||||
__attribute__((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,15 @@ INSERT INTO global_suppressions VALUES
|
|||
("Can't find file: '.\\\\test\\\\\\?{8}.frm'"),
|
||||
("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")||
|
||||
|
||||
|
||||
|
|
|
@ -50,9 +50,6 @@
|
|||
is killed.
|
||||
*/
|
||||
|
||||
/* Requires Windows 2000 or higher */
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <tlhelp32.h>
|
||||
|
|
|
@ -48,5 +48,310 @@ commit;
|
|||
set autocommit=default;
|
||||
drop table t1;
|
||||
#
|
||||
# Bug#41756 Strange error messages about locks from InnoDB
|
||||
#
|
||||
drop table if exists t1;
|
||||
# In the default transaction isolation mode, and/or with
|
||||
# innodb_locks_unsafe_for_binlog=OFF, handler::unlock_row()
|
||||
# in InnoDB does nothing.
|
||||
# Thus in order to reproduce the condition that led to the
|
||||
# warning, one needs to relax isolation by either
|
||||
# setting a weaker tx_isolation value, or by turning on
|
||||
# the unsafe replication switch.
|
||||
# For testing purposes, choose to tweak the isolation level,
|
||||
# since it's settable at runtime, unlike
|
||||
# innodb_locks_unsafe_for_binlog, which is
|
||||
# only a command-line switch.
|
||||
#
|
||||
set @@session.tx_isolation="read-committed";
|
||||
# Prepare data. We need a table with a unique index,
|
||||
# for join_read_key to be used. The other column
|
||||
# allows to control what passes WHERE clause filter.
|
||||
create table t1 (a int primary key, b int) engine=innodb;
|
||||
# Let's make sure t1 has sufficient amount of rows
|
||||
# to exclude JT_ALL access method when reading it,
|
||||
# i.e. make sure that JT_EQ_REF(a) is always preferred.
|
||||
insert into t1 values (1,1), (2,null), (3,1), (4,1),
|
||||
(5,1), (6,1), (7,1), (8,1), (9,1), (10,1),
|
||||
(11,1), (12,1), (13,1), (14,1), (15,1),
|
||||
(16,1), (17,1), (18,1), (19,1), (20,1);
|
||||
#
|
||||
# Demonstrate that for the SELECT statement
|
||||
# used later in the test JT_EQ_REF access method is used.
|
||||
#
|
||||
explain
|
||||
select 1 from t1 natural join (select 2 as a, 1 as b union all
|
||||
select 2 as a, 2 as b) as t2 for update;
|
||||
id 1
|
||||
select_type PRIMARY
|
||||
table <derived2>
|
||||
type ALL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows 2
|
||||
Extra
|
||||
id 1
|
||||
select_type PRIMARY
|
||||
table t1
|
||||
type eq_ref
|
||||
possible_keys PRIMARY
|
||||
key PRIMARY
|
||||
key_len 4
|
||||
ref t2.a
|
||||
rows 1
|
||||
Extra Using where
|
||||
id 2
|
||||
select_type DERIVED
|
||||
table NULL
|
||||
type NULL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows NULL
|
||||
Extra No tables used
|
||||
id 3
|
||||
select_type UNION
|
||||
table NULL
|
||||
type NULL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows NULL
|
||||
Extra No tables used
|
||||
id NULL
|
||||
select_type UNION RESULT
|
||||
table <union2,3>
|
||||
type ALL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows NULL
|
||||
Extra
|
||||
#
|
||||
# Demonstrate that the reported SELECT statement
|
||||
# no longer produces warnings.
|
||||
#
|
||||
select 1 from t1 natural join (select 2 as a, 1 as b union all
|
||||
select 2 as a, 2 as b) as t2 for update;
|
||||
1
|
||||
commit;
|
||||
#
|
||||
# Demonstrate that due to lack of inter-sweep "reset" function,
|
||||
# we keep some non-matching records locked, even though we know
|
||||
# we could unlock them.
|
||||
# To do that, show that if there is only one distinct value
|
||||
# for a in t2 (a=2), we will keep record (2,null) in t1 locked.
|
||||
# But if we add another value for "a" to t2, say 6,
|
||||
# join_read_key cache will be pruned at least once,
|
||||
# and thus record (2, null) in t1 will get unlocked.
|
||||
#
|
||||
begin;
|
||||
select 1 from t1 natural join (select 2 as a, 1 as b union all
|
||||
select 2 as a, 2 as b) as t2 for update;
|
||||
1
|
||||
#
|
||||
# Switching to connection con1
|
||||
# We should be able to delete all records from t1 except (2, null),
|
||||
# since they were not locked.
|
||||
begin;
|
||||
# Delete in series of 3 records so that full scan
|
||||
# is not used and we're not blocked on record (2,null)
|
||||
delete from t1 where a in (1,3,4);
|
||||
delete from t1 where a in (5,6,7);
|
||||
delete from t1 where a in (8,9,10);
|
||||
delete from t1 where a in (11,12,13);
|
||||
delete from t1 where a in (14,15,16);
|
||||
delete from t1 where a in (17,18);
|
||||
delete from t1 where a in (19,20);
|
||||
#
|
||||
# Record (2, null) is locked. This is actually unnecessary,
|
||||
# because the previous select returned no rows.
|
||||
# Just demonstrate the effect.
|
||||
#
|
||||
delete from t1;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
rollback;
|
||||
#
|
||||
# Switching to connection default
|
||||
#
|
||||
# Show that the original contents of t1 is intact:
|
||||
select * from t1;
|
||||
a b
|
||||
1 1
|
||||
2 NULL
|
||||
3 1
|
||||
4 1
|
||||
5 1
|
||||
6 1
|
||||
7 1
|
||||
8 1
|
||||
9 1
|
||||
10 1
|
||||
11 1
|
||||
12 1
|
||||
13 1
|
||||
14 1
|
||||
15 1
|
||||
16 1
|
||||
17 1
|
||||
18 1
|
||||
19 1
|
||||
20 1
|
||||
commit;
|
||||
#
|
||||
# Have a one more record in t2 to show that
|
||||
# if join_read_key cache is purned, the current
|
||||
# row under the cursor is unlocked (provided, this row didn't
|
||||
# match the partial WHERE clause, of course).
|
||||
# Sic: the result of this test dependent on the order of retrieval
|
||||
# of records --echo # from the derived table, if !
|
||||
# We use DELETE to disable the JOIN CACHE. This DELETE modifies no
|
||||
# records. It also should leave no InnoDB row locks.
|
||||
#
|
||||
begin;
|
||||
delete t1.* from t1 natural join (select 2 as a, 2 as b union all
|
||||
select 0 as a, 0 as b) as t2;
|
||||
# Demonstrate that nothing was deleted form t1
|
||||
select * from t1;
|
||||
a b
|
||||
1 1
|
||||
2 NULL
|
||||
3 1
|
||||
4 1
|
||||
5 1
|
||||
6 1
|
||||
7 1
|
||||
8 1
|
||||
9 1
|
||||
10 1
|
||||
11 1
|
||||
12 1
|
||||
13 1
|
||||
14 1
|
||||
15 1
|
||||
16 1
|
||||
17 1
|
||||
18 1
|
||||
19 1
|
||||
20 1
|
||||
#
|
||||
# Switching to connection con1
|
||||
begin;
|
||||
# Since there is another distinct record in the derived table
|
||||
# the previous matching record in t1 -- (2,null) -- was unlocked.
|
||||
delete from t1;
|
||||
# We will need the contents of the table again.
|
||||
rollback;
|
||||
select * from t1;
|
||||
a b
|
||||
1 1
|
||||
2 NULL
|
||||
3 1
|
||||
4 1
|
||||
5 1
|
||||
6 1
|
||||
7 1
|
||||
8 1
|
||||
9 1
|
||||
10 1
|
||||
11 1
|
||||
12 1
|
||||
13 1
|
||||
14 1
|
||||
15 1
|
||||
16 1
|
||||
17 1
|
||||
18 1
|
||||
19 1
|
||||
20 1
|
||||
commit;
|
||||
#
|
||||
# Switching to connection default
|
||||
rollback;
|
||||
begin;
|
||||
#
|
||||
# Before this patch, we could wrongly unlock a record
|
||||
# that was cached and later used in a join. Demonstrate that
|
||||
# this is no longer the case.
|
||||
# Sic: this test is also order-dependent (i.e. the
|
||||
# the bug would show up only if the first record in the union
|
||||
# is retreived and processed first.
|
||||
#
|
||||
# Verify that JT_EQ_REF is used.
|
||||
explain
|
||||
select 1 from t1 natural join (select 3 as a, 2 as b union all
|
||||
select 3 as a, 1 as b) as t2 for update;
|
||||
id 1
|
||||
select_type PRIMARY
|
||||
table <derived2>
|
||||
type ALL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows 2
|
||||
Extra
|
||||
id 1
|
||||
select_type PRIMARY
|
||||
table t1
|
||||
type eq_ref
|
||||
possible_keys PRIMARY
|
||||
key PRIMARY
|
||||
key_len 4
|
||||
ref t2.a
|
||||
rows 1
|
||||
Extra Using where
|
||||
id 2
|
||||
select_type DERIVED
|
||||
table NULL
|
||||
type NULL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows NULL
|
||||
Extra No tables used
|
||||
id 3
|
||||
select_type UNION
|
||||
table NULL
|
||||
type NULL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows NULL
|
||||
Extra No tables used
|
||||
id NULL
|
||||
select_type UNION RESULT
|
||||
table <union2,3>
|
||||
type ALL
|
||||
possible_keys NULL
|
||||
key NULL
|
||||
key_len NULL
|
||||
ref NULL
|
||||
rows NULL
|
||||
Extra
|
||||
# Lock the record.
|
||||
select 1 from t1 natural join (select 3 as a, 2 as b union all
|
||||
select 3 as a, 1 as b) as t2 for update;
|
||||
1
|
||||
1
|
||||
# Switching to connection con1
|
||||
#
|
||||
# We should not be able to delete record (3,1) from t1,
|
||||
# (previously it was possible).
|
||||
#
|
||||
delete from t1 where a=3;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
# Switching to connection default
|
||||
commit;
|
||||
set @@session.tx_isolation=default;
|
||||
drop table t1;
|
||||
#
|
||||
# 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
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
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
|
||||
|
|
|
@ -753,4 +753,16 @@ b
|
|||
100
|
||||
NULL
|
||||
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
|
||||
|
|
|
@ -14,3 +14,4 @@ query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails spo
|
|||
partition_innodb_builtin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes
|
||||
partition_innodb_plugin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes
|
||||
innodb-autoinc : Bug#48482 2009-11-02 svoj innodb-autoinc.test fails with results difference
|
||||
rpl_killed_ddl : Bug#45520: rpl_killed_ddl fails sporadically in pb2
|
||||
|
|
|
@ -70,6 +70,161 @@ commit;
|
|||
set autocommit=default;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#41756 Strange error messages about locks from InnoDB
|
||||
--echo #
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
--echo # In the default transaction isolation mode, and/or with
|
||||
--echo # innodb_locks_unsafe_for_binlog=OFF, handler::unlock_row()
|
||||
--echo # in InnoDB does nothing.
|
||||
--echo # Thus in order to reproduce the condition that led to the
|
||||
--echo # warning, one needs to relax isolation by either
|
||||
--echo # setting a weaker tx_isolation value, or by turning on
|
||||
--echo # the unsafe replication switch.
|
||||
--echo # For testing purposes, choose to tweak the isolation level,
|
||||
--echo # since it's settable at runtime, unlike
|
||||
--echo # innodb_locks_unsafe_for_binlog, which is
|
||||
--echo # only a command-line switch.
|
||||
--echo #
|
||||
set @@session.tx_isolation="read-committed";
|
||||
|
||||
--echo # Prepare data. We need a table with a unique index,
|
||||
--echo # for join_read_key to be used. The other column
|
||||
--echo # allows to control what passes WHERE clause filter.
|
||||
create table t1 (a int primary key, b int) engine=innodb;
|
||||
--echo # Let's make sure t1 has sufficient amount of rows
|
||||
--echo # to exclude JT_ALL access method when reading it,
|
||||
--echo # i.e. make sure that JT_EQ_REF(a) is always preferred.
|
||||
insert into t1 values (1,1), (2,null), (3,1), (4,1),
|
||||
(5,1), (6,1), (7,1), (8,1), (9,1), (10,1),
|
||||
(11,1), (12,1), (13,1), (14,1), (15,1),
|
||||
(16,1), (17,1), (18,1), (19,1), (20,1);
|
||||
--echo #
|
||||
--echo # Demonstrate that for the SELECT statement
|
||||
--echo # used later in the test JT_EQ_REF access method is used.
|
||||
--echo #
|
||||
--vertical_results
|
||||
explain
|
||||
select 1 from t1 natural join (select 2 as a, 1 as b union all
|
||||
select 2 as a, 2 as b) as t2 for update;
|
||||
--horizontal_results
|
||||
--echo #
|
||||
--echo # Demonstrate that the reported SELECT statement
|
||||
--echo # no longer produces warnings.
|
||||
--echo #
|
||||
select 1 from t1 natural join (select 2 as a, 1 as b union all
|
||||
select 2 as a, 2 as b) as t2 for update;
|
||||
commit;
|
||||
--echo #
|
||||
--echo # Demonstrate that due to lack of inter-sweep "reset" function,
|
||||
--echo # we keep some non-matching records locked, even though we know
|
||||
--echo # we could unlock them.
|
||||
--echo # To do that, show that if there is only one distinct value
|
||||
--echo # for a in t2 (a=2), we will keep record (2,null) in t1 locked.
|
||||
--echo # But if we add another value for "a" to t2, say 6,
|
||||
--echo # join_read_key cache will be pruned at least once,
|
||||
--echo # and thus record (2, null) in t1 will get unlocked.
|
||||
--echo #
|
||||
begin;
|
||||
select 1 from t1 natural join (select 2 as a, 1 as b union all
|
||||
select 2 as a, 2 as b) as t2 for update;
|
||||
connect (con1,localhost,root,,);
|
||||
--echo #
|
||||
--echo # Switching to connection con1
|
||||
connection con1;
|
||||
--echo # We should be able to delete all records from t1 except (2, null),
|
||||
--echo # since they were not locked.
|
||||
begin;
|
||||
--echo # Delete in series of 3 records so that full scan
|
||||
--echo # is not used and we're not blocked on record (2,null)
|
||||
delete from t1 where a in (1,3,4);
|
||||
delete from t1 where a in (5,6,7);
|
||||
delete from t1 where a in (8,9,10);
|
||||
delete from t1 where a in (11,12,13);
|
||||
delete from t1 where a in (14,15,16);
|
||||
delete from t1 where a in (17,18);
|
||||
delete from t1 where a in (19,20);
|
||||
--echo #
|
||||
--echo # Record (2, null) is locked. This is actually unnecessary,
|
||||
--echo # because the previous select returned no rows.
|
||||
--echo # Just demonstrate the effect.
|
||||
--echo #
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
delete from t1;
|
||||
rollback;
|
||||
--echo #
|
||||
--echo # Switching to connection default
|
||||
connection default;
|
||||
--echo #
|
||||
--echo # Show that the original contents of t1 is intact:
|
||||
select * from t1;
|
||||
commit;
|
||||
--echo #
|
||||
--echo # Have a one more record in t2 to show that
|
||||
--echo # if join_read_key cache is purned, the current
|
||||
--echo # row under the cursor is unlocked (provided, this row didn't
|
||||
--echo # match the partial WHERE clause, of course).
|
||||
--echo # Sic: the result of this test dependent on the order of retrieval
|
||||
--echo # of records --echo # from the derived table, if !
|
||||
--echo # We use DELETE to disable the JOIN CACHE. This DELETE modifies no
|
||||
--echo # records. It also should leave no InnoDB row locks.
|
||||
--echo #
|
||||
begin;
|
||||
delete t1.* from t1 natural join (select 2 as a, 2 as b union all
|
||||
select 0 as a, 0 as b) as t2;
|
||||
--echo # Demonstrate that nothing was deleted form t1
|
||||
select * from t1;
|
||||
--echo #
|
||||
--echo # Switching to connection con1
|
||||
connection con1;
|
||||
begin;
|
||||
--echo # Since there is another distinct record in the derived table
|
||||
--echo # the previous matching record in t1 -- (2,null) -- was unlocked.
|
||||
delete from t1;
|
||||
--echo # We will need the contents of the table again.
|
||||
rollback;
|
||||
select * from t1;
|
||||
commit;
|
||||
--echo #
|
||||
--echo # Switching to connection default
|
||||
connection default;
|
||||
rollback;
|
||||
begin;
|
||||
--echo #
|
||||
--echo # Before this patch, we could wrongly unlock a record
|
||||
--echo # that was cached and later used in a join. Demonstrate that
|
||||
--echo # this is no longer the case.
|
||||
--echo # Sic: this test is also order-dependent (i.e. the
|
||||
--echo # the bug would show up only if the first record in the union
|
||||
--echo # is retreived and processed first.
|
||||
--echo #
|
||||
--echo # Verify that JT_EQ_REF is used.
|
||||
--vertical_results
|
||||
explain
|
||||
select 1 from t1 natural join (select 3 as a, 2 as b union all
|
||||
select 3 as a, 1 as b) as t2 for update;
|
||||
--horizontal_results
|
||||
--echo # Lock the record.
|
||||
select 1 from t1 natural join (select 3 as a, 2 as b union all
|
||||
select 3 as a, 1 as b) as t2 for update;
|
||||
--echo # Switching to connection con1
|
||||
connection con1;
|
||||
--echo #
|
||||
--echo # We should not be able to delete record (3,1) from t1,
|
||||
--echo # (previously it was possible).
|
||||
--echo #
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
delete from t1 where a=3;
|
||||
--echo # Switching to connection default
|
||||
connection default;
|
||||
commit;
|
||||
|
||||
disconnect con1;
|
||||
set @@session.tx_isolation=default;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 5.1 tests
|
||||
--echo #
|
||||
|
|
|
@ -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';
|
||||
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
|
||||
|
|
|
@ -390,4 +390,17 @@ SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
|
|||
|
||||
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
|
||||
|
|
|
@ -17,17 +17,42 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
use Fcntl;
|
||||
use File::Spec;
|
||||
use if $^O eq 'MSWin32', 'Term::ReadKey' => qw/ReadMode/;
|
||||
use strict;
|
||||
|
||||
my $config = ".my.cnf.$$";
|
||||
my $command = ".mysql.$$";
|
||||
my $hadpass = 0;
|
||||
|
||||
# FIXME
|
||||
# trap "interrupt" 2
|
||||
|
||||
my $mysql; # How to call the mysql client
|
||||
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 {
|
||||
if ($^O eq 'MSWin32') {
|
||||
ReadMode('normal');
|
||||
|
@ -55,6 +80,25 @@ sub write_file {
|
|||
}
|
||||
|
||||
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 ) {
|
||||
next if -f $file; # Already exists
|
||||
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 {
|
||||
my $query = shift;
|
||||
write_file($command, $query);
|
||||
system("mysql --defaults-file=$config < $command");
|
||||
return $?;
|
||||
my $rv = system("$mysql --defaults-file=$config < $command");
|
||||
# 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 {
|
||||
my $password = shift;
|
||||
|
||||
my $esc_pass = basic_single_escape($rootpass);
|
||||
write_file($config,
|
||||
"# mysql_secure_installation config file",
|
||||
"[mysql]",
|
||||
"user=root",
|
||||
"password=$rootpass");
|
||||
"password='$esc_pass'");
|
||||
}
|
||||
|
||||
sub get_root_password {
|
||||
my $status = 1;
|
||||
while ( $status == 1 ) {
|
||||
echo_off();
|
||||
print "Enter current password for root (enter for none): ";
|
||||
my $password = <STDIN>;
|
||||
echo_on();
|
||||
my $attempts = 3;
|
||||
for (;;) {
|
||||
my $password = read_without_echo("Enter current password for root (enter for none): ");
|
||||
if ( $password ) {
|
||||
$hadpass = 1;
|
||||
} else {
|
||||
|
@ -95,64 +159,56 @@ sub get_root_password {
|
|||
}
|
||||
$rootpass = $password;
|
||||
make_config($rootpass);
|
||||
do_query("");
|
||||
$status = $?;
|
||||
last if do_query("");
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
sub set_root_password {
|
||||
echo_off();
|
||||
print "New password: ";
|
||||
my $password1 = <STDIN>;
|
||||
print "\nRe-enter new password: ";
|
||||
my $password2 = <STDIN>;
|
||||
print "\n";
|
||||
echo_on();
|
||||
my $password1;
|
||||
for (;;) {
|
||||
$password1 = read_without_echo("New password: ");
|
||||
|
||||
if ( $password1 eq $password2 ) {
|
||||
print "Sorry, passwords do not match.\n\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
if ( !$password1 ) {
|
||||
print "Sorry, you can't use an empty password here.\n\n";
|
||||
next;
|
||||
}
|
||||
print "\n";
|
||||
$rootpass = $password1;
|
||||
make_config($rootpass);
|
||||
} else {
|
||||
print "Password update failed!\n";
|
||||
exit 1;
|
||||
|
||||
my $password2 = read_without_echo("Re-enter new password: ");
|
||||
|
||||
if ( $password1 ne $password2 ) {
|
||||
print "Sorry, passwords do not match.\n\n";
|
||||
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 {
|
||||
do_query("DELETE FROM mysql.user WHERE User='';");
|
||||
if ( $? == 0 ) {
|
||||
print " ... Success!\n";
|
||||
} else {
|
||||
print " ... Failed!\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
do_query("DELETE FROM mysql.user WHERE User='';")
|
||||
or die print " ... Failed!\n";
|
||||
print " ... Success!\n";
|
||||
}
|
||||
|
||||
sub remove_remote_root {
|
||||
do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';");
|
||||
if ( $? == 0 ) {
|
||||
if (do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';")) {
|
||||
print " ... Success!\n";
|
||||
} else {
|
||||
print " ... Failed!\n";
|
||||
|
@ -161,44 +217,31 @@ sub remove_remote_root {
|
|||
|
||||
sub remove_test_database {
|
||||
print " - Dropping test database...\n";
|
||||
do_query("DROP DATABASE test;");
|
||||
if ( $? == 0 ) {
|
||||
if (do_query("DROP DATABASE test;")) {
|
||||
print " ... Success!\n";
|
||||
} else {
|
||||
print " ... Failed! Not critical, keep moving...\n";
|
||||
}
|
||||
|
||||
print " - Removing privileges on test database...\n";
|
||||
do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'");
|
||||
if ( $? == 0 ) {
|
||||
if (do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'")) {
|
||||
print " ... Success!\n";
|
||||
} else {
|
||||
print " ... Failed! Not critical, keep moving...\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub reload_privilege_tables {
|
||||
do_query("FLUSH PRIVILEGES;");
|
||||
if ( $? == 0 ) {
|
||||
if (do_query("FLUSH PRIVILEGES;")) {
|
||||
print " ... Success!\n";
|
||||
return 0;
|
||||
return 1;
|
||||
} else {
|
||||
print " ... Failed!\n";
|
||||
return 1;
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub interrupt {
|
||||
print "\nAborting!\n\n";
|
||||
cleanup();
|
||||
echo_on();
|
||||
exit 1;
|
||||
}
|
||||
|
||||
sub cleanup {
|
||||
print "Cleaning up...\n";
|
||||
unlink($config,$command);
|
||||
}
|
||||
|
||||
|
@ -242,11 +285,7 @@ my $reply = <STDIN>;
|
|||
if ( $reply =~ /n/i ) {
|
||||
print " ... skipping.\n";
|
||||
} else {
|
||||
my $status = 1;
|
||||
while ( $status == 1 ) {
|
||||
set_root_password();
|
||||
$status = $?;
|
||||
}
|
||||
set_root_password();
|
||||
}
|
||||
print "\n";
|
||||
|
||||
|
@ -334,8 +373,6 @@ if ( $reply =~ /n/i ) {
|
|||
}
|
||||
print "\n";
|
||||
|
||||
cleanup();
|
||||
|
||||
print <<HERE;
|
||||
|
||||
|
||||
|
|
|
@ -38,16 +38,39 @@ prepare() {
|
|||
}
|
||||
|
||||
do_query() {
|
||||
echo $1 >$command
|
||||
echo "$1" >$command
|
||||
#sed 's,^,> ,' < $command # Debugging
|
||||
mysql --defaults-file=$config <$command
|
||||
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() {
|
||||
echo "# mysql_secure_installation config file" >$config
|
||||
echo "[mysql]" >>$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() {
|
||||
|
@ -94,13 +117,12 @@ set_root_password() {
|
|||
return 1
|
||||
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
|
||||
echo "Password updated successfully!"
|
||||
echo "Reloading privilege tables.."
|
||||
if ! reload_privilege_tables; then
|
||||
exit 1
|
||||
fi
|
||||
reload_privilege_tables || exit 1
|
||||
echo
|
||||
rootpass=$password1
|
||||
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)
|
||||
{
|
||||
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:
|
||||
return new Item_cache_int();
|
||||
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)
|
||||
{
|
||||
|
@ -6969,17 +6990,19 @@ void Item_cache::print(String *str, enum_query_type query_type)
|
|||
str->append(')');
|
||||
}
|
||||
|
||||
|
||||
void Item_cache_int::store(Item *item)
|
||||
void Item_cache_int::cache_value()
|
||||
{
|
||||
value= item->val_int_result();
|
||||
null_value= item->null_value;
|
||||
unsigned_flag= item->unsigned_flag;
|
||||
value_cached= TRUE;
|
||||
value= example->val_int_result();
|
||||
null_value= example->null_value;
|
||||
unsigned_flag= example->unsigned_flag;
|
||||
}
|
||||
|
||||
|
||||
void Item_cache_int::store(Item *item, longlong val_arg)
|
||||
{
|
||||
/* An explicit values is given, save it. */
|
||||
value_cached= TRUE;
|
||||
value= val_arg;
|
||||
null_value= item->null_value;
|
||||
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)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
str->set(value, default_charset());
|
||||
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)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
|
||||
return decimal_val;
|
||||
}
|
||||
|
||||
|
||||
void Item_cache_real::store(Item *item)
|
||||
double Item_cache_int::val_real()
|
||||
{
|
||||
value= item->val_result();
|
||||
null_value= item->null_value;
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
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()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
return (longlong) rint(value);
|
||||
}
|
||||
|
||||
|
@ -7019,6 +7072,8 @@ longlong Item_cache_real::val_int()
|
|||
String* Item_cache_real::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
str->set_real(value, decimals, default_charset());
|
||||
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)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
double2my_decimal(E_DEC_FATAL_ERROR, value, 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);
|
||||
if (!(null_value= item->null_value) && val != &decimal_value)
|
||||
value_cached= TRUE;
|
||||
my_decimal *val= example->val_decimal_result(&decimal_value);
|
||||
if (!(null_value= example->null_value) && val != &decimal_value)
|
||||
my_decimal2decimal(val, &decimal_value);
|
||||
}
|
||||
|
||||
|
@ -7043,6 +7101,8 @@ double Item_cache_decimal::val_real()
|
|||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
double res;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
|
||||
return res;
|
||||
}
|
||||
|
@ -7051,6 +7111,8 @@ longlong Item_cache_decimal::val_int()
|
|||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
longlong res;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
|
||||
return res;
|
||||
}
|
||||
|
@ -7058,6 +7120,8 @@ longlong Item_cache_decimal::val_int()
|
|||
String* Item_cache_decimal::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
|
||||
&decimal_value);
|
||||
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)
|
||||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
if (!value_cached)
|
||||
cache_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= item->str_result(&value_buff);
|
||||
if ((null_value= item->null_value))
|
||||
value_cached= TRUE;
|
||||
value_buff.set(buffer, sizeof(buffer), example->collation.collation);
|
||||
value= example->str_result(&value_buff);
|
||||
if ((null_value= example->null_value))
|
||||
value= 0;
|
||||
else if (value != &value_buff)
|
||||
{
|
||||
|
@ -7097,6 +7164,8 @@ double Item_cache_str::val_real()
|
|||
DBUG_ASSERT(fixed == 1);
|
||||
int err_not_used;
|
||||
char *end_not_used;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (value)
|
||||
return my_strntod(value->charset(), (char*) value->ptr(),
|
||||
value->length(), &end_not_used, &err_not_used);
|
||||
|
@ -7108,6 +7177,8 @@ longlong Item_cache_str::val_int()
|
|||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
int err;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (value)
|
||||
return my_strntoll(value->charset(), value->ptr(),
|
||||
value->length(), 10, (char**) 0, &err);
|
||||
|
@ -7115,9 +7186,21 @@ longlong Item_cache_str::val_int()
|
|||
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)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (value)
|
||||
string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
||||
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)
|
||||
{
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
int res= Item_cache::save_in_field(field, no_conversions);
|
||||
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
|
||||
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)
|
||||
{
|
||||
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;
|
||||
item->bring_value();
|
||||
example->bring_value();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
50
sql/item.h
50
sql/item.h
|
@ -1024,7 +1024,11 @@ class sp_head;
|
|||
|
||||
class Item_basic_constant :public Item
|
||||
{
|
||||
table_map used_table_map;
|
||||
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) */
|
||||
void cleanup()
|
||||
{
|
||||
|
@ -2889,15 +2893,25 @@ protected:
|
|||
*/
|
||||
Field *cached_field;
|
||||
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:
|
||||
Item_cache():
|
||||
example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING)
|
||||
Item_cache():
|
||||
example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING),
|
||||
value_cached(0)
|
||||
{
|
||||
fixed= 1;
|
||||
null_value= 1;
|
||||
}
|
||||
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;
|
||||
null_value= 1;
|
||||
|
@ -2917,10 +2931,10 @@ public:
|
|||
cached_field= ((Item_field *)item)->field;
|
||||
return 0;
|
||||
};
|
||||
virtual void store(Item *)= 0;
|
||||
enum Type type() const { return CACHE_ITEM; }
|
||||
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, const Item_result type);
|
||||
table_map used_tables() const { return used_table_map; }
|
||||
virtual void keep_array() {}
|
||||
virtual void print(String *str, enum_query_type query_type);
|
||||
|
@ -2932,6 +2946,8 @@ public:
|
|||
{
|
||||
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:
|
||||
longlong value;
|
||||
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(field_type_arg), value(0) {}
|
||||
|
||||
void store(Item *item);
|
||||
void store(Item *item, longlong val_arg);
|
||||
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
|
||||
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String* val_str(String *str);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return INT_RESULT; }
|
||||
bool result_as_longlong() { return TRUE; }
|
||||
void cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
@ -2959,14 +2976,15 @@ class Item_cache_real: public Item_cache
|
|||
{
|
||||
double value;
|
||||
public:
|
||||
Item_cache_real(): Item_cache(), value(0) {}
|
||||
Item_cache_real(): Item_cache(),
|
||||
value(0) {}
|
||||
|
||||
void store(Item *item);
|
||||
double val_real() { DBUG_ASSERT(fixed == 1); return value; }
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String* val_str(String *str);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return REAL_RESULT; }
|
||||
void cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
@ -2977,12 +2995,12 @@ protected:
|
|||
public:
|
||||
Item_cache_decimal(): Item_cache() {}
|
||||
|
||||
void store(Item *item);
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String* val_str(String *str);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return DECIMAL_RESULT; }
|
||||
void cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
@ -3000,14 +3018,14 @@ public:
|
|||
MYSQL_TYPE_VARCHAR &&
|
||||
!((const Item_field *) item)->field->has_charset())
|
||||
{}
|
||||
void store(Item *item);
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; }
|
||||
String* val_str(String *);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return STRING_RESULT; }
|
||||
CHARSET_INFO *charset() const { return value->charset(); };
|
||||
int save_in_field(Field *field, bool no_conversions);
|
||||
void cache_value();
|
||||
};
|
||||
|
||||
class Item_cache_row: public Item_cache
|
||||
|
@ -3017,7 +3035,8 @@ class Item_cache_row: public Item_cache
|
|||
bool save_array;
|
||||
public:
|
||||
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
|
||||
|
@ -3075,6 +3094,7 @@ public:
|
|||
values= 0;
|
||||
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)
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
/*
|
||||
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.
|
||||
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 ||
|
||||
((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
ulonglong value;
|
||||
bool error;
|
||||
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;
|
||||
ulonglong const_value= (ulonglong)-1;
|
||||
thd= current_thd;
|
||||
owner= owner_arg;
|
||||
a= a1;
|
||||
b= a2;
|
||||
|
||||
if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
|
||||
{
|
||||
thd= current_thd;
|
||||
owner= owner_arg;
|
||||
a_type= (*a)->field_type();
|
||||
b_type= (*b)->field_type();
|
||||
a_cache= 0;
|
||||
|
@ -895,6 +901,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||
|
||||
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();
|
||||
/* Mark the cache as non-const to prevent re-caching. */
|
||||
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)
|
||||
{
|
||||
/* Compare TIME values as integers. */
|
||||
thd= current_thd;
|
||||
owner= owner_arg;
|
||||
a_cache= 0;
|
||||
b_cache= 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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)
|
||||
{
|
||||
thd= current_thd;
|
||||
|
@ -1582,6 +1626,7 @@ longlong Item_in_optimizer::val_int()
|
|||
bool tmp;
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
cache->store(args[0]);
|
||||
cache->cache_value();
|
||||
|
||||
if (cache->null_value)
|
||||
{
|
||||
|
|
|
@ -94,6 +94,8 @@ public:
|
|||
ulonglong *const_val_arg);
|
||||
|
||||
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];
|
||||
|
||||
friend class Item_func;
|
||||
|
|
|
@ -480,6 +480,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
|
|||
void Item_singlerow_subselect::store(uint i, Item *item)
|
||||
{
|
||||
row[i]->store(item);
|
||||
row[i]->cache_value();
|
||||
}
|
||||
|
||||
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)))
|
||||
return;
|
||||
row[i]->setup(sel_item);
|
||||
row[i]->store(sel_item);
|
||||
}
|
||||
if (item_list.elements > 1)
|
||||
res_type= ROW_RESULT;
|
||||
|
@ -1954,6 +1956,7 @@ int subselect_single_select_engine::exec()
|
|||
tab->read_record.record= tab->table->record[0];
|
||||
tab->read_record.thd= join->thd;
|
||||
tab->read_record.ref_length= tab->table->file->ref_length;
|
||||
tab->read_record.unlock_row= rr_unlock_row;
|
||||
*(last_changed_tab++)= tab;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -941,14 +941,16 @@ static Item *create_comparator(MY_XPATH *xpath,
|
|||
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 *scalar, *comp;
|
||||
if (a->type() == Item::XPATH_NODESET)
|
||||
{
|
||||
nodeset= (Item_nodeset_func*) a;
|
||||
scalar= b;
|
||||
comp= eq_func(oper, fake, scalar);
|
||||
comp= eq_func(oper, (Item*)fake, scalar);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -3888,6 +3888,27 @@ server.");
|
|||
|
||||
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];
|
||||
const char *ln;
|
||||
ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf);
|
||||
|
|
|
@ -62,6 +62,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
|
|||
info->file= table->file;
|
||||
info->record= table->record[0];
|
||||
info->print_error= print_error;
|
||||
info->unlock_row= rr_unlock_row;
|
||||
|
||||
table->status=0; /* And it's always found */
|
||||
if (!table->file->inited)
|
||||
|
@ -187,6 +188,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
|
|||
}
|
||||
info->select=select;
|
||||
info->print_error=print_error;
|
||||
info->unlock_row= rr_unlock_row;
|
||||
info->ignore_not_found_rows= 0;
|
||||
table->status=0; /* And it's always found */
|
||||
|
||||
|
|
|
@ -132,6 +132,29 @@ int init_relay_log_info(Relay_log_info* rli,
|
|||
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];
|
||||
const char *ln;
|
||||
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]->cache_value();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
|
|||
static int join_read_system(JOIN_TAB *tab);
|
||||
static int join_read_const(JOIN_TAB *tab);
|
||||
static int join_read_key(JOIN_TAB *tab);
|
||||
static void join_read_key_unlock_row(st_join_table *tab);
|
||||
static int join_read_always_key(JOIN_TAB *tab);
|
||||
static int join_read_last_key(JOIN_TAB *tab);
|
||||
static int join_no_more_records(READ_RECORD *info);
|
||||
|
@ -981,14 +982,20 @@ JOIN::optimize()
|
|||
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"));
|
||||
DBUG_RETURN(1);
|
||||
if (rollup_process_const_fields())
|
||||
{
|
||||
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");
|
||||
if (result->initialize_tables(this))
|
||||
{
|
||||
|
@ -1287,11 +1294,14 @@ JOIN::optimize()
|
|||
- 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
|
||||
- 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) ||
|
||||
(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
|
||||
make_join_readinfo(this,
|
||||
|
@ -5628,7 +5638,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||
}
|
||||
j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
|
||||
j->ref.key_err=1;
|
||||
j->ref.has_record= FALSE;
|
||||
j->ref.null_rejecting= 0;
|
||||
j->ref.use_count= 0;
|
||||
keyuse=org_keyuse;
|
||||
|
||||
store_key **ref_key= j->ref.key_copy;
|
||||
|
@ -6461,6 +6473,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The default implementation of unlock-row method of READ_RECORD,
|
||||
used in all access methods.
|
||||
*/
|
||||
|
||||
void rr_unlock_row(st_join_table *tab)
|
||||
{
|
||||
READ_RECORD *info= &tab->read_record;
|
||||
info->file->unlock_row();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
make_join_readinfo(JOIN *join, ulonglong options)
|
||||
{
|
||||
|
@ -6476,6 +6502,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
|
|||
TABLE *table=tab->table;
|
||||
tab->read_record.table= table;
|
||||
tab->read_record.file=table->file;
|
||||
tab->read_record.unlock_row= rr_unlock_row;
|
||||
tab->next_select=sub_select; /* normal select */
|
||||
|
||||
/*
|
||||
|
@ -6521,6 +6548,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
|
|||
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.read_record= join_no_more_records;
|
||||
if (table->covering_keys.is_set(tab->ref.key) &&
|
||||
!table->no_keyread)
|
||||
|
@ -11357,7 +11385,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
|
|||
return NESTED_LOOP_NO_MORE_ROWS;
|
||||
}
|
||||
else
|
||||
join_tab->read_record.file->unlock_row();
|
||||
join_tab->read_record.unlock_row(join_tab);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -11367,7 +11395,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
|
|||
*/
|
||||
join->examined_rows++;
|
||||
join->thd->row_count++;
|
||||
join_tab->read_record.file->unlock_row();
|
||||
join_tab->read_record.unlock_row(join_tab);
|
||||
}
|
||||
return NESTED_LOOP_OK;
|
||||
}
|
||||
|
@ -11727,18 +11755,55 @@ join_read_key(JOIN_TAB *tab)
|
|||
table->status=STATUS_NOT_FOUND;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
Moving away from the current record. Unlock the row
|
||||
in the handler if it did not match the partial WHERE.
|
||||
*/
|
||||
if (tab->ref.has_record && tab->ref.use_count == 0)
|
||||
{
|
||||
tab->read_record.file->unlock_row();
|
||||
tab->ref.has_record= FALSE;
|
||||
}
|
||||
error=table->file->index_read_map(table->record[0],
|
||||
tab->ref.key_buff,
|
||||
make_prev_keypart_map(tab->ref.key_parts),
|
||||
HA_READ_KEY_EXACT);
|
||||
if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
|
||||
return report_error(table, error);
|
||||
|
||||
if (! error)
|
||||
{
|
||||
tab->ref.has_record= TRUE;
|
||||
tab->ref.use_count= 1;
|
||||
}
|
||||
}
|
||||
else if (table->status == 0)
|
||||
{
|
||||
DBUG_ASSERT(tab->ref.has_record);
|
||||
tab->ref.use_count++;
|
||||
}
|
||||
table->null_row=0;
|
||||
return table->status ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Since join_read_key may buffer a record, do not unlock
|
||||
it if it was not used in this invocation of join_read_key().
|
||||
Only count locks, thus remembering if the record was left unused,
|
||||
and unlock already when pruning the current value of
|
||||
TABLE_REF buffer.
|
||||
@sa join_read_key()
|
||||
*/
|
||||
|
||||
static void
|
||||
join_read_key_unlock_row(st_join_table *tab)
|
||||
{
|
||||
DBUG_ASSERT(tab->ref.use_count);
|
||||
if (tab->ref.use_count)
|
||||
tab->ref.use_count--;
|
||||
}
|
||||
|
||||
/*
|
||||
ref access method implementation: "read_first" function
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ class store_key;
|
|||
typedef struct st_table_ref
|
||||
{
|
||||
bool key_err;
|
||||
/** True if something was read into buffer in join_read_key. */
|
||||
bool has_record;
|
||||
uint key_parts; ///< num of ...
|
||||
uint key_length; ///< length of key_buff
|
||||
int key; ///< key no
|
||||
|
@ -85,6 +87,11 @@ typedef struct st_table_ref
|
|||
table_map depend_map; ///< Table depends on these tables.
|
||||
/* null byte position in the key_buf. Used for REF_OR_NULL optimization */
|
||||
uchar *null_ref_key;
|
||||
/*
|
||||
The number of times the record associated with this key was used
|
||||
in the join.
|
||||
*/
|
||||
ha_rows use_count;
|
||||
} TABLE_REF;
|
||||
|
||||
|
||||
|
|
|
@ -115,16 +115,22 @@ typedef struct st_reginfo { /* Extra info about reg */
|
|||
} REGINFO;
|
||||
|
||||
|
||||
struct st_read_record; /* For referense later */
|
||||
class SQL_SELECT;
|
||||
class THD;
|
||||
class handler;
|
||||
struct st_join_table;
|
||||
|
||||
typedef struct st_read_record { /* Parameter to read_record */
|
||||
void rr_unlock_row(st_join_table *tab);
|
||||
|
||||
struct READ_RECORD { /* Parameter to read_record */
|
||||
typedef int (*Read_func)(READ_RECORD*);
|
||||
typedef void (*Unlock_row_func)(st_join_table *);
|
||||
struct st_table *table; /* Head-form */
|
||||
handler *file;
|
||||
struct st_table **forms; /* head and ref forms */
|
||||
int (*read_record)(struct st_read_record *);
|
||||
|
||||
Read_func read_record;
|
||||
Unlock_row_func unlock_row;
|
||||
THD *thd;
|
||||
SQL_SELECT *select;
|
||||
uint cache_records;
|
||||
|
@ -136,7 +142,7 @@ typedef struct st_read_record { /* Parameter to read_record */
|
|||
uchar *cache,*cache_pos,*cache_end,*read_positions;
|
||||
IO_CACHE *io_cache;
|
||||
bool print_error, ignore_not_found_rows;
|
||||
} READ_RECORD;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue