summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am3
-rw-r--r--sql/field.cc3
-rw-r--r--sql/item.cc34
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_sum.cc160
-rw-r--r--sql/item_sum.h79
-rw-r--r--sql/item_uniq.h2
-rw-r--r--sql/log.cc51
-rw-r--r--sql/mysql_priv.h14
-rw-r--r--sql/mysqld.cc120
-rw-r--r--sql/net_serv.cc7
-rw-r--r--sql/protocol.cc7
-rw-r--r--sql/set_var.cc136
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/slave.cc27
-rw-r--r--sql/sql_base.cc27
-rw-r--r--sql/sql_cache.cc19
-rw-r--r--sql/sql_insert.cc24
-rw-r--r--sql/sql_list.h3
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc489
-rw-r--r--sql/sql_select.h49
-rw-r--r--sql/sql_show.cc27
-rw-r--r--sql/sql_state.c53
-rw-r--r--sql/sql_string.cc4
-rw-r--r--sql/sql_string.h5
-rw-r--r--sql/sql_table.cc138
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc1
-rw-r--r--sql/sql_yacc.yy22
-rw-r--r--sql/time.cc56
-rw-r--r--sql/unireg.h4
32 files changed, 1141 insertions, 435 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index c3b7c77e252..7c98f1a9315 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -64,7 +64,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
thr_malloc.cc item_create.cc item_subselect.cc \
item_row.cc item_geofunc.cc \
field.cc key.cc sql_class.cc sql_list.cc \
- net_serv.cc protocol.cc lock.cc my_lock.c \
+ net_serv.cc protocol.cc sql_state.c \
+ lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
set_var.cc sql_parse.cc sql_yacc.yy \
diff --git a/sql/field.cc b/sql/field.cc
index 044684b2675..484eab5e130 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2755,6 +2755,7 @@ int Field_timestamp::store(longlong nr)
if ((nr=fix_datetime(nr)))
{
+ long not_used;
part1=(long) (nr/LL(1000000));
part2=(long) (nr - (longlong) part1*LL(1000000));
l_time.year= (int) (part1/10000L); part1%=10000L;
@@ -2763,7 +2764,7 @@ int Field_timestamp::store(longlong nr)
l_time.hour= (int) (part2/10000L); part2%=10000L;
l_time.minute=(int) part2 / 100;
l_time.second=(int) part2 % 100;
- timestamp=my_gmt_sec(&l_time);
+ timestamp=my_gmt_sec(&l_time, &not_used);
}
else
timestamp=0;
diff --git a/sql/item.cc b/sql/item.cc
index 42a949287e5..cdd78572a0a 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -117,7 +117,9 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
/*
- This function is only called when comparing items in the WHERE clause
+ This function is called when:
+ - Comparing items in the WHERE clause (when doing where optimization)
+ - When trying to find an ORDER BY/GROUP BY item in the SELECT part
*/
bool Item::eq(const Item *item, bool binary_cmp) const
@@ -243,6 +245,7 @@ void Item_field::set_field(Field *field_par)
decimals= field->decimals();
table_name=field_par->table_name;
field_name=field_par->field_name;
+ db_name=field_par->table->table_cache_key;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
set_charset(field_par->charset(), COER_IMPLICIT);
}
@@ -344,9 +347,34 @@ longlong Item_field::val_int_result()
return result_field->val_int();
}
+
bool Item_field::eq(const Item *item, bool binary_cmp) const
{
- return item->type() == FIELD_ITEM && ((Item_field*) item)->field == field;
+ if (item->type() != FIELD_ITEM)
+ return 0;
+
+ Item_field *item_field= (Item_field*) item;
+ if (item_field->field)
+ return item_field->field == field;
+ /*
+ We may come here when we are trying to find a function in a GROUP BY
+ clause from the select list.
+ In this case the '100 % correct' way to do this would be to first
+ run fix_fields() on the GROUP BY item and then retry this function, but
+ I think it's better to relax the checking a bit as we will in
+ most cases do the correct thing by just checking the field name.
+ (In cases where we would choose wrong we would have to generate a
+ ER_NON_UNIQ_ERROR).
+ */
+ return (!my_strcasecmp(system_charset_info, item_field->name,
+ field_name) &&
+ (!item_field->table_name ||
+ (!my_strcasecmp(table_alias_charset, item_field->table_name,
+ table_name) &&
+ (!item_field->db_name ||
+ (item_field->db_name && !my_strcasecmp(table_alias_charset,
+ item_field->db_name,
+ db_name))))));
}
table_map Item_field::used_tables() const
@@ -837,7 +865,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
}
}
- }
+ }
else if (!tmp)
return -1;
diff --git a/sql/item.h b/sql/item.h
index 2d285bbe434..5cfe8eb3907 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -29,6 +29,8 @@ class Item {
void operator=(Item &);
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr,size_t size) {} /*lint -e715 */
enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index fa8bf7e6e0f..a57291702bc 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -217,11 +217,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
** reset and add of sum_func
***********************************************************************/
-void Item_sum_sum::reset()
+Item *Item_sum_sum::copy_or_same(THD* thd)
{
- null_value=1; sum=0.0; Item_sum_sum::add();
+ return new (&thd->mem_root) Item_sum_sum(thd, *this);
}
+
+bool Item_sum_sum::reset()
+{
+ null_value=1; sum=0.0;
+ return Item_sum_sum::add();
+}
+
+
bool Item_sum_sum::add()
{
sum+=args[0]->val();
@@ -230,17 +238,26 @@ bool Item_sum_sum::add()
return 0;
}
+
double Item_sum_sum::val()
{
return sum;
}
-void Item_sum_count::reset()
+Item *Item_sum_count::copy_or_same(THD* thd)
{
- count=0; add();
+ return new (&thd->mem_root) Item_sum_count(thd, *this);
}
+
+bool Item_sum_count::reset()
+{
+ count=0;
+ return add();
+}
+
+
bool Item_sum_count::add()
{
if (!args[0]->maybe_null)
@@ -260,14 +277,22 @@ longlong Item_sum_count::val_int()
}
/*
-** Avgerage
+ Avgerage
*/
-void Item_sum_avg::reset()
+Item *Item_sum_avg::copy_or_same(THD* thd)
{
- sum=0.0; count=0; Item_sum_avg::add();
+ return new (&thd->mem_root) Item_sum_avg(thd, *this);
}
+
+bool Item_sum_avg::reset()
+{
+ sum=0.0; count=0;
+ return Item_sum_avg::add();
+}
+
+
bool Item_sum_avg::add()
{
double nr=args[0]->val();
@@ -292,7 +317,7 @@ double Item_sum_avg::val()
/*
-** Standard deviation
+ Standard deviation
*/
double Item_sum_std::val()
@@ -301,15 +326,27 @@ double Item_sum_std::val()
return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}
+Item *Item_sum_std::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_std(thd, *this);
+}
+
+
/*
-** variance
+ Variance
*/
-void Item_sum_variance::reset()
+Item *Item_sum_variance::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_variance(thd, *this);
+}
+
+
+bool Item_sum_variance::reset()
{
sum=sum_sqr=0.0;
count=0;
- (void) Item_sum_variance::add();
+ return Item_sum_variance::add();
}
bool Item_sum_variance::add()
@@ -440,6 +477,13 @@ Item_sum_hybrid::val_str(String *str)
return str; // Keep compiler happy
}
+
+Item *Item_sum_min::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_min(thd, *this);
+}
+
+
bool Item_sum_min::add()
{
switch (hybrid_type) {
@@ -487,6 +531,12 @@ bool Item_sum_min::add()
}
+Item *Item_sum_max::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_max(thd, *this);
+}
+
+
bool Item_sum_max::add()
{
switch (hybrid_type) {
@@ -541,11 +591,19 @@ longlong Item_sum_bit::val_int()
return (longlong) bits;
}
-void Item_sum_bit::reset()
+
+bool Item_sum_bit::reset()
+{
+ bits=reset_bits;
+ return add();
+}
+
+Item *Item_sum_or::copy_or_same(THD* thd)
{
- bits=reset_bits; add();
+ return new (&thd->mem_root) Item_sum_or(thd, *this);
}
+
bool Item_sum_or::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
@@ -554,6 +612,12 @@ bool Item_sum_or::add()
return 0;
}
+Item *Item_sum_and::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_and(thd, *this);
+}
+
+
bool Item_sum_and::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
@@ -1032,12 +1096,21 @@ Item_sum_count_distinct::~Item_sum_count_distinct()
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref)
{
- if (Item_sum_num::fix_fields(thd, tables, ref) ||
- !(tmp_table_param= new TMP_TABLE_PARAM))
+ if (Item_sum_num::fix_fields(thd, tables, ref))
return 1;
return 0;
}
+/* This is used by rollup to create a separate usable copy of the function */
+
+void Item_sum_count_distinct::make_unique()
+{
+ table=0;
+ original= 0;
+ tree= &tree_base;
+}
+
+
bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
@@ -1045,6 +1118,9 @@ bool Item_sum_count_distinct::setup(THD *thd)
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
return 1;
+ if (!(tmp_table_param= new TMP_TABLE_PARAM))
+ return 1;
+
/* Create a table with an unique key over all parameters */
for (uint i=0; i < arg_count ; i++)
{
@@ -1192,7 +1268,14 @@ int Item_sum_count_distinct::tree_to_myisam()
return 0;
}
-void Item_sum_count_distinct::reset()
+
+Item *Item_sum_count_distinct::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_count_distinct(thd, *this);
+}
+
+
+bool Item_sum_count_distinct::reset()
{
if (use_tree)
reset_tree(tree);
@@ -1202,7 +1285,7 @@ void Item_sum_count_distinct::reset()
table->file->delete_all_rows();
table->file->extra(HA_EXTRA_WRITE_CACHE);
}
- (void) add();
+ return add();
}
bool Item_sum_count_distinct::add()
@@ -1265,11 +1348,11 @@ longlong Item_sum_count_distinct::val_int()
#ifdef HAVE_DLOPEN
-void Item_udf_sum::reset()
+bool Item_udf_sum::reset()
{
DBUG_ENTER("Item_udf_sum::reset");
udf.reset(&null_value);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
}
bool Item_udf_sum::add()
@@ -1279,6 +1362,11 @@ bool Item_udf_sum::add()
DBUG_RETURN(0);
}
+Item *Item_sum_udf_float::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_udf_float(thd, *this);
+}
+
double Item_sum_udf_float::val()
{
DBUG_ENTER("Item_sum_udf_float::val");
@@ -1298,6 +1386,12 @@ String *Item_sum_udf_float::val_str(String *str)
}
+Item *Item_sum_udf_int::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_udf_int(thd, *this);
+}
+
+
longlong Item_sum_udf_int::val_int()
{
DBUG_ENTER("Item_sum_udf_int::val_int");
@@ -1306,6 +1400,7 @@ longlong Item_sum_udf_int::val_int()
DBUG_RETURN(udf.val_int(&null_value));
}
+
String *Item_sum_udf_int::val_str(String *str)
{
longlong nr=val_int();
@@ -1327,6 +1422,13 @@ void Item_sum_udf_str::fix_length_and_dec()
DBUG_VOID_RETURN;
}
+
+Item *Item_sum_udf_str::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_udf_str(thd, *this);
+}
+
+
String *Item_sum_udf_str::val_str(String *str)
{
DBUG_ENTER("Item_sum_udf_str::str");
@@ -1568,7 +1670,13 @@ Item_func_group_concat::~Item_func_group_concat()
}
-void Item_func_group_concat::reset()
+Item *Item_func_group_concat::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_func_group_concat(thd, *this);
+}
+
+
+bool Item_func_group_concat::reset()
{
result.length(0);
result.copy();
@@ -1582,7 +1690,7 @@ void Item_func_group_concat::reset()
}
if (tree_mode)
reset_tree(tree);
- add();
+ return add();
}
@@ -1768,6 +1876,16 @@ bool Item_func_group_concat::setup(THD *thd)
return 0;
}
+/* This is used by rollup to create a separate usable copy of the function */
+
+void Item_func_group_concat::make_unique()
+{
+ table=0;
+ original= 0;
+ tree= &tree_base;
+}
+
+
String* Item_func_group_concat::val_str(String* str)
{
if (null_value)
diff --git a/sql/item_sum.h b/sql/item_sum.h
index f996f980fff..c8614dda679 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -26,9 +26,11 @@
class Item_sum :public Item_result_field
{
public:
- enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
- MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
- UDF_SUM_FUNC, GROUP_CONCAT_FUNC };
+ enum Sumfunctype
+ { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
+ MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
+ UDF_SUM_FUNC, GROUP_CONCAT_FUNC
+ };
Item **args,*tmp_args[2];
uint arg_count;
@@ -60,7 +62,7 @@ public:
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
- virtual void reset()=0;
+ virtual bool reset()=0;
virtual bool add()=0;
virtual void reset_field()=0;
virtual void update_field(int offset)=0;
@@ -78,6 +80,7 @@ public:
void fix_num_length_and_dec();
void no_rows_in_result() { reset(); }
virtual bool setup(THD *thd) {return 0;}
+ virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
};
@@ -121,14 +124,14 @@ class Item_sum_sum :public Item_sum_num
Item_sum_sum(THD *thd, Item_sum_sum &item)
:Item_sum_num(thd, item), sum(item.sum) {}
enum Sumfunctype sum_func () const {return SUM_FUNC;}
- void reset();
+ bool reset();
bool add();
double val();
void reset_field();
void update_field(int offset);
void no_rows_in_result() {}
const char *func_name() const { return "sum"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_sum(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -148,7 +151,7 @@ class Item_sum_count :public Item_sum_int
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
- void reset();
+ bool reset();
void no_rows_in_result() { count=0; }
bool add();
void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
@@ -156,7 +159,7 @@ class Item_sum_count :public Item_sum_int
void reset_field();
void update_field(int offset);
const char *func_name() const { return "count"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_count(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -222,17 +225,15 @@ class Item_sum_count_distinct :public Item_sum_int
table_map used_tables() const { return used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
- void reset();
+ bool reset();
bool add();
longlong val_int();
void reset_field() { return ;} // Never called
void update_field(int offset) { return ; } // Never called
const char *func_name() const { return "count_distinct"; }
bool setup(THD *thd);
- Item *copy_or_same(THD* thd)
- {
- return new Item_sum_count_distinct(thd, *this);
- }
+ void make_unique();
+ Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
};
@@ -268,7 +269,7 @@ class Item_sum_avg :public Item_sum_num
Item_sum_avg(THD *thd, Item_sum_avg &item)
:Item_sum_num(thd, item), sum(item.sum), count(item.count) {}
enum Sumfunctype sum_func () const {return AVG_FUNC;}
- void reset();
+ bool reset();
bool add();
double val();
void reset_field();
@@ -276,7 +277,7 @@ class Item_sum_avg :public Item_sum_num
Item *result_item(Field *field)
{ return new Item_avg_field(this); }
const char *func_name() const { return "avg"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_avg(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
class Item_sum_variance;
@@ -321,7 +322,7 @@ class Item_sum_variance : public Item_sum_num
Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr),
count(item.count) {}
enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
- void reset();
+ bool reset();
bool add();
double val();
void reset_field();
@@ -329,7 +330,7 @@ class Item_sum_variance : public Item_sum_num
Item *result_item(Field *field)
{ return new Item_variance_field(this); }
const char *func_name() const { return "variance"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_variance(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
class Item_sum_std;
@@ -349,12 +350,16 @@ public:
class Item_sum_std :public Item_sum_variance
{
public:
- Item_sum_std(Item *item_par) :Item_sum_variance(item_par){}
+ Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {}
+ Item_sum_std(THD *thd, Item_sum_std &item)
+ :Item_sum_variance(thd, item)
+ {}
enum Sumfunctype sum_func () const { return STD_FUNC; }
double val();
Item *result_item(Field *field)
{ return new Item_std_field(this); }
const char *func_name() const { return "std"; }
+ Item *copy_or_same(THD* thd);
};
// This class is a string or number function depending on num_func
@@ -386,13 +391,13 @@ class Item_sum_hybrid :public Item_sum
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
- void reset()
+ bool reset()
{
sum=0.0;
sum_int=0;
value.length(0);
null_value=1;
- add();
+ return add();
}
double val();
longlong val_int();
@@ -418,7 +423,7 @@ public:
bool add();
const char *func_name() const { return "min"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_min(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -431,7 +436,7 @@ public:
bool add();
const char *func_name() const { return "max"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_max(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -446,7 +451,7 @@ class Item_sum_bit :public Item_sum_int
Item_sum_bit(THD *thd, Item_sum_bit &item):
Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {}
enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;}
- void reset();
+ bool reset();
longlong val_int();
void reset_field();
void fix_length_and_dec()
@@ -462,7 +467,7 @@ class Item_sum_or :public Item_sum_bit
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_or"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_or(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -474,7 +479,7 @@ class Item_sum_and :public Item_sum_bit
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_and"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_and(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
/*
@@ -504,7 +509,7 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
virtual bool have_field_update(void) const { return 0; }
- void reset();
+ bool reset();
bool add();
void reset_field() {};
void update_field(int offset_arg) {};
@@ -524,7 +529,7 @@ class Item_sum_udf_float :public Item_udf_sum
double val();
String *val_str(String*str);
void fix_length_and_dec() { fix_num_length_and_dec(); }
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -542,7 +547,7 @@ public:
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() { decimals=0; max_length=21; }
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -571,7 +576,7 @@ public:
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
#else /* Dummy functions to get sql_yacc.cc compiled */
@@ -586,10 +591,9 @@ class Item_sum_udf_float :public Item_sum_num
~Item_sum_udf_float() {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
double val() { return 0.0; }
- void reset() {}
+ bool reset() { return 0; }
bool add() { return 0; }
void update_field(int offset) {}
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); }
};
@@ -604,10 +608,9 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
longlong val_int() { return 0; }
double val() { return 0; }
- void reset() {}
+ bool reset() { return 0; }
bool add() { return 0; }
void update_field(int offset) {}
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); }
};
@@ -625,10 +628,9 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec() { maybe_null=1; max_length=0; }
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
- void reset() {}
+ bool reset() { return 0; }
bool add() { return 0; }
void update_field(int offset) {}
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); }
};
#endif /* HAVE_DLOPEN */
@@ -676,7 +678,7 @@ class Item_func_group_concat : public Item_sum
warning(item.warning),
warning_available(item.warning_available),
separator(item.separator),
- tree(item.tree),
+ tree(item.tree),
table(item.table),
expr(item.expr),
order(item.order),
@@ -700,11 +702,12 @@ class Item_func_group_concat : public Item_sum
enum Type type() const { return SUM_FUNC_ITEM; }
void fix_length_and_dec() { max_length=group_concat_max_len; }
virtual Item_result result_type () const { return STRING_RESULT; }
- void reset();
+ bool reset();
bool add();
void reset_field();
bool fix_fields(THD *, TABLE_LIST *, Item **);
bool setup(THD *thd);
+ void make_unique();
virtual void update_field(int offset) {};
double val()
{
@@ -717,5 +720,5 @@ class Item_func_group_concat : public Item_sum
return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
}
String* val_str(String* str);
- Item *copy_or_same(THD* thd) { return new Item_func_group_concat(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index 5ffd10be7a5..f2c64c4bde9 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -41,7 +41,7 @@ public:
:Item_sum_num(thd, item) {}
double val() { return 0.0; }
enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
- void reset() {}
+ bool reset() { return 0;}
bool add() { return 0; }
void reset_field() {}
void update_field(int offset) {}
diff --git a/sql/log.cc b/sql/log.cc
index c05d52bdc5d..0ccb40c5246 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1200,6 +1200,12 @@ bool MYSQL_LOG::write(Log_event* event_info)
No check for auto events flag here - this write method should
never be called if auto-events are enabled
*/
+
+ /*
+ 1. Write first log events which describe the 'run environment'
+ of the SQL command
+ */
+
if (thd)
{
if (thd->last_insert_id_used)
@@ -1245,7 +1251,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
goto err;
}
}
-#if 0
+#ifdef TO_BE_REMOVED
if (thd->variables.convert_set)
{
char buf[256], *p;
@@ -1257,12 +1263,39 @@ bool MYSQL_LOG::write(Log_event* event_info)
goto err;
}
#endif
+
+ /*
+ If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL
+ command in the binlog inside:
+ SET FOREIGN_KEY_CHECKS=0;
+ <command>;
+ SET FOREIGN_KEY_CHECKS=1;
+ */
+
+ if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
+ {
+ Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
}
+
+ /* Write the SQL command */
+
event_info->set_log_pos(this);
- if (event_info->write(file) ||
- file == &log_file && flush_io_cache(file))
+ if (event_info->write(file))
goto err;
- error=0;
+
+ /* Write log events to reset the 'run environment' of the SQL command */
+
+ if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
+ {
+ Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
/*
Tell for transactional table handlers up to which position in the
@@ -1283,6 +1316,9 @@ bool MYSQL_LOG::write(Log_event* event_info)
if (file == &log_file) // we are writing to the real log (disk)
{
+ if (flush_io_cache(file))
+ goto err;
+
if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log))
{
/*
@@ -1292,8 +1328,8 @@ bool MYSQL_LOG::write(Log_event* event_info)
handler if the log event type is appropriate.
*/
- if (event_info->get_type_code() == QUERY_EVENT
- || event_info->get_type_code() == EXEC_LOAD_EVENT)
+ if (event_info->get_type_code() == QUERY_EVENT ||
+ event_info->get_type_code() == EXEC_LOAD_EVENT)
{
error = ha_report_binlog_offset_and_commit(thd, log_file_name,
file->pos_in_file);
@@ -1303,6 +1339,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
/* we wrote to the real log, check automatic rotation */
should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size);
}
+ error=0;
err:
if (error)
@@ -1329,7 +1366,7 @@ err:
Flush the transactional handler log file now that we have released
LOCK_log; the flush is placed here to eliminate the bottleneck on the
group commit
- */
+ */
if (called_handler_commit)
ha_commit_complete(thd);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a59f1d4b81a..0508d0aa986 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -66,9 +66,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#endif
#endif
-extern CHARSET_INFO *system_charset_info;
-extern CHARSET_INFO *files_charset_info;
-extern CHARSET_INFO *national_charset_info;
+extern CHARSET_INFO *system_charset_info, *files_charset_info ;
+extern CHARSET_INFO *national_charset_info, *table_alias_charset;
/***************************************************************************
Configuration parameters
@@ -208,7 +207,7 @@ extern CHARSET_INFO *national_charset_info;
#define MODE_PIPES_AS_CONCAT 2
#define MODE_ANSI_QUOTES 4
#define MODE_IGNORE_SPACE 8
-#define MODE_SERIALIZABLE 16
+#define MODE_NOT_USED 16
#define MODE_ONLY_FULL_GROUP_BY 32
#define MODE_NO_UNSIGNED_SUBTRACTION 64
#define MODE_POSTGRESQL 128
@@ -221,6 +220,7 @@ extern CHARSET_INFO *national_charset_info;
#define MODE_NO_FIELD_OPTIONS 16384
#define MODE_MYSQL323 32768
#define MODE_MYSQL40 65536
+#define MODE_ANSI (MODE_MYSQL40*2)
#define RAID_BLOCK_SIZE 1024
@@ -461,7 +461,6 @@ bool mysql_rename_table(enum db_type base,
const char * old_name,
const char *new_db,
const char * new_name);
-bool close_cached_table(THD *thd,TABLE *table);
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
@@ -501,6 +500,7 @@ Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
#ifdef HAVE_OPENSSL
+#include <openssl/des.h>
struct st_des_keyblock
{
des_cblock key1, key2, key3;
@@ -723,7 +723,7 @@ extern ulong ha_read_rnd_count, ha_read_rnd_next_count;
extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong max_insert_delayed_threads, max_user_connections;
-extern ulong long_query_count, what_to_log,flush_time,opt_sql_mode;
+extern ulong long_query_count, what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size;
@@ -837,7 +837,7 @@ uint calc_days_in_year(uint year);
void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
void init_time(void);
-long my_gmt_sec(TIME *);
+long my_gmt_sec(TIME *, long *current_timezone);
time_t str_to_timestamp(const char *str,uint length);
bool str_to_time(const char *str,uint length,TIME *l_time);
longlong str_to_datetime(const char *str,uint length,bool fuzzy_date);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1a595c46e81..2d5ce52d557 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -208,9 +208,9 @@ const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
const char *sql_mode_names[] =
{
"REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
- "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
+ "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
"POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS",
- "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40",
+ "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
NullS
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
@@ -324,6 +324,9 @@ MY_TMPDIR mysql_tmpdir_list;
DATE_FORMAT dayord;
MY_BITMAP temp_pool;
+CHARSET_INFO *system_charset_info, *files_charset_info ;
+CHARSET_INFO *national_charset_info, *table_alias_charset;
+
SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam;
SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache;
SHOW_COMP_OPTION have_crypt, have_compress;
@@ -562,7 +565,7 @@ static void close_connections(void)
unix_sock= INVALID_SOCKET;
}
#endif
- end_thr_alarm(); // Don't allow alarms
+ end_thr_alarm(0); // Abort old alarms.
end_slave();
/* First signal all threads that it's time to die */
@@ -871,6 +874,7 @@ void clean_up(bool print_message)
#endif
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
end_key_cache();
+ end_thr_alarm(1); /* Free allocated memory */
#ifdef USE_RAID
end_raid();
#endif
@@ -936,7 +940,6 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_crypt);
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
- (void) pthread_mutex_destroy(&LOCK_timezone);
(void) pthread_mutex_destroy(&LOCK_user_conn);
#ifdef HAVE_REPLICATION
(void) pthread_mutex_destroy(&LOCK_rpl_status);
@@ -1497,7 +1500,6 @@ the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size);
fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size);
- fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size);
fprintf(stderr, "max_used_connections=%ld\n", max_used_connections);
fprintf(stderr, "max_connections=%ld\n", max_connections);
fprintf(stderr, "threads_connected=%d\n", thread_count);
@@ -1505,7 +1507,7 @@ and this may fail.\n\n");
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\
bytes of memory\n", ((ulong) keybuff_size +
(global_system_variables.read_buff_size +
- thd->variables.sortbuff_size) *
+ global_system_variables.sortbuff_size) *
max_connections)/ 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
@@ -1534,14 +1536,9 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
Some pointers may be invalid and cause the dump to abort...\n");
safe_print_str("thd->query", thd->query, 1024);
fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id);
- fprintf(stderr, "\n\
-Successfully dumped variables, if you ran with --log, take a look at the\n\
-details of what thread %ld did to cause the crash. In some cases of really\n\
-bad corruption, the values shown above may be invalid.\n\n",
- thd->thread_id);
}
fprintf(stderr, "\
-The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\
+The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\
information that should help you find out what is causing the crash.\n");
fflush(stderr);
#endif /* HAVE_STACKTRACE */
@@ -1565,6 +1562,7 @@ information that should help you find out what is causing the crash.\n");
static void init_signals(void)
{
sigset_t set;
+ struct sigaction sa;
DBUG_ENTER("init_signals");
sigset(THR_KILL_SIGNAL,end_thread_signal);
@@ -1572,7 +1570,6 @@ static void init_signals(void)
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
{
- struct sigaction sa;
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
sigemptyset(&sa.sa_mask);
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
@@ -1614,15 +1611,23 @@ static void init_signals(void)
sigaddset(&set,SIGQUIT);
sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP);
- sigset(SIGTERM, print_signal_warning); // If it's blocked by parent
- sigset(SIGHUP, print_signal_warning); // If it's blocked by parent
+
+ /* Fix signals if blocked by parents (can happen on Mac OS X) */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = print_signal_warning;
+ sigaction(SIGTERM, &sa, (struct sigaction*) 0);
+ sa.sa_flags = 0;
+ sa.sa_handler = print_signal_warning;
+ sigaction(SIGHUP, &sa, (struct sigaction*) 0);
#ifdef SIGTSTP
sigaddset(&set,SIGTSTP);
#endif
sigaddset(&set,THR_SERVER_ALARM);
sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT
sigdelset(&set,THR_CLIENT_ALARM); // For alarms
- (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
+ sigprocmask(SIG_SETMASK,&set,NULL);
+ pthread_sigmask(SIG_SETMASK,&set,NULL);
DBUG_VOID_RETURN;
}
@@ -1890,7 +1895,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
#endif
-const char *load_default_groups[]= { "mysqld","server",0 };
+const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0 };
bool open_log(MYSQL_LOG *log, const char *hostname,
const char *opt_name, const char *extension,
@@ -1947,19 +1952,11 @@ static int init_common_variables(const char *conf_file_name, int argc,
}
#endif
#ifdef HAVE_TZNAME
-#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
{
struct tm tm_tmp;
localtime_r(&start_time,&tm_tmp);
strmov(time_zone,tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]);
}
-#else
- {
- struct tm *start_tm;
- start_tm=localtime(&start_time);
- strmov(time_zone,tzname[start_tm->tm_isdst != 0 ? 1 : 0]);
- }
-#endif
#endif
if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
@@ -2073,7 +2070,6 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
@@ -2282,9 +2278,7 @@ static void handle_connections_methods()
#endif /* __NT__ */
if (have_tcpip && !opt_disable_networking)
{
-#ifdef __NT__
handler_count++;
-#endif
if (pthread_create(&hThread,&connection_attrib,
handle_connections_sockets, 0))
{
@@ -2295,9 +2289,7 @@ static void handle_connections_methods()
#ifdef HAVE_SMEM
if (opt_enable_shared_memory)
{
-#ifdef __NT__
handler_count++;
-#endif
if (pthread_create(&hThread,&connection_attrib,
handle_connections_shared_memory, 0))
{
@@ -2312,6 +2304,16 @@ static void handle_connections_methods()
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
+
+void decrement_handler_count()
+{
+ pthread_mutex_lock(&LOCK_thread_count);
+ handler_count--;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_cond_signal(&COND_handler_count);
+}
+#else
+#define decrement_handler_count()
#endif /* defined(__NT__) || defined(HAVE_SMEM) */
@@ -2429,18 +2431,18 @@ The server will not act as a slave.");
#endif
/* init_slave() must be called after the thread keys are created */
init_slave();
-
+
if (opt_bootstrap)
{
int error=bootstrap(stdin);
- end_thr_alarm(); // Don't allow alarms
+ end_thr_alarm(1); // Don't allow alarms
unireg_abort(error ? 1 : 0);
}
if (opt_init_file)
{
if (read_init_file(opt_init_file))
{
- end_thr_alarm(); // Don't allow alarms
+ end_thr_alarm(1); // Don't allow alarms
unireg_abort(1);
}
}
@@ -2612,9 +2614,12 @@ int main(int argc, char **argv)
return 0;
if (Service.IsService(argv[2]))
{
- /* start an optional service */
+ /*
+ mysqld was started as
+ mysqld --defaults-file=my_path\my.ini service-name
+ */
use_opt_args=1;
- opt_argc=argc;
+ opt_argc= 2; // Skip service-name
opt_argv=argv;
start_mode= 1;
Service.Init(argv[2], mysql_service);
@@ -3020,13 +3025,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
// kill server must be invoked from thread 1!
kill_server(MYSQL_KILL_SIGNAL);
#endif
-
-#ifdef __NT__
- pthread_mutex_lock(&LOCK_thread_count);
- handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
- pthread_cond_signal(&COND_handler_count);
-#endif
+ decrement_handler_count();
DBUG_RETURN(0);
}
@@ -3106,10 +3105,7 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
create_new_thread(thd);
}
- pthread_mutex_lock(&LOCK_thread_count);
- handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
- pthread_cond_signal(&COND_handler_count);
+ decrement_handler_count();
DBUG_RETURN(0);
}
#endif /* __NT__ */
@@ -3323,12 +3319,8 @@ error:
if (!handle_connect_file_map) CloseHandle(handle_connect_file_map);
if (!event_connect_answer) CloseHandle(event_connect_answer);
if (!event_connect_request) CloseHandle(event_connect_request);
-#ifdef __NT__
- pthread_mutex_lock(&LOCK_thread_count);
- handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
- pthread_cond_signal(&COND_handler_count);
-#endif
+
+ decrement_handler_count();
DBUG_RETURN(0);
}
#endif /* HAVE_SMEM */
@@ -3922,7 +3914,7 @@ replicating a LOAD DATA INFILE command",
(gptr*) &opt_sql_bin_update, (gptr*) &opt_sql_bin_update, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
- "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
+ "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
(gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
#ifdef HAVE_OPENSSL
@@ -4635,6 +4627,12 @@ static void mysql_init_variables(void)
bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
bzero((gptr) &com_stat, sizeof(com_stat));
+ /* Character sets */
+ system_charset_info= &my_charset_utf8_general_ci;
+ files_charset_info= &my_charset_utf8_general_ci;
+ national_charset_info= &my_charset_utf8_general_ci;
+ table_alias_charset= &my_charset_bin;
+
/* Things with default values that are not zero */
delay_key_write_options= (uint) DELAY_KEY_WRITE_ON;
opt_specialflag= SPECIAL_ENGLISH;
@@ -4685,6 +4683,7 @@ static void mysql_init_variables(void)
default_collation_name= (char*) MYSQL_DEFAULT_COLLATION_NAME;
sys_charset_system.value= (char*) system_charset_info->csname;
+
/* Set default values for some option variables */
global_system_variables.character_set_server= default_charset_info;
global_system_variables.character_set_database= default_charset_info;
@@ -4792,10 +4791,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_endinfo=1; /* unireg: memory allocation */
break;
case 'a':
- global_system_variables.sql_mode=
- (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT |
- MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE |
- MODE_ONLY_FULL_GROUP_BY);
+ global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI);
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
break;
case 'b':
@@ -5273,11 +5269,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
fprintf(stderr, "Unknown option to sql-mode: %s\n", argument);
exit(1);
}
- global_system_variables.tx_isolation=
- ((global_system_variables.sql_mode & MODE_SERIALIZABLE) ?
- ISO_SERIALIZABLE :
- ISO_REPEATABLE_READ);
- break;
+ global_system_variables.sql_mode= fix_sql_mode(global_system_variables.
+ sql_mode);
}
case OPT_MASTER_PASSWORD:
master_password=argument;
@@ -5335,6 +5328,9 @@ static void get_options(int argc,char **argv)
/* Set global variables based on startup options */
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
+ table_alias_charset= (lower_case_table_names ?
+ files_charset_info :
+ &my_charset_bin);
}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 8271d971782..621fa5f6334 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -15,6 +15,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
+ This file is the net layer API for the MySQL client/server protocol,
+ which is a tightly coupled, proprietary protocol owned by MySQL AB.
+ Any re-implementations of this protocol must also be under GPL
+ unless one has got an license from MySQL AB stating otherwise.
+*/
+
+/*
Write and read of logical packets to/from socket
Writes are cached into net_buffer_length big packets.
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 7abbf3ce85b..10fe2c1725e 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -102,7 +102,8 @@ void send_error(THD *thd, uint sql_errno, const char *err)
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
/* The first # is to make the protocol backward compatible */
- strmov(buff+2, "#000000");
+ buff[2]= '#';
+ strmov(buff+3, mysql_errno_to_sqlstate(sql_errno));
pos= buff + 2 + SQLSTATE_LENGTH +1;
}
length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff);
@@ -222,8 +223,8 @@ net_printf(THD *thd, uint errcode, ...)
int2store(pos, errcode);
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- /* The first # is to make the protocol backward compatible */
- memcpy(pos+2, "#000000", SQLSTATE_LENGTH +1);
+ pos[2]= '#'; /* To make the protocol backward compatible */
+ memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
}
}
VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 60b0d24430d..ad3966f76f9 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -89,6 +89,7 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type);
static void fix_key_buffer_size(THD *thd, enum_var_type type);
static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type);
static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type);
+void fix_sql_mode_var(THD *thd, enum_var_type type);
static byte *get_error_count(THD *thd);
static byte *get_warning_count(THD *thd);
@@ -207,6 +208,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
&SV::read_buff_size);
+sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
&SV::read_rnd_buff_size);
#ifdef HAVE_REPLICATION
@@ -235,7 +237,6 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
&slave_net_timeout);
#endif
-sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
sys_var_long_ptr sys_slow_launch_time("slow_launch_time",
&slow_launch_time);
sys_var_thd_ulong sys_sort_buffer("sort_buffer_size",
@@ -599,6 +600,7 @@ struct show_var_st init_vars[]= {
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
{sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
+ {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
{sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
#ifdef HAVE_REPLICATION
{sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
@@ -1168,40 +1170,6 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type)
-{
- ulong val;
- char buff[256];
- String tmp(buff, sizeof(buff), &my_charset_latin1);
- my_bool found= 0;
-
- tmp.length(0);
- val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
- thd->variables.*offset);
- for (uint i= 0; val; val>>= 1, i++)
- {
- if (val & 1)
- {
- tmp.append(enum_names->type_names[i]);
- tmp.append(',');
- }
- }
- if (tmp.length())
- tmp.length(tmp.length() - 1);
- return (byte*) thd->strmake(tmp.ptr(), tmp.length());
-}
-
-
-void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= 0;
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-
bool sys_var_thd_bit::update(THD *thd, set_var *var)
{
int res= (*update_func)(thd, var);
@@ -1857,7 +1825,105 @@ int set_var_password::update(THD *thd)
1 : 0);
}
+/****************************************************************************
+ Functions to handle sql_mode
+****************************************************************************/
+
+byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type)
+{
+ ulong val;
+ char buff[256];
+ String tmp(buff, sizeof(buff), &my_charset_latin1);
+ my_bool found= 0;
+
+ tmp.length(0);
+ val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
+ thd->variables.*offset);
+ for (uint i= 0; val; val>>= 1, i++)
+ {
+ if (val & 1)
+ {
+ tmp.append(enum_names->type_names[i]);
+ tmp.append(',');
+ }
+ }
+ if (tmp.length())
+ tmp.length(tmp.length() - 1);
+ return (byte*) thd->strmake(tmp.ptr(), tmp.length());
+}
+
+
+void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.*offset= 0;
+ else
+ thd->variables.*offset= global_system_variables.*offset;
+}
+
+void fix_sql_mode_var(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.sql_mode=
+ fix_sql_mode(global_system_variables.sql_mode);
+ else
+ thd->variables.sql_mode= fix_sql_mode(thd->variables.sql_mode);
+}
+
+/* Map database specific bits to function bits */
+ulong fix_sql_mode(ulong sql_mode)
+{
+ /*
+ Note that we dont set
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS
+ to allow one to get full use of MySQL in this mode.
+ */
+
+ if (sql_mode & MODE_ANSI)
+ sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE | MODE_ONLY_FULL_GROUP_BY);
+ if (sql_mode & MODE_ORACLE)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MSSQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MSSQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_POSTGRESQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_DB2)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_DB2)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_SAPDB)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MYSQL40)
+ sql_mode|= MODE_NO_FIELD_OPTIONS;
+ if (sql_mode & MODE_MYSQL323)
+ sql_mode|= MODE_NO_FIELD_OPTIONS;
+ return sql_mode;
+}
diff --git a/sql/set_var.h b/sql/set_var.h
index d016c3a7085..998d61ff2d1 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -309,11 +309,14 @@ public:
};
+extern void fix_sql_mode_var(THD *thd, enum_var_type type);
+
class sys_var_thd_sql_mode :public sys_var_thd_enum
{
public:
sys_var_thd_sql_mode(const char *name_arg, ulong SV::*offset_arg)
- :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib)
+ :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib,
+ fix_sql_mode_var)
{}
bool check(THD *thd, set_var *var)
{
@@ -636,6 +639,7 @@ void set_var_free();
sys_var *find_sys_var(const char *str, uint length=0);
int sql_set_variables(THD *thd, List<set_var_base> *var_list);
void fix_delay_key_write(THD *thd, enum_var_type type);
+ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
diff --git a/sql/slave.cc b/sql/slave.cc
index 22c47bbdd05..4767245834a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1388,9 +1388,7 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
- {
pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
- }
thd->proc_info = save_proc_info;
pthread_mutex_unlock(&rli->log_space_lock);
DBUG_RETURN(slave_killed);
@@ -2101,7 +2099,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
Log_event * ev = next_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
if (sql_slave_killed(thd,rli))
+ {
+ /* do not forget to free ev ! */
+ if (ev) delete ev;
return 1;
+ }
if (ev)
{
int type_code = ev->get_type_code();
@@ -2376,6 +2378,18 @@ reconnect done to recover from failed read");
goto err;
}
flush_master_info(mi);
+ /*
+ See if the relay logs take too much space.
+ We don't lock mi->rli.log_space_lock here; this dirty read saves time
+ and does not introduce any problem:
+ - if mi->rli.ignore_log_space_limit is 1 but becomes 0 just after (so
+ the clean value is 0), then we are reading only one more event as we
+ should, and we'll block only at the next event. No big deal.
+ - if mi->rli.ignore_log_space_limit is 0 but becomes 1 just after (so
+ the clean value is 1), then we are going into wait_for_relay_log_space()
+ for no reason, but this function will do a clean read, notice the clean
+ value and exit immediately.
+ */
if (mi->rli.log_space_limit && mi->rli.log_space_limit <
mi->rli.log_space_total &&
!mi->rli.ignore_log_space_limit)
@@ -2489,7 +2503,9 @@ slave_begin:
pthread_cond_broadcast(&rli->start_cond);
//tell the I/O thread to take relay_log_space_limit into account from now on
+ pthread_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0;
+ pthread_mutex_unlock(&rli->log_space_lock);
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
@@ -3223,7 +3239,12 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
pthread_mutex_lock(&rli->log_space_lock);
// prevent the I/O thread from blocking next times
rli->ignore_log_space_limit= 1;
- // If the I/O thread is blocked, unblock it
+ /*
+ If the I/O thread is blocked, unblock it.
+ Ok to broadcast after unlock, because the mutex is only destroyed in
+ ~st_relay_log_info(), i.e. when rli is destroyed, and rli will not be
+ destroyed before we exit the present function.
+ */
pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
// Note that wait_for_update unlocks lock_log !
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 81c620fdaf4..1ef4e9df020 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -544,7 +544,8 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table,
{
for (; table; table= table->next)
if ((!db_name || !strcmp(table->db, db_name)) &&
- (!table_name || !strcmp(table->alias, table_name)))
+ (!table_name || !my_strcasecmp(table_alias_charset,
+ table->alias, table_name)))
break;
return table;
}
@@ -1739,7 +1740,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
bool found_table=0;
for (; tables ; tables=tables->next)
{
- if (!strcmp(tables->alias,table_name) &&
+ if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
(!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db)))
{
found_table=1;
@@ -1868,20 +1869,22 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
List_iterator<Item> li(items);
Item **found=0,*item;
+ const char *db_name=0;
const char *field_name=0;
const char *table_name=0;
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
{
field_name= ((Item_ident*) find)->field_name;
table_name= ((Item_ident*) find)->table_name;
+ db_name= ((Item_ident*) find)->db_name;
}
for (uint i= 0; (item=li++); i++)
{
if (field_name && item->type() == Item::FIELD_ITEM)
{
- if (!my_strcasecmp(system_charset_info,
- ((Item_field*) item)->name,field_name))
+ Item_field *item_field= (Item_field*) item;
+ if (!my_strcasecmp(system_charset_info, item_field->name, field_name))
{
if (!table_name)
{
@@ -1897,11 +1900,16 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
found= li.ref();
*counter= i;
}
- else if (!strcmp(((Item_field*) item)->table_name,table_name))
+ else
{
- found= li.ref();
- *counter= i;
- break;
+ if (!strcmp(item_field->table_name,table_name) &&
+ (!db_name || (db_name && item_field->db_name &&
+ !strcmp(item_field->table_name,table_name))))
+ {
+ found= li.ref();
+ *counter= i;
+ break;
+ }
}
}
}
@@ -2094,7 +2102,8 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
for (; tables ; tables=tables->next)
{
TABLE *table=tables->table;
- if (!table_name || (!strcmp(table_name,tables->alias) &&
+ if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
+ tables->alias) &&
(!db_name || !strcmp(tables->db,db_name))))
{
/* Ensure that we have access right to all columns */
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index adc3d177fdf..ac6471e794c 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -739,7 +739,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
query_cache_size_arg));
free_cache(0);
query_cache_size= query_cache_size_arg;
- DBUG_RETURN(init_cache());
+ DBUG_RETURN(::query_cache_size= init_cache());
}
@@ -1318,6 +1318,12 @@ ulong Query_cache::init_cache()
mem_bin_steps = 1;
mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
prev_size = 0;
+ if (mem_bin_size <= min_allocation_unit)
+ {
+ DBUG_PRINT("qcache", ("too small query cache => query cache disabled"));
+ // TODO here (and above) should be warning in 4.1
+ goto err;
+ }
while (mem_bin_size > min_allocation_unit)
{
mem_bin_num += mem_bin_count;
@@ -1344,14 +1350,6 @@ ulong Query_cache::init_cache()
query_cache_size -= additional_data_size;
STRUCT_LOCK(&structure_guard_mutex);
- if (max_mem_bin_size <= min_allocation_unit)
- {
- DBUG_PRINT("qcache",
- (" max bin size (%lu) <= min_allocation_unit => cache disabled",
- max_mem_bin_size));
- STRUCT_UNLOCK(&structure_guard_mutex);
- goto err;
- }
if (!(cache = (byte *)
my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
@@ -1432,7 +1430,8 @@ ulong Query_cache::init_cache()
#else
// windows, OS/2 or other case insensitive file names work around
VOID(hash_init(&tables,
- lower_case_table_names ? &my_charset_bin : system_charset_info,
+ lower_case_table_names ? &my_charset_bin :
+ system_charset_info,
def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0));
#endif
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c3a399cd5a7..f65ef4b968a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1421,6 +1421,24 @@ void select_insert::send_error(uint errcode,const char *err)
::send_error(thd,errcode,err);
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd);
+ /*
+ If at least one row has been inserted/modified and will stay in the table
+ (the table doesn't have transactions) (example: we got a duplicate key
+ error while inserting into a MyISAM table) we must write to the binlog (and
+ the error code will make the slave stop).
+ */
+ if ((info.copied || info.deleted) && !table->file->has_transactions())
+ {
+ if (last_insert_id)
+ thd->insert_id(last_insert_id); // For binary log
+ mysql_update_log.write(thd,thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ table->file->has_transactions());
+ mysql_bin_log.write(&qinfo);
+ }
+ }
if (info.copied || info.deleted)
query_cache_invalidate3(thd, table, 1);
ha_rollback_stmt(thd);
@@ -1442,7 +1460,10 @@ bool select_insert::send_eof()
if (info.copied || info.deleted)
query_cache_invalidate3(thd, table, 1);
+ if (last_insert_id)
+ thd->insert_id(last_insert_id); // For binary log
/* Write to binlog before commiting transaction */
+ mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -1467,10 +1488,7 @@ bool select_insert::send_eof()
else
sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
thd->cuted_fields);
- if (last_insert_id)
- thd->insert_id(last_insert_id); // For update log
::send_ok(thd,info.copied+info.deleted,last_insert_id,buff);
- mysql_update_log.write(thd,thd->query,thd->query_length);
return 0;
}
}
diff --git a/sql/sql_list.h b/sql/sql_list.h
index ff21663576a..2450b2051f2 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -33,6 +33,8 @@ public:
{
return (void*) sql_alloc((uint) size);
}
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr, size_t size) {} /*lint -e715 */
static void operator delete[](void *ptr, size_t size) {}
#ifdef HAVE_purify
@@ -190,6 +192,7 @@ public:
inline void *replace(void *element)
{ // Return old element
void *tmp=current->info;
+ DBUG_ASSERT(current->info != 0);
current->info=element;
return tmp;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 95ac57013da..fcddc2d2252 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -663,7 +663,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
thd->protocol_simple.send_fields(&fields, 0) ||
send_item_params(stmt))
DBUG_RETURN(1);
- join->cleanup(thd);
+ join->cleanup();
}
DBUG_RETURN(0);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 4167da5802a..61a64573eaa 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -138,7 +138,6 @@ static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool alloc_group_fields(JOIN *join,ORDER *group);
-static bool make_sum_func_list(JOIN *join,List<Item> &fields);
// Create list for using with tempory table
static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
List<Item> &new_list1,
@@ -153,7 +152,7 @@ static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
-static void init_sum_functions(Item_sum **func);
+static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct, const char *message=NullS);
@@ -313,9 +312,11 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having->with_sum_func)
having->split_sum_func(ref_pointer_array, all_fields);
}
-
+
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
+
+
/*
Check if one one uses a not constant column with group functions
and no GROUP BY.
@@ -345,45 +346,47 @@ JOIN::prepare(Item ***rref_pointer_array,
for (table=tables_list ; table ; table=table->next)
tables++;
}
+ {
+ /* Caclulate the number of groups */
+ send_group_parts= 0;
+ for (ORDER *group= group_list ; group ; group= group->next)
+ send_group_parts++;
+ }
+
procedure= setup_procedure(thd, proc_param, result, fields_list, &error);
if (error)
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
if (procedure)
{
if (setup_new_fields(thd, tables_list, fields_list, all_fields,
procedure->param_fields))
- { /* purecov: inspected */
- delete procedure; /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
- }
+ goto err; /* purecov: inspected */
if (procedure->group)
{
if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */
- delete procedure; /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
}
#ifdef NOT_NEEDED
else if (!group_list && procedure->flags & PROC_GROUP)
{
my_message(0,"Select must have a group with this procedure",MYF(0));
- delete procedure;
- DBUG_RETURN(-1);
+ goto err;
}
#endif
if (order && (procedure->flags & PROC_NO_SORT))
- { /* purecov: inspected */
+ { /* purecov: inspected */
my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */
- delete procedure; /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
}
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
+ ref_pointer_array_size= all_fields.elements*sizeof(Item*);
this->group= group_list != 0;
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
@@ -398,15 +401,23 @@ JOIN::prepare(Item ***rref_pointer_array,
if (sum_func_count && !group_list && (func_count || field_count))
{
my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
- delete procedure;
- DBUG_RETURN(-1);
+ goto err;
}
#endif
if (!procedure && result->prepare(fields_list, unit))
- { /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
- }
+ goto err; /* purecov: inspected */
+
+ if (select_lex->olap == ROLLUP_TYPE && rollup_init())
+ goto err;
+ if (alloc_func_list())
+ goto err;
+
DBUG_RETURN(0); // All OK
+
+err:
+ delete procedure; /* purecov: inspected */
+ procedure= 0;
+ DBUG_RETURN(-1); /* purecov: inspected */
}
/*
@@ -638,7 +649,9 @@ JOIN::optimize()
else if (thd->is_fatal_error) // End of memory
DBUG_RETURN(1);
}
- group_list= remove_const(this, group_list, conds, &simple_group);
+ simple_group= 0;
+ if (rollup.state == ROLLUP::STATE_NONE)
+ group_list= remove_const(this, group_list, conds, &simple_group);
if (!group_list && group)
{
order=0; // The output has only one row
@@ -788,14 +801,14 @@ JOIN::optimize()
thd->proc_info="Sorting for group";
if (create_sort_index(thd, &join_tab[const_tables], group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
- make_sum_func_list(this, all_fields) ||
- alloc_group_fields(this, group_list))
+ alloc_group_fields(this, group_list) ||
+ make_sum_func_list(all_fields, fields_list, 1))
DBUG_RETURN(1);
group_list=0;
}
else
{
- if (make_sum_func_list(this, all_fields))
+ if (make_sum_func_list(all_fields, fields_list, 0))
DBUG_RETURN(1);
if (!group_list && ! exec_tmp_table1->distinct && order && simple_order)
{
@@ -862,7 +875,7 @@ int
JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
- //TODO move to unit reinit
+ /* TODO move to unit reinit */
unit->offset_limit_cnt =select_lex->offset_limit;
unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
if (unit->select_limit_cnt < select_lex->select_limit)
@@ -873,7 +886,7 @@ JOIN::reinit()
if (setup_tables(tables_list))
DBUG_RETURN(1);
- // Reset of sum functions
+ /* Reset of sum functions */
first_record= 0;
if (sum_funcs)
{
@@ -897,7 +910,7 @@ JOIN::reinit()
filesort_free_buffers(exec_tmp_table2);
}
if (items0)
- memcpy(ref_pointer_array, items0, ref_pointer_array_size);
+ set_items_ref_array(items0);
if (tmp_join)
restore_tmp();
@@ -977,9 +990,6 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
- /* Perform FULLTEXT search before all regular searches */
- //init_ftfuncs(thd, select_lex, test(order));
-
JOIN *curr_join= this;
List<Item> *curr_all_fields= &all_fields;
List<Item> *curr_fields_list= &fields_list;
@@ -1030,7 +1040,7 @@ JOIN::exec()
}
curr_all_fields= &tmp_all_fields1;
curr_fields_list= &tmp_fields_list1;
- memcpy(ref_pointer_array, items1, ref_pointer_array_size);
+ set_items_ref_array(items1);
if (sort_and_group || curr_tmp_table->group)
{
@@ -1079,7 +1089,8 @@ JOIN::exec()
if (make_simple_join(curr_join, curr_tmp_table))
DBUG_VOID_RETURN;
calc_group_buffer(curr_join, group_list);
- count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1,
+ count_field_types(&curr_join->tmp_table_param,
+ curr_join->tmp_all_fields1,
curr_join->select_distinct && !curr_join->group_list);
curr_join->tmp_table_param.hidden_field_count=
(curr_join->tmp_all_fields1.elements-
@@ -1117,7 +1128,8 @@ JOIN::exec()
thd->proc_info="Copying to group table";
tmp_error= -1;
- if (make_sum_func_list(curr_join, *curr_all_fields) ||
+ if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
+ 1) ||
(tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
0)))
{
@@ -1141,7 +1153,7 @@ JOIN::exec()
}
curr_fields_list= &curr_join->tmp_fields_list2;
curr_all_fields= &curr_join->tmp_all_fields2;
- memcpy(ref_pointer_array, items2, ref_pointer_array_size);
+ set_items_ref_array(items2);
curr_join->tmp_table_param.field_count+=
curr_join->tmp_table_param.sum_func_count;
curr_join->tmp_table_param.sum_func_count= 0;
@@ -1169,9 +1181,7 @@ JOIN::exec()
}
if (procedure)
- {
count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0);
- }
if (curr_join->group || curr_join->tmp_table_param.sum_func_count ||
(procedure && (procedure->flags & PROC_GROUP)))
@@ -1201,10 +1211,10 @@ JOIN::exec()
}
curr_fields_list= &tmp_fields_list3;
curr_all_fields= &tmp_all_fields3;
- memcpy(ref_pointer_array, items3, ref_pointer_array_size);
+ set_items_ref_array(items3);
- if (make_sum_func_list(curr_join, *curr_all_fields) ||
- thd->is_fatal_error)
+ if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
+ 1) || thd->is_fatal_error)
DBUG_VOID_RETURN;
}
if (curr_join->group_list || curr_join->order)
@@ -1291,7 +1301,7 @@ JOIN::exec()
*/
int
-JOIN::cleanup(THD *thd)
+JOIN::cleanup()
{
DBUG_ENTER("JOIN::cleanup");
select_lex->join= 0;
@@ -1312,7 +1322,7 @@ JOIN::cleanup(THD *thd)
}
}
tmp_join->tmp_join= 0;
- DBUG_RETURN(tmp_join->cleanup(thd));
+ DBUG_RETURN(tmp_join->cleanup());
}
lock=0; // It's faster to unlock later
@@ -1396,7 +1406,7 @@ err:
thd->limit_found_rows= curr_join->send_records;
thd->examined_row_count= curr_join->examined_rows;
thd->proc_info="end";
- err= join->cleanup(thd);
+ err= join->cleanup();
if (thd->net.report_error)
err= -1;
delete join;
@@ -2916,7 +2926,6 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->tmp_table_param.func_count=0;
join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0;
join->first_record=join->sort_and_group=0;
- join->sum_funcs=0;
join->send_records=(ha_rows) 0;
join->group=0;
join->row_limit=join->unit->select_limit_cnt;
@@ -5715,8 +5724,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
- else if (join->do_send_rows)
- error=join->procedure->send_row(*join->fields) ? 1 : 0;
+ else
+ {
+ if (join->do_send_rows)
+ error=join->procedure->send_row(*join->fields) ? 1 : 0;
+ join->send_records++;
+ }
if (end_of_records && join->procedure->end_of_records())
error= 1; // Fatal error
}
@@ -5730,17 +5743,23 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
- else if (join->do_send_rows)
- error=join->result->send_data(*join->fields) ? 1 : 0;
+ else
+ {
+ if (join->do_send_rows)
+ error=join->result->send_data(*join->fields) ? 1 : 0;
+ join->send_records++;
+ }
+ if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0)
+ {
+ if (join->rollup_send_data((uint) (idx+1)))
+ error= 1;
+ }
}
if (error > 0)
DBUG_RETURN(-1); /* purecov: inspected */
if (end_of_records)
- {
- join->send_records++;
DBUG_RETURN(0);
- }
- if (!error && ++join->send_records >= join->unit->select_limit_cnt &&
+ if (join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
@@ -5760,7 +5779,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (idx < (int) join->send_group_parts)
{
copy_fields(&join->tmp_table_param);
- init_sum_functions(join->sum_funcs);
+ if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
+ DBUG_RETURN(-1);
if (join->procedure)
join->procedure->add();
DBUG_RETURN(0);
@@ -6016,7 +6036,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.items_to_copy);
- init_sum_functions(join->sum_funcs);
+ if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
+ DBUG_RETURN(-1);
if (join->procedure)
join->procedure->add();
DBUG_RETURN(0);
@@ -7674,7 +7695,10 @@ err2:
/*
- Copy fields and null values between two tables
+ Make a copy of all simple SELECT'ed items
+
+ This is done at the start of a new group so that we can retrieve
+ these later when the group changes.
*/
void
@@ -7694,33 +7718,76 @@ copy_fields(TMP_TABLE_PARAM *param)
}
-/*****************************************************************************
- Make an array of pointer to sum_functions to speed up sum_func calculation
-*****************************************************************************/
+/*
+ Make an array of pointers to sum_functions to speed up sum_func calculation
-static bool
-make_sum_func_list(JOIN *join,List<Item> &fields)
+ SYNOPSIS
+ alloc_func_list()
+
+ RETURN
+ 0 ok
+ 1 Error
+*/
+
+bool JOIN::alloc_func_list()
{
+ uint func_count, group_parts;
+ DBUG_ENTER("alloc_func_list");
+
+ func_count= tmp_table_param.sum_func_count;
+ /*
+ If we are using rollup, we need a copy of the summary functions for
+ each level
+ */
+ if (rollup.state != ROLLUP::STATE_NONE)
+ func_count*= (send_group_parts+1);
+
+ group_parts= send_group_parts;
+ /*
+ If distinct, reserve memory for possible
+ disctinct->group_by optimization
+ */
+ if (select_distinct)
+ group_parts+= fields_list.elements;
+
+ /* This must use calloc() as rollup_make_fields depends on this */
+ sum_funcs= (Item_sum**) thd->calloc(sizeof(Item_sum**) * (func_count+1) +
+ sizeof(Item_sum***) * (group_parts+1));
+ sum_funcs_end= (Item_sum***) (sum_funcs+func_count+1);
+ DBUG_RETURN(sum_funcs == 0);
+}
+
+
+bool JOIN::make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
+ bool before_group_by)
+{
+ List_iterator_fast<Item> it(all_fields);
+ Item_sum **func;
+ Item *item;
DBUG_ENTER("make_sum_func_list");
- Item_sum **func =
- (Item_sum**) sql_alloc(sizeof(Item_sum*)*
- (join->tmp_table_param.sum_func_count+1));
- if (!func)
- DBUG_RETURN(TRUE);
- List_iterator<Item> it(fields);
- join->sum_funcs=func;
- Item *field;
- while ((field=it++))
+ func= sum_funcs;
+ while ((item=it++))
{
- if (field->type() == Item::SUM_FUNC_ITEM && !field->const_item())
+ if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
{
- *func++=(Item_sum*) field;
+ *func++= (Item_sum*) item;
/* let COUNT(DISTINCT) create the temporary table */
- if (((Item_sum*) field)->setup(join->thd))
+ if (((Item_sum*) item)->setup(thd))
DBUG_RETURN(TRUE);
}
}
+ if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
+ {
+ rollup.state= ROLLUP::STATE_READY;
+ if (rollup_make_fields(all_fields, send_fields, &func))
+ DBUG_RETURN(TRUE); // Should never happen
+ }
+ else if (rollup.state == ROLLUP::STATE_NONE)
+ {
+ for (uint i=0 ; i <= send_group_parts ;i++)
+ sum_funcs_end[i]= func;
+ }
*func=0; // End marker
DBUG_RETURN(FALSE);
}
@@ -7816,8 +7883,8 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
all_fields - all fields list
RETURN
- 0 - ok
- !=0 - error
+ 0 ok
+ 1 error
*/
static bool
@@ -7886,12 +7953,21 @@ copy_sum_funcs(Item_sum **func_ptr)
}
-static void
-init_sum_functions(Item_sum **func_ptr)
+static bool
+init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
{
- Item_sum *func;
- for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
- func->reset();
+ for (; func_ptr != end_ptr ;func_ptr++)
+ {
+ if ((*func_ptr)->reset())
+ return 1;
+ }
+ /* If rollup, calculate the upper sum levels */
+ for ( ; *func_ptr ; func_ptr++)
+ {
+ if ((*func_ptr)->add())
+ return 1;
+ }
+ return 0;
}
@@ -7916,10 +7992,10 @@ copy_funcs(Item **func_ptr)
}
-/*****************************************************************************
+/*
Create a condition for a const reference and add this to the
currenct select for the table
-*****************************************************************************/
+*/
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
{
@@ -7935,7 +8011,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
for (uint i=0 ; i < join_tab->ref.key_parts ; i++)
{
- Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].fieldnr-1];
+ Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].
+ fieldnr-1];
Item *value=join_tab->ref.items[i];
cond->add(new Item_func_equal(new Item_field(field),value));
}
@@ -7958,7 +8035,241 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
DBUG_RETURN(error ? TRUE : FALSE);
}
+
+/*
+ Free joins of subselect of this select.
+
+ free_underlaid_joins()
+ thd - THD pointer
+ select - pointer to st_select_lex which subselects joins we will free
+*/
+
+void free_underlaid_joins(THD *thd, SELECT_LEX *select)
+{
+ for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ unit->cleanup();
+}
+
+/****************************************************************************
+ ROLLUP handling
+****************************************************************************/
+
+/* Allocate memory needed for other rollup functions */
+
+bool JOIN::rollup_init()
+{
+ uint i,j;
+ ORDER *group;
+ Item **ref_array;
+
+ tmp_table_param.quick_group= 0; // Can't create groups in tmp table
+ rollup.state= ROLLUP::STATE_INITED;
+
+ /*
+ Create pointers to the different sum function groups
+ These are updated by rollup_make_fields()
+ */
+ tmp_table_param.group_parts= send_group_parts;
+
+ if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) +
+ sizeof(List<Item>) +
+ ref_pointer_array_size)
+ * send_group_parts)))
+ return 1;
+ rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts);
+ ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);
+ rollup.item_null= new (&thd->mem_root) Item_null();
+
+ /*
+ Prepare space for field list for the different levels
+ These will be filled up in rollup_make_fields()
+ */
+ for (i= 0 ; i < send_group_parts ; i++)
+ {
+ List<Item> *fields= &rollup.fields[i];
+ fields->empty();
+ rollup.ref_pointer_arrays[i]= ref_array;
+ ref_array+= all_fields.elements;
+ for (j=0 ; j < fields_list.elements ; j++)
+ fields->push_back(rollup.item_null);
+ }
+ return 0;
+}
+
+
+/*
+ Fill up rollup structures with pointers to fields to use
+
+ SYNOPSIS
+ rollup_make_fields()
+ all_fields List of all fields (hidden and real ones)
+ fields Pointer to selected fields
+ func Store here a pointer to all fields
+
+ IMPLEMENTATION:
+ Creates copies of item_sum items for each sum level
+
+ RETURN
+ 0 if ok
+ In this case func is pointing to next not used element.
+ 1 on error
+*/
+
+bool JOIN::rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
+ Item_sum ***func)
+{
+ List_iterator_fast<Item> it(all_fields);
+ Item *first_field= fields.head();
+ uint level;
+
+ /*
+ Create field lists for the different levels
+
+ The idea here is to have a separate field list for each rollup level to
+ avoid all runtime checks of which columns should be NULL.
+
+ The list is stored in reverse order to get sum function in such an order
+ in func that it makes it easy to reset them with init_sum_functions()
+
+ Assuming: SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP
+
+ rollup.fields[0] will contain list where a,b,c is NULL
+ rollup.fields[1] will contain list where b,c is NULL
+ ...
+ rollup.ref_pointer_array[#] points to fields for rollup.fields[#]
+ ...
+ sum_funcs_end[0] points to all sum functions
+ sum_funcs_end[1] points to all sum functions, except grand totals
+ ...
+ */
+
+ for (level=0 ; level < send_group_parts > 0 ; level++)
+ {
+ uint i;
+ uint pos= send_group_parts - level -1;
+ bool real_fields= 0;
+ Item *item;
+ List_iterator<Item> new_it(rollup.fields[pos]);
+ Item **ref_array_start= rollup.ref_pointer_arrays[pos];
+ ORDER *start_group;
+
+ /* Point to first hidden field */
+ Item **ref_array= ref_array_start + all_fields.elements-1;
+
+ /* Remember where the sum functions ends for the previous level */
+ sum_funcs_end[pos+1]= *func;
+
+ /* Find the start of the group for this level */
+ for (i= 0, start_group= group_list ;
+ i++ < pos ;
+ start_group= start_group->next)
+ ;
+
+ it.rewind();
+ while ((item= it++))
+ {
+ if (item == first_field)
+ {
+ real_fields= 1; // End of hidden fields
+ ref_array= ref_array_start;
+ }
+
+ if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
+ {
+ /*
+ This is a top level summary function that must be replaced with
+ a sum function that is reset for this level.
+
+ NOTE: This code creates an object which is not that nice in a
+ sub select. Fortunately it's not common to have rollup in
+ sub selects.
+ */
+ item= item->copy_or_same(thd);
+ ((Item_sum*) item)->make_unique();
+ if (((Item_sum*) item)->setup(thd))
+ return 1;
+ *(*func)= (Item_sum*) item;
+ (*func)++;
+ }
+ else if (real_fields)
+ {
+ /* Check if this is something that is part of this group by */
+ ORDER *group;
+ for (group= start_group ; group ; group= group->next)
+ {
+ if (*group->item == item)
+ {
+ /*
+ This is an element that is used by the GROUP BY and should be
+ set to NULL in this level
+ */
+ item->maybe_null= 1; // Value will be null sometimes
+ item= rollup.item_null;
+ break;
+ }
+ }
+ }
+ *ref_array= item;
+ if (real_fields)
+ {
+ (void) new_it++; // Point to next item
+ new_it.replace(item); // Replace previous
+ ref_array++;
+ }
+ else
+ ref_array--;
+ }
+ }
+ sum_funcs_end[0]= *func; // Point to last function
+ return 0;
+}
+
+/*
+ Send all rollup levels higher than the current one to the client
+
+ SYNOPSIS:
+ rollup_send_data()
+ idx Level we are on:
+ 0 = Total sum level
+ 1 = First group changed (a)
+ 2 = Second group changed (a,b)
+
+ SAMPLE
+ SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP
+
+ RETURN
+ 0 ok
+ 1 If send_data_failed()
+*/
+
+int JOIN::rollup_send_data(uint idx)
+{
+ uint i;
+ for (i= send_group_parts ; i-- > idx ; )
+ {
+ /* Get reference pointers to sum functions in place */
+ memcpy((char*) ref_pointer_array,
+ (char*) rollup.ref_pointer_arrays[i],
+ ref_pointer_array_size);
+ if ((!having || having->val_int()))
+ {
+ if (send_records < unit->select_limit_cnt &&
+ result->send_data(rollup.fields[i]))
+ return 1;
+ send_records++;
+ }
+ }
+ /* Restore ref_pointer_array */
+ set_items_ref_array(current_ref_pointer_array);
+ return 0;
+}
+
+
/****************************************************************************
+ EXPLAIN handling
+
Send a description about what how the select will be done to stdout
****************************************************************************/
@@ -8198,19 +8509,3 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
result, unit, select_lex, 0);
DBUG_RETURN(res);
}
-
-/*
- Free joins of subselect of this select.
-
- free_underlaid_joins()
- thd - THD pointer
- select - pointer to st_select_lex which subselects joins we will free
-*/
-
-void free_underlaid_joins(THD *thd, SELECT_LEX *select)
-{
- for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
- unit;
- unit= unit->next_unit())
- unit->cleanup();
-}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 7f3669f7478..df21d337b54 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -106,12 +106,22 @@ typedef struct st_join_table {
} JOIN_TAB;
-typedef struct st_position { /* Used in find_best */
+typedef struct st_position /* Used in find_best */
+{
double records_read;
JOIN_TAB *table;
KEYUSE *key;
} POSITION;
+typedef struct st_rollup
+{
+ enum State { STATE_NONE, STATE_INITED, STATE_READY };
+ State state;
+ Item *item_null;
+ Item ***ref_pointer_arrays;
+ List<Item> *fields;
+} ROLLUP;
+
class JOIN :public Sql_alloc
{
@@ -132,7 +142,7 @@ class JOIN :public Sql_alloc
// used to store 2 possible tmp table of SELECT
TABLE *exec_tmp_table1, *exec_tmp_table2;
THD *thd;
- Item_sum **sum_funcs;
+ Item_sum **sum_funcs, ***sum_funcs_end;
Procedure *procedure;
Item *having;
Item *tmp_having; // To store Having when processed temporary table
@@ -146,6 +156,7 @@ class JOIN :public Sql_alloc
SELECT_LEX *select_lex;
JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
+ ROLLUP rollup; // Used with rollup
bool select_distinct, //Is select distinct?
no_order, simple_order, simple_group,
@@ -159,7 +170,7 @@ class JOIN :public Sql_alloc
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
//Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
- List<Item> & fields_list; // hold field list passed to mysql_select
+ List<Item> &fields_list; // hold field list passed to mysql_select
int error;
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
@@ -168,15 +179,15 @@ class JOIN :public Sql_alloc
SQL_SELECT *select; //created in optimisation phase
Item **ref_pointer_array; //used pointer reference for this select
// Copy of above to be used with different lists
- Item **items0, **items1, **items2, **items3;
+ Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
uint ref_pointer_array_size; // size of above in bytes
const char *zero_result_cause; // not 0 if exec must return zero result
bool union_part; // this subselect is part of union
bool optimized; // flag to avoid double optimization in EXPLAIN
- JOIN(THD *thd, List<Item> &fields,
- ulong select_options, select_result *result):
+ JOIN(THD *thd_arg, List<Item> &fields, ulong select_options_arg,
+ select_result *result_arg):
join_tab(0),
table(0),
tables(0), const_tables(0),
@@ -184,13 +195,13 @@ class JOIN :public Sql_alloc
do_send_rows(1),
send_records(0), found_records(0), examined_rows(0),
exec_tmp_table1(0), exec_tmp_table2(0),
- thd(thd),
+ thd(thd_arg),
sum_funcs(0),
procedure(0),
having(0), tmp_having(0),
- select_options(select_options),
- result(result),
- lock(thd->lock),
+ select_options(select_options_arg),
+ result(result_arg),
+ lock(thd_arg->lock),
select_lex(0), //for safety
tmp_join(0),
select_distinct(test(select_options & SELECT_DISTINCT)),
@@ -212,6 +223,7 @@ class JOIN :public Sql_alloc
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.copy_field=0;
tmp_table_param.end_write_records= HA_POS_ERROR;
+ rollup.state= ROLLUP::STATE_NONE;
}
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
@@ -221,15 +233,28 @@ class JOIN :public Sql_alloc
int optimize();
int reinit();
void exec();
- int cleanup(THD *thd);
+ int cleanup();
void restore_tmp();
+ bool alloc_func_list();
+ bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
+ bool before_group_by);
+ inline void set_items_ref_array(Item **ptr)
+ {
+ memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size);
+ current_ref_pointer_array= ptr;
+ }
inline void init_items_ref_array()
{
items0= ref_pointer_array + all_fields.elements;
- ref_pointer_array_size= all_fields.elements*sizeof(Item*);
memcpy(items0, ref_pointer_array, ref_pointer_array_size);
+ current_ref_pointer_array= items0;
}
+
+ bool rollup_init();
+ bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
+ Item_sum ***func);
+ int JOIN::rollup_send_data(uint idx);
};
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 277bc5d8337..1c4954e0276 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1006,12 +1006,7 @@ static void
append_identifier(THD *thd, String *packet, const char *name)
{
char qtype;
- if ((thd->variables.sql_mode & MODE_ANSI_QUOTES) ||
- (thd->variables.sql_mode & MODE_POSTGRESQL) ||
- (thd->variables.sql_mode & MODE_ORACLE) ||
- (thd->variables.sql_mode & MODE_MSSQL) ||
- (thd->variables.sql_mode & MODE_DB2) ||
- (thd->variables.sql_mode & MODE_SAPDB))
+ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
qtype= '\"';
else
qtype= '`';
@@ -1033,16 +1028,16 @@ append_identifier(THD *thd, String *packet, const char *name)
static int
store_create_info(THD *thd, TABLE *table, String *packet)
{
- my_bool foreign_db_mode= ((thd->variables.sql_mode & MODE_POSTGRESQL) ||
- (thd->variables.sql_mode & MODE_ORACLE) ||
- (thd->variables.sql_mode & MODE_MSSQL) ||
- (thd->variables.sql_mode & MODE_DB2) ||
- (thd->variables.sql_mode & MODE_SAPDB));
- my_bool limited_mysql_mode= ((thd->variables.sql_mode &
- MODE_NO_FIELD_OPTIONS) ||
- (thd->variables.sql_mode & MODE_MYSQL323) ||
- (thd->variables.sql_mode & MODE_MYSQL40));
-
+ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
+ MODE_ORACLE |
+ MODE_MSSQL |
+ MODE_DB2 |
+ MODE_SAPDB |
+ MODE_ANSI)) != 0;
+ my_bool limited_mysql_mode= (thd->variables.sql_mode &
+ (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
+ MODE_MYSQL40)) != 0;
+
DBUG_ENTER("store_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
diff --git a/sql/sql_state.c b/sql/sql_state.c
new file mode 100644
index 00000000000..355b847f239
--- /dev/null
+++ b/sql/sql_state.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions to map mysqld errno to sql_state */
+
+#include <my_global.h>
+#include <mysqld_error.h>
+
+struct st_map_errno_to_sqlstate
+{
+ uint mysql_errno;
+ const char *odbc_state;
+ const char *jdbc_state;
+};
+
+struct st_map_errno_to_sqlstate sqlstate_map[]=
+{
+#include <sql_state.h>
+};
+
+const char *mysql_errno_to_sqlstate(uint mysql_errno)
+{
+ uint first=0, end= array_elements(sqlstate_map)-1;
+ struct st_map_errno_to_sqlstate *map;
+
+ /* Do binary search in the sorted array */
+ while (first != end)
+ {
+ uint mid= (first+end)/2;
+ map= sqlstate_map+mid;
+ if (map->mysql_errno < mysql_errno)
+ first= mid+1;
+ else
+ end= mid;
+ }
+ map= sqlstate_map+first;
+ if (map->mysql_errno == mysql_errno)
+ return map->odbc_state;
+ return "HY000"; /* General error */
+}
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index cf6645fa23e..0a3e8d0db9f 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -28,10 +28,6 @@
#include <floatingpoint.h>
#endif
-CHARSET_INFO *system_charset_info= &my_charset_utf8_general_ci;
-CHARSET_INFO *files_charset_info= &my_charset_utf8_general_ci;
-CHARSET_INFO *national_charset_info= &my_charset_utf8_general_ci;
-
extern gptr sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
diff --git a/sql/sql_string.h b/sql/sql_string.h
index ee38853a2d3..e88c9389589 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -69,7 +69,10 @@ public:
Alloced_length=str.Alloced_length; alloced=0;
str_charset=str.str_charset;
}
- static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size)
+ { return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
{ sql_element_free(ptr_arg); }
~String() { free(); }
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c53ca0b68a8..2b329aac305 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1082,58 +1082,76 @@ mysql_rename_table(enum db_type base,
}
/*
- close table in this thread and force close + reopen in other threads
- This assumes that the calling thread has lock on LOCK_open
- Win32 clients must also have a WRITE LOCK on the table !
+ Force all other threads to stop using the table
+
+ SYNOPSIS
+ wait_while_table_is_used()
+ thd Thread handler
+ table Table to remove from cache
+
+ NOTES
+ When returning, the table will be unusable for other threads until
+ the table is closed.
+
+ PREREQUISITES
+ Lock on LOCK_open
+ Win32 clients must also have a WRITE LOCK on the table !
*/
-static void safe_remove_from_cache(THD *thd,TABLE *table)
+static void wait_while_table_is_used(THD *thd,TABLE *table)
{
- DBUG_ENTER("safe_remove_from_cache");
- if (table)
- {
- DBUG_PRINT("enter",("table: %s", table->real_name));
- VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
- /* Mark all tables that are in use as 'old' */
- mysql_lock_abort(thd,table); // end threads waiting on lock
+ DBUG_PRINT("enter",("table: %s", table->real_name));
+ DBUG_ENTER("wait_while_table_is_used");
+ safe_mutex_assert_owner(&LOCK_open);
-#if defined(USING_TRANSACTIONS) || defined( __WIN__) || defined( __EMX__) || !defined(OS2)
- /* Wait until all there are no other threads that has this table open */
- while (remove_table_from_cache(thd,table->table_cache_key,
- table->real_name))
- {
- dropping_tables++;
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- dropping_tables--;
- }
-#else
- (void) remove_table_from_cache(thd,table->table_cache_key,
- table->real_name);
-#endif
- /* When lock on LOCK_open is freed other threads can continue */
- pthread_cond_broadcast(&COND_refresh);
+ VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
+ /* Mark all tables that are in use as 'old' */
+ mysql_lock_abort(thd, table); // end threads waiting on lock
+
+ /* Wait until all there are no other threads that has this table open */
+ while (remove_table_from_cache(thd,table->table_cache_key,
+ table->real_name))
+ {
+ dropping_tables++;
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ dropping_tables--;
}
DBUG_VOID_RETURN;
}
+/*
+ Close a cached table
-bool close_cached_table(THD *thd,TABLE *table)
+ SYNOPSIS
+ clsoe_cached_table()
+ thd Thread handler
+ table Table to remove from cache
+
+ NOTES
+ Function ends by signaling threads waiting for the table to try to
+ reopen the table.
+
+ PREREQUISITES
+ Lock on LOCK_open
+ Win32 clients must also have a WRITE LOCK on the table !
+*/
+
+static bool close_cached_table(THD *thd, TABLE *table)
{
DBUG_ENTER("close_cached_table");
- safe_mutex_assert_owner(&LOCK_open);
-
- if (table)
+
+ wait_while_table_is_used(thd,table);
+ /* Close lock if this is not got with LOCK TABLES */
+ if (thd->lock)
{
- safe_remove_from_cache(thd,table);
- /* Close lock if this is not got with LOCK TABLES */
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0; // Start locked threads
- }
- /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
- thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0; // Start locked threads
}
+ /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
+ thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
+
+ /* When lock on LOCK_open is freed other threads can continue */
+ pthread_cond_broadcast(&COND_refresh);
DBUG_RETURN(0);
}
@@ -1262,10 +1280,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id);
- pthread_mutex_lock(&LOCK_open);
- close_cached_table(thd,table_list->table);
- pthread_mutex_unlock(&LOCK_open);
-
+ /* If we could open the table, close it */
+ if (table_list->table)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ close_cached_table(thd, table);
+ pthread_mutex_unlock(&LOCK_open);
+ }
if (lock_and_wait_for_table_name(thd,table_list))
{
error= -1;
@@ -1732,10 +1753,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
fn_same(new_name_buff,table_name,3);
if (lower_case_table_names)
my_casedn_str(system_charset_info,new_name);
- if ((lower_case_table_names &&
- !my_strcasecmp(system_charset_info, new_name_buff,table_name)) ||
- (!lower_case_table_names &&
- !strcmp(new_name_buff,table_name)))
+ if (!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
new_name=table_name; // No. Make later check easier
else
{
@@ -1798,11 +1816,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
else
{
*fn_ext(new_name)=0;
- close_cached_table(thd,table);
+ close_cached_table(thd, table);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name))
error= -1;
}
- VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
}
if (!error)
@@ -1811,12 +1828,18 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
case LEAVE_AS_IS:
break;
case ENABLE:
- safe_remove_from_cache(thd,table);
- error= table->file->activate_all_index(thd);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ error= table->file->activate_all_index(thd);
+ /* COND_refresh will be signaled in close_thread_tables() */
break;
case DISABLE:
- safe_remove_from_cache(thd,table);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table);
+ VOID(pthread_mutex_unlock(&LOCK_open));
table->file->deactivate_non_unique_index(HA_POS_ERROR);
+ /* COND_refresh will be signaled in close_thread_tables() */
break;
}
}
@@ -2251,7 +2274,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
close the original table at before doing the rename
*/
table_name=thd->strdup(table_name); // must be saved
- if (close_cached_table(thd,table))
+ if (close_cached_table(thd, table))
{ // Aborted
VOID(quick_rm_table(new_db_type,new_db,tmp_name));
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -2285,7 +2308,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
This shouldn't happen. We solve this the safe way by
closing the locked table.
*/
- close_cached_table(thd,table);
+ if (table)
+ close_cached_table(thd,table);
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
@@ -2295,7 +2319,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Not table locking or alter table with rename
free locks and remove old table
*/
- close_cached_table(thd,table);
+ if (table)
+ close_cached_table(thd,table);
VOID(quick_rm_table(old_db_type,db,old_name));
}
else
@@ -2315,7 +2340,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (close_data_tables(thd,db,table_name) ||
reopen_tables(thd,1,0))
{ // This shouldn't happen
- close_cached_table(thd,table); // Remove lock for table
+ if (table)
+ close_cached_table(thd,table); // Remove lock for table
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 1d0f37f0042..f47900d8276 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -389,7 +389,7 @@ int st_select_lex_unit::cleanup()
JOIN *join;
if ((join= sl->join))
{
- error|= sl->join->cleanup(thd);
+ error|= sl->join->cleanup();
delete join;
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 1f6364ec427..989d17b006b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -200,7 +200,6 @@ int mysql_update(THD *thd,
*/
uint length;
SORT_FIELD *sortorder;
- List<Item> fields;
ha_rows examined_rows;
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9b2808f93a8..5219a8df04a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2975,7 +2975,7 @@ olap_opt:
}
lex->current_select->select_lex()->olap= CUBE_TYPE;
net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE");
- YYABORT; /* To be deleted in 4.1 */
+ YYABORT; /* To be deleted in 5.1 */
}
| WITH ROLLUP_SYM
{
@@ -2987,8 +2987,6 @@ olap_opt:
YYABORT;
}
lex->current_select->select_lex()->olap= ROLLUP_TYPE;
- net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "ROLLUP");
- YYABORT; /* To be deleted in 4.1 */
}
;
@@ -3043,20 +3041,7 @@ opt_limit_clause:
;
limit_clause:
- LIMIT
- {
- LEX *lex= Lex;
- if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- lex->current_select->select_lex()->olap !=
- UNSPECIFIED_OLAP_TYPE)
- {
- net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP",
- "LIMIT");
- YYABORT;
- }
- }
- limit_options
- {}
+ LIMIT limit_options {}
;
limit_options:
@@ -4343,6 +4328,7 @@ keyword:
| SHARE_SYM {}
| SHUTDOWN {}
| SLAVE {}
+ | SOUNDS_SYM {}
| SQL_CACHE_SYM {}
| SQL_BUFFER_RESULT {}
| SQL_NO_CACHE_SYM {}
@@ -4367,8 +4353,8 @@ keyword:
| VARIABLES {}
| VALUE_SYM {}
| WORK_SYM {}
+ | X509_SYM {}
| YEAR_SYM {}
- | SOUNDS_SYM {}
;
/* Option functions */
diff --git a/sql/time.cc b/sql/time.cc
index eba664a690d..b6ca306e523 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -28,7 +28,6 @@ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037
/* Currently only my_time_zone is inited */
static long my_time_zone=0;
-pthread_mutex_t LOCK_timezone;
void init_time(void)
{
@@ -39,14 +38,14 @@ void init_time(void)
seconds= (time_t) time((time_t*) 0);
localtime_r(&seconds,&tm_tmp);
l_time= &tm_tmp;
- my_time_zone=0;
+ my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */
my_time.year= (uint) l_time->tm_year+1900;
my_time.month= (uint) l_time->tm_mon+1;
my_time.day= (uint) l_time->tm_mday;
my_time.hour= (uint) l_time->tm_hour;
my_time.minute= (uint) l_time->tm_min;
- my_time.second= (uint) l_time->tm_sec;
- VOID(my_gmt_sec(&my_time)); /* Init my_time_zone */
+ my_time.second= (uint) l_time->tm_sec;
+ my_gmt_sec(&my_time, &my_time_zone); /* Init my_time_zone */
}
/*
@@ -57,26 +56,39 @@ void init_time(void)
*/
-long my_gmt_sec(TIME *t)
+long my_gmt_sec(TIME *t, long *my_timezone)
{
uint loop;
time_t tmp;
struct tm *l_time,tm_tmp;
- long diff;
+ long diff, current_timezone;
if (t->hour >= 24)
{ /* Fix for time-loop */
t->day+=t->hour/24;
t->hour%=24;
}
- pthread_mutex_lock(&LOCK_timezone);
- tmp=(time_t) ((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
- (long) days_at_timestart)*86400L + (long) t->hour*3600L +
- (long) (t->minute*60 + t->second)) + (time_t) my_time_zone;
+
+ /*
+ Calculate the gmt time based on current time and timezone
+ The -1 on the end is to ensure that if have a date that exists twice
+ (like 2002-10-27 02:00:0 MET), we will find the initial date.
+
+ By doing -3600 we will have to call localtime_r() several times, but
+ I couldn't come up with a better way to get a repeatable result :(
+
+ We can't use mktime() as it's buggy on many platforms and not thread safe.
+ */
+ tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
+ (long) days_at_timestart)*86400L + (long) t->hour*3600L +
+ (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
+ 3600);
+ current_timezone= my_time_zone;
+
localtime_r(&tmp,&tm_tmp);
l_time=&tm_tmp;
for (loop=0;
- loop < 3 &&
+ loop < 2 &&
(t->hour != (uint) l_time->tm_hour ||
t->minute != (uint) l_time->tm_min);
loop++)
@@ -89,14 +101,16 @@ long my_gmt_sec(TIME *t)
days= -1;
diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
(long) (60*((int) t->minute - (int) l_time->tm_min)));
- my_time_zone+=diff;
- tmp+=(time_t) diff;
+ current_timezone+= diff+3600; // Compensate for -3600 above
+ tmp+= (time_t) diff;
localtime_r(&tmp,&tm_tmp);
l_time=&tm_tmp;
}
- /* Fix that if we are in the not existing daylight saving time hour
- we move the start of the next real hour */
- if (loop == 3 && t->hour != (uint) l_time->tm_hour)
+ /*
+ Fix that if we are in the not existing daylight saving time hour
+ we move the start of the next real hour
+ */
+ if (loop == 2 && t->hour != (uint) l_time->tm_hour)
{
int days= t->day - l_time->tm_mday;
if (days < -1)
@@ -108,11 +122,9 @@ long my_gmt_sec(TIME *t)
if (diff == 3600)
tmp+=3600 - t->minute*60 - t->second; // Move to next hour
else if (diff == -3600)
- tmp-=t->minute*60 + t->second; // Move to next hour
+ tmp-=t->minute*60 + t->second; // Move to previous hour
}
- if ((my_time_zone >=0 ? my_time_zone: -my_time_zone) > 3600L*12)
- my_time_zone=0; /* Wrong date */
- pthread_mutex_unlock(&LOCK_timezone);
+ *my_timezone= current_timezone;
return (long) tmp;
} /* my_gmt_sec */
@@ -428,6 +440,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
time_t str_to_timestamp(const char *str,uint length)
{
TIME l_time;
+ long not_used;
+
if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE)
return(0);
if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR)
@@ -435,7 +449,7 @@ time_t str_to_timestamp(const char *str,uint length)
current_thd->cuted_fields++;
return(0);
}
- return(my_gmt_sec(&l_time));
+ return(my_gmt_sec(&l_time, &not_used));
}
diff --git a/sql/unireg.h b/sql/unireg.h
index 6ddd9856724..cd459dfc783 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -106,8 +106,8 @@
#define SPECIAL_SAFE_MODE 2048
/* Extern defines */
-#define store_record(A,B) bmove_allign((A)->B,(A)->record[0],(size_t) (A)->reclength)
-#define restore_record(A,B) bmove_allign((A)->record[0],(A)->B,(size_t) (A)->reclength)
+#define store_record(A,B) bmove_align((A)->B,(A)->record[0],(size_t) (A)->reclength)
+#define restore_record(A,B) bmove_align((A)->record[0],(A)->B,(size_t) (A)->reclength)
#define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->reclength)
#define empty_record(A) { \
restore_record((A),default_values); \