From e4efb4a521b98355346b164431ef19108894f396 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Fri, 21 Dec 2007 12:44:24 +0200 Subject: [PATCH 1/3] Bug #33256: CREATE ... SELECT creates obsolete table w/ Field_date instead of Field_newdate Field_date was still used in temp table creation. Fixed by using Field_newdate consistently throughout the server except when reading tables defined with older MySQL version. No test suite is possible because both Field_date and Field_newdate return the same values in all the metadata calls. --- mysql-test/r/type_decimal.result | 4 ---- sql/field.h | 4 ++++ sql/item.cc | 2 +- sql/item_sum.cc | 2 +- sql/item_timefunc.cc | 2 +- sql/item_timefunc.h | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index a438755ce6b..a2ccf042165 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -786,10 +786,6 @@ from (select 1 as s,'t' as t union select null, null ) as sub1; select group_concat(t) from t1 group by week(date)/10; group_concat(t) t -Warnings: -Warning 1292 Truncated incorrect datetime value: '0000-00-00' -Warning 1292 Truncated incorrect datetime value: '0000-00-00' -Warning 1292 Truncated incorrect datetime value: '0000-00-00' drop table t1; CREATE TABLE t1 ( qty decimal(16,6) default NULL, diff --git a/sql/field.h b/sql/field.h index e5c473ed556..476ca797fa0 100644 --- a/sql/field.h +++ b/sql/field.h @@ -961,6 +961,10 @@ public: :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, cs) {} + Field_newdate(bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg, cs) {} enum_field_types type() const { return FIELD_TYPE_DATE;} enum_field_types real_type() const { return FIELD_TYPE_NEWDATE; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } diff --git a/sql/item.cc b/sql/item.cc index 2d49c7b6d60..cafa40ecbb0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4384,7 +4384,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) name, table, 0, unsigned_flag); case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_DATE: - return new Field_date(maybe_null, name, table, &my_charset_bin); + return new Field_newdate(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_TIME: return new Field_time(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_TIMESTAMP: diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 7d00de493aa..3d261dc2c36 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -628,7 +628,7 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, */ switch (args[0]->field_type()) { case MYSQL_TYPE_DATE: - return new Field_date(maybe_null, name, table, collation.collation); + return new Field_newdate(maybe_null, name, table, collation.collation); case MYSQL_TYPE_TIME: return new Field_time(maybe_null, name, table, collation.collation); case MYSQL_TYPE_TIMESTAMP: diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 04060d190a0..0cb3c963dad 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3303,7 +3303,7 @@ Field *Item_func_str_to_date::tmp_table_field(TABLE *t_arg) if (cached_field_type == MYSQL_TYPE_TIME) return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); if (cached_field_type == MYSQL_TYPE_DATE) - return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_newdate(maybe_null, name, t_arg, &my_charset_bin)); if (cached_field_type == MYSQL_TYPE_DATETIME) return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin)); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index b647e93b700..7960c03d2e5 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -340,7 +340,7 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_newdate(maybe_null, name, t_arg, &my_charset_bin)); } bool result_as_longlong() { return TRUE; } my_decimal *val_decimal(my_decimal *decimal_value) @@ -784,7 +784,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_newdate(maybe_null, name, t_arg, &my_charset_bin)); } void fix_length_and_dec() { @@ -884,7 +884,7 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_newdate(maybe_null, name, t_arg, &my_charset_bin)); } longlong val_int(); my_decimal *val_decimal(my_decimal *decimal_value) From ce111a0d734951a363e2f44670e0e40100d7f757 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 9 Jan 2008 00:40:41 +0300 Subject: [PATCH 2/3] Bug#33675: Usage of an uninitialized memory by filesort in a subquery caused server crash. The filesort implementation has an optimization for subquery execution which consists of reusing previously allocated buffers. In particular the call to the read_buffpek_from_file function might be skipped when a big enough buffer for buffer descriptors (buffpeks) is already allocated. Beside allocating memory for buffpeks this function fills allocated buffer with data read from disk. Skipping it might led to using an arbitrary memory as fields' data and finally to a crash. Now the read_buffpek_from_file function is always called. It allocates new buffer only when necessary, but always fill it with correct data. --- mysql-test/r/subselect.result | 9 +++++++++ mysql-test/t/subselect.test | 22 ++++++++++++++++++++++ sql/filesort.cc | 22 +++++++++++++--------- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f6487ae3ddf..75df77b0790 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4383,4 +4383,13 @@ SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a) UNION ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION (SELECT 1 FROM t2 WHERE t1.a = t2.a))' at line 2 DROP TABLE t1,t2; +create table t1(f11 int, f12 int); +create table t2(f21 int unsigned not null, f22 int, f23 varchar(10)); +insert into t1 values(1,1),(2,2), (3, 3); +set session sort_buffer_size= 33*1024; +select count(*) from t1 where f12 = +(select f22 from t2 where f22 = f12 order by f21 desc, f22, f23 limit 1); +count(*) +3 +drop table t1,t2; End of 5.0 tests. diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ea080964058..88e4f683e9e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3230,4 +3230,26 @@ SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a) UNION DROP TABLE t1,t2; +# +# Bug#33675: Usage of an uninitialized memory by filesort in a subquery +# caused server crash. +# +create table t1(f11 int, f12 int); +create table t2(f21 int unsigned not null, f22 int, f23 varchar(10)); +insert into t1 values(1,1),(2,2), (3, 3); +let $i=10000; +--disable_query_log +--disable_warnings +while ($i) +{ + eval insert into t2 values (-1 , $i/5000 + 1, '$i'); + dec $i; +} +--enable_warnings +--enable_query_log +set session sort_buffer_size= 33*1024; +select count(*) from t1 where f12 = +(select f22 from t2 where f22 = f12 order by f21 desc, f22, f23 limit 1); + +drop table t1,t2; --echo End of 5.0 tests. diff --git a/sql/filesort.cc b/sql/filesort.cc index 08ffa2211fa..5a8e3627758 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -37,7 +37,8 @@ if (my_b_write((file),(byte*) (from),param->ref_length)) \ static char **make_char_array(char **old_pos, register uint fields, uint length, myf my_flag); -static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffer_file, uint count); +static byte *read_buffpek_from_file(IO_CACHE *buffer_file, uint count, + byte *buf); static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select, uchar * *sort_keys, IO_CACHE *buffer_file, IO_CACHE *tempfile,IO_CACHE *indexfile); @@ -238,9 +239,10 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, } else { - if (!table_sort.buffpek && table_sort.buffpek_len < maxbuffer && - !(table_sort.buffpek= - (byte *) read_buffpek_from_file(&buffpek_pointers, maxbuffer))) + if (!(table_sort.buffpek= + read_buffpek_from_file(&buffpek_pointers, maxbuffer, + (table_sort.buffpek_len < maxbuffer ? + NULL : table_sort.buffpek)))) goto err; buffpek= (BUFFPEK *) table_sort.buffpek; table_sort.buffpek_len= maxbuffer; @@ -368,18 +370,20 @@ static char **make_char_array(char **old_pos, register uint fields, /* Read 'count' number of buffer pointers into memory */ -static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count) +static byte *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count, + byte *buf) { - ulong length; - BUFFPEK *tmp; + ulong length= sizeof(BUFFPEK)*count; + byte *tmp= buf; DBUG_ENTER("read_buffpek_from_file"); if (count > UINT_MAX/sizeof(BUFFPEK)) return 0; /* sizeof(BUFFPEK)*count will overflow */ - tmp=(BUFFPEK*) my_malloc(length=sizeof(BUFFPEK)*count, MYF(MY_WME)); + if (!tmp) + tmp= (byte *)my_malloc(length, MYF(MY_WME)); if (tmp) { if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) || - my_b_read(buffpek_pointers, (byte*) tmp, length)) + my_b_read(buffpek_pointers, tmp, length)) { my_free((char*) tmp, MYF(0)); tmp=0; From 2fc45f017d511ea2386a8c0417eadeab849f3de6 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Wed, 9 Jan 2008 16:49:13 +0200 Subject: [PATCH 3/3] Bug #33133: Views are not transparent When resolving references we need to take into consideration the view "fields" and allow qualified access to them. Fixed by extending the reference resolution to process view fields correctly. --- mysql-test/r/func_group.result | 12 ++++++++++++ mysql-test/t/func_group.test | 15 +++++++++++++++ sql/sql_base.cc | 31 ++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 1e130877088..4785ca9919d 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1407,4 +1407,16 @@ SELECT COUNT(*), a FROM t1; COUNT(*) a 4 1 DROP TABLE t1; +set SQL_MODE=ONLY_FULL_GROUP_BY; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE VIEW v1 AS SELECT a,(a + 1) AS y FROM t1; +EXPLAIN EXTENDED SELECT y FROM v1 GROUP BY v1.y; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +Warnings: +Note 1003 select (`test`.`t1`.`a` + 1) AS `y` from `test`.`t1` group by (`test`.`t1`.`a` + 1) +DROP VIEW v1; +DROP TABLE t1; +SET SQL_MODE=DEFAULT; End of 5.0 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 25cb13a2f75..75a380c733f 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -901,5 +901,20 @@ SELECT COUNT(*), a FROM t1; DROP TABLE t1; +# +# Bug #33133: Views are not transparent +# + +set SQL_MODE=ONLY_FULL_GROUP_BY; + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE VIEW v1 AS SELECT a,(a + 1) AS y FROM t1; +EXPLAIN EXTENDED SELECT y FROM v1 GROUP BY v1.y; + +DROP VIEW v1; +DROP TABLE t1; +SET SQL_MODE=DEFAULT; + ### --echo End of 5.0 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fd921be1ecf..f2dd58bc8e5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4255,7 +4255,36 @@ find_item_in_list(Item *find, List &items, uint *counter, *resolution= RESOLVED_IGNORING_ALIAS; break; } - } + } + else if (table_name && item->type() == Item::REF_ITEM && + ((Item_ref *)item)->ref_type() == Item_ref::VIEW_REF) + { + /* + TODO:Here we process prefixed view references only. What we should + really do is process all types of Item_refs. But this will currently + lead to a clash with the way references to outer SELECTs (from the + HAVING clause) are handled in e.g. : + SELECT 1 FROM t1 AS t1_o GROUP BY a + HAVING (SELECT t1_o.a FROM t1 AS t1_i GROUP BY t1_i.a LIMIT 1). + Processing all Item_refs here will cause t1_o.a to resolve to itself. + We still need to process the special case of Item_direct_view_ref + because in the context of views they have the same meaning as + Item_field for tables. + */ + Item_ident *item_ref= (Item_ident *) item; + if (item_ref->name && item_ref->table_name && + !my_strcasecmp(system_charset_info, item_ref->name, field_name) && + !my_strcasecmp(table_alias_charset, item_ref->table_name, + table_name) && + (!db_name || (item_ref->db_name && + !strcmp (item_ref->db_name, db_name)))) + { + found= li.ref(); + *counter= i; + *resolution= RESOLVED_IGNORING_ALIAS; + break; + } + } } if (!found) {