mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Bug fixes for 3.23.23
myisam/mi_debug.c: ***MISSING WEAVE*** Docs/internals.texi: Added coding guidelines Docs/manual.texi: Changelog update + Win32 -> Windows client/mysql.cc: Changed --no-named-commands to be on by default client/mysqlimport.c: Bug fix include/config-win.h: Update of supported functions include/global.h: Removed compiler warning libmysql/libmysql.c: Fix for Ia64 myisam/ChangeLog: Changelog myisam/Makefile.am: Added file mi_dbug.c myisam/ft_stopwords.c: Fix for Ia64 myisam/mi_delete_table.c: Extra debugging myisam/mi_rename.c: Extra debugging myisam/mi_rnext.c: Fixed bug with MIN and concurrent insert myisam/mi_rprev.c: Fixed bug with MAX and concurrent insert myisam/mi_search.c: Fixed bug with DECIMAL/NUMERIC keys myisam/myisamdef.h: Extra debugging scripts/make_binary_distribution.sh: Added thread safe mysql library sql/ha_heap.cc: Fix of HEAP bug with range keys sql/ha_heap.h: Fix of HEAP bug with range keys sql/handler.cc: Optimizing sql/handler.h: Optimizing sql/lock.cc: More DEBUG + fix of RENAME bug sql/mini_client.cc: Fix for Ia64 sql/mysql_priv.h: Fix for name locks sql/mysqld.cc: Shorter message if wrong options sql/opt_range.cc: Added TODO sql/sql_base.cc: Fix for DROP TABLE sql/sql_parse.cc: Fix of permission checking for CHECK TABLE sql/sql_select.cc: Fix of using LEFT JOIN with empty table sql/table.h: Fix for name locks tests/fork_test.pl: Fixed typo
This commit is contained in:
@ -143,6 +143,65 @@ same tables.
|
||||
and then we read the rows in the sorted order into a row buffer
|
||||
(record_buffer) .
|
||||
|
||||
@node Coding guidelines
|
||||
@chapter Coding guidelines
|
||||
|
||||
- We are using bitkeeper (www.bitkeeper.com) for source management.
|
||||
- You should use the MySQL 3.23 or MySQL 4.0 source for all developments.
|
||||
- If you have any questions about the MySQL source, you can post these
|
||||
to developers@mysql.com and we will answer them.
|
||||
Note that we will shortly change the name of this list to
|
||||
internals@mysql.com, to more accurately reflect what should be
|
||||
posted to this list.
|
||||
|
||||
- Try to write code in a lot of black boxes that can be reused or at
|
||||
least have a clean interface
|
||||
- Reuse code; There is already in MySQL a lot of algorithms for list handling,
|
||||
queues, dynamic and hashed arrays, sorting...) that can be reused.
|
||||
- Try to always write optimized code, so that you don't have to
|
||||
go back and rewrite it a couple of months later. It's better to
|
||||
spend 3 times as much time designing and writing and optimal function than
|
||||
having to do it all over again later on.
|
||||
- Avoid CPU wasteful code, even where it does not matter, so that
|
||||
you will not develop sloppy coding habits.
|
||||
- If you can write it in fewer lines, do it (as long as the code will not
|
||||
be slower or much harder to read)
|
||||
- do not check the same pointer for NULL more than once.
|
||||
- Use long function and variable names in English; This makes your
|
||||
code easier to read.
|
||||
- Think assembly - make it easier for the compiler to optimize your code.
|
||||
- Comment your code when you do something that someone else may think
|
||||
is 'not trivial'.
|
||||
- Use the my_ functions like my_read/my_write/my_malloc() that you can
|
||||
find in the mysys library instead of the direct system calls; This
|
||||
will make your code easier to debug and more portable.
|
||||
- use libstring functions instead of standard libc string functions
|
||||
whenever possible
|
||||
- Avoid using alloc (its REAL slow); For memory allocations that only
|
||||
needs to live for the lifetime of one thread, on should use
|
||||
sql_alloc() instead.
|
||||
- Before doing big design decision, please first post a summary of
|
||||
what you want to do, why you want to do it and how you plan to do
|
||||
it. This way we can easily provide you with feedback and also
|
||||
easily discuss is throughly if some other developer thinks there is better
|
||||
way to do the same thing!
|
||||
|
||||
- Use my_var as opposed to myVar or MyVar ( _ rather than dancing SHIFT
|
||||
to spearate words in identifiers)
|
||||
- class names start with a capital
|
||||
- structure types are typedefed to all caps identifier
|
||||
- #defines are capitalized
|
||||
- matching { are in the same column
|
||||
- functions return 0 on success , non-zero on error, so you can do
|
||||
if(a() || b() || c()) { error("something went wrong");}
|
||||
- goto is ok if not abused
|
||||
- avoid default variable initalizations, use LINT_INIT() if the
|
||||
compiler complains after making sure that there is really no way
|
||||
the variable can be used uninitialized
|
||||
- Do not instantiate a class if you do not have to
|
||||
- Use pointers rather than array indexing when operating on strings
|
||||
|
||||
|
||||
@node Index
|
||||
@unnumbered Index
|
||||
|
||||
|
422
Docs/manual.texi
422
Docs/manual.texi
File diff suppressed because it is too large
Load Diff
@ -114,7 +114,7 @@ static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
|
||||
no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
|
||||
opt_compress=0,
|
||||
vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
|
||||
no_named_cmds=0;
|
||||
no_named_cmds=1; // we want this to be the default
|
||||
static uint verbose=0,opt_silent=0,opt_mysql_port=0;
|
||||
static my_string opt_mysql_unix_port=0;
|
||||
static int connect_flag=CLIENT_INTERACTIVE;
|
||||
@ -160,7 +160,7 @@ typedef struct {
|
||||
|
||||
static COMMANDS commands[] = {
|
||||
{ "help", 'h', com_help, 0, "Display this text" },
|
||||
{ "?", 'h', com_help, 0, "Synonym for `help'" },
|
||||
{ "?", '?', com_help, 0, "Synonym for `help'" },
|
||||
{ "clear", 'c', com_clear, 0, "Clear command"},
|
||||
{ "connect",'r', com_connect,1,
|
||||
"Reconnect to the server. Optional arguments are db and host" },
|
||||
@ -300,7 +300,7 @@ int main(int argc,char *argv[])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sprintf(buff, "Type '%s' for help.\n", no_named_cmds ? "\\h" : "help");
|
||||
sprintf(buff, "Type 'help;' or '\\h' for help.\n");
|
||||
put_info(buff,INFO_INFO);
|
||||
status.exit_status=read_lines(1); // read lines and execute them
|
||||
mysql_end(0);
|
||||
@ -352,6 +352,7 @@ static struct option long_options[] =
|
||||
{"database", required_argument, 0, 'D'},
|
||||
{"debug-info", no_argument, 0, 'T'},
|
||||
{"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
|
||||
{"enable-named-commands", no_argument, 0, 'G'},
|
||||
{"execute", required_argument, 0, 'e'},
|
||||
{"force", no_argument, 0, 'f'},
|
||||
{"help", no_argument, 0, '?'},
|
||||
@ -401,7 +402,7 @@ CHANGEABLE_VAR changeable_vars[] = {
|
||||
|
||||
static void usage(int version)
|
||||
{
|
||||
printf("%s Ver 10.8 Distrib %s, for %s (%s)\n",
|
||||
printf("%s Ver 10.10 Distrib %s, for %s (%s)\n",
|
||||
my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
|
||||
if (version)
|
||||
return;
|
||||
@ -426,11 +427,17 @@ static void usage(int version)
|
||||
-D, --database=.. Database to use.\n\
|
||||
--default-character-set=...\n\
|
||||
Set the default character set.\n\
|
||||
-G, --enable-named-commands\n\
|
||||
Named commands are enabled. Opposite to -g.\n\
|
||||
-e, --execute=... Execute command and quit. (Output like with --batch)\n\
|
||||
-E, --vertical Print the output of a query (rows) vertically.\n\
|
||||
-f, --force Continue even if we get an sql error.\n\
|
||||
-g, --no-named-commands\n\
|
||||
Named commands are disabled. Use \\* form only.\n\
|
||||
Named commands are disabled. Use \\* form only, or\n\
|
||||
use named commands only in the beginning of a line\n\
|
||||
ending with a semicolon (;)\n\
|
||||
Since version 10.9 the client now starts with this\n\
|
||||
option ENABLED by default! Disable with '-G'\n\
|
||||
-i, --ignore-space Ignore space after function names.\n\
|
||||
-h, --host=... Connect to host.\n\
|
||||
-H, --html Produce HTML output.\n\
|
||||
@ -486,7 +493,7 @@ static int get_options(int argc, char **argv)
|
||||
bool tty_password=0;
|
||||
|
||||
set_all_changeable_vars(changeable_vars);
|
||||
while ((c=getopt_long(argc,argv,"?ABCD:LfgHinNoqrstTUvVwWEe:h:O:P:S:u:#::p::",
|
||||
while ((c=getopt_long(argc,argv,"?ABCD:LfgGHinNoqrstTUvVwWEe:h:O:P:S:u:#::p::",
|
||||
long_options, &option_index)) != EOF)
|
||||
{
|
||||
switch(c) {
|
||||
@ -565,6 +572,7 @@ static int get_options(int argc, char **argv)
|
||||
case 'E': vertical=1; break;
|
||||
case 'w': wait_flag=1; break;
|
||||
case 'A': no_rehash=1; break;
|
||||
case 'G': no_named_cmds=0; break;
|
||||
case 'g': no_named_cmds=1; break;
|
||||
case 'H': opt_html=1; break;
|
||||
case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
|
||||
@ -1171,11 +1179,13 @@ com_help (String *buffer __attribute__((unused)),
|
||||
reg1 int i;
|
||||
|
||||
put_info("\nMySQL commands:",INFO_INFO);
|
||||
if (no_named_cmds)
|
||||
put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
|
||||
for (i = 0; commands[i].name; i++)
|
||||
{
|
||||
if (commands[i].func)
|
||||
printf("%s\t(\\%c)\t%s\n", commands[i].name,commands[i].cmd_char,
|
||||
commands[i].doc);
|
||||
printf("%s\t(\\%c)\t%s\n", commands[i].name,
|
||||
commands[i].cmd_char, commands[i].doc);
|
||||
}
|
||||
if (connected)
|
||||
printf("\nConnection id: %ld (Can be used with mysqladmin kill)\n\n",
|
||||
|
@ -25,7 +25,7 @@
|
||||
** * *
|
||||
** *************************
|
||||
*/
|
||||
#define IMPORT_VERSION "2.3"
|
||||
#define IMPORT_VERSION "2.4"
|
||||
|
||||
#include <global.h>
|
||||
#include <my_sys.h>
|
||||
@ -514,7 +514,6 @@ int main(int argc, char **argv)
|
||||
exitcode = error;
|
||||
db_disconnect(current_host, sock);
|
||||
my_free(password,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
|
||||
free_defaults(argv_to_free);
|
||||
my_end(0);
|
||||
return(exitcode);
|
||||
|
@ -250,6 +250,8 @@ inline double ulonglong2double(ulonglong value)
|
||||
#define HAVE_RINT /* defined in this file */
|
||||
#define NO_FCNTL_NONBLOCK /* No FCNTL */
|
||||
#define HAVE_ALLOCA
|
||||
#define HAVE_STRPBRK
|
||||
#define HAVE_STRSTR
|
||||
#define HAVE_COMPRESS
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
@ -110,7 +110,7 @@
|
||||
#endif
|
||||
|
||||
/* In Linux-alpha we have atomic.h if we are using gcc */
|
||||
#if defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && defined(__alpha__) && (__GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95))
|
||||
#if defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && defined(__alpha__) && (__GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95)) && !defined(HAVE_ATOMIC_ADD)
|
||||
#define HAVE_ATOMIC_ADD
|
||||
#define HAVE_ATOMIC_SUB
|
||||
#endif
|
||||
|
@ -112,7 +112,8 @@ static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
|
||||
* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
|
||||
*****************************************************************************/
|
||||
|
||||
static int connect2(File s, const struct sockaddr *name, uint namelen, uint to)
|
||||
static int connect2(my_socket s, const struct sockaddr *name, uint namelen,
|
||||
uint to)
|
||||
{
|
||||
#if defined(__WIN__)
|
||||
return connect(s, (struct sockaddr*) name, namelen);
|
||||
@ -1138,7 +1139,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
|
||||
uint port, const char *unix_socket,uint client_flag)
|
||||
{
|
||||
char buff[100],charset_name_buff[16],*end,*host_info, *charset_name;
|
||||
int sock;
|
||||
my_socket sock;
|
||||
uint32 ip_addr;
|
||||
struct sockaddr_in sock_addr;
|
||||
uint pkt_length;
|
||||
@ -1270,7 +1271,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
|
||||
sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
|
||||
DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
|
||||
/* _WIN64 ; Assume that the (int) range is enough for socket() */
|
||||
if ((sock = (int) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
|
||||
if ((sock = (my_socket) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
|
||||
{
|
||||
net->last_errno=CR_IPSOCK_ERROR;
|
||||
sprintf(net->last_error,ER(net->last_errno),ERRNO);
|
||||
|
@ -1,3 +1,7 @@
|
||||
2000-08-23 Michael Widenius <monty@mysql.com>
|
||||
|
||||
* Fixed bug when comparing DECIMAL/NUMERIC key parts.
|
||||
|
||||
2000-08-17 Michael Widenius <monty@mysql.com>
|
||||
|
||||
* Add a new flag in share.staus so that we can quickly check if a table
|
||||
|
@ -43,7 +43,7 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
|
||||
mi_rsamepos.c mi_panic.c mi_close.c mi_create.c\
|
||||
mi_range.c mi_dbug.c mi_checksum.c mi_log.c \
|
||||
mi_changed.c mi_static.c mi_delete_all.c \
|
||||
mi_delete_table.c mi_rename.c mi_check.c \
|
||||
mi_delete_table.c mi_rename.c mi_check.c mi_debug.c \
|
||||
ft_parser.c ft_search.c ft_stopwords.c ft_static.c \
|
||||
ft_update.c sort.c
|
||||
CLEANFILES = test?.IS? isam.log mi_test_all
|
||||
|
@ -48,7 +48,7 @@ int ft_init_stopwords(const char **sws)
|
||||
|
||||
for(;*sws;sws++)
|
||||
{
|
||||
if( (sw.len=strlen(sw.pos=*sws)) < MIN_WORD_LEN) continue;
|
||||
if( (sw.len= (uint) strlen(sw.pos=*sws)) < MIN_WORD_LEN) continue;
|
||||
if(!tree_insert(stopwords3, &sw, 0))
|
||||
{
|
||||
delete_tree(stopwords3);
|
||||
|
@ -30,6 +30,10 @@ int mi_delete_table(const char *name)
|
||||
uint raid_type=0,raid_chunks=0;
|
||||
#endif
|
||||
DBUG_ENTER("mi_delete_table");
|
||||
|
||||
#ifdef EXTRA_DEBUG
|
||||
check_table_is_closed(name,"delete");
|
||||
#endif
|
||||
#ifdef USE_RAID
|
||||
{
|
||||
MI_INFO *info;
|
||||
@ -39,7 +43,10 @@ int mi_delete_table(const char *name)
|
||||
raid_chunks = info->s->base.raid_chunks;
|
||||
mi_close(info);
|
||||
}
|
||||
#ifdef EXTRA_DEBUG
|
||||
check_table_is_closed(name,"delete");
|
||||
#endif
|
||||
#endif /* USE_RAID */
|
||||
|
||||
fn_format(from,name,"",MI_NAME_IEXT,4);
|
||||
if (my_delete(from, MYF(MY_WME)))
|
||||
|
@ -30,6 +30,11 @@ int mi_rename(const char *old_name, const char *new_name)
|
||||
uint raid_type=0,raid_chunks=0;
|
||||
#endif
|
||||
DBUG_ENTER("mi_rename");
|
||||
|
||||
#ifdef EXTRA_DEBUG
|
||||
check_table_is_closed(old_name,"rename old_table");
|
||||
check_table_is_closed(new_name,"rename new table2");
|
||||
#endif
|
||||
#ifdef USE_RAID
|
||||
{
|
||||
MI_INFO *info;
|
||||
@ -39,7 +44,10 @@ int mi_rename(const char *old_name, const char *new_name)
|
||||
raid_chunks = info->s->base.raid_chunks;
|
||||
mi_close(info);
|
||||
}
|
||||
#ifdef EXTRA_DEBUG
|
||||
check_table_is_closed(old_name,"rename raidcheck");
|
||||
#endif
|
||||
#endif /* USE_RAID */
|
||||
|
||||
fn_format(from,old_name,"",MI_NAME_IEXT,4);
|
||||
fn_format(to,new_name,"",MI_NAME_IEXT,4);
|
||||
|
@ -57,7 +57,7 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx)
|
||||
/* Skip rows that are inserted by other threads since we got a lock */
|
||||
if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey,
|
||||
info->lastkey_length,
|
||||
flag,
|
||||
SEARCH_BIGGER,
|
||||
info->s->state.key_root[inx])))
|
||||
break;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ int mi_rprev(MI_INFO *info, byte *buf, int inx)
|
||||
/* Skip rows that are inserted by other threads since we got a lock */
|
||||
if ((error=_mi_search_next(info,share->keyinfo+inx,info->lastkey,
|
||||
info->lastkey_length,
|
||||
flag,
|
||||
SEARCH_SMALLER,
|
||||
share->state.key_root[inx])))
|
||||
break;
|
||||
}
|
||||
|
@ -716,6 +716,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
|
||||
{
|
||||
alength= *a++; blength= *b++;
|
||||
end=a+alength;
|
||||
next_key_length=key_length-blength-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -622,6 +622,8 @@ void mi_dectivate_non_unique_index(MI_INFO *info, ha_rows rows);
|
||||
int _mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
|
||||
enum ha_rkey_function search_flag, bool raw_key);
|
||||
|
||||
my_bool check_table_is_closed(const char *name, const char *where);
|
||||
|
||||
/* Functions needed by mi_check */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -48,7 +48,7 @@ rm $BASE/include/Makefile*; rm $BASE/include/*.in
|
||||
|
||||
cp -p tests/*.res tests/*.tst tests/*.pl $BASE/tests
|
||||
cp -p support-files/* $BASE/support-files
|
||||
cp -p libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* libmysql/libmysqlclient.* mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a $BASE/lib
|
||||
cp -p libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* libmysql/libmysqlclient.* libmysql_r/.libs/libmysqlclient_a.a libmysql_r/.libs/libmysqlclient.so* libmysql_r/libmysqlclient.* mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a $BASE/lib
|
||||
cp -r -p sql/share/* $BASE/share/mysql; rm -f $BASE/share/mysql/Makefile* $BASE/share/mysql/*/*.OLD $BASE/share/CVS $BASE/share/*/CVS
|
||||
|
||||
cp -p scripts/* $BASE/bin
|
||||
|
@ -251,6 +251,21 @@ int ha_heap::rename_table(const char * from, const char * to)
|
||||
}
|
||||
|
||||
|
||||
ha_rows ha_heap::records_in_range(int inx,
|
||||
const byte *start_key,uint start_key_len,
|
||||
enum ha_rkey_function start_search_flag,
|
||||
const byte *end_key,uint end_key_len,
|
||||
enum ha_rkey_function end_search_flag)
|
||||
{
|
||||
KEY *pos=table->key_info+inx;
|
||||
if (start_key_len != end_key_len ||
|
||||
start_key_len != pos->key_length ||
|
||||
start_search_flag != HA_READ_KEY_EXACT ||
|
||||
end_search_flag != HA_READ_KEY_EXACT)
|
||||
return HA_POS_ERROR; // Can't only use exact keys
|
||||
return 10; // Good guess
|
||||
}
|
||||
|
||||
/* We can just delete the heap on creation */
|
||||
|
||||
int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info)
|
||||
|
@ -65,7 +65,10 @@ class ha_heap: public handler
|
||||
int reset(void);
|
||||
int external_lock(THD *thd, int lock_type);
|
||||
int delete_all_rows(void);
|
||||
|
||||
ha_rows records_in_range(int inx, const byte *start_key,uint start_key_len,
|
||||
enum ha_rkey_function start_search_flag,
|
||||
const byte *end_key,uint end_key_len,
|
||||
enum ha_rkey_function end_search_flag);
|
||||
int delete_table(const char *from);
|
||||
int rename_table(const char * from, const char * to);
|
||||
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
|
||||
|
@ -317,8 +317,8 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
|
||||
}
|
||||
if (!error)
|
||||
{
|
||||
|
||||
if (!(ref=(byte*) my_malloc(ALIGN_SIZE(ref_length)*2,MYF(0))))
|
||||
if (!(ref=(byte*) alloc_root(&table->mem_root,
|
||||
ALIGN_SIZE(ref_length)*2)))
|
||||
{
|
||||
close();
|
||||
error=HA_ERR_OUT_OF_MEM;
|
||||
|
@ -200,7 +200,7 @@ public:
|
||||
create_time(0), check_time(0), update_time(0), mean_rec_length(0),
|
||||
ft_handler(0)
|
||||
{}
|
||||
virtual ~handler(void) { my_free((char*) ref,MYF(MY_ALLOW_ZERO_PTR)); }
|
||||
virtual ~handler(void) {}
|
||||
int ha_open(const char *name, int mode, int test_if_locked);
|
||||
void update_timestamp(byte *record);
|
||||
void update_auto_increment();
|
||||
|
22
sql/lock.cc
22
sql/lock.cc
@ -407,15 +407,17 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
|
||||
TABLE *table;
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
uint key_length;
|
||||
key_length=(uint) (strmov(strmov(key,table_list->db)+1,table_list->name)-key)+
|
||||
1;
|
||||
DBUG_ENTER("lock_table_name");
|
||||
|
||||
key_length=(uint) (strmov(strmov(key,table_list->db)+1,table_list->name)
|
||||
-key)+ 1;
|
||||
|
||||
/* Only insert the table if we haven't insert it already */
|
||||
for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
|
||||
table ;
|
||||
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
|
||||
if (table->in_use == thd)
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
/* Create a table entry with the right key and with an old refresh version */
|
||||
/* Note that we must use my_malloc() here as this is freed by the table
|
||||
@ -423,17 +425,18 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
|
||||
|
||||
if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length,
|
||||
MYF(MY_WME | MY_ZEROFILL))))
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
memcpy((table->table_cache_key= (char*) (table+1)), key, key_length);
|
||||
table->key_length=key_length;
|
||||
table->in_use=thd;
|
||||
table->locked_by_name=1;
|
||||
table_list->table=table;
|
||||
|
||||
if (hash_insert(&open_cache, (byte*) table))
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
if (remove_table_from_cache(thd, table_list->db, table_list->name))
|
||||
return 1; // Table is in use
|
||||
return 0;
|
||||
DBUG_RETURN(1); // Table is in use
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
void unlock_table_name(THD *thd, TABLE_LIST *table_list)
|
||||
@ -446,7 +449,7 @@ static bool locked_named_table(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
for ( ; table_list ; table_list=table_list->next)
|
||||
{
|
||||
if (table_list->table && table_is_used(table_list->table))
|
||||
if (table_list->table && table_is_used(table_list->table,0))
|
||||
return 1;
|
||||
}
|
||||
return 0; // All tables are locked
|
||||
@ -456,6 +459,7 @@ static bool locked_named_table(THD *thd, TABLE_LIST *table_list)
|
||||
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
bool result=0;
|
||||
DBUG_ENTER("wait_for_locked_table_names");
|
||||
|
||||
while (locked_named_table(thd,table_list))
|
||||
{
|
||||
@ -467,5 +471,5 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
|
||||
wait_for_refresh(thd);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
}
|
||||
return result;
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
@ -225,7 +225,8 @@ static void mc_free_old_query(MYSQL *mysql)
|
||||
* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
|
||||
*****************************************************************************/
|
||||
|
||||
static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to)
|
||||
static int mc_sock_connect(my_socket s, const struct sockaddr *name,
|
||||
uint namelen, uint to)
|
||||
{
|
||||
#if defined(__WIN__)
|
||||
return connect(s, (struct sockaddr*) name, namelen);
|
||||
@ -451,7 +452,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
|
||||
uint port, const char *unix_socket,uint client_flag)
|
||||
{
|
||||
char buff[100],*end,*host_info;
|
||||
int sock;
|
||||
my_socket sock;
|
||||
ulong ip_addr;
|
||||
struct sockaddr_in sock_addr;
|
||||
uint pkt_length;
|
||||
|
@ -319,10 +319,11 @@ TABLE *open_table(THD *thd,const char *db,const char *table,const char *alias,
|
||||
TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
|
||||
bool reopen_table(TABLE *table,bool locked=0);
|
||||
bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
|
||||
void close_old_data_files(THD *thd, TABLE *table, bool abort_locks);
|
||||
void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
|
||||
bool send_refresh);
|
||||
bool close_data_tables(THD *thd,const char *db, const char *table_name);
|
||||
bool wait_for_tables(THD *thd);
|
||||
bool table_is_used(TABLE *table);
|
||||
bool table_is_used(TABLE *table, bool wait_for_name_lock);
|
||||
bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
|
||||
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
|
||||
Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables);
|
||||
|
@ -2407,6 +2407,12 @@ static void print_version(void)
|
||||
server_version,SYSTEM_TYPE,MACHINE_TYPE);
|
||||
}
|
||||
|
||||
static void use_help(void)
|
||||
{
|
||||
print_version();
|
||||
printf("Use %s --help for a list of available options\n",my_progname);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
print_version();
|
||||
@ -2621,7 +2627,7 @@ static void get_options(int argc,char **argv)
|
||||
case 'O':
|
||||
if (set_changeable_var(optarg, changeable_vars))
|
||||
{
|
||||
usage();
|
||||
use_help();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
@ -2666,7 +2672,8 @@ static void get_options(int argc,char **argv)
|
||||
opt_noacl=1;
|
||||
else
|
||||
{
|
||||
usage();
|
||||
fprintf(stderr,"%s: Unrecognized option: %s\n",my_progname,optarg);
|
||||
use_help();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
@ -2910,7 +2917,7 @@ static void get_options(int argc,char **argv)
|
||||
|
||||
default:
|
||||
fprintf(stderr,"%s: Unrecognized option: %c\n",my_progname,c);
|
||||
usage();
|
||||
use_help();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -2920,7 +2927,7 @@ static void get_options(int argc,char **argv)
|
||||
if (argc != optind)
|
||||
{
|
||||
fprintf(stderr,"%s: Too many parameters\n",my_progname);
|
||||
usage();
|
||||
use_help();
|
||||
exit(1);
|
||||
}
|
||||
fix_paths();
|
||||
|
@ -14,6 +14,16 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Fix that MAYBE_KEY are stored in the tree so that we can detect use
|
||||
of full hash keys for queries like:
|
||||
|
||||
select s.id, kws.keyword_id from sites as s,kws where s.id=kws.site_id and kws.keyword_id in (204,205);
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma implementation // gcc: Class implementation
|
||||
@ -557,7 +567,7 @@ SEL_ARG *SEL_ARG::clone_tree()
|
||||
** Returns:
|
||||
** -1 if impossible select
|
||||
** 0 if can't use quick_select
|
||||
** 1 if found usably range
|
||||
** 1 if found usable range
|
||||
** Updates the following in the select parameter:
|
||||
** needed_reg ; Bits for keys with may be used if all prev regs are read
|
||||
** quick ; Parameter to use when reading records.
|
||||
|
@ -582,9 +582,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
|
||||
thd->mysys_var->current_cond= &COND_refresh;
|
||||
thd->proc_info="Flushing tables";
|
||||
pthread_mutex_unlock(&thd->mysys_var->mutex);
|
||||
VOID(pthread_cond_broadcast(&COND_refresh)); // If one flush is locked
|
||||
|
||||
close_old_data_files(thd,thd->open_tables,1);
|
||||
close_old_data_files(thd,thd->open_tables,1,1);
|
||||
bool found=1;
|
||||
/* Wait until all threads has closed all the tables we had locked */
|
||||
DBUG_PRINT("info", ("Waiting for others threads to close their open tables"));
|
||||
@ -921,7 +920,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
|
||||
** There is a refresh in progress for this table
|
||||
** Wait until the table is freed or the thread is killed.
|
||||
*/
|
||||
close_old_data_files(thd,thd->open_tables,0);
|
||||
close_old_data_files(thd,thd->open_tables,0,0);
|
||||
if (table->in_use != thd)
|
||||
wait_for_refresh(thd);
|
||||
else
|
||||
@ -1216,9 +1215,11 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
|
||||
abort_locks is set if called from flush_tables.
|
||||
*/
|
||||
|
||||
void close_old_data_files(THD *thd, TABLE *table, bool abort_locks)
|
||||
void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
|
||||
bool send_refresh)
|
||||
{
|
||||
bool found=0;
|
||||
DBUG_ENTER("close_old_data_files");
|
||||
bool found=send_refresh;
|
||||
for (; table ; table=table->next)
|
||||
{
|
||||
if (table->version != refresh_version)
|
||||
@ -1241,6 +1242,7 @@ void close_old_data_files(THD *thd, TABLE *table, bool abort_locks)
|
||||
}
|
||||
if (found)
|
||||
VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -1250,17 +1252,19 @@ void close_old_data_files(THD *thd, TABLE *table, bool abort_locks)
|
||||
if the table is closed
|
||||
*/
|
||||
|
||||
bool table_is_used(TABLE *table)
|
||||
bool table_is_used(TABLE *table, bool wait_for_name_lock)
|
||||
{
|
||||
do
|
||||
{
|
||||
char *key= table->table_cache_key;
|
||||
uint key_length=table->key_length;
|
||||
for (TABLE *search=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
|
||||
for (TABLE *search=(TABLE*) hash_search(&open_cache,
|
||||
(byte*) key,key_length) ;
|
||||
search ;
|
||||
search = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
|
||||
{
|
||||
if (search->locked_by_flush ||
|
||||
search->locked_by_name && wait_for_name_lock ||
|
||||
search->db_stat && search->version < refresh_version)
|
||||
return 1; // Table is used
|
||||
}
|
||||
@ -1278,19 +1282,14 @@ bool wait_for_tables(THD *thd)
|
||||
|
||||
thd->proc_info="Waiting for tables";
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
while (!thd->killed)
|
||||
{
|
||||
thd->some_tables_deleted=0;
|
||||
close_old_data_files(thd,thd->open_tables,0);
|
||||
if (dropping_tables)
|
||||
{
|
||||
(void) pthread_cond_broadcast(&COND_refresh); // Signal to refresh/delete
|
||||
close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0);
|
||||
if (!table_is_used(thd->open_tables,1))
|
||||
break;
|
||||
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
|
||||
}
|
||||
|
||||
while (table_is_used(thd->open_tables) && ! thd->killed)
|
||||
{
|
||||
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
|
||||
}
|
||||
|
||||
if (thd->killed)
|
||||
result= 1; // aborted
|
||||
else
|
||||
|
@ -1170,9 +1170,8 @@ mysql_execute_command(void)
|
||||
#endif
|
||||
case SQLCOM_REPAIR:
|
||||
{
|
||||
if (!tables->db)
|
||||
tables->db=thd->db;
|
||||
if (check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
|
||||
if (check_db_used(thd,tables) ||
|
||||
check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
|
||||
goto error; /* purecov: inspected */
|
||||
res = mysql_repair_table(thd, tables, &lex->check_opt);
|
||||
break;
|
||||
@ -1695,6 +1694,10 @@ error:
|
||||
** Get the user (global) and database privileges for all used tables
|
||||
** Returns true (error) if we can't get the privileges and we don't use
|
||||
** table/column grants.
|
||||
** The idea of EXTRA_ACL is that one will be granted access to the table if
|
||||
** one has the asked privilege on any column combination of the table; For
|
||||
** example to be able to check a table one needs to have SELECT privilege on
|
||||
** any column of the table.
|
||||
****************************************************************************/
|
||||
|
||||
bool
|
||||
@ -1760,7 +1763,8 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
|
||||
TABLE_LIST *org_tables=tables;
|
||||
for (; tables ; tables=tables->next)
|
||||
{
|
||||
if ((thd->master_access & want_access) == want_access && thd->db)
|
||||
if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
|
||||
thd->db)
|
||||
tables->grant.privilege= want_access;
|
||||
else if (tables->db && tables->db == thd->db)
|
||||
{
|
||||
|
@ -800,6 +800,14 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
if ((s->on_expr=tables->on_expr))
|
||||
{
|
||||
// table->maybe_null=table->outer_join=1; // Mark for send fields
|
||||
if (!table->file->records)
|
||||
{ // Empty table
|
||||
s->key_dependent=s->dependent=0;
|
||||
s->type=JT_SYSTEM;
|
||||
const_table_map|=table->map;
|
||||
set_position(join,const_count++,s,(KEYUSE*) 0);
|
||||
continue;
|
||||
}
|
||||
s->key_dependent=s->dependent=
|
||||
s->on_expr->used_tables() & ~(table->map);
|
||||
s->dependent|=stat_vector[i-1]->dependent | table_vector[i-1]->map;
|
||||
|
@ -91,6 +91,7 @@ struct st_table {
|
||||
my_bool crypted;
|
||||
my_bool db_low_byte_first; /* Portable row format */
|
||||
my_bool locked_by_flush;
|
||||
my_bool locked_by_name;
|
||||
Field *next_number_field, /* Set if next_number is activated */
|
||||
*found_next_number_field, /* Set on open */
|
||||
*rowid_field;
|
||||
|
220
tests/drop_test.pl
Executable file
220
tests/drop_test.pl
Executable file
@ -0,0 +1,220 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# This is a test with uses processes to insert, select and drop tables.
|
||||
#
|
||||
|
||||
$opt_loop_count=100000; # Change this to make test harder/easier
|
||||
|
||||
##################### Standard benchmark inits ##############################
|
||||
|
||||
use DBI;
|
||||
use Getopt::Long;
|
||||
use Benchmark;
|
||||
|
||||
package main;
|
||||
|
||||
$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert=
|
||||
$opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0;
|
||||
$opt_host=""; $opt_db="test";
|
||||
|
||||
GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in","skip-delete",
|
||||
"verbose","fast-insert","lock-tables","debug","fast","force") || die "Aborted";
|
||||
$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these
|
||||
|
||||
print "Testing 5 multiple connections to a server with 1 insert, 2 drop/rename\n";
|
||||
print "1 select and 1 flush thread\n";
|
||||
|
||||
$firsttable = "bench_f1";
|
||||
|
||||
####
|
||||
#### Start timeing and start test
|
||||
####
|
||||
|
||||
$start_time=new Benchmark;
|
||||
if (!$opt_skip_create)
|
||||
{
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
$dbh->do("drop table if exists $firsttable, ${firsttable}_1, ${firsttable}_2");
|
||||
|
||||
print "Creating table $firsttable in database $opt_db\n";
|
||||
$dbh->do("create table $firsttable (id int(6) not null, info varchar(32), marker char(1), primary key(id))") || die $DBI::errstr;
|
||||
$dbh->disconnect; $dbh=0; # Close handler
|
||||
}
|
||||
$|= 1; # Autoflush
|
||||
|
||||
####
|
||||
#### Start the tests
|
||||
####
|
||||
|
||||
test_insert() if (($pid=fork()) == 0); $work{$pid}="insert";
|
||||
test_drop(1) if (($pid=fork()) == 0); $work{$pid}="drop 1";
|
||||
test_drop(2) if (($pid=fork()) == 0); $work{$pid}="drop 2";
|
||||
test_select() if (($pid=fork()) == 0); $work{$pid}="select";
|
||||
test_flush() if (($pid=fork()) == 0); $work{$pid}="flush";
|
||||
|
||||
$errors=0;
|
||||
while (($pid=wait()) != -1)
|
||||
{
|
||||
$ret=$?/256;
|
||||
print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
|
||||
$errors++ if ($ret != 0);
|
||||
}
|
||||
|
||||
if (!$opt_skip_delete && !$errors)
|
||||
{
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
$dbh->do("drop table $firsttable");
|
||||
$dbh->disconnect; $dbh=0; # Close handler
|
||||
}
|
||||
print ($errors ? "Test failed\n" :"Test ok\n");
|
||||
|
||||
$end_time=new Benchmark;
|
||||
print "Total time: " .
|
||||
timestr(timediff($end_time, $start_time),"noc") . "\n";
|
||||
|
||||
exit(0);
|
||||
|
||||
#
|
||||
# Insert records in the table
|
||||
#
|
||||
|
||||
sub test_insert
|
||||
{
|
||||
my ($dbh,$i);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
for ($i=0 ; $i < $opt_loop_count; $i++)
|
||||
{
|
||||
if (!$dbh->do("insert into $firsttable values ($i,'This is entry $i','')"))
|
||||
{
|
||||
print "Warning; Got error on insert: " . $dbh->errstr . "\n" if (! ($dbh->errstr =~ /doesn't exist/));
|
||||
}
|
||||
}
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_insert: Inserted $i rows\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
sub test_drop
|
||||
{
|
||||
my ($id) = @_;
|
||||
my ($dbh,$i,$sth,$error_counter,$sleep_time);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
$error_counter=0;
|
||||
$sleep_time=2;
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
sleep($sleep_time);
|
||||
# Check if insert thread is ready
|
||||
$sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on select from $firsttable: $dbh->errstr\n";
|
||||
if (!$sth->execute || !(@row = $sth->fetchrow_array()) ||
|
||||
!$row[0])
|
||||
{
|
||||
$sth->finish;
|
||||
$sleep_time=1;
|
||||
last if ($error_counter++ == 5);
|
||||
next;
|
||||
}
|
||||
$sleep_time=2;
|
||||
$sth->finish;
|
||||
|
||||
# Change to use a new table
|
||||
$dbh->do("create table ${firsttable}_$id (id int(6) not null, info varchar(32), marker char(1), primary key(id))") || die $DBI::errstr;
|
||||
$dbh->do("drop table if exists $firsttable") || die "Got error on drop table: $dbh->errstr\n";
|
||||
if (!$dbh->do("alter table ${firsttable}_$id rename to $firsttable"))
|
||||
{
|
||||
print "Warning; Got error from alter table: " . $dbh->errstr . "\n" if (! ($dbh->errstr =~ /already exist/));
|
||||
$dbh->do("drop table if exists ${firsttable}_$id") || die "Got error on drop table: $dbh->errstr\n";
|
||||
}
|
||||
}
|
||||
$dbh->do("drop table if exists $firsttable,${firsttable}_$id") || die "Got error on drop table: $dbh->errstr\n";
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_drop: Did a drop $i times\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# select records
|
||||
#
|
||||
|
||||
sub test_select
|
||||
{
|
||||
my ($dbh,$i,$sth,@row,$error_counter,$sleep_time);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
|
||||
$error_counter=0;
|
||||
$sleep_time=3;
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
sleep($sleep_time);
|
||||
$sth=$dbh->prepare("select sum(t.id) from $firsttable as t,$firsttable as t2") || die "Got error on select: $dbh->errstr;\n";
|
||||
if ($sth->execute)
|
||||
{
|
||||
@row = $sth->fetchrow_array();
|
||||
$sth->finish;
|
||||
$sleep_time=3;
|
||||
}
|
||||
else
|
||||
{
|
||||
print "Warning; Got error from select: " . $dbh->errstr . "\n" if (! ($dbh->errstr =~ /doesn't exist/));
|
||||
$sth->finish;
|
||||
last if ($error_counter++ == 5);
|
||||
$sleep_time=1;
|
||||
}
|
||||
}
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_select: ok\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#
|
||||
# flush records
|
||||
#
|
||||
|
||||
sub test_flush
|
||||
{
|
||||
my ($dbh,$i,$sth,@row,$error_counter,$sleep_time);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
|
||||
$error_counter=0;
|
||||
$sleep_time=5;
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
sleep($sleep_time);
|
||||
$sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on prepar: $dbh->errstr;\n";
|
||||
if ($sth->execute)
|
||||
{
|
||||
@row = $sth->fetchrow_array();
|
||||
$sth->finish;
|
||||
$sleep_time=5;
|
||||
$dbh->do("flush tables $firsttable") || die "Got error on flush table: " . $dbh->errstr . "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print "Warning; Got error from select: " . $dbh->errstr . "\n" if (! ($dbh->errstr =~ /doesn't exist/));
|
||||
$sth->finish;
|
||||
last if ($error_counter++ == 5);
|
||||
$sleep_time=1;
|
||||
}
|
||||
}
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_select: ok\n";
|
||||
exit(0);
|
||||
}
|
@ -67,7 +67,7 @@ $errors=0;
|
||||
while (($pid=wait()) != -1)
|
||||
{
|
||||
$ret=$?/256;
|
||||
print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
|
||||
print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
|
||||
$errors++ if ($ret != 0);
|
||||
}
|
||||
|
||||
|
204
tests/rename_test.pl
Executable file
204
tests/rename_test.pl
Executable file
@ -0,0 +1,204 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# This is a test with uses processes to insert, select and drop tables.
|
||||
#
|
||||
|
||||
$opt_loop_count=100000; # Change this to make test harder/easier
|
||||
|
||||
##################### Standard benchmark inits ##############################
|
||||
|
||||
use DBI;
|
||||
use Getopt::Long;
|
||||
use Benchmark;
|
||||
|
||||
package main;
|
||||
|
||||
$opt_skip_create=$opt_skip_delete=$opt_skip_flush=0;
|
||||
$opt_host=""; $opt_db="test";
|
||||
|
||||
GetOptions("host=s","db=s","loop-count=i","skip-create","skip-delete",
|
||||
"skip-flush") || die "Aborted";
|
||||
|
||||
print "Testing 5 multiple connections to a server with 1 insert, 1 rename\n";
|
||||
print "1 select and 1 flush thread\n";
|
||||
|
||||
$firsttable = "bench_f1";
|
||||
|
||||
####
|
||||
#### Start timing and start test
|
||||
####
|
||||
|
||||
$start_time=new Benchmark;
|
||||
if (!$opt_skip_create)
|
||||
{
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
$dbh->do("drop table if exists $firsttable, ${firsttable}_1, ${firsttable}_2");
|
||||
|
||||
print "Creating table $firsttable in database $opt_db\n";
|
||||
$dbh->do("create table $firsttable (id int(6) not null, info varchar(32), marker char(1), primary key(id))") || die $DBI::errstr;
|
||||
$dbh->disconnect; $dbh=0; # Close handler
|
||||
}
|
||||
$|= 1; # Autoflush
|
||||
|
||||
####
|
||||
#### Start the tests
|
||||
####
|
||||
|
||||
test_insert() if (($pid=fork()) == 0); $work{$pid}="insert";
|
||||
test_rename(1) if (($pid=fork()) == 0); $work{$pid}="rename 1";
|
||||
test_rename(2) if (($pid=fork()) == 0); $work{$pid}="rename 2";
|
||||
test_select() if (($pid=fork()) == 0); $work{$pid}="select";
|
||||
if (!$opt_skip_flush)
|
||||
{
|
||||
test_flush() if (($pid=fork()) == 0); $work{$pid}="flush";
|
||||
}
|
||||
$errors=0;
|
||||
while (($pid=wait()) != -1)
|
||||
{
|
||||
$ret=$?/256;
|
||||
print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
|
||||
$errors++ if ($ret != 0);
|
||||
}
|
||||
|
||||
if (!$opt_skip_delete && !$errors)
|
||||
{
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
$dbh->do("drop table $firsttable");
|
||||
$dbh->disconnect; $dbh=0; # Close handler
|
||||
}
|
||||
print ($errors ? "Test failed\n" :"Test ok\n");
|
||||
|
||||
$end_time=new Benchmark;
|
||||
print "Total time: " .
|
||||
timestr(timediff($end_time, $start_time),"noc") . "\n";
|
||||
|
||||
exit(0);
|
||||
|
||||
#
|
||||
# Insert records in the table. Delete table when test is finnished
|
||||
#
|
||||
|
||||
sub test_insert
|
||||
{
|
||||
my ($dbh,$i,$error);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
for ($i=0 ; $i < $opt_loop_count; $i++)
|
||||
{
|
||||
if (!$dbh->do("insert into $firsttable values ($i,'This is entry $i','')"))
|
||||
{
|
||||
$error=$dbh->errstr;
|
||||
$dbh->do("drop table ${firsttable}"); # End other threads
|
||||
die "Warning; Got error on insert: " . $error . "\n";
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
$dbh->do("drop table ${firsttable}") || die "Got error on drop table: " . $dbh->errstr . "\n";
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_insert: Inserted $i rows\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
sub test_rename
|
||||
{
|
||||
my ($id) = @_;
|
||||
my ($dbh,$i,$error_counter,$sleep_time);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
$error_counter=0;
|
||||
$sleep_time=2;
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
sleep($sleep_time);
|
||||
$dbh->do("create table ${firsttable}_$id (id int(6) not null, info varchar(32), marker char(1), primary key(id))") || die $DBI::errstr;
|
||||
if (!$dbh->do("rename table $firsttable to ${firsttable}_${id}_1, ${firsttable}_$id to ${firsttable}"))
|
||||
{
|
||||
last if ($dbh->errstr =~ /^Can\'t find/);
|
||||
die "Got error on rename: " . $dbh->errstr . "\n";
|
||||
}
|
||||
$dbh->do("drop table ${firsttable}_${id}_1") || die "Got error on drop table: " . $dbh->errstr . "\n";
|
||||
}
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_drop: Did a drop $i times\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# select records
|
||||
#
|
||||
|
||||
sub test_select
|
||||
{
|
||||
my ($dbh,$i,$sth,@row,$sleep_time);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
|
||||
$sleep_time=3;
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
sleep($sleep_time);
|
||||
$sth=$dbh->prepare("select sum(t.id) from $firsttable as t,$firsttable as t2") || die "Got error on select: $dbh->errstr;\n";
|
||||
if ($sth->execute)
|
||||
{
|
||||
@row = $sth->fetchrow_array();
|
||||
$sth->finish;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sth->finish;
|
||||
last if (! ($dbh->errstr =~ /doesn\'t exist/));
|
||||
die "Got error on select: " . $dbh->errstr . "\n";
|
||||
}
|
||||
}
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_select: ok\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#
|
||||
# flush records
|
||||
#
|
||||
|
||||
sub test_flush
|
||||
{
|
||||
my ($dbh,$i,$sth,@row,$error_counter,$sleep_time);
|
||||
|
||||
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
|
||||
$opt_user, $opt_password,
|
||||
{ PrintError => 0}) || die $DBI::errstr;
|
||||
|
||||
$error_counter=0;
|
||||
$sleep_time=5;
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
sleep($sleep_time);
|
||||
$sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on prepar: $dbh->errstr;\n";
|
||||
if ($sth->execute)
|
||||
{
|
||||
@row = $sth->fetchrow_array();
|
||||
$sth->finish;
|
||||
$sleep_time=5;
|
||||
$dbh->do("flush tables $firsttable") || die "Got error on flush table: " . $dbh->errstr . "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
last if (! ($dbh->errstr =~ /doesn\'t exist/));
|
||||
die "Got error on flush: " . $dbh->errstr . "\n";
|
||||
}
|
||||
}
|
||||
$dbh->disconnect; $dbh=0;
|
||||
print "Test_select: ok\n";
|
||||
exit(0);
|
||||
}
|
Reference in New Issue
Block a user