Commit fd98ed36 authored by unknown's avatar unknown

Manual merge

parent f4353d48
...@@ -126,8 +126,8 @@ class Item { ...@@ -126,8 +126,8 @@ class Item {
top AND/OR ctructure of WHERE clause to protect it of top AND/OR ctructure of WHERE clause to protect it of
optimisation changes in prepared statements optimisation changes in prepared statements
*/ */
Item(THD *thd, Item &item); Item(THD *thd, Item *item);
virtual ~Item() { name=0; cleanup(); } /*lint -e1509 */ virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs); void set_name(const char *str,uint length, CHARSET_INFO *cs);
void init_make_field(Send_field *tmp_field,enum enum_field_types type); void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup() { fixed=0; } virtual void cleanup() { fixed=0; }
...@@ -206,6 +206,7 @@ class Item { ...@@ -206,6 +206,7 @@ class Item {
virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
CHARSET_INFO *default_charset() const; CHARSET_INFO *default_charset() const;
virtual CHARSET_INFO *compare_collation() { return NULL; }
virtual bool walk(Item_processor processor, byte *arg) virtual bool walk(Item_processor processor, byte *arg)
{ {
...@@ -239,6 +240,11 @@ class Item { ...@@ -239,6 +240,11 @@ class Item {
/* Used in sql_select.cc:eliminate_not_funcs() */ /* Used in sql_select.cc:eliminate_not_funcs() */
virtual Item *neg_transformer() { return NULL; } virtual Item *neg_transformer() { return NULL; }
void delete_self()
{
cleanup();
delete this;
}
}; };
...@@ -304,7 +310,10 @@ class Item_splocal : public Item ...@@ -304,7 +310,10 @@ class Item_splocal : public Item
inline void make_field(Send_field *field) inline void make_field(Send_field *field)
{ {
this_item()->make_field(field); Item *it= this_item();
it->set_name(m_name.str, m_name.length, system_charset_info);
it->make_field(field);
} }
inline Item_result result_type() const inline Item_result result_type() const
...@@ -326,6 +335,11 @@ class Item_splocal : public Item ...@@ -326,6 +335,11 @@ class Item_splocal : public Item
{ {
str->append(m_name.str, m_name.length); str->append(m_name.str, m_name.length);
} }
inline bool send(Protocol *protocol, String *str)
{
return this_item()->send(protocol, str);
}
}; };
...@@ -339,7 +353,7 @@ class Item_ident :public Item ...@@ -339,7 +353,7 @@ class Item_ident :public Item
st_select_lex *depended_from; st_select_lex *depended_from;
Item_ident(const char *db_name_par,const char *table_name_par, Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par); const char *field_name_par);
Item_ident(THD *thd, Item_ident &item); Item_ident(THD *thd, Item_ident *item);
const char *full_name() const; const char *full_name() const;
bool remove_dependence_processor(byte * arg); bool remove_dependence_processor(byte * arg);
...@@ -362,7 +376,7 @@ class Item_field :public Item_ident ...@@ -362,7 +376,7 @@ class Item_field :public Item_ident
item_equal(0) item_equal(0)
{ collation.set(DERIVATION_IMPLICIT); } { collation.set(DERIVATION_IMPLICIT); }
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
Item_field(THD *thd, Item_field &item); Item_field(THD *thd, Item_field *item);
Item_field(Field *field); Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; } enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
...@@ -393,6 +407,7 @@ class Item_field :public Item_ident ...@@ -393,6 +407,7 @@ class Item_field :public Item_ident
bool get_time(TIME *ltime); bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); } bool is_null() { return field->is_null(); }
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
void cleanup();
Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg); Item *equal_fields_propagator(byte *arg);
bool replace_equal_field_processor(byte *arg); bool replace_equal_field_processor(byte *arg);
...@@ -583,7 +598,7 @@ class Item_string :public Item ...@@ -583,7 +598,7 @@ class Item_string :public Item
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
{ {
collation.set(cs, dv); collation.set(cs, dv);
str_value.set(str,length,cs); str_value.set_or_copy_aligned(str,length,cs);
/* /*
We have to have a different max_length than 'length' here to We have to have a different max_length than 'length' here to
ensure that we get the right length if we do use the item ensure that we get the right length if we do use the item
...@@ -599,12 +614,11 @@ class Item_string :public Item ...@@ -599,12 +614,11 @@ class Item_string :public Item
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
{ {
collation.set(cs, dv); collation.set(cs, dv);
str_value.set(str,length,cs); str_value.set_or_copy_aligned(str,length,cs);
max_length= str_value.numchars()*cs->mbmaxlen; max_length= str_value.numchars()*cs->mbmaxlen;
set_name(name_par,0,cs); set_name(name_par,0,cs);
decimals=NOT_FIXED_DEC; decimals=NOT_FIXED_DEC;
} }
~Item_string() {}
enum Type type() const { return STRING_ITEM; } enum Type type() const { return STRING_ITEM; }
double val() double val()
{ {
...@@ -671,7 +685,6 @@ class Item_varbinary :public Item ...@@ -671,7 +685,6 @@ class Item_varbinary :public Item
{ {
public: public:
Item_varbinary(const char *str,uint str_length); Item_varbinary(const char *str,uint str_length);
~Item_varbinary() {}
enum Type type() const { return VARBIN_ITEM; } enum Type type() const { return VARBIN_ITEM; }
double val() { return (double) Item_varbinary::val_int(); } double val() { return (double) Item_varbinary::val_int(); }
longlong val_int(); longlong val_int();
...@@ -688,8 +701,8 @@ class Item_result_field :public Item /* Item with result field */ ...@@ -688,8 +701,8 @@ class Item_result_field :public Item /* Item with result field */
Field *result_field; /* Save result here */ Field *result_field; /* Save result here */
Item_result_field() :result_field(0) {} Item_result_field() :result_field(0) {}
// Constructor used for Item_sum/Item_cond_and/or (see Item comment) // Constructor used for Item_sum/Item_cond_and/or (see Item comment)
Item_result_field(THD *thd, Item_result_field &item): Item_result_field(THD *thd, Item_result_field *item):
Item(thd, item), result_field(item.result_field) Item(thd, item), result_field(item->result_field)
{} {}
~Item_result_field() {} /* Required with gcc 2.95 */ ~Item_result_field() {} /* Required with gcc 2.95 */
Field *get_tmp_table_field() { return result_field; } Field *get_tmp_table_field() { return result_field; }
...@@ -708,20 +721,25 @@ class Item_result_field :public Item /* Item with result field */ ...@@ -708,20 +721,25 @@ class Item_result_field :public Item /* Item with result field */
class Item_ref :public Item_ident class Item_ref :public Item_ident
{ {
public: public:
Field *result_field; /* Save result here */ Field *result_field; /* Save result here */
Item **ref; Item **ref;
Item_ref(const char *db_par, const char *table_name_par, Item **hook_ptr; /* These two to restore */
const char *field_name_par) Item *orig_item; /* things in 'cleanup()' */
:Item_ident(db_par,table_name_par,field_name_par),ref(0) {} Item_ref(Item **hook, Item *original,const char *db_par,
Item_ref(Item **item, const char *table_name_par, const char *field_name_par) const char *table_name_par, const char *field_name_par)
:Item_ident(NullS,table_name_par,field_name_par),ref(item) {} :Item_ident(db_par,table_name_par,field_name_par),ref(0), hook_ptr(hook),
orig_item(original) {}
Item_ref(Item **item, Item **hook,
const char *table_name_par, const char *field_name_par)
:Item_ident(NullS,table_name_par,field_name_par),
ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {}
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
Item_ref(THD *thd, Item_ref &item) Item_ref(THD *thd, Item_ref *item, Item **hook)
:Item_ident(thd, item), ref(item.ref) {} :Item_ident(thd, item), ref(item->ref),
hook_ptr(hook), orig_item(hook ? *hook : 0) {}
enum Type type() const { return REF_ITEM; } enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const bool eq(const Item *item, bool binary_cmp) const
{ return ref && (*ref)->eq(item, binary_cmp); } { return ref && (*ref)->eq(item, binary_cmp); }
~Item_ref() { if (ref && (*ref) && (*ref) != this) delete *ref; }
double val() double val()
{ {
double tmp=(*ref)->val_result(); double tmp=(*ref)->val_result();
...@@ -766,6 +784,7 @@ class Item_ref :public Item_ident ...@@ -766,6 +784,7 @@ class Item_ref :public Item_ident
} }
Item *real_item() { return *ref; } Item *real_item() { return *ref; }
void print(String *str); void print(String *str);
void cleanup();
}; };
class Item_in_subselect; class Item_in_subselect;
...@@ -776,7 +795,7 @@ class Item_ref_null_helper: public Item_ref ...@@ -776,7 +795,7 @@ class Item_ref_null_helper: public Item_ref
public: public:
Item_ref_null_helper(Item_in_subselect* master, Item **item, Item_ref_null_helper(Item_in_subselect* master, Item **item,
const char *table_name_par, const char *field_name_par): const char *table_name_par, const char *field_name_par):
Item_ref(item, table_name_par, field_name_par), owner(master) {} Item_ref(item, NULL, table_name_par, field_name_par), owner(master) {}
double val(); double val();
longlong val_int(); longlong val_int();
String* val_str(String* s); String* val_str(String* s);
...@@ -840,7 +859,6 @@ class Item_copy_string :public Item ...@@ -840,7 +859,6 @@ class Item_copy_string :public Item
name=item->name; name=item->name;
cached_field_type= item->field_type(); cached_field_type= item->field_type();
} }
~Item_copy_string() { delete item; }
enum Type type() const { return COPY_STR_ITEM; } enum Type type() const { return COPY_STR_ITEM; }
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return cached_field_type; } enum_field_types field_type() const { return cached_field_type; }
...@@ -997,13 +1015,15 @@ class Item_cache: public Item ...@@ -997,13 +1015,15 @@ class Item_cache: public Item
void set_used_tables(table_map map) { used_table_map= map; } void set_used_tables(table_map map) { used_table_map= map; }
virtual bool allocate(uint i) { return 0; }; virtual bool allocate(uint i) { return 0; };
virtual bool setup(Item *item) { example= item; return 0; }; virtual bool setup(Item *item)
virtual void store(Item *)= 0;
void set_len_n_dec(uint32 max_len, uint8 dec)
{ {
max_length= max_len; example= item;
decimals= dec; max_length= item->max_length;
} decimals= item->decimals;
collation.set(item->collation);
return 0;
};
virtual void store(Item *)= 0;
enum Type type() const { return CACHE_ITEM; } enum Type type() const { return CACHE_ITEM; }
static Item_cache* get_cache(Item_result type); static Item_cache* get_cache(Item_result type);
table_map used_tables() const { return used_table_map; } table_map used_tables() const { return used_table_map; }
...@@ -1028,7 +1048,7 @@ class Item_cache_real: public Item_cache ...@@ -1028,7 +1048,7 @@ class Item_cache_real: public Item_cache
double value; double value;
public: public:
Item_cache_real(): Item_cache() {} Item_cache_real(): Item_cache() {}
void store(Item *item); void store(Item *item);
double val() { return value; } double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); }
...@@ -1101,6 +1121,11 @@ class Item_cache_row: public Item_cache ...@@ -1101,6 +1121,11 @@ class Item_cache_row: public Item_cache
bool check_cols(uint c); bool check_cols(uint c);
bool null_inside(); bool null_inside();
void bring_value(); void bring_value();
void cleanup()
{
Item_cache::cleanup();
values= 0;
}
}; };
...@@ -1111,6 +1136,7 @@ class Item_type_holder: public Item ...@@ -1111,6 +1136,7 @@ class Item_type_holder: public Item
{ {
protected: protected:
Item_result item_type; Item_result item_type;
Item_result orig_type;
Field *field_example; Field *field_example;
public: public:
Item_type_holder(THD*, Item*); Item_type_holder(THD*, Item*);
...@@ -1122,6 +1148,11 @@ class Item_type_holder: public Item ...@@ -1122,6 +1148,11 @@ class Item_type_holder: public Item
String *val_str(String*); String *val_str(String*);
bool join_types(THD *thd, Item *); bool join_types(THD *thd, Item *);
Field *example() { return field_example; } Field *example() { return field_example; }
void cleanup()
{
Item::cleanup();
item_type= orig_type;
}
}; };
......
...@@ -301,10 +301,11 @@ typedef struct st_qsel_param { ...@@ -301,10 +301,11 @@ typedef struct st_qsel_param {
uint imerge_cost_buff_size; /* size of the buffer */ uint imerge_cost_buff_size; /* size of the buffer */
} PARAM; } PARAM;
static SEL_TREE * get_mm_parts(PARAM *param,Field *field, static SEL_TREE * get_mm_parts(PARAM *param,COND *cond_func,Field *field,
Item_func::Functype type,Item *value, Item_func::Functype type,Item *value,
Item_result cmp_type); Item_result cmp_type);
static SEL_ARG *get_mm_leaf(PARAM *param,Field *field,KEY_PART *key_part, static SEL_ARG *get_mm_leaf(PARAM *param,COND *cond_func,Field *field,
KEY_PART *key_part,
Item_func::Functype type,Item *value); Item_func::Functype type,Item *value);
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond); static SEL_TREE *get_mm_tree(PARAM *param,COND *cond);
static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree); static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree);
...@@ -612,14 +613,25 @@ SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0) ...@@ -612,14 +613,25 @@ SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
} }
SQL_SELECT::~SQL_SELECT() void SQL_SELECT::cleanup()
{ {
delete quick; delete quick;
quick= 0;
if (free_cond) if (free_cond)
{
free_cond=0;
delete cond; delete cond;
cond= 0;
}
close_cached_file(&file); close_cached_file(&file);
} }
SQL_SELECT::~SQL_SELECT()
{
cleanup();
}
#undef index // Fix for Unixware 7 #undef index // Fix for Unixware 7
QUICK_SELECT_I::QUICK_SELECT_I() QUICK_SELECT_I::QUICK_SELECT_I()
...@@ -1746,7 +1758,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) ...@@ -1746,7 +1758,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
static SEL_TREE * static SEL_TREE *
get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, get_mm_parts(PARAM *param, COND *cond_func, Field *field,
Item_func::Functype type,
Item *value, Item_result cmp_type) Item *value, Item_result cmp_type)
{ {
DBUG_ENTER("get_mm_parts"); DBUG_ENTER("get_mm_parts");
...@@ -1768,7 +1781,8 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, ...@@ -1768,7 +1781,8 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
DBUG_RETURN(0); // OOM DBUG_RETURN(0); // OOM
if (!value || !(value->used_tables() & ~param->read_tables)) if (!value || !(value->used_tables() & ~param->read_tables))
{ {
sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value); sel_arg=get_mm_leaf(param,cond_func,
key_part->field,key_part,type,value);
if (!sel_arg) if (!sel_arg)
continue; continue;
if (sel_arg->type == SEL_ARG::IMPOSSIBLE) if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
...@@ -1794,7 +1808,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, ...@@ -1794,7 +1808,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
static SEL_ARG * static SEL_ARG *
get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
Item_func::Functype type,Item *value) Item_func::Functype type,Item *value)
{ {
uint maybe_null=(uint) field->real_maybe_null(), copies; uint maybe_null=(uint) field->real_maybe_null(), copies;
...@@ -1803,6 +1817,32 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, ...@@ -1803,6 +1817,32 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
char *str, *str2; char *str, *str2;
DBUG_ENTER("get_mm_leaf"); DBUG_ENTER("get_mm_leaf");
if (!value) // IS NULL or IS NOT NULL
{
if (field->table->outer_join) // Can't use a key on this
DBUG_RETURN(0);
if (!maybe_null) // Not null field
DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
DBUG_RETURN(0); // out of memory
if (type == Item_func::ISNOTNULL_FUNC)
{
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
tree->max_flag=NO_MAX_RANGE;
}
DBUG_RETURN(tree);
}
/*
We can't use an index when comparing strings of
different collations
*/
if (field->result_type() == STRING_RESULT &&
value->result_type() == STRING_RESULT &&
key_part->image_type == Field::itRAW &&
((Field_str*)field)->charset() != conf_func->compare_collation())
DBUG_RETURN(0);
if (type == Item_func::LIKE_FUNC) if (type == Item_func::LIKE_FUNC)
{ {
bool like_error; bool like_error;
...@@ -1866,22 +1906,6 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, ...@@ -1866,22 +1906,6 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(new SEL_ARG(field,min_str,max_str)); DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
} }
if (!value) // IS NULL or IS NOT NULL
{
if (field->table->outer_join) // Can't use a key on this
DBUG_RETURN(0);
if (!maybe_null) // Not null field
DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
DBUG_RETURN(0); // out of memory
if (type == Item_func::ISNOTNULL_FUNC)
{
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
tree->max_flag=NO_MAX_RANGE;
}
DBUG_RETURN(tree);
}
if (!field->optimize_range(param->real_keynr[key_part->key]) && if (!field->optimize_range(param->real_keynr[key_part->key]) &&
type != Item_func::EQ_FUNC && type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC) type != Item_func::EQUAL_FUNC)
...@@ -1895,7 +1919,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, ...@@ -1895,7 +1919,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
value->result_type() != STRING_RESULT && value->result_type() != STRING_RESULT &&
field->cmp_type() != value->result_type()) field->cmp_type() != value->result_type())
DBUG_RETURN(0); DBUG_RETURN(0);
if (value->save_in_field(field, 1) > 0) if (value->save_in_field(field, 1) > 0)
{ {
/* This happens when we try to insert a NULL field in a not null column */ /* This happens when we try to insert a NULL field in a not null column */
...@@ -3097,6 +3121,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree) ...@@ -3097,6 +3121,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
param->table->quick_rows[key]=records; param->table->quick_rows[key]=records;
param->table->quick_key_parts[key]=param->max_key_part+1; param->table->quick_key_parts[key]=param->max_key_part+1;
} }
DBUG_PRINT("exit", ("Records: %lu", (ulong) records));
DBUG_RETURN(records); DBUG_RETURN(records);
} }
...@@ -3440,8 +3465,30 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, ...@@ -3440,8 +3465,30 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
key_part->part_length+=HA_KEY_BLOB_LENGTH; key_part->part_length+=HA_KEY_BLOB_LENGTH;
key_part->null_bit= key_info->key_part[part].null_bit; key_part->null_bit= key_info->key_part[part].null_bit;
} }
if (!insert_dynamic(&quick->ranges,(gptr)&range)) if (insert_dynamic(&quick->ranges,(gptr)&range))
return quick; goto err;
/*
Add a NULL range if REF_OR_NULL optimization is used.
For example:
if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above
and have ref->null_ref_key set. Will create a new NULL range here.
*/
if (ref->null_ref_key)
{
QUICK_RANGE *null_range;
*ref->null_ref_key= 1; // Set null byte then create a range
if (!(null_range= new QUICK_RANGE(ref->key_buff, ref->key_length,
ref->key_buff, ref->key_length,
EQ_RANGE)))
goto err;
*ref->null_ref_key= 0; // Clear null byte
if (insert_dynamic(&quick->ranges,(gptr)&null_range))
goto err;
}
return quick;
err: err:
delete quick; delete quick;
...@@ -3584,12 +3631,7 @@ int QUICK_RANGE_SELECT::get_next() ...@@ -3584,12 +3631,7 @@ int QUICK_RANGE_SELECT::get_next()
int result; int result;
if (range) if (range)
{ // Already read through key { // Already read through key
/* result=((range->flag & EQ_RANGE) ? result=((range->flag & (EQ_RANGE | GEOM_FLAG)) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
*/
result=((range->flag & (EQ_RANGE | GEOM_FLAG) ) ?
file->index_next_same(record, (byte*) range->min_key, file->index_next_same(record, (byte*) range->min_key,
range->min_length) : range->min_length) :
file->index_next(record)); file->index_next(record));
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sql_select.h" #include "sql_select.h"
#include "opt_ft.h"
#include <m_ctype.h> #include <m_ctype.h>
#include <hash.h> #include <hash.h>
#include <ft_global.h> #include <ft_global.h>
...@@ -89,7 +87,7 @@ static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, ...@@ -89,7 +87,7 @@ static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
Procedure *proc); Procedure *proc);
static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last); static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last);
static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records); static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records);
static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
...@@ -182,7 +180,6 @@ int handle_select(THD *thd, LEX *lex, select_result *result) ...@@ -182,7 +180,6 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
register SELECT_LEX *select_lex = &lex->select_lex; register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select"); DBUG_ENTER("handle_select");
fix_tables_pointers(lex->all_selects_list);
if (select_lex->next_select()) if (select_lex->next_select())
res=mysql_union(thd, lex, result, &lex->unit); res=mysql_union(thd, lex, result, &lex->unit);
else else
...@@ -309,7 +306,7 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -309,7 +306,7 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */ /* Check that all tables, fields, conds and order are ok */
if (setup_tables(tables_list) || if (setup_tables(tables_list, 0) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) || select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
...@@ -939,8 +936,10 @@ JOIN::optimize() ...@@ -939,8 +936,10 @@ JOIN::optimize()
as in other cases the join is done before the sort. as in other cases the join is done before the sort.
*/ */
if (const_tables != tables && if (const_tables != tables &&
(order || group_list) && join_tab[const_tables].type != JT_ALL && (order || group_list) &&
join_tab[const_tables].type != JT_ALL &&
join_tab[const_tables].type != JT_FT && join_tab[const_tables].type != JT_FT &&
join_tab[const_tables].type != JT_REF_OR_NULL &&
(order && simple_order || group_list && simple_group)) (order && simple_order || group_list && simple_group))
{ {
if (add_ref_to_table_cond(thd,&join_tab[const_tables])) if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
...@@ -1094,7 +1093,7 @@ JOIN::reinit() ...@@ -1094,7 +1093,7 @@ JOIN::reinit()
if (unit->select_limit_cnt == HA_POS_ERROR) if (unit->select_limit_cnt == HA_POS_ERROR)
select_lex->options&= ~OPTION_FOUND_ROWS; select_lex->options&= ~OPTION_FOUND_ROWS;
if (setup_tables(tables_list)) if (setup_tables(tables_list, 1))
DBUG_RETURN(1); DBUG_RETURN(1);
/* Reset of sum functions */ /* Reset of sum functions */
...@@ -1590,12 +1589,7 @@ JOIN::cleanup() ...@@ -1590,12 +1589,7 @@ JOIN::cleanup()
JOIN_TAB *tab, *end; JOIN_TAB *tab, *end;
for (tab= join_tab, end= tab+tables ; tab != end ; tab++) for (tab= join_tab, end= tab+tables ; tab != end ; tab++)
{ {
delete tab->select; tab->cleanup();
delete tab->quick;
tab->select=0;
tab->quick=0;
x_free(tab->cache.buff);
tab->cache.buff= 0;
} }
} }
tmp_join->tmp_join= 0; tmp_join->tmp_join= 0;
...@@ -1659,13 +1653,14 @@ mysql_select(THD *thd, Item ***rref_pointer_array, ...@@ -1659,13 +1653,14 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
goto err; goto err;
} }
} }
free_join= 0;
} }
free_join= 0;
join->select_options= select_options; join->select_options= select_options;
} }
else else
{ {
join= new JOIN(thd, fields, select_options, result); if (!(join= new JOIN(thd, fields, select_options, result)))
DBUG_RETURN(-1);
thd->proc_info="init"; thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields thd->used_tables=0; // Updated by setup_fields
if (join->prepare(rref_pointer_array, tables, wild_num, if (join->prepare(rref_pointer_array, tables, wild_num,
...@@ -1726,8 +1721,8 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, ...@@ -1726,8 +1721,8 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
{ {
select->head=table; select->head=table;
table->reginfo.impossible_range=0; table->reginfo.impossible_range=0;
if ((error=select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,limit)) if ((error=select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,
== 1) limit)) == 1)
DBUG_RETURN(select->quick->records); DBUG_RETURN(select->quick->records);
if (error == -1) if (error == -1)
{ {
...@@ -2210,7 +2205,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, ...@@ -2210,7 +2205,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
*/ */
static void static void
add_key_field(KEY_FIELD **key_fields,uint and_level, add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
Field *field,bool eq_func,Item **value, uint num_values, Field *field,bool eq_func,Item **value, uint num_values,
table_map usable_tables) table_map usable_tables)
{ {
...@@ -2277,6 +2272,17 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, ...@@ -2277,6 +2272,17 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
(*value)->result_type() != STRING_RESULT && (*value)->result_type() != STRING_RESULT &&
field->cmp_type() != (*value)->result_type()) field->cmp_type() != (*value)->result_type())
return; return;
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
*/
if (field->result_type() == STRING_RESULT &&
(*value)->result_type() == STRING_RESULT &&
field->cmp_type() == STRING_RESULT &&
((Field_str*)field)->charset() != cond->compare_collation())
return;
} }
} }
DBUG_ASSERT(num_values == 1); DBUG_ASSERT(num_values == 1);
...@@ -3441,7 +3447,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, ...@@ -3441,7 +3447,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
{ {
/* Must read with repeat */ /* Must read with repeat */
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
j->null_ref_key= null_ref_key; j->ref.null_ref_key= null_ref_key;
} }
else if (ref_key == j->ref.key_copy) else if (ref_key == j->ref.key_copy)
{ {
...@@ -3920,6 +3926,41 @@ bool error_if_full_join(JOIN *join) ...@@ -3920,6 +3926,41 @@ bool error_if_full_join(JOIN *join)
} }
/*
cleanup JOIN_TAB
SYNOPSIS
JOIN_TAB::cleanup()
*/
void JOIN_TAB::cleanup()
{
delete select;
select= 0;
delete quick;
quick= 0;
x_free(cache.buff);
cache.buff= 0;
if (table)
{
if (table->key_read)
{
table->key_read= 0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
/* Don't free index if we are using read_record */
if (!read_record.table)
table->file->index_end();
/*
We need to reset this for next select
(Tested in part_of_refkey)
*/
table->reginfo.join_tab= 0;
}
end_read_record(&read_record);
}
/* /*
Free resources of given join Free resources of given join
...@@ -3954,11 +3995,6 @@ JOIN::join_free(bool full) ...@@ -3954,11 +3995,6 @@ JOIN::join_free(bool full)
{ {
if (tab->table) if (tab->table)
{ {
if (tab->table->key_read)
{
tab->table->key_read= 0;
tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
}
/* Don't free index if we are using read_record */ /* Don't free index if we are using read_record */
if (!tab->read_record.table) if (!tab->read_record.table)
tab->table->file->index_end(); tab->table->file->index_end();
...@@ -3969,29 +4005,7 @@ JOIN::join_free(bool full) ...@@ -3969,29 +4005,7 @@ JOIN::join_free(bool full)
{ {
for (tab= join_tab, end= tab+tables; tab != end; tab++) for (tab= join_tab, end= tab+tables; tab != end; tab++)
{ {
delete tab->select; tab->cleanup();
delete tab->quick;
tab->select=0;
tab->quick=0;
x_free(tab->cache.buff);
tab->cache.buff= 0;
if (tab->table)
{
if (tab->table->key_read)
{
tab->table->key_read= 0;
tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
}
/* Don't free index if we are using read_record */
if (!tab->read_record.table)
tab->table->file->index_end();
/*
We need to reset this for next select
(Tested in part_of_refkey)
*/
tab->table->reginfo.join_tab= 0;
}
end_read_record(&tab->read_record);
} }
table= 0; table= 0;
} }
...@@ -5237,17 +5251,9 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) ...@@ -5237,17 +5251,9 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
{ {
Item *new_item=remove_eq_conds(item,&tmp_cond_value); Item *new_item=remove_eq_conds(item,&tmp_cond_value);
if (!new_item) if (!new_item)
{
#ifdef DELETE_ITEMS
delete item; // This may be shared
#endif
li.remove(); li.remove();
}
else if (item != new_item) else if (item != new_item)
{ {
#ifdef DELETE_ITEMS
delete item; // This may be shared
#endif
VOID(li.replace(new_item)); VOID(li.replace(new_item));
should_fix_fields=1; should_fix_fields=1;
} }
...@@ -6604,14 +6610,14 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) ...@@ -6604,14 +6610,14 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
static int static int
flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last) flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
{ {
int error; int error;
READ_RECORD *info; READ_RECORD *info;
if (!join_tab->cache.records) if (!join_tab->cache.records)
return 0; /* Nothing to do */ return 0; /* Nothing to do */
if (skipp_last) if (skip_last)
(void) store_record_in_cache(&join_tab->cache); // Must save this for later (void) store_record_in_cache(&join_tab->cache); // Must save this for later
if (join_tab->use_quick == 2) if (join_tab->use_quick == 2)
{ {
...@@ -6645,21 +6651,21 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last) ...@@ -6645,21 +6651,21 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
} }
SQL_SELECT *select=join_tab->select; SQL_SELECT *select=join_tab->select;
if (!error && (!join_tab->cache.select || if (!error && (!join_tab->cache.select ||
!join_tab->cache.select->skipp_record())) !join_tab->cache.select->skip_record()))
{ {
uint i; uint i;
reset_cache(&join_tab->cache); reset_cache(&join_tab->cache);
for (i=(join_tab->cache.records- (skipp_last ? 1 : 0)) ; i-- > 0 ;) for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;)
{ {
read_cached_record(join_tab); read_cached_record(join_tab);
if (!select || !select->skipp_record()) if (!select || !select->skip_record())
if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0) if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0)
return error; /* purecov: inspected */ return error; /* purecov: inspected */
} }
} }
} while (!(error=info->read_record(info))); } while (!(error=info->read_record(info)));
if (skipp_last) if (skip_last)
read_cached_record(join_tab); // Restore current record read_cached_record(join_tab); // Restore current record
reset_cache(&join_tab->cache); reset_cache(&join_tab->cache);
join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0; join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0;
...@@ -7066,12 +7072,12 @@ join_read_always_key_or_null(JOIN_TAB *tab) ...@@ -7066,12 +7072,12 @@ join_read_always_key_or_null(JOIN_TAB *tab)
int res; int res;
/* First read according to key which is NOT NULL */ /* First read according to key which is NOT NULL */
*tab->null_ref_key=0; *tab->ref.null_ref_key= 0; // Clear null byte
if ((res= join_read_always_key(tab)) >= 0) if ((res= join_read_always_key(tab)) >= 0)
return res; return res;
/* Then read key with null value */ /* Then read key with null value */
*tab->null_ref_key= 1; *tab->ref.null_ref_key= 1; // Set null byte
return safe_index_read(tab); return safe_index_read(tab);
} }
...@@ -7085,10 +7091,10 @@ join_read_next_same_or_null(READ_RECORD *info) ...@@ -7085,10 +7091,10 @@ join_read_next_same_or_null(READ_RECORD *info)
JOIN_TAB *tab= info->table->reginfo.join_tab; JOIN_TAB *tab= info->table->reginfo.join_tab;
/* Test if we have already done a read after null key */ /* Test if we have already done a read after null key */
if (*tab->null_ref_key) if (*tab->ref.null_ref_key)
return -1; // All keys read return -1; // All keys read
*tab->null_ref_key= 1; // Read null key *tab->ref.null_ref_key= 1; // Set null byte
return safe_index_read(tab); return safe_index_read(tab); // then read null keys
} }
...@@ -8061,8 +8067,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -8061,8 +8067,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
For impossible ranges (like when doing a lookup on NULL on a NOT NULL For impossible ranges (like when doing a lookup on NULL on a NOT NULL
field, quick will contain an empty record set. field, quick will contain an empty record set.
*/ */
if (!(select->quick=get_ft_or_quick_select_for_ref(tab->join->thd, if (!(select->quick= tab->type == JT_FT ?
table, tab))) new FT_SELECT(thd, table, tab->ref.key) :
get_quick_select_for_ref(thd, table, &tab->ref)))
goto err; goto err;
} }
} }
...@@ -8070,9 +8077,12 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -8070,9 +8077,12 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
table->file->info(HA_STATUS_VARIABLE); // Get record count table->file->info(HA_STATUS_VARIABLE); // Get record count
table->sort.found_records=filesort(thd, table,sortorder, length, table->sort.found_records=filesort(thd, table,sortorder, length,
select, filesort_limit, &examined_rows); select, filesort_limit, &examined_rows);
tab->records=table->sort.found_records; // For SQL_CALC_ROWS tab->records= table->sort.found_records; // For SQL_CALC_ROWS
delete select; // filesort did select if (select)
tab->select=0; {
select->cleanup(); // filesort did select
tab->select= 0;
}
tab->select_cond=0; tab->select_cond=0;
tab->type=JT_ALL; // Read with normal read_record tab->type=JT_ALL; // Read with normal read_record
tab->read_first_record= join_init_read_record; tab->read_first_record= join_init_read_record;
...@@ -9155,7 +9165,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, ...@@ -9155,7 +9165,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
if (pos->type() == Item::FIELD_ITEM) if (pos->type() == Item::FIELD_ITEM)
{ {
Item_field *item; Item_field *item;
if (!(item= new Item_field(thd, *((Item_field*) pos)))) if (!(item= new Item_field(thd, ((Item_field*) pos))))
goto err; goto err;
pos= item; pos= item;
if (item->field->flags & BLOB_FLAG) if (item->field->flags & BLOB_FLAG)
...@@ -10056,20 +10066,23 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) ...@@ -10056,20 +10066,23 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
sl; sl;
sl= sl->next_select()) sl= sl->next_select())
{ {
// drop UNCACHEABLE_EXPLAIN, because it is for internal usage only
uint8 uncacheable= (sl->uncacheable & ~UNCACHEABLE_EXPLAIN);
res= mysql_explain_select(thd, sl, res= mysql_explain_select(thd, sl,
(((&thd->lex->select_lex)==sl)? (((&thd->lex->select_lex)==sl)?
((thd->lex->all_selects_list != sl)?"PRIMARY": ((thd->lex->all_selects_list != sl) ?
"SIMPLE"): primary_key_name : "SIMPLE"):
((sl == first)? ((sl == first)?
((sl->linkage == DERIVED_TABLE_TYPE) ? ((sl->linkage == DERIVED_TABLE_TYPE) ?
"DERIVED": "DERIVED":
((sl->uncacheable & UNCACHEABLE_DEPENDENT)? ((uncacheable & UNCACHEABLE_DEPENDENT) ?
"DEPENDENT SUBQUERY": "DEPENDENT SUBQUERY":
(sl->uncacheable?"UNCACHEABLE SUBQUERY": (uncacheable?"UNCACHEABLE SUBQUERY":
"SUBQUERY"))): "SUBQUERY"))):
((sl->uncacheable & UNCACHEABLE_DEPENDENT)? ((uncacheable & UNCACHEABLE_DEPENDENT) ?
"DEPENDENT UNION": "DEPENDENT UNION":
sl->uncacheable?"UNCACHEABLE UNION": uncacheable?"UNCACHEABLE UNION":
"UNION"))), "UNION"))),
result); result);
if (res) if (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