summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore4
-rw-r--r--client/sql_string.h8
-rw-r--r--configure.in25
-rw-r--r--include/my_global.h5
-rw-r--r--man/Makefile.am3
-rw-r--r--myisam/mi_delete.c2
-rw-r--r--myisam/mi_dynrec.c157
-rw-r--r--myisam/mi_rkey.c49
-rw-r--r--myisam/mi_test_all.res70
-rwxr-xr-xmyisam/mi_test_all.sh3
-rw-r--r--mysql-test/r/func_str.result7
-rw-r--r--mysql-test/r/myisam.result28
-rw-r--r--mysql-test/t/func_str.test8
-rw-r--r--mysql-test/t/myisam.test35
-rw-r--r--mysys/my_lread.c2
-rw-r--r--mysys/my_lwrite.c2
-rw-r--r--mysys/my_pread.c12
-rw-r--r--mysys/my_quick.c26
-rw-r--r--mysys/my_read.c9
-rw-r--r--mysys/my_write.c20
-rwxr-xr-xnetware/BUILD/mwasmnlm5
-rwxr-xr-xnetware/BUILD/mwccnlm5
-rwxr-xr-xnetware/BUILD/mwldnlm5
-rw-r--r--scripts/make_binary_distribution.sh22
-rw-r--r--scripts/make_sharedlib_distribution.sh6
-rw-r--r--scripts/mysqlhotcopy.sh7
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_strfunc.cc15
-rw-r--r--sql/item_strfunc.h1
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_select.cc14
-rw-r--r--sql/sql_string.h8
-rw-r--r--support-files/mysql.spec.sh2
33 files changed, 449 insertions, 127 deletions
diff --git a/.bzrignore b/.bzrignore
index 1d5a2dcebdb..f37b74c9fc9 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -549,3 +549,7 @@ support-files/my-innodb-heavy-4G.cnf
ac_available_languages_fragment
support-files/MacOSX/postflight
support-files/MacOSX/preflight
+*/.deps
+*.Po
+*.Plo
+*/.libs/*
diff --git a/client/sql_string.h b/client/sql_string.h
index cffe78936a0..13687eef4dc 100644
--- a/client/sql_string.h
+++ b/client/sql_string.h
@@ -67,6 +67,14 @@ public:
Ptr[str_length]=0;
return Ptr;
}
+ inline char *c_ptr_safe()
+ {
+ if (Ptr && str_length < Alloced_length)
+ Ptr[str_length]=0;
+ else
+ (void) realloc(str_length);
+ return Ptr;
+ }
void set(String &str,uint32 offset,uint32 arg_length)
{
diff --git a/configure.in b/configure.in
index 8dd224d0a87..0be3bcf0406 100644
--- a/configure.in
+++ b/configure.in
@@ -1241,8 +1241,9 @@ if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
then
# Look for LinuxThreads.
AC_MSG_CHECKING("LinuxThreads")
- res=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l`
- if test "$res" -gt 0
+ grepres=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l`
+ getconfres=`which getconf >/dev/null && getconf GNU_LIBPTHREAD_VERSION | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |grep LINUXTHREADS | wc -l || echo 0`
+ if test "$grepres" -gt 0 -o "$getconfres" -gt 0
then
AC_MSG_RESULT("Found")
AC_DEFINE(HAVE_LINUXTHREADS)
@@ -1255,12 +1256,20 @@ then
else
AC_MSG_RESULT("Not found")
# If this is a linux machine we should barf
+ AC_MSG_CHECKING("NPTL")
if test "$IS_LINUX" = "true"
then
- AC_MSG_ERROR([This is a linux system and Linuxthreads was not
-found. On linux Linuxthreads should be used. Please install Linuxthreads
-(or a new glibc) and try again. See the Installation chapter in the
-Reference Manual for more information.])
+ getconfres=`which getconf >/dev/null && getconf GNU_LIBPTHREAD_VERSION | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |grep NPTL | wc -l || echo 0`
+ if test "$getconfres" -gt 0
+ then
+ AC_DEFINE(HAVE_LINUXTHREADS) dnl All this code predates NPTL, so "have linuxthreads" is a poor name.
+ with_named_thread="-lpthread"
+ else
+ AC_MSG_ERROR([This is a Linux system and neither Linuxthreads nor NPTL were
+found. Please install Linuxthreads or a new glibc and try
+again. See the Installation chapter in the Reference Manual for
+more information.])
+ fi
else
AC_MSG_CHECKING("DEC threads")
if test -f /usr/shlib/libpthread.so -a -f /usr/lib/libmach.a -a -f /usr/ccs/lib/cmplrs/cc/libexc.a
@@ -2209,12 +2218,16 @@ then
man_dirs="man"
man1_files=`ls -1 $srcdir/man/*.1 | sed -e 's;^.*man/;;'`
man1_files=`echo $man1_files`
+ man8_files=`ls -1 $srcdir/man/*.8 | sed -e 's;^.*man/;;'`
+ man8_files=`echo $man8_files`
else
man_dirs=""
man1_files=""
+ man8_files=""
fi
AC_SUBST(man_dirs)
AC_SUBST(man1_files)
+AC_SUBST(man8_files)
# Shall we build the bench code?
AC_ARG_WITH(bench,
diff --git a/include/my_global.h b/include/my_global.h
index aed4ee4fa01..37e53c65dec 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -348,10 +348,7 @@ int __void__;
#endif
/* Define some useful general macros */
-#if defined(__cplusplus) && defined(__GNUC__)
-#define max(a, b) ((a) >? (b))
-#define min(a, b) ((a) <? (b))
-#elif !defined(max)
+#if !defined(max)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
diff --git a/man/Makefile.am b/man/Makefile.am
index 9702c4b2ace..5753259fd3d 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -18,7 +18,8 @@
## Process this file with automake to create Makefile.in
man1_MANS = @man1_files@
-EXTRA_DIST = $(man1_MANS)
+man8_MANS = @man8_files@
+EXTRA_DIST = $(man1_MANS) $(man8_MANS)
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index 6f94e3c4256..2c7e2b28a3d 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -348,7 +348,7 @@ static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key,
else
{
DBUG_PRINT("test",("Inserting of key when deleting"));
- if (_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos,
+ if (!_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos,
&tmp))
goto err;
ret_value=_mi_insert(info,keyinfo,key,leaf_buff,endpos,keybuff,
diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c
index 0ffab05b6bc..c4865315283 100644
--- a/myisam/mi_dynrec.c
+++ b/myisam/mi_dynrec.c
@@ -1095,12 +1095,41 @@ void _my_store_blob_length(byte *pos,uint pack_length,uint length)
}
- /* Read record from datafile */
- /* Returns 0 if ok, -1 if error */
+/*
+ Read record from datafile.
+
+ SYNOPSIS
+ _mi_read_dynamic_record()
+ info MI_INFO pointer to table.
+ filepos From where to read the record.
+ buf Destination for record.
+
+ NOTE
+
+ If a write buffer is active, it needs to be flushed if its contents
+ intersects with the record to read. We always check if the position
+ of the first byte of the write buffer is lower than the position
+ past the last byte to read. In theory this is also true if the write
+ buffer is completely below the read segment. That is, if there is no
+ intersection. But this case is unusual. We flush anyway. Only if the
+ first byte in the write buffer is above the last byte to read, we do
+ not flush.
+
+ A dynamic record may need several reads. So this check must be done
+ before every read. Reading a dynamic record starts with reading the
+ block header. If the record does not fit into the free space of the
+ header, the block may be longer than the header. In this case a
+ second read is necessary. These one or two reads repeat for every
+ part of the record.
+
+ RETURN
+ 0 OK
+ -1 Error
+*/
int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
{
- int flag;
+ int block_of_record;
uint b_type,left_length;
byte *to;
MI_BLOCK_INFO block_info;
@@ -1112,17 +1141,16 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
LINT_INIT(to);
LINT_INIT(left_length);
file=info->dfile;
- block_info.next_filepos=filepos; /* for easyer loop */
- flag=block_info.second_read=0;
+ block_of_record= 0; /* First block of record is numbered as zero. */
+ block_info.second_read= 0;
do
{
if (info->opt_flag & WRITE_CACHE_USED &&
- info->rec_cache.pos_in_file <= block_info.next_filepos &&
+ info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
flush_io_cache(&info->rec_cache))
goto err;
info->rec_cache.seek_not_done=1;
- if ((b_type=_mi_get_block_info(&block_info,file,
- block_info.next_filepos))
+ if ((b_type= _mi_get_block_info(&block_info, file, filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR))
{
@@ -1130,9 +1158,8 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
my_errno=HA_ERR_RECORD_DELETED;
goto err;
}
- if (flag == 0) /* First block */
+ if (block_of_record++ == 0) /* First block */
{
- flag=1;
if (block_info.rec_len > (uint) info->s->base.max_pack_length)
goto panic;
if (info->s->base.blobs)
@@ -1147,11 +1174,35 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
}
if (left_length < block_info.data_len || ! block_info.data_len)
goto panic; /* Wrong linked record */
- if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos,
- MYF(MY_NABP)))
- goto panic;
- left_length-=block_info.data_len;
- to+=block_info.data_len;
+ /* copy information that is already read */
+ {
+ uint offset= (uint) (block_info.filepos - filepos);
+ uint prefetch_len= (sizeof(block_info.header) - offset);
+ filepos+= sizeof(block_info.header);
+
+ if (prefetch_len > block_info.data_len)
+ prefetch_len= block_info.data_len;
+ if (prefetch_len)
+ {
+ memcpy((byte*) to, block_info.header + offset, prefetch_len);
+ block_info.data_len-= prefetch_len;
+ left_length-= prefetch_len;
+ to+= prefetch_len;
+ }
+ }
+ /* read rest of record from file */
+ if (block_info.data_len)
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file < filepos + block_info.data_len &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
+ if (my_read(file, (byte*) to, block_info.data_len, MYF(MY_NABP)))
+ goto panic;
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ }
+ filepos= block_info.next_filepos;
} while (left_length);
info->update|= HA_STATE_AKTIV; /* We have a aktive record */
@@ -1308,11 +1359,45 @@ err:
}
+/*
+ Read record from datafile.
+
+ SYNOPSIS
+ _mi_read_rnd_dynamic_record()
+ info MI_INFO pointer to table.
+ buf Destination for record.
+ filepos From where to read the record.
+ skip_deleted_blocks If to repeat reading until a non-deleted
+ record is found.
+
+ NOTE
+
+ If a write buffer is active, it needs to be flushed if its contents
+ intersects with the record to read. We always check if the position
+ of the first byte of the write buffer is lower than the position
+ past the last byte to read. In theory this is also true if the write
+ buffer is completely below the read segment. That is, if there is no
+ intersection. But this case is unusual. We flush anyway. Only if the
+ first byte in the write buffer is above the last byte to read, we do
+ not flush.
+
+ A dynamic record may need several reads. So this check must be done
+ before every read. Reading a dynamic record starts with reading the
+ block header. If the record does not fit into the free space of the
+ header, the block may be longer than the header. In this case a
+ second read is necessary. These one or two reads repeat for every
+ part of the record.
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
register my_off_t filepos,
- my_bool skipp_deleted_blocks)
+ my_bool skip_deleted_blocks)
{
- int flag,info_read,save_errno;
+ int block_of_record, info_read, save_errno;
uint left_len,b_type;
byte *to;
MI_BLOCK_INFO block_info;
@@ -1338,7 +1423,8 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
else
info_read=1; /* memory-keyinfoblock is ok */
- flag=block_info.second_read=0;
+ block_of_record= 0; /* First block of record is numbered as zero. */
+ block_info.second_read= 0;
left_len=1;
do
{
@@ -1361,15 +1447,15 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
{
if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
sizeof(block_info.header),
- (!flag && skipp_deleted_blocks ? READING_NEXT : 0) |
- READING_HEADER))
+ (!block_of_record && skip_deleted_blocks ?
+ READING_NEXT : 0) | READING_HEADER))
goto panic;
b_type=_mi_get_block_info(&block_info,-1,filepos);
}
else
{
if (info->opt_flag & WRITE_CACHE_USED &&
- info->rec_cache.pos_in_file <= filepos &&
+ info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
flush_io_cache(&info->rec_cache))
DBUG_RETURN(my_errno);
info->rec_cache.seek_not_done=1;
@@ -1380,7 +1466,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
BLOCK_FATAL_ERROR))
{
if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
- && skipp_deleted_blocks)
+ && skip_deleted_blocks)
{
filepos=block_info.filepos+block_info.block_len;
block_info.second_read=0;
@@ -1394,7 +1480,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
}
goto err;
}
- if (flag == 0) /* First block */
+ if (block_of_record == 0) /* First block */
{
if (block_info.rec_len > (uint) share->base.max_pack_length)
goto panic;
@@ -1427,7 +1513,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
left_len-=tmp_length;
to+=tmp_length;
filepos+=tmp_length;
- }
+ }
}
/* read rest of record from file */
if (block_info.data_len)
@@ -1436,11 +1522,17 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
{
if (_mi_read_cache(&info->rec_cache,(byte*) to,filepos,
block_info.data_len,
- (!flag && skipp_deleted_blocks) ? READING_NEXT :0))
+ (!block_of_record && skip_deleted_blocks) ?
+ READING_NEXT : 0))
goto panic;
}
else
{
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <
+ block_info.filepos + block_info.data_len &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
/* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */
if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP)))
{
@@ -1450,10 +1542,14 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
}
}
}
- if (flag++ == 0)
+ /*
+ Increment block-of-record counter. If it was the first block,
+ remember the position behind the block for the next call.
+ */
+ if (block_of_record++ == 0)
{
- info->nextpos=block_info.filepos+block_info.block_len;
- skipp_deleted_blocks=0;
+ info->nextpos= block_info.filepos + block_info.block_len;
+ skip_deleted_blocks= 0;
}
left_len-=block_info.data_len;
to+=block_info.data_len;
@@ -1485,6 +1581,11 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
if (file >= 0)
{
+ /*
+ We do not use my_pread() here because we want to have the file
+ pointer set to the end of the header after this function.
+ my_pread() may leave the file pointer untouched.
+ */
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
if (my_read(file,(char*) header,sizeof(info->header),MYF(0)) !=
sizeof(info->header))
diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c
index 70122288d6c..be99d66618d 100644
--- a/myisam/mi_rkey.c
+++ b/myisam/mi_rkey.c
@@ -66,6 +66,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
if (fast_mi_readinfo(info))
goto err;
+
if (share->concurrent_insert)
rw_rdlock(&share->key_root_lock[inx]);
@@ -77,19 +78,43 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
if (!_mi_search(info,keyinfo, key_buff, use_key_length,
myisam_read_vec[search_flag], info->s->state.key_root[inx]))
{
- while (info->lastpos >= info->state->data_file_length)
+ /*
+ If we searching for a partial key (or using >, >=, < or <=) and
+ the data is outside of the data file, we need to continue searching
+ for the first key inside the data file
+ */
+ if (info->lastpos >= info->state->data_file_length &&
+ (search_flag != HA_READ_KEY_EXACT ||
+ last_used_keyseg != keyinfo->seg + keyinfo->keysegs))
{
- /*
- Skip rows that are inserted by other threads since we got a lock
- Note that this can only happen if we are not searching after an
- exact key, because the keys are sorted according to position
- */
-
- if (_mi_search_next(info, keyinfo, info->lastkey,
- info->lastkey_length,
- myisam_readnext_vec[search_flag],
- info->s->state.key_root[inx]))
- break;
+ do
+ {
+ uint not_used;
+ /*
+ Skip rows that are inserted by other threads since we got a lock
+ Note that this can only happen if we are not searching after an
+ full length exact key, because the keys are sorted
+ according to position
+ */
+ if (_mi_search_next(info, keyinfo, info->lastkey,
+ info->lastkey_length,
+ myisam_readnext_vec[search_flag],
+ info->s->state.key_root[inx]))
+ break;
+ /*
+ Check that the found key does still match the search.
+ _mi_search_next() delivers the next key regardless of its
+ value.
+ */
+ if (search_flag == HA_READ_KEY_EXACT &&
+ _mi_key_cmp(keyinfo->seg, key_buff, info->lastkey, use_key_length,
+ SEARCH_FIND, &not_used))
+ {
+ my_errno= HA_ERR_KEY_NOT_FOUND;
+ info->lastpos= HA_OFFSET_ERROR;
+ break;
+ }
+ } while (info->lastpos >= info->state->data_file_length);
}
}
if (share->concurrent_insert)
diff --git a/myisam/mi_test_all.res b/myisam/mi_test_all.res
index 94355bf1aa2..5c0d05cc977 100644
--- a/myisam/mi_test_all.res
+++ b/myisam/mi_test_all.res
@@ -5,46 +5,46 @@ myisamchk: MyISAM file test2
myisamchk: warning: Datafile is almost full, 65532 of 65534 used
MyISAM-table 'test2' is usable but should be fixed
Commands Used count Errors Recover errors
-open 17 0 0
-write 850 0 0
-update 85 0 0
-delete 850 0 0
-close 17 0 0
-extra 102 0 0
-Total 1921 0 0
+open 7 0 0
+write 350 0 0
+update 35 0 0
+delete 350 0 0
+close 7 0 0
+extra 42 0 0
+Total 791 0 0
Commands Used count Errors Recover errors
-open 18 0 0
-write 900 0 0
-update 90 0 0
-delete 900 0 0
-close 18 0 0
-extra 108 0 0
-Total 2034 0 0
+open 8 0 0
+write 400 0 0
+update 40 0 0
+delete 400 0 0
+close 8 0 0
+extra 48 0 0
+Total 904 0 0
-real 0m1.054s
-user 0m0.410s
-sys 0m0.640s
+real 0m0.221s
+user 0m0.120s
+sys 0m0.100s
-real 0m1.077s
-user 0m0.550s
-sys 0m0.530s
+real 0m0.222s
+user 0m0.140s
+sys 0m0.084s
-real 0m1.100s
-user 0m0.420s
-sys 0m0.680s
+real 0m0.232s
+user 0m0.112s
+sys 0m0.120s
-real 0m0.783s
-user 0m0.590s
-sys 0m0.200s
+real 0m0.163s
+user 0m0.116s
+sys 0m0.036s
-real 0m0.764s
-user 0m0.560s
-sys 0m0.210s
+real 0m0.159s
+user 0m0.136s
+sys 0m0.020s
-real 0m0.699s
-user 0m0.570s
-sys 0m0.130s
+real 0m0.147s
+user 0m0.132s
+sys 0m0.016s
-real 0m0.991s
-user 0m0.630s
-sys 0m0.350s
+real 0m0.211s
+user 0m0.124s
+sys 0m0.088s
diff --git a/myisam/mi_test_all.sh b/myisam/mi_test_all.sh
index 07e71d65675..c1fb12d7c3b 100755
--- a/myisam/mi_test_all.sh
+++ b/myisam/mi_test_all.sh
@@ -79,7 +79,8 @@ myisamchk$suffix -se test1
# check of myisampack / myisamchk
myisampack$suffix --force -s test1
-myisamchk$suffix -es test1
+# Ignore error for index file
+myisamchk$suffix -es test1 2>&1 >& /dev/null
myisamchk$suffix -rqs test1
myisamchk$suffix -es test1
myisamchk$suffix -rs test1
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 6fefbb16353..1feda854014 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -436,3 +436,10 @@ id aes_decrypt(str, 'bar')
1 foo
2 NULL
DROP TABLE t1, t2;
+create table t1(a varchar(8), primary key(a));
+insert into t1 values('bar'), ('foo');
+select a from t1 where a=elt(1, 'foo', 'bar') or a=elt(2, 'foo', 'bar');
+a
+bar
+foo
+drop table t1;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index e6df3499eb5..9d8e8289667 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -472,3 +472,31 @@ select c1 from t1 order by c1 limit 1;
c1
a
drop table t1;
+create table t1 (a int not null, primary key(a));
+create table t2 (a int not null, b int not null, primary key(a,b));
+insert into t1 values (1),(2),(3),(4),(5),(6);
+insert into t2 values (1,1),(2,1);
+lock tables t1 read local, t2 read local;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+a a b
+1 1 1
+2 2 1
+insert into t2 values(2,0);
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+a a b
+1 1 1
+2 2 1
+drop table t1,t2;
+CREATE TABLE t1 (c1 varchar(250) NOT NULL);
+CREATE TABLE t2 (c1 varchar(250) NOT NULL, PRIMARY KEY (c1));
+INSERT INTO t1 VALUES ('test000001'), ('test000002'), ('test000003');
+INSERT INTO t2 VALUES ('test000002'), ('test000003'), ('test000004');
+LOCK TABLES t1 READ LOCAL, t2 READ LOCAL;
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+t1c1 t2c1
+INSERT INTO t2 VALUES ('test000001'), ('test000005');
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+t1c1 t2c1
+DROP TABLE t1,t2;
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 81d5daaf0ba..0e7ab70940a 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -254,3 +254,11 @@ SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id
DROP TABLE t1, t2;
+#
+# Bug #12728: strange elt() behavior
+#
+
+create table t1(a varchar(8), primary key(a));
+insert into t1 values('bar'), ('foo');
+select a from t1 where a=elt(1, 'foo', 'bar') or a=elt(2, 'foo', 'bar');
+drop table t1;
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index a502002d30e..83d93686429 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -458,3 +458,38 @@ insert into t1 values ('a'), ('b');
select c1 from t1 order by c1 limit 1;
drop table t1;
+#
+# Bug #14400 Join could miss concurrently inserted row
+#
+# Partial key.
+create table t1 (a int not null, primary key(a));
+create table t2 (a int not null, b int not null, primary key(a,b));
+insert into t1 values (1),(2),(3),(4),(5),(6);
+insert into t2 values (1,1),(2,1);
+lock tables t1 read local, t2 read local;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock);
+insert into t2 values(2,0);
+disconnect root;
+connection default;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+drop table t1,t2;
+#
+# Full key.
+CREATE TABLE t1 (c1 varchar(250) NOT NULL);
+CREATE TABLE t2 (c1 varchar(250) NOT NULL, PRIMARY KEY (c1));
+INSERT INTO t1 VALUES ('test000001'), ('test000002'), ('test000003');
+INSERT INTO t2 VALUES ('test000002'), ('test000003'), ('test000004');
+LOCK TABLES t1 READ LOCAL, t2 READ LOCAL;
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+ WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+connect (con1,localhost,root,,);
+connection con1;
+INSERT INTO t2 VALUES ('test000001'), ('test000005');
+disconnect con1;
+connection default;
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+ WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+DROP TABLE t1,t2;
+
+# end of 4.0 tests
diff --git a/mysys/my_lread.c b/mysys/my_lread.c
index 601d772b844..a96febe4474 100644
--- a/mysys/my_lread.c
+++ b/mysys/my_lread.c
@@ -30,6 +30,8 @@ uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags)
DBUG_PRINT("my",("Fd: %d Buffer: %ld Count: %ld MyFlags: %d",
Filedes, Buffer, Count, MyFlags));
+ DBUG_PRINT("error", ("Deprecated my_lread() function should not be used."));
+
/* Temp hack to get count to int32 while read wants int */
if ((readbytes = (uint32) read(Filedes, Buffer, (uint) Count)) != Count)
{
diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c
index e1a3decd053..cfdbd5d4576 100644
--- a/mysys/my_lwrite.c
+++ b/mysys/my_lwrite.c
@@ -26,6 +26,8 @@ uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags)
DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %ld MyFlags: %d",
Filedes, Buffer, Count, MyFlags));
+ DBUG_PRINT("error", ("Deprecated my_lwrite() function should not be used."));
+
/* Temp hack to get count to int32 while write wants int */
if ((writenbytes = (uint32) write(Filedes, Buffer, (uint) Count)) != Count)
{
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index f76233fc4cc..70990ad12a6 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -52,8 +52,12 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
readbytes,Count,Filedes,my_errno));
#ifdef THREAD
- if (readbytes == 0 && errno == EINTR)
- continue; /* Interrupted */
+ if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
+ {
+ DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d",
+ (int) readbytes));
+ continue; /* Interrupted */
+ }
#endif
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
@@ -124,8 +128,8 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
continue;
}
- if ((writenbytes == 0 && my_errno == EINTR) ||
- (writenbytes > 0 && (uint) writenbytes != (uint) -1))
+ if ((writenbytes > 0 && (uint) writenbytes != (uint) -1) ||
+ my_errno == EINTR)
continue; /* Retry */
#endif
if (MyFlags & (MY_NABP | MY_FNABP))
diff --git a/mysys/my_quick.c b/mysys/my_quick.c
index 44ed3fc0b2c..ffc8160c371 100644
--- a/mysys/my_quick.c
+++ b/mysys/my_quick.c
@@ -26,6 +26,14 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags)
if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
{
+#ifndef DBUG_OFF
+ if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
+ {
+ DBUG_PRINT("error", ("my_quick_read() was interrupted and returned %d"
+ ". This function does not retry the read!",
+ (int) readbytes));
+ }
+#endif
my_errno=errno;
return readbytes;
}
@@ -35,8 +43,24 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags)
uint my_quick_write(File Filedes,const byte *Buffer,uint Count)
{
- if ((uint) write(Filedes,Buffer,Count) != Count)
+#ifndef DBUG_OFF
+ uint writtenbytes;
+#endif
+
+ if ((
+#ifndef DBUG_OFF
+ writtenbytes =
+#endif
+ (uint) write(Filedes,Buffer,Count)) != Count)
{
+#ifndef DBUG_OFF
+ if ((writtenbytes == 0 || (int) writtenbytes == -1) && errno == EINTR)
+ {
+ DBUG_PRINT("error", ("my_quick_write() was interrupted and returned %d"
+ ". This function does not retry the write!",
+ (int) writtenbytes));
+ }
+#endif
my_errno=errno;
return (uint) -1;
}
diff --git a/mysys/my_read.c b/mysys/my_read.c
index bca28694295..ff47a7c67f9 100644
--- a/mysys/my_read.c
+++ b/mysys/my_read.c
@@ -51,10 +51,11 @@ uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
readbytes, Count, Filedes, my_errno));
#ifdef THREAD
- if ((int) readbytes <= 0 && errno == EINTR)
- {
- DBUG_PRINT("debug", ("my_read() was interrupted and returned %d", (int) readbytes));
- continue; /* Interrupted */
+ if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
+ {
+ DBUG_PRINT("debug", ("my_read() was interrupted and returned %d",
+ (int) readbytes));
+ continue; /* Interrupted */
}
#endif
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
diff --git a/mysys/my_write.c b/mysys/my_write.c
index 1d1a893090a..de762c16a07 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -57,18 +57,24 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
continue;
}
- if (!writenbytes)
+
+ if ((writenbytes == 0 || (int) writenbytes == -1))
{
- /* We may come here on an interrupt or if the file quote is exeeded */
if (my_errno == EINTR)
- continue;
- if (!errors++) /* Retry once */
{
- errno=EFBIG; /* Assume this is the error */
- continue;
+ DBUG_PRINT("debug", ("my_write() was interrupted and returned %d",
+ (int) writenbytes));
+ continue; /* Interrupted */
+ }
+
+ if (!writenbytes && !errors++) /* Retry once */
+ {
+ /* We may come here if the file quota is exeeded */
+ errno=EFBIG; /* Assume this is the error */
+ continue;
}
}
- else if ((uint) writenbytes != (uint) -1)
+ else
continue; /* Retry */
#endif
if (MyFlags & (MY_NABP | MY_FNABP))
diff --git a/netware/BUILD/mwasmnlm b/netware/BUILD/mwasmnlm
index 381f84ec0c8..11fc2bc3842 100755
--- a/netware/BUILD/mwasmnlm
+++ b/netware/BUILD/mwasmnlm
@@ -5,4 +5,7 @@ set -e
args=" $*"
-wine --debugmsg -all -- mwasmnlm $args
+# NOTE: Option 'pipefail' is not standard sh
+set -o pipefail
+wine --debugmsg -all -- mwasmnlm $args | \
+perl -pe 's/\r//g; s/^\e.*\e(\[J|>)?//; s/[[^:print:]]//g'
diff --git a/netware/BUILD/mwccnlm b/netware/BUILD/mwccnlm
index cb2d62fe8cf..e6840e781f8 100755
--- a/netware/BUILD/mwccnlm
+++ b/netware/BUILD/mwccnlm
@@ -7,4 +7,7 @@ set -e
# convert it to "-I../include"
args=" "`echo $* | sed -e 's/-I.\/../-I../g'`
-wine --debugmsg -all -- mwccnlm $args
+# NOTE: Option 'pipefail' is not standard sh
+set -o pipefail
+wine --debugmsg -all -- mwccnlm $args | \
+perl -pe 's/\r//g; s/^\e.*\e(\[J|>)?//; s/[[^:print:]]//g'
diff --git a/netware/BUILD/mwldnlm b/netware/BUILD/mwldnlm
index 28566fc5cb1..cc8c9e63c6e 100755
--- a/netware/BUILD/mwldnlm
+++ b/netware/BUILD/mwldnlm
@@ -5,4 +5,7 @@ set -e
args=" $*"
-wine --debugmsg -all -- mwldnlm $args
+# NOTE: Option 'pipefail' is not standard sh
+set -o pipefail
+wine --debugmsg -all -- mwldnlm $args | \
+perl -pe 's/\r//g; s/^\e.*\e(\[J|>)?//; s/[[^:print:]]//g'
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index f372762c05d..ae24752d290 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -70,7 +70,7 @@ mkdir $BASE $BASE/bin $BASE/docs \
if [ $BASE_SYSTEM != "netware" ] ; then
mkdir $BASE/share/mysql $BASE/tests $BASE/sql-bench $BASE/man \
- $BASE/man/man1 $BASE/data $BASE/data/mysql $BASE/data/test
+ $BASE/man/man1 $BASE/man/man8 $BASE/data $BASE/data/mysql $BASE/data/test
chmod o-rwx $BASE/data $BASE/data/*
fi
@@ -154,11 +154,21 @@ if [ $BASE_SYSTEM = "netware" ] ; then
fi
for i in \
- libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* \
- libmysql/libmysqlclient.* libmysql_r/.libs/libmysqlclient_r.a \
- libmysql_r/.libs/libmysqlclient_r.so* libmysql_r/libmysqlclient_r.* \
+ libmysql/.libs/libmysqlclient.a \
+ libmysql/.libs/libmysqlclient.so* \
+ libmysql/.libs/libmysqlclient.sl* \
+ libmysql/.libs/libmysqlclient*.dylib \
+ libmysql/libmysqlclient.* \
+ libmysql_r/.libs/libmysqlclient_r.a \
+ libmysql_r/.libs/libmysqlclient_r.so* \
+ libmysql_r/.libs/libmysqlclient_r.sl* \
+ libmysql_r/.libs/libmysqlclient_r*.dylib \
+ libmysql_r/libmysqlclient_r.* \
+ libmysqld/.libs/libmysqld.a \
+ libmysqld/.libs/libmysqld.so* \
+ libmysqld/.libs/libmysqld.sl* \
+ libmysqld/.libs/libmysqld*.dylib \
mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a \
- libmysqld/.libs/libmysqld.a libmysqld/.libs/libmysqld.so* \
libmysqld/libmysqld.a netware/libmysql.imp
do
if [ -f $i ]
@@ -188,6 +198,7 @@ if [ $BASE_SYSTEM != "netware" ] ; then
fi
if [ -d man ] ; then
$CP man/*.1 $BASE/man/man1
+ $CP man/*.8 $BASE/man/man8
fi
fi
@@ -245,7 +256,6 @@ else
fi
# Make safe_mysqld a symlink to mysqld_safe for backwards portability
-# To be removed in MySQL 4.1
(cd $BASE/bin ; ln -s mysqld_safe safe_mysqld )
# Clean up if we did this from a bk tree
diff --git a/scripts/make_sharedlib_distribution.sh b/scripts/make_sharedlib_distribution.sh
index fbc945e445a..c475d0e14a4 100644
--- a/scripts/make_sharedlib_distribution.sh
+++ b/scripts/make_sharedlib_distribution.sh
@@ -45,9 +45,11 @@ fi
mkdir -p $BASE/lib
for i in \
- libmysql/.libs/libmysqlclient.s{l,o}* \
+ libmysql/.libs/libmysqlclient.so* \
+ libmysql/.libs/libmysqlclient.sl* \
libmysql/.libs/libmysqlclient*.dylib \
- libmysql_r/.libs/libmysqlclient_r.s{l,o}* \
+ libmysql_r/.libs/libmysqlclient_r.so* \
+ libmysql_r/.libs/libmysqlclient_r.sl* \
libmysql_r/.libs/libmysqlclient_r*.dylib
do
if [ -f $i ]
diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh
index f9e29e33195..b3ea9dc4035 100644
--- a/scripts/mysqlhotcopy.sh
+++ b/scripts/mysqlhotcopy.sh
@@ -262,6 +262,7 @@ my $hc_locks = "";
my $hc_tables = "";
my $num_tables = 0;
my $num_files = 0;
+my $raid_dir_regex = '[A-Za-z0-9]{2}';
foreach my $rdb ( @db_desc ) {
my $db = $rdb->{src};
@@ -296,7 +297,7 @@ foreach my $rdb ( @db_desc ) {
my @raid_dir = ();
while ( defined( my $name = readdir DBDIR ) ) {
- if ( $name =~ /^\d\d$/ && -d "$db_dir/$name" ) {
+ if ( $name =~ /^$raid_dir_regex$/ && -d "$db_dir/$name" ) {
push @raid_dir, $name;
}
else {
@@ -604,7 +605,7 @@ sub copy_files {
# add recursive option for scp
$cp.= " -r" if $^O =~ /m^(solaris|linux|freebsd|darwin)$/ && $method =~ /^scp\b/;
- my @non_raid = map { "'$_'" } grep { ! m:/\d{2}/[^/]+$: } @$files;
+ my @non_raid = map { "'$_'" } grep { ! m:/$raid_dir_regex/[^/]+$: } @$files;
# add files to copy and the destination directory
safe_system( $cp, @non_raid, "'$target'" ) if (@non_raid);
@@ -797,7 +798,7 @@ sub get_raid_dirs {
my %dirs = ();
foreach my $f ( @$r_files ) {
- if ( $f =~ m:^(\d\d)/: ) {
+ if ( $f =~ m:^($raid_dir_regex)/: ) {
$dirs{$1} = 1;
}
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 3627af4ebb1..3336f2afd1b 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -120,7 +120,10 @@ public:
{
return (null_value=args[0]->get_time(ltime));
}
- bool is_null() { (void) val_int(); return null_value; }
+ bool is_null() {
+ (void) val_int(); /* Discard result. It sets null_value as side-effect. */
+ return null_value;
+ }
friend class udf_handler;
unsigned int size_of() { return sizeof(*this);}
Field *tmp_table_field(TABLE *t_arg);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index f070382e5c1..81e3129471c 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -51,14 +51,14 @@ double Item_str_func::val()
{
String *res;
res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? atof(res->c_ptr_safe()) : 0.0;
}
longlong Item_str_func::val_int()
{
String *res;
res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),NULL,10) : (longlong) 0;
+ return res ? strtoll(res->c_ptr_safe(),NULL,10) : (longlong) 0;
}
@@ -1599,6 +1599,17 @@ String *Item_func_elt::val_str(String *str)
}
+bool Item_func_elt::eq(const Item *par_item, bool binary_cmp) const
+{
+ /*
+ We can use (Item_func_elt*) typecast here because the check is done
+ in the Item_func::eq().
+ */
+ return Item_func::eq(par_item, binary_cmp) &&
+ item->eq(((Item_func_elt*) par_item)->item, binary_cmp);
+}
+
+
void Item_func_make_set::split_sum_func(List<Item> &fields)
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index ece15484fd9..482a941c55b 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -372,6 +372,7 @@ public:
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "elt"; }
+ bool eq(const Item *par_item, bool binary_cmp) const;
unsigned int size_of() { return sizeof(*this);}
};
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 66d23ada163..f8cf8a7a58e 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -477,7 +477,7 @@ bool select_send::send_data(List<Item> &items)
{
List_iterator_fast<Item> li(items);
String *packet= &thd->packet;
- DBUG_ENTER("send_data");
+ DBUG_ENTER("select_send::send_data");
#ifdef HAVE_INNOBASE_DB
/* We may be passing the control from mysqld to the client: release the
@@ -611,7 +611,7 @@ select_export::prepare(List<Item> &list)
bool select_export::send_data(List<Item> &items)
{
- DBUG_ENTER("send_data");
+ DBUG_ENTER("select_export::send_data");
char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
bool space_inited=0;
String tmp(buff,sizeof(buff)),*res;
@@ -828,7 +828,7 @@ bool select_dump::send_data(List<Item> &items)
String tmp(buff,sizeof(buff)),*res;
tmp.length(0);
Item *item;
- DBUG_ENTER("send_data");
+ DBUG_ENTER("select_dump::send_data");
if (thd->offset_limit)
{ // using limit offset,count
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 32658f92416..e28bc81753d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7222,6 +7222,8 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
param->copy_funcs.empty();
while ((pos=li++))
{
+ Field *field;
+ char *tmp;
if (pos->type() == Item::FIELD_ITEM)
{
Item_field *item=(Item_field*) pos;
@@ -7245,13 +7247,21 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
}
/* set up save buffer and change result_field to point at saved value */
- Field *field= item->field;
+ field= item->field;
item->result_field=field->new_field(&thd->mem_root,field->table);
- char *tmp=(char*) sql_alloc(field->pack_length()+1);
+ /*
+ We need to allocate one extra byte for null handling and
+ another extra byte to not get warnings from purify in
+ Field_string::val_int
+ */
+ tmp= (char*) sql_alloc(field->pack_length()+2);
if (!tmp)
goto err;
copy->set(tmp, item->result_field);
item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
+#ifdef HAVE_purify
+ copy->to_ptr[copy->from_length]= 0;
+#endif
copy++;
}
else if ((pos->type() == Item::FUNC_ITEM ||
diff --git a/sql/sql_string.h b/sql/sql_string.h
index ad7455ecbf1..25abfd27eef 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -74,6 +74,14 @@ public:
Ptr[str_length]=0;
return Ptr;
}
+ inline char *c_ptr_safe()
+ {
+ if (Ptr && str_length < Alloced_length)
+ Ptr[str_length]=0;
+ else
+ (void) realloc(str_length);
+ return Ptr;
+ }
void set(String &str,uint32 offset,uint32 arg_length)
{
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 5796e776b83..2958e857049 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -444,7 +444,7 @@ fi
%doc %attr(644, root, man) %{_mandir}/man1/myisamchk.1*
%doc %attr(644, root, man) %{_mandir}/man1/myisamlog.1*
%doc %attr(644, root, man) %{_mandir}/man1/myisampack.1*
-%doc %attr(644, root, man) %{_mandir}/man1/mysqld.1*
+%doc %attr(644, root, man) %{_mandir}/man8/mysqld.8*
%doc %attr(644, root, man) %{_mandir}/man1/mysqld_multi.1*
%doc %attr(644, root, man) %{_mandir}/man1/mysqld_safe.1*
%doc %attr(644, root, man) %{_mandir}/man1/mysql_fix_privilege_tables.1*