Commit df5c5aea authored by malff/marcsql@weblab.(none)'s avatar malff/marcsql@weblab.(none)

Merge weblab.(none):/home/marcsql/TREE/mysql-5.0-base

into  weblab.(none):/home/marcsql/TREE/mysql-5.0-rt-merge
parents 2f5a2b24 7d98fb7e
......@@ -3012,6 +3012,7 @@ language = $path_language
character-sets-dir = $path_charsetsdir
basedir = $path_my_basedir
server_id = $server_id
shutdown-delay = 10
skip-stack-trace
skip-innodb
skip-ndbcluster
......
......@@ -128,3 +128,6 @@ f1 f2 if(f1, 40.0, 5.00)
0 0 5.00
1 1 40.00
drop table t1;
select if(0, 18446744073709551610, 18446744073709551610);
if(0, 18446744073709551610, 18446744073709551610)
18446744073709551610
......@@ -21,6 +21,6 @@ Success: the process was restarted.
Success: server is ready to accept connection on socket.
SHOW INSTANCE STATUS mysqld1;
instance_name status version
mysqld1 online VERSION
mysqld1 STATE VERSION
STOP INSTANCE mysqld2;
Success: the process has been stopped.
INSERT INTO init_file.startup VALUES ( NOW() );
SELECT * INTO @X FROM init_file.startup limit 0,1;
SELECT * INTO @Y FROM init_file.startup limit 1,1;
SELECT YEAR(@X)-YEAR(@Y);
YEAR(@X)-YEAR(@Y)
0
DROP DATABASE init_file;
ok
end of 4.1 tests
select * from t1;
......
......@@ -431,17 +431,17 @@ SELECT HEX(v10);
END|
CALL p1();
HEX(v1)
01
1
HEX(v2)
00
0
HEX(v3)
05
5
HEX(v4)
5555555555555555
HEX(v5)
07
7
HEX(v6)
0000000000000005
5
HEX(v7)
80
HEX(v8)
......@@ -748,12 +748,60 @@ HEX(b) b = 0 b = FALSE b IS FALSE b = 1 b = TRUE b IS TRUE
1 0 0 0 1 1 1
call p2();
HEX(vb) vb = 0 vb = FALSE vb IS FALSE vb = 1 vb = TRUE vb IS TRUE
00 1 1 1 0 0 0
0 1 1 1 0 0 0
HEX(vb) vb = 0 vb = FALSE vb IS FALSE vb = 1 vb = TRUE vb IS TRUE
01 0 0 1 1 1 0
1 0 0 0 1 1 1
DROP TABLE t1;
DROP PROCEDURE p1;
DROP PROCEDURE p2;
DROP TABLE IF EXISTS table_12976_a;
DROP TABLE IF EXISTS table_12976_b;
DROP PROCEDURE IF EXISTS proc_12976_a;
DROP PROCEDURE IF EXISTS proc_12976_b;
CREATE TABLE table_12976_a (val bit(1));
CREATE TABLE table_12976_b(
appname varchar(15),
emailperm bit not null default 1,
phoneperm bit not null default 0);
insert into table_12976_b values ('A', b'1', b'1'), ('B', b'0', b'0');
CREATE PROCEDURE proc_12976_a()
BEGIN
declare localvar bit(1);
SELECT val INTO localvar FROM table_12976_a;
SELECT coalesce(localvar, 1)+1, coalesce(val, 1)+1 FROM table_12976_a;
END||
CREATE PROCEDURE proc_12976_b(
name varchar(15),
out ep bit,
out msg varchar(10))
BEGIN
SELECT emailperm into ep FROM table_12976_b where (appname = name);
IF ep is true THEN
SET msg = 'True';
ELSE
SET msg = 'False';
END IF;
END||
INSERT table_12976_a VALUES (0);
call proc_12976_a();
coalesce(localvar, 1)+1 coalesce(val, 1)+1
1 1
UPDATE table_12976_a set val=1;
call proc_12976_a();
coalesce(localvar, 1)+1 coalesce(val, 1)+1
2 2
call proc_12976_b('A', @ep, @msg);
select @ep, @msg;
@ep @msg
1 True
call proc_12976_b('B', @ep, @msg);
select @ep, @msg;
@ep @msg
0 False
DROP TABLE table_12976_a;
DROP TABLE table_12976_b;
DROP PROCEDURE proc_12976_a;
DROP PROCEDURE proc_12976_b;
---------------------------------------------------------------
BUG#9572
......
This diff is collapsed.
......@@ -834,14 +834,16 @@ show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 99999999999999999999999999999999999999999999999999999 AS `col1`
drop view v1;
create table t (c char);
create view v as select c from t;
insert into v values ('');
select * from v;
c
drop view v;
drop table t;
set names utf8;
create table tü (cü char);
create view vü as select cü from tü;
insert into vü values ('ü');
select * from vü;
ü
drop view vü;
drop table tü;
set names latin1;
create table t1 (a int, b int);
insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
create view v1(c) as select a+1 from t1 where b >= 4;
......@@ -3035,7 +3037,7 @@ View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select _latin1'The\ZEnd' AS `TheEnd`
DROP VIEW v1;
CREATE TABLE t1 (mydate DATETIME);
INSERT INTO t1 VALUES
INSERT INTO t1 VALUES
('2007-01-01'), ('2007-01-02'), ('2007-01-30'), ('2007-01-31');
CREATE VIEW v1 AS SELECT mydate from t1;
SELECT * FROM t1 WHERE mydate BETWEEN '2007-01-01' AND '2007-01-31';
......@@ -3135,4 +3137,139 @@ code COUNT(DISTINCT country)
100 2
DROP VIEW v1;
DROP TABLE t1;
DROP VIEW IF EXISTS v1;
SELECT * FROM (SELECT 1) AS t;
1
1
CREATE VIEW v1 AS SELECT * FROM (SELECT 1) AS t;
ERROR HY000: View's SELECT contains a subquery in the FROM clause
# Previously the following would fail.
SELECT * FROM (SELECT 1) AS t;
1
1
drop view if exists view_24532_a;
drop view if exists view_24532_b;
drop table if exists table_24532;
create table table_24532 (
a int,
b bigint,
c int(4),
d bigint(48)
);
create view view_24532_a as
select
a IS TRUE,
a IS NOT TRUE,
a IS FALSE,
a IS NOT FALSE,
a IS UNKNOWN,
a IS NOT UNKNOWN,
a is NULL,
a IS NOT NULL,
ISNULL(a),
b IS TRUE,
b IS NOT TRUE,
b IS FALSE,
b IS NOT FALSE,
b IS UNKNOWN,
b IS NOT UNKNOWN,
b is NULL,
b IS NOT NULL,
ISNULL(b),
c IS TRUE,
c IS NOT TRUE,
c IS FALSE,
c IS NOT FALSE,
c IS UNKNOWN,
c IS NOT UNKNOWN,
c is NULL,
c IS NOT NULL,
ISNULL(c),
d IS TRUE,
d IS NOT TRUE,
d IS FALSE,
d IS NOT FALSE,
d IS UNKNOWN,
d IS NOT UNKNOWN,
d is NULL,
d IS NOT NULL,
ISNULL(d)
from table_24532;
describe view_24532_a;
Field Type Null Key Default Extra
a IS TRUE int(1) NO 0
a IS NOT TRUE int(1) NO 0
a IS FALSE int(1) NO 0
a IS NOT FALSE int(1) NO 0
a IS UNKNOWN int(1) NO 0
a IS NOT UNKNOWN int(1) NO 0
a is NULL int(1) NO 0
a IS NOT NULL int(1) NO 0
ISNULL(a) int(1) NO 0
b IS TRUE int(1) NO 0
b IS NOT TRUE int(1) NO 0
b IS FALSE int(1) NO 0
b IS NOT FALSE int(1) NO 0
b IS UNKNOWN int(1) NO 0
b IS NOT UNKNOWN int(1) NO 0
b is NULL int(1) NO 0
b IS NOT NULL int(1) NO 0
ISNULL(b) int(1) NO 0
c IS TRUE int(1) NO 0
c IS NOT TRUE int(1) NO 0
c IS FALSE int(1) NO 0
c IS NOT FALSE int(1) NO 0
c IS UNKNOWN int(1) NO 0
c IS NOT UNKNOWN int(1) NO 0
c is NULL int(1) NO 0
c IS NOT NULL int(1) NO 0
ISNULL(c) int(1) NO 0
d IS TRUE int(1) NO 0
d IS NOT TRUE int(1) NO 0
d IS FALSE int(1) NO 0
d IS NOT FALSE int(1) NO 0
d IS UNKNOWN int(1) NO 0
d IS NOT UNKNOWN int(1) NO 0
d is NULL int(1) NO 0
d IS NOT NULL int(1) NO 0
ISNULL(d) int(1) NO 0
create view view_24532_b as
select
a IS TRUE,
if(ifnull(a, 0), 1, 0) as old_istrue,
a IS NOT TRUE,
if(ifnull(a, 0), 0, 1) as old_isnottrue,
a IS FALSE,
if(ifnull(a, 1), 0, 1) as old_isfalse,
a IS NOT FALSE,
if(ifnull(a, 1), 1, 0) as old_isnotfalse
from table_24532;
describe view_24532_b;
Field Type Null Key Default Extra
a IS TRUE int(1) NO 0
old_istrue int(1) NO 0
a IS NOT TRUE int(1) NO 0
old_isnottrue int(1) NO 0
a IS FALSE int(1) NO 0
old_isfalse int(1) NO 0
a IS NOT FALSE int(1) NO 0
old_isnotfalse int(1) NO 0
show create view view_24532_b;
View Create View
view_24532_b CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `view_24532_b` AS select (`table_24532`.`a` is true) AS `a IS TRUE`,if(ifnull(`table_24532`.`a`,0),1,0) AS `old_istrue`,(`table_24532`.`a` is not true) AS `a IS NOT TRUE`,if(ifnull(`table_24532`.`a`,0),0,1) AS `old_isnottrue`,(`table_24532`.`a` is false) AS `a IS FALSE`,if(ifnull(`table_24532`.`a`,1),0,1) AS `old_isfalse`,(`table_24532`.`a` is not false) AS `a IS NOT FALSE`,if(ifnull(`table_24532`.`a`,1),1,0) AS `old_isnotfalse` from `table_24532`
insert into table_24532 values (0, 0, 0, 0);
select * from view_24532_b;
a IS TRUE old_istrue a IS NOT TRUE old_isnottrue a IS FALSE old_isfalse a IS NOT FALSE old_isnotfalse
0 0 1 1 1 1 0 0
update table_24532 set a=1;
select * from view_24532_b;
a IS TRUE old_istrue a IS NOT TRUE old_isnottrue a IS FALSE old_isfalse a IS NOT FALSE old_isnotfalse
1 1 0 0 0 0 1 1
update table_24532 set a=NULL;
select * from view_24532_b;
a IS TRUE old_istrue a IS NOT TRUE old_isnottrue a IS FALSE old_isfalse a IS NOT FALSE old_isnotfalse
0 0 1 1 0 0 1 1
drop view view_24532_a;
drop view view_24532_b;
drop table table_24532;
End of 5.0 tests.
......@@ -27,3 +27,12 @@ insert into t2 values (11), (13);
drop procedure p1;
drop function f1;
drop view v1;
#
# Bug#23240 --init-file statements with NOW() reports '1970-01-01 11:00:00'as the date time
#
CREATE DATABASE IF NOT EXISTS init_file;
CREATE TABLE IF NOT EXISTS init_file.startup ( startdate DATETIME );
INSERT INTO init_file.startup VALUES ( NOW() );
......@@ -10,6 +10,5 @@
#
##############################################################################
im_daemon_life_cycle : Bug#24415 see note: [19 Dec 23:17] Trudy Pelzer
ndb_load : Bug#17233
user_limits : Bug#23921 random failure of user_limits.test
......@@ -97,3 +97,14 @@ create table t1 (f1 int, f2 int);
insert into t1 values(1,1),(0,0);
select f1, f2, if(f1, 40.0, 5.00) from t1 group by f1 order by f2;
drop table t1;
#
# Bug#24532 (The return data type of IS TRUE is different from similar
# operations)
#
# IF(x, unsigned, unsigned) should be unsigned.
#
select if(0, 18446744073709551610, 18446744073709551610);
......@@ -23,15 +23,20 @@
# - wait for IM-main to start accepting connections before continue test
# case;
#
# NOTE: timeout is 55 seconds. Timeout should be more than shutdown-delay
# specified for managed MySQL instance. Now shutdown-delay is 10 seconds
# (set in mysql-test-run.pl). So, 55 seconds should be enough to make 5
# attempts.
#
###########################################################################
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Main-test: starting...
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Killing IM-main...
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 55 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Waiting for IM-main to start accepting connections...
--exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 30 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 55 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Main-test: done.
......@@ -58,23 +63,23 @@
START INSTANCE mysqld2;
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: waiting to start...
--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 55 started im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: started.
# 2. Restart IM-main;
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Killing IM-main...
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 55 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Waiting for IM-main to start accepting connections...
--exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 30 im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 55 im_daemon_life_cycle
# 3. Issue some statement -- connection should be re-established.
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Checking that IM-main processing commands...
--replace_column 3 VERSION
--replace_column 2 STATE 3 VERSION
SHOW INSTANCE STATUS mysqld1;
# 4. Stop mysqld2, because it will not be stopped by IM, as it is nonguarded.
......@@ -85,7 +90,7 @@ SHOW INSTANCE STATUS mysqld1;
STOP INSTANCE mysqld2;
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: waiting to stop...
--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 55 stopped im_daemon_life_cycle
--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: stopped.
###########################################################################
......
......@@ -6,6 +6,15 @@
# mysql-test/t/init_file-master.opt for the actual test
#
#
# Bug#23240 --init-file statements with NOW() reports '1970-01-01 11:00:00'as the date time
#
INSERT INTO init_file.startup VALUES ( NOW() );
SELECT * INTO @X FROM init_file.startup limit 0,1;
SELECT * INTO @Y FROM init_file.startup limit 1,1;
SELECT YEAR(@X)-YEAR(@Y);
DROP DATABASE init_file;
--echo ok
--echo end of 4.1 tests
#
......
......@@ -53,7 +53,7 @@ pid_path="$1"
expected_result="$2"
total_timeout="$3"
test_id="$4"
log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
log_file="$MYSQLTEST_VARDIR/log/$test_id.script.log"
log_debug "-- $basename: starting --"
log_debug "pid_path: '$pid_path'"
......
......@@ -17,7 +17,7 @@ if [ $# -lt 2 ]; then
fi
test_id="$1"
log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
log_file="$MYSQLTEST_VARDIR/log/$test_id.script.log"
shift
......
......@@ -500,8 +500,6 @@ DROP PROCEDURE p1;
#
# Test case for BUG#12976: Boolean values reversed in stored procedures?
#
# TODO: test case failed.
#
###########################################################################
--echo
......@@ -566,13 +564,8 @@ BEGIN
END|
delimiter ;|
# The expected and correct result.
call p1();
# The wrong result. Note that only hex(vb) works, but is printed with two
# digits for some reason in this case.
call p2();
#
......@@ -583,6 +576,64 @@ DROP TABLE t1;
DROP PROCEDURE p1;
DROP PROCEDURE p2;
# Additional tests for Bug#12976
--disable_warnings
DROP TABLE IF EXISTS table_12976_a;
DROP TABLE IF EXISTS table_12976_b;
DROP PROCEDURE IF EXISTS proc_12976_a;
DROP PROCEDURE IF EXISTS proc_12976_b;
--enable_warnings
CREATE TABLE table_12976_a (val bit(1));
CREATE TABLE table_12976_b(
appname varchar(15),
emailperm bit not null default 1,
phoneperm bit not null default 0);
insert into table_12976_b values ('A', b'1', b'1'), ('B', b'0', b'0');
delimiter ||;
CREATE PROCEDURE proc_12976_a()
BEGIN
declare localvar bit(1);
SELECT val INTO localvar FROM table_12976_a;
SELECT coalesce(localvar, 1)+1, coalesce(val, 1)+1 FROM table_12976_a;
END||
CREATE PROCEDURE proc_12976_b(
name varchar(15),
out ep bit,
out msg varchar(10))
BEGIN
SELECT emailperm into ep FROM table_12976_b where (appname = name);
IF ep is true THEN
SET msg = 'True';
ELSE
SET msg = 'False';
END IF;
END||
delimiter ;||
INSERT table_12976_a VALUES (0);
call proc_12976_a();
UPDATE table_12976_a set val=1;
call proc_12976_a();
call proc_12976_b('A', @ep, @msg);
select @ep, @msg;
call proc_12976_b('B', @ep, @msg);
select @ep, @msg;
DROP TABLE table_12976_a;
DROP TABLE table_12976_b;
DROP PROCEDURE proc_12976_a;
DROP PROCEDURE proc_12976_b;
###########################################################################
#
# Test case for BUG#9572: Stored procedures: variable type declarations
......
......@@ -2002,7 +2002,7 @@ EXPLAIN SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL;
DROP TABLE t1;
#
# Bug 24653: sorting by expressions containing subselects
# Bug 24653: sorting by expressions containing subselects
# that return more than one row
#
......@@ -2014,12 +2014,12 @@ INSERT INTO t2 VALUES
(2,1), (1,3), (2,1), (4,4), (2,2), (1,4);
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2 );
--error 1242
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1);
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2), a;
--error 1242
--error 1242
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1);
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2), a;
--error 1242
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1), a;
SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 2);
--error 1242
SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 1);
......@@ -2036,28 +2036,28 @@ SELECT a FROM t1 GROUP BY a
SELECT a FROM t1 GROUP BY a
HAVING IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;
--error 1242
--error 1242
SELECT a FROM t1 GROUP BY a
HAVING IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)) > 3;
SELECT a FROM t1
SELECT a FROM t1
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 2),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b));
--error 1242
SELECT a FROM t1
SELECT a FROM t1
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 1),
(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b));
SELECT a FROM t1
SELECT a FROM t1
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b));
--error 1242
SELECT a FROM t1
SELECT a FROM t1
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b));
DROP TABLE t1,t2;
DROP TABLE t1,t2;
# End of 4.1 tests
......@@ -2571,7 +2571,7 @@ DROP TABLE t1,t2;
#
# Bug #25219: EXIST subquery with UNION over a mix of
# correlated and uncorrelated selects
#
#
CREATE TABLE t1 (id char(4) PRIMARY KEY, c int);
CREATE TABLE t2 (c int);
......@@ -2579,52 +2579,125 @@ CREATE TABLE t2 (c int);
INSERT INTO t1 VALUES ('aa', 1);
INSERT INTO t2 VALUES (1);
SELECT * FROM t1
SELECT * FROM t1
WHERE EXISTS (SELECT c FROM t2 WHERE c=1
UNION
UNION
SELECT c from t2 WHERE c=t1.c);
INSERT INTO t1 VALUES ('bb', 2), ('cc', 3), ('dd',1);
SELECT * FROM t1
SELECT * FROM t1
WHERE EXISTS (SELECT c FROM t2 WHERE c=1
UNION
UNION
SELECT c from t2 WHERE c=t1.c);
INSERT INTO t2 VALUES (2);
CREATE TABLE t3 (c int);
INSERT INTO t3 VALUES (1);
SELECT * FROM t1
SELECT * FROM t1
WHERE EXISTS (SELECT t2.c FROM t2 JOIN t3 ON t2.c=t3.c WHERE t2.c=1
UNION
UNION
SELECT c from t2 WHERE c=t1.c);
DROP TABLE t1,t2,t3;
#
# Bug#23800: Outer fields in correlated subqueries is used in a temporary
# table created for sorting.
#
CREATE TABLE t1(f1 int);
CREATE TABLE t2(f2 int, f21 int, f3 timestamp);
INSERT INTO t1 VALUES (1),(1),(2),(2);
INSERT INTO t2 VALUES (1,1,"2004-02-29 11:11:11"), (2,2,"2004-02-29 11:11:11");
SELECT ((SELECT f2 FROM t2 WHERE f21=f1 LIMIT 1) * COUNT(f1)) AS sq FROM t1 GROUP BY f1;
SELECT (SELECT SUM(1) FROM t2 ttt GROUP BY t2.f3 LIMIT 1) AS tt FROM t2;
PREPARE stmt1 FROM 'SELECT ((SELECT f2 FROM t2 WHERE f21=f1 LIMIT 1) * COUNT(f1)) AS sq FROM t1 GROUP BY f1';
EXECUTE stmt1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SELECT f2, AVG(f21),
(SELECT t.f3 FROM t2 AS t WHERE t2.f2=t.f2 AND t.f3=MAX(t2.f3)) AS test
FROM t2 GROUP BY f2;
DROP TABLE t1,t2;
CREATE TABLE t1 (a int, b INT, c CHAR(10) NOT NULL);
INSERT INTO t1 VALUES
(1,1,'a'), (1,2,'b'), (1,3,'c'), (1,4,'d'), (1,5,'e'),
(2,1,'f'), (2,2,'g'), (2,3,'h'), (3,4,'i'), (3,3,'j'),
(3,2,'k'), (3,1,'l'), (1,9,'m');
SELECT a, MAX(b),
(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b)) AS test
FROM t1 GROUP BY a;
DROP TABLE t1;
DROP TABLE t1,t2,t3;
#
# Bug#21904 (parser problem when using IN with a double "(())")
#
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1xt2;
--enable_warnings
CREATE TABLE t1 (
id_1 int(5) NOT NULL,
t varchar(4) DEFAULT NULL
);
CREATE TABLE t2 (
id_2 int(5) NOT NULL,
t varchar(4) DEFAULT NULL
);
CREATE TABLE t1xt2 (
id_1 int(5) NOT NULL,
id_2 int(5) NOT NULL
);
INSERT INTO t1 VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd');
INSERT INTO t2 VALUES (2, 'bb'), (3, 'cc'), (4, 'dd'), (12, 'aa');
INSERT INTO t1xt2 VALUES (2, 2), (3, 3), (4, 4);
# subselect returns 0 rows
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 where t1.id_1 = t1xt2.id_1)));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 where t1.id_1 = t1xt2.id_1))));
insert INTO t1xt2 VALUES (1, 12);
# subselect returns 1 row
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))));
insert INTO t1xt2 VALUES (2, 12);
# subselect returns more than 1 row
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)));
SELECT DISTINCT t1.id_1 FROM t1 WHERE
(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))));
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t1xt2;
......@@ -748,12 +748,14 @@ drop view v1;
#
# VIEWs with national characters
#
create table t (c char);
create view v as select c from t;
insert into v values ('');
select * from v;
drop view v;
drop table t;
set names utf8;
create table tü (cü char);
create view vü as select cü from tü;
insert into vü values ('ü');
select * from vü;
drop view vü;
drop table tü;
set names latin1;
#
# problem with used_tables() of outer reference resolved in VIEW
......@@ -2991,7 +2993,7 @@ DROP VIEW v1;
#
CREATE TABLE t1 (mydate DATETIME);
INSERT INTO t1 VALUES
INSERT INTO t1 VALUES
('2007-01-01'), ('2007-01-02'), ('2007-01-30'), ('2007-01-31');
CREATE VIEW v1 AS SELECT mydate from t1;
......@@ -3039,7 +3041,7 @@ drop view v1;
drop table t1;
#
# Bug#26209: queries with GROUP BY and ORDER BY using views
# Bug#26209: queries with GROUP BY and ORDER BY using views
#
CREATE TABLE t1 (
......@@ -3058,4 +3060,107 @@ SELECT code, COUNT(DISTINCT country) FROM v1 GROUP BY code ORDER BY MAX(id);
DROP VIEW v1;
DROP TABLE t1;
#
# BUG#25897: Some queries are no longer possible after a CREATE VIEW
# fails
#
--disable_warnings
DROP VIEW IF EXISTS v1;
--enable_warnings
let $query = SELECT * FROM (SELECT 1) AS t;
eval $query;
--error ER_VIEW_SELECT_DERIVED
eval CREATE VIEW v1 AS $query;
--echo # Previously the following would fail.
eval $query;
#
# Bug#24532: The return data type of IS TRUE is different from similar
# operations
#
--disable_warnings
drop view if exists view_24532_a;
drop view if exists view_24532_b;
drop table if exists table_24532;
--enable_warnings
create table table_24532 (
a int,
b bigint,
c int(4),
d bigint(48)
);
create view view_24532_a as
select
a IS TRUE,
a IS NOT TRUE,
a IS FALSE,
a IS NOT FALSE,
a IS UNKNOWN,
a IS NOT UNKNOWN,
a is NULL,
a IS NOT NULL,
ISNULL(a),
b IS TRUE,
b IS NOT TRUE,
b IS FALSE,
b IS NOT FALSE,
b IS UNKNOWN,
b IS NOT UNKNOWN,
b is NULL,
b IS NOT NULL,
ISNULL(b),
c IS TRUE,
c IS NOT TRUE,
c IS FALSE,
c IS NOT FALSE,
c IS UNKNOWN,
c IS NOT UNKNOWN,
c is NULL,
c IS NOT NULL,
ISNULL(c),
d IS TRUE,
d IS NOT TRUE,
d IS FALSE,
d IS NOT FALSE,
d IS UNKNOWN,
d IS NOT UNKNOWN,
d is NULL,
d IS NOT NULL,
ISNULL(d)
from table_24532;
describe view_24532_a;
create view view_24532_b as
select
a IS TRUE,
if(ifnull(a, 0), 1, 0) as old_istrue,
a IS NOT TRUE,
if(ifnull(a, 0), 0, 1) as old_isnottrue,
a IS FALSE,
if(ifnull(a, 1), 0, 1) as old_isfalse,
a IS NOT FALSE,
if(ifnull(a, 1), 1, 0) as old_isnotfalse
from table_24532;
describe view_24532_b;
show create view view_24532_b;
insert into table_24532 values (0, 0, 0, 0);
select * from view_24532_b;
update table_24532 set a=1;
select * from view_24532_b;
update table_24532 set a=NULL;
select * from view_24532_b;
drop view view_24532_a;
drop view view_24532_b;
drop table table_24532;
--echo End of 5.0 tests.
......@@ -63,7 +63,7 @@ pid_path="$1"
total_attempts="$2"
event="$3"
test_id="$4"
log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
log_file="$MYSQLTEST_VARDIR/log/$test_id.script.log"
log_debug "-- $basename: starting --"
log_debug "pid_path: '$pid_path'"
......
......@@ -30,7 +30,7 @@ password="$4"
db="$5"
total_timeout="$6"
test_id="$7"
log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
log_file="$MYSQLTEST_VARDIR/log/$test_id.script.log"
log_debug "-- $basename: starting --"
log_debug "client_exe: '$client_exe'"
......
......@@ -508,7 +508,7 @@ int Instance_options::add_option(const char* option)
{"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD},
{"--mysqld-path=", 14, &mysqld_path, SAVE_VALUE},
{"--nonguarded", 9, &nonguarded, SAVE_WHOLE},
{"--shutdown_delay", 9, &shutdown_delay, SAVE_VALUE},
{"--shutdown-delay", 9, &shutdown_delay, SAVE_VALUE},
{NULL, 0, NULL, 0}
};
struct selected_options_st *selected_options;
......
......@@ -210,10 +210,13 @@ void Listener_thread::run()
return;
err:
log_error("Listener: failed to initialize. Initiate shutdown...");
// we have to close the ip sockets in case of error
for (i= 0; i < num_sockets; i++)
closesocket(sockets[i]);
thread_registry.set_error_status();
thread_registry.unregister_thread(&thread_info);
thread_registry.request_shutdown();
my_thread_end();
......
......@@ -114,6 +114,9 @@ void stop_all(Guardian_thread *guardian, Thread_registry *registry)
pthread_cond_signal(&guardian->COND_guardian);
/* stop all threads */
registry->deliver_shutdown();
/* Set error status in the thread registry. */
registry->set_error_status();
}
/*
......@@ -123,7 +126,7 @@ void stop_all(Guardian_thread *guardian, Thread_registry *registry)
architecture.
*/
void manager(const Options &options)
int manager(const Options &options)
{
Thread_registry thread_registry;
/*
......@@ -145,10 +148,10 @@ void manager(const Options &options)
instance_map.guardian= &guardian_thread;
if (instance_map.init() || user_map.init())
return;
return 1;
if (user_map.load(options.password_file_name))
return;
return 1;
/* write Instance Manager pid file */
......@@ -157,7 +160,7 @@ void manager(const Options &options)
(int) manager_pid);
if (create_pid_file(options.pid_file_name, manager_pid))
return;
return 1;
/*
Initialize signals and alarm-infrastructure.
......@@ -301,5 +304,6 @@ err:
end_thr_alarm(1);
/* don't pthread_exit to kill all threads who did not shut down in time */
#endif
}
return thread_registry.get_error_status() ? 1 : 0;
}
......@@ -18,7 +18,7 @@
struct Options;
void manager(const Options &options);
int manager(const Options &options);
int create_pid_file(const char *pid_file_name, int pid);
......
......@@ -110,8 +110,7 @@ int main(int argc, char *argv[])
else
#endif
manager(options);
return_value= 0;
return_value= manager(options);
err:
options.cleanup();
......@@ -254,26 +253,23 @@ static void daemonize(const char *log_file_name)
enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL };
static volatile sig_atomic_t child_status= CHILD_OK;
static volatile sig_atomic_t child_exit_code= 0;
/*
Signal handler for SIGCHLD: reap child, analyze child exit status, and set
Signal handler for SIGCHLD: reap child, analyze child exit code, and set
child_status appropriately.
*/
void reap_child(int __attribute__((unused)) signo)
{
int child_exit_status;
/* As we have only one child, no need to cycle waitpid */
if (waitpid(0, &child_exit_status, WNOHANG) > 0)
/* NOTE: As we have only one child, no need to cycle waitpid(). */
int exit_code;
if (waitpid(0, &exit_code, WNOHANG) > 0)
{
if (WIFSIGNALED(child_exit_status))
child_status= CHILD_NEED_RESPAWN;
else
/*
As reap_child is not called for SIGSTOP, we should be here only
if the child exited normally.
*/
child_status= CHILD_EXIT_ANGEL;
child_exit_code= exit_code;
child_status= exit_code ? CHILD_NEED_RESPAWN : CHILD_EXIT_ANGEL;
}
}
......@@ -353,10 +349,16 @@ spawn:
else if (child_status == CHILD_NEED_RESPAWN)
{
child_status= CHILD_OK;
log_error("angel(): mysqlmanager exited abnormally: respawning...");
log_error("angel(): mysqlmanager exited abnormally (exit code: %d):"
"respawning...",
(int) child_exit_code);
sleep(1); /* don't respawn too fast */
goto spawn;
}
/* Delete IM-angel pid file. */
my_delete(Options::angel_pid_file_name, MYF(0));
/*
mysqlmanager successfully exited, let's silently evaporate
If we return to main we fall into the manager() function, so let's
......
......@@ -53,6 +53,7 @@ Thread_info::Thread_info(pthread_t thread_id_arg) :
Thread_registry::Thread_registry() :
shutdown_in_progress(false)
,sigwait_thread_pid(pthread_self())
,error_status(FALSE)
{
pthread_mutex_init(&LOCK_thread_registry, 0);
pthread_cond_init(&COND_thread_registry_is_empty, 0);
......@@ -243,3 +244,23 @@ void Thread_registry::request_shutdown()
{
pthread_kill(sigwait_thread_pid, SIGTERM);
}
int Thread_registry::get_error_status()
{
int ret_error_status;
pthread_mutex_lock(&LOCK_thread_registry);
ret_error_status= error_status;
pthread_mutex_unlock(&LOCK_thread_registry);
return ret_error_status;
}
void Thread_registry::set_error_status()
{
pthread_mutex_lock(&LOCK_thread_registry);
error_status= TRUE;
pthread_mutex_unlock(&LOCK_thread_registry);
}
......@@ -97,12 +97,16 @@ public:
pthread_mutex_t *mutex);
int cond_timedwait(Thread_info *info, pthread_cond_t *cond,
pthread_mutex_t *mutex, struct timespec *wait_time);
int get_error_status();
void set_error_status();
private:
Thread_info head;
bool shutdown_in_progress;
pthread_mutex_t LOCK_thread_registry;
pthread_cond_t COND_thread_registry_is_empty;
pthread_t sigwait_thread_pid;
bool error_status;
};
......
......@@ -793,6 +793,59 @@ int Arg_comparator::compare_e_row()
}
void Item_func_truth::fix_length_and_dec()
{
maybe_null= 0;
null_value= 0;
decimals= 0;
max_length= 1;
}
void Item_func_truth::print(String *str)
{
str->append('(');
args[0]->print(str);
str->append(STRING_WITH_LEN(" is "));
if (! affirmative)
str->append(STRING_WITH_LEN("not "));
if (value)
str->append(STRING_WITH_LEN("true"));
else
str->append(STRING_WITH_LEN("false"));
str->append(')');
}
bool Item_func_truth::val_bool()
{
bool val= args[0]->val_bool();
if (args[0]->null_value)
{
/*
NULL val IS {TRUE, FALSE} --> FALSE
NULL val IS NOT {TRUE, FALSE} --> TRUE
*/
return (! affirmative);
}
if (affirmative)
{
/* {TRUE, FALSE} val IS {TRUE, FALSE} value */
return (val == value);
}
/* {TRUE, FALSE} val IS NOT {TRUE, FALSE} value */
return (val != value);
}
longlong Item_func_truth::val_int()
{
return (val_bool() ? 1 : 0);
}
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
......@@ -1529,6 +1582,7 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
......@@ -1558,12 +1612,20 @@ Item_func_if::fix_length_and_dec()
collation.set(&my_charset_bin); // Number
}
}
max_length=
(cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
(max(args[1]->max_length - args[1]->decimals,
args[2]->max_length - args[2]->decimals) + decimals +
(unsigned_flag ? 0 : 1) ) :
max(args[1]->max_length, args[2]->max_length);
if ((cached_result_type == DECIMAL_RESULT )
|| (cached_result_type == INT_RESULT))
{
int len1= args[1]->max_length - args[1]->decimals
- (args[1]->unsigned_flag ? 0 : 1);
int len2= args[2]->max_length - args[2]->decimals
- (args[2]->unsigned_flag ? 0 : 1);
max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
}
else
max_length= max(args[1]->max_length, args[2]->max_length);
}
......
......@@ -101,6 +101,92 @@ public:
uint decimal_precision() const { return 1; }
};
/**
Abstract Item class, to represent <code>X IS [NOT] (TRUE | FALSE)</code>
boolean predicates.
*/
class Item_func_truth : public Item_bool_func
{
public:
virtual bool val_bool();
virtual longlong val_int();
virtual void fix_length_and_dec();
virtual void print(String *str);
protected:
Item_func_truth(Item *a, bool a_value, bool a_affirmative)
: Item_bool_func(a), value(a_value), affirmative(a_affirmative)
{}
~Item_func_truth()
{}
private:
/**
True for <code>X IS [NOT] TRUE</code>,
false for <code>X IS [NOT] FALSE</code> predicates.
*/
const bool value;
/**
True for <code>X IS Y</code>, false for <code>X IS NOT Y</code> predicates.
*/
const bool affirmative;
};
/**
This Item represents a <code>X IS TRUE</code> boolean predicate.
*/
class Item_func_istrue : public Item_func_truth
{
public:
Item_func_istrue(Item *a) : Item_func_truth(a, true, true) {}
~Item_func_istrue() {}
virtual const char* func_name() const { return "istrue"; }
};
/**
This Item represents a <code>X IS NOT TRUE</code> boolean predicate.
*/
class Item_func_isnottrue : public Item_func_truth
{
public:
Item_func_isnottrue(Item *a) : Item_func_truth(a, true, false) {}
~Item_func_isnottrue() {}
virtual const char* func_name() const { return "isnottrue"; }
};
/**
This Item represents a <code>X IS FALSE</code> boolean predicate.
*/
class Item_func_isfalse : public Item_func_truth
{
public:
Item_func_isfalse(Item *a) : Item_func_truth(a, false, true) {}
~Item_func_isfalse() {}
virtual const char* func_name() const { return "isfalse"; }
};
/**
This Item represents a <code>X IS NOT FALSE</code> boolean predicate.
*/
class Item_func_isnotfalse : public Item_func_truth
{
public:
Item_func_isnotfalse(Item *a) : Item_func_truth(a, false, false) {}
~Item_func_isnotfalse() {}
virtual const char* func_name() const { return "isnotfalse"; }
};
class Item_cache;
#define UNKNOWN ((my_bool)-1)
......
......@@ -51,6 +51,10 @@ Item_subselect::Item_subselect():
void Item_subselect::init(st_select_lex *select_lex,
select_subselect *result)
{
/*
Please see Item_singlerow_subselect::invalidate_and_restore_select_lex(),
which depends on alterations to the parse tree implemented here.
*/
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex));
......@@ -91,6 +95,12 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_VOID_RETURN;
}
st_select_lex *
Item_subselect::get_select_lex()
{
return unit->first_select();
}
void Item_subselect::cleanup()
{
DBUG_ENTER("Item_subselect::cleanup");
......@@ -268,6 +278,26 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
DBUG_VOID_RETURN;
}
st_select_lex *
Item_singlerow_subselect::invalidate_and_restore_select_lex()
{
DBUG_ENTER("Item_singlerow_subselect::invalidate_and_restore_select_lex");
st_select_lex *result= get_select_lex();
DBUG_ASSERT(result);
/*
This code restore the parse tree in it's state before the execution of
Item_singlerow_subselect::Item_singlerow_subselect(),
and in particular decouples this object from the SELECT_LEX,
so that the SELECT_LEX can be used with a different flavor
or Item_subselect instead, as part of query rewriting.
*/
unit->item= NULL;
DBUG_RETURN(result);
}
Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
Item_subselect *parent,
st_select_lex *select_lex,
......
......@@ -126,6 +126,12 @@ public:
virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; }
/**
Get the SELECT_LEX structure associated with this Item.
@return the SELECT_LEX structure associated with this Item
*/
st_select_lex* get_select_lex();
friend class select_subselect;
friend class Item_in_optimizer;
friend bool Item_field::fix_fields(THD *, Item **);
......@@ -169,6 +175,20 @@ public:
bool null_inside();
void bring_value();
/**
This method is used to implement a special case of semantic tree
rewriting, mandated by a SQL:2003 exception in the specification.
The only caller of this method is handle_sql2003_note184_exception(),
see the code there for more details.
Note that this method breaks the object internal integrity, by
removing it's association with the corresponding SELECT_LEX,
making this object orphan from the parse tree.
No other method, beside the destructor, should be called on this
object, as it is now invalid.
@return the SELECT_LEX structure that was given in the constructor.
*/
st_select_lex* invalidate_and_restore_select_lex();
friend class select_singlerow_subselect;
};
......
......@@ -36,6 +36,7 @@ Item_result
sp_map_result_type(enum enum_field_types type)
{
switch (type) {
case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
......@@ -58,6 +59,7 @@ Item::Type
sp_map_item_type(enum enum_field_types type)
{
switch (type) {
case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
......
......@@ -1210,6 +1210,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
int4store(key + key_length, thd->server_id);
int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
/*
Unless requested otherwise, try to resolve this table in the list
of temporary tables of this thread. In MySQL temporary tables
are always thread-local and "shadow" possible base tables with the
same name. This block implements the behaviour.
TODO: move this block into a separate function.
*/
if (!table_list->skip_temporary)
{
for (table= thd->temporary_tables; table ; table=table->next)
......@@ -1218,6 +1225,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
!memcmp(table->s->table_cache_key, key,
key_length + TMP_TABLE_KEY_EXTRA))
{
/*
We're trying to use the same temporary table twice in a query.
Right now we don't support this because a temporary table
is always represented by only one TABLE object in THD, and
it can not be cloned. Emit an error for an unsupported behaviour.
*/
if (table->query_id == thd->query_id ||
thd->prelocked_mode && table->query_id)
{
......@@ -1233,6 +1246,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
}
/*
The table is not temporary - if we're in pre-locked or LOCK TABLES
mode, let's try to find the requested table in the list of pre-opened
and locked tables. If the table is not there, return an error - we can't
open not pre-opened tables in pre-locked/LOCK TABLES mode.
TODO: move this block into a separate function.
*/
if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) &&
(thd->locked_tables || thd->prelocked_mode))
{ // Using table locks
......@@ -1304,7 +1324,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
goto reset;
}
/*
is it view?
Is this table a view and not a base table?
(it is work around to allow to open view with locked tables,
real fix will be made after definition cache will be made)
*/
......@@ -1338,8 +1358,32 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
DBUG_RETURN(0);
}
/*
Non pre-locked/LOCK TABLES mode, and the table is not temporary:
this is the normal use case.
Now we should:
- try to find the table in the table cache.
- if one of the discovered TABLE instances is name-locked
(table->s->version == 0) or some thread has started FLUSH TABLES
(refresh_version > table->s->version), back off -- we have to wait
until no one holds a name lock on the table.
- if there is no such TABLE in the name cache, read the table definition
and insert it into the cache.
We perform all of the above under LOCK_open which currently protects
the open cache (also known as table cache) and table definitions stored
on disk.
*/
VOID(pthread_mutex_lock(&LOCK_open));
/*
If it's the first table from a list of tables used in a query,
remember refresh_version (the version of open_cache state).
If the version changes while we're opening the remaining tables,
we will have to back off, close all the tables opened-so-far,
and try to reopen them.
Note: refresh_version is currently changed only during FLUSH TABLES.
*/
if (!thd->open_tables)
thd->version=refresh_version;
else if ((thd->version != refresh_version) &&
......@@ -1356,12 +1400,39 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
/*
Actually try to find the table in the open_cache.
The cache may contain several "TABLE" instances for the same
physical table. The instances that are currently "in use" by
some thread have their "in_use" member != NULL.
There is no good reason for having more than one entry in the
hash for the same physical table, except that we use this as
an implicit "pending locks queue" - see
wait_for_locked_table_names for details.
*/
for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
&state);
table && table->in_use ;
table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
&state))
{
/*
Normally, table->s->version contains the value of
refresh_version from the moment when this table was
(re-)opened and added to the cache.
If since then we did (or just started) FLUSH TABLES
statement, refresh_version has been increased.
For "name-locked" TABLE instances, table->s->version is set
to 0 (see lock_table_name for details).
In case there is a pending FLUSH TABLES or a name lock, we
need to back off and re-start opening tables.
If we do not back off now, we may dead lock in case of lock
order mismatch with some other thread:
c1: name lock t1; -- sort of exclusive lock
c2: open t2; -- sort of shared lock
c1: name lock t2; -- blocks
c2: open t1; -- blocks
*/
if (table->s->version != refresh_version)
{
DBUG_PRINT("note",
......@@ -1375,16 +1446,35 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
/*
There is a refresh in progress for this table
Wait until the table is freed or the thread is killed.
Back off, part 1: mark the table as "unused" for the
purpose of name-locking by setting table->db_stat to 0. Do
that only for the tables in this thread that have an old
table->s->version (this is an optimization (?)).
table->db_stat == 0 signals wait_for_locked_table_names
that the tables in question are not used any more. See
table_is_used call for details.
*/
close_old_data_files(thd,thd->open_tables,0,0);
/*
Back-off part 2: try to avoid "busy waiting" on the table:
if the table is in use by some other thread, we suspend
and wait till the operation is complete: when any
operation that juggles with table->s->version completes,
it broadcasts COND_refresh condition variable.
*/
if (table->in_use != thd)
{
wait_for_refresh(thd);
/* wait_for_refresh will unlock LOCK_open for us */
}
else
{
VOID(pthread_mutex_unlock(&LOCK_open));
}
/*
There is a refresh in progress for this table.
Signal the caller that it has to try again.
*/
if (refresh)
*refresh=1;
DBUG_RETURN(0);
......@@ -1392,6 +1482,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
if (table)
{
/* Unlink the table from "unused_tables" list. */
if (table == unused_tables)
{ // First unused
unused_tables=unused_tables->next; // Remove from link
......@@ -1404,6 +1495,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
else
{
/* Insert a new TABLE instance into the open cache */
TABLE_SHARE *share;
int error;
/* Free cache if too big */
......@@ -2145,6 +2237,10 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
}
}
/*
For every table in the list of tables to open, try to find or open
a table.
*/
for (tables= *start; tables ;tables= tables->next_global)
{
/*
......@@ -2159,6 +2255,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
goto process_view_routines;
continue;
}
/*
If this TABLE_LIST object is a placeholder for an information_schema
table, create a temporary table to represent the information_schema
table in the query. Do not fill it yet - will be filled during
execution.
*/
if (tables->schema_table)
{
if (!mysql_schema_table(thd, thd->lex, tables))
......@@ -2166,7 +2268,11 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
DBUG_RETURN(-1);
}
(*counter)++;
/*
Not a placeholder: must be a base table or a view, and the table is
not opened yet. Try to open the table.
*/
if (!tables->table &&
!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
{
......@@ -2273,7 +2379,7 @@ process_view_routines:
{
/*
Serious error during reading stored routines from mysql.proc table.
Something's wrong with the table or its contents, and an error has
Something is wrong with the table or its contents, and an error has
been emitted; we must abort.
*/
result= -1;
......
......@@ -1765,8 +1765,18 @@ void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
if (query_cache_size > 0)
{
flush_cache();
/*
There may be two free_cache() calls in progress, because we
release 'structure_guard_mutex' in flush_cache(). When the second
flush_cache() wakes up from the wait on 'COND_flush_finished', the
first call to free_cache() has done its job. So we have to test
'query_cache_size > 0' the second time to see if the cache wasn't
reset by other thread, or if it was reset and was re-enabled then.
If the cache was reset, then we have nothing to do here.
*/
if (query_cache_size > 0)
{
#ifndef DBUG_OFF
if (bins[0].free_blocks == 0)
{
......@@ -1808,6 +1818,12 @@ void Query_cache::free_cache()
flush_in_progress flag and releases the lock, so other threads may
proceed skipping the cache as if it is disabled. Concurrent
flushes are performed in turn.
After flush_cache() call, the cache is flushed, all the freed
memory is accumulated in bin[0], and the 'structure_guard_mutex'
is locked. However, since we could release the mutex during
execution, the rest of the cache state could have been changed,
and should not be relied on.
*/
void Query_cache::flush_cache()
......
......@@ -319,6 +319,7 @@ void THD::init(void)
void THD::init_for_queries()
{
set_time();
ha_enable_transaction(this,TRUE);
reset_root_defaults(mem_root, variables.query_alloc_block_size,
......
......@@ -99,6 +99,16 @@ void lex_free(void)
}
void
st_parsing_options::reset()
{
allows_variable= TRUE;
allows_select_into= TRUE;
allows_select_procedure= TRUE;
allows_derived= TRUE;
}
/*
This is called before every query that is to be parsed.
Because of this, it's critical to not do too much things here.
......@@ -149,6 +159,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0;
lex->leaf_tables_insert= 0;
lex->parsing_options.reset();
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
......
......@@ -891,10 +891,8 @@ struct st_parsing_options
bool allows_select_procedure;
bool allows_derived;
st_parsing_options()
: allows_variable(TRUE), allows_select_into(TRUE),
allows_select_procedure(TRUE), allows_derived(TRUE)
{}
st_parsing_options() { reset(); }
void reset();
};
......
......@@ -1162,7 +1162,6 @@ pthread_handler_t handle_one_connection(void *arg)
thd->version= refresh_version;
thd->proc_info= 0;
thd->command= COM_SLEEP;
thd->set_time();
thd->init_for_queries();
if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
......@@ -1178,7 +1177,6 @@ pthread_handler_t handle_one_connection(void *arg)
sql_print_warning("%s", net->last_error);
}
thd->proc_info=0;
thd->set_time();
thd->init_for_queries();
}
......@@ -1312,6 +1310,7 @@ pthread_handler_t handle_bootstrap(void *arg)
mode we have only one thread.
*/
thd->query_id=next_query_id();
thd->set_time();
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
......
......@@ -59,15 +59,6 @@ const LEX_STRING null_lex_str={0,0};
YYABORT; \
}
/* Helper for parsing "IS [NOT] truth_value" */
inline Item *is_truth_value(Item *A, bool v1, bool v2)
{
return new Item_func_if(create_func_ifnull(A,
new Item_int((char *) (v2 ? "TRUE" : "FALSE"), v2, 1)),
new Item_int((char *) (v1 ? "TRUE" : "FALSE"), v1, 1),
new Item_int((char *) (v1 ? "FALSE" : "TRUE"),!v1, 1));
}
#ifndef DBUG_OFF
#define YYDEBUG 1
#else
......@@ -277,6 +268,81 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
lex->sphead->do_cont_backpatch();
}
/**
Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
This function returns the proper item for the SQL expression
<code>left [NOT] IN ( expr )</code>
@param thd the current thread
@param left the in predicand
@param equal true for IN predicates, false for NOT IN predicates
@param expr first and only expression of the in value list
@return an expression representing the IN predicate.
*/
Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
Item *expr)
{
/*
Relevant references for this issue:
- SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
- SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
- SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
- SQL:2003, Part 2, section 7.15 <subquery>, page 370,
- SQL:2003 Feature F561, "Full value expressions".
The exception in SQL:2003 Note 184 means:
Item_singlerow_subselect, which corresponds to a <scalar subquery>,
should be re-interpreted as an Item_in_subselect, which corresponds
to a <table subquery> when used inside an <in predicate>.
Our reading of Note 184 is reccursive, so that all:
- IN (( <subquery> ))
- IN ((( <subquery> )))
- IN '('^N <subquery> ')'^N
- etc
should be interpreted as a <table subquery>, no matter how deep in the
expression the <subquery> is.
*/
Item *result;
DBUG_ENTER("handle_sql2003_note184_exception");
if (expr->type() == Item::SUBSELECT_ITEM)
{
Item_subselect *expr2 = (Item_subselect*) expr;
if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
{
Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
st_select_lex *subselect;
/*
Implement the mandated change, by altering the semantic tree:
left IN Item_singlerow_subselect(subselect)
is modified to
left IN (subselect)
which is represented as
Item_in_subselect(left, subselect)
*/
subselect= expr3->invalidate_and_restore_select_lex();
result= new (thd->mem_root) Item_in_subselect(left, subselect);
if (! equal)
result = negate_expression(thd, result);
DBUG_RETURN(result);
}
}
if (equal)
result= new (thd->mem_root) Item_func_eq(left, expr);
else
result= new (thd->mem_root) Item_func_ne(left, expr);
DBUG_RETURN(result);
}
%}
%union {
int num;
......@@ -4393,13 +4459,18 @@ bool_factor:
| bool_test ;
bool_test:
bool_pri IS TRUE_SYM { $$= is_truth_value($1,1,0); }
| bool_pri IS not TRUE_SYM { $$= is_truth_value($1,0,0); }
| bool_pri IS FALSE_SYM { $$= is_truth_value($1,0,1); }
| bool_pri IS not FALSE_SYM { $$= is_truth_value($1,1,1); }
| bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
| bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
| bool_pri ;
bool_pri IS TRUE_SYM
{ $$= new (YYTHD->mem_root) Item_func_istrue($1); }
| bool_pri IS not TRUE_SYM
{ $$= new (YYTHD->mem_root) Item_func_isnottrue($1); }
| bool_pri IS FALSE_SYM
{ $$= new (YYTHD->mem_root) Item_func_isfalse($1); }
| bool_pri IS not FALSE_SYM
{ $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); }
| bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
| bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
| bool_pri
;
bool_pri:
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
......@@ -4412,31 +4483,37 @@ bool_pri:
| predicate ;
predicate:
bit_expr IN_SYM '(' subselect ')'
{ $$= new Item_in_subselect($1, $4); }
| bit_expr not IN_SYM '(' subselect ')'
{ $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); }
bit_expr IN_SYM '(' subselect ')'
{
$$= new (YYTHD->mem_root) Item_in_subselect($1, $4);
}
| bit_expr not IN_SYM '(' subselect ')'
{
THD *thd= YYTHD;
Item *item= new (thd->mem_root) Item_in_subselect($1, $5);
$$= negate_expression(thd, item);
}
| bit_expr IN_SYM '(' expr ')'
{
$$= new Item_func_eq($1, $4);
$$= handle_sql2003_note184_exception(YYTHD, $1, true, $4);
}
| bit_expr IN_SYM '(' expr ',' expr_list ')'
{
$6->push_front($4);
$6->push_front($1);
$$= new Item_func_in(*$6);
| bit_expr IN_SYM '(' expr ',' expr_list ')'
{
$6->push_front($4);
$6->push_front($1);
$$= new (YYTHD->mem_root) Item_func_in(*$6);
}
| bit_expr not IN_SYM '(' expr ')'
{
$$= new Item_func_ne($1, $5);
$$= handle_sql2003_note184_exception(YYTHD, $1, false, $5);
}
| bit_expr not IN_SYM '(' expr ',' expr_list ')'
| bit_expr not IN_SYM '(' expr ',' expr_list ')'
{
$7->push_front($5);
$7->push_front($1);
Item_func_in *item = new Item_func_in(*$7);
item->negate();
$$= item;
$7->push_front($5);
$7->push_front($1);
Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7);
item->negate();
$$= item;
}
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment