Commit 1776fbac authored by unknown's avatar unknown

Fixed bug in ALTER TABLE

Removed _mi_rkey() function
New fork_big.pl multi-thread test


BitKeeper/deleted/.del-fork3_test.pl~c4a7bffb4f8e813c:
  Delete: tests/fork3_test.pl
BitKeeper/deleted/.del-fork_test.pl~3d3535329ed8cd5e:
  Delete: tests/fork_test.pl
Docs/manual.texi:
  Changelog.
  Updated support information
client/mysqladmin.c:
  Removed not used --timeout option
configure.in:
  Update version
myisam/mi_extra.c:
  Fixed bug in ALTER TABLE
myisam/mi_rkey.c:
  Removed _mi_rkey() function
myisam/myisamdef.h:
  Removed _mi_rkey() function
myisammrg/myrg_rkey.c:
  Removed _mi_rkey() function
myisammrg/myrg_rnext.c:
  Removed _mi_rkey() function
mysql-test/t/alter_table.test:
  Added test case for ALTER TABLE bug
sql/derror.cc:
  Moved shutdown message to clean_up
sql/mysql_priv.h:
  Moved shutdown message to clean_up
sql/sql_class.cc:
  Fixed bug in MySQL compiled with transactions but using --skip-"table-handler"
sql/sql_show.cc:
  Use time_after_lock for time of query when debugging
sql/sql_test.cc:
  Check memory overruns when using 'mysqladmin debug'
strings/ctype-tis620.c:
  F
parent 05f08c18
......@@ -528,10 +528,10 @@ GEMINI Tables
INNOBASE Tables
* INNOBASE overview::
* INNOBASE overview:: INNOBASE overview
* INNOBASE start:: INNOBASE startup options
* Using INNOBASE tables:: Using INNOBASE tables
* INNOBASE restrictions:: Some restrictions on @code{INNOBASE} tables:
* INNOBASE restrictions:: Some restrictions on @code{INNOBASE} tables
MySQL Tutorial
......@@ -899,7 +899,7 @@ Changes in release 4.0.x (Development; Alpha)
Changes in release 3.23.x (Stable)
* News-3.23.37::
* News-3.23.37:: Changes in release 3.23.37
* News-3.23.36:: Changes in release 3.23.36
* News-3.23.35:: Changes in release 3.23.35
* News-3.23.34a:: Changes in release 3.23.34a
......@@ -3873,6 +3873,29 @@ please send e-mail to @email{webmaster@@mysql.com}.
* Table handler support:: Support for other table handlers
@end menu
The following holds for all support options.
@itemize @bullet
@item
The support is per year.
@item
Fixing or provide reasonable workarounds for any repeatable bug.
@item
A reasonable effort to find and fix any other MySQL related bug.
@item
The following doesn't hold for Basic email support (As this only includes
basic installation support):
For not bug related things, like helping you optimize your queries or
your system, extending MySQL with new functionality... we charge 200
EURO/hour, which is deducted from your support contract. In other words,
if you have login support (2000 EURO), you can expect us to work up to
10 hours to help you with things like this.
@item
The higher level of support contract the more effort we will put into finding
a solution to your problems..
@end itemize
@cindex email, technical support
@cindex technical support, by email
@node Basic email support, Extended email support, Support, Support
......@@ -4635,12 +4658,6 @@ Please report bad or out-of-date mirrors to @email{webmaster@@mysql.com}.
@c @image{Flags/usa} USA [Savages/Oregon] @
@c @uref{http://mysql.savages.com, WWW}
@c @item
@c No mirror! 010323 Matt
@c EMAIL: tcobb@staff.circle.net (Troy Cobb)
@c @image{Flags/usa} USA [Circle Net/North Carolina] @
@c @uref{http://www.mysql.net, WWW}
@c @item
@c Not ok 20000919; Non-existent (Matt)
@c EMAIL: paul@gina.net (Paul Vining)
......@@ -7172,13 +7189,10 @@ Linux version that doesn't have @code{glibc2}, you must install
LinuxThreads before trying to compile
@strong{MySQL}. @uref{http://www.mysql.com/Downloads/Linux}
Note that @code{glibc} versions before and including Version 2.1.1 have a fatal
bug in @code{pthread_mutex_timedwait} handling, which is used when you
do @code{INSERT DELAYED}. If you are using @code{INSERT DELAYED}, you
@strong{MUST} add the following patch to your glibc library:
@uref{http://www.mysql.com/Downloads/Patches/glibc-pthread_cond_timedwait.patch}.
@strong{MySQL} Versions 3.23.7 and 3.22.32 contain a temporary
workaround for this bug.
Note that @code{glibc} versions before and including Version 2.1.1 have
a fatal bug in @code{pthread_mutex_timedwait} handling, which is used
when you do @code{INSERT DELAYED}. We recommend you to not use
@code{INSERT DELAYED} before upgrading glibc.
If you plan to have 1000+ concurrent connections, you will need to make
some changes to LinuxThreads, recompile it, and relink MySQL against
......@@ -7216,8 +7230,7 @@ tables with lots of data. The more you reduce @code{STACK_SIZE} in
LinuxThreads the more threads you can safely create. We recommend the values
between 128K and 256 K.
If you use a lot of concurrent connections, you may suffer from a 2.2
If you use a lot of concurrent connections, you may suffer from a 2.2
kernel "feature" in 2.2 kernel that penalizes a process for
forking or cloning a child
in an attempt to prevent a fork bomb attack. This will cause MySQL not
......@@ -7239,7 +7252,7 @@ on several systems of one of our biggest customers. The patch has signficantly
improved @code{MySQL} performance without causing any problems. So it should
be pretty safe. This issue has been fixed in the 2.4 kernel.
We have also tested @strong{MySQL} on 2.4 kernel on a 2 CPU machine and
We have also tested @strong{MySQL} on 2.4 kernel on a 2 CPU machine and
found @strong{MySQL} scales MUCH better - there was virtually no slowdown
on query throughput all the way up
to 1000 clients. If your plan to set up a
......@@ -7250,31 +7263,33 @@ systems. If you have access such a system and have done some benchmarks,
please send a mail to @email{docs@@mysql.com} with the results - we will
include them in the manual.
The following paragraph is only relevant if you are using a glibc
version older than 2.2.2 (Note that if you are going to use MANY
connections to MySQL, you still need to change the STACK_SIZE and
PTHREAD_THREADS_MAX variables in glibc 2.2.2).
There is another issue that greatly hurts @strong{MySQL} performance,
especially on SMP systems. The current implementation of mutex in Linuxthreads is also very bad for
programs with many threads that only hold the mutex for a short time. On an
SMP system, ironic as it is, if you link @strong{MySQL} against unmodified
@strong{LinuxThreads}, removing processors from the machine improves
@strong{MySQL} performance in many cases.
We have made a patch available for glibc 2.1,
especially on SMP systems. The old implementation of mutex in
LinuxThreads was also very bad for programs with many threads that only
hold the mutex for a short time. On an SMP system, ironic as it is, if
you link @strong{MySQL} against unmodified @strong{LinuxThreads},
removing processors from the machine improves @strong{MySQL} performance
in many cases. We have made a patch available for glibc 2.1,
@uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.1-patch,linuxthreads-2.1-patch}
and for glibc 2.2,
@uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.2-patch,linuxthreads-2.2-patch} to correct this behaviour. Please note that since there are so
many versions of glibc floating around, the patch may not apply cleanly to
@uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.2-patch,linuxthreads-2.2-patch}
to correct this behaveour. Please note that since there are so many
versions of glibc floating around, the patch may not apply cleanly to
yours, so some manual work may be required.
We recommend that you use the above patched to build a special static version
of @code{libpthread.a} and use it only for statically linking
against @code{MySQL}. We
know that the patch is safe for @code{MySQL} and significantly improves its
performance, but we cannot say anything about other applications. If you
link other applications against the patched version of the library, or
build a patched shared version and install it on your system, you are doing
it at your own risk with regard to other applicatioins that depend on
@code{LinuxThreads}.
@c Monty, is the stuff below any longer relevant? I know it needs to be
@c at least corrected as RPM and binary are now the same
We recommend that you use the above patches to build a special static
version of @code{libpthread.a} and use it only for statically linking
against @code{MySQL}. We know that the patch is safe for @code{MySQL}
and significantly improves its performance, but we cannot say anything
about other applications. If you link other applications against the
patched version of the library, or build a patched shared version and
install it on your system, you are doing it at your own risk with regard
to other applications that depend on @code{LinuxThreads}.
If you can't start @code{mysqld} or if @code{mysql_install_db} doesn't work,
please continue reading! This only happens on Linux system with problems in
......@@ -9792,6 +9807,11 @@ Set the default character set. @xref{Character sets}.
@item --default-table-type=type
Set the default table type for tables. @xref{Table types}.
@item --debug[...]=
If @strong{MySQL} is configured with @code{--with-debug}, you can use
this option to get a trace file of what @code{mysqld} is
doing. @xref{The DBUG package}.
@item --delay-key-write-for-all-tables
Don't flush key buffers between writes for any @code{MyISAM} table.
@xref{Server parameters}.
......@@ -9946,14 +9966,23 @@ All interaction with @code{mysqld} must be made via Unix sockets.
This option is highly recommended for systems where only local requests
are allowed. @xref{DNS}.
@item --skip-host-cache
Never use host name cache for faster name-ip resolution, but query
DNS server on every connect instead. @xref{DNS}.
@item --skip-new
Don't use new, possible wrong routines.
Implies @code{--skip-delay-key-write}.
This will also set default table type to @code{ISAM}. @xref{ISAM}.
@item --skip-host-cache
Never use host name cache for faster name-ip resolution, but query
DNS server on every connect instead. @xref{DNS}.
@item --skip-safemalloc
If @strong{MySQL} is configured with @code{--with-debug=full}, all
programs will check the memory for overruns for every memory allocation /
memory freeing. As this checking is very slow, you can avoid this,
when you don't need memory checking, by using this option.
this option to get a trace file of what @code{mysqld} is
doing. @xref{The DBUG package}.
@item --skip-show-database
Don't allow 'SHOW DATABASE' commands, unless the user has
......@@ -10291,6 +10320,9 @@ Version 3.23:
@itemize @bullet
@item
All tables that uses the @code{tis620} character set must be fixed
with @code{myisamchk -r} or @code{REPAIR TABLE}.
@item
If you do a @code{DROP DATABASE} on a symbolic linked database, both the
link and the original database is deleted. (This didn't happen in 3.22
because configure didn't detect the @code{readlink} system call).
......@@ -12377,9 +12409,12 @@ You can use the wild-card characters @samp{%} and @samp{_} in the @code{Host}
field.
@item
A @code{Host} value of @code{'%'} matches any hostname. A blank @code{Host}
value is equivalent to @code{'%'}. Note that these values match @emph{any
host that can create a connection to your server!}
A @code{Host} value of @code{'%'} matches any hostname.
@item
A blank @code{Host} value means that the privilege should be anded
with the entry in the @code{host} table that matches the given host name.
You can find more information about this in the next chapter.
@cindex netmask notation, in @code{mysql.user} table
@item
......@@ -18304,7 +18339,7 @@ or MIN_ROWS = #
or PACK_KEYS = @{0 | 1@}
or PASSWORD = "string"
or DELAY_KEY_WRITE = @{0 | 1@}
or ROW_FORMAT= @{ default | dynamic | static | compressed @}
or ROW_FORMAT= @{ default | dynamic | fixed | compressed @}
or RAID_TYPE= @{1 | STRIPED | RAID0 @} RAID_CHUNKS=# RAID_CHUNKSIZE=#
or UNION = (table_name,[table_name...])
......@@ -21489,6 +21524,20 @@ The buffer that is allocated when sorting the index when doing a
@code{REPAIR} or when creating indexes with @code{CREATE INDEX} or
@code{ALTER TABLE}.
@item @code{myisam_max_extra_sort_file_size}.
If the creating of the temporary file for fast index creation would be
this much bigger than using the key cache, then prefer the key cache
method. This is mainly used to force long character keys in large
tables to use the slower key cache method to create the index.
@strong{NOTE} that this parameter is given in megabytes!
@item @code{myisam_max_sort_file_size}
The maximum size of the temporary file @strong{MySQL} is allowed to create
to while recreating the index (during @code{REPAIR}, @code{ALTER TABLE}
or @code{LOAD DATA INFILE}. If the file size would be bigger than this,
the index will be created through the key cache (which is slower).
@strong{NOTE} that this parameter is given in megabytes!
@item @code{net_buffer_length}
The communication buffer is reset to this size between queries. This
should not normally be changed, but if you have very little memory, you
......@@ -23083,13 +23132,16 @@ system resources than @code{ISAM}, but will need more CPU when inserting
data into a compressed index.
The following options to @code{mysqld} can be used to change the behavior of
@code{MyISAM} tables:
@code{MyISAM} tables. @xref{SHOW VARIABLES}.
@multitable @columnfractions .40 .60
@item @strong{Option} @tab @strong{Meaning}
@item @code{--myisam-recover=#} @tab Automatic recover of crashed tables.
@item @code{-O myisam_sort_buffer_size=#} @tab Buffer used when recovering tables.
@item @code{--delay-key-write-for-all-tables} @tab Don't flush key buffers between writes for any MyISAM table
@item @code{-O myisam_max_extra_sort_file_size=#} @tab Used to help @strong{MySQL} to decide when to use the slow but safe key cache index create method. @strong{NOTE} that this parameter is given in megabytes!
@item @code{-O myisam_max_sort_file_size=#} @tab Don't use the fast sort index method to created index if the temporary file would get bigger than this.
@strong{NOTE} that this paramter is given in megabytes!
@end multitable
The automatic recovery is activated if you start mysqld with
......@@ -34084,7 +34136,7 @@ this problem.
@itemize @bullet
@item
You can use the static @strong{MySQL} libraries for Borland C++ that you
can find on @uref{http://www.mysql.net/downloads/os-win32.html}.
can find on @uref{http://www.mysql.com/downloads/os-win32.html}.
@item
Only call @code{mysql_init()} with @code{NULL} as an argument, not a
pre-allocated MYSQL struct.
......@@ -42427,7 +42479,19 @@ not yet 100 % confident in this code.
Fixed bug in @code{ALTER TABLE} and @code{LOAD DATA INFILE} that disabled
key-sorting. These command should now be faster in most cases.
@item
Fixed problem with @code{ALTER TABLE} to Innobase tables on Freebsd.
@item
Added @code{mysqld} variables @code{myisam_max_sort_file_size} and
@code{myisam_max_extra_sort_file_size}.
@item
Initialize signals early to avoid problem with signals in Innobase..
@item
Applied patch for the @code{tis620} character set to make comparisons
case-independent and to fix a bug in @code{LIKE} for this character set.
@strong{NOTE}: All tables that uses the @code{tis620} character set must be
fixed with @code{myisamchk -r} or @code{REPAIR TABLE} !
@item
Added @code{--skip-safemalloc} option to @code{mysqld}.
@end itemize
@node News-3.23.36, News-3.23.35, News-3.23.37, News-3.23.x
......@@ -48417,6 +48481,11 @@ file of what the program is debugging.
One uses the debug package by invoking the program with the
@code{--debug="..."} or the @code{-#...} option.
Most @strong{MySQL} programs has a default debug string that will be
used if you don't specify an option to @code{--debug}. The default
trace file is usually @code{/tmp/programname.trace} on Unix and
@code{\programname.trace} on windows.
The debug control string is a sequence of colon separated fields
as follows:
......@@ -28,7 +28,7 @@
#include <my_pthread.h> /* because of signal() */
#endif
#define ADMIN_VERSION "8.18"
#define ADMIN_VERSION "8.19"
#define MAX_MYSQL_VAR 64
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
#define MAX_TRUNC_LENGTH 3
......@@ -817,8 +817,6 @@ static void usage(void)
-s, --silent Silently exit if one can't connect to server\n\
-S, --socket=... Socket file to use for connection\n");
#include "sslopt-usage.h"
printf("\
-t, --timeout=... Timeout for connection to the mysqld server\n");
#ifndef DONT_ALLOW_USER_CHANGE
printf("\
-u, --user=# User for login if not current user\n");
......
......@@ -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, 3.23.36)
AM_INIT_AUTOMAKE(mysql, 3.23.37)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
......@@ -660,6 +660,7 @@ int main()
#
MAX_C_OPTIMIZE="-O6"
case $SYSTEM_TYPE in
*solaris2.7*)
# Solaris 2.7 has a broken /usr/include/widec.h
......
......@@ -319,6 +319,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
{
my_free(info->rec_alloc,MYF(MY_ALLOW_ZERO_PTR));
info->rec_alloc=info->rec_buff=0;
mi_fix_rec_buff_for_blob(info,info->s->base.pack_reclength);
}
break;
case HA_EXTRA_NORMAL: /* Theese isn't in use */
......
......@@ -22,8 +22,8 @@
/* Read a record using key */
/* Ordinary search_flag is 0 ; Give error if no record with key */
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)
int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
enum ha_rkey_function search_flag)
{
uchar *key_buff;
MYISAM_SHARE *share=info->s;
......@@ -37,7 +37,7 @@ int _mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
if (raw_key)
if (!info->use_packed_key)
{
if (key_len == 0)
key_len=USE_WHOLE_KEY;
......@@ -101,11 +101,3 @@ int _mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
err:
DBUG_RETURN(my_errno);
} /* _mi_rkey */
/* shouldn't forget to do it inline sometime */
int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
enum ha_rkey_function search_flag)
{
return _mi_rkey(info,buf,inx,key,key_len,search_flag,TRUE);
}
......@@ -258,6 +258,7 @@ struct st_myisam_info {
my_bool quick_mode;
my_bool page_changed; /* If info->buff can't be used for rnext */
my_bool buff_used; /* If info->buff has to be reread for rnext */
my_bool use_packed_key; /* For MYISAMMRG */
myf lock_wait; /* is 0 or MY_DONT_WAIT */
int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
LIST open_list;
......@@ -630,8 +631,6 @@ void mi_update_status(void* param);
void mi_copy_status(void* to,void *from);
my_bool mi_check_status(void* param);
void mi_disable_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);
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share);
......
......@@ -63,7 +63,9 @@ int myrg_rkey(MYRG_INFO *info,byte *record,int inx, const byte *key,
}
else
{
err=_mi_rkey(mi,buf,inx,key_buff,pack_key_length,search_flag,FALSE);
mi->use_packed_key=1;
err=mi_rkey(mi,buf,inx,key_buff,pack_key_length,search_flag);
mi->use_packed_key=0;
}
info->last_used_table=table+1;
......
......@@ -68,8 +68,10 @@ int _myrg_finish_scan(MYRG_INFO *info, int inx, enum ha_rkey_function type)
for (; table < info->end_table ; table++)
{
mi=table->table;
if ((err=_mi_rkey(mi,NULL,inx,key_buff,pack_key_length,
type,FALSE)))
mi->use_packed_key=1;
err=mi_rkey(mi,NULL,inx,key_buff,pack_key_length,type);
mi->use_packed_key=0;
if (err)
{
if (err == HA_ERR_KEY_NOT_FOUND) /* If end of file */
continue;
......
......@@ -57,13 +57,17 @@ CREATE TABLE t1 (
PRIMARY KEY (id)
) TYPE=MyISAM;
ALTER TABLE
t1
ORDER BY
t1.id,
t1.status,
t1.type_id,
t1.user_id,
t1.body;
ALTER TABLE t1 ORDER BY t1.id, t1.status, t1.type_id, t1.user_id, t1.body;
DROP TABLE t1;
drop table t1;
#
# The following combination found a hang-bug in MyISAM
#
CREATE TABLE t1 (AnamneseId int(10) unsigned NOT NULL auto_increment,B BLOB,PRIMARY KEY (AnamneseId)) type=myisam;
insert into t1 values (null,"hello");
LOCK TABLES t1 WRITE;
ALTER TABLE t1 ADD Column new_col int not null;
UNLOCK TABLES;
OPTIMIZE TABLE t1;
DROP TABLE t1;
......@@ -72,7 +72,7 @@ static void read_texts(const char *file_name,const char ***point,
Check that the above file is the right version for this program!\n\n",
my_progname,name,ant,error_messages);
VOID(my_close(file,MYF(MY_WME)));
clean_up(); /* Clean_up frees everything */
clean_up(0); /* Clean_up frees everything */
exit(1); /* We can't continue */
}
......@@ -115,7 +115,7 @@ err:
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
fprintf(stderr,buff,my_progname,name);
clean_up(); /* Clean_up frees everything */
clean_up(0); /* Clean_up frees everything */
exit(1); /* We can't continue */
} /* read_texts */
......
......@@ -611,7 +611,7 @@ uint calc_week(TIME *ltime, bool with_year, bool sunday_first_day_of_week,
void find_date(char *pos,uint *vek,uint flag);
TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
TYPELIB *typelib(List<String> &strings);
void clean_up(void);
void clean_up(bool print_message=1);
ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
......
......@@ -136,9 +136,9 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
(hash_get_key) get_var_key,
(void (*)(void*)) free_var,0);
#ifdef USING_TRANSACTIONS
bzero((char*) &transaction,sizeof(transaction));
if (opt_using_transactions)
{
bzero((char*) &transaction,sizeof(transaction));
if (open_cached_file(&transaction.trans_log,
mysql_tmpdir, LOG_PREFIX, binlog_cache_size,
MYF(MY_WME)))
......
......@@ -1006,7 +1006,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (pthread_kill(tmp->real_id,0))
tmp->proc_info="*** DEAD ***"; // This shouldn't happen
#endif
#ifdef EXTRA_DEBUG
thd_info->start_time= tmp->time_after_lock;
#else
thd_info->start_time= tmp->start_time;
#endif
thd_info->query=0;
if (tmp->query)
{
......
......@@ -240,6 +240,7 @@ Open streams: %10lu\n",
fflush(stdout);
if (thd)
thd->proc_info="malloc";
my_checkmalloc();
TERMINATE(stdout); // Write malloc information
if (thd)
thd->proc_info=0;
......
/*
/*
Copyright (C) 2001 by Korakot Chaovavanich <korakot@iname.com> and
Apisilp Trunganont <apisilp@pantip.inet.co.th>
Copyright (C) 1998, 1999 by Pruet Boonma <pruet@eng.cmu.ac.th>
Copyright (C) 1998 by Theppitak Karoonboonyanan <thep@links.nectec.or.th>
Copyright (C) 1989, 1991 by Samphan Raruenrom <samphan@thai.com>
......@@ -6,9 +8,10 @@
Permission to use, copy, modify, distribute and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies.
Smaphan Raruenrom , Theppitak Karoonboonyanan and Pruet Boonma makes
no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
Samphan Raruenrom , Theppitak Karoonboonyanan , Pruet Boonma ,
Korakot Chaovavanich and Apisilp Trunganont makes no representations
about the suitability of this software for any purpose. It is provided
"as is" without express or implied warranty.
*/
......@@ -32,7 +35,7 @@
static uchar* thai2sortable(const uchar *tstr,uint len);
#define BUFFER_MULTIPLY 4
#define BUFFER_MULTIPLY 4
#define buffsize(s) (BUFFER_MULTIPLY * (strlen(s) + 1))
#define M L_MIDDLE
#define U L_UPPER
......@@ -42,71 +45,71 @@ static uchar* thai2sortable(const uchar *tstr,uint len);
int t_ctype[][TOT_LEVELS] = {
/*0x00*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x00*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x01*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x02*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x03*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x04*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x05*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x06*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x07*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x08*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x09*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x10*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x11*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x12*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x13*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x14*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x15*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x16*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x17*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x18*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x19*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x20*/ { IGNORE, IGNORE, L3_SPACE, IGNORE, M},
/*0x21*/ { IGNORE, IGNORE, L3_EXCLAMATION, IGNORE, M },
/*0x22*/ { IGNORE, IGNORE, L3_QUOTATION, IGNORE, M },
/*0x23*/ { IGNORE, IGNORE, L3_NUMBER, IGNORE, M },
/*0x24*/ { IGNORE, IGNORE, L3_DOLLAR, IGNORE, M },
/*0x25*/ { IGNORE, IGNORE, L3_PERCENT, IGNORE, M },
/*0x26*/ { IGNORE, IGNORE, L3_AMPERSAND, IGNORE, M },
/*0x02*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x03*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x04*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x05*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x06*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x07*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x08*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x09*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x0F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x10*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x11*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x12*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x13*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x14*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x15*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x16*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x17*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x18*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x19*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x1F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x20*/ { IGNORE, IGNORE, L3_SPACE, IGNORE, M},
/*0x21*/ { IGNORE, IGNORE, L3_EXCLAMATION, IGNORE, M },
/*0x22*/ { IGNORE, IGNORE, L3_QUOTATION, IGNORE, M },
/*0x23*/ { IGNORE, IGNORE, L3_NUMBER, IGNORE, M },
/*0x24*/ { IGNORE, IGNORE, L3_DOLLAR, IGNORE, M },
/*0x25*/ { IGNORE, IGNORE, L3_PERCENT, IGNORE, M },
/*0x26*/ { IGNORE, IGNORE, L3_AMPERSAND, IGNORE, M },
/*0x27*/ { IGNORE, IGNORE, L3_APOSTROPHE, IGNORE, M },
/*0x28*/ { IGNORE, IGNORE, L3_L_PARANTHESIS, IGNORE, M },
/*0x29*/ { IGNORE, IGNORE, L3_R_PARENTHESIS, IGNORE, M },
/*0x2A*/ { IGNORE, IGNORE, L3_ASTERISK, IGNORE, M },
/*0x2B*/ { IGNORE, IGNORE, L3_PLUS, IGNORE, M },
/*0x2C*/ { IGNORE, IGNORE, L3_COMMA, IGNORE, M },
/*0x2D*/ { IGNORE, IGNORE, L3_HYPHEN, IGNORE, M },
/*0x2E*/ { IGNORE, IGNORE, L3_FULL_STOP, IGNORE, M },
/*0x2F*/ { IGNORE, IGNORE, L3_SOLIDUS, IGNORE, M },
/*0x2A*/ { IGNORE, IGNORE, L3_ASTERISK, IGNORE, M },
/*0x2B*/ { IGNORE, IGNORE, L3_PLUS, IGNORE, M },
/*0x2C*/ { IGNORE, IGNORE, L3_COMMA, IGNORE, M },
/*0x2D*/ { IGNORE, IGNORE, L3_HYPHEN, IGNORE, M },
/*0x2E*/ { IGNORE, IGNORE, L3_FULL_STOP, IGNORE, M },
/*0x2F*/ { IGNORE, IGNORE, L3_SOLIDUS, IGNORE, M },
/*0x30*/ { L1_08, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x31*/ { L1_18, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x32*/ { L1_28, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x33*/ { L1_38, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x33*/ { L1_38, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x34*/ { L1_48, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x35*/ { L1_58, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x36*/ { L1_68, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x35*/ { L1_58, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x36*/ { L1_68, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x37*/ { L1_78, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x38*/ { L1_88, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x39*/ { L1_98, L2_BLANK, L3_BLANK, L4_BLANK, M },
/*0x3A*/ { IGNORE, IGNORE, L3_COLON, IGNORE, M },
/*0x3B*/ { IGNORE, IGNORE, L3_SEMICOLON, IGNORE, M },
/*0x3C*/ { IGNORE, IGNORE, L3_LESS_THAN, IGNORE, M },
/*0x3D*/ { IGNORE, IGNORE, L3_EQUAL, IGNORE, M },
/*0x3A*/ { IGNORE, IGNORE, L3_COLON, IGNORE, M },
/*0x3B*/ { IGNORE, IGNORE, L3_SEMICOLON, IGNORE, M },
/*0x3C*/ { IGNORE, IGNORE, L3_LESS_THAN, IGNORE, M },
/*0x3D*/ { IGNORE, IGNORE, L3_EQUAL, IGNORE, M },
/*0x3E*/ { IGNORE, IGNORE, L3_GREATER_THAN, IGNORE, M },
/*0x3F*/ { IGNORE, IGNORE, L3_QUESTION, IGNORE, M },
/*0x40*/ { IGNORE, IGNORE, L3_AT, IGNORE, M },
/*0x3F*/ { IGNORE, IGNORE, L3_QUESTION, IGNORE, M },
/*0x40*/ { IGNORE, IGNORE, L3_AT, IGNORE, M },
/*0x41*/ { L1_A8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x42*/ { L1_B8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x43*/ { L1_C8, L2_BLANK, L3_BLANK, L4_CAP, M },
......@@ -119,11 +122,11 @@ int t_ctype[][TOT_LEVELS] = {
/*0x4A*/ { L1_J8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4B*/ { L1_K8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4C*/ { L1_L8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4D*/ { L1_M8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4E*/ { L1_N8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4F*/ { L1_O8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x50*/ { L1_P8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x51*/ { L1_Q8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4D*/ { L1_M8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4E*/ { L1_N8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x4F*/ { L1_O8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x50*/ { L1_P8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x51*/ { L1_Q8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x52*/ { L1_R8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x53*/ { L1_S8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x54*/ { L1_T8, L2_BLANK, L3_BLANK, L4_CAP, M },
......@@ -133,12 +136,12 @@ int t_ctype[][TOT_LEVELS] = {
/*0x58*/ { L1_X8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x59*/ { L1_Y8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x5A*/ { L1_Z8, L2_BLANK, L3_BLANK, L4_CAP, M },
/*0x5B*/ { IGNORE, IGNORE, L3_L_BRACKET, IGNORE, M },
/*0x5B*/ { IGNORE, IGNORE, L3_L_BRACKET, IGNORE, M },
/*0x5C*/ { IGNORE, IGNORE, L3_BK_SOLIDUS, IGNORE, M },
/*0x5D*/ { IGNORE, IGNORE, L3_R_BRACKET, IGNORE, M },
/*0x5D*/ { IGNORE, IGNORE, L3_R_BRACKET, IGNORE, M },
/*0x5E*/ { IGNORE, IGNORE, L3_CIRCUMFLEX, IGNORE, M },
/*0x5F*/ { IGNORE, IGNORE, L3_LOW_LINE, IGNORE, M },
/*0x60*/ { IGNORE, IGNORE, L3_GRAVE, IGNORE, M },
/*0x5F*/ { IGNORE, IGNORE, L3_LOW_LINE, IGNORE, M },
/*0x60*/ { IGNORE, IGNORE, L3_GRAVE, IGNORE, M },
/*0x61*/ { L1_A8, L2_BLANK, L3_BLANK, L4_MIN, M },
/*0x62*/ { L1_B8, L2_BLANK, L3_BLANK, L4_MIN, M },
/*0x63*/ { L1_C8, L2_BLANK, L3_BLANK, L4_MIN, M },
......@@ -165,10 +168,10 @@ int t_ctype[][TOT_LEVELS] = {
/*0x78*/ { L1_X8, L2_BLANK, L3_BLANK, L4_MIN, M },
/*0x79*/ { L1_Y8, L2_BLANK, L3_BLANK, L4_MIN, M },
/*0x7A*/ { L1_Z8, L2_BLANK, L3_BLANK, L4_MIN, M },
/*0x7B*/ { IGNORE, IGNORE, L3_L_BRACE, IGNORE, M },
/*0x7C*/ { IGNORE, IGNORE, L3_V_LINE, IGNORE, M },
/*0x7D*/ { IGNORE, IGNORE, L3_R_BRACE, IGNORE, M },
/*0x7E*/ { IGNORE, IGNORE, L3_TILDE, IGNORE, M },
/*0x7B*/ { IGNORE, IGNORE, L3_L_BRACE, IGNORE, M },
/*0x7C*/ { IGNORE, IGNORE, L3_V_LINE, IGNORE, M },
/*0x7D*/ { IGNORE, IGNORE, L3_R_BRACE, IGNORE, M },
/*0x7E*/ { IGNORE, IGNORE, L3_TILDE, IGNORE, M },
/*0x7F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x80*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x81*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
......@@ -202,31 +205,31 @@ int t_ctype[][TOT_LEVELS] = {
/*0x9D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x9E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0x9F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xA0*/ { IGNORE, IGNORE, L3_NB_SACE, IGNORE, X },
/*0xA0*/ { IGNORE, IGNORE, L3_NB_SACE, IGNORE, X },
/*0xA1*/ { L1_KO_KAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA2*/ { L1_KHO_KHAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA2*/ { L1_KHO_KHAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA3*/ { L1_KHO_KHUAT, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA4*/ { L1_KHO_KHWAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA5*/ { L1_KHO_KHON, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA6*/ { L1_KHO_RAKHANG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA7*/ { L1_NGO_NGU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA7*/ { L1_NGO_NGU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA8*/ { L1_CHO_CHAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xA9*/ { L1_CHO_CHING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAA*/ { L1_CHO_CHANG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAB*/ { L1_SO_SO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAB*/ { L1_SO_SO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAC*/ { L1_CHO_CHOE, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAD*/ { L1_YO_YING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAD*/ { L1_YO_YING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAE*/ { L1_DO_CHADA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xAF*/ { L1_TO_PATAK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB0*/ { L1_THO_THAN, L2_BLANK,L3_BLANK, L4_BLANK, M | _consnt},
/*0xB1*/ { L1_THO_NANGMONTHO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB0*/ { L1_THO_THAN, L2_BLANK,L3_BLANK, L4_BLANK, M | _consnt},
/*0xB1*/ { L1_THO_NANGMONTHO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB2*/ { L1_THO_PHUTHAO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB3*/ { L1_NO_NEN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB4*/ { L1_DO_DEK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB5*/ { L1_TO_TAO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB5*/ { L1_TO_TAO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB6*/ { L1_THO_THUNG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB7*/ { L1_THO_THAHAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB8*/ { L1_THO_THONG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB8*/ { L1_THO_THONG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xB9*/ { L1_NO_NU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xBA*/ { L1_BO_BAIMAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xBB*/ { L1_PO_PLA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
......@@ -238,40 +241,40 @@ int t_ctype[][TOT_LEVELS] = {
/*0xC1*/ { L1_MO_MA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC2*/ { L1_YO_YAK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC3*/ { L1_RO_RUA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC4*/ { L1_RU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC4*/ { L1_RU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC5*/ { L1_LO_LING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC6*/ { L1_LU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC7*/ { L1_WO_WAEN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC8*/ { L1_SO_SALA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC9*/ { L1_SO_RUSI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCA*/ { L1_SO_SUA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCB*/ { L1_HO_HIP, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC6*/ { L1_LU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC7*/ { L1_WO_WAEN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC8*/ { L1_SO_SALA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xC9*/ { L1_SO_RUSI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCA*/ { L1_SO_SUA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCB*/ { L1_HO_HIP, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCC*/ { L1_LO_CHULA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCD*/ { L1_O_ANG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCE*/ { L1_HO_NOKHUK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCF*/ { IGNORE, IGNORE, L3_PAIYAN_NOI, IGNORE, M},
/*0xD0*/ { L1_SARA_A, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
/*0xD1*/ { L1_MAI_HAN_AKAT, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD2*/ { L1_SARA_AA, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
/*0xCE*/ { L1_HO_NOKHUK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
/*0xCF*/ { IGNORE, IGNORE, L3_PAIYAN_NOI, IGNORE, M},
/*0xD0*/ { L1_SARA_A, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
/*0xD1*/ { L1_MAI_HAN_AKAT, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD2*/ { L1_SARA_AA, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
/*0xD3*/ { L1_SARA_AM, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
/*0xD4*/ { L1_SARA_I, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD5*/ { L1_SARA_II, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD6*/ { L1_SARA_UE, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD5*/ { L1_SARA_II, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD6*/ { L1_SARA_UE, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD7*/ { L1_SARA_UEE, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
/*0xD8*/ { L1_SARA_U, L2_BLANK, L3_BLANK, L4_BLANK, L | _lwrvowel},
/*0xD8*/ { L1_SARA_U, L2_BLANK, L3_BLANK, L4_BLANK, L | _lwrvowel},
/*0xD9*/ { L1_SARA_UU, L2_BLANK, L3_BLANK, L4_BLANK, L | _lwrvowel},
/*0xDA*/ { IGNORE, L2_PINTHU, L3_BLANK, L4_BLANK, L },
/*0xDB*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDC*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDD*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDE*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDB*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDC*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDD*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDE*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xDF*/ { IGNORE, IGNORE, L3_BAHT, IGNORE, M},
/*0xE0*/ { L1_SARA_E, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
/*0xE1*/ { L1_SARA_AE, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
/*0xE2*/ { L1_SARA_O, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
/*0xE3*/ { L1_SARA_AI_MAIMUAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
/*0xE3*/ { L1_SARA_AI_MAIMUAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
/*0xE4*/ { L1_SARA_AI_MAIMALAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
/*0xE5*/ { L1_SARA_AA, L2_BLANK, L3_BLANK, L4_EXT, M | _fllwvowel },
/*0xE5*/ { L1_SARA_AA, L2_BLANK, L3_BLANK, L4_EXT, M | _fllwvowel },
/*0xE6*/ { IGNORE, IGNORE, L3_MAI_YAMOK, IGNORE, M | _stone },
/*0xE7*/ { IGNORE, L2_TYKHU, L3_BLANK, L4_BLANK, U | _diacrt1 | _stone },
/*0xE8*/ { IGNORE, L2_TONE1, L3_BLANK, L4_BLANK, UU | _tone | _combine | _stone },
......@@ -281,8 +284,8 @@ int t_ctype[][TOT_LEVELS] = {
/*0xEC*/ { IGNORE, L2_GARAN, L3_BLANK, L4_BLANK, UU | _diacrt2 | _combine | _stone },
/*0xED*/ { L1_NKHIT, L2_BLANK, L3_BLANK, L4_BLANK, U | _diacrt1 },
/*0xEE*/ { IGNORE, L2_YAMAK, L3_BLANK, L4_BLANK, U | _diacrt1 },
/*0xEF*/ { IGNORE, IGNORE, L3_FONGMAN, IGNORE, M },
/*0xF0*/ { L1_08, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
/*0xEF*/ { IGNORE, IGNORE, L3_FONGMAN, IGNORE, M },
/*0xF0*/ { L1_08, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
/*0xF1*/ { L1_18, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
/*0xF2*/ { L1_28, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
/*0xF3*/ { L1_38, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
......@@ -297,7 +300,8 @@ int t_ctype[][TOT_LEVELS] = {
/*0xFC*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xFD*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xFE*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xFF*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/* Utilize 0xFF for max_sort_chr in my_like_range_tis620 */
/*0xFF*/ { 255 /*IGNORE*/, IGNORE, IGNORE, IGNORE, X },
};
uchar NEAR ctype_tis620[257] =
......@@ -429,17 +433,21 @@ uchar NEAR sort_order_tis620[]=
(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
};
/* Convert thai string to "Standard C String Function" sortable string
/* Convert thai string to "Standard C String Function" sortable string
Arg: const source string and length of converted string
Ret: Sortable string
*/
static uchar* thai2sortable(const uchar * tstr,uint len)
static uchar* thai2sortable(const uchar * tstr,uint len)
{
/* We use only 3 levels (neglect capitalization). */
const uchar* p = tstr;
uchar *outBuf;
uchar *pRight1, *pRight2, *pRight3, *pRight4;
uchar *pLeft1, *pLeft2, *pLeft3, *pLeft4;
uchar *outBuf;
// uchar *pRight1, *pRight2, *pRight3, *pRight4;
// uchar *pLeft1, *pLeft2, *pLeft3, *pLeft4;
uchar *pRight1, *pRight2, *pRight3;
uchar *pLeft1, *pLeft2, *pLeft3;
uint bufSize;
len = (uint) strnlen((char*) tstr,len);
......@@ -460,49 +468,50 @@ static uchar* thai2sortable(const uchar * tstr,uint len)
return((uchar*) tstr);
}
pLeft3 = pRight3;
if(!(pRight4 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) {
/* if(!(pRight4 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) {
free(pRight1);
free(pRight2);
free(pRight3);
return((uchar*) tstr);
}
pLeft4 = pRight4;
pLeft4 = pRight4;*/
while(len--) {
if(isldvowel(*p) && isconsnt(p[1])) {
*pRight1++ = t_ctype[p[1]][0];
*pRight2++ = t_ctype[p[1]][1];
*pRight3++ = t_ctype[p[1]][2];
*pRight4++ = t_ctype[p[1]][3];
// *pRight4++ = t_ctype[p[1]][3];
*pRight1++ = t_ctype[*p][0];
*pRight2++ = t_ctype[*p][1];
*pRight3++ = t_ctype[*p][2];
*pRight4++ = t_ctype[*p][3];
// *pRight4++ = t_ctype[*p][3];
len--;
p += 2;
} else {
*pRight1 = t_ctype[*p][0];
*pRight1 = t_ctype[*p][0];
if(*pRight1 != IGNORE) pRight1++;
*pRight2 = t_ctype[*p][1];
if(*pRight2 != IGNORE) pRight2++;
*pRight3 = t_ctype[*p][2];
if(*pRight3 != IGNORE) pRight3++;
*pRight4 = t_ctype[*p][3];
if(*pRight4 != IGNORE) pRight4++;
/* *pRight4 = t_ctype[*p][3];
if(*pRight4 != IGNORE) pRight4++;*/
p++;
}
}
*pRight1++ = L2_BLANK;
*pRight2++ = L3_BLANK;
*pRight3++ = L4_BLANK;
*pRight4++ = '\0';
// *pRight3++ = L4_BLANK;
*pRight3++ = '\0';
// *pRight4++ = '\0';
memcpy(pRight1, pLeft2, pRight2 - pLeft2);
pRight1 += pRight2 - pLeft2;
memcpy(pRight1, pLeft3, pRight3 - pLeft3);
pRight1 += pRight3 - pLeft3;
memcpy(pRight1, pLeft4, pRight4 - pLeft4);
// pRight1 += pRight3 - pLeft3;
// memcpy(pRight1, pLeft4, pRight4 - pLeft4);
free(pLeft2);
free(pLeft3);
free(pLeft4);
// free(pLeft4);
return(outBuf);
}
......@@ -510,7 +519,7 @@ static uchar* thai2sortable(const uchar * tstr,uint len)
Arg: 2 Strings and it compare length
Ret: strcmp result
*/
int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2)
int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2)
{
uchar *tc1, *tc2;
int i;
......@@ -526,7 +535,7 @@ int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2)
Arg: Destination buffer, source string, dest length and source length
Ret: Conveted string size
*/
int my_strnxfrm_tis620(uchar * dest, uchar * src, int len, int srclen)
int my_strnxfrm_tis620(uchar * dest, uchar * src, int len, int srclen)
{
uint bufSize;
uchar *tmp;
......@@ -542,7 +551,7 @@ int my_strnxfrm_tis620(uchar * dest, uchar * src, int len, int srclen)
Arg: 2 strings
Ret: strcmp result
*/
int my_strcoll_tis620(const uchar * s1, const uchar * s2)
int my_strcoll_tis620(const uchar * s1, const uchar * s2)
{
uchar *tc1, *tc2;
int i;
......@@ -555,7 +564,7 @@ int my_strcoll_tis620(const uchar * s1, const uchar * s2)
}
/* strxfrm replacment, convert Thai string to sortable string
Arg: Destination buffer, String and dest buffer size
Arg: Destination buffer, String and dest buffer size
Ret: Converting string size
*/
int my_strxfrm_tis620(uchar * dest, uchar * src, int len)
......@@ -574,55 +583,58 @@ int my_strxfrm_tis620(uchar * dest, uchar * src, int len)
Arg: String, its length, escape character, resource length, minimal string and maximum string
Ret: Alway 0
*/
/* We just copy this function from opt_range.cc. No need to convert to
thai2sortable string. min_str and max_str will be use for comparison and
converted there. */
#define max_sort_chr ((char) 255)
#define wild_one '_'
#define wild_many '%'
my_bool my_like_range_tis620(const char *ptr, uint ptr_length, pchar escape,
uint res_length, char *min_str, char *max_str,
uint *min_length,uint *max_length)
uint res_length, char *min_str, char *max_str,
uint *min_length, uint *max_length)
{
char *end;
char *min_org= min_str;
char *min_end = min_str + res_length;
char *tbuff;
uchar *tc;
uint tbuff_length;
const char *end=ptr+ptr_length;
char *min_org=min_str;
char *min_end=min_str+res_length;
char *tmp;
tbuff = (char*) (tc=thai2sortable((uchar*) ptr, ptr_length));
tbuff_length = (uint) buffsize(ptr);
end = tbuff + tbuff_length;
for(;tbuff != end && min_str != min_end; tbuff++)
for (; ptr != end && min_str != min_end ; ptr++)
{
if(*tbuff == escape && tbuff + 1 != end)
if (*ptr == escape && ptr+1 != end)
{
tbuff++;
*min_str++ = *max_str++ = *tbuff;
ptr++; // Skipp escape
*min_str++= *max_str++ = *ptr;
continue;
}
if(*tbuff == '_')
if (*ptr == wild_one) // '_' in SQL
{
*min_str++ = '\0';
*max_str++ = '\255';
*min_str++='\0'; // This should be min char
*max_str++=max_sort_chr;
continue;
}
if(*tbuff == '%')
if (*ptr == wild_many) // '%' in SQL
{
*min_length= (uint) (min_str - min_org);
*max_length= res_length;
do
{
*min_str++ = ' ';
*max_str++ = '\255';
} while(min_str != min_end);
free(tc);
return(0);
*max_length=res_length;
do {
*min_str++ = ' '; // Because if key compression
*max_str++ = max_sort_chr;
} while (min_str != min_end);
return 0;
}
*min_str++ = *max_str++ = *tbuff;
*min_str++= *max_str++ = *ptr;
}
*min_length= *max_length = (uint) (min_str - min_org);
while(min_str != min_end)
{
*min_str++ = *max_str++ = ' ';
}
free(tc);
return(0);
/* Temporary fix for handling wild_one at end of string (key compression) */
// for (tmp= min_str ; tmp > min_org && tmp[-1] == '\0';)
// *--tmp=' ';
while (min_str != min_end)
*min_str++ = *max_str++ = ' '; // Because if key compression
return 0;
}
/* Thai normalization for input sub system
......@@ -635,7 +647,7 @@ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length)
uchar* p = ptr;
if(length > field_length) {
length = field_length;
length = field_length;
}
while (length--)
{
......
#!/usr/bin/perl -w
#
# This is a test with uses 4 processes to insert, delete , check and select
#
$opt_loop_count=200000; # 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 4 multiple connections to a server with 1 insert, 1 delete\n";
print "1 select and one repair/check connection.\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");
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_delete() if (($pid=fork()) == 0); $work{$pid}="delete";
test_select() if (($pid=fork()) == 0); $work{$pid}="select1";
repair_and_check() if (($pid=fork()) == 0); $work{$pid}="repair/check";
$errors=0;
while (($pid=wait()) != -1)
{
$ret=$?/256;
print "thread '" . $work{$pid} . "' finnished 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,$sth);
$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++)
{
$sth=$dbh->do("insert into $firsttable values ($i,'This is entry $i','')") || die "Got error on insert: $Mysql::db_errstr\n";
$sth=0;
}
$dbh->disconnect; $dbh=0;
print "Test_insert: Inserted $i rows\n";
exit(0);
}
sub test_delete
{
my ($dbh,$i,$sth,@row);
$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++)
{
sleep(5);
if ($opt_lock_tables)
{
$sth=$dbh->do("lock tables $firsttable WRITE") || die "Got error on lock tables $firsttable: $Mysql::db_errstr\n";
}
$sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on select from $firsttable: $dbh->errstr\n";
$sth->execute || die $dbh->errstr;
if ((@row = $sth->fetchrow_array()))
{
last if (!$row[0]); # Insert thread is probably ready
}
$sth=$dbh->do("delete from $firsttable") || die "Got error on delete from $firsttable: $dbh->errstr;\n";
}
$sth=0;
$dbh->disconnect; $dbh=0;
print "Test_delete: Deleted all rows $i times\n";
exit(0);
}
#
# select records
#
sub test_select
{
my ($dbh,$i,$sth,@row);
$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++)
{
$sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on select from $firsttable: $dbh->errstr;\n";
$sth->execute || die $dbh->errstr;
@row = $sth->fetchrow_array();
$sth=0;
}
$dbh->disconnect; $dbh=0;
print "Test_select: ok\n";
exit(0);
}
sub repair_and_check
{
my ($dbh,$row,$found1,$last_found1,$i,$type, $table);
$found1=0; $last_found1= -1;
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
for ($i=0; $found1 != $last_found1 ; $i++)
{
$type=($i & 2) ? "repair" : "check";
$table=$firsttable;
$last_found1=$found1;
$sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $dbh->errstr\n";
$sth->execute || die $dbh->errstr;
while (($row=$sth->fetchrow_arrayref))
{
if ($row->[3] ne "OK")
{
print "Got error " . $row->[3] . " when doing $type on $table\n";
exit(1);
}
}
$sth=$dbh->prepare("select count(*) from $table") || die "Got error on prepare: $dbh->errstr\n";
$sth->execute || die $dbh->errstr;
@row = $sth->fetchrow_array();
$found1= $row[0];
$sth->finish;
sleep(3);
}
$dbh->disconnect; $dbh=0;
print "check/repair: Did $i repair/checks\n";
exit(0);
}
#!/usr/bin/perl -w
#
# This is a test with uses many processes to test a MySQL server.
#
# Tested a lot with: --threads=30
$opt_loop_count=200000; # 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_threads=5;
$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","threads=i") || 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 "Test of multiple connections that test the following things:\n";
print "insert, select, delete, update, check, repair and flush\n";
@testtables = ( ["bench_f31", ""],
["bench_f32", "row_format=fixed"],
["bench_f33", "delay_key_write=1"],
["bench_f34", "checksum=1"],
["bench_f35", "delay_key_write=1"]);
$abort_table="bench_f39";
$numtables = $#testtables+1;
srand 100; # Make random numbers repeatable
####
#### Start timeing and start test
####
$start_time=new Benchmark;
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
if (!$opt_skip_create)
{
my $table_def;
foreach $table_def (@testtables)
{
my ($table,$extra)= ($table_def->[0], $table_def->[1]);
print "Creating table $table in database $opt_db\n";
$dbh->do("drop table if exists $table");
$dbh->do("create table $table".
" (id int(6) not null auto_increment,".
" info varchar(32)," .
" marker timestamp," .
" flag int not null," .
" primary key(id)) $extra")
or die $DBI::errstr;
# One row in the table will make future tests easier
$dbh->do("insert into $table (id) values (null)")
or die $DBI::errstr;
}
# Create the table we use to signal that we should end the test
$dbh->do("drop table if exists $abort_table");
$dbh->do("create table $abort_table (id int(6) not null) type=heap") ||
die $DBI::errstr;
}
$dbh->do("delete from $abort_table");
$dbh->disconnect; $dbh=0; # Close handler
$|= 1; # Autoflush
####
#### Start the tests
####
for ($i=0 ; $i < $opt_threads ; $i ++)
{
test_insert() if (($pid=fork()) == 0); $work{$pid}="insert";
}
for ($i=0 ; $i < $numtables ; $i ++)
{
test_insert($i,$i) if (($pid=fork()) == 0); $work{$pid}="insert_one";
}
for ($i=0 ; $i < $opt_threads ; $i ++)
{
test_select() if (($pid=fork()) == 0); $work{$pid}="select_key";
}
test_delete() if (($pid=fork()) == 0); $work{$pid}="delete";
test_update() if (($pid=fork()) == 0); $work{$pid}="update";
test_flush() if (($pid=fork()) == 0); $work{$pid}= "flush";
test_check() if (($pid=fork()) == 0); $work{$pid}="check";
test_repair() if (($pid=fork()) == 0); $work{$pid}="repair";
print "Started " . ($opt_threads*2+4) . " threads\n";
$errors=0;
$running_insert_threads=$opt_threads+$numtables;
while (($pid=wait()) != -1)
{
$ret=$?/256;
print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
if ($work{$pid} =~ /^insert/)
{
if (!--$running_insert_threads)
{
# Time to stop other threads
signal_abort();
}
}
$errors++ if ($ret != 0);
}
#
# Cleanup
#
if (!$opt_skip_delete && !$errors)
{
my $table_def;
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$dbh->do("drop table $abort_table");
foreach $table_def (@testtables)
{
$dbh->do("drop table " . $table_def->[0]);
}
$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 ($from_table,$to_table)= @_;
my ($dbh,$i,$j,$count,$table_def,$table);
if (!defined($from_table))
{
$from_table=0; $to_table=$numtables-1;
}
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
for ($i=$count=0 ; $i < $opt_loop_count; $i++)
{
for ($j= $from_table ; $j <= $to_table ; $j++)
{
my ($table)= ($testtables[$j]->[0]);
$dbh->do("insert into $table values (NULL,'This is entry $i','',0)") || die "Got error on insert: $DBI::errstr\n";
$count++;
}
}
$dbh->disconnect; $dbh=0;
print "Test_insert: Inserted $count rows\n";
exit(0);
}
#
# select records
# Do continously select over all tables as long as there is changed
# rows in the table
#
sub test_select
{
my ($dbh, $i, $j, $count, $loop);
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$count_query=make_count_query($numtables);
$count=0;
$loop=9999;
$i=0;
while (($i++ % 100) || !test_if_abort($dbh))
{
if ($loop++ >= 100)
{
$loop=0;
$row_counts=simple_query($dbh, $count_query);
}
for ($j=0 ; $j < $numtables ; $j++)
{
my ($id)= int rand $row_counts->[$j];
my ($table)= $testtables[$j]->[0];
simple_query($dbh, "select id,info from $table where id=$id");
$count++;
}
}
$dbh->disconnect; $dbh=0;
print "Test_select: Executed $count selects\n";
exit(0);
}
#
# Delete 1-5 rows from the first 2 tables.
# Test ends when the number of rows for table 3 didn't change during
# one loop
#
sub test_delete
{
my ($dbh, $i,$j, $row_counts, $count_query, $table_count, $count);
$table_count=2;
$count=0;
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$count_query=make_count_query($table_count+1);
sleep(5); # Give time to insert some rows
$i=0;
while (($i++ % 10) || !test_if_abort($dbh))
{
sleep(1);
$row_counts=simple_query($dbh, $count_query);
for ($j=0 ; $j < $table_count ; $j++)
{
my ($id)= int rand $row_counts->[$j];
my ($table)= $testtables[$j]->[0];
$dbh->do("delete from $table where id >= $id-2 and id <= $id +2") || die "Got error on delete from $table: $DBI::errstr\n";
$count++;
}
}
$dbh->disconnect; $dbh=0;
print "Test_delete: Executed $count deletes\n";
exit(0);
}
#
# Update the flag for table 2 and 3
# Will abort after a while when table1 doesn't change max value
#
sub test_update
{
my ($dbh, $i, $j, $row_counts, $count_query, $count, $loop);
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$count_query=make_count_query(3);
$loop=9999;
$count=0;
sleep(5); # Give time to insert some rows
$i=0;
while (($i++ % 100) || !test_if_abort($dbh))
{
if ($loop++ >= 100)
{
$loop=0;
$row_counts=simple_query($dbh, $count_query);
}
for ($j=1 ; $j <= 2 ; $j++)
{
my ($id)= int rand $row_counts->[$j];
my ($table)= $testtables[$j]->[0];
# Fix to not change the same rows as the above delete
$id= ($id + $count) % $row_counts->[$j];
$dbh->do("update $table set flag=flag+1 where id >= $id-2 and id <= $id +2") || die "Got error on update of $table: $DBI::errstr\n";
$count++;
}
}
$dbh->disconnect; $dbh=0;
print "Test_update: Executed $count updates\n";
exit(0);
}
#
# Run a check on all tables except the last one
# (The last one is not checked to put pressure on the key cache)
#
sub test_check
{
my ($dbh, $row, $i, $j, $type, $table);
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$type= "check";
for ($i=$j=0 ; !test_if_abort($dbh) ; $i++)
{
sleep(60);
$table=$testtables[$j]->[0];
$sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $DBI::errstr\n";
$sth->execute || die $DBI::errstr;
while (($row=$sth->fetchrow_arrayref))
{
if ($row->[3] ne "OK")
{
print "Got error " . $row->[3] . " when doing $type on $table\n";
exit(1);
}
}
if (++$j == $numtables-1)
{
$j=0;
}
}
$dbh->disconnect; $dbh=0;
print "test_check: Executed $i checks\n";
exit(0);
}
#
# Do a repair on the first table once in a while
#
sub test_repair
{
my ($dbh, $row, $i, $type, $table);
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$type= "repair";
for ($i=0 ; !test_if_abort($dbh) ; $i++)
{
sleep(95);
$table=$testtables[0]->[0];
$sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $DBI::errstr\n";
$sth->execute || die $DBI::errstr;
while (($row=$sth->fetchrow_arrayref))
{
if ($row->[3] ne "OK")
{
print "Got error " . $row->[3] . " when doing $type on $table\n";
exit(1);
}
}
}
$dbh->disconnect; $dbh=0;
print "test_repair: Executed $i repairs\n";
exit(0);
}
#
# Do a flush tables on table 3 and 4 once in a while
#
sub test_flush
{
my ($dbh,$count,$tables);
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$tables=$testtables[2]->[0] . "," . $testtables[3]->[0];
$count=0;
while (!test_if_abort($dbh))
{
sleep(60);
$dbh->do("flush tables $tables") ||
die "Got error on flush $DBI::errstr\n";
$count++;
}
$dbh->disconnect; $dbh=0;
print "flush: Executed $count flushs\n";
exit(0);
}
#
# Help functions
#
sub signal_abort
{
my ($dbh);
$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
$opt_user, $opt_password,
{ PrintError => 0}) || die $DBI::errstr;
$dbh->do("insert into $abort_table values(1)") || die $DBI::errstr;
$dbh->disconnect; $dbh=0;
exit(0);
}
sub test_if_abort()
{
my ($dbh)=@_;
$row=simple_query($dbh,"select * from $abort_table");
return (defined($row) && defined($row->[0]) != 0) ? 1 : 0;
}
sub make_count_query
{
my ($table_count)= @_;
my ($tables, $count_query, $i, $tables_def);
$tables="";
$count_query="select high_priority ";
$table_count--;
for ($i=0 ; $i < $table_count ; $i++)
{
my ($table_def)= $testtables[$i];
$tables.=$table_def->[0] . ",";
$count_query.= "max(" . $table_def->[0] . ".id),";
}
$table_def=$testtables[$table_count];
$tables.=$table_def->[0];
$count_query.= "max(" . $table_def->[0] . ".id) from $tables";
return $count_query;
}
sub simple_query()
{
my ($dbh, $query)= @_;
my ($sth,$row);
$sth=$dbh->prepare($query) || die "Got error on '$query': $DBI::errstr\n";
$sth->execute || die "Got error on '$query': $dbh->errstr\n";
$row= $sth->fetchrow_arrayref();
$sth=0;
return $row;
}
#!/usr/bin/perl -w
# This is a test with uses 5 processes to insert, update and select from
# two tables.
# One inserts records in the tables, one updates some record in it and
# the last 3 does different selects on the tables.
#
$opt_loop_count=10000; # Change this to make test harder/easier
##################### Standard benchmark inits ##############################
use Mysql;
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=$Mysql::db_errstr=$opt_force=undef; # Ignore warnings from these
print "Testing 5 multiple connections to a server with 1 insert, 1 update\n";
print "and 3 select connections.\n";
$firsttable = "bench_f1";
$secondtable = "bench_f2";
####
#### Start timeing and start test
####
$start_time=new Benchmark;
if (!$opt_skip_create)
{
$dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$Mysql::QUIET = 1;
$dbh->Query("drop table $firsttable");
$dbh->Query("drop table $secondtable");
$Mysql::QUIET = 0;
print "Creating tables $firsttable and $secondtable in database $opt_db\n";
$dbh->Query("create table $firsttable (id int(6) not null, info varchar(32), marker char(1), primary key(id))") or die $Mysql::db_errstr;
$dbh->Query("create table $secondtable (id int(6) not null, row int(3) not null,value double, primary key(id,row))") or die $Mysql::db_errstr;
$dbh=0; # Close handler
}
$|= 1; # Autoflush
####
#### Start the tests
####
test_1() if (($pid=fork()) == 0); $work{$pid}="insert";
test_2() if (($pid=fork()) == 0); $work{$pid}="update";
test_3() if (($pid=fork()) == 0); $work{$pid}="select1";
test_4() if (($pid=fork()) == 0); $work{$pid}="select2";
test_5() if (($pid=fork()) == 0); $work{$pid}="select3";
$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 = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$dbh->Query("drop table $firsttable");
$dbh->Query("drop table $secondtable");
}
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 two tables
#
sub test_1
{
my ($dbh,$tmpvar,$rows,$found,$i);
$dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$tmpvar=1;
$rows=$found=0;
for ($i=0 ; $i < $opt_loop_count; $i++)
{
$tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
$sth=$dbh->Query("insert into $firsttable values ($i,'This is entry $i','')") || die "Got error on insert: $Mysql::db_errstr\n";
$row_count=($i % 7)+1;
$rows+=1+$row_count;
for ($j=0 ; $j < $row_count; $j++)
{
$sth=$dbh->Query("insert into $secondtable values ($i,$j,0)") || die "Got error on insert: $Mysql::db_errstr\n";
}
if (($tmpvar % 10) == 0)
{
$sth=$dbh->Query("select max(info) from $firsttable") || die "Got error on select max(info): $Mysql::db_errstr\n";
$sth=$dbh->Query("select max(value) from $secondtable") || die "Got error on select max(info): $Mysql::db_errstr\n";
$found+=2;
}
}
$dbh=0;
print "Test_1: Inserted $rows rows, found $found rows\n";
exit(0);
}
#
# Update records in both tables
#
sub test_2
{
my ($dbh,$id,$tmpvar,$rows,$found,$i,$max_id,$tmp);
$dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$tmpvar=111111;
$rows=$found=$max_id=$id=0;
for ($i=0 ; $i < $opt_loop_count ; $i++)
{
$tmp=(($tmpvar + 63) + $i)*3;
$tmp=$tmp-int($tmp/100000)*100000;
$tmpvar^= $tmp;
$tmp=$tmpvar - int($tmpvar/10)*10;
if ($max_id < 2 || $tmp == 0)
{
$max_id=0;
$sth=$dbh->Query("select max(id) from $firsttable where marker=''") || die "Got error select max: $Mysql::db_errstr\n";
if ((@row = $sth->FetchRow()) && defined($row[0]))
{
$found++;
$max_id=$id=$row[0];
}
}
else
{
$id= $tmpvar % ($max_id-1)+1;
}
if ($id)
{
$sth=$dbh->Query("update $firsttable set marker='x' where id=$id") || die "Got error update $firsttable: $Mysql::db_errstr\n";
$rows+=$sth->affected_rows;
if ($sth->affected_rows)
{
$sth=$dbh->Query("update $secondtable set value=$i where id=$id") || die "Got error update $firsttable: $Mysql::db_errstr\n";
$rows+=$sth->affected_rows;
}
}
}
$dbh=0;
print "Test_2: Found $found rows, Updated $rows rows\n";
exit(0);
}
#
# select records
#
sub test_3
{
my ($dbh,$id,$tmpvar,$rows,$i);
$dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$tmpvar=222222;
$rows=0;
for ($i=0 ; $i < $opt_loop_count ; $i++)
{
$tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
$id=$tmpvar % $opt_loop_count;
$sth=$dbh->Query("select id from $firsttable where id=$id") || die "Got error on select from $firsttable: $Mysql::db_errstr\n";
$rows+=$sth->numrows;
}
$dbh=0;
print "Test_3: Found $rows rows\n";
exit(0);
}
#
# Note that this uses row=1 and in some cases won't find any matching
# records
#
sub test_4
{
my ($dbh,$id,$tmpvar,$rows,$i);
$dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$tmpvar=333333;
$rows=0;
for ($i=0 ; $i < $opt_loop_count; $i++)
{
$tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
$id=$tmpvar % $opt_loop_count;
$sth=$dbh->Query("select id from $secondtable where id=$id") || die "Got error on select form $secondtable: $Mysql::db_errstr\n";
$rows+=$sth->numrows;
}
$dbh=0;
print "Test_4: Found $rows rows\n";
exit(0);
}
sub test_5
{
my ($dbh,$id,$tmpvar,$rows,$i,$max_id);
$dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
$tmpvar=444444;
$rows=$max_id=0;
for ($i=0 ; $i < $opt_loop_count ; $i++)
{
$tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
if ($max_id == 0 || ($tmpvar % 10 == 0))
{
$sth=$dbh->Query("select max(id) from $firsttable") || die "Got error select max: $Mysql::db_errstr\n";
if ((@row = $sth->FetchRow()) && defined($row[0]))
{
$max_id=$id=$row[0];
}
else
{
$id=0;
}
}
else
{
$id= $tmpvar % $max_id;
}
$sth=$dbh->Query("select value from $firsttable,$secondtable where $firsttable.id=$id and $secondtable.id=$firsttable.id") || die "Got error on select form $secondtable: $Mysql::db_errstr\n";
$rows+=$sth->numrows;
}
$dbh=0;
print "Test_5: Found $rows rows\n";
exit(0);
}
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