Commit f06d8027 authored by mskold@mysql.com's avatar mskold@mysql.com

Merge mskold@build.mysql.com:/home/bk/mysql-4.1

into mysql.com:/usr/local/home/marty/MySQL/test/mysql-4.1
parents 646f1036 36548b10
...@@ -30,6 +30,7 @@ bk@admin.bk ...@@ -30,6 +30,7 @@ bk@admin.bk
bk@mysql.r18.ru bk@mysql.r18.ru
brian@avenger.(none) brian@avenger.(none)
brian@brian-akers-computer.local brian@brian-akers-computer.local
brian@private-client-ip-101.oz.net
carsten@tsort.bitbybit.dk carsten@tsort.bitbybit.dk
davida@isil.mysql.com davida@isil.mysql.com
dlenev@brandersnatch.localdomain dlenev@brandersnatch.localdomain
......
...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. ...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc) AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line! # 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) AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10 PROTOCOL_VERSION=10
......
...@@ -47,6 +47,7 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset, ...@@ -47,6 +47,7 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
uint key_length, hash_get_key get_key, uint key_length, hash_get_key get_key,
void (*free_element)(void*), uint flags CALLER_INFO_PROTO); void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
void hash_free(HASH *tree); void hash_free(HASH *tree);
void hash_reset(HASH *hash);
byte *hash_element(HASH *hash,uint idx); byte *hash_element(HASH *hash,uint idx);
gptr hash_search(HASH *info,const byte *key,uint length); gptr hash_search(HASH *info,const byte *key,uint length);
gptr hash_next(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); ...@@ -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); void hash_replace(HASH *hash, uint idx, byte *new_row);
my_bool hash_check(HASH *hash); /* Only in debug library */ 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) #define hash_inited(H) ((H)->array.buffer != 0)
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -42,6 +42,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename); ...@@ -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, void mysql_read_default_options(struct st_mysql_options *options,
const char *filename,const char *group); const char *filename,const char *group);
void mysql_detach_stmt_list(LIST **stmt_list);
MYSQL * STDCALL MYSQL * STDCALL
cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user, cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db, const char *passwd, const char *db,
......
...@@ -662,6 +662,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, ...@@ -662,6 +662,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db) const char *passwd, const char *db)
{ {
char buff[512],*end=buff; char buff[512],*end=buff;
int rc;
DBUG_ENTER("mysql_change_user"); DBUG_ENTER("mysql_change_user");
if (!user) if (!user)
...@@ -695,18 +696,26 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, ...@@ -695,18 +696,26 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
/* Write authentication package */ /* Write authentication package */
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
if ((*mysql->methods->read_change_user_result)(mysql, buff, passwd)) rc= (*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)); The server will close all statements no matter was the attempt
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); to change user successful or not.
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); */
mysql_detach_stmt_list(&mysql->stmts);
/* alloc new connect information */ if (rc == 0)
mysql->user= my_strdup(user,MYF(MY_WME)); {
mysql->passwd=my_strdup(passwd,MYF(MY_WME)); /* Free old connect information */
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0; my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN(0); 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) #if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
......
This diff is collapsed.
...@@ -1297,4 +1297,6 @@ INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); ...@@ -1297,4 +1297,6 @@ INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W');
INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring','');
INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
SELECT * FROM t2; SELECT * FROM t2;
OPTIMIZE TABLE t2;
SELECT * FROM t2;
drop table t1, t2; drop table t1, t2;
...@@ -88,6 +88,32 @@ void hash_free(HASH *hash) ...@@ -88,6 +88,32 @@ void hash_free(HASH *hash)
DBUG_VOID_RETURN; 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 */ /* some helper functions */
/* /*
......
...@@ -229,10 +229,10 @@ LocalConfig::parseString(const char * connectString, char *line){ ...@@ -229,10 +229,10 @@ LocalConfig::parseString(const char * connectString, char *line){
bool LocalConfig::readFile(const char * filename, bool &fopenError) bool LocalConfig::readFile(const char * filename, bool &fopenError)
{ {
char line[150], line2[150]; char line[1024];
fopenError = false; fopenError = false;
FILE * file = fopen(filename, "r"); FILE * file = fopen(filename, "r");
if(file == 0){ if(file == 0){
snprintf(line, 150, "Unable to open local config file: %s", filename); snprintf(line, 150, "Unable to open local config file: %s", filename);
...@@ -241,31 +241,33 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError) ...@@ -241,31 +241,33 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError)
return false; return false;
} }
unsigned int sz = 1024; BaseString theString;
char* theString = (char*)NdbMem_Allocate(sz);
theString[0] = 0; while(fgets(line, 1024, file)){
BaseString tmp(line);
fgets(theString, sz, file); tmp.trim(" \t\n\r");
while (fgets(line+1, 100, file)) { if(tmp.length() > 0 && tmp.c_str()[0] != '#'){
line[0] = ';'; theString.append(tmp);
while (strlen(theString) + strlen(line) >= sz) { break;
sz = sz*2;
char *newString = (char*)NdbMem_Allocate(sz);
strcpy(newString, theString);
free(theString);
theString = newString;
} }
strcat(theString, line);
} }
while (fgets(line, 1024, file)) {
bool return_value = parseString(theString, line); BaseString tmp(line);
tmp.trim(" \t\n\r");
if(tmp.length() > 0 && tmp.c_str()[0] != '#'){
theString.append(";");
theString.append(tmp);
}
}
bool return_value = parseString(theString.c_str(), line);
if (!return_value) { if (!return_value) {
snprintf(line2, 150, "Reading %s: %s", filename, line); BaseString tmp;
setError(0,line2); tmp.assfmt("Reading %s: %s", filename, line);
setError(0, tmp.c_str());
} }
free(theString);
fclose(file); fclose(file);
return return_value; return return_value;
} }
......
...@@ -2239,6 +2239,32 @@ static void mysql_close_free(MYSQL *mysql) ...@@ -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) void STDCALL mysql_close(MYSQL *mysql)
{ {
DBUG_ENTER("mysql_close"); DBUG_ENTER("mysql_close");
...@@ -2255,20 +2281,7 @@ void STDCALL mysql_close(MYSQL *mysql) ...@@ -2255,20 +2281,7 @@ void STDCALL mysql_close(MYSQL *mysql)
} }
mysql_close_free_options(mysql); mysql_close_free_options(mysql);
mysql_close_free(mysql); mysql_close_free(mysql);
#ifdef MYSQL_CLIENT mysql_detach_stmt_list(&mysql->stmts);
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*/
#ifndef TO_BE_DELETED #ifndef TO_BE_DELETED
/* free/close slave list */ /* free/close slave list */
if (mysql->rpl_pivot) if (mysql->rpl_pivot)
......
...@@ -70,7 +70,6 @@ ...@@ -70,7 +70,6 @@
Allow users to set compression level. Allow users to set compression level.
Add truncate table command. Add truncate table command.
Implement versioning, should be easy. Implement versioning, should be easy.
Implement optimize so we can fix broken tables.
Allow for errors, find a way to mark bad rows. Allow for errors, find a way to mark bad rows.
See if during an optimize you can make the table smaller. See if during an optimize you can make the table smaller.
Talk to the gzip guys, come up with a writable format so that updates are doable Talk to the gzip guys, come up with a writable format so that updates are doable
...@@ -88,6 +87,7 @@ static int archive_init= 0; ...@@ -88,6 +87,7 @@ static int archive_init= 0;
/* The file extension */ /* The file extension */
#define ARZ ".ARZ" #define ARZ ".ARZ"
#define ARN ".ARN"
/* /*
Used for hash table that tracks open tables. Used for hash table that tracks open tables.
...@@ -117,7 +117,7 @@ static ARCHIVE_SHARE *get_share(const char *table_name, TABLE *table) ...@@ -117,7 +117,7 @@ static ARCHIVE_SHARE *get_share(const char *table_name, TABLE *table)
if (!archive_init) if (!archive_init)
{ {
VOID(pthread_mutex_init(&archive_mutex,MY_MUTEX_INIT_FAST)); VOID(pthread_mutex_init(&archive_mutex,MY_MUTEX_INIT_FAST));
if (!hash_init(&archive_open_tables,system_charset_info,32,0,0, if (hash_init(&archive_open_tables,system_charset_info,32,0,0,
(hash_get_key) archive_get_key,0,0)) (hash_get_key) archive_get_key,0,0))
{ {
pthread_mutex_unlock(&LOCK_mysql_create_db); pthread_mutex_unlock(&LOCK_mysql_create_db);
...@@ -205,7 +205,7 @@ static int free_share(ARCHIVE_SHARE *share) ...@@ -205,7 +205,7 @@ static int free_share(ARCHIVE_SHARE *share)
We just implement one additional file extension. We just implement one additional file extension.
*/ */
const char **ha_archive::bas_ext() const const char **ha_archive::bas_ext() const
{ static const char *ext[]= { ARZ, NullS }; return ext; } { static const char *ext[]= { ARZ, ARN, NullS }; return ext; }
/* /*
...@@ -322,6 +322,11 @@ err: ...@@ -322,6 +322,11 @@ err:
/* /*
Look at ha_archive::open() for an explanation of the row format. Look at ha_archive::open() for an explanation of the row format.
Here we just write out the row. Here we just write out the row.
Wondering about start_bulk_insert()? We don't implement it for
archive since it optimizes for lots of writes. The only save
for implementing start_bulk_insert() is that we could skip
setting dirty to true each time.
*/ */
int ha_archive::write_row(byte * buf) int ha_archive::write_row(byte * buf)
{ {
...@@ -380,17 +385,7 @@ int ha_archive::rnd_init(bool scan) ...@@ -380,17 +385,7 @@ int ha_archive::rnd_init(bool scan)
pthread_mutex_lock(&share->mutex); pthread_mutex_lock(&share->mutex);
if (share->dirty == TRUE) if (share->dirty == TRUE)
{ {
/* I was having problems with OSX, but it worked for 10.3 so I am wrapping this with and ifdef */
#ifdef BROKEN_GZFLUSH
gzclose(share->archive_write);
if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
{
pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(errno ? errno : -1);
}
#else
gzflush(share->archive_write, Z_SYNC_FLUSH); gzflush(share->archive_write, Z_SYNC_FLUSH);
#endif
share->dirty= FALSE; share->dirty= FALSE;
} }
pthread_mutex_unlock(&share->mutex); pthread_mutex_unlock(&share->mutex);
...@@ -504,6 +499,54 @@ int ha_archive::rnd_pos(byte * buf, byte *pos) ...@@ -504,6 +499,54 @@ int ha_archive::rnd_pos(byte * buf, byte *pos)
DBUG_RETURN(get_row(buf)); DBUG_RETURN(get_row(buf));
} }
/*
The table can become fragmented if data was inserted, read, and then
inserted again. What we do is open up the file and recompress it completely.
*/
int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
{
DBUG_ENTER("ha_archive::optimize");
int read; // Bytes read, gzread() returns int
gzFile reader, writer;
char block[IO_SIZE];
char writer_filename[FN_REFLEN];
/* Lets create a file to contain the new data */
fn_format(writer_filename,share->table_name,"",ARN, MY_REPLACE_EXT|MY_UNPACK_FILENAME);
/* Closing will cause all data waiting to be flushed, to be flushed */
gzclose(share->archive_write);
if ((reader= gzopen(share->data_file_name, "rb")) == NULL)
DBUG_RETURN(-1);
if ((writer= gzopen(writer_filename, "wb")) == NULL)
{
gzclose(reader);
DBUG_RETURN(-1);
}
while (read= gzread(reader, block, IO_SIZE))
gzwrite(writer, block, read);
gzclose(reader);
gzclose(writer);
my_rename(writer_filename,share->data_file_name,MYF(0));
/*
We reopen the file in case some IO is waiting to go through.
In theory the table is closed right after this operation,
but it is possible for IO to still happen.
I may be being a bit too paranoid right here.
*/
if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
DBUG_RETURN(errno ? errno : -1);
share->dirty= FALSE;
DBUG_RETURN(0);
}
/****************************************************************************** /******************************************************************************
Everything below here is default, please look at ha_example.cc for Everything below here is default, please look at ha_example.cc for
......
...@@ -112,7 +112,7 @@ public: ...@@ -112,7 +112,7 @@ public:
int external_lock(THD *thd, int lock_type); int external_lock(THD *thd, int lock_type);
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key); ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type); enum thr_lock_type lock_type);
}; };
...@@ -185,7 +185,7 @@ void ha_ndbcluster::records_update() ...@@ -185,7 +185,7 @@ void ha_ndbcluster::records_update()
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d", DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(), ((const NDBTAB *)m_table)->getTableId(),
info->no_uncommitted_rows_count)); info->no_uncommitted_rows_count));
if (info->records == ~(ha_rows)0) // if (info->records == ~(ha_rows)0)
{ {
Uint64 rows; Uint64 rows;
if(ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0) == 0){ if(ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0) == 0){
...@@ -617,7 +617,7 @@ int ha_ndbcluster::get_metadata(const char *path) ...@@ -617,7 +617,7 @@ int ha_ndbcluster::get_metadata(const char *path)
DBUG_ENTER("get_metadata"); DBUG_ENTER("get_metadata");
DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path));
if (!(tab= dict->getTable(m_tabname, &m_table_info))) if (!(tab= dict->getTable(m_tabname)))
ERR_RETURN(dict->getNdbError()); ERR_RETURN(dict->getNdbError());
DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion()));
...@@ -665,8 +665,8 @@ int ha_ndbcluster::get_metadata(const char *path) ...@@ -665,8 +665,8 @@ int ha_ndbcluster::get_metadata(const char *path)
if (error) if (error)
DBUG_RETURN(error); DBUG_RETURN(error);
// All checks OK, lets use the table m_table= NULL;
m_table= (void*)tab; m_table_info= NULL;
DBUG_RETURN(build_index_list(table, ILBP_OPEN)); DBUG_RETURN(build_index_list(table, ILBP_OPEN));
} }
...@@ -781,6 +781,7 @@ void ha_ndbcluster::release_metadata() ...@@ -781,6 +781,7 @@ void ha_ndbcluster::release_metadata()
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
m_table= NULL; m_table= NULL;
m_table_info= NULL;
// Release index list // Release index list
for (i= 0; i < MAX_KEY; i++) for (i= 0; i < MAX_KEY; i++)
...@@ -2402,7 +2403,17 @@ void ha_ndbcluster::info(uint flag) ...@@ -2402,7 +2403,17 @@ void ha_ndbcluster::info(uint flag)
if (flag & HA_STATUS_VARIABLE) if (flag & HA_STATUS_VARIABLE)
{ {
DBUG_PRINT("info", ("HA_STATUS_VARIABLE")); DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
records_update(); if (m_table_info)
{
records_update();
}
else
{
Uint64 rows;
if(ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0) == 0){
records= rows;
}
}
} }
if (flag & HA_STATUS_CONST) if (flag & HA_STATUS_CONST)
{ {
...@@ -2794,6 +2805,16 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) ...@@ -2794,6 +2805,16 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
// Start of transaction // Start of transaction
retrieve_all_fields= FALSE; retrieve_all_fields= FALSE;
ops_pending= 0; ops_pending= 0;
{
NDBDICT *dict= m_ndb->getDictionary();
const NDBTAB *tab;
void *tab_info;
if (!(tab= dict->getTable(m_tabname, &tab_info)))
ERR_RETURN(dict->getNdbError());
DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion()));
m_table= (void *)tab;
m_table_info= tab_info;
}
no_uncommitted_rows_init(thd); no_uncommitted_rows_init(thd);
} }
else else
...@@ -2816,6 +2837,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) ...@@ -2816,6 +2837,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
thd->transaction.stmt.ndb_tid= 0; thd->transaction.stmt.ndb_tid= 0;
} }
} }
m_table= NULL;
m_table_info= NULL;
if (m_active_trans) if (m_active_trans)
DBUG_PRINT("warning", ("m_active_trans != NULL")); DBUG_PRINT("warning", ("m_active_trans != NULL"));
if (m_active_cursor) if (m_active_cursor)
...@@ -3301,6 +3324,7 @@ int ha_ndbcluster::alter_table_name(const char *from, const char *to) ...@@ -3301,6 +3324,7 @@ int ha_ndbcluster::alter_table_name(const char *from, const char *to)
ERR_RETURN(dict->getNdbError()); ERR_RETURN(dict->getNdbError());
m_table= NULL; m_table= NULL;
m_table_info= NULL;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -328,6 +328,7 @@ void THD::change_user(void) ...@@ -328,6 +328,7 @@ void THD::change_user(void)
cleanup(); cleanup();
cleanup_done= 0; cleanup_done= 0;
init(); init();
stmt_map.reset();
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key, (hash_get_key) get_var_key,
(hash_free_key) free_user_var, 0); (hash_free_key) free_user_var, 0);
......
...@@ -566,7 +566,7 @@ public: ...@@ -566,7 +566,7 @@ public:
assignment in Statement::Statement) assignment in Statement::Statement)
Non-empty statement names are unique too: attempt to insert a new statement Non-empty statement names are unique too: attempt to insert a new statement
with duplicate name causes older statement to be deleted with duplicate name causes older statement to be deleted
Statements are auto-deleted when they are removed from the map and when the Statements are auto-deleted when they are removed from the map and when the
map is deleted. map is deleted.
*/ */
...@@ -575,7 +575,7 @@ class Statement_map ...@@ -575,7 +575,7 @@ class Statement_map
{ {
public: public:
Statement_map(); Statement_map();
int insert(Statement *statement); int insert(Statement *statement);
Statement *find_by_name(LEX_STRING *name) Statement *find_by_name(LEX_STRING *name)
...@@ -608,11 +608,18 @@ public: ...@@ -608,11 +608,18 @@ public:
} }
hash_delete(&st_hash, (byte *) statement); 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() ~Statement_map()
{ {
hash_free(&st_hash);
hash_free(&names_hash); hash_free(&names_hash);
hash_free(&st_hash);
} }
private: private:
HASH st_hash; HASH st_hash;
......
...@@ -10391,6 +10391,34 @@ static void test_bug5194() ...@@ -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 Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -10694,6 +10722,8 @@ int main(int argc, char **argv) ...@@ -10694,6 +10722,8 @@ int main(int argc, char **argv)
test_bug5399(); /* check that statement id uniquely identifies test_bug5399(); /* check that statement id uniquely identifies
statement */ statement */
test_bug5194(); /* bulk inserts in prepared mode */ 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 XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. 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