Commit 3d067e7d authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

Merge work:/my/mysql-4.0 into mashka.mysql.fi:/home/my/mysql-4.0

parents 50ca3ba7 e3cd6352
...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. ...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc) AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line! # The Docs Makefile.am parses this line!
AM_INIT_AUTOMAKE(mysql, 4.0.10-gamma) AM_INIT_AUTOMAKE(mysql, 4.0.11)
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10 PROTOCOL_VERSION=10
......
...@@ -62,7 +62,7 @@ my_string mysql_unix_port=0; ...@@ -62,7 +62,7 @@ my_string mysql_unix_port=0;
#define closesocket(A) close(A) #define closesocket(A) close(A)
#endif #endif
static void mysql_once_init(void); void STDCALL mysql_once_init(void);
static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields, static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
uint field_count); uint field_count);
static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
......
...@@ -151,3 +151,56 @@ sum(num) ...@@ -151,3 +151,56 @@ sum(num)
45.63 45.63
51.80 51.80
drop table t1; drop table t1;
create table t1 (a1 int, a2 char(3), key k1(a1), key k2(a2));
insert into t1 values(10,'aaa'), (10,null), (10,'bbb'), (20,'zzz');
create table t2(a1 char(3), a2 int, a3 real, key k1(a1), key k2(a2, a1));
select * from t1;
a1 a2
10 aaa
10 NULL
10 bbb
20 zzz
select min(a2) from t1;
min(a2)
aaa
select max(t1.a1), max(t2.a2) from t1, t2;
max(t1.a1) max(t2.a2)
NULL NULL
select max(t1.a1) from t1, t2;
max(t1.a1)
NULL
select max(t2.a2), max(t1.a1) from t1, t2;
max(t2.a2) max(t1.a1)
NULL NULL
explain select min(a2) from t1;
Comment
Select tables optimized away
explain select max(t1.a1), max(t2.a2) from t1, t2;
Comment
No matching min/max row
insert into t2 values('AAA', 10, 0.5);
select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9;
max(t1.a1) max(t2.a1)
NULL NULL
select max(t2.a1), max(t1.a1) from t1, t2 where t2.a2=9;
max(t2.a1) max(t1.a1)
NULL NULL
select t1.a1, t1.a2, t2.a1, t2.a2 from t1 left outer join t2 on t1.a1=10;
a1 a2 a1 a2
10 aaa AAA 10
10 NULL AAA 10
10 bbb AAA 10
20 zzz NULL NULL
select max(t1.a2) from t1 left outer join t2 on t1.a1=10;
max(t1.a2)
zzz
select max(t1.a2) from t1 left outer join t2 on t1.a1=10 where t1.a1=20;
max(t1.a2)
zzz
select max(t1.a2) from t1 left outer join t2 on t1.a1=10 where t1.a1=10;
max(t1.a2)
bbb
select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA';
max(t2.a1)
NULL
drop table t1,t2;
...@@ -99,3 +99,30 @@ insert into t1 values (5.2,'nem'),(8.64,'monty'),(11.12,'sinisa'); ...@@ -99,3 +99,30 @@ insert into t1 values (5.2,'nem'),(8.64,'monty'),(11.12,'sinisa');
select sum(num) from t1; select sum(num) from t1;
select sum(num) from t1 group by user; select sum(num) from t1 group by user;
drop table t1; drop table t1;
#
# Test problem with MIN() optimization in case of null values
#
create table t1 (a1 int, a2 char(3), key k1(a1), key k2(a2));
insert into t1 values(10,'aaa'), (10,null), (10,'bbb'), (20,'zzz');
create table t2(a1 char(3), a2 int, a3 real, key k1(a1), key k2(a2, a1));
select * from t1;
# The following returned NULL in 4.0.10
select min(a2) from t1;
select max(t1.a1), max(t2.a2) from t1, t2;
select max(t1.a1) from t1, t2;
select max(t2.a2), max(t1.a1) from t1, t2;
explain select min(a2) from t1;
explain select max(t1.a1), max(t2.a2) from t1, t2;
insert into t2 values('AAA', 10, 0.5);
select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9;
select max(t2.a1), max(t1.a1) from t1, t2 where t2.a2=9;
select t1.a1, t1.a2, t2.a1, t2.a2 from t1 left outer join t2 on t1.a1=10;
select max(t1.a2) from t1 left outer join t2 on t1.a1=10;
select max(t1.a2) from t1 left outer join t2 on t1.a1=10 where t1.a1=20;
select max(t1.a2) from t1 left outer join t2 on t1.a1=10 where t1.a1=10;
select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA';
drop table t1,t2;
...@@ -89,6 +89,7 @@ public: ...@@ -89,6 +89,7 @@ public:
virtual void set_result_field(Field *field) {} virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; } virtual bool is_result_field() { return 0; }
virtual void save_in_result_field(bool no_conversions) {} virtual void save_in_result_field(bool no_conversions) {}
virtual void no_rows_in_result() {}
}; };
......
...@@ -69,6 +69,7 @@ public: ...@@ -69,6 +69,7 @@ public:
void make_field(Send_field *field); void make_field(Send_field *field);
void print(String *str); void print(String *str);
void fix_num_length_and_dec(); void fix_num_length_and_dec();
void no_rows_in_result() { reset(); }
virtual bool setup(THD *thd) {return 0;} virtual bool setup(THD *thd) {return 0;}
unsigned int size_of() { return sizeof(*this);} unsigned int size_of() { return sizeof(*this);}
}; };
...@@ -135,6 +136,7 @@ class Item_sum_count :public Item_sum_int ...@@ -135,6 +136,7 @@ class Item_sum_count :public Item_sum_int
bool const_item() const { return !used_table_cache; } bool const_item() const { return !used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_FUNC; } enum Sumfunctype sum_func () const { return COUNT_FUNC; }
void reset(); void reset();
void no_rows_in_result() { count=0; }
bool add(); bool add();
void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; } void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
longlong val_int(); longlong val_int();
......
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB /* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -22,28 +22,55 @@ ...@@ -22,28 +22,55 @@
static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond); static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond);
/***************************************************************************** /*
** This function is only called for queries with sum functions and no Substitutes constants for some COUNT(), MIN() and MAX() functions.
** GROUP BY part.
** This substitutes constants for some COUNT(), MIN() and MAX() functions. SYNOPSIS
** The function returns 1 if all items was resolved and -1 on impossible opt_sum_query()
** conditions tables Tables in query
****************************************************************************/ all_fields All fields to be returned
conds WHERE clause
NOTE:
This function is only called for queries with sum functions and no
GROUP BY part.
RETURN VALUES
0 No errors
1 if all items was resolved
-1 on impossible conditions
*/
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
{ {
List_iterator_fast<Item> it(all_fields); List_iterator_fast<Item> it(all_fields);
int const_result=1; int const_result= 1;
bool recalc_const_item=0; bool recalc_const_item= 0;
table_map removed_tables=0; table_map removed_tables= 0, outer_tables= 0, used_tables= 0;
table_map where_tables= 0;
Item *item; Item *item;
COND *org_conds= conds; COND *org_conds= conds;
/* Add all ON conditions to WHERE condition */ if (conds)
where_tables= conds->used_tables();
/* Don't replace expression on a table that is part of an outer join */
for (TABLE_LIST *tl=tables; tl ; tl= tl->next) for (TABLE_LIST *tl=tables; tl ; tl= tl->next)
{ {
if (tl->on_expr) if (tl->on_expr)
conds= and_expressions(conds, tl->on_expr, &org_conds); {
outer_tables|= tl->table->map;
/*
We can't optimise LEFT JOIN in cases where the WHERE condition
restricts the table that is used, like in:
SELECT MAX(t1.a) FROM t1 LEFT JOIN t2 join-condition
WHERE t2.field IS NULL;
*/
if (tl->table->map & where_tables)
return 0;
}
used_tables|= tl->table->map;
} }
/* /*
...@@ -68,8 +95,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -68,8 +95,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
TABLE_LIST *table; TABLE_LIST *table;
for (table=tables; table ; table=table->next) for (table=tables; table ; table=table->next)
{ {
if (table->on_expr || (table->table->file->table_flags() & if (outer_tables || (table->table->file->table_flags() &
HA_NOT_EXACT_COUNT)) HA_NOT_EXACT_COUNT))
{ {
const_result=0; // Can't optimize left join const_result=0; // Can't optimize left join
break; break;
...@@ -99,21 +126,35 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -99,21 +126,35 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
byte key_buff[MAX_KEY_LENGTH]; byte key_buff[MAX_KEY_LENGTH];
TABLE_REF ref; TABLE_REF ref;
ref.key_buff=key_buff; ref.key_buff=key_buff;
Item_field *item_field= ((Item_field*) expr);
TABLE *table= item_field->field->table;
if (!find_range_key(&ref, ((Item_field*) expr)->field,conds)) if ((outer_tables & table->map) ||
(!find_range_key(&ref, item_field->field,conds)))
{ {
const_result=0; const_result=0;
break; break;
} }
TABLE *table=((Item_field*) expr)->field->table; bool error= table->file->index_init((uint) ref.key);
bool error=table->file->index_init((uint) ref.key); enum ha_rkey_function find_flag= HA_READ_KEY_OR_NEXT;
uint prefix_len= ref.key_length;
/*
If we are doing MIN() on a column with NULL fields
we must read the key after the NULL column
*/
if (item_field->field->null_bit)
{
ref.key_buff[ref.key_length++]=1;
find_flag= HA_READ_AFTER_KEY;
}
if (!ref.key_length) if (!ref.key_length)
error=table->file->index_first(table->record[0]) !=0; error=table->file->index_first(table->record[0]) !=0;
else else
error=table->file->index_read(table->record[0],key_buff, error=table->file->index_read(table->record[0],key_buff,
ref.key_length, ref.key_length,
HA_READ_KEY_OR_NEXT) || find_flag) ||
key_cmp(table, key_buff, ref.key, ref.key_length); key_cmp(table, key_buff, ref.key, prefix_len);
if (table->key_read) if (table->key_read)
{ {
table->key_read=0; table->key_read=0;
...@@ -121,7 +162,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -121,7 +162,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
} }
table->file->index_end(); table->file->index_end();
if (error) if (error)
return -1; // Impossible query return -1; // No rows matching where
removed_tables|= table->map; removed_tables|= table->map;
} }
else if (!expr->const_item()) // This is VERY seldom false else if (!expr->const_item()) // This is VERY seldom false
...@@ -147,13 +188,14 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -147,13 +188,14 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
byte key_buff[MAX_KEY_LENGTH]; byte key_buff[MAX_KEY_LENGTH];
TABLE_REF ref; TABLE_REF ref;
ref.key_buff=key_buff; ref.key_buff=key_buff;
TABLE *table=((Item_field*) expr)->field->table;
if (!find_range_key(&ref, ((Item_field*) expr)->field,conds)) if ((outer_tables & table->map) ||
!find_range_key(&ref, ((Item_field*) expr)->field,conds))
{ {
const_result=0; const_result=0;
break; break;
} }
TABLE *table=((Item_field*) expr)->field->table;
if ((table->file->table_flags() & HA_NOT_READ_AFTER_KEY)) if ((table->file->table_flags() & HA_NOT_READ_AFTER_KEY))
{ {
const_result=0; const_result=0;
...@@ -203,8 +245,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -203,8 +245,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
const_result=0; const_result=0;
} }
} }
if (conds && (conds->used_tables() & ~ removed_tables)) if (used_tables != removed_tables)
const_result=0; const_result=0; // We didn't remove all tables
return const_result; return const_result;
} }
......
...@@ -3104,7 +3104,13 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, ...@@ -3104,7 +3104,13 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
if (!(result->send_fields(fields,1))) if (!(result->send_fields(fields,1)))
{ {
if (send_row) if (send_row)
{
List_iterator_fast<Item> it(fields);
Item *item;
while ((item= it++))
item->no_rows_in_result();
result->send_data(fields); result->send_data(fields);
}
if (tables) // Not from do_select() if (tables) // Not from do_select()
{ {
/* Close open cursors */ /* Close open cursors */
......
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