summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc12
-rw-r--r--sql/item.cc3
-rw-r--r--sql/item.h20
-rw-r--r--sql/item_func.cc9
-rw-r--r--sql/item_func.h8
-rw-r--r--sql/item_strfunc.cc12
-rw-r--r--sql/item_subselect.cc20
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_base.cc27
-rw-r--r--sql/sql_class.cc79
-rw-r--r--sql/sql_class.h13
-rw-r--r--sql/sql_db.cc12
-rw-r--r--sql/sql_derived.cc24
-rw-r--r--sql/sql_help.cc6
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_lex.cc5
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_olap.cc2
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc15
-rw-r--r--sql/sql_show.cc18
-rw-r--r--sql/sql_string.cc46
-rw-r--r--sql/sql_string.h1
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/sql_union.cc7
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_yacc.yy2
-rw-r--r--sql/table.cc4
30 files changed, 231 insertions, 143 deletions
diff --git a/sql/field.cc b/sql/field.cc
index a9029b893e3..1a0716326fe 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4567,17 +4567,19 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
}
else
{
+ bool was_conversion;
char buff[80];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
+
/* Convert character set if nesessary */
- if (use_conversion(cs, field_charset))
+ if ((was_conversion= use_conversion(cs, field_charset)))
{
tmpstr.copy(from, length, cs, field_charset);
from= tmpstr.ptr();
length= tmpstr.length();
}
Field_blob::store_length(length);
- if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
+ if (was_conversion || table->copy_blobs || length <= MAX_FIELD_WIDTH)
{ // Must make a copy
if (from != value.ptr()) // For valgrind
{
@@ -5609,16 +5611,16 @@ create_field::create_field(Field *old_field,Field *orig_field)
case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
default: sql_type= FIELD_TYPE_LONG_BLOB; break;
}
- length /= charset->mbmaxlen; // QQ: Probably not needed
+ length=(length+charset->mbmaxlen-1)/charset->mbmaxlen; // QQ: Probably not needed
break;
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
- length /= charset->mbmaxlen;
+ length=(length+charset->mbmaxlen-1)/charset->mbmaxlen;
break;
default:
break;
}
-
+
decimals= old_field->decimals();
if (sql_type == FIELD_TYPE_STRING)
{
diff --git a/sql/item.cc b/sql/item.cc
index 417f05680cf..37240700c68 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1867,7 +1867,6 @@ void Item_cache_int::store(Item *item)
{
value= item->val_int_result();
null_value= item->null_value;
- collation.set(item->collation);
}
@@ -1875,7 +1874,6 @@ void Item_cache_real::store(Item *item)
{
value= item->val_result();
null_value= item->null_value;
- collation.set(item->collation);
}
@@ -1898,7 +1896,6 @@ void Item_cache_str::store(Item *item)
value_buff.copy(*value);
value= &value_buff;
}
- collation.set(item->collation);
}
diff --git a/sql/item.h b/sql/item.h
index 5def1e2b710..e7ccdb7ea12 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -477,7 +477,7 @@ public:
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
{
collation.set(cs, dv);
- str_value.set(str,length,cs);
+ str_value.set_or_copy_aligned(str,length,cs);
/*
We have to have a different max_length than 'length' here to
ensure that we get the right length if we do use the item
@@ -493,7 +493,7 @@ public:
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
{
collation.set(cs, dv);
- str_value.set(str,length,cs);
+ str_value.set_or_copy_aligned(str,length,cs);
max_length= str_value.numchars()*cs->mbmaxlen;
set_name(name_par,0,cs);
decimals=NOT_FIXED_DEC;
@@ -878,13 +878,15 @@ public:
void set_used_tables(table_map map) { used_table_map= map; }
virtual bool allocate(uint i) { return 0; };
- virtual bool setup(Item *item) { example= item; return 0; };
- virtual void store(Item *)= 0;
- void set_len_n_dec(uint32 max_len, uint8 dec)
+ virtual bool setup(Item *item)
{
- max_length= max_len;
- decimals= dec;
- }
+ example= item;
+ max_length= item->max_length;
+ decimals= item->decimals;
+ collation.set(item->collation);
+ return 0;
+ };
+ virtual void store(Item *)= 0;
enum Type type() const { return CACHE_ITEM; }
static Item_cache* get_cache(Item_result type);
table_map used_tables() const { return used_table_map; }
@@ -909,7 +911,7 @@ class Item_cache_real: public Item_cache
double value;
public:
Item_cache_real(): Item_cache() {}
-
+
void store(Item *item);
double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 5af64ca0be4..802b6dbb8d6 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2618,6 +2618,7 @@ longlong Item_func_inet_aton::val_int()
const char *p,* end;
char c = '.'; // we mark c to indicate invalid IP in case length is 0
char buff[36];
+ int dot_count= 0;
String *s,tmp(buff,sizeof(buff),&my_charset_bin);
if (!(s = args[0]->val_str(&tmp))) // If null value
@@ -2636,6 +2637,7 @@ longlong Item_func_inet_aton::val_int()
}
else if (c == '.')
{
+ dot_count++;
result= (result << 8) + (ulonglong) byte_result;
byte_result = 0;
}
@@ -2643,7 +2645,14 @@ longlong Item_func_inet_aton::val_int()
goto err; // Invalid character
}
if (c != '.') // IP number can't end on '.'
+ {
+ switch (dot_count)
+ {
+ case 1: result<<= 8;
+ case 2: result<<= 8;
+ }
return (result << 8) + (ulonglong) byte_result;
+ }
err:
null_value=1;
diff --git a/sql/item_func.h b/sql/item_func.h
index ac67b5a4065..33a4357d26c 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -212,8 +212,8 @@ class Item_func_signed :public Item_int_func
{
public:
Item_func_signed(Item *a) :Item_int_func(a) {}
- double val() { return args[0]->val(); }
- longlong val_int() { return args[0]->val_int(); }
+ double val() { null_value=args[0]->null_value; return args[0]->val(); }
+ longlong val_int() { null_value=args[0]->null_value; return args[0]->val_int(); }
void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=0; }
void print(String *str);
@@ -224,8 +224,8 @@ class Item_func_unsigned :public Item_int_func
{
public:
Item_func_unsigned(Item *a) :Item_int_func(a) {}
- double val() { return args[0]->val(); }
- longlong val_int() { return args[0]->val_int(); }
+ double val() { null_value=args[0]->null_value; return args[0]->val(); }
+ longlong val_int() { null_value=args[0]->null_value; return args[0]->val_int(); }
void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=1; }
void print(String *str);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index fdacc4ec536..4507b2598a3 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -975,9 +975,10 @@ String *Item_func_right::val_str(String *str)
if (res->length() <= (uint) length)
return res; /* purecov: inspected */
- uint start=res->numchars()-(uint) length;
- if (start<=0) return res;
- start=res->charpos(start);
+ uint start=res->numchars();
+ if (start <= (uint) length)
+ return res;
+ start=res->charpos(start - (uint) length);
tmp_value.set(*res,start,res->length()-start);
return &tmp_value;
}
@@ -2022,9 +2023,8 @@ String *Item_func_lpad::val_str(String *str)
{
uint32 res_char_length,pad_char_length;
ulong count= (long) args[1]->val_int(), byte_count;
- String a1,a3;
- String *res= args[0]->val_str(&a1);
- String *pad= args[2]->val_str(&a3);
+ String *res= args[0]->val_str(&tmp_value);
+ String *pad= args[2]->val_str(&lpad_str);
if (!res || args[1]->null_value || !pad)
goto err;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 43775e1c96c..ee034e4c559 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -301,8 +301,6 @@ void Item_singlerow_subselect::fix_length_and_dec()
if ((max_columns= engine->cols()) == 1)
{
engine->fix_length_and_dec(row= &value);
- if (!(value= Item_cache::get_cache(engine->type())))
- return;
}
else
{
@@ -906,7 +904,8 @@ int subselect_single_select_engine::prepare()
{
if (prepared)
return 0;
- join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
+ join= new JOIN(thd, select_lex->item_list,
+ select_lex->options | SELECT_NO_UNLOCK, result);
if (!join || !result)
{
thd->fatal_error(); //out of memory
@@ -933,7 +932,7 @@ int subselect_single_select_engine::prepare()
int subselect_union_engine::prepare()
{
- return unit->prepare(thd, result);
+ return unit->prepare(thd, result, SELECT_NO_UNLOCK);
}
int subselect_uniquesubquery_engine::prepare()
@@ -955,13 +954,9 @@ static Item_result set_row(List<Item> &item_list, Item *item,
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
*maybe_null= sel_item->maybe_null;
- if (row)
- {
- if (!(row[i]= Item_cache::get_cache(res_type)))
- return STRING_RESULT; // we should return something
- row[i]->set_len_n_dec(sel_item->max_length, sel_item->decimals);
- row[i]->collation.set(sel_item->collation);
- }
+ if (!(row[i]= Item_cache::get_cache(res_type)))
+ return STRING_RESULT; // we should return something
+ row[i]->setup(sel_item);
}
if (item_list.elements > 1)
res_type= ROW_RESULT;
@@ -982,7 +977,10 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
DBUG_ASSERT(row || unit->first_select()->item_list.elements==1);
if (unit->first_select()->item_list.elements == 1)
+ {
res_type= set_row(unit->types, item, row, &maybe_null);
+ item->collation.set(row[0]->collation);
+ }
else
{
bool fake= 0;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 15a99385285..4da5381abf1 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -38,6 +38,7 @@ typedef ulong key_part_map; /* Used for finding key parts */
/* useful constants */
extern const key_map key_map_empty;
extern const key_map key_map_full;
+extern const char *primary_key_name;
#include "mysql_com.h"
#include <violite.h>
@@ -664,7 +665,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
List_iterator<Item> *it);
-bool setup_tables(TABLE_LIST *tables);
+bool setup_tables(TABLE_LIST *tables, my_bool reinit);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d7984213fd6..3125c392751 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2039,15 +2039,28 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
/*
- Remap table numbers if INSERT ... SELECT
- Check also that the 'used keys' and 'ignored keys' exists and set up the
- table structure accordingly
+ prepare tables
- This has to be called for all tables that are used by items, as otherwise
- table->map is not set and all Item_field will be regarded as const items.
+ SYNOPSIS
+ setup_tables()
+ tables - tables list
+ reinit - true if called for table reinitialization before
+ subquery reexecuting
+
+ RETURN
+ 0 ok; In this case *map will includes the choosed index
+ 1 error
+
+ NOTE
+ Remap table numbers if INSERT ... SELECT
+ Check also that the 'used keys' and 'ignored keys' exists and set up the
+ table structure accordingly
+
+ This has to be called for all tables that are used by items, as otherwise
+ table->map is not set and all Item_field will be regarded as const items.
*/
-bool setup_tables(TABLE_LIST *tables)
+bool setup_tables(TABLE_LIST *tables, my_bool reinit)
{
DBUG_ENTER("setup_tables");
uint tablenr=0;
@@ -2074,7 +2087,7 @@ bool setup_tables(TABLE_LIST *tables)
table->keys_in_use_for_query.subtract(map);
}
table->used_keys.intersect(table->keys_in_use_for_query);
- if (table_list->shared || table->clear_query_id)
+ if ((table_list->shared || table->clear_query_id) && !reinit)
{
table->clear_query_id= 0;
/* Clear query_id that may have been set by previous select */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 89b812eb205..ce30c6f3d09 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -695,39 +695,53 @@ select_export::~select_export()
thd->sent_row_count=row_count;
}
-int
-select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
+
+static int create_file(THD *thd, char *path, sql_exchange *exchange,
+ File *file, IO_CACHE *cache)
{
- char path[FN_REFLEN];
- uint option=4;
- bool blob_flag=0;
- unit= u;
+ uint option= 4;
+
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
- option|=1; // Force use of db directory
+ option|= 1; // Force use of db directory
#endif
- if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
- strmake(path,exchange->file_name,FN_REFLEN-1);
- (void) fn_format(path,exchange->file_name, thd->db ? thd->db : "", "",
+ (void) fn_format(path, exchange->file_name, thd->db ? thd->db : "", "",
option);
- if (!access(path,F_OK))
+ if (!access(path, F_OK))
{
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
return 1;
}
/* Create the file world readable */
- if ((file=my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
+ if ((*file= my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
return 1;
#ifdef HAVE_FCHMOD
- (void) fchmod(file,0666); // Because of umask()
+ (void) fchmod(*file, 0666); // Because of umask()
#else
- (void) chmod(path,0666);
+ (void) chmod(path, 0666);
#endif
- if (init_io_cache(&cache,file,0L,WRITE_CACHE,0L,1,MYF(MY_WME)))
+ if (init_io_cache(cache, *file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
{
- my_close(file,MYF(0));
- file= -1;
+ my_close(*file, MYF(0));
+ my_delete(path, MYF(0)); // Delete file on error, it was just created
+ *file= -1;
+ end_io_cache(cache);
return 1;
}
+ return 0;
+}
+
+
+int
+select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
+{
+ char path[FN_REFLEN];
+ bool blob_flag=0;
+ unit= u;
+ if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
+ strmake(path,exchange->file_name,FN_REFLEN-1);
+
+ if (create_file(thd, path, exchange, &file, &cache))
+ return 1;
/* Check if there is any blobs in data */
{
List_iterator_fast<Item> li(list);
@@ -901,7 +915,6 @@ err:
void select_export::send_error(uint errcode, const char *err)
{
::send_error(thd,errcode,err);
- (void) end_io_cache(&cache);
(void) my_close(file,MYF(0));
file= -1;
}
@@ -938,33 +951,9 @@ int
select_dump::prepare(List<Item> &list __attribute__((unused)),
SELECT_LEX_UNIT *u)
{
- uint option=4;
unit= u;
-#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
- option|=1; // Force use of db directory
-#endif
- (void) fn_format(path,exchange->file_name, thd->db ? thd->db : "", "",
- option);
- if (!access(path,F_OK))
- {
- my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
+ if (create_file(thd, path, exchange, &file, &cache))
return 1;
- }
- /* Create the file world readable */
- if ((file=my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
- return 1;
-#ifdef HAVE_FCHMOD
- (void) fchmod(file,0666); // Because of umask()
-#else
- (void) chmod(path,0666);
-#endif
- if (init_io_cache(&cache,file,0L,WRITE_CACHE,0L,1,MYF(MY_WME)))
- {
- my_close(file,MYF(0));
- my_delete(path,MYF(0));
- file= -1;
- return 1;
- }
return 0;
}
@@ -1011,9 +1000,7 @@ err:
void select_dump::send_error(uint errcode,const char *err)
{
::send_error(thd,errcode,err);
- (void) end_io_cache(&cache);
(void) my_close(file,MYF(0));
- (void) my_delete(path,MYF(0)); // Delete file on error
file= -1;
}
@@ -1039,7 +1026,7 @@ bool select_singlerow_subselect::send_data(List<Item> &items)
Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
if (it->assigned())
{
- my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
+ my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
DBUG_RETURN(1);
}
if (unit->offset_limit_cnt)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 5390e8a4ac4..7971137d848 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -624,6 +624,19 @@ public:
and are still in use by this thread
*/
TABLE *open_tables,*temporary_tables, *handler_tables, *derived_tables;
+ /*
+ During a MySQL session, one can lock tables in two modes: automatic
+ or manual. In automatic mode all necessary tables are locked just before
+ statement execution, and all acquired locks are stored in 'lock'
+ member. Unlocking takes place automatically as well, when the
+ statement ends.
+ Manual mode comes into play when a user issues a 'LOCK TABLES'
+ statement. In this mode the user can only use the locked tables.
+ Trying to use any other tables will give an error. The locked tables are
+ stored in 'locked_tables' member. Manual locking is described in
+ the 'LOCK_TABLES' chapter of the MySQL manual.
+ See also lock_tables() for details.
+ */
MYSQL_LOCK *lock; /* Current locks */
MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */
/*
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 70b1d1d0d3a..697859eb264 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -270,11 +270,8 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not alter database if another thread is holding read lock
- if (wait_if_global_read_lock(thd,0))
- {
- error= -1;
+ if ((error=wait_if_global_read_lock(thd,0)))
goto exit2;
- }
/* Check directory */
(void)sprintf(path,"%s/%s/%s", mysql_data_home, db, MY_DB_OPT_FILE);
@@ -307,7 +304,7 @@ exit:
start_waiting_global_read_lock(thd);
exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- DBUG_RETURN(error);
+ DBUG_RETURN(error ? -1 : 0); /* -1 to delegate send_error() */
}
@@ -411,7 +408,7 @@ exit:
when the slave is replicating a DROP DATABASE:
- garbage characters in the error message:
"Error 'Can't drop database 'test2'; database doesn't exist' on query
- 'h4zIż'"
+ 'h4zI©'"
- segfault
- hang in "free(vio)" (yes!) in the I/O or SQL slave threads (so slave
server hangs at shutdown etc).
@@ -420,7 +417,8 @@ exit:
{
if (!(thd->slave_thread)) /* a slave thread will free it itself */
x_free(thd->db);
- thd->db= 0;
+ thd->db= 0;
+ thd->db_length= 0;
}
exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index e8f1c5d87de..374e56ecdd4 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -114,7 +114,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
DBUG_RETURN(1); // out of memory
// st_select_lex_unit::prepare correctly work for single select
- if ((res= unit->prepare(thd, derived_result)))
+ if ((res= unit->prepare(thd, derived_result, 0)))
goto exit;
/*
@@ -146,17 +146,19 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
}
derived_result->set_table(table);
- unit->offset_limit_cnt= first_select->offset_limit;
- unit->select_limit_cnt= first_select->select_limit+
- first_select->offset_limit;
- if (unit->select_limit_cnt < first_select->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR;
- if (unit->select_limit_cnt == HA_POS_ERROR)
- first_select->options&= ~OPTION_FOUND_ROWS;
-
if (is_union)
res= mysql_union(thd, lex, derived_result, unit);
else
+ {
+ unit->offset_limit_cnt= first_select->offset_limit;
+ unit->select_limit_cnt= first_select->select_limit+
+ first_select->offset_limit;
+ if (unit->select_limit_cnt < first_select->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR;
+ if (unit->select_limit_cnt == HA_POS_ERROR)
+ first_select->options&= ~OPTION_FOUND_ROWS;
+
+ lex->current_select= first_select;
res= mysql_select(thd, &first_select->ref_pointer_array,
(TABLE_LIST*) first_select->table_list.first,
first_select->with_wild,
@@ -169,6 +171,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
(first_select->options | thd->options |
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
+ }
if (!res)
{
@@ -198,7 +201,10 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
}
}
else
+ {
unit->exclude_tree();
+ unit->cleanup();
+ }
org_table_list->db= (char *)"";
// Force read of table stats in the optimizer
table->file->info(HA_STATUS_VARIABLE);
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index c40133c04a8..3c98b7b0bb4 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -274,9 +274,9 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
DBUG_ENTER("get_topics_for_keyword");
- if ((iindex_topic= find_type((char*) "PRIMARY",
+ if ((iindex_topic= find_type((char*) primary_key_name,
&topics->keynames, 1+2)-1)<0 ||
- (iindex_relations= find_type((char*) "PRIMARY",
+ (iindex_relations= find_type((char*) primary_key_name,
&relations->keynames, 1+2)-1)<0)
{
send_error(thd,ER_CORRUPT_HELP_DB);
@@ -686,7 +686,7 @@ int mysqld_help(THD *thd, const char *mask)
goto end;
}
/* Init tables and fields to be usable from items */
- setup_tables(tables);
+ setup_tables(tables, 0);
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e23e62fb714..c2f3e737daf 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -84,7 +84,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
table_list.grant=table->grant;
thd->dupp_field=0;
- if (setup_tables(&table_list) ||
+ if (setup_tables(&table_list, 0) ||
setup_fields(thd, 0, &table_list,fields,1,0,0))
return -1;
if (thd->dupp_field)
@@ -204,7 +204,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
}
if (check_insert_fields(thd,table,fields,*values,1) ||
- setup_tables(insert_table_list) ||
+ setup_tables(insert_table_list, 0) ||
setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
(duplic == DUP_UPDATE &&
(setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) ||
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index de0d6ade618..efb0ce92ad0 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1222,11 +1222,6 @@ void st_select_lex::mark_as_dependent(SELECT_LEX *last)
s->uncacheable|= UNCACHEABLE_DEPENDENT;
SELECT_LEX_UNIT *munit= s->master_unit();
munit->uncacheable|= UNCACHEABLE_DEPENDENT;
- //Tables will be reopened many times
- for (TABLE_LIST *tbl= s->get_table_list();
- tbl;
- tbl= tbl->next)
- tbl->shared= 1;
}
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index c1f7809e0b5..bcbd60e9716 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -351,7 +351,7 @@ public:
void exclude_tree();
/* UNION methods */
- int prepare(THD *thd, select_result *result);
+ int prepare(THD *thd, select_result *result, ulong additional_options);
int exec();
int cleanup();
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 0c35e99ed08..175791ef31e 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -123,7 +123,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else
{ // Part field list
thd->dupp_field=0;
- if (setup_tables(table_list) ||
+ if (setup_tables(table_list, 0) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0))
DBUG_RETURN(-1);
if (thd->dupp_field)
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index ef7bf013be8..1d16771c1a4 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -164,7 +164,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
List<Item> all_fields(select_lex->item_list);
- if (setup_tables((TABLE_LIST *)select_lex->table_list.first) ||
+ if (setup_tables((TABLE_LIST *)select_lex->table_list.first, 0) ||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
select_lex->item_list, 1, &all_fields,1) ||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a6be104730e..de75ed301e5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1624,9 +1624,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
switch (command) {
case MYSQL_OPTION_MULTI_STATEMENTS_ON:
thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
+ send_eof(thd);
break;
case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
+ send_eof(thd);
break;
default:
send_error(thd, ER_UNKNOWN_COM_ERROR);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 5d6ab165641..0a565c00ba7 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -679,7 +679,7 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt,
#endif
if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(1);
- if (setup_tables(table_list) ||
+ if (setup_tables(table_list, 0) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
setup_conds(thd, table_list, &conds) || thd->net.report_error)
DBUG_RETURN(1);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 92cdd12ad37..75a94995830 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -301,7 +301,7 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */
- if (setup_tables(tables_list) ||
+ if (setup_tables(tables_list, 0) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
@@ -1015,7 +1015,7 @@ JOIN::reinit()
if (unit->select_limit_cnt == HA_POS_ERROR)
select_lex->options&= ~OPTION_FOUND_ROWS;
- if (setup_tables(tables_list))
+ if (setup_tables(tables_list, 1))
DBUG_RETURN(1);
/* Reset of sum functions */
@@ -1586,7 +1586,8 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
}
else
{
- join= new JOIN(thd, fields, select_options, result);
+ if (!(join= new JOIN(thd, fields, select_options, result)))
+ DBUG_RETURN(-1);
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
if (join->prepare(rref_pointer_array, tables, wild_num,
@@ -9143,16 +9144,16 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
{
res= mysql_explain_select(thd, sl,
(((&thd->lex->select_lex)==sl)?
- ((thd->lex->all_selects_list != sl)?"PRIMARY":
- "SIMPLE"):
+ ((thd->lex->all_selects_list != sl) ?
+ primary_key_name : "SIMPLE"):
((sl == first)?
((sl->linkage == DERIVED_TABLE_TYPE) ?
"DERIVED":
- ((sl->uncacheable & UNCACHEABLE_DEPENDENT)?
+ ((sl->uncacheable & UNCACHEABLE_DEPENDENT) ?
"DEPENDENT SUBQUERY":
(sl->uncacheable?"UNCACHEABLE SUBQUERY":
"SUBQUERY"))):
- ((sl->uncacheable & UNCACHEABLE_DEPENDENT)?
+ ((sl->uncacheable & UNCACHEABLE_DEPENDENT) ?
"DEPENDENT UNION":
sl->uncacheable?"UNCACHEABLE UNION":
"UNION"))),
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 52f7e6cb9ed..4ae59093a0e 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -997,6 +997,19 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
DBUG_RETURN(0);
}
+/* possible TODO: call find_keyword() from sql_lex.cc here */
+static bool require_quotes(const char *name, uint length)
+{
+ uint i, d, c;
+ for (i=0; i<length; i+=d)
+ {
+ c=((uchar *)name)[i];
+ d=my_mbcharlen(system_charset_info, c);
+ if (d==1 && !system_charset_info->ident_map[c])
+ return 1;
+ }
+ return 0;
+}
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
@@ -1007,7 +1020,8 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
else
qtype= '`';
- if (thd->options & OPTION_QUOTE_SHOW_CREATE)
+ if ((thd->options & OPTION_QUOTE_SHOW_CREATE) ||
+ require_quotes(name, length))
{
packet->append(&qtype, 1);
packet->append(name, length, system_charset_info);
@@ -1167,7 +1181,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
bool found_primary=0;
packet->append(",\n ", 4);
- if (i == primary_key && !strcmp(key_info->name,"PRIMARY"))
+ if (i == primary_key && !strcmp(key_info->name, primary_key_name))
{
found_primary=1;
packet->append("PRIMARY ", 8);
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 89f48607969..9534c5605fe 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -228,6 +228,52 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs)
return FALSE;
}
+/*
+** For real multi-byte, ascii incompatible charactser sets,
+** like UCS-2, add leading zeros if we have an incomplete character.
+** Thus,
+** SELECT _ucs2 0xAA
+** will automatically be converted into
+** SELECT _ucs2 0x00AA
+*/
+
+bool String::set_or_copy_aligned(const char *str,uint32 arg_length,
+ CHARSET_INFO *cs)
+{
+ /* How many bytes are in incomplete character */
+ uint32 offs= (arg_length % cs->mbminlen);
+
+ if (!offs) /* All characters are complete, just copy */
+ {
+ set(str, arg_length, cs);
+ return FALSE;
+ }
+
+ offs= cs->mbmaxlen - offs; /* How many zeros we should prepend */
+ uint32 aligned_length= arg_length + offs;
+ if (alloc(aligned_length))
+ return TRUE;
+
+ /*
+ Probably this condition is not really necessary
+ because if aligned_length is 0 then offs is 0 too
+ and we'll return after calling set().
+ */
+ if ((str_length= aligned_length))
+ {
+ /*
+ Note, this is only safe for little-endian UCS-2.
+ If we add big-endian UCS-2 sometimes, this code
+ will be more complicated. But it's OK for now.
+ */
+ bzero((char*)Ptr, offs);
+ memcpy(Ptr + offs, str, arg_length);
+ }
+ Ptr[aligned_length]=0;
+ str_charset=cs;
+ return FALSE;
+}
+
/* Copy with charset convertion */
bool String::copy(const char *str, uint32 arg_length,
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 325611737ca..8817aa8eab8 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -183,6 +183,7 @@ public:
bool copy(); // Alloc string if not alloced
bool copy(const String &s); // Allocate new string
bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string
+ bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
CHARSET_INFO *csto);
bool append(const String &s);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ecd5f9ccb66..413fb77d929 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -29,7 +29,7 @@
#include <io.h>
#endif
-static const char *primary_key_name="PRIMARY";
+const char *primary_key_name= "PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
@@ -2242,13 +2242,15 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
KEY *key_info=table->key_info;
for (uint i=0 ; i < table->keys ; i++,key_info++)
{
- if (drop_primary && (key_info->flags & HA_NOSAME))
+ char *key_name= key_info->name;
+
+ if (drop_primary && (key_info-> flags & HA_NOSAME) &&
+ !my_strcasecmp(system_charset_info, key_name, primary_key_name))
{
- drop_primary=0;
+ drop_primary= 0;
continue;
}
- char *key_name=key_info->name;
Alter_drop *drop;
drop_it.rewind();
while ((drop=drop_it++))
@@ -2303,7 +2305,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
(key_info->flags & HA_NOSAME ?
(!my_strcasecmp(system_charset_info,
- key_name, "PRIMARY") ?
+ key_name, primary_key_name) ?
Key::PRIMARY : Key::UNIQUE) :
(key_info->flags & HA_FULLTEXT ?
Key::FULLTEXT : Key::MULTIPLE)),
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 25620229844..260903c9dd1 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -29,7 +29,7 @@ int mysql_union(THD *thd, LEX *lex, select_result *result,
{
DBUG_ENTER("mysql_union");
int res= 0;
- if (!(res= unit->prepare(thd, result)))
+ if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK)))
res= unit->exec();
res|= unit->cleanup();
DBUG_RETURN(res);
@@ -106,7 +106,8 @@ bool select_union::flush()
}
-int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result)
+int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
+ ulong additional_options)
{
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_select;
@@ -146,7 +147,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result)
for (;sl; sl= sl->next_select())
{
JOIN *join= new JOIN(thd_arg, sl->item_list,
- sl->options | thd_arg->options | SELECT_NO_UNLOCK,
+ sl->options | thd_arg->options | additional_options,
tmp_result);
thd_arg->lex->current_select= sl;
offset_limit_cnt= sl->offset_limit;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index cdea32ad3f6..9fc8d482bfa 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -95,7 +95,7 @@ int mysql_update(THD *thd,
tables.table= table;
tables.alias= table_list->alias;
- if (setup_tables(update_table_list) ||
+ if (setup_tables(update_table_list, 0) ||
setup_conds(thd,update_table_list,&conds) ||
thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 310d8a41be2..ab95ba312d8 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1077,7 +1077,7 @@ create_table_options:
create_table_option:
ENGINE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; }
- | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; WARN_DEPRECATED("TYPE=database_engine","ENGINE=database_engine"); }
+ | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; WARN_DEPRECATED("TYPE=storage_engine","ENGINE=storage_engine"); }
| MAX_ROWS opt_equal ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
| MIN_ROWS opt_equal ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
| AVG_ROW_LENGTH opt_equal ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
diff --git a/sql/table.cc b/sql/table.cc
index 912c133e571..1127349db20 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -481,8 +481,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
/* Fix key->name and key_part->field */
if (key_parts)
{
- uint primary_key=(uint) (find_type((char*) "PRIMARY",&outparam->keynames,
- 3)-1);
+ uint primary_key=(uint) (find_type((char*) primary_key_name,
+ &outparam->keynames, 3) - 1);
uint ha_option=outparam->file->table_flags();
keyinfo=outparam->key_info;
key_part=keyinfo->key_part;