Commit fcf27382 authored by unknown's avatar unknown

Merge marko@build.mysql.com:/home/bk/mysql-4.0

into hundin.mysql.fi:/home/marko/k/mysql-4.0

parents cf51de6d 34474695
......@@ -35,6 +35,7 @@ greg@mysql.com
guilhem@mysql.com
gweir@build.mysql.com
gweir@work.mysql.com
hartmut@mysql.com
heikki@donna.mysql.fi
heikki@hundin.mysql.fi
heikki@rescue.
......
#!/usr/bin/perl -i
#!/usr/bin/perl -wi
# Untar a MySQL distribution, change the copyright texts,
# pack it up again to a given directory
$VER="1.3";
$VER="1.4";
use Cwd;
use File::Basename;
......@@ -79,7 +79,7 @@ sub main
$newdistname .= $suffix if $win_flag;
}
# find out the extract path (should be same as distname!)
chomp($destdir = `tar ztf ../$distfile | head -1`);
chomp($destdir= `tar ztf ../$distfile | head -1`);
# remove slash from the end
$destdir= substr($destdir, 0, -1);
......@@ -104,37 +104,25 @@ sub main
unlink("$destdir/COPYING", "$destdir/EXCEPTIONS-CLIENT");
copy("$WD/Docs/MySQLEULA.txt", "$destdir");
# remove readline subdir and update configure accordingly
system("rm -rf $destdir/cmd-line-utils/readline");
if ($win_flag) {
chdir("$destdir") or (print "$! Unable to change directory to $destdir!\n" && exit(0));
} else {
chdir("$destdir");
unlink ("configure") or die "Can't delete $destdir/configure: $!\n";
open(CONFIGURE,"<configure.in") or die "$! Unable to open configure.in to read from!\n";
local $/;
undef $/;
my $configure = <CONFIGURE>;
close(CONFIGURE);
$configure =~ s|cmd\-line\-utils/readline/Makefile dnl\n?||g;
open(CONFIGURE,">configure.in") or die "$! Unable to open configure.in to write to!\n";
print CONFIGURE $configure;
close(CONFIGURE);
`aclocal && autoheader && aclocal && automake && autoconf`;
if (! -f "configure") {
print "\"./configure\" was not produced, exiting!\n";
exit(0);
}
if (-d "autom4te.cache") {
print "Trying to delete autom4te.cache dir\n" if $opt_verbose;
system("rm -rf autom4te.cache") or print "Unable to delete autom4te.cache dir: $!\n";
}
# remove subdirectories 'bdb', 'cmd-line-utils/readline'
# (latter does not apply to 4.0, but is in different place there!)
my @extra_fat= ('bdb', 'cmd-line-utils/readline');
foreach my $fat (@extra_fat)
{
&trim_the_fat($fat);
}
# fix file copyrights
&fix_usage_copyright();
&add_copyright();
# fix LICENSE tag in include/mysql_version.h
&fix_mysql_version();
# apply "autotools" - must be last to ensure proper timestamps
&run_autotools();
# rename the directory with new distribution name
chdir("$WD/$dir");
print "renaming $destdir $newdistname\n" if $opt_verbose;
......@@ -160,6 +148,101 @@ sub main
exit(0);
}
####
#### This function will s/GPL/Commercial/ in include/mysql_version.h for the
#### LICENSE tag.
####
sub fix_mysql_version
{
my $cwd= getcwd();
chdir("$destdir");
my $header_file= (-f 'include/mysql_version.h.in')? 'include/mysql_version.h.in' : 'include/mysql_version.h';
open(MYSQL_VERSION,"<$header_file") or die "Unable to open $header_file for read: $!\n";
undef $/;
my $mysql_version= <MYSQL_VERSION>;
close(MYSQL_VERSION);
$mysql_version=~ s/\#define LICENSE[\s\t]+GPL/#define LICENSE Commercial/;
open(MYSQL_VERSION,">$header_file") or die "Unable to open $header_file for write: $!\n";
print MYSQL_VERSION $mysql_version;
close(MYSQL_VERSION);
chdir("$cwd");
}
####
#### This function will remove unwanted parts of a src tree for the mysqlcom
#### distributions.
####
sub trim_the_fat
{
my $the_fat= shift;
my $cwd= getcwd();
chdir("$destdir");
if ( -d "${the_fat}" )
{
system("rm -rf ${the_fat}");
if (!$win_flag)
{
open(CONFIG_IN,"<configure.in") or die "Unable to open configure.in for read: $!\n";
undef $/;
my $config_in= <CONFIG_IN>;
close(CONFIG_IN);
#
# If $the_fat Makefile line closes the parenthesis, then
# replace that line with just the closing parenthesis.
#
if ($config_in=~ m|${the_fat}/Makefile\)\n?|)
{
$config_in=~ s|${the_fat}/Makefile(\)\n?)|$1|;
}
#
# Else just delete the line
#
else
{
$config_in=~ s|${the_fat}/Makefile dnl\n?||;
}
open(CONFIG_IN,">configure.in") or die "Unable to open configure.in for write: $!\n";
print CONFIG_IN $config_in;
close(CONFIG_IN);
}
}
chdir("$cwd");
}
####
#### This function will run the autotools on the reduced source tree.
####
sub run_autotools
{
my $cwd= getcwd();
if (!$win_flag)
{
chdir("$destdir");
unlink ("configure") or die "Can't delete $destdir/configure: $!\n";
# File "configure.in" has already been modified by "trim_the_fat()"
`aclocal && autoheader && aclocal && automake && autoconf`;
die "'./configure' was not produced!" unless (-f "configure");
if (-d "autom4te.cache") {
print "Trying to delete autom4te.cache dir\n" if $opt_verbose;
system("rm -rf autom4te.cache") or print "Unable to delete autom4te.cache dir: $!\n";
}
chdir("$cwd");
}
}
####
#### mysqld and MySQL client programs have a usage printed with --help.
#### This usage includes a copyright, which needs to be modified
......@@ -191,6 +274,7 @@ sub add_copyright
foreach my $file (@files)
{
next if ! -f $file;
next if -B $file;
print "processing file $file in cwd $cwd\n" if $opt_verbose;
`$WD/Build-tools/mysql-copyright-2 "$file"`;
}
......
......@@ -22,7 +22,7 @@ AUTOMAKE_OPTIONS = foreign
EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT
SUBDIRS = . include @docs_dirs@ @readline_dir@ \
@thread_dirs@ pstack @sql_client_dirs@ \
@sql_server_dirs@ scripts man tests \
@sql_server_dirs@ scripts @man_dirs@ tests \
BUILD netware os2 @libmysqld_dirs@ \
@bench_dirs@ support-files @fs_dirs@ @tools_dirs@
......
......@@ -788,7 +788,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [
AC_DEFUN(MYSQL_CHECK_OPENSSL, [
AC_MSG_CHECKING(for OpenSSL)
AC_ARG_WITH([openssl],
[ --with-openssl Include the OpenSSL support],
[ --with-openssl[=DIR] Include the OpenSSL support],
[openssl="$withval"],
[openssl=no])
......@@ -806,8 +806,19 @@ AC_MSG_CHECKING(for OpenSSL)
[openssl_libs="$withval"],
[openssl_libs=""])
if test "$openssl" = "yes"
if test "$openssl" != "no"
then
if test "$openssl" != "yes"
then
if test -z "$openssl_includes"
then
openssl_includes="$openssl/include"
fi
if test -z "$openssl_libs"
then
openssl_libs="$openssl/lib"
fi
fi
MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs])
#force VIO use
vio_dir="vio"
......@@ -843,6 +854,14 @@ AC_MSG_CHECKING(for OpenSSL)
NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS $openssl_libs"
else
AC_MSG_RESULT(no)
if test ! -z "$openssl_includes"
then
AC_MSG_ERROR(Can't have --with-openssl-includes without --with-openssl);
fi
if test ! -z "$openssl_libs"
then
AC_MSG_ERROR(Can't have --with-openssl-libs without --with-openssl);
fi
fi
AC_SUBST(openssl_libs)
AC_SUBST(openssl_includes)
......
......@@ -150,7 +150,7 @@ static struct my_option my_long_options[] =
"Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed,
(gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
{"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
(gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, NO_ARG, 0, 0, 0, 0, 0, 0},
(gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"first-slave", 'x', "Locks all tables across all databases.",
(gptr*) &opt_first_slave, (gptr*) &opt_first_slave, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
......
......@@ -2181,6 +2181,21 @@ else
fi
AC_SUBST(docs_dirs)
# Shall we build the man pages?
AC_ARG_WITH(man,
[ --without-man Skip building of the man pages.],
[with_man=$withval],
[with_man=yes]
)
if test "$with_man" = "yes"
then
man_dirs="man"
else
man_dirs=""
fi
AC_SUBST(man_dirs)
# Shall we build the bench code?
AC_ARG_WITH(bench,
[ --without-bench Skip building of the benchmark suite.],
......
......@@ -96,6 +96,7 @@ typedef struct st_mi_create_info
ha_rows reloc_rows;
ulonglong auto_increment;
ulonglong data_file_length;
ulonglong key_file_length;
uint raid_type,raid_chunks;
ulong raid_chunksize;
uint old_options;
......
......@@ -2965,9 +2965,11 @@ os_aio_print(
srv_io_thread_op_info[i],
srv_io_thread_function[i]);
#ifndef __WIN__
if (os_aio_segment_wait_events[i]->is_set) {
fprintf(file, " ev set");
}
#endif
fprintf(file, "\n");
}
......
......@@ -3520,7 +3520,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
create_info.raid_chunksize= share.base.raid_chunksize;
create_info.language = (param->language ? param->language :
share.state.header.language);
create_info.key_file_length= status_info.key_file_length;
/* We don't have to handle symlinks here because we are using
HA_DONT_TOUCH_DATA */
if (mi_create(filename,
......
......@@ -70,7 +70,8 @@ int mi_close(register MI_INFO *info)
error=my_errno;
if (share->kfile >= 0)
{
if (share->mode != O_RDONLY && mi_is_crashed(info))
/* We must always flush the state with the current open_count. */
if (share->mode != O_RDONLY)
mi_state_info_write(share->kfile, &share->state, 1);
if (my_close(share->kfile,MYF(0)))
error = my_errno;
......
......@@ -46,7 +46,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
ulong reclength, real_reclength,min_pack_length;
char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
ulong pack_reclength;
ulonglong tot_length,max_rows;
ulonglong tot_length,max_rows, tmp;
enum en_fieldtype type;
MYISAM_SHARE share;
MI_KEYDEF *keydef,tmp_keydef;
......@@ -442,10 +442,15 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.state.auto_increment=ci->auto_increment;
share.options=options;
share.base.rec_reflength=pointer;
/* Get estimate for index file length (this may be wrong for FT keys) */
tmp= (tot_length + max_key_block_length * keys *
MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
/*
use maximum of key_file_length we calculated and key_file_length value we
got from MYI file header (see also myisampack.c:save_state)
*/
share.base.key_reflength=
mi_get_pointer_length((tot_length + max_key_block_length * keys *
MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH,
3);
mi_get_pointer_length(max(ci->key_file_length,tmp),3);
share.base.keys= share.state.header.keys = keys;
share.state.header.uniques= uniques;
mi_int2store(share.state.header.key_parts,key_segs);
......
......@@ -26,6 +26,9 @@
#include <errno.h>
#endif
static int mi_unlock_open_count(MI_INFO *info, my_bool write_info);
/* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
int mi_lock_database(MI_INFO *info, int lock_type)
......@@ -35,7 +38,12 @@ int mi_lock_database(MI_INFO *info, int lock_type)
MYISAM_SHARE *share=info->s;
uint flag;
DBUG_ENTER("mi_lock_database");
DBUG_PRINT("info",("lock_type: %d", lock_type));
DBUG_PRINT("enter",("mi_lock_database: lock_type %d, old lock %d"
", r_locks %u, w_locks %u", lock_type,
info->lock_type, share->r_locks, share->w_locks));
DBUG_PRINT("enter",("mi_lock_database: gl._changed %d, open_count %u '%s'",
share->global_changed, share->state.open_count,
share->index_file_name));
if (share->options & HA_OPTION_READ_ONLY_DATA ||
info->lock_type == lock_type)
......@@ -54,7 +62,6 @@ int mi_lock_database(MI_INFO *info, int lock_type)
{
switch (lock_type) {
case F_UNLCK:
DBUG_PRINT("info", ("old lock: %d", info->lock_type));
if (info->lock_type == F_RDLCK)
count= --share->r_locks;
else
......@@ -83,7 +90,8 @@ int mi_lock_database(MI_INFO *info, int lock_type)
share->state.process= share->last_process=share->this_process;
share->state.unique= info->last_unique= info->this_unique;
share->state.update_count= info->last_loop= ++info->this_loop;
if (mi_state_info_write(share->kfile, &share->state, 1))
if (mi_unlock_open_count(info, FALSE) ||
mi_state_info_write(share->kfile, &share->state, 1))
error=my_errno;
share->changed=0;
if (myisam_flush)
......@@ -98,6 +106,19 @@ int mi_lock_database(MI_INFO *info, int lock_type)
if (error)
mi_mark_crashed(info);
}
else
{
/*
There are chances that _mi_mark_file_changed() has been called,
while share->changed remained FALSE. Consequently, we need to
clear the open_count even when share->changed is FALSE. Note,
that mi_unlock_open_count() will only clear the open_count when
it is set and only write the status to file, if it changes it
and we are running --with-external-locking.
*/
if (mi_unlock_open_count(info, ! my_disable_locking))
error= my_errno;
}
if (info->lock_type != F_EXTRA_LCK)
{
if (share->r_locks)
......@@ -122,10 +143,15 @@ int mi_lock_database(MI_INFO *info, int lock_type)
case F_RDLCK:
if (info->lock_type == F_WRLCK)
{ /* Change RW to READONLY */
/*
mysqld does not turn write locks to read locks,
so we're never here in mysqld.
*/
if (share->w_locks == 1)
{
flag=1;
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
if (mi_unlock_open_count(info, ! my_disable_locking) ||
my_lock(share->kfile,lock_type,0L,F_TO_EOF,
MYF(MY_SEEK_NOT_DONE)))
{
error=my_errno;
......@@ -153,6 +179,14 @@ int mi_lock_database(MI_INFO *info, int lock_type)
my_errno=error;
break;
}
if (share->state.open_count)
{
DBUG_PRINT("error",("RD: Table has not been correctly unlocked"
": open_count %d '%s'",
share->state.open_count,
share->index_file_name));
mi_mark_crashed(info);
}
}
VOID(_mi_test_if_changed(info));
share->r_locks++;
......@@ -198,6 +232,14 @@ int mi_lock_database(MI_INFO *info, int lock_type)
my_errno=error;
break;
}
if (share->state.open_count)
{
DBUG_PRINT("error",("WR: Table has not been correctly unlocked"
": open_count %d '%s'",
share->state.open_count,
share->index_file_name));
mi_mark_crashed(info);
}
}
}
}
......@@ -459,3 +501,36 @@ int _mi_decrement_open_count(MI_INFO *info)
}
return test(lock_error || write_error);
}
/*
Decrement open_count in preparation for unlock.
SYNOPSIS
mi_unlock_open_count()
info Pointer to the MI_INFO structure.
write_info If info must be written when changed.
RETURN
0 OK
*/
static int mi_unlock_open_count(MI_INFO *info, my_bool write_info)
{
int rc= 0;
MYISAM_SHARE *share=info->s;
DBUG_ENTER("mi_unlock_open_count");
DBUG_PRINT("enter",("mi_unlock_open_count: gl._changed %d open_count %d '%s'",
share->global_changed, share->state.open_count,
share->index_file_name));
if (share->global_changed)
{
share->global_changed= 0;
if (share->state.open_count)
share->state.open_count--;
if (write_info)
rc= _mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE);
}
DBUG_RETURN(rc);
}
......@@ -2041,7 +2041,11 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length,
share->state.split=(ha_rows) mrg->records;
share->state.version=(ulong) time((time_t*) 0);
share->state.key_map=0;
share->state.state.key_file_length=share->base.keystart;
/*
Don't save key_file_length here, keep key_file_length of original file
so "myisamchk -rq" can use this value (this is necessary because index
size cannot be easily calculated for fulltext keys)
*/
for (key=0 ; key < share->base.keys ; key++)
share->state.key_root[key]= HA_OFFSET_ERROR;
for (key=0 ; key < share->state.header.max_block_size ; key++)
......
......@@ -64,3 +64,6 @@ select if(1>2,a,avg(a)) from t1;
if(1>2,a,avg(a))
1.5000
drop table t1;
SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL;
NULLIF(5,5) IS NULL NULLIF(5,5) IS NOT NULL
1 0
......@@ -17,6 +17,18 @@ unlock tables;
n
1
drop table t1;
create table t1 (a int, b int);
create table t2 (c int, d int);
insert into t1 values(1,1);
insert into t1 values(2,2);
insert into t2 values(1,2);
lock table t1 read;
update t1,t2 set c=a where b=d;
select c from t2;
c
2
drop table t1;
drop table t2;
create table t1 (a int);
create table t2 (a int);
lock table t1 write, t2 write;
......
......@@ -151,7 +151,6 @@ Table 't2' was locked with a READ lock and can't be updated
UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
Table 't2' was locked with a READ lock and can't be updated
UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
Table 't2' was locked with a READ lock and can't be updated
unlock tables;
LOCK TABLES t1 write, t2 write;
UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
......
......@@ -122,40 +122,41 @@ t2 t4 t6 t8 t10 t12 t14
0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00
1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59
drop table t1;
set new=0;
create table t1 (t1 timestamp default '2003-01-01 00:00:00',
t2 timestamp default '2003-01-01 00:00:00');
set TIMESTAMP=1000000000;
insert into t1 values();
select * from t1;
t1 t2
2001-09-09 04:46:40 2003-01-01 00:00:00
20010909044640 20030101000000
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`t1` timestamp(14) NOT NULL,
`t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00'
`t2` timestamp(14) NOT NULL default '20030101000000'
) TYPE=MyISAM
show columns from t1;
Field Type Null Key Default Extra
t1 timestamp(14) YES NULL
t2 timestamp(14) YES 2003-01-01 00:00:00
t2 timestamp(14) YES 20030101000000
show columns from t1 like 't2';
Field Type Null Key Default Extra
t2 timestamp(14) YES 2003-01-01 00:00:00
t2 timestamp(14) YES 20030101000000
create table t2 (select * from t1);
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`t1` timestamp(14) NOT NULL,
`t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00'
`t2` timestamp(14) NOT NULL default '20030101000000'
) TYPE=MyISAM
alter table t1 add column t0 timestamp first;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`t0` timestamp(14) NOT NULL,
`t1` timestamp(14) NOT NULL default '2003-01-01 00:00:00',
`t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00'
`t1` timestamp(14) NOT NULL default '20030101000000',
`t2` timestamp(14) NOT NULL default '20030101000000'
) TYPE=MyISAM
drop table t1,t2;
create table t1 (ts1 timestamp, ts2 timestamp);
......@@ -164,8 +165,8 @@ insert into t1 values ();
insert into t1 values (DEFAULT, DEFAULT);
select * from t1;
ts1 ts2
2001-09-09 04:46:40 0000-00-00 00:00:00
2001-09-09 04:46:40 0000-00-00 00:00:00
20010909044640 00000000000000
20010909044640 00000000000000
drop table t1;
create table t1 (ts timestamp(19));
show create table t1;
......@@ -179,3 +180,44 @@ select * from t1;
ts
2001-09-09 04:46:40
drop table t1;
set new=1;
create table t1 (a char(2), t timestamp);
insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'),
('b', '2004-02-01 00:00:00');
select max(t) from t1 group by a;
max(t)
2004-01-01 01:00:00
2004-02-01 00:00:00
drop table t1;
create table t1 (ts1 timestamp);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`ts1` timestamp(19) NOT NULL
) TYPE=MyISAM
alter table t1 add ts2 timestamp;
set new=0;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`ts1` timestamp(19) NOT NULL,
`ts2` timestamp(19) NOT NULL default '0000-00-00 00:00:00'
) TYPE=MyISAM
drop table t1;
create table t1 (ts1 timestamp);
insert into t1 values ('2004-01-01 00:00:00'), ('2004-01-01 01:00:00');
select * from t1;
ts1
20040101000000
20040101010000
set new=1;
select * from t1;
ts1
2004-01-01 00:00:00
2004-01-01 01:00:00
set new=0;
select * from t1;
ts1
20040101000000
20040101010000
drop table t1;
......@@ -47,3 +47,7 @@ insert t1 values (1),(2);
select if(1>2,a,avg(a)) from t1;
drop table t1;
#
# Bug #5595 NULLIF() IS NULL returns false if NULLIF() returns NULL
#
SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL;
......@@ -50,6 +50,30 @@ connection reader;
reap;
drop table t1;
#
# Test problem when using locks with multi-updates
# It should not block when multi-update is reading on a read-locked table
#
connection locker;
create table t1 (a int, b int);
create table t2 (c int, d int);
insert into t1 values(1,1);
insert into t1 values(2,2);
insert into t2 values(1,2);
lock table t1 read;
connection writer;
--sleep 2
send update t1,t2 set c=a where b=d;
connection reader;
--sleep 2
select c from t2;
connection writer;
reap;
connection locker;
drop table t1;
drop table t2;
#
# Test problem when using locks on many tables and droping a table that
# is to-be-locked by another thread
......
......@@ -151,8 +151,6 @@ LOCK TABLES t1 write, t2 read;
DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n;
--error 1099
UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
# The following should be fixed to not give an error
--error 1099
UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
unlock tables;
LOCK TABLES t1 write, t2 write;
......
......@@ -71,6 +71,7 @@ select * from t1;
set new=1;
select * from t1;
drop table t1;
set new=0;
#
# Bug #1885, bug #2539.
......@@ -116,3 +117,34 @@ set TIMESTAMP=1000000000;
insert into t1 values ();
select * from t1;
drop table t1;
#
# Test for bug #4131, TIMESTAMP columns missing minutes and seconds when
# using GROUP BY in @@new=1 mode.
#
set new=1;
create table t1 (a char(2), t timestamp);
insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'),
('b', '2004-02-01 00:00:00');
select max(t) from t1 group by a;
drop table t1;
#
# More --new mode tests
# Both columns created before and during alter should have same length.
#
create table t1 (ts1 timestamp);
show create table t1;
alter table t1 add ts2 timestamp;
set new=0;
show create table t1;
drop table t1;
# Selecting from table in --new mode should not affect further selects.
create table t1 (ts1 timestamp);
insert into t1 values ('2004-01-01 00:00:00'), ('2004-01-01 01:00:00');
select * from t1;
set new=1;
select * from t1;
set new=0;
select * from t1;
drop table t1;
......@@ -41,7 +41,7 @@ const char * NEAR globerrs[GLOBERRS]=
"Can't change dir to '%s' (Errcode: %d)",
"Warning: '%s' had %d links",
"%d files and %d streams is left open\n",
"Disk is full writing '%s'. Waiting for someone to free space...",
"Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... Retry in %d secs",
"Can't create directory '%s' (Errcode: %d)",
"Character set '%s' is not a compiled character set and is not specified in the '%s' file",
"Out of resources when opening file '%s' (Errcode: %d)",
......
......@@ -114,11 +114,13 @@ uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
if (my_thread_var->abort)
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
#endif
if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
if ((errno == ENOSPC || errno == EDQUOT) &&
(MyFlags & MY_WAIT_IF_FULL))
{
if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH));
sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
"[stream]",my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC);
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
continue;
}
......
......@@ -115,11 +115,12 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
if (my_thread_var->abort)
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
#endif
if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
if ((my_errno == ENOSPC || my_errno == EDQUOT) &&
(MyFlags & MY_WAIT_IF_FULL))
{
if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
my_filename(Filedes));
my_filename(Filedes),my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC);
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
continue;
}
......@@ -131,7 +132,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
{
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
my_filename(Filedes),my_errno);
}
DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
......@@ -142,4 +143,4 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Want only errors */
DBUG_RETURN(writenbytes+written); /* purecov: inspected */
} /* my_write */
} /* my_pwrite */
......@@ -48,12 +48,13 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
if (my_thread_var->abort)
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
#endif
if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL) &&
if ((my_errno == ENOSPC || my_errno == EDQUOT) &&
(MyFlags & MY_WAIT_IF_FULL) &&
(uint) writenbytes != (uint) -1)
{
if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
my_filename(Filedes));
my_filename(Filedes),my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC);
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
continue;
}
......
......@@ -29,3 +29,11 @@ extern pthread_mutex_t THR_LOCK_charset;
#else
#include <my_no_pthread.h>
#endif
/*
EDQUOT is used only in 3 C files only in mysys/. If it does not exist on
system, we set it to some value which can never happen.
*/
#ifndef EDQUOT
#define EDQUOT (-1)
#endif
......@@ -2467,8 +2467,7 @@ void Field_double::sql_type(String &res) const
enum Item_result Field_timestamp::result_type() const
{
return (!current_thd->variables.new_mode &&
(field_length == 8 || field_length == 14) ? INT_RESULT :
return ((field_length == 8 || field_length == 14) ? INT_RESULT :
STRING_RESULT);
}
......@@ -2480,6 +2479,9 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
:Field_num(ptr_arg, len_arg, (uchar*) 0,0,
unireg_check_arg, field_name_arg, table_arg,
0, 1, 1)
#if MYSQL_VERSION_ID < 40100
, orig_field_length(len_arg)
#endif
{
if (table && !table->timestamp_field)
{
......@@ -2697,7 +2699,7 @@ String *Field_timestamp::val_str(String *val_buffer,
time_t time_arg;
struct tm *l_time;
struct tm tm_tmp;
my_bool new_format= (current_thd->variables.new_mode) || field_length == 19,
my_bool new_format= field_length == 19,
full_year=(field_length == 8 || field_length == 14 || new_format);
int real_field_length= new_format ? 19 : field_length;
......@@ -2859,22 +2861,6 @@ void Field_timestamp::set_time()
longstore(ptr,tmp);
}
/*
This is an exact copy of Field_num except that 'length' is depending
on --new mode
*/
void Field_timestamp::make_field(Send_field *field)
{
field->table_name=table_name;
field->col_name=field_name;
/* If --new, then we are using "YYYY-MM-DD HH:MM:SS" format */
field->length= current_thd->variables.new_mode ? 19 : field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
field->decimals=dec;
}
/****************************************************************************
** time type
......
......@@ -546,6 +546,13 @@ public:
class Field_timestamp :public Field_num {
#if MYSQL_VERSION_ID < 40100
/*
We save the original field length here because field_length is
changed to a mock value in case when the 'new_mode' is in effect.
*/
uint32 orig_field_length;
#endif
public:
Field_timestamp(char *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg, const char *field_name_arg,
......@@ -587,7 +594,11 @@ public:
void fill_and_store(char *from,uint len);
bool get_date(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
void make_field(Send_field *field);
#if MYSQL_VERSION_ID < 40100
friend TABLE *open_table(THD *thd,const char *db,const char *table_name,
const char *alias,bool *refresh);
#endif
};
......
......@@ -1000,9 +1000,27 @@ int ha_myisam::delete_table(const char *name)
int ha_myisam::external_lock(THD *thd, int lock_type)
{
return mi_lock_database(file, !table->tmp_table ?
int rc;
while ((! (rc= mi_lock_database(file, !table->tmp_table ?
lock_type : ((lock_type == F_UNLCK) ?
F_UNLCK : F_EXTRA_LCK));
F_UNLCK : F_EXTRA_LCK)))) &&
mi_is_crashed(file) && (myisam_recover_options != HA_RECOVER_NONE))
{
/*
check_and_repair() implicitly write locks the table, unless a
LOCK TABLES is in effect. It should be safer to always write lock here.
The implicit lock by check_and_repair() will then be a no-op.
check_and_repair() does not restore the original lock, but unlocks the
table. So we have to get the requested lock type again. And then to
check, if the table has been crashed again meanwhile by another server.
If anything fails, we break.
*/
if (((lock_type != F_WRLCK) && (rc= mi_lock_database(file, F_WRLCK))) ||
(rc= check_and_repair(thd)))
break;
}
return rc;
}
......
......@@ -654,6 +654,15 @@ Item_func_nullif::val_str(String *str)
return res;
}
bool
Item_func_nullif::is_null()
{
if (!(this->*cmp_func)())
return null_value=1;
return 0;
}
/*
CASE expression
Return the matching ITEM or NULL if all compares (including else) failed
......
......@@ -240,6 +240,7 @@ public:
void fix_length_and_dec();
const char *func_name() const { return "nullif"; }
table_map not_null_tables() const { return 0; }
bool is_null();
};
......
......@@ -2080,8 +2080,7 @@ static void check_data_home(const char *path)
/* ARGSUSED */
extern "C" int my_message_sql(uint error, const char *str,
myf MyFlags __attribute__((unused)))
extern "C" int my_message_sql(uint error, const char *str, myf MyFlags)
{
NET *net;
DBUG_ENTER("my_message_sql");
......@@ -2094,7 +2093,7 @@ extern "C" int my_message_sql(uint error, const char *str,
net->last_errno=error ? error : ER_UNKNOWN_ERROR;
}
}
else
if (!net || MyFlags & ME_NOREFRESH)
sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
DBUG_RETURN(0);
}
......
......@@ -132,6 +132,10 @@ net_printf(NET *net, uint errcode, ...)
length=sizeof(net->last_error)-1; /* purecov: inspected */
va_end(args);
/* Replication slave relies on net->last_* to see if there was error */
net->last_errno= errcode;
strmake(net->last_error, text_pos, sizeof(net->last_error)-1);
if (net->vio == 0)
{
if (thd && thd->bootstrap)
......
......@@ -941,6 +941,31 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
for (uint i=0 ; i < table->fields ; i++)
table->field[i]->table_name=table->table_name;
}
#if MYSQL_VERSION_ID < 40100
/*
If per-connection "new" variable (represented by variables.new_mode)
is set then we should pretend that the length of TIMESTAMP field is 19.
The cheapest (from perfomance viewpoint) way to achieve that is to set
field_length of all Field_timestamp objects in a table after opening
it (to 19 if new_mode is true or to original field length otherwise).
We save value of new_mode variable in TABLE::timestamp_mode to
not perform this setup if new_mode value is the same between sequential
table opens.
*/
my_bool new_mode= thd->variables.new_mode;
if (table->timestamp_mode != new_mode)
{
for (uint i=0 ; i < table->fields ; i++)
{
Field *field= table->field[i];
if (field->type() == FIELD_TYPE_TIMESTAMP)
field->field_length= new_mode ? 19 :
((Field_timestamp *)(field))->orig_field_length;
}
table->timestamp_mode= new_mode;
}
#endif
/* These variables are also set in reopen_table() */
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
......
......@@ -282,6 +282,8 @@ multi_delete::initialize_tables(JOIN *join)
walk=walk->next;
/* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1;
/* Don't use record cache */
tbl->no_cache= 1;
tbl->used_keys= 0;
if (tbl->file->has_transactions())
log_delayed= transactional_tables= 1;
......
......@@ -1927,8 +1927,6 @@ mysql_execute_command(void)
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
if (select_lex->table_list.elements == 1)
{
if (check_one_table_access(thd, UPDATE_ACL, tables, 0))
goto error; /* purecov: inspected */
......@@ -1940,8 +1938,15 @@ mysql_execute_command(void)
(ORDER *) select_lex->order_list.first,
select_lex->select_limit,
lex->duplicates);
break;
case SQLCOM_MULTI_UPDATE:
if (check_db_used(thd,tables))
goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
else
{
const char *msg= 0;
TABLE_LIST *table;
......@@ -3242,7 +3247,18 @@ bool add_field_to_list(char *field_name, enum_field_types type,
}
break;
case FIELD_TYPE_TIMESTAMP:
#if MYSQL_VERSION_ID < 40100
/*
When in in --new mode, we should create TIMESTAMP(19) fields by default;
otherwise we will have problems with ALTER TABLE changing lengths of
existing TIMESTAMP fields to 19 and adding new fields with length 14.
*/
if (thd->variables.new_mode)
new_field->length= 19;
else if (!length)
#else
if (!length)
#endif
new_field->length= 14; // Full date YYYYMMDDHHMMSS
else if (new_field->length != 19)
{
......
......@@ -193,28 +193,24 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
{ /* Return databases */
#ifdef USE_SYMDIR
char *ext;
char buff[FN_REFLEN];
if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
{
/* Only show the sym file if it points to a directory */
char buff[FN_REFLEN], *end;
MY_STAT status;
char *end;
*ext=0; /* Remove extension */
unpack_dirname(buff, file->name);
end= strend(buff);
if (end != buff && end[-1] == FN_LIBCHAR)
end[-1]= 0; // Remove end FN_LIBCHAR
if (!my_stat(buff, &status, MYF(0)) ||
!MY_S_ISDIR(status.st_mode))
if (!my_stat(buff, file->mystat, MYF(0)))
continue;
}
else
#endif
{
if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) ||
(wild && wild_compare(file->name,wild, 0)))
continue;
}
}
else
{
// Return only .frm files which aren't temp files.
......
......@@ -2208,7 +2208,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (!(copy= new Copy_field[to->fields]))
DBUG_RETURN(-1); /* purecov: inspected */
to->file->external_lock(thd,F_WRLCK);
if (to->file->external_lock(thd, F_WRLCK))
{
/* We must always unlock, even when lock failed. */
(void) to->file->external_lock(thd, F_UNLCK);
DBUG_RETURN(-1);
}
to->file->extra(HA_EXTRA_WRITE_CACHE);
from->file->info(HA_STATUS_VARIABLE);
to->file->deactivate_non_unique_index(from->file->records);
......@@ -2308,11 +2313,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
error=1;
if (ha_commit(thd))
error=1;
if (to->file->external_lock(thd,F_UNLCK))
error=1;
err:
free_io_cache(from);
*copied= found_count;
*deleted=delete_count;
/* we must always unlock the table on return. */
if (to->file->external_lock(thd,F_UNLCK))
error=1;
DBUG_RETURN(error > 0 ? -1 : 0);
}
......@@ -401,9 +401,21 @@ int mysql_multi_update(THD *thd,
int res;
multi_update *result;
TABLE_LIST *tl;
const bool locked= !(thd->locked_tables);
DBUG_ENTER("mysql_multi_update");
if ((res=open_and_lock_tables(thd,table_list)))
for (;;)
{
table_map update_map= 0;
int tnr= 0;
if ((res= open_tables(thd, table_list)))
DBUG_RETURN(res);
/*
Only need to call lock_tables if (thd->locked_tables == NULL)
*/
if (locked && ((res= lock_tables(thd, table_list))))
DBUG_RETURN(res);
thd->select_limit=HA_POS_ERROR;
......@@ -411,16 +423,80 @@ int mysql_multi_update(THD *thd,
/*
Ensure that we have update privilege for all tables and columns in the
SET part
While we are here, initialize the table->map field.
*/
for (tl= table_list ; tl ; tl=tl->next)
{
TABLE *table= tl->table;
table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege);
table->map= (table_map) 1 << (tnr++);
}
if (setup_fields(thd, table_list, *fields, 1, 0, 0))
if (!setup_fields(thd, table_list, *fields, 1, 0, 0))
{
List_iterator_fast<Item> field_it(*fields);
Item_field *item;
while ((item= (Item_field *) field_it++))
update_map|= item->used_tables();
DBUG_PRINT("info",("update_map=0x%08x", update_map));
}
else
DBUG_RETURN(-1);
/*
Unlock the tables in preparation for relocking
*/
if (locked)
{
pthread_mutex_lock(&LOCK_open);
mysql_unlock_tables(thd, thd->lock);
thd->lock= 0;
pthread_mutex_unlock(&LOCK_open);
}
/*
Set the table locking strategy according to the update map
*/
for (tl= table_list ; tl ; tl=tl->next)
{
TABLE *table= tl->table;
if (update_map & table->map)
{
DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
tl->lock_type= thd->lex.lock_option;
tl->updating= 1;
}
else
{
DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
tl->lock_type= TL_READ;
tl->updating= 0;
}
if (locked)
tl->table->reginfo.lock_type= tl->lock_type;
}
/*
Relock the tables
*/
if (!(res=lock_tables(thd,table_list)))
break;
if (!locked)
DBUG_RETURN(res);
List_iterator_fast<Item> field_it(*fields);
Item_field *item;
while ((item= (Item_field *) field_it++))
/* item->cleanup(); XXX Use this instead in MySQL 4.1+ */
item->field= item->result_field= 0;
close_thread_tables(thd);
}
/*
Count tables and setup timestamp handling
*/
......
......@@ -2751,10 +2751,18 @@ update:
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
opt_low_priority opt_ignore join_table_list
SET update_list where_clause opt_order_clause delete_limit_clause
SET update_list
{
if (Lex->select->table_list.elements > 1)
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_MULTI_UPDATE;
lex->lock_option= $3;
}
else
set_lock_for_tables($3);
}
where_clause opt_order_clause delete_limit_clause {}
;
update_list:
......
......@@ -197,7 +197,7 @@ terribly wrong...\n");
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
end:
fprintf(stderr, "Please read http://www.mysql.com/doc/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\
fprintf(stderr, "Please read http://dev.mysql.com/doc/mysql/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\
stack trace is much more helpful in diagnosing the problem, so please do \n\
resolve it\n");
}
......
......@@ -106,6 +106,14 @@ struct st_table {
*found_next_number_field, /* Set on open */
*rowid_field;
Field_timestamp *timestamp_field;
#if MYSQL_VERSION_ID < 40100
/*
Indicates whenever we have to set field_length members of all TIMESTAMP
fields to 19 (to honour 'new_mode' variable) or to original
field_length values.
*/
my_bool timestamp_mode;
#endif
my_string comment; /* Comment about table */
REGINFO reginfo; /* field connections */
MEM_ROOT mem_root;
......
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