Commit e67cb86a authored by unknown's avatar unknown

Merge bk-internal.mysql.com:/home/bk/mysql-4.1

into mysql.com:/my/mysql-4.1

parents 88d103aa c6311f86
...@@ -5,7 +5,7 @@ reset slave; ...@@ -5,7 +5,7 @@ reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave; start slave;
drop database if exists mysqltest; drop database if exists mysqltest;
reset master; stop slave;
create database mysqltest; create database mysqltest;
create table t1(a int, b int, unique(b)); create table t1(a int, b int, unique(b));
use mysqltest; use mysqltest;
......
...@@ -53,7 +53,7 @@ select 0,'#' union select a,b from t1 union all select a,b from t2 union select ...@@ -53,7 +53,7 @@ select 0,'#' union select a,b from t1 union all select a,b from t2 union select
4 d 4 d
5 f 5 f
6 e 6 e
7 g 7 gg
select a,b from t1 union select a,b from t1; select a,b from t1 union select a,b from t1;
a b a b
1 a 1 a
...@@ -449,10 +449,10 @@ INSERT INTO t2 (id, id_master, text1, text2) VALUES("4", "1", ...@@ -449,10 +449,10 @@ INSERT INTO t2 (id, id_master, text1, text2) VALUES("4", "1",
SELECT 1 AS id_master, 1 AS id, NULL AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; SELECT 1 AS id_master, 1 AS id, NULL AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master;
id_master id text1 text2 id_master id text1 text2
1 1 NULL ABCDE 1 1 NULL ABCDE
1 1 bar1 1 1 foo1 bar1
1 2 bar2 1 2 foo2 bar2
1 3 NULL bar3 1 3 NULL bar3
1 4 bar4 1 4 foo4 bar4
SELECT 1 AS id_master, 1 AS id, 'ABCDE' AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; SELECT 1 AS id_master, 1 AS id, 'ABCDE' AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master;
id_master id text1 text2 id_master id text1 text2
1 1 ABCDE ABCDE 1 1 ABCDE ABCDE
...@@ -523,3 +523,226 @@ pla_id matintnum ...@@ -523,3 +523,226 @@ pla_id matintnum
105 c 105 c
0 0 0 0
drop table t1, t2; drop table t1, t2;
create table t1 SELECT "a" as a UNION select "aa" as a;
select * from t1;
a
a
aa
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(2) NOT NULL default ''
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT 12 as a UNION select "aa" as a;
select * from t1;
a
12
aa
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(2) NOT NULL default ''
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT 12 as a UNION select 12.2 as a;
select * from t1;
a
12.0
12.2
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` double(4,1) NOT NULL default '0.0'
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob);
insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'testc', 'testv', 'tetetetetest');
create table t1 SELECT it2 from t2 UNION select it1 from t2;
select * from t1;
it2
1
NULL
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`it2` tinyint(4) default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT it2 from t2 UNION select i from t2;
select * from t1;
it2
1
3
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`it2` int(11) NOT NULL default '0'
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT i from t2 UNION select f from t2;
select * from t1;
i
3
1.5
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` double default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT f from t2 UNION select d from t2;
select * from t1;
f
1.5
2.5
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` double default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT ib from t2 UNION select f from t2;
select * from t1;
ib
4
1.5
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`ib` double default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT ib from t2 UNION select d from t2;
select * from t1;
ib
4
2.5
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`ib` double default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT f from t2 UNION select y from t2;
select * from t1;
f
1.5
1972
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` float default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT f from t2 UNION select da from t2;
select * from t1;
f
1.5
1972-10-22
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` char(12) binary default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT y from t2 UNION select da from t2;
select * from t1;
y
1972
1972-10-22
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`y` char(10) binary default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT y from t2 UNION select dt from t2;
select * from t1;
y
1972
1972-10-22 11:50:00
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`y` char(19) binary default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT da from t2 UNION select dt from t2;
select * from t1;
da
1972-10-22 00:00:00
1972-10-22 11:50:00
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`da` datetime default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT dt from t2 UNION select sc from t2;
select * from t1;
dt
1972-10-22 11:50:00
testc
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` char(19) default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT dt from t2 UNION select sv from t2;
select * from t1;
dt
1972-10-22 11:50:00
testv
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` char(19) default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT sc from t2 UNION select sv from t2;
select * from t1;
sc
testc
testv
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`sc` varchar(10) default NULL
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT dt from t2 UNION select b from t2;
select * from t1;
dt
1972-10-22 11:50:00
tetetetetest
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` blob
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT sv from t2 UNION select b from t2;
select * from t1;
sv
testv
tetetetetest
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`sv` blob
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2;
select * from t1;
i
3
2.5
tetetetetest
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` blob
) TYPE=MyISAM DEFAULT CHARSET=latin1
drop table t1,t2;
...@@ -9,7 +9,7 @@ drop database if exists mysqltest; ...@@ -9,7 +9,7 @@ drop database if exists mysqltest;
--enable_warnings --enable_warnings
connection slave; connection slave;
reset master; stop slave; # don't need slave for this test
# Test logging on master # Test logging on master
......
...@@ -302,3 +302,93 @@ insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd' ...@@ -302,3 +302,93 @@ insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd'
insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105);
SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id union SELECT 0, 0; SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id union SELECT 0, 0;
drop table t1, t2; drop table t1, t2;
#
# types conversions
#
create table t1 SELECT "a" as a UNION select "aa" as a;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT 12 as a UNION select "aa" as a;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT 12 as a UNION select 12.2 as a;
select * from t1;
show create table t1;
drop table t1;
create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob);
insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'testc', 'testv', 'tetetetetest');
create table t1 SELECT it2 from t2 UNION select it1 from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT it2 from t2 UNION select i from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT i from t2 UNION select f from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT f from t2 UNION select d from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT ib from t2 UNION select f from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT ib from t2 UNION select d from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT f from t2 UNION select y from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT f from t2 UNION select da from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT y from t2 UNION select da from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT y from t2 UNION select dt from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT da from t2 UNION select dt from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT dt from t2 UNION select sc from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT dt from t2 UNION select sv from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT sc from t2 UNION select sv from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT dt from t2 UNION select b from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT sv from t2 UNION select b from t2;
select * from t1;
show create table t1;
drop table t1;
create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2;
select * from t1;
show create table t1;
drop table t1,t2;
...@@ -169,6 +169,128 @@ static inline uint field_length_without_space(const char *ptr, uint length) ...@@ -169,6 +169,128 @@ static inline uint field_length_without_space(const char *ptr, uint length)
return (uint) (end-ptr); return (uint) (end-ptr);
} }
/*
Tables of filed type compatibility.
There are tables for every type, table consist of list of types in which
given type can be converted without data lost, list should be ended with
FIELD_CAST_STOP
*/
static Field::field_cast_enum field_cast_decimal[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_tiny[]=
{Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
Field::FIELD_CAST_LONGLONG,
Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_short[]=
{Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_medium[]=
{Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_long[]=
{Field::FIELD_CAST_LONGLONG,
Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_longlong[]=
{Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_float[]=
{Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_double[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_null[]=
{Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT,
Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_TIMESTAMP, Field::FIELD_CAST_YEAR,
Field::FIELD_CAST_DATE, Field::FIELD_CAST_NEWDATE,
Field::FIELD_CAST_TIME, Field::FIELD_CAST_DATETIME,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB,
Field::FIELD_CAST_GEOM, Field::FIELD_CAST_ENUM, Field::FIELD_CAST_SET,
Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_timestamp[]=
{Field::FIELD_CAST_DATETIME,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_year[]=
{Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
Field::FIELD_CAST_LONGLONG,
Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_date[]=
{Field::FIELD_CAST_DATETIME,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_newdate[]=
{Field::FIELD_CAST_DATETIME,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_time[]=
{Field::FIELD_CAST_DATETIME,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_datetime[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_string[]=
{Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_varstring[]=
{Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_blob[]=
{Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_geom[]=
{Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_enum[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_set[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
// Array of pointers on conversion table for all fields types casting
static Field::field_cast_enum *field_cast_array[]=
{0, //FIELD_CAST_STOP
field_cast_decimal, field_cast_tiny, field_cast_short,
field_cast_medium, field_cast_long, field_cast_longlong,
field_cast_float, field_cast_double,
field_cast_null,
field_cast_timestamp, field_cast_year, field_cast_date, field_cast_newdate,
field_cast_time, field_cast_datetime,
field_cast_string, field_cast_varstring, field_cast_blob,
field_cast_geom, field_cast_enum, field_cast_set
};
bool Field::field_cast_compatible(Field::field_cast_enum type)
{
DBUG_ASSERT(type != FIELD_CAST_STOP);
Field::field_cast_enum *array= field_cast_array[field_cast_type()];
uint i= 0;
Field::field_cast_enum tp;
do
{
tp= array[i++];
if (tp == type)
return 1;
} while (tp != FIELD_CAST_STOP);
return 0;
}
/**************************************************************************** /****************************************************************************
** Functions for the base classes ** Functions for the base classes
** This is an unpacked number. ** This is an unpacked number.
......
...@@ -61,6 +61,17 @@ class Field ...@@ -61,6 +61,17 @@ class Field
GEOM_GEOMETRYCOLLECTION = 7 GEOM_GEOMETRYCOLLECTION = 7
}; };
enum imagetype { itRAW, itMBR}; enum imagetype { itRAW, itMBR};
enum field_cast_enum
{
FIELD_CAST_STOP, FIELD_CAST_DECIMAL, FIELD_CAST_TINY, FIELD_CAST_SHORT,
FIELD_CAST_MEDIUM, FIELD_CAST_LONG, FIELD_CAST_LONGLONG,
FIELD_CAST_FLOAT, FIELD_CAST_DOUBLE,
FIELD_CAST_NULL,
FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE,
FIELD_CAST_TIME, FIELD_CAST_DATETIME,
FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB,
FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET
};
utype unireg_check; utype unireg_check;
uint32 field_length; // Length of field uint32 field_length; // Length of field
...@@ -230,6 +241,8 @@ class Field ...@@ -230,6 +241,8 @@ class Field
virtual bool has_charset(void) const { return FALSE; } virtual bool has_charset(void) const { return FALSE; }
virtual void set_charset(CHARSET_INFO *charset) { } virtual void set_charset(CHARSET_INFO *charset) { }
void set_warning(const unsigned int level, const unsigned int code); void set_warning(const unsigned int level, const unsigned int code);
virtual field_cast_enum field_cast_type()= 0;
bool field_cast_compatible(field_cast_enum type);
friend bool reopen_table(THD *,struct st_table *,bool); friend bool reopen_table(THD *,struct st_table *,bool);
friend int cre_myisam(my_string name, register TABLE *form, uint options, friend int cre_myisam(my_string name, register TABLE *form, uint options,
ulonglong auto_increment_value); ulonglong auto_increment_value);
...@@ -334,6 +347,7 @@ class Field_decimal :public Field_num { ...@@ -334,6 +347,7 @@ class Field_decimal :public Field_num {
void overflow(bool negative); void overflow(bool negative);
bool zero_pack() const { return 0; } bool zero_pack() const { return 0; }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_DECIMAL; }
}; };
...@@ -369,6 +383,7 @@ class Field_tiny :public Field_num { ...@@ -369,6 +383,7 @@ class Field_tiny :public Field_num {
void sort_string(char *buff,uint length); void sort_string(char *buff,uint length);
uint32 pack_length() const { return 1; } uint32 pack_length() const { return 1; }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_TINY; }
}; };
...@@ -404,6 +419,7 @@ class Field_short :public Field_num { ...@@ -404,6 +419,7 @@ class Field_short :public Field_num {
void sort_string(char *buff,uint length); void sort_string(char *buff,uint length);
uint32 pack_length() const { return 2; } uint32 pack_length() const { return 2; }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_SHORT; }
}; };
...@@ -434,6 +450,7 @@ class Field_medium :public Field_num { ...@@ -434,6 +450,7 @@ class Field_medium :public Field_num {
void sort_string(char *buff,uint length); void sort_string(char *buff,uint length);
uint32 pack_length() const { return 3; } uint32 pack_length() const { return 3; }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_MEDIUM; }
}; };
...@@ -469,6 +486,7 @@ class Field_long :public Field_num { ...@@ -469,6 +486,7 @@ class Field_long :public Field_num {
void sort_string(char *buff,uint length); void sort_string(char *buff,uint length);
uint32 pack_length() const { return 4; } uint32 pack_length() const { return 4; }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_LONG; }
}; };
...@@ -507,6 +525,7 @@ class Field_longlong :public Field_num { ...@@ -507,6 +525,7 @@ class Field_longlong :public Field_num {
uint32 pack_length() const { return 8; } uint32 pack_length() const { return 8; }
void sql_type(String &str) const; void sql_type(String &str) const;
bool store_for_compare() { return 1; } bool store_for_compare() { return 1; }
field_cast_enum field_cast_type() { return FIELD_CAST_LONGLONG; }
}; };
#endif #endif
...@@ -540,6 +559,7 @@ class Field_float :public Field_num { ...@@ -540,6 +559,7 @@ class Field_float :public Field_num {
void sort_string(char *buff,uint length); void sort_string(char *buff,uint length);
uint32 pack_length() const { return sizeof(float); } uint32 pack_length() const { return sizeof(float); }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_FLOAT; }
}; };
...@@ -573,6 +593,7 @@ class Field_double :public Field_num { ...@@ -573,6 +593,7 @@ class Field_double :public Field_num {
void sort_string(char *buff,uint length); void sort_string(char *buff,uint length);
uint32 pack_length() const { return sizeof(double); } uint32 pack_length() const { return sizeof(double); }
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_DOUBLE; }
}; };
...@@ -606,6 +627,7 @@ class Field_null :public Field_str { ...@@ -606,6 +627,7 @@ class Field_null :public Field_str {
uint32 pack_length() const { return 0; } uint32 pack_length() const { return 0; }
void sql_type(String &str) const; void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
field_cast_enum field_cast_type() { return FIELD_CAST_NULL; }
}; };
...@@ -649,6 +671,7 @@ class Field_timestamp :public Field_str { ...@@ -649,6 +671,7 @@ class Field_timestamp :public Field_str {
} }
bool get_date(TIME *ltime,uint fuzzydate); bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime); bool get_time(TIME *ltime);
field_cast_enum field_cast_type() { return FIELD_CAST_TIMESTAMP; }
}; };
...@@ -674,6 +697,7 @@ class Field_year :public Field_tiny { ...@@ -674,6 +697,7 @@ class Field_year :public Field_tiny {
String *val_str(String*,String *); String *val_str(String*,String *);
bool send_binary(Protocol *protocol); bool send_binary(Protocol *protocol);
void sql_type(String &str) const; void sql_type(String &str) const;
field_cast_enum field_cast_type() { return FIELD_CAST_YEAR; }
}; };
...@@ -706,6 +730,7 @@ class Field_date :public Field_str { ...@@ -706,6 +730,7 @@ class Field_date :public Field_str {
void sql_type(String &str) const; void sql_type(String &str) const;
bool store_for_compare() { return 1; } bool store_for_compare() { return 1; }
bool zero_pack() const { return 1; } bool zero_pack() const { return 1; }
field_cast_enum field_cast_type() { return FIELD_CAST_DATE; }
}; };
class Field_newdate :public Field_str { class Field_newdate :public Field_str {
...@@ -737,6 +762,7 @@ class Field_newdate :public Field_str { ...@@ -737,6 +762,7 @@ class Field_newdate :public Field_str {
bool zero_pack() const { return 1; } bool zero_pack() const { return 1; }
bool get_date(TIME *ltime,uint fuzzydate); bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime); bool get_time(TIME *ltime);
field_cast_enum field_cast_type() { return FIELD_CAST_NEWDATE; }
}; };
...@@ -770,6 +796,7 @@ class Field_time :public Field_str { ...@@ -770,6 +796,7 @@ class Field_time :public Field_str {
void sql_type(String &str) const; void sql_type(String &str) const;
bool store_for_compare() { return 1; } bool store_for_compare() { return 1; }
bool zero_pack() const { return 1; } bool zero_pack() const { return 1; }
field_cast_enum field_cast_type() { return FIELD_CAST_TIME; }
}; };
...@@ -807,6 +834,7 @@ class Field_datetime :public Field_str { ...@@ -807,6 +834,7 @@ class Field_datetime :public Field_str {
bool zero_pack() const { return 1; } bool zero_pack() const { return 1; }
bool get_date(TIME *ltime,uint fuzzydate); bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime); bool get_time(TIME *ltime);
field_cast_enum field_cast_type() { return FIELD_CAST_DATETIME; }
}; };
...@@ -851,6 +879,7 @@ class Field_string :public Field_str { ...@@ -851,6 +879,7 @@ class Field_string :public Field_str {
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
enum_field_types real_type() const { return FIELD_TYPE_STRING; } enum_field_types real_type() const { return FIELD_TYPE_STRING; }
bool has_charset(void) const { return TRUE; } bool has_charset(void) const { return TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_STRING; }
}; };
...@@ -894,6 +923,7 @@ class Field_varstring :public Field_str { ...@@ -894,6 +923,7 @@ class Field_varstring :public Field_str {
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; } enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; }
bool has_charset(void) const { return TRUE; } bool has_charset(void) const { return TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_VARSTRING; }
}; };
...@@ -983,6 +1013,7 @@ class Field_blob :public Field_str { ...@@ -983,6 +1013,7 @@ class Field_blob :public Field_str {
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
bool has_charset(void) const bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; } { return charset() == &my_charset_bin ? FALSE : TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_BLOB; }
}; };
...@@ -1011,6 +1042,7 @@ class Field_geom :public Field_blob { ...@@ -1011,6 +1042,7 @@ class Field_geom :public Field_blob {
void get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type); void get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type);
void set_key_image(char *buff,uint length, CHARSET_INFO *cs); void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
field_cast_enum field_cast_type() { return FIELD_CAST_GEOM; }
}; };
...@@ -1052,6 +1084,7 @@ class Field_enum :public Field_str { ...@@ -1052,6 +1084,7 @@ class Field_enum :public Field_str {
bool optimize_range(uint idx) { return 0; } bool optimize_range(uint idx) { return 0; }
bool eq_def(Field *field); bool eq_def(Field *field);
bool has_charset(void) const { return TRUE; } bool has_charset(void) const { return TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; }
}; };
...@@ -1077,6 +1110,7 @@ class Field_set :public Field_enum { ...@@ -1077,6 +1110,7 @@ class Field_set :public Field_enum {
void sql_type(String &str) const; void sql_type(String &str) const;
enum_field_types real_type() const { return FIELD_TYPE_SET; } enum_field_types real_type() const { return FIELD_TYPE_SET; }
bool has_charset(void) const { return TRUE; } bool has_charset(void) const { return TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_SET; }
}; };
......
...@@ -312,7 +312,7 @@ void Item_field::set_field(Field *field_par) ...@@ -312,7 +312,7 @@ void Item_field::set_field(Field *field_par)
const char *Item_ident::full_name() const const char *Item_ident::full_name() const
{ {
char *tmp; char *tmp;
if (!table_name) if (!table_name || !field_name)
return field_name ? field_name : name ? name : "tmp_field"; return field_name ? field_name : name ? name : "tmp_field";
if (db_name && db_name[0]) if (db_name && db_name[0])
{ {
...@@ -1881,6 +1881,8 @@ void Item_cache_str::store(Item *item) ...@@ -1881,6 +1881,8 @@ void Item_cache_str::store(Item *item)
} }
collation.set(item->collation); collation.set(item->collation);
} }
double Item_cache_str::val() double Item_cache_str::val()
{ {
int err; int err;
...@@ -1890,6 +1892,8 @@ double Item_cache_str::val() ...@@ -1890,6 +1892,8 @@ double Item_cache_str::val()
else else
return (double)0; return (double)0;
} }
longlong Item_cache_str::val_int() longlong Item_cache_str::val_int()
{ {
int err; int err;
...@@ -1900,6 +1904,7 @@ longlong Item_cache_str::val_int() ...@@ -1900,6 +1904,7 @@ longlong Item_cache_str::val_int()
return (longlong)0; return (longlong)0;
} }
bool Item_cache_row::allocate(uint num) bool Item_cache_row::allocate(uint num)
{ {
item_count= num; item_count= num;
...@@ -1908,6 +1913,7 @@ bool Item_cache_row::allocate(uint num) ...@@ -1908,6 +1913,7 @@ bool Item_cache_row::allocate(uint num)
(Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count))); (Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count)));
} }
bool Item_cache_row::setup(Item * item) bool Item_cache_row::setup(Item * item)
{ {
example= item; example= item;
...@@ -1924,6 +1930,7 @@ bool Item_cache_row::setup(Item * item) ...@@ -1924,6 +1930,7 @@ bool Item_cache_row::setup(Item * item)
return 0; return 0;
} }
void Item_cache_row::store(Item * item) void Item_cache_row::store(Item * item)
{ {
null_value= 0; null_value= 0;
...@@ -1935,6 +1942,7 @@ void Item_cache_row::store(Item * item) ...@@ -1935,6 +1942,7 @@ void Item_cache_row::store(Item * item)
} }
} }
void Item_cache_row::illegal_method_call(const char *method) void Item_cache_row::illegal_method_call(const char *method)
{ {
DBUG_ENTER("Item_cache_row::illegal_method_call"); DBUG_ENTER("Item_cache_row::illegal_method_call");
...@@ -1944,6 +1952,7 @@ void Item_cache_row::illegal_method_call(const char *method) ...@@ -1944,6 +1952,7 @@ void Item_cache_row::illegal_method_call(const char *method)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
bool Item_cache_row::check_cols(uint c) bool Item_cache_row::check_cols(uint c)
{ {
if (c != item_count) if (c != item_count)
...@@ -1954,6 +1963,7 @@ bool Item_cache_row::check_cols(uint c) ...@@ -1954,6 +1963,7 @@ bool Item_cache_row::check_cols(uint c)
return 0; return 0;
} }
bool Item_cache_row::null_inside() bool Item_cache_row::null_inside()
{ {
for (uint i= 0; i < item_count; i++) for (uint i= 0; i < item_count; i++)
...@@ -1973,6 +1983,7 @@ bool Item_cache_row::null_inside() ...@@ -1973,6 +1983,7 @@ bool Item_cache_row::null_inside()
return 0; return 0;
} }
void Item_cache_row::bring_value() void Item_cache_row::bring_value()
{ {
for (uint i= 0; i < item_count; i++) for (uint i= 0; i < item_count; i++)
...@@ -1980,6 +1991,106 @@ void Item_cache_row::bring_value() ...@@ -1980,6 +1991,106 @@ void Item_cache_row::bring_value()
return; return;
} }
Item_type_holder::Item_type_holder(THD *thd, Item *item)
:Item(thd, *item), item_type(item->result_type())
{
DBUG_ASSERT(item->fixed);
/*
It is safe assign pointer on field, because it will be used just after
all JOIN::prepare calls and before any SELECT execution
*/
if (item->type() == Item::FIELD_ITEM)
field_example= ((Item_field*) item)->field;
else
field_example= 0;
}
// STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT
static Item_result type_convertor[4][4]=
{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT},
{STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT},
{STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT},
{ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}};
void Item_type_holder::join_types(THD *thd, Item *item)
{
bool change_field= 0, skip_store_field= 0;
Item_result new_type= type_convertor[item_type][item->result_type()];
// we have both fields
if (field_example && item->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field *)item)->field;
if (field_example->field_cast_type() != field->field_cast_type())
{
if (!(change_field=
field_example->field_cast_compatible(field->field_cast_type())))
{
/*
if old field can't store value of 'worse' new field we will make
decision about result field type based only on Item result type
*/
if (!field->field_cast_compatible(field_example->field_cast_type()))
skip_store_field= 1;
}
}
}
// size/type should be changed
if (change_field ||
(new_type != item_type) ||
(max_length < item->max_length) ||
((new_type == INT_RESULT) &&
(decimals < item->decimals)) ||
(!maybe_null && item->maybe_null))
{
// new field has some parameters worse then current
skip_store_field|= (change_field &&
(max_length > item->max_length) ||
((new_type == INT_RESULT) &&
(decimals > item->decimals)) ||
(maybe_null && !item->maybe_null));
/*
It is safe assign pointer on field, because it will be used just after
all JOIN::prepare calls and before any SELECT execution
*/
if (skip_store_field || item->type() != Item::FIELD_ITEM)
field_example= 0;
else
field_example= ((Item_field*) item)->field;
max_length= max(max_length, item->max_length);
decimals= max(decimals, item->decimals);
maybe_null|= item->maybe_null;
item_type= new_type;
}
DBUG_ASSERT(item_type != ROW_RESULT);
}
double Item_type_holder::val()
{
DBUG_ASSERT(0); // should never be called
return 0.0;
}
longlong Item_type_holder::val_int()
{
DBUG_ASSERT(0); // should never be called
return 0;
}
String *Item_type_holder::val_str(String*)
{
DBUG_ASSERT(0); // should never be called
return 0;
}
/***************************************************************************** /*****************************************************************************
** Instantiate templates ** Instantiate templates
*****************************************************************************/ *****************************************************************************/
......
...@@ -98,7 +98,7 @@ class Item { ...@@ -98,7 +98,7 @@ class Item {
COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM}; SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
...@@ -390,17 +390,17 @@ class Item_int :public Item ...@@ -390,17 +390,17 @@ class Item_int :public Item
public: public:
const longlong value; const longlong value;
Item_int(int32 i,uint length=11) :value((longlong) i) Item_int(int32 i,uint length=11) :value((longlong) i)
{ max_length=length;} { max_length=length; fixed= 1; }
#ifdef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG
Item_int(longlong i,uint length=21) :value(i) Item_int(longlong i,uint length=21) :value(i)
{ max_length=length;} { max_length=length; fixed= 1;}
#endif #endif
Item_int(const char *str_arg,longlong i,uint length) :value(i) Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg;} { max_length=length; name=(char*) str_arg; fixed= 1; }
Item_int(const char *str_arg) : Item_int(const char *str_arg) :
value(str_arg[0] == '-' ? strtoll(str_arg,(char**) 0,10) : value(str_arg[0] == '-' ? strtoll(str_arg,(char**) 0,10) :
(longlong) strtoull(str_arg,(char**) 0,10)) (longlong) strtoull(str_arg,(char**) 0,10))
{ max_length= (uint) strlen(str_arg); name=(char*) str_arg;} { max_length= (uint) strlen(str_arg); name=(char*) str_arg; fixed= 1; }
enum Type type() const { return INT_ITEM; } enum Type type() const { return INT_ITEM; }
enum Item_result result_type () const { return INT_RESULT; } enum Item_result result_type () const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
...@@ -988,6 +988,28 @@ class Item_cache_row: public Item_cache ...@@ -988,6 +988,28 @@ class Item_cache_row: public Item_cache
void bring_value(); void bring_value();
}; };
/*
Used to store type. name, length of Item for UNIONS & derived table
*/
class Item_type_holder: public Item
{
protected:
Item_result item_type;
Field *field_example;
public:
Item_type_holder(THD*, Item*);
Item_result result_type () const { return item_type; }
enum Type type() const { return TYPE_HOLDER; }
double val();
longlong val_int();
String *val_str(String*);
void join_types(THD *thd, Item *);
Field *example() { return field_example; }
};
extern Item_buff *new_Item_buff(Item *item); extern Item_buff *new_Item_buff(Item *item);
extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item_result item_cmp_type(Item_result a,Item_result b);
extern Item *resolve_const_item(Item *item,Item *cmp_item); extern Item *resolve_const_item(Item *item,Item *cmp_item);
......
...@@ -924,7 +924,7 @@ int subselect_single_select_engine::prepare() ...@@ -924,7 +924,7 @@ int subselect_single_select_engine::prepare()
(ORDER*) select_lex->group_list.first, (ORDER*) select_lex->group_list.first,
select_lex->having, select_lex->having,
(ORDER*) 0, select_lex, (ORDER*) 0, select_lex,
select_lex->master_unit(), 0)) select_lex->master_unit()))
return 1; return 1;
thd->lex.current_select= save_select; thd->lex.current_select= save_select;
return 0; return 0;
...@@ -932,7 +932,7 @@ int subselect_single_select_engine::prepare() ...@@ -932,7 +932,7 @@ int subselect_single_select_engine::prepare()
int subselect_union_engine::prepare() int subselect_union_engine::prepare()
{ {
return unit->prepare(thd, result, 0); return unit->prepare(thd, result);
} }
int subselect_uniquesubquery_engine::prepare() int subselect_uniquesubquery_engine::prepare()
...@@ -942,12 +942,12 @@ int subselect_uniquesubquery_engine::prepare() ...@@ -942,12 +942,12 @@ int subselect_uniquesubquery_engine::prepare()
return 1; return 1;
} }
static Item_result set_row(SELECT_LEX *select_lex, Item * item, static Item_result set_row(List<Item> &item_list, Item *item,
Item_cache **row, bool *maybe_null) Item_cache **row, bool *maybe_null)
{ {
Item_result res_type= STRING_RESULT; Item_result res_type= STRING_RESULT;
Item *sel_item; Item *sel_item;
List_iterator_fast<Item> li(select_lex->item_list); List_iterator_fast<Item> li(item_list);
for (uint i= 0; (sel_item= li++); i++) for (uint i= 0; (sel_item= li++); i++)
{ {
item->max_length= sel_item->max_length; item->max_length= sel_item->max_length;
...@@ -962,7 +962,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item, ...@@ -962,7 +962,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item,
row[i]->collation.set(sel_item->collation); row[i]->collation.set(sel_item->collation);
} }
} }
if (select_lex->item_list.elements > 1) if (item_list.elements > 1)
res_type= ROW_RESULT; res_type= ROW_RESULT;
return res_type; return res_type;
} }
...@@ -970,7 +970,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item, ...@@ -970,7 +970,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item,
void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) void subselect_single_select_engine::fix_length_and_dec(Item_cache **row)
{ {
DBUG_ASSERT(row || select_lex->item_list.elements==1); DBUG_ASSERT(row || select_lex->item_list.elements==1);
res_type= set_row(select_lex, item, row, &maybe_null); res_type= set_row(select_lex->item_list, item, row, &maybe_null);
item->collation.set(row[0]->collation); item->collation.set(row[0]->collation);
if (cols() != 1) if (cols() != 1)
maybe_null= 0; maybe_null= 0;
...@@ -981,44 +981,11 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) ...@@ -981,44 +981,11 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
DBUG_ASSERT(row || unit->first_select()->item_list.elements==1); DBUG_ASSERT(row || unit->first_select()->item_list.elements==1);
if (unit->first_select()->item_list.elements == 1) if (unit->first_select()->item_list.elements == 1)
{ res_type= set_row(unit->types, item, row, &maybe_null);
uint32 mlen= 0, len;
Item *sel_item= 0;
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
{
List_iterator_fast<Item> li(sl->item_list);
Item *s_item= li++;
if ((len= s_item->max_length) > mlen)
mlen= len;
if (!sel_item)
sel_item= s_item;
maybe_null= s_item->maybe_null;
}
item->max_length= mlen;
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
if (row)
{
if (!(row[0]= Item_cache::get_cache(res_type)))
return;
row[0]->set_len_n_dec(mlen, sel_item->decimals);
}
}
else else
{ {
SELECT_LEX *sl= unit->first_select();
bool fake= 0; bool fake= 0;
res_type= set_row(sl, item, row, &fake); res_type= set_row(unit->types, item, row, &fake);
for (sl= sl->next_select(); sl; sl= sl->next_select())
{
List_iterator_fast<Item> li(sl->item_list);
Item *sel_item;
for (uint i= 0; (sel_item= li++); i++)
{
if (sel_item->max_length > row[i]->max_length)
row[i]->max_length= sel_item->max_length;
}
}
} }
} }
......
...@@ -482,7 +482,7 @@ int mysql_select(THD *thd, Item ***rref_pointer_array, ...@@ -482,7 +482,7 @@ int mysql_select(THD *thd, Item ***rref_pointer_array,
COND *conds, uint og_num, ORDER *order, ORDER *group, COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulong select_type, Item *having, ORDER *proc_param, ulong select_type,
select_result *result, SELECT_LEX_UNIT *unit, select_result *result, SELECT_LEX_UNIT *unit,
SELECT_LEX *select_lex, bool tables_and_fields_initied); SELECT_LEX *select_lex);
void free_underlaid_joins(THD *thd, SELECT_LEX *select); void free_underlaid_joins(THD *thd, SELECT_LEX *select);
void fix_tables_pointers(SELECT_LEX *select_lex); void fix_tables_pointers(SELECT_LEX *select_lex);
void fix_tables_pointers(SELECT_LEX_UNIT *select_lex); void fix_tables_pointers(SELECT_LEX_UNIT *select_lex);
...@@ -491,7 +491,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, ...@@ -491,7 +491,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type, int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result); select_result *result);
int mysql_union(THD *thd, LEX *lex, select_result *result, int mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit, bool tables_and_fields_initied); SELECT_LEX_UNIT *unit);
int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t); int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field, Item ***copy_func, Field **from_field,
...@@ -675,7 +675,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ...@@ -675,7 +675,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
List<Item> &item, bool set_query_id, List<Item> &item, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func); List<Item> *sum_func_list, bool allow_sum_func);
void unfix_item_list(List<Item> item_list);
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
int setup_ftfuncs(SELECT_LEX* select); int setup_ftfuncs(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
......
...@@ -908,7 +908,12 @@ int load_master_data(THD* thd) ...@@ -908,7 +908,12 @@ int load_master_data(THD* thd)
// don't hit the magic number // don't hit the magic number
if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE) if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE; active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
flush_master_info(active_mi); /*
Relay log's IO_CACHE may not be inited (even if we are sure that some
host was specified; there could have been a problem when replication
started, which led to relay log's IO_CACHE to not be inited.
*/
flush_master_info(active_mi, 0);
} }
mysql_free_result(master_status_res); mysql_free_result(master_status_res);
} }
......
...@@ -1107,7 +1107,7 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi) ...@@ -1107,7 +1107,7 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
break; break;
default: default:
/* 5.0 is not supported */ /* 5.0 is not supported */
errmsg = "Master reported an unrecognized MySQL version. Note that 4.0 \ errmsg = "Master reported an unrecognized MySQL version. Note that 4.1 \
slaves can't replicate a 5.0 or newer master."; slaves can't replicate a 5.0 or newer master.";
break; break;
} }
...@@ -1368,32 +1368,9 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) ...@@ -1368,32 +1368,9 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
} }
/* /*
The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. It is The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
notable that the last kilobytes of it (8 kB for example) may live in Note that the I/O thread flushes it to disk after writing every event, in
memory, not on disk (depending on what the thread using it does). While flush_master_info(mi, 1).
this is efficient, it has a side-effect one must know:
The size of the relay log on disk (displayed by 'ls -l' on Unix) can be a
few kilobytes less than one would expect by doing SHOW SLAVE STATUS; this
happens when only the IO thread is started (not the SQL thread). The
"missing" kilobytes are in memory, are preserved during 'STOP SLAVE; START
SLAVE IO_THREAD', and are flushed to disk when the slave's mysqld stops. So
this does not cause any bug. Example of how disk size grows by leaps:
Read_Master_Log_Pos: 7811 -rw-rw---- 1 guilhem qq 4 Jun 5 16:19 gbichot2-relay-bin.002
...later...
Read_Master_Log_Pos: 9744 -rw-rw---- 1 guilhem qq 8192 Jun 5 16:27 gbichot2-relay-bin.002
See how 4 is less than 7811 and 8192 is less than 9744.
WARNING: this is risky because the slave can stay like this for a long
time; then if it has a power failure, master.info says the I/O thread has
read until 9744 while the relay-log contains only until 8192 (the
in-memory part from 8192 to 9744 has been lost), so the SQL slave thread
will miss some events, silently breaking replication.
Ideally we would like to flush master.info only when we know that the relay
log has no in-memory tail.
Note that the above problem may arise only when only the IO thread is
started, which is unlikely.
*/ */
/* /*
...@@ -1850,7 +1827,7 @@ file '%s')", fname); ...@@ -1850,7 +1827,7 @@ file '%s')", fname);
mi->inited = 1; mi->inited = 1;
// now change cache READ -> WRITE - must do this before flush_master_info // now change cache READ -> WRITE - must do this before flush_master_info
reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1); reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
if ((error=test(flush_master_info(mi)))) if ((error=test(flush_master_info(mi, 1))))
sql_print_error("Failed to flush master info file"); sql_print_error("Failed to flush master info file");
pthread_mutex_unlock(&mi->data_lock); pthread_mutex_unlock(&mi->data_lock);
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -2100,7 +2077,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi) ...@@ -2100,7 +2077,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
} }
bool flush_master_info(MASTER_INFO* mi) bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
{ {
IO_CACHE* file = &mi->file; IO_CACHE* file = &mi->file;
char lbuf[22]; char lbuf[22];
...@@ -2124,6 +2101,20 @@ bool flush_master_info(MASTER_INFO* mi) ...@@ -2124,6 +2101,20 @@ bool flush_master_info(MASTER_INFO* mi)
(int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
mi->ssl_cipher, mi->ssl_key); mi->ssl_cipher, mi->ssl_key);
flush_io_cache(file); flush_io_cache(file);
/*
Flush the relay log to disk. If we don't do it, then the relay log while
have some part (its last kilobytes) in memory only, so if the slave server
dies now, with, say, from master's position 100 to 150 in memory only (not
on disk), and with position 150 in master.info, then when the slave
restarts, the I/O thread will fetch binlogs from 150, so in the relay log
we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
SQL thread will jump from 100 to 150, and replication will silently break.
When we come to this place in code, relay log may or not be initialized;
the caller is responsible for setting 'flush_relay_log_cache' accordingly.
*/
if (flush_relay_log_cache)
flush_io_cache(mi->rli.relay_log.get_log_file());
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -2982,7 +2973,7 @@ reconnect done to recover from failed read"); ...@@ -2982,7 +2973,7 @@ reconnect done to recover from failed read");
sql_print_error("Slave I/O thread could not queue event from master"); sql_print_error("Slave I/O thread could not queue event from master");
goto err; goto err;
} }
flush_master_info(mi); flush_master_info(mi, 1); /* sure that we can flush the relay log */
/* /*
See if the relay logs take too much space. See if the relay logs take too much space.
We don't lock mi->rli.log_space_lock here; this dirty read saves time We don't lock mi->rli.log_space_lock here; this dirty read saves time
......
...@@ -461,7 +461,7 @@ typedef struct st_table_rule_ent ...@@ -461,7 +461,7 @@ typedef struct st_table_rule_ent
int init_slave(); int init_slave();
void init_slave_skip_errors(const char* arg); void init_slave_skip_errors(const char* arg);
bool flush_master_info(MASTER_INFO* mi); bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache);
bool flush_relay_log_info(RELAY_LOG_INFO* rli); bool flush_relay_log_info(RELAY_LOG_INFO* rli);
int register_slave_on_master(MYSQL* mysql); int register_slave_on_master(MYSQL* mysql);
int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
......
...@@ -2023,20 +2023,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ...@@ -2023,20 +2023,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
DBUG_RETURN(test(thd->net.report_error)); DBUG_RETURN(test(thd->net.report_error));
} }
/*
Mark all items in list as not fixed (0 assigned to 'fixed' field)
SYNOPSYS
unfix_item_list()
item_list - list of items
*/
void unfix_item_list(List<Item> item_list)
{
Item *item;
List_iterator_fast<Item> it(item_list);
while ((item= it++))
item->walk(&Item::remove_fixed, 0);
}
/* /*
Remap table numbers if INSERT ... SELECT Remap table numbers if INSERT ... SELECT
......
...@@ -946,6 +946,7 @@ class select_union :public select_result { ...@@ -946,6 +946,7 @@ class select_union :public select_result {
bool send_data(List<Item> &items); bool send_data(List<Item> &items);
bool send_eof(); bool send_eof();
bool flush(); bool flush();
void set_table(TABLE *tbl) { table= tbl; }
}; };
/* Base subselect interface class */ /* Base subselect interface class */
......
...@@ -62,16 +62,15 @@ ...@@ -62,16 +62,15 @@
int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
TABLE_LIST *org_table_list) TABLE_LIST *org_table_list)
{ {
SELECT_LEX *select_cursor= unit->first_select(); SELECT_LEX *first_select= unit->first_select();
List<Item> item_list;
TABLE *table; TABLE *table;
int res; int res;
select_union *derived_result; select_union *derived_result;
TABLE_LIST *tables= (TABLE_LIST *)select_cursor->table_list.first; TABLE_LIST *tables= (TABLE_LIST *)first_select->table_list.first;
TMP_TABLE_PARAM tmp_table_param; TMP_TABLE_PARAM tmp_table_param;
bool is_union= select_cursor->next_select() && bool is_union= first_select->next_select() &&
select_cursor->next_select()->linkage == UNION_TYPE; first_select->next_select()->linkage == UNION_TYPE;
bool is_subsel= select_cursor->first_inner_unit() ? 1: 0; bool is_subsel= first_select->first_inner_unit() ? 1: 0;
SELECT_LEX *save_current_select= lex->current_select; SELECT_LEX *save_current_select= lex->current_select;
DBUG_ENTER("mysql_derived"); DBUG_ENTER("mysql_derived");
...@@ -112,16 +111,12 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, ...@@ -112,16 +111,12 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
fix_tables_pointers(unit); fix_tables_pointers(unit);
} }
lex->current_select= select_cursor; if(!(derived_result= new select_union(0)))
TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first; DBUG_RETURN(1); // out of memory
/* Setting up. A must if a join or IGNORE, USE or similar are utilised */
if (setup_tables(first_table) || // st_select_lex_unit::prepare correctly work for single select
setup_wild(thd, first_table, select_cursor->item_list, 0, if ((res= unit->prepare(thd, derived_result)))
select_cursor->with_wild))
{
res= -1;
goto exit; goto exit;
}
/* /*
This is done in order to redo all field optimisations when any of the This is done in order to redo all field optimisations when any of the
...@@ -133,30 +128,16 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, ...@@ -133,30 +128,16 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
cursor->table->clear_query_id= 1; cursor->table->clear_query_id= 1;
} }
item_list= select_cursor->item_list;
select_cursor->with_wild= 0;
if (select_cursor->setup_ref_array(thd,
select_cursor->order_list.elements +
select_cursor->group_list.elements) ||
setup_fields(thd, select_cursor->ref_pointer_array, first_table,
item_list, 0, 0, 1))
{
res= -1;
goto exit;
}
// Item list should be fix_fielded yet another time in JOIN::prepare
unfix_item_list(item_list);
bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count= item_list.elements; tmp_table_param.field_count= unit->types.elements;
/* /*
Temp table is created so that it hounours if UNION without ALL is to be Temp table is created so that it hounours if UNION without ALL is to be
processed processed
*/ */
if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, if (!(table= create_tmp_table(thd, &tmp_table_param, unit->types,
(ORDER*) 0, (ORDER*) 0,
is_union && !unit->union_option, 1, is_union && !unit->union_option, 1,
(select_cursor->options | thd->options | (first_select->options | thd->options |
TMP_TABLE_ALL_COLUMNS), TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR, HA_POS_ERROR,
org_table_list->alias))) org_table_list->alias)))
...@@ -164,70 +145,69 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, ...@@ -164,70 +145,69 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
res= -1; res= -1;
goto exit; goto exit;
} }
derived_result->set_table(table);
if ((derived_result=new select_union(table))) derived_result->tmp_table_param=tmp_table_param;
unit->offset_limit_cnt= first_select->offset_limit;
unit->select_limit_cnt= first_select->select_limit+
first_select->offset_limit;
if (unit->select_limit_cnt < first_select->select_limit)
unit->select_limit_cnt= HA_POS_ERROR;
if (unit->select_limit_cnt == HA_POS_ERROR)
first_select->options&= ~OPTION_FOUND_ROWS;
if (is_union)
res= mysql_union(thd, lex, derived_result, unit);
else
res= mysql_select(thd, &first_select->ref_pointer_array,
(TABLE_LIST*) first_select->table_list.first,
first_select->with_wild,
first_select->item_list, first_select->where,
(first_select->order_list.elements+
first_select->group_list.elements),
(ORDER *) first_select->order_list.first,
(ORDER *) first_select->group_list.first,
first_select->having, (ORDER*) NULL,
(first_select->options | thd->options |
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
if (!res)
{ {
derived_result->tmp_table_param=tmp_table_param; /*
unit->offset_limit_cnt= select_cursor->offset_limit; Here we entirely fix both TABLE_LIST and list of SELECT's as
unit->select_limit_cnt= select_cursor->select_limit+ there were no derived tables
select_cursor->offset_limit; */
if (unit->select_limit_cnt < select_cursor->select_limit) if (derived_result->flush())
unit->select_limit_cnt= HA_POS_ERROR; res= 1;
if (unit->select_limit_cnt == HA_POS_ERROR)
select_cursor->options&= ~OPTION_FOUND_ROWS;
if (is_union)
res= mysql_union(thd, lex, derived_result, unit, 1);
else else
res= mysql_select(thd, &select_cursor->ref_pointer_array,
(TABLE_LIST*) select_cursor->table_list.first,
select_cursor->with_wild,
select_cursor->item_list, select_cursor->where,
(select_cursor->order_list.elements+
select_cursor->group_list.elements),
(ORDER *) select_cursor->order_list.first,
(ORDER *) select_cursor->group_list.first,
select_cursor->having, (ORDER*) NULL,
(select_cursor->options | thd->options |
SELECT_NO_UNLOCK),
derived_result, unit, select_cursor, 1);
if (!res)
{ {
/* org_table_list->real_name=table->real_name;
Here we entirely fix both TABLE_LIST and list of SELECT's as org_table_list->table=table;
there were no derived tables table->derived_select_number= first_select->select_number;
*/ table->tmp_table= TMP_TABLE;
if (derived_result->flush())
res= 1;
else
{
org_table_list->real_name=table->real_name;
org_table_list->table=table;
table->derived_select_number= select_cursor->select_number;
table->tmp_table= TMP_TABLE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
org_table_list->grant.privilege= SELECT_ACL; org_table_list->grant.privilege= SELECT_ACL;
#endif #endif
if (lex->describe) if (lex->describe)
{
// to fix a problem in EXPLAIN
if (tables)
{ {
// to fix a problem in EXPLAIN for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
if (tables) if (cursor->table_list)
{ cursor->table_list->table=cursor->table;
for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
if (cursor->table_list)
cursor->table_list->table=cursor->table;
}
} }
else
unit->exclude_tree();
org_table_list->db= (char *)"";
// Force read of table stats in the optimizer
table->file->info(HA_STATUS_VARIABLE);
} }
else
unit->exclude_tree();
org_table_list->db= (char *)"";
// Force read of table stats in the optimizer
table->file->info(HA_STATUS_VARIABLE);
} }
delete derived_result;
} }
delete derived_result;
if (res) if (res)
free_tmp_table(thd, table); free_tmp_table(thd, table);
else else
......
...@@ -295,7 +295,6 @@ class JOIN; ...@@ -295,7 +295,6 @@ class JOIN;
class select_union; class select_union;
class st_select_lex_unit: public st_select_lex_node { class st_select_lex_unit: public st_select_lex_node {
protected: protected:
List<Item> item_list;
TABLE_LIST result_table_list; TABLE_LIST result_table_list;
select_union *union_result; select_union *union_result;
TABLE *table; /* temporary table using for appending UNION results */ TABLE *table; /* temporary table using for appending UNION results */
...@@ -305,9 +304,19 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -305,9 +304,19 @@ class st_select_lex_unit: public st_select_lex_node {
ulong found_rows_for_union; ulong found_rows_for_union;
bool prepared, // prepare phase already performed for UNION (unit) bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit)
executed, // already executed executed; // already executed
t_and_f; // used for transferring tables_and_fields_initied UNIT:: methods
public: public:
// list of fields which points to temporary table for union
List<Item> item_list;
/*
list of types of items inside union (used for union & derived tables)
Item_type_holders from which this list consist may have pointers to Field,
pointers is valid only after preparing SELECTS of this unit and before
any SELECT of this unit execution
*/
List<Item> types;
/* /*
Pointer to 'last' select or pointer to unit where stored Pointer to 'last' select or pointer to unit where stored
global parameters for union global parameters for union
...@@ -342,7 +351,7 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -342,7 +351,7 @@ class st_select_lex_unit: public st_select_lex_node {
void exclude_tree(); void exclude_tree();
/* UNION methods */ /* UNION methods */
int prepare(THD *thd, select_result *result, bool tables_and_fields_initied); int prepare(THD *thd, select_result *result);
int exec(); int exec();
int cleanup(); int cleanup();
......
...@@ -2716,7 +2716,7 @@ mysql_execute_command(THD *thd) ...@@ -2716,7 +2716,7 @@ mysql_execute_command(THD *thd)
(ORDER *)NULL, (ORDER *)NULL,
select_lex->options | thd->options | select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK, SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
result, unit, select_lex, 0); result, unit, select_lex);
if (thd->net.report_error) if (thd->net.report_error)
res= -1; res= -1;
delete result; delete result;
......
...@@ -682,7 +682,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, ...@@ -682,7 +682,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
if (join->prepare(&select_lex->ref_pointer_array, tables, if (join->prepare(&select_lex->ref_pointer_array, tables,
wild_num, conds, og_num, order, group, having, proc, wild_num, conds, og_num, order, group, having, proc,
select_lex, unit, 0)) select_lex, unit))
DBUG_RETURN(1); DBUG_RETURN(1);
if (send_prep_stmt(stmt, fields.elements) || if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0) || thd->protocol_simple.send_fields(&fields, 0) ||
......
...@@ -1085,8 +1085,11 @@ int change_master(THD* thd, MASTER_INFO* mi) ...@@ -1085,8 +1085,11 @@ int change_master(THD* thd, MASTER_INFO* mi)
strmake(mi->master_log_name, mi->rli.group_master_log_name, strmake(mi->master_log_name, mi->rli.group_master_log_name,
sizeof(mi->master_log_name)-1); sizeof(mi->master_log_name)-1);
} }
/*
flush_master_info(mi); Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never
a slave before).
*/
flush_master_info(mi, 0);
if (need_relay_log_purge) if (need_relay_log_purge)
{ {
relay_log_purge= 1; relay_log_purge= 1;
......
This diff is collapsed.
...@@ -266,7 +266,7 @@ class JOIN :public Sql_alloc ...@@ -266,7 +266,7 @@ class JOIN :public Sql_alloc
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group, COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, SELECT_LEX *select, Item *having, ORDER *proc_param, SELECT_LEX *select,
SELECT_LEX_UNIT *unit, bool tables_and_fields_initied); SELECT_LEX_UNIT *unit);
int optimize(); int optimize();
int reinit(); int reinit();
void exec(); void exec();
......
...@@ -25,11 +25,11 @@ ...@@ -25,11 +25,11 @@
#include "sql_select.h" #include "sql_select.h"
int mysql_union(THD *thd, LEX *lex, select_result *result, int mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit, bool tables_and_fields_initied) SELECT_LEX_UNIT *unit)
{ {
DBUG_ENTER("mysql_union"); DBUG_ENTER("mysql_union");
int res= 0; int res= 0;
if (!(res= unit->prepare(thd, result, tables_and_fields_initied))) if (!(res= unit->prepare(thd, result)))
res= unit->exec(); res= unit->exec();
res|= unit->cleanup(); res|= unit->cleanup();
DBUG_RETURN(res); DBUG_RETURN(res);
...@@ -59,12 +59,6 @@ select_union::~select_union() ...@@ -59,12 +59,6 @@ select_union::~select_union()
int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{ {
unit= u; unit= u;
if (not_describe && list.elements != table->fields)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
return -1;
}
return 0; return 0;
} }
...@@ -112,11 +106,11 @@ bool select_union::flush() ...@@ -112,11 +106,11 @@ bool select_union::flush()
} }
int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, int st_select_lex_unit::prepare(THD *thd, select_result *sel_result)
bool tables_and_fields_initied)
{ {
SELECT_LEX *lex_select_save= thd->lex.current_select; SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor,*sl; SELECT_LEX *sl, *first_select;
select_result *tmp_result;
DBUG_ENTER("st_select_lex_unit::prepare"); DBUG_ENTER("st_select_lex_unit::prepare");
/* /*
...@@ -129,74 +123,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, ...@@ -129,74 +123,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
DBUG_RETURN(0); DBUG_RETURN(0);
prepared= 1; prepared= 1;
res= 0; res= 0;
found_rows_for_union= first_select_in_union()->options & OPTION_FOUND_ROWS;
TMP_TABLE_PARAM tmp_table_param; TMP_TABLE_PARAM tmp_table_param;
t_and_f= tables_and_fields_initied;
bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM)); bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM));
thd->lex.current_select= sl= select_cursor= first_select_in_union(); thd->lex.current_select= sl= first_select= first_select_in_union();
found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
/* Global option */ /* Global option */
if (t_and_f)
if (first_select->next_select())
{ {
// Item list and tables will be initialized by mysql_derived if (!(tmp_result= union_result= new select_union(0)))
item_list= select_cursor->item_list; goto err;
union_result->not_describe= 1;
union_result->tmp_table_param= tmp_table_param;
} }
else else
{ {
item_list.empty(); tmp_result= sel_result;
TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first; // single select should be processed like select in p[arantses
first_select->braces= 1;
if (setup_tables(first_table) ||
setup_wild(thd, first_table, select_cursor->item_list, 0,
select_cursor->with_wild))
goto err;
List_iterator<Item> it(select_cursor->item_list);
Item *item;
item_list= select_cursor->item_list;
select_cursor->with_wild= 0;
if (select_cursor->setup_ref_array(thd,
select_cursor->order_list.elements +
select_cursor->group_list.elements) ||
setup_fields(thd, select_cursor->ref_pointer_array, first_table,
item_list, 0, 0, 1))
goto err;
// Item list should be fix_fielded yet another time in JOIN::prepare
unfix_item_list(item_list);
t_and_f= 1;
while((item=it++))
{
item->maybe_null=1;
if (item->type() == Item::FIELD_ITEM)
((class Item_field *)item)->field->table->maybe_null=1;
}
} }
tmp_table_param.field_count=item_list.elements;
if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
(ORDER*) 0, !union_option,
1, (select_cursor->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR, (char*) "")))
goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
bzero((char*) &result_table_list,sizeof(result_table_list));
result_table_list.db= (char*) "";
result_table_list.real_name=result_table_list.alias= (char*) "union";
result_table_list.table=table;
if (!(union_result=new select_union(table)))
goto err;
union_result->not_describe=1;
union_result->tmp_table_param=tmp_table_param;
for (;sl; sl= sl->next_select()) for (;sl; sl= sl->next_select())
{ {
JOIN *join= new JOIN(thd, sl->item_list, JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK, sl->options | thd->options | SELECT_NO_UNLOCK,
union_result); tmp_result);
thd->lex.current_select= sl; thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit; offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit; select_limit_cnt= sl->select_limit+sl->offset_limit;
...@@ -215,27 +168,76 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, ...@@ -215,27 +168,76 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
(ORDER*) sl->group_list.first, (ORDER*) sl->group_list.first,
sl->having, sl->having,
(ORDER*) NULL, (ORDER*) NULL,
sl, this, t_and_f); sl, this);
t_and_f= 0;
if (res || thd->is_fatal_error) if (res || thd->is_fatal_error)
goto err; goto err;
if (sl == first_select)
{
types.empty();
List_iterator_fast<Item> it(sl->item_list);
Item *item;
while((item= it++))
{
types.push_back(new Item_type_holder(thd, item));
}
if (thd->is_fatal_error)
goto err; // out of memory
}
else
{
if (types.elements != sl->item_list.elements)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
goto err;
}
List_iterator_fast<Item> it(sl->item_list);
List_iterator_fast<Item> tp(types);
Item *type, *item;
while((type= tp++, item= it++))
{
((Item_type_holder*)type)->join_types(thd, item);
}
}
} }
item_list.empty(); if (first_select->next_select())
thd->lex.current_select= lex_select_save;
{ {
List_iterator<Item> it(select_cursor->item_list); tmp_table_param.field_count= types.elements;
Field **field; if (!(table= create_tmp_table(thd, &tmp_table_param, types,
(ORDER*) 0, !union_option, 1,
(first_select_in_union()->options |
thd->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR, (char*) "")))
goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
bzero((char*) &result_table_list, sizeof(result_table_list));
result_table_list.db= (char*) "";
result_table_list.real_name= result_table_list.alias= (char*) "union";
result_table_list.table= table;
union_result->set_table(table);
for (field= table->field; *field; field++) item_list.empty();
thd->lex.current_select= lex_select_save;
{ {
(void) it++; Field **field;
if (item_list.push_back(new Item_field(*field))) for (field= table->field; *field; field++)
DBUG_RETURN(-1); {
if (item_list.push_back(new Item_field(*field)))
DBUG_RETURN(-1);
}
} }
} }
else
first_select->braces= 0; // remove our changes
thd->lex.current_select= lex_select_save;
DBUG_RETURN(res || thd->is_fatal_error ? 1 : 0); DBUG_RETURN(res || thd->is_fatal_error ? 1 : 0);
err: err:
thd->lex.current_select= lex_select_save; thd->lex.current_select= lex_select_save;
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -419,7 +421,7 @@ int st_select_lex_unit::exec() ...@@ -419,7 +421,7 @@ int st_select_lex_unit::exec()
(ORDER*)global_parameters->order_list.first, (ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL, (ORDER*) NULL, NULL, (ORDER*) NULL,
options | SELECT_NO_UNLOCK, options | SELECT_NO_UNLOCK,
result, this, fake_select_lex, 0); result, this, fake_select_lex);
if (!res) if (!res)
thd->limit_found_rows = (ulonglong)table->file->records + add_rows; thd->limit_found_rows = (ulonglong)table->file->records + add_rows;
/* /*
......
...@@ -461,7 +461,7 @@ int mysql_multi_update(THD *thd, ...@@ -461,7 +461,7 @@ int mysql_multi_update(THD *thd,
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
(ORDER *)NULL, (ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK, options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
result, unit, select_lex, 0); result, unit, select_lex);
delete result; delete result;
DBUG_RETURN(res); DBUG_RETURN(res);
} }
......
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