diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 12 | ||||
-rw-r--r-- | sql/item.cc | 3 | ||||
-rw-r--r-- | sql/item.h | 20 | ||||
-rw-r--r-- | sql/item_func.cc | 9 | ||||
-rw-r--r-- | sql/item_func.h | 8 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 12 | ||||
-rw-r--r-- | sql/item_subselect.cc | 20 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 27 | ||||
-rw-r--r-- | sql/sql_class.cc | 79 | ||||
-rw-r--r-- | sql/sql_class.h | 13 | ||||
-rw-r--r-- | sql/sql_db.cc | 12 | ||||
-rw-r--r-- | sql/sql_derived.cc | 24 | ||||
-rw-r--r-- | sql/sql_help.cc | 6 | ||||
-rw-r--r-- | sql/sql_insert.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_load.cc | 2 | ||||
-rw-r--r-- | sql/sql_olap.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 15 | ||||
-rw-r--r-- | sql/sql_show.cc | 18 | ||||
-rw-r--r-- | sql/sql_string.cc | 46 | ||||
-rw-r--r-- | sql/sql_string.h | 1 | ||||
-rw-r--r-- | sql/sql_table.cc | 12 | ||||
-rw-r--r-- | sql/sql_union.cc | 7 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 2 | ||||
-rw-r--r-- | sql/table.cc | 4 |
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; |