diff options
-rw-r--r-- | BitKeeper/etc/logging_ok | 1 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | include/hash.h | 2 | ||||
-rw-r--r-- | include/my_sys.h | 3 | ||||
-rw-r--r-- | libmysql/client_settings.h | 1 | ||||
-rw-r--r-- | libmysql/libmysql.c | 33 | ||||
-rw-r--r-- | mysql-test/r/gis.result | 7 | ||||
-rw-r--r-- | mysql-test/r/ps.result | 8 | ||||
-rw-r--r-- | mysql-test/r/rpl_charset.result | 8 | ||||
-rw-r--r-- | mysql-test/r/type_enum.result | 16 | ||||
-rw-r--r-- | mysql-test/t/gis.test | 4 | ||||
-rw-r--r-- | mysql-test/t/ps.test | 10 | ||||
-rw-r--r-- | mysql-test/t/rpl_charset.test | 18 | ||||
-rw-r--r-- | mysql-test/t/type_enum.test | 14 | ||||
-rw-r--r-- | mysys/hash.c | 26 | ||||
-rw-r--r-- | mysys/my_alloc.c | 37 | ||||
-rw-r--r-- | sql-common/client.c | 41 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 26 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 33 | ||||
-rw-r--r-- | sql/item_geofunc.h | 62 | ||||
-rw-r--r-- | sql/log_event.cc | 10 | ||||
-rw-r--r-- | sql/opt_range.cc | 8 | ||||
-rw-r--r-- | sql/sql_class.cc | 70 | ||||
-rw-r--r-- | sql/sql_class.h | 29 | ||||
-rw-r--r-- | sql/sql_show.cc | 2 | ||||
-rw-r--r-- | tests/client_test.c | 32 |
26 files changed, 377 insertions, 126 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 6520b17e787..77c82618446 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -24,6 +24,7 @@ bar@bar.udmsearch.izhnet.ru bar@deer.(none) bar@gw.udmsearch.izhnet.ru bar@mysql.com +bar@noter.intranet.mysql.r18.ru bell@laptop.sanja.is.com.ua bell@sanja.is.com.ua bk@admin.bk diff --git a/configure.in b/configure.in index 341fd7ba0d9..39151205533 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.1.5-gamma) +AM_INIT_AUTOMAKE(mysql, 4.1.6-gamma) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 diff --git a/include/hash.h b/include/hash.h index c7cc118b7bd..6e6db27cd40 100644 --- a/include/hash.h +++ b/include/hash.h @@ -47,6 +47,7 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset, uint key_length, hash_get_key get_key, void (*free_element)(void*), uint flags CALLER_INFO_PROTO); void hash_free(HASH *tree); +void hash_reset(HASH *hash); byte *hash_element(HASH *hash,uint idx); gptr hash_search(HASH *info,const byte *key,uint length); gptr hash_next(HASH *info,const byte *key,uint length); @@ -56,7 +57,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length); void hash_replace(HASH *hash, uint idx, byte *new_row); my_bool hash_check(HASH *hash); /* Only in debug library */ -#define hash_clear(H) bzero((char*) (H),sizeof(*(H))) #define hash_inited(H) ((H)->array.buffer != 0) #ifdef __cplusplus diff --git a/include/my_sys.h b/include/my_sys.h index ad1966ba67f..271e0ea0bcb 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -725,7 +725,8 @@ extern void my_free_lock(byte *ptr,myf flags); #define my_free_lock(A,B) my_free((A),(B)) #endif #define alloc_root_inited(A) ((A)->min_malloc != 0) -#define clear_alloc_root(A) bzero((void *) (A), sizeof(MEM_ROOT)) +#define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8) +#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; } while(0) extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size); extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h index 5857c0c84d6..552307733ea 100644 --- a/libmysql/client_settings.h +++ b/libmysql/client_settings.h @@ -42,6 +42,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename); void mysql_read_default_options(struct st_mysql_options *options, const char *filename,const char *group); +void mysql_detach_stmt_list(LIST **stmt_list); MYSQL * STDCALL cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user, const char *passwd, const char *db, diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 6601d3e4ad7..2ad6771cc69 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -662,6 +662,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db) { char buff[512],*end=buff; + int rc; DBUG_ENTER("mysql_change_user"); if (!user) @@ -695,18 +696,26 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, /* Write authentication package */ simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); - if ((*mysql->methods->read_change_user_result)(mysql, buff, passwd)) - DBUG_RETURN(1); - /* Free old connect information */ - my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); - - /* alloc new connect information */ - mysql->user= my_strdup(user,MYF(MY_WME)); - mysql->passwd=my_strdup(passwd,MYF(MY_WME)); - mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0; - DBUG_RETURN(0); + rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd); + + /* + The server will close all statements no matter was the attempt + to change user successful or not. + */ + mysql_detach_stmt_list(&mysql->stmts); + if (rc == 0) + { + /* Free old connect information */ + my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); + + /* alloc new connect information */ + mysql->user= my_strdup(user,MYF(MY_WME)); + mysql->passwd=my_strdup(passwd,MYF(MY_WME)); + mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0; + } + DBUG_RETURN(rc); } #if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 9f5dd286cf9..fd71cad36a6 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -485,3 +485,10 @@ MBRContains(GeomFromText('Polygon((0 0, 0 7, 7 7, 7 0, 0 0))'), a); AsText(a) POINT(1 1) drop table t1; +create table t1 select POINT(1,3); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `POINT(1,3)` longblob NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 8742ac29989..12337d358e1 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -289,3 +289,11 @@ execute stmt using @var; select * from t1; deallocate prepare stmt; drop table t1; +prepare stmt from "select 'abc' like convert('abc' using utf8)"; +execute stmt; +'abc' like convert('abc' using utf8) +1 +execute stmt; +'abc' like convert('abc' using utf8) +1 +deallocate prepare stmt; diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result index a60c9269625..54cce23b301 100644 --- a/mysql-test/r/rpl_charset.result +++ b/mysql-test/r/rpl_charset.result @@ -198,4 +198,12 @@ CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 +stop slave; +delete from t1; +change master to master_log_pos=5801; +start slave until master_log_file='master-bin.000001', master_log_pos=5937; +start slave; +select hex(c1), hex(c2) from t1; +hex(c1) hex(c2) +CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 drop table t1; diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index 976c484dabf..a94e90885db 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1661,3 +1661,19 @@ t1 CREATE TABLE `t1` ( `a` enum('ä','1','2') NOT NULL default 'ä' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set names latin1; +CREATE TABLE t1 ( +a INT default 1, +b ENUM('value','öäü_value','ÊÃÕ') character set latin1 NOT NULL +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) default '1', + `b` enum('value','öäü_value','ÊÃÕ') NOT NULL default 'value' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +a int(11) YES 1 +b enum('value','öäü_value','ÊÃÕ') value +drop table t1; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index e35b9996a44..30da019be3e 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -190,3 +190,7 @@ select AsText(a) from t1 where and MBRContains(GeomFromText('Polygon((0 0, 0 7, 7 7, 7 0, 0 0))'), a); drop table t1; + +create table t1 select POINT(1,3); +show create table t1; +drop table t1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index af356ca2a09..4b63a7db95f 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -304,3 +304,13 @@ select * from t1; deallocate prepare stmt; drop table t1; +# +# BUG#5688 "Upgraded 4.1.5 Server seg faults" # (prepared statements) +# The test case speaks for itself. +# Just another place where we used wrong memory root for Items created +# during statement prepare. +# +prepare stmt from "select 'abc' like convert('abc' using utf8)"; +execute stmt; +execute stmt; +deallocate prepare stmt; diff --git a/mysql-test/t/rpl_charset.test b/mysql-test/t/rpl_charset.test index 83e7d95e28c..9b9f53a94de 100644 --- a/mysql-test/t/rpl_charset.test +++ b/mysql-test/t/rpl_charset.test @@ -148,6 +148,24 @@ INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); select hex(c1), hex(c2) from t1; sync_slave_with_master; select hex(c1), hex(c2) from t1; + +# Now test for BUG##5705: SET CHARATER_SET_SERVERetc will be lost if +# STOP SLAVE before following query + +stop slave; +delete from t1; +change master to master_log_pos=5801; +start slave until master_log_file='master-bin.000001', master_log_pos=5937; +# Slave is supposed to stop _after_ the INSERT, even though 5937 is +# the position of the beginning of the INSERT; after SET slave is not +# supposed to increment position. +wait_for_slave_to_stop; +# When you merge this into 5.0 you will have to adjust positions +# above; the first master_log_pos above should be the one of the SET, +# the second should be the one of the INSERT. +start slave; +sync_with_master; +select hex(c1), hex(c2) from t1; connection master; drop table t1; sync_slave_with_master; diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index b8f32107892..2f1e11810af 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -45,3 +45,17 @@ create table t1 (a enum(0xE4, '1', '2') not null default 0xE4); show columns from t1; show create table t1; drop table t1; + + +# +# Bug #5628 German characters in field-defs will be '?' +# with some table definitions +# +set names latin1; +CREATE TABLE t1 ( + a INT default 1, + b ENUM('value','öäü_value','ÊÃÕ') character set latin1 NOT NULL +); +show create table t1; +show columns from t1; +drop table t1; diff --git a/mysys/hash.c b/mysys/hash.c index ce25ae89b63..6f2788ddce7 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -88,6 +88,32 @@ void hash_free(HASH *hash) DBUG_VOID_RETURN; } + +/* + Delete all elements from the hash (the hash itself is to be reused). + + SYNOPSIS + hash_reset() + hash the hash to delete elements of +*/ + +void hash_reset(HASH *hash) +{ + DBUG_ENTER("hash_reset"); + if (hash->free) + { + HASH_LINK *link= dynamic_element(&hash->array, 0, HASH_LINK*); + HASH_LINK *end= link + hash->records; + for (; link < end; ++link) + (*hash->free)(link->data); + } + reset_dynamic(&hash->array); + hash->records= 0; + hash->blength= 1; + hash->current_record= NO_RECORD; + DBUG_VOID_RETURN; +} + /* some helper functions */ /* diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index c9784ddc9a0..f0bc62b10a0 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -22,6 +22,27 @@ #undef EXTRA_DEBUG #define EXTRA_DEBUG + +/* + Initialize memory root + + SYNOPSIS + init_alloc_root() + mem_root - memory root to initialize + block_size - size of chunks (blocks) used for memory allocation + (It is external size of chunk i.e. it should include + memory required for internal structures, thus it + should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE) + pre_alloc_size - if non-0, then size of block that should be + pre-allocated during memory root initialization. + + DESCRIPTION + This function prepares memory root for further use, sets initial size of + chunk for memory allocation and pre-allocates first block if specified. + Altough error can happen during execution of this function if pre_alloc_size + is non-0 it won't be reported. Instead it will be reported as error in first + alloc_root() on this memory root. +*/ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size __attribute__((unused))) { @@ -29,7 +50,7 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, DBUG_PRINT("enter",("root: 0x%lx", mem_root)); mem_root->free= mem_root->used= mem_root->pre_alloc= 0; mem_root->min_malloc= 32; - mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8; + mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE; mem_root->error_handler= 0; mem_root->block_num= 4; /* We shift this with >>2 */ mem_root->first_block_usage= 0; @@ -54,9 +75,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, SYNOPSIS reset_root_defaults() mem_root memory root to change defaults of - block_size new value of block size. Must be - greater than ~68 bytes (the exact value depends on - platform and compilation flags) + block_size new value of block size. Must be greater or equal + than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about + 68 bytes and depends on platform and compilation flags) pre_alloc_size new size of preallocated block. If not zero, must be equal to or greater than block size, otherwise means 'no prealloc'. @@ -70,7 +91,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size __attribute__((unused))) { - mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8; + DBUG_ASSERT(alloc_root_inited(mem_root)); + + mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE; #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG)) if (pre_alloc_size) { @@ -123,6 +146,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) DBUG_ENTER("alloc_root"); DBUG_PRINT("enter",("root: 0x%lx", mem_root)); + DBUG_ASSERT(alloc_root_inited(mem_root)); + Size+=ALIGN_SIZE(sizeof(USED_MEM)); if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME)))) { @@ -140,6 +165,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) reg1 USED_MEM *next= 0; reg2 USED_MEM **prev; + DBUG_ASSERT(alloc_root_inited(mem_root)); + Size= ALIGN_SIZE(Size); if ((*(prev= &mem_root->free)) != NULL) { diff --git a/sql-common/client.c b/sql-common/client.c index 930388d2459..43e116eb0b6 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2239,6 +2239,32 @@ static void mysql_close_free(MYSQL *mysql) } +/* + Clear connection pointer of every statement: this is necessary + to give error on attempt to use a prepared statement of closed + connection. + + SYNOPSYS + mysql_detach_stmt_list() + stmt_list pointer to mysql->stmts +*/ + +void mysql_detach_stmt_list(LIST **stmt_list) +{ +#ifdef MYSQL_CLIENT + /* Reset connection handle in all prepared statements. */ + LIST *element= *stmt_list; + for (; element; element= element->next) + { + MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; + stmt->mysql= 0; + /* No need to call list_delete for statement here */ + } + *stmt_list= 0; +#endif /* MYSQL_CLIENT */ +} + + void STDCALL mysql_close(MYSQL *mysql) { DBUG_ENTER("mysql_close"); @@ -2255,20 +2281,7 @@ void STDCALL mysql_close(MYSQL *mysql) } mysql_close_free_options(mysql); mysql_close_free(mysql); -#ifdef MYSQL_CLIENT - if (mysql->stmts) - { - /* Reset connection handle in all prepared statements. */ - LIST *element; - for (element= mysql->stmts; element; element= element->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; - stmt->mysql= 0; - /* No need to call list_delete for statement here */ - } - mysql->stmts= 0; - } -#endif /*MYSQL_CLIENT*/ + mysql_detach_stmt_list(&mysql->stmts); #ifndef TO_BE_DELETED /* free/close slave list */ if (mysql->rpl_pivot) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 85b22d1eddd..8950ad0c594 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -188,17 +188,27 @@ void Item_bool_func2::fix_length_and_dec() { uint strong= 0; uint weak= 0; + uint32 dummy_offset; DTCollation coll; if (args[0]->result_type() == STRING_RESULT && args[1]->result_type() == STRING_RESULT && - !my_charset_same(args[0]->collation.collation, - args[1]->collation.collation) && + String::needs_conversion(0, args[0]->collation.collation, + args[1]->collation.collation, + &dummy_offset) && !coll.set(args[0]->collation, args[1]->collation, TRUE)) { Item* conv= 0; + THD *thd= current_thd; + Item_arena *arena= thd->current_arena, backup; strong= coll.strong; weak= strong ? 0 : 1; + /* + In case we're in statement prepare, create conversion item + in its memory: it will be reused on each execute. + */ + if (arena->is_stmt_prepare()) + thd->set_n_backup_item_arena(arena, &backup); if (args[weak]->type() == STRING_ITEM) { String tmp, cstr; @@ -211,21 +221,13 @@ void Item_bool_func2::fix_length_and_dec() } else { - THD *thd= current_thd; - /* - In case we're in statement prepare, create conversion item - in its memory: it will be reused on each execute. - */ - Item_arena *arena= thd->current_arena, backup; - if (arena->is_stmt_prepare()) - thd->set_n_backup_item_arena(arena, &backup); conv= new Item_func_conv_charset(args[weak], args[strong]->collation.collation); - if (arena->is_stmt_prepare()) - thd->restore_backup_item_arena(arena, &backup); conv->collation.set(args[weak]->collation.derivation); conv->fix_fields(thd, 0, &conv); } + if (arena->is_stmt_prepare()) + thd->restore_backup_item_arena(arena, &backup); args[weak]= conv ? conv : args[weak]; } } diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 9d58cc37c2a..935925c1e83 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -27,6 +27,13 @@ #include "sql_acl.h" #include <m_ctype.h> +void Item_geometry_func::fix_length_and_dec() +{ + collation.set(&my_charset_bin); + decimals=0; + max_length=MAX_BLOB_WIDTH; +} + String *Item_func_geometry_from_text::val_str(String *str) { @@ -44,6 +51,7 @@ String *Item_func_geometry_from_text::val_str(String *str) if ((arg_count == 2) && !args[1]->null_value) srid= (uint32)args[1]->val_int(); + str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) return 0; str->length(0); @@ -54,12 +62,6 @@ String *Item_func_geometry_from_text::val_str(String *str) } -void Item_func_geometry_from_text::fix_length_and_dec() -{ - max_length=MAX_BLOB_WIDTH; -} - - String *Item_func_geometry_from_wkb::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -71,6 +73,7 @@ String *Item_func_geometry_from_wkb::val_str(String *str) if ((arg_count == 2) && !args[1]->null_value) srid= (uint32)args[1]->val_int(); + str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) return 0; str->length(0); @@ -84,12 +87,6 @@ String *Item_func_geometry_from_wkb::val_str(String *str) } -void Item_func_geometry_from_wkb::fix_length_and_dec() -{ - max_length=MAX_BLOB_WIDTH; -} - - String *Item_func_as_wkt::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -138,12 +135,6 @@ String *Item_func_as_wkb::val_str(String *str) } -void Item_func_as_wkb::fix_length_and_dec() -{ - max_length= MAX_BLOB_WIDTH; -} - - String *Item_func_geometry_type::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -180,6 +171,7 @@ String *Item_func_envelope::val_str(String *str) return 0; srid= uint4korr(swkb->ptr()); + str->set_charset(&my_charset_bin); str->length(0); if (str->reserve(SRID_SIZE, 512)) return 0; @@ -202,6 +194,7 @@ String *Item_func_centroid::val_str(String *str) swkb->length() - SRID_SIZE)))) return 0; + str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) return 0; str->length(0); @@ -232,6 +225,7 @@ String *Item_func_spatial_decomp::val_str(String *str) return 0; srid= uint4korr(swkb->ptr()); + str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) goto err; str->length(0); @@ -279,6 +273,7 @@ String *Item_func_spatial_decomp_n::val_str(String *str) swkb->length() - SRID_SIZE))))) return 0; + str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) goto err; srid= uint4korr(swkb->ptr()); @@ -333,6 +328,7 @@ String *Item_func_point::val_str(String *str) str->realloc(1 + 4 + SIZEOF_STORED_DOUBLE*2)))) return 0; + str->set_charset(&my_charset_bin); str->length(0); str->q_append((char)Geometry::wkb_ndr); str->q_append((uint32)Geometry::wkb_point); @@ -358,6 +354,7 @@ String *Item_func_spatial_collection::val_str(String *str) String arg_value; uint i; + str->set_charset(&my_charset_bin); str->length(0); if (str->reserve(1 + 4 + 4, 512)) goto err; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index a1f36130152..79e4f804a04 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -23,24 +23,33 @@ #pragma interface /* gcc class implementation */ #endif -class Item_func_geometry_from_text: public Item_str_func +class Item_geometry_func: public Item_str_func { public: - Item_func_geometry_from_text(Item *a) :Item_str_func(a) {} - Item_func_geometry_from_text(Item *a, Item *srid) :Item_str_func(a, srid) {} + Item_geometry_func() :Item_str_func() {} + Item_geometry_func(Item *a) :Item_str_func(a) {} + Item_geometry_func(Item *a,Item *b) :Item_str_func(a,b) {} + Item_geometry_func(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {} + Item_geometry_func(List<Item> &list) :Item_str_func(list) {} + void fix_length_and_dec(); +}; + +class Item_func_geometry_from_text: public Item_geometry_func +{ +public: + Item_func_geometry_from_text(Item *a) :Item_geometry_func(a) {} + Item_func_geometry_from_text(Item *a, Item *srid) :Item_geometry_func(a, srid) {} const char *func_name() const { return "geometryfromtext"; } String *val_str(String *); - void fix_length_and_dec(); }; -class Item_func_geometry_from_wkb: public Item_str_func +class Item_func_geometry_from_wkb: public Item_geometry_func { public: - Item_func_geometry_from_wkb(Item *a): Item_str_func(a) {} - Item_func_geometry_from_wkb(Item *a, Item *srid): Item_str_func(a, srid) {} + Item_func_geometry_from_wkb(Item *a): Item_geometry_func(a) {} + Item_func_geometry_from_wkb(Item *a, Item *srid): Item_geometry_func(a, srid) {} const char *func_name() const { return "geometryfromwkb"; } String *val_str(String *); - void fix_length_and_dec(); }; class Item_func_as_wkt: public Item_str_func @@ -52,13 +61,12 @@ public: void fix_length_and_dec(); }; -class Item_func_as_wkb: public Item_str_func +class Item_func_as_wkb: public Item_geometry_func { public: - Item_func_as_wkb(Item *a): Item_str_func(a) {} + Item_func_as_wkb(Item *a): Item_geometry_func(a) {} const char *func_name() const { return "aswkb"; } String *val_str(String *); - void fix_length_and_dec(); }; class Item_func_geometry_type: public Item_str_func @@ -73,40 +81,37 @@ public: }; }; -class Item_func_centroid: public Item_str_func +class Item_func_centroid: public Item_geometry_func { public: - Item_func_centroid(Item *a): Item_str_func(a) {} + Item_func_centroid(Item *a): Item_geometry_func(a) {} const char *func_name() const { return "centroid"; } String *val_str(String *); - void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;} }; -class Item_func_envelope: public Item_str_func +class Item_func_envelope: public Item_geometry_func { public: - Item_func_envelope(Item *a): Item_str_func(a) {} + Item_func_envelope(Item *a): Item_geometry_func(a) {} const char *func_name() const { return "envelope"; } String *val_str(String *); - void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;} }; -class Item_func_point: public Item_str_func +class Item_func_point: public Item_geometry_func { public: - Item_func_point(Item *a, Item *b): Item_str_func(a, b) {} - Item_func_point(Item *a, Item *b, Item *srid): Item_str_func(a, b, srid) {} + Item_func_point(Item *a, Item *b): Item_geometry_func(a, b) {} + Item_func_point(Item *a, Item *b, Item *srid): Item_geometry_func(a, b, srid) {} const char *func_name() const { return "point"; } String *val_str(String *); - void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;} }; -class Item_func_spatial_decomp: public Item_str_func +class Item_func_spatial_decomp: public Item_geometry_func { enum Functype decomp_func; public: Item_func_spatial_decomp(Item *a, Item_func::Functype ft) : - Item_str_func(a) { decomp_func = ft; } + Item_geometry_func(a) { decomp_func = ft; } const char *func_name() const { switch (decomp_func) @@ -123,15 +128,14 @@ public: } } String *val_str(String *); - void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;} }; -class Item_func_spatial_decomp_n: public Item_str_func +class Item_func_spatial_decomp_n: public Item_geometry_func { enum Functype decomp_func_n; public: Item_func_spatial_decomp_n(Item *a, Item *b, Item_func::Functype ft): - Item_str_func(a, b) { decomp_func_n = ft; } + Item_geometry_func(a, b) { decomp_func_n = ft; } const char *func_name() const { switch (decomp_func_n) @@ -148,10 +152,9 @@ public: } } String *val_str(String *); - void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;} }; -class Item_func_spatial_collection: public Item_str_func +class Item_func_spatial_collection: public Item_geometry_func { String tmp_value; enum Geometry::wkbType coll_type; @@ -159,13 +162,12 @@ class Item_func_spatial_collection: public Item_str_func public: Item_func_spatial_collection( List<Item> &list, enum Geometry::wkbType ct, enum Geometry::wkbType it): - Item_str_func(list) + Item_geometry_func(list) { coll_type=ct; item_type=it; } String *val_str(String *); - void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;} const char *func_name() const { return "multipoint"; } }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 1f30e932c01..326f2fc5c59 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1091,7 +1091,15 @@ end: VOID(pthread_mutex_unlock(&LOCK_thread_count)); close_thread_tables(thd); free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC)); - return (thd->query_error ? thd->query_error : Log_event::exec_event(rli)); + /* + If there was an error we stop. Otherwise we increment positions. Note that + we will not increment group* positions if we are just after a SET + ONE_SHOT, because SET ONE_SHOT should not be separated from its following + updating query. + */ + return (thd->query_error ? thd->query_error : + (thd->one_shot_set ? (rli->inc_event_relay_log_pos(get_event_len()),0) : + Log_event::exec_event(rli))); } #endif diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 27e8e9c11e7..9c5b0235767 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2554,7 +2554,8 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) { - QUICK_SELECT *quick=new QUICK_SELECT(thd, table, ref->key, 1); + MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC); + QUICK_SELECT *quick= new QUICK_SELECT(thd, table, ref->key); KEY *key_info = &table->key_info[ref->key]; KEY_PART *key_part; QUICK_RANGE *range; @@ -2566,7 +2567,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) { if (thd->is_fatal_error) goto err; // out of memory - return quick; // empty range + goto ok; // empty range } if (!(range= new QUICK_RANGE())) @@ -2613,9 +2614,12 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) goto err; } +ok: + my_pthread_setspecific_ptr(THR_MALLOC, old_root); return quick; err: + my_pthread_setspecific_ptr(THR_MALLOC, old_root); delete quick; return 0; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 16c0c206df3..6cf01896b03 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -221,7 +221,6 @@ THD::THD() init(); /* Initialize sub structures */ - clear_alloc_root(&transaction.mem_root); init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); user_connect=(USER_CONN *)0; hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, @@ -258,6 +257,7 @@ THD::THD() transaction.trans_log.end_of_file= max_binlog_cache_size; } #endif + init_alloc_root(&transaction.mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); { ulong tmp=sql_rnd_with_mutex(); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); @@ -303,12 +303,12 @@ void THD::init(void) void THD::init_for_queries() { ha_enable_transaction(this,TRUE); - init_sql_alloc(&mem_root, - variables.query_alloc_block_size, - variables.query_prealloc_size); - init_sql_alloc(&transaction.mem_root, - variables.trans_alloc_block_size, - variables.trans_prealloc_size); + + reset_root_defaults(&mem_root, variables.query_alloc_block_size, + variables.query_prealloc_size); + reset_root_defaults(&transaction.mem_root, + variables.trans_alloc_block_size, + variables.trans_prealloc_size); } @@ -328,6 +328,7 @@ void THD::change_user(void) cleanup(); cleanup_done= 0; init(); + stmt_map.reset(); hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, (hash_free_key) free_user_var, 0); @@ -1331,6 +1332,17 @@ void select_dumpvar::cleanup() } +/* + Create arena for already constructed THD. + + SYNOPSYS + Item_arena() + thd - thread for which arena is created + + DESCRIPTION + Create arena for already existing THD using its variables as parameters + for memory root initialization. +*/ Item_arena::Item_arena(THD* thd) :free_list(0), state(INITIALIZED) @@ -1341,24 +1353,31 @@ Item_arena::Item_arena(THD* thd) } -/* This constructor is called when Item_arena is a subobject of THD */ +/* + Create arena and optionally initialize memory root. -Item_arena::Item_arena() - :free_list(0), - state(CONVENTIONAL_EXECUTION) -{ - clear_alloc_root(&mem_root); -} + SYNOPSYS + Item_arena() + init_mem_root - whenever we need to initialize memory root + DESCRIPTION + Create arena and optionally initialize memory root with minimal + possible parameters. + NOTE + We use this constructor when arena is part of THD, but reinitialize + its memory root in THD::init_for_queries() before execution of real + statements. +*/ Item_arena::Item_arena(bool init_mem_root) :free_list(0), - state(INITIALIZED) + state(CONVENTIONAL_EXECUTION) { if (init_mem_root) - clear_alloc_root(&mem_root); + init_alloc_root(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); } + Item_arena::Type Item_arena::type() const { DBUG_ASSERT("Item_arena::type()" == "abstract"); @@ -1366,10 +1385,6 @@ Item_arena::Type Item_arena::type() const } -Item_arena::~Item_arena() -{} - - /* Statement functions */ @@ -1393,7 +1408,8 @@ Statement::Statement(THD *thd) */ Statement::Statement() - :id(0), + :Item_arena((bool)TRUE), + id(0), set_query_id(1), allow_sum_func(0), /* initialized later */ lex(&main_lex), @@ -1461,8 +1477,16 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup) { set->set_item_arena(this); set_item_arena(backup); - // reset backup mem_root to avoid its freeing - init_alloc_root(&backup->mem_root, 0, 0); +#ifdef NOT_NEEDED_NOW + /* + Reset backup mem_root to avoid its freeing. + Since Item_arena's mem_root is freed only when it is part of Statement + we need this only if we use some Statement's arena as backup storage. + But we do this only with THD::stmt_backup and this Statement is specially + handled in this respect. So this code is not really needed now. + */ + clear_alloc_root(&backup->mem_root); +#endif } void Item_arena::set_item_arena(Item_arena *set) diff --git a/sql/sql_class.h b/sql/sql_class.h index 387bba43cad..68d187168d3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -441,11 +441,23 @@ public: STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE }; + /* + This constructor is used only when Item_arena is created as + backup storage for another instance of Item_arena. + */ + Item_arena() {}; + /* + Create arena for already constructed THD using its variables as + parameters for memory root initialization. + */ Item_arena(THD *thd); - Item_arena(); + /* + Create arena and optionally init memory root with minimal values. + Particularly used if Item_arena is part of Statement. + */ Item_arena(bool init_mem_root); virtual Type type() const; - virtual ~Item_arena(); + virtual ~Item_arena() {}; inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } @@ -566,7 +578,7 @@ public: assignment in Statement::Statement) Non-empty statement names are unique too: attempt to insert a new statement with duplicate name causes older statement to be deleted - + Statements are auto-deleted when they are removed from the map and when the map is deleted. */ @@ -575,7 +587,7 @@ class Statement_map { public: Statement_map(); - + int insert(Statement *statement); Statement *find_by_name(LEX_STRING *name) @@ -608,11 +620,18 @@ public: } hash_delete(&st_hash, (byte *) statement); } + /* Erase all statements (calls Statement destructor) */ + void reset() + { + hash_reset(&names_hash); + hash_reset(&st_hash); + last_found_statement= 0; + } ~Statement_map() { - hash_free(&st_hash); hash_free(&names_hash); + hash_free(&st_hash); } private: HASH st_hash; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 57c5f01d0bf..fbb45ce2484 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1265,6 +1265,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) // check for surprises from the previous call to Field::sql_type() if (type.ptr() != tmp) type.set(tmp, sizeof(tmp), system_charset_info); + else + type.set_charset(system_charset_info); field->sql_type(type); packet->append(type.ptr(), type.length(), system_charset_info); diff --git a/tests/client_test.c b/tests/client_test.c index 0a4d635984d..a2b0791baa2 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -10251,7 +10251,7 @@ static void test_bug5194() /* Number of columns per row */ const int COLUMN_COUNT= sizeof(float_array)/sizeof(*float_array); /* Number of rows per bulk insert to start with */ - const int MIN_ROWS_PER_INSERT= 260; + const int MIN_ROWS_PER_INSERT= 262; /* Max number of rows per bulk insert to end with */ const int MAX_ROWS_PER_INSERT= 300; const int MAX_PARAM_COUNT= COLUMN_COUNT*MAX_ROWS_PER_INSERT; @@ -10391,6 +10391,34 @@ static void test_bug5194() } +static void test_bug5315() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + + myheader("test_bug5315"); + + stmt_text= "SELECT 1"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + DBUG_ASSERT(rc == 0); + mysql_change_user(mysql, opt_user, opt_password, current_db); + rc= mysql_stmt_execute(stmt); + DBUG_ASSERT(rc != 0); + if (rc) + printf("Got error (as expected):\n%s", mysql_stmt_error(stmt)); + /* check that connection is OK */ + mysql_stmt_close(stmt); + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + DBUG_ASSERT(rc == 0); + rc= mysql_stmt_execute(stmt); + DBUG_ASSERT(rc == 0); + mysql_stmt_close(stmt); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -10694,6 +10722,8 @@ int main(int argc, char **argv) test_bug5399(); /* check that statement id uniquely identifies statement */ test_bug5194(); /* bulk inserts in prepared mode */ + test_bug5315(); /* check that mysql_change_user closes all + prepared statements */ /* XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. |