mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
Merge tulin@bk-internal.mysql.com:/home/bk/mysql-4.1-ndb
into poseidon.ndb.mysql.com:/home/tomas/mysql-4.1-ndb-merge
This commit is contained in:
@@ -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));
|
||||
rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
|
||||
|
||||
/* 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);
|
||||
/*
|
||||
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('<27>','1','2') NOT NULL default '<27>'
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
set names latin1;
|
||||
CREATE TABLE t1 (
|
||||
a INT default 1,
|
||||
b ENUM('value','<27><><EFBFBD>_value','<27><><EFBFBD>') character set latin1 NOT NULL
|
||||
);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) default '1',
|
||||
`b` enum('value','<27><><EFBFBD>_value','<27><><EFBFBD>') 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','<27><><EFBFBD>_value','<27><><EFBFBD>') 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','<27><><EFBFBD>_value','<27><><EFBFBD>') character set latin1 NOT NULL
|
||||
);
|
||||
show create table t1;
|
||||
show columns from t1;
|
||||
drop table t1;
|
||||
|
||||
26
mysys/hash.c
26
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 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -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) {}
|
||||
const char *func_name() const { return "geometryfromtext"; }
|
||||
String *val_str(String *);
|
||||
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_wkb: public Item_str_func
|
||||
class Item_func_geometry_from_text: 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_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 *);
|
||||
};
|
||||
|
||||
class Item_func_geometry_from_wkb: public Item_geometry_func
|
||||
{
|
||||
public:
|
||||
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()
|
||||
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(CONVENTIONAL_EXECUTION)
|
||||
{
|
||||
clear_alloc_root(&mem_root);
|
||||
}
|
||||
|
||||
|
||||
Item_arena::Item_arena(bool init_mem_root)
|
||||
:free_list(0),
|
||||
state(INITIALIZED)
|
||||
{
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user