Commit 5ef32b58 authored by unknown's avatar unknown

Merge tulin@bk-internal.mysql.com:/home/bk/mysql-4.1-ndb

into poseidon.ndb.mysql.com:/home/tomas/mysql-4.1-ndb-merge

parents 99a020db f90828cb
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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);
......
......@@ -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,
......
......@@ -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)
......
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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 */
/*
......
......@@ -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)
{
......
......@@ -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)
......
......@@ -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];
}
}
......
......@@ -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;
......
......@@ -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"; }
};
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -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;
......
......@@ -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);
......
......@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment