diff options
152 files changed, 2776 insertions, 1235 deletions
diff --git a/Build-tools/Bootstrap b/Build-tools/Bootstrap index 17b15d190b0..7d3ac1322f4 100755 --- a/Build-tools/Bootstrap +++ b/Build-tools/Bootstrap @@ -274,11 +274,13 @@ if (defined $opt_changelog) # unless ($opt_skip_manual) { - $msg= "Adding manual.texi"; + $msg= "Updating manual files"; &logger($msg); - $command= "install -m 644 $opt_docdir/Docs/{internals,manual,reservedwords}.texi"; - $command.= " $target_dir/Docs/"; - &run_command($command, "Could not update the manual in $target_dir/Docs/!"); + foreach $file qw/internals manual reservedwords/ + { + system ("bk cat $opt_docdir/Docs/$file.texi > $target_dir/Docs/$file.texi") == 0 + or &abort("Could not update $file.texi in $target_dir/Docs/!"); + } } # @@ -364,11 +366,13 @@ sub print_help Usage: Bootstrap [options] <bk repository> -Checks out (exports) a clear-text version of the given local BitKeeper +Creates a MySQL source distribution to be used for the release builds. + +It checks out (exports) a clear-text version of the given local BitKeeper repository, creates and adds a Changelog file (if requested), adds the -latest manual.texi from the mysqldoc tree and builds a source distribution -(*.tar.gz) file. Optionally, the test suite can be run before the source -archive is being created. +latest manual files from the mysqldoc BK tree and builds a source +distribution (*.tar.gz) file. Optionally, the test suite and the +distribution check can be run before the source archive is being created. Options: diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index 0541ebe96ce..2039c2f1c5a 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -1,6 +1,8 @@ #!/usr/bin/perl -w +use File::Basename; use Getopt::Long; +use Sys::Hostname; @config_options= (); @make_options= (); @@ -76,7 +78,7 @@ if (@config_env > 0) $opt_config_env= join(" ", @config_env); } -chomp($host=`hostname`); +$host= hostname(); chomp($uname=`uname`); $full_host_name=$host; $connect_option= ($opt_tcpip ? "--host=$host" : ""); @@ -84,7 +86,7 @@ $host =~ /^([^.-]*)/; $host=$1 . $opt_suffix; $email="$opt_user\@mysql.com"; chomp($pwd = `pwd`); -$VER= `basename $opt_distribution`; chop $VER; +$VER= basename($opt_distribution); $VER=~ /mysql.*-([1-9]\.[0-9]{1,2}\.[0-9]{1,2}.*)\.tar*/; $version=$1; ($major, $minor, $release) = split(/\./,$version); $log="$pwd/Logs/$host-$major.$minor$opt_version_suffix.log"; @@ -111,7 +113,7 @@ if (defined($gcc_version) && ! $opt_config_env) $new_opt_tmp=0; if ($opt_tmp) { - if (! -d $opt_tmp) + unless (-d $opt_tmp) { safe_system("mkdir $opt_tmp"); $new_opt_tmp=1; diff --git a/Build-tools/Do-rpm b/Build-tools/Do-rpm index 0f423feb921..cedd55d1405 100755 --- a/Build-tools/Do-rpm +++ b/Build-tools/Do-rpm @@ -3,14 +3,12 @@ # Do-rpm - compile RPM packages out of a source tarball and move the # resulting RPM packages into the current directory. # -# The script currently assumes the following environment (which should exist -# like that, if the Do-compile script was used to build the binary -# distribution) +# The script currently assumes the following environment: # # - there must be a source distribution (mysql-<version>.tar.gz) # in the current directory -# - there must be a spec file (mysql-<version>.spec) in the directory -# $HOME/<hostname>/mysql-<version>/support-files/ +# - You must provide the name of an RPM spec file (mysql-<version>.spec) +# as the argument # # Use the "--help" option for more info! # @@ -35,7 +33,10 @@ $opt_log= undef; $opt_mail= ""; $opt_verbose= undef; +# Set a dummy version until we know the correct one +$VERSION= "x.y.z"; $MAJOR= $MINOR= $RELEASE= 0; +$SUFFIX= ""; GetOptions( "cc=s", @@ -50,7 +51,9 @@ GetOptions( "verbose|v", ) || &print_help; -defined($VERSION=$ARGV[0]) || print_help("Please provide the MySQL version!"); +&print_help("") if ($opt_help); + +defined($SPECFILE=$ARGV[0]) || print_help("Please provide the spec file name!"); # Include helper functions $PWD= cwd(); @@ -64,6 +67,28 @@ else die "ERROR: $LOGGER cannot be found!\n"; } +# Open the spec file and extract the version number +open(SPEC, $SPECFILE) or &abort("Unable to open \"$ARGV[0]\": $!"); +@spec= <SPEC>; +close SPEC; + +foreach (@spec) +{ + if (m/^%define\s*mysql_version\s*(.*)/) + { + $VERSION= $1; + ($MAJOR, $MINOR, $RELEASE)= split(/\./,$VERSION); + ($RELEASE, $SUFFIX)= split(/\-/,$RELEASE); + $SUFFIX= "-" . $SUFFIX if ($SUFFIX); + } +} + +$HOST= hostname(); +$HOST=~ /^([^.-]*)/; +$HOST= $1; +$LOGFILE= "$PWD/Logs/Do-rpm-$HOST-$MAJOR.$MINOR.log"; +&logger("Using spec file for version: $VERSION"); + # # Override predefined Log file name # @@ -82,14 +107,6 @@ if (defined $opt_log) } } -($MAJOR, $MINOR, $RELEASE)= split(/\./, $VERSION); -$HOST= hostname(); -$HOST=~ /^([^.-]*)/; -$HOST= $1; -$LOGFILE= "$PWD/Logs/Do-rpm-$HOST-$MAJOR.$MINOR.log"; - -&print_help("") if ($opt_help); - # # Newer RPM versions ship with a separate tool "rpmbuild" to build RPMs # @@ -120,8 +137,7 @@ chomp($SOURCEDIR= `$RPM --eval "%{_sourcedir}" 2> /dev/null`); chomp($SPECDIR= `$RPM --eval "%{_specdir}" 2> /dev/null`); chomp($SRCRPMDIR= `$RPM --eval "%{_srcrpmdir}" 2> /dev/null`); -$SOURCEFILE= "mysql-$VERSION.tar.gz"; -$SPECFILE= "$PWD/$HOST/mysql-$VERSION/support-files/mysql-$VERSION.spec"; +$SOURCEFILE= glob "mysql*-$VERSION.tar.gz"; &logger("Starting RPM build of MySQL-$VERSION on $HOST"); @@ -134,10 +150,13 @@ foreach $file ($SOURCEFILE, $SPECFILE) # Install source and spec file # &logger("Copying SOURCE and SPEC file to build directories."); -copy($SOURCEFILE, $SOURCEDIR) -or &abort("Unable to copy $SOURCEFILE to $SOURCEDIR!"); -copy($SPECFILE, $SPECDIR) -or &abort("Unable to copy $SPECFILE to $SPECDIR!"); +unless ($opt_dry_run) +{ + copy($SOURCEFILE, $SOURCEDIR) + or &abort("Unable to copy $SOURCEFILE to $SOURCEDIR!"); + copy($SPECFILE, $SPECDIR) + or &abort("Unable to copy $SPECFILE to $SPECDIR!"); +} # # Set environment variables - these are being used in the @@ -168,11 +187,13 @@ $command.= basename($SPECFILE); $command= "mv"; $command.= " -v " if ($opt_verbose); $command.= "$SRCRPMDIR/MySQL*$VERSION*.src.rpm $PWD"; +&logger("Moving source RPM to current dir."); &run_command($command, "Error moving source RPM!"); $command= "mv"; $command.= " -v " if ($opt_verbose); $command.= "$RPMDIR/$RPMARCH/MySQL*$VERSION*.$RPMARCH.rpm $PWD"; +&logger("Moving binary RPMs to current dir."); &run_command($command, "Error moving binary RPMs!"); # @@ -181,11 +202,14 @@ $command.= "$RPMDIR/$RPMARCH/MySQL*$VERSION*.$RPMARCH.rpm $PWD"; if ($opt_clean) { &logger("Removing spec file and source package"); - unlink("$SPECDIR/" . basename($SPECFILE)); - unlink("$SOURCEDIR/$SOURCEFILE"); + unless ($opt_dry_run) + { + unlink("$SPECDIR/" . basename($SPECFILE)); + unlink("$SOURCEDIR/$SOURCEFILE"); + } } -&logger("SUCCESS: RPM files successfully created.") if (!$opt_dry_run); +&logger("SUCCESS: RPM files successfully created.") unless ($opt_dry_run); exit 0; sub print_help @@ -198,11 +222,14 @@ sub print_help } print <<EOF; -Usage: Do-rpm <options> <version> +Usage: Do-rpm [options] <specfile> -Creates a binary RPM package out of a MySQL source distribution and moves the -resulting RPMs into the current directory. <version> is the MySQL version -number (e.g. 4.0.11-gamma) +Creates a binary RPM package out of a MySQL source distribution and moves +the resulting RPMs into the current directory. <specfile> is the MySQL RPM +spec file to use (e.g. mysql-4.0.17.spec). + +This script expects to find the required MySQL source distribution +(mysql-<version>.tar.gz) in the current directory. Options: @@ -222,6 +249,10 @@ Options: Example: --mail=user\\\@domain.com -v, --verbose Verbose execution +Example: + + Do-rpm -cv mysql-4.0.17.spec + EOF exit 1; } diff --git a/VC++Files/InstallShield/4.0.XX-classic/String Tables/0009-English/value.shl b/VC++Files/InstallShield/4.0.XX-classic/String Tables/0009-English/value.shl index 5f767a63f43..868c801c68c 100755 --- a/VC++Files/InstallShield/4.0.XX-classic/String Tables/0009-English/value.shl +++ b/VC++Files/InstallShield/4.0.XX-classic/String Tables/0009-English/value.shl @@ -19,5 +19,5 @@ ERROR_UNINSTSETUP=unInstaller setup failed to initialize. You may not be able t [General] Language=0009 Type=STRINGTABLESPECIFIC -Version=@VERSION@ +Version=1.00.000 diff --git a/VC++Files/InstallShield/4.0.XX-gpl/String Tables/0009-English/value.shl b/VC++Files/InstallShield/4.0.XX-gpl/String Tables/0009-English/value.shl index 0a6c33be42b..35e7c278cc9 100755 --- a/VC++Files/InstallShield/4.0.XX-gpl/String Tables/0009-English/value.shl +++ b/VC++Files/InstallShield/4.0.XX-gpl/String Tables/0009-English/value.shl @@ -19,5 +19,5 @@ ERROR_UNINSTSETUP=unInstaller setup failed to initialize. You may not be able t [General] Language=0009 Type=STRINGTABLESPECIFIC -Version=@VERSION@ +Version=1.00.000 diff --git a/VC++Files/InstallShield/4.0.XX-pro/String Tables/0009-English/value.shl b/VC++Files/InstallShield/4.0.XX-pro/String Tables/0009-English/value.shl index 61b2e6fb50f..525f3be0b3e 100755 --- a/VC++Files/InstallShield/4.0.XX-pro/String Tables/0009-English/value.shl +++ b/VC++Files/InstallShield/4.0.XX-pro/String Tables/0009-English/value.shl @@ -19,5 +19,5 @@ ERROR_UNINSTSETUP=unInstaller setup failed to initialize. You may not be able t [General] Language=0009 Type=STRINGTABLESPECIFIC -Version=@VERSION@ +Version=1.00.000 diff --git a/acinclude.m4 b/acinclude.m4 index 15a6abc38d4..d3a404e5fb0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -785,7 +785,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [ for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \ /usr/lib /usr/lib64 /opt/ssl/lib /opt/openssl/lib /usr/local/lib/ ; do - if test -f $d/libssl.a ; then + if test -f $d/libssl.a || test -f $d/libssl.so || test -f $d/libssl.dylib ; then OPENSSL_LIB=$d fi done @@ -797,7 +797,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [ if test -f $incs/openssl/ssl.h ; then OPENSSL_INCLUDE=-I$incs fi - if test -f $libs/libssl.a ; then + if test -f $libs/libssl.a || test -f $libs/libssl.so || test -f $libs/libssl.dylib ; then OPENSSL_LIB=$libs fi ;; diff --git a/client/mysql.cc b/client/mysql.cc index 42088d107ed..df55ebcfab0 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -380,7 +380,7 @@ int main(int argc,char *argv[]) put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.", INFO_INFO); sprintf((char*) glob_buffer.ptr(), - "Your MySQL connection id is %ld to server version: %s\n", + "Your MySQL connection id is %lu to server version: %s\n", mysql_thread_id(&mysql),mysql_get_server_info(&mysql)); put_info((char*) glob_buffer.ptr(),INFO_INFO); @@ -613,8 +613,8 @@ static struct my_option my_long_options[] = 0, 1}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "", (gptr*) &max_allowed_packet, (gptr*) &max_allowed_packet, 0, GET_ULONG, - REQUIRED_ARG, 16 *1024L*1024L, 4096, 512*1024L*1024L, MALLOC_OVERHEAD, - 1024, 0}, + REQUIRED_ARG, 16 *1024L*1024L, 4096, (longlong) 2*1024L*1024L*1024L, + MALLOC_OVERHEAD, 1024, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "", (gptr*) &net_buffer_length, (gptr*) &net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 16384, 1024, 512*1024*1024L, MALLOC_OVERHEAD, 1024, 0}, @@ -2346,7 +2346,7 @@ com_connect(String *buffer, char *line) if (connected) { - sprintf(buff,"Connection id: %ld",mysql_thread_id(&mysql)); + sprintf(buff,"Connection id: %lu",mysql_thread_id(&mysql)); put_info(buff,INFO_INFO); sprintf(buff,"Current database: %s\n", current_db ? current_db : "*** NONE ***"); @@ -2652,7 +2652,7 @@ com_status(String *buffer __attribute__((unused)), { MYSQL_RES *result; LINT_INIT(result); - tee_fprintf(stdout, "\nConnection id:\t\t%ld\n",mysql_thread_id(&mysql)); + tee_fprintf(stdout, "\nConnection id:\t\t%lu\n",mysql_thread_id(&mysql)); if (!mysql_query(&mysql,"select DATABASE(),USER()") && (result=mysql_use_result(&mysql))) { diff --git a/client/mysqldump.c b/client/mysqldump.c index 5c3fa44e30b..d5c80b31141 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -37,7 +37,7 @@ ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov */ -#define DUMP_VERSION "10.3" +#define DUMP_VERSION "10.4" #include <my_global.h> #include <my_sys.h> @@ -81,7 +81,7 @@ static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1, opt_alldbs=0,opt_create_db=0,opt_first_slave=0,opt_set_names=0, opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0, opt_delete_master_logs=0, tty_password=0, - opt_single_transaction=0; + opt_single_transaction=0, opt_comments= 0; static MYSQL mysql_connection,*sock=0; static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, *current_host=0,*path=0,*fields_terminated=0, @@ -280,12 +280,15 @@ static struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "", (gptr*) &max_allowed_packet, (gptr*) &max_allowed_packet, 0, - GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, 1024*1024L*1024L, - MALLOC_OVERHEAD, 1024, 0}, + GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, + (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "", (gptr*) &net_buffer_length, (gptr*) &net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L, MALLOC_OVERHEAD-1024, 1024, 0}, + {"comments", 'i', "Write additional information.", + (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -302,6 +305,8 @@ static int init_dumping(char *); static int dump_databases(char **); static int dump_all_databases(); static char *quote_name(const char *name, char *buff, my_bool force); +static const char *check_if_ignore_table(const char *table_name); + static void print_version(void) { @@ -345,7 +350,7 @@ static void write_header(FILE *sql_file, char *db_name) fputs("<?xml version=\"1.0\"?>\n", sql_file); fputs("<mysqldump>\n", sql_file); } - else + else if (opt_comments) { fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION); fprintf(sql_file, "-- Host: %s Database: %s\n", @@ -656,6 +661,23 @@ static char *quote_name(const char *name, char *buff, my_bool force) } /* quote_name */ + +static char *quote_for_like(const char *name, char *buff) +{ + char *to= buff; + *to++= '\''; + while (*name) + { + if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%') + *to++= '\\'; + *to++= *name++; + } + to[0]= '\''; + to[1]= 0; + return buff; +} + + /* Quote and print a string. @@ -854,7 +876,8 @@ static uint getTableStructure(char *table, char* db) } write_header(sql_file, db); } - fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", + if (!opt_xml && opt_comments) + fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", result_table); if (opt_drop) fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); @@ -930,7 +953,7 @@ static uint getTableStructure(char *table, char* db) } write_header(sql_file, db); } - if (!opt_xml) + if (!opt_xml && opt_comments) fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", result_table); if (opt_drop) @@ -1067,16 +1090,9 @@ static uint getTableStructure(char *table, char* db) /* Get MySQL specific create options */ if (create_options) { - ulong len= strlen(table); - char *tmp= (char*) my_malloc(len * 2 + 1, MYF(MY_WME)); - if (!tmp) - { - ignore_errors= 0; - safe_exit(EX_MYSQLERR); - } - mysql_real_escape_string(&mysql_connection, tmp, table, len); - sprintf(buff,"show table status like \"%s\"", tmp); - my_free(tmp, MYF(MY_WME)); + char show_name_buff[FN_REFLEN]; + sprintf(buff,"show table status like %s", + quote_for_like(table, show_name_buff)); if (mysql_query(sock, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) @@ -1191,11 +1207,23 @@ static void dumpTable(uint numFields, char *table) MYSQL_FIELD *field; MYSQL_ROW row; ulong rownr, row_break, total_length, init_length; + const char *table_type; - if (verbose) - fprintf(stderr, "-- Sending SELECT query...\n"); result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); + + /* Check table type */ + if ((table_type= check_if_ignore_table(table))) + { + if (verbose) + fprintf(stderr, + "-- Skipping data for table '%s' because it's of type %s\n", + table, table_type); + return; + } + + if (verbose) + fprintf(stderr, "-- Sending SELECT query...\n"); if (path) { char filename[FN_REFLEN], tmp_path[FN_REFLEN]; @@ -1234,14 +1262,14 @@ static void dumpTable(uint numFields, char *table) } else { - if (!opt_xml) + if (!opt_xml && opt_comments) fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n", result_table); sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", result_table); if (where) { - if (!opt_xml) + if (!opt_xml && opt_comments) fprintf(md_result_file,"-- WHERE: %s\n",where); strxmov(strend(query), " WHERE ",where,NullS); } @@ -1337,11 +1365,23 @@ static void dumpTable(uint numFields, char *table) } else { - /* change any strings ("inf","nan",..) into NULL */ + /* change any strings ("inf", "-inf", "nan") into NULL */ char *ptr = row[i]; - dynstr_append(&extended_row, - (!my_isalpha(charset_info,*ptr)) ? - ptr : "NULL"); + if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && + my_isalpha(charset_info, ptr[1]))) + dynstr_append(&extended_row, "NULL"); + else + { + if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + dynstr_append(&extended_row, "\""); + dynstr_append(&extended_row, ptr); + dynstr_append(&extended_row, "\""); + } + else + dynstr_append(&extended_row, ptr); + } } } else @@ -1373,7 +1413,7 @@ static void dumpTable(uint numFields, char *table) } else { - /* change any strings ("inf","nan",..) into NULL */ + /* change any strings ("inf", "-inf", "nan") into NULL */ char *ptr = row[i]; if (opt_xml) { @@ -1383,9 +1423,19 @@ static void dumpTable(uint numFields, char *table) md_result_file); fputs("</field>\n", md_result_file); } - else - fputs((!my_isalpha(charset_info,*ptr)) ? - ptr : "NULL", md_result_file); + else if (my_isalpha(charset_info, *ptr) || + (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) + fputs("NULL", md_result_file); + else if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + fputs("\"", md_result_file); + fputs(ptr, md_result_file); + fputs("\"", md_result_file); + } + else + fputs(ptr, md_result_file); + } } } else @@ -1533,8 +1583,8 @@ static int init_dumping(char *database) */ char quoted_database_buf[64*2+3]; char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); - - fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); + if (opt_comments) + fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); if (!opt_create_db) { char qbuf[256]; @@ -1730,6 +1780,61 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, } /* print_value */ +/* + Check if we the table is one of the table types that should be ignored: + MRG_ISAM, MRG_MYISAM + + SYNOPSIS + check_if_ignore_table() + table_name Table name to check + + GLOBAL VARIABLES + sock MySQL socket + verbose Write warning messages + + RETURN + 0 Table should be backuped + # Type of table (that should be skipped) +*/ + +static const char *check_if_ignore_table(const char *table_name) +{ + char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN]; + MYSQL_RES *res; + MYSQL_ROW row; + const char *result= 0; + + sprintf(buff,"show table status like %s", + quote_for_like(table_name, show_name_buff)); + if (mysql_query(sock, buff)) + { + if (mysql_errno(sock) != ER_PARSE_ERROR) + { /* If old MySQL version */ + if (verbose) + fprintf(stderr, + "-- Warning: Couldn't get status information for table %s (%s)\n", + table_name,mysql_error(sock)); + return 0; /* assume table is ok */ + } + } + if (!(res= mysql_store_result(sock)) || + !(row= mysql_fetch_row(res))) + { + fprintf(stderr, + "Error: Couldn't read status information for table %s (%s)\n", + table_name, mysql_error(sock)); + if (res) + mysql_free_result(res); + return 0; /* assume table is ok */ + } + if (strcmp(row[1], (result= "MRG_MyISAM")) && + strcmp(row[1], (result= "MRG_ISAM"))) + result= 0; + mysql_free_result(res); + return result; +} + + int main(int argc, char **argv) { MYSQL_ROW row; @@ -1799,8 +1904,9 @@ int main(int argc, char **argv) row = mysql_fetch_row(master); if (row && row[0] && row[1]) { - fprintf(md_result_file, - "\n--\n-- Position to start replication from\n--\n\n"); + if (opt_comments) + fprintf(md_result_file, + "\n--\n-- Position to start replication from\n--\n\n"); fprintf(md_result_file, "CHANGE MASTER TO MASTER_LOG_FILE='%s', \ MASTER_LOG_POS=%s ;\n",row[0],row[1]); diff --git a/configure.in b/configure.in index f46e48eaa1a..e607f87747b 100644 --- a/configure.in +++ b/configure.in @@ -731,7 +731,7 @@ AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \ strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \ unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \ - sys/ioctl.h malloc.h sys/malloc.h) + sys/ioctl.h malloc.h sys/malloc.h linux/config.h) #-------------------------------------------------------------------- # Check for system libraries. Adds the library to $LIBS diff --git a/dbug/dbug.c b/dbug/dbug.c index f7b2fb75ba0..d96ef0cae09 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -501,7 +501,7 @@ void _db_push_ (const char *control) if (! _db_fp_) _db_fp_= stderr; /* Output stream, default stderr */ - if (control && *control == '-') + if (*control == '-') { if (*++control == '#') control++; diff --git a/include/config-win.h b/include/config-win.h index 86318bddbcb..10490fd2f91 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -93,6 +93,7 @@ functions */ #define LONGLONG_MIN ((__int64) 0x8000000000000000) #define LONGLONG_MAX ((__int64) 0x7FFFFFFFFFFFFFFF) +#define ULONGLONG_MAX ((unsigned __int64) 0xFFFFFFFFFFFFFFFF) #define LL(A) ((__int64) A) /* Type information */ @@ -158,6 +159,10 @@ typedef uint rf_SetTimer; #define USE_MB_IDENT 1 #define USE_STRCOLL 1 +/* All windows servers should support .sym files */ +#undef USE_SYMDIR +#define USE_SYMDIR + /* If LOAD DATA LOCAL INFILE should be enabled by default */ #define ENABLED_LOCAL_INFILE 1 diff --git a/include/my_base.h b/include/my_base.h index 25521d7b13d..89b46de520f 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -190,11 +190,17 @@ enum ha_base_keytype { /* poor old NISAM has 8-bit flags :-( */ #define HA_SORT_ALLOWS_SAME 128 /* Intern bit when sorting records */ #endif +/* + Key has a part that can have end space. If this is an unique key + we have to handle it differently from other unique keys as we can find + many matching rows for one key (becaue end space are not compared) +*/ +#define HA_END_SPACE_KEY 4096 - /* These flags can be order to key-seg-flag */ + /* These flags can be added to key-seg-flag */ #define HA_SPACE_PACK 1 /* Pack space in key-seg */ -#define HA_PART_KEY 4 /* Used by MySQL for part-key-cols */ +#define HA_PART_KEY_SEG 4 /* Used by MySQL for part-key-cols */ #define HA_VAR_LENGTH 8 #define HA_NULL_PART 16 #define HA_BLOB_PART 32 diff --git a/include/my_dir.h b/include/my_dir.h index 4ccda050914..851b6d8d7e9 100644 --- a/include/my_dir.h +++ b/include/my_dir.h @@ -74,14 +74,21 @@ typedef struct my_stat #endif /* USE_MY_STAT_STRUCT */ -typedef struct fileinfo /* Struct returned from my_dir & my_stat */ +/* Struct describing one file returned from my_dir */ +typedef struct fileinfo { char *name; - MY_STAT mystat; + MY_STAT *mystat; } FILEINFO; typedef struct st_my_dir /* Struct returned from my_dir */ { + /* + These members are just copies of parts of DYNAMIC_ARRAY structure, + which is allocated right after the end of MY_DIR structure (MEM_ROOT + for storing names is also resides there). We've left them here because + we don't want to change code that uses my_dir. + */ struct fileinfo *dir_entry; uint number_off_files; } MY_DIR; diff --git a/include/my_global.h b/include/my_global.h index b5b78774e91..9529cbee62c 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -287,6 +287,9 @@ C_MODE_END #endif #ifdef HAVE_ATOMIC_ADD #define __SMP__ +#ifdef HAVE_LINUX_CONFIG_H +#include <linux/config.h> /* May define CONFIG_SMP */ +#endif #ifndef CONFIG_SMP #define CONFIG_SMP #endif @@ -626,11 +629,26 @@ extern double my_atof(const char*); #define HAVE_LONG_LONG 1 #endif +/* + Some pre-ANSI-C99 systems like AIX 5.1 and Linux/GCC 2.95 define + ULONGLONG_MAX, LONGLONG_MIN, LONGLONG_MAX; we use them if they're defined. + Also on Windows we define these constants by hand in config-win.h. +*/ + #if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) #define LONGLONG_MIN ((long long) 0x8000000000000000LL) #define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) #endif +#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) +/* First check for ANSI C99 definition: */ +#ifdef ULLONG_MAX +#define ULONGLONG_MAX ULLONG_MAX +#else +#define ULONGLONG_MAX ((unsigned long long)(~0ULL)) +#endif +#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ + #if SIZEOF_LONG == 4 #define INT_MIN32 (long) 0x80000000L #define INT_MAX32 (long) 0x7FFFFFFFL diff --git a/include/my_pthread.h b/include/my_pthread.h index 44e6edcddec..cf04d078c70 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -117,6 +117,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #undef SAFE_MUTEX /* This will cause conflicts */ #define pthread_key(T,V) DWORD V #define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) +#define pthread_key_delete(A) TlsFree(A) #define pthread_getspecific(A) (TlsGetValue(A)) #define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) #define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) @@ -125,6 +126,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #else #define pthread_key(T,V) __declspec(thread) T V #define pthread_key_create(A,B) pthread_dummy(0) +#define pthread_key_delete(A) pthread_dummy(0) #define pthread_getspecific(A) (&(A)) #define my_pthread_getspecific(T,A) (&(A)) #define my_pthread_getspecific_ptr(T,V) (V) @@ -180,6 +182,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *); typedef int pthread_attr_t; /* Needed by Unixware 7.0.0 */ #define pthread_key_create(A,B) thr_keycreate((A),(B)) +#define pthread_key_delete(A) thr_keydelete(A) #define pthread_handler_decl(A,B) void *A(void *B) #define pthread_key(T,V) pthread_key_t V diff --git a/include/my_sys.h b/include/my_sys.h index 59d5767d204..7927192848a 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -163,7 +163,7 @@ extern char *my_strdup_with_length(const byte *from, uint length, #if defined(_AIX) && !defined(__GNUC__) && !defined(_AIX43) #pragma alloca #endif /* _AIX */ -#if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) +#if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) && ! defined(alloca) #define alloca __builtin_alloca #endif /* GNUC */ #define my_alloca(SZ) alloca((size_t) (SZ)) @@ -583,7 +583,7 @@ extern int my_printf_error _VARARGS((uint my_err, const char *format, extern int my_message(uint my_err, const char *str,myf MyFlags); extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); extern int my_message_curses(uint my_err, const char *str,myf MyFlags); -extern void my_init(void); +extern my_bool my_init(void); extern void my_end(int infoflag); extern int my_redel(const char *from, const char *to, int MyFlags); extern int my_copystat(const char *from, const char *to, int MyFlags); diff --git a/include/mysql.h b/include/mysql.h index fd0330b35da..8f3bc9aaf2f 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -638,7 +638,7 @@ int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); (*(mysql)->methods->advanced_command)(mysql, command, \ NullS, 0, arg, length, skip_check) unsigned long net_safe_read(MYSQL* mysql); -void mysql_once_init(void); +int mysql_once_init(void); extern my_bool server_inited; diff --git a/include/mysql_com.h b/include/mysql_com.h index 2036b3d0ac2..d4c1ac5440a 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -351,7 +351,7 @@ const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); /* Some other useful functions */ -void my_init(void); +my_bool my_init(void); int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); my_bool my_thread_init(void); diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c index 93e9e815c99..b2bfdbec4e4 100644 --- a/innobase/btr/btr0cur.c +++ b/innobase/btr/btr0cur.c @@ -1151,7 +1151,6 @@ btr_cur_pessimistic_insert( } /*==================== B-TREE UPDATE =========================*/ -/* Only clustered index records are modified using these functions */ /***************************************************************** For an update, checks the locks and does the undo logging. */ @@ -1175,12 +1174,16 @@ btr_cur_upd_lock_and_undo( ut_ad(cursor && update && thr && roll_ptr); - /* Only clustered index records are updated using this function */ - ut_ad((cursor->index)->type & DICT_CLUSTERED); - rec = btr_cur_get_rec(cursor); index = cursor->index; + if (!(index->type & DICT_CLUSTERED)) { + /* We do undo logging only when we update a clustered index + record */ + return(lock_sec_rec_modify_check_and_lock(flags, rec, index, + thr)); + } + /* Check if we have to wait for a lock: enqueue an explicit lock request if yes */ @@ -1227,6 +1230,13 @@ btr_cur_update_in_place_log( mach_write_to_1(log_ptr, flags); log_ptr++; + /* The code below assumes index is a clustered index: change index to + the clustered index if we are updating a secondary index record (or we + could as well skip writing the sys col values to the log in this case + because they are not needed for a secondary index record update) */ + + index = dict_table_get_first_index(index->table); + log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr, mtr); mach_write_to_2(log_ptr, rec - buf_frame_align(rec)); @@ -1394,13 +1404,10 @@ btr_cur_update_in_place( buf_block_t* block; ulint err; rec_t* rec; - dulint roll_ptr; + dulint roll_ptr = ut_dulint_zero; trx_t* trx; ibool was_delete_marked; - /* Only clustered index records are updated using this function */ - ut_ad(cursor->index->type & DICT_CLUSTERED); - rec = btr_cur_get_rec(cursor); index = cursor->index; trx = thr_get_trx(thr); @@ -1425,7 +1432,12 @@ btr_cur_update_in_place( block = buf_block_align(rec); if (block->is_hashed) { - if (row_upd_changes_ord_field_binary(NULL, index, update)) { + /* The function row_upd_changes_ord_field_binary works only + if the update vector was built for a clustered index, we must + NOT call it if index is secondary */ + + if (!(index->type & DICT_CLUSTERED) + || row_upd_changes_ord_field_binary(NULL, index, update)) { /* Remove possible hash index pointer to this record */ btr_search_update_hash_on_delete(cursor); @@ -1499,9 +1511,6 @@ btr_cur_optimistic_update( mem_heap_t* heap; ibool reorganized = FALSE; ulint i; - - /* Only clustered index records are updated using this function */ - ut_ad((cursor->index)->type & DICT_CLUSTERED); page = btr_cur_get_page(cursor); rec = btr_cur_get_rec(cursor); @@ -1551,8 +1560,8 @@ btr_cur_optimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); - row_upd_index_replace_new_col_vals(new_entry, index, update, NULL); - + row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update, + NULL); old_rec_size = rec_get_size(rec); new_rec_size = rec_get_converted_size(new_entry); @@ -1735,7 +1744,6 @@ btr_cur_pessimistic_update( index = cursor->index; tree = index->tree; - ut_ad(index->type & DICT_CLUSTERED); ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), @@ -1786,8 +1794,8 @@ btr_cur_pessimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); - row_upd_index_replace_new_col_vals(new_entry, index, update, heap); - + row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update, + heap); if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr); diff --git a/innobase/include/btr0cur.h b/innobase/include/btr0cur.h index 506877333c3..31aecef8104 100644 --- a/innobase/include/btr0cur.h +++ b/innobase/include/btr0cur.h @@ -188,22 +188,6 @@ btr_cur_pessimistic_insert( que_thr_t* thr, /* in: query thread or NULL */ mtr_t* mtr); /* in: mtr */ /***************************************************************** -Updates a secondary index record when the update causes no size -changes in its fields. The only case when this function is currently -called is that in a char field characters change to others which -are identified in the collation order. */ - -ulint -btr_cur_update_sec_rec_in_place( -/*============================*/ - /* out: DB_SUCCESS or error number */ - btr_cur_t* cursor, /* in: cursor on the record to update; - cursor stays valid and positioned on the - same record */ - upd_t* update, /* in: update vector */ - que_thr_t* thr, /* in: query thread */ - mtr_t* mtr); /* in: mtr */ -/***************************************************************** Updates a record when the update causes no size changes in its fields. */ ulint diff --git a/innobase/include/row0upd.h b/innobase/include/row0upd.h index 473c55c7ef9..f5e0a88231f 100644 --- a/innobase/include/row0upd.h +++ b/innobase/include/row0upd.h @@ -123,8 +123,8 @@ row_upd_changes_field_size_or_external( /* out: TRUE if the update changes the size of some field in index or the field is external in rec or update */ - rec_t* rec, /* in: record in clustered index */ - dict_index_t* index, /* in: clustered index */ + rec_t* rec, /* in: record in index */ + dict_index_t* index, /* in: index */ upd_t* update);/* in: update vector */ /*************************************************************** Replaces the new column values stored in the update vector to the record @@ -172,12 +172,30 @@ Replaces the new column values stored in the update vector to the index entry given. */ void +row_upd_index_replace_new_col_vals_index_pos( +/*=========================================*/ + dtuple_t* entry, /* in/out: index entry where replaced */ + dict_index_t* index, /* in: index; NOTE that this may also be a + non-clustered index */ + upd_t* update, /* in: an update vector built for the index so + that the field number in an upd_field is the + index position */ + mem_heap_t* heap); /* in: memory heap to which we allocate and + copy the new values, set this as NULL if you + do not want allocation */ +/*************************************************************** +Replaces the new column values stored in the update vector to the index entry +given. */ + +void row_upd_index_replace_new_col_vals( /*===============================*/ dtuple_t* entry, /* in/out: index entry where replaced */ - dict_index_t* index, /* in: index; NOTE that may also be a + dict_index_t* index, /* in: index; NOTE that this may also be a non-clustered index */ - upd_t* update, /* in: update vector */ + upd_t* update, /* in: an update vector built for the + CLUSTERED index so that the field number in + an upd_field is the clustered index position */ mem_heap_t* heap); /* in: memory heap to which we allocate and copy the new values, set this as NULL if you do not want allocation */ @@ -199,7 +217,9 @@ row_upd_changes_ord_field_binary( known when this function is called, e.g., at compile time */ dict_index_t* index, /* in: index of the record */ - upd_t* update);/* in: update vector for the row */ + upd_t* update);/* in: update vector for the row; NOTE: the + field numbers in this MUST be clustered index + positions! */ /*************************************************************** Checks if an update vector changes an ordering field of an index record. This function is fast if the update vector is short or the number of ordering @@ -271,7 +291,10 @@ row_upd_index_parse( /* Update vector field */ struct upd_field_struct{ - ulint field_no; /* field number in the clustered + ulint field_no; /* field number in an index, usually + the clustered index, but in updating + a secondary index record in btr0cur.c + this is the position in the secondary index */ que_node_t* exp; /* expression for calculating a new value: it refers to column values and diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index af589cd9441..7fdca02ee94 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -339,6 +339,11 @@ lock_deadlock_recursive( ulint* cost); /* in/out: number of calculation steps thus far: if this exceeds LOCK_MAX_N_STEPS_... we return TRUE */ + +#define lock_mutex_enter_kernel() mutex_enter(&kernel_mutex) +#define lock_mutex_exit_kernel() mutex_exit(&kernel_mutex) + +#ifdef notdefined /************************************************************************* Reserves the kernel mutex. This function is used in this module to allow monitoring the contention degree on the kernel mutex caused by the lock @@ -362,6 +367,7 @@ lock_mutex_exit_kernel(void) { mutex_exit(&kernel_mutex); } +#endif #ifdef notdefined diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 1a7864be5e9..c89f41f69ad 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -225,11 +225,15 @@ ulint row_ins_sec_index_entry_by_modify( /*==============================*/ /* out: DB_SUCCESS or error code */ + ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, + depending on whether mtr holds just a leaf + latch or also a tree latch */ btr_cur_t* cursor, /* in: B-tree cursor */ dtuple_t* entry, /* in: index entry to insert */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr) /* in: mtr */ { + big_rec_t* dummy_big_rec; mem_heap_t* heap; upd_t* update; rec_t* rec; @@ -241,16 +245,28 @@ row_ins_sec_index_entry_by_modify( ut_ad(rec_get_deleted_flag(rec)); /* We know that in the alphabetical ordering, entry and rec are - identical. But in their binary form there may be differences if + identified. But in their binary form there may be differences if there are char fields in them. Therefore we have to calculate the - difference and do an update-in-place if necessary. */ + difference. */ heap = mem_heap_create(1024); update = row_upd_build_sec_rec_difference_binary(cursor->index, entry, rec, heap); + if (mode == BTR_MODIFY_LEAF) { + /* Try an optimistic updating of the record, keeping changes + within the page */ - err = btr_cur_update_sec_rec_in_place(cursor, update, thr, mtr); + err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor, + update, 0, thr, mtr); + if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { + err = DB_FAIL; + } + } else { + ut_a(mode == BTR_MODIFY_TREE); + err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, + &dummy_big_rec, update, 0, thr, mtr); + } mem_heap_free(heap); @@ -1838,7 +1854,8 @@ row_ins_index_entry_low( ext_vec, n_ext_vec, thr, &mtr); } else { - err = row_ins_sec_index_entry_by_modify(&cursor, entry, + err = row_ins_sec_index_entry_by_modify(mode, &cursor, + entry, thr, &mtr); } diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index f41574b2855..e6080a5f201 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -51,7 +51,8 @@ to que_run_threads: this is to allow canceling runaway queries */ /************************************************************************ Returns TRUE if the user-defined column values in a secondary index record -are the same as the corresponding columns in the clustered index record. +are alphabetically the same as the corresponding columns in the clustered +index record. NOTE: the comparison is NOT done as a binary comparison, but character fields are compared with collation! */ static @@ -96,11 +97,6 @@ row_sel_sec_rec_is_for_clust_rec( clust_len = ifield->prefix_len; } - if (sec_len != clust_len) { - - return(FALSE); - } - if (0 != cmp_data_data(dict_col_get_type(col), clust_field, clust_len, sec_field, sec_len)) { diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c index 0a050e0a1b6..1bfd71f8c64 100644 --- a/innobase/row/row0umod.c +++ b/innobase/row/row0umod.c @@ -377,8 +377,14 @@ row_undo_mod_del_mark_or_remove_sec_low( } /*************************************************************** -Delete marks or removes a secondary index entry if found. */ -UNIV_INLINE +Delete marks or removes a secondary index entry if found. +NOTE that if we updated the fields of a delete-marked secondary index record +so that alphabetically they stayed the same, e.g., 'abc' -> 'aBc', we cannot +return to the original values because we do not know them. But this should +not cause problems because in row0sel.c, in queries we always retrieve the +clustered index record or an earlier version of it, if the secondary index +record through which we do the search is delete-marked. */ +static ulint row_undo_mod_del_mark_or_remove_sec( /*================================*/ @@ -403,20 +409,31 @@ row_undo_mod_del_mark_or_remove_sec( } /*************************************************************** -Delete unmarks a secondary index entry which must be found. */ +Delete unmarks a secondary index entry which must be found. It might not be +delete-marked at the moment, but it does not harm to unmark it anyway. We also +need to update the fields of the secondary index record if we updated its +fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'. */ static -void -row_undo_mod_del_unmark_sec( -/*========================*/ +ulint +row_undo_mod_del_unmark_sec_and_undo_update( +/*========================================*/ + /* out: DB_FAIL or DB_SUCCESS or + DB_OUT_OF_FILE_SPACE */ + ulint mode, /* in: search mode: BTR_MODIFY_LEAF or + BTR_MODIFY_TREE */ undo_node_t* node, /* in: row undo node */ que_thr_t* thr, /* in: query thread */ dict_index_t* index, /* in: index */ dtuple_t* entry) /* in: index entry */ { + mem_heap_t* heap; btr_pcur_t pcur; btr_cur_t* btr_cur; - ulint err; + upd_t* update; + rec_t* rec; + ulint err = DB_SUCCESS; ibool found; + big_rec_t* dummy_big_rec; mtr_t mtr; char err_buf[1000]; @@ -425,8 +442,8 @@ row_undo_mod_del_unmark_sec( log_free_check(); mtr_start(&mtr); - found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, - &mtr); + found = row_search_index_entry(index, entry, mode, &pcur, &mtr); + if (!found) { fprintf(stderr, "InnoDB: error in sec index entry del undo in\n" @@ -443,17 +460,47 @@ row_undo_mod_del_unmark_sec( "%s\nInnoDB: Make a detailed bug report and send it\n", err_buf); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); - } else { btr_cur = btr_pcur_get_btr_cur(&pcur); + rec = btr_cur_get_rec(btr_cur); + err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG, btr_cur, FALSE, thr, &mtr); - ut_ad(err == DB_SUCCESS); + ut_a(err == DB_SUCCESS); + heap = mem_heap_create(100); + + update = row_upd_build_sec_rec_difference_binary(index, entry, + rec, heap); + if (upd_get_n_fields(update) == 0) { + + /* Do nothing */ + + } else if (mode == BTR_MODIFY_LEAF) { + /* Try an optimistic updating of the record, keeping + changes within the page */ + + err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG + | BTR_NO_LOCKING_FLAG, + btr_cur, update, 0, thr, &mtr); + if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { + err = DB_FAIL; + } + } else { + ut_a(mode == BTR_MODIFY_TREE); + err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG + | BTR_NO_LOCKING_FLAG, + btr_cur, &dummy_big_rec, + update, 0, thr, &mtr); + } + + mem_heap_free(heap); } btr_pcur_close(&pcur); mtr_commit(&mtr); + + return(err); } /*************************************************************** @@ -501,13 +548,14 @@ static ulint row_undo_mod_del_mark_sec( /*======================*/ - /* out: DB_SUCCESS */ + /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ undo_node_t* node, /* in: row undo node */ que_thr_t* thr) /* in: query thread */ { mem_heap_t* heap; dtuple_t* entry; dict_index_t* index; + ulint err; heap = mem_heap_create(1024); @@ -516,7 +564,21 @@ row_undo_mod_del_mark_sec( entry = row_build_index_entry(node->row, index, heap); - row_undo_mod_del_unmark_sec(node, thr, index, entry); + err = row_undo_mod_del_unmark_sec_and_undo_update( + BTR_MODIFY_LEAF, + node, thr, index, entry); + if (err == DB_FAIL) { + err = row_undo_mod_del_unmark_sec_and_undo_update( + BTR_MODIFY_TREE, + node, thr, index, entry); + } + + if (err != DB_SUCCESS) { + + mem_heap_free(heap); + + return(err); + } node->index = dict_table_get_next_index(node->index); } @@ -532,7 +594,7 @@ static ulint row_undo_mod_upd_exist_sec( /*=======================*/ - /* out: DB_SUCCESS or error code */ + /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ undo_node_t* node, /* in: row undo node */ que_thr_t* thr) /* in: query thread */ { @@ -558,22 +620,48 @@ row_undo_mod_upd_exist_sec( /* Build the newest version of the index entry */ entry = row_build_index_entry(node->row, index, heap); + /* NOTE that if we updated the fields of a + delete-marked secondary index record so that + alphabetically they stayed the same, e.g., + 'abc' -> 'aBc', we cannot return to the original + values because we do not know them. But this should + not cause problems because in row0sel.c, in queries + we always retrieve the clustered index record or an + earlier version of it, if the secondary index record + through which we do the search is delete-marked. */ + err = row_undo_mod_del_mark_or_remove_sec(node, thr, - index, entry); + index, entry); if (err != DB_SUCCESS) { mem_heap_free(heap); return(err); } - + /* We may have to update the delete mark in the secondary index record of the previous version of - the row */ + the row. We also need to update the fields of + the secondary index record if we updated its fields + but alphabetically they stayed the same, e.g., + 'abc' -> 'aBc'. */ row_upd_index_replace_new_col_vals(entry, index, node->update, NULL); + err = row_undo_mod_del_unmark_sec_and_undo_update( + BTR_MODIFY_LEAF, + node, thr, index, entry); + if (err == DB_FAIL) { + err = + row_undo_mod_del_unmark_sec_and_undo_update( + BTR_MODIFY_TREE, + node, thr, index, entry); + } - row_undo_mod_del_unmark_sec(node, thr, index, entry); + if (err != DB_SUCCESS) { + mem_heap_free(heap); + + return(err); + } } node->index = dict_table_get_next_index(node->index); diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 606f7404d50..b9e9b8c15c9 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -361,8 +361,8 @@ row_upd_changes_field_size_or_external( /* out: TRUE if the update changes the size of some field in index or the field is external in rec or update */ - rec_t* rec, /* in: record in clustered index */ - dict_index_t* index, /* in: clustered index */ + rec_t* rec, /* in: record in index */ + dict_index_t* index, /* in: index */ upd_t* update) /* in: update vector */ { upd_field_t* upd_field; @@ -372,8 +372,6 @@ row_upd_changes_field_size_or_external( ulint n_fields; ulint i; - ut_ad(index->type & DICT_CLUSTERED); - n_fields = upd_get_n_fields(update); for (i = 0; i < n_fields; i++) { @@ -698,7 +696,7 @@ row_upd_build_sec_rec_difference_binary( ulint i; /* This function is used only for a secondary index */ - ut_ad(0 == (index->type & DICT_CLUSTERED)); + ut_a(0 == (index->type & DICT_CLUSTERED)); update = upd_create(dtuple_get_n_fields(entry), heap); @@ -710,7 +708,13 @@ row_upd_build_sec_rec_difference_binary( dfield = dtuple_get_nth_field(entry, i); - ut_a(len == dfield_get_len(dfield)); + /* NOTE that it may be that len != dfield_get_len(dfield) if we + are updating in a character set and collation where strings of + different length can be equal in an alphabetical comparison, + and also in the case where we have a column prefix index + and the last characters in the index field are spaces; the + latter case probably caused the assertion failures reported at + row0upd.c line 713 in versions 4.0.14 - 4.0.16. */ /* NOTE: we compare the fields as binary strings! (No collation) */ @@ -820,12 +824,76 @@ Replaces the new column values stored in the update vector to the index entry given. */ void +row_upd_index_replace_new_col_vals_index_pos( +/*=========================================*/ + dtuple_t* entry, /* in/out: index entry where replaced */ + dict_index_t* index, /* in: index; NOTE that this may also be a + non-clustered index */ + upd_t* update, /* in: an update vector built for the index so + that the field number in an upd_field is the + index position */ + mem_heap_t* heap) /* in: memory heap to which we allocate and + copy the new values, set this as NULL if you + do not want allocation */ +{ + dict_field_t* field; + upd_field_t* upd_field; + dfield_t* dfield; + dfield_t* new_val; + ulint j; + ulint i; + + ut_ad(index); + + dtuple_set_info_bits(entry, update->info_bits); + + for (j = 0; j < dict_index_get_n_fields(index); j++) { + + field = dict_index_get_nth_field(index, j); + + for (i = 0; i < upd_get_n_fields(update); i++) { + + upd_field = upd_get_nth_field(update, i); + + if (upd_field->field_no == j) { + + dfield = dtuple_get_nth_field(entry, j); + + new_val = &(upd_field->new_val); + + dfield_set_data(dfield, new_val->data, + new_val->len); + if (heap && new_val->len != UNIV_SQL_NULL) { + dfield->data = mem_heap_alloc(heap, + new_val->len); + ut_memcpy(dfield->data, new_val->data, + new_val->len); + } + + if (field->prefix_len > 0 + && new_val->len != UNIV_SQL_NULL + && new_val->len > field->prefix_len) { + + dfield->len = field->prefix_len; + } + } + } + } +} + +/*************************************************************** +Replaces the new column values stored in the update vector to the index entry +given. */ + +void row_upd_index_replace_new_col_vals( /*===============================*/ dtuple_t* entry, /* in/out: index entry where replaced */ dict_index_t* index, /* in: index; NOTE that this may also be a non-clustered index */ - upd_t* update, /* in: update vector */ + upd_t* update, /* in: an update vector built for the + CLUSTERED index so that the field number in + an upd_field is the clustered index position */ mem_heap_t* heap) /* in: memory heap to which we allocate and copy the new values, set this as NULL if you do not want allocation */ @@ -893,7 +961,9 @@ row_upd_changes_ord_field_binary( known when this function is called, e.g., at compile time */ dict_index_t* index, /* in: index of the record */ - upd_t* update) /* in: update vector for the row */ + upd_t* update) /* in: update vector for the row; NOTE: the + field numbers in this MUST be clustered index + positions! */ { upd_field_t* upd_field; dict_field_t* ind_field; diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index d4a463d8a96..fca56389e45 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -117,9 +117,10 @@ row_vers_impl_x_locked_off_kernel( return(NULL); } - /* We look up if some earlier version of the clustered index record - would require rec to be in a different state (delete marked or - unmarked, or not existing). If there is such a version, then rec was + /* We look up if some earlier version, which was modified by the trx_id + transaction, of the clustered index record would require rec to be in + a different state (delete marked or unmarked, or have different field + values, or not existing). If there is such a version, then rec was modified by the trx_id transaction, and it has an implicit x-lock on rec. Note that if clust_rec itself would require rec to be in a different state, then the trx_id transaction has not yet had time to @@ -188,6 +189,8 @@ row_vers_impl_x_locked_off_kernel( vers_del = rec_get_deleted_flag(prev_version); + /* We check if entry and rec are identified in the alphabetical + ordering */ if (0 == cmp_dtuple_rec(entry, rec)) { /* The delete marks of rec and prev_version should be equal for rec to be in the state required by @@ -198,6 +201,20 @@ row_vers_impl_x_locked_off_kernel( break; } + + /* It is possible that the row was updated so that the + secondary index record remained the same in + alphabetical ordering, but the field values changed + still. For example, 'abc' -> 'ABC'. Check also that. */ + + dtuple_set_types_binary(entry, + dtuple_get_n_fields(entry)); + if (0 != cmp_dtuple_rec(entry, rec)) { + + trx = trx_get_on_id(trx_id); + + break; + } } else if (!rec_del) { /* The delete mark should be set in rec for it to be in the state required by prev_version */ @@ -256,8 +273,8 @@ row_vers_must_preserve_del_marked( Finds out if a version of the record, where the version >= the current purge view, should have ientry as its secondary index entry. We check if there is any not delete marked version of the record where the trx -id >= purge view, and the secondary index entry == ientry; exactly in -this case we return TRUE. */ +id >= purge view, and the secondary index entry and ientry are identified in +the alphabetical ordering; exactly in this case we return TRUE. */ ibool row_vers_old_has_index_entry( diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index a4b300a0448..03c8436c13f 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -94,13 +94,32 @@ my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list); static my_bool mysql_client_init= 0; static my_bool org_my_init_done= 0; -void mysql_once_init(void) + +/* + Initialize the MySQL library + + SYNOPSIS + mysql_once_init() + + NOTES + Can't be static on NetWare + This function is called by mysql_init() and indirectly called + by mysql_query(), so one should never have to call this from an + outside program. + + RETURN + 0 ok + 1 could not initialize environment (out of memory or thread keys) +*/ + +int mysql_once_init(void) { if (!mysql_client_init) { mysql_client_init=1; org_my_init_done=my_init_done; - my_init(); /* Will init threads */ + if (my_init()) /* Will init threads */ + return 1; init_client_errs(); if (!mysql_port) { @@ -133,18 +152,19 @@ void mysql_once_init(void) #endif } #ifdef THREAD - else - my_thread_init(); /* Init if new thread */ + else if (my_thread_init()) /* Init if new thread */ + return 1; #endif + return 0; } + #ifndef EMBEDDED_LIBRARY int STDCALL mysql_server_init(int argc __attribute__((unused)), char **argv __attribute__((unused)), char **groups __attribute__((unused))) { - mysql_once_init(); - return 0; + return (int) mysql_once_init(); } void STDCALL mysql_server_end() diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index f48a12b6f28..8cbb7a71a43 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -373,10 +373,13 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, to alloc queue with alloc_root() */ res=ftb->queue.max_elements=1+query_len/(min(ft_min_word_len,2)+1); - ftb->queue.root=(byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*)); + if (!(ftb->queue.root= + (byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*)))) + goto err; reinit_queue(& ftb->queue, res, 0, 0, (int (*)(void*,byte*,byte*))FTB_WORD_cmp, 0); - ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR)); + if (!(ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR)))) + goto err; ftbe->weight=1; ftbe->flags=FTB_FLAG_YES; ftbe->nos=1; @@ -394,6 +397,10 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, if (ftb->queue.elements<2) ftb->with_scan &= ~FTB_FLAG_TRUNC; ftb->state=READY; return ftb; +err: + free_root(& ftb->mem_root, MYF(0)); + my_free((gptr)ftb,MYF(0)); + return 0; } diff --git a/myisam/mi_check.c b/myisam/mi_check.c index f9e943fe42c..02bca2911b4 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -112,20 +112,13 @@ int chk_status(MI_CHECK *param, register MI_INFO *info) int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag) { reg2 ha_rows i; - uint j,delete_link_length; + uint delete_link_length; my_off_t empty,next_link,old_link; char buff[22],buff2[22]; DBUG_ENTER("chk_del"); - if (!(test_flag & T_SILENT)) - puts("- check key delete-chain"); - LINT_INIT(old_link); param->record_checksum=0; - param->key_file_blocks=info->s->base.keystart; - for (j=0 ; j < info->s->state.header.max_block_size ; j++) - if (check_k_link(param,info,j)) - goto wrong; delete_link_length=((info->s->options & HA_OPTION_PACK_RECORD) ? 20 : info->s->rec_reflength+1); @@ -352,6 +345,18 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) char buff[22],buff2[22]; DBUG_ENTER("chk_key"); + if (!(param->testflag & T_SILENT)) + puts("- check key delete-chain"); + + param->key_file_blocks=info->s->base.keystart; + for (key=0 ; key < info->s->state.header.max_block_size ; key++) + if (check_k_link(param,info,key)) + { + if (param->testflag & T_VERBOSE) puts(""); + mi_check_print_error(param,"key delete-link-chain corrupted"); + DBUG_RETURN(-1); + } + if (!(param->testflag & T_SILENT)) puts("- check index reference"); all_keydata=all_totaldata=key_totlength=0; @@ -1208,9 +1213,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, if (!rep_quick) { /* Get real path for data file */ - fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); if ((new_file=my_raid_create(fn_format(param->temp_filename, - param->temp_filename,"", + share->data_file_name, "", DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, share->base.raid_type, @@ -1882,11 +1886,9 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, if (!rep_quick) { /* Get real path for data file */ - fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); if ((new_file=my_raid_create(fn_format(param->temp_filename, - param->temp_filename, "", - DATA_TMP_EXT, - 2+4), + share->data_file_name, "", + DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, share->base.raid_type, share->base.raid_chunks, @@ -2248,9 +2250,8 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, if (!rep_quick) { /* Get real path for data file */ - fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); if ((new_file=my_raid_create(fn_format(param->temp_filename, - param->temp_filename, "", + share->data_file_name, "", DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index 6548b38c135..02d1c7d05d6 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -137,6 +137,10 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg, { uint tmp_length; get_key_length(tmp_length,key); + /* + The following command sometimes gives a warning from valgrind. + Not yet sure if the bug is in valgrind, glibc or mysqld + */ VOID(fprintf(stream,"%.*s",(int) tmp_length,key)); key+=tmp_length; break; diff --git a/myisam/mi_key.c b/myisam/mi_key.c index 93e3b9621f3..97af156e89a 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -19,6 +19,7 @@ #include "myisamdef.h" #include "m_ctype.h" #include "sp_defs.h" +#include <assert.h> #ifdef HAVE_IEEEFP_H #include <ieeefp.h> #endif @@ -397,53 +398,86 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf) return(-1); /* Wrong data to read */ } + +/* + Update auto_increment info - /* Update auto_increment info */ + SYNOPSIS + update_auto_increment() + info MyISAM handler + record Row to update + + IMPLEMENTATION + Only replace the auto_increment value if it is higher than the previous + one. For signed columns we don't update the auto increment value if it's + less than zero. +*/ void update_auto_increment(MI_INFO *info,const byte *record) { - ulonglong value; - HA_KEYSEG *keyseg=info->s->keyinfo[info->s->base.auto_key-1].seg; - const uchar *key=(uchar*) record+keyseg->start; + ulonglong value= 0; /* Store unsigned values here */ + longlong s_value= 0; /* Store signed values here */ + HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg; + const uchar *key= (uchar*) record + keyseg->start; switch (keyseg->type) { case HA_KEYTYPE_INT8: + s_value= (longlong) *(char*)key; + break; case HA_KEYTYPE_BINARY: value=(ulonglong) *(uchar*) key; break; case HA_KEYTYPE_SHORT_INT: + s_value= (longlong) sint2korr(key); + break; case HA_KEYTYPE_USHORT_INT: value=(ulonglong) uint2korr(key); break; case HA_KEYTYPE_LONG_INT: + s_value= (longlong) sint4korr(key); + break; case HA_KEYTYPE_ULONG_INT: value=(ulonglong) uint4korr(key); break; case HA_KEYTYPE_INT24: + s_value= (longlong) sint3korr(key); + break; case HA_KEYTYPE_UINT24: value=(ulonglong) uint3korr(key); break; - case HA_KEYTYPE_FLOAT: /* This shouldn't be used */ + case HA_KEYTYPE_FLOAT: /* This shouldn't be used */ { float f_1; float4get(f_1,key); - value = (ulonglong) f_1; + /* Ignore negative values */ + value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1; break; } - case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */ + case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */ { double f_1; float8get(f_1,key); - value = (ulonglong) f_1; + /* Ignore negative values */ + value = (f_1 < 0.0) ? 0 : (ulonglong) f_1; break; } case HA_KEYTYPE_LONGLONG: + s_value= sint8korr(key); + break; case HA_KEYTYPE_ULONGLONG: value= uint8korr(key); break; default: - value=0; /* Error */ + DBUG_ASSERT(0); + value=0; /* Error */ break; } - set_if_bigger(info->s->state.auto_increment,value); + + /* + The following code works becasue if s_value < 0 then value is 0 + and if s_value == 0 then value will contain either s_value or the + correct value. + */ + set_if_bigger(info->s->state.auto_increment, + (s_value > 0) ? (ulonglong) s_value : value); } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index d5492ae5e35..2c4661c4d3e 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -867,6 +867,8 @@ char *mi_state_info_read(char *ptr, MI_STATE_INFO *state) state->status = mi_uint4korr(ptr); ptr +=4; state->update_count=mi_uint4korr(ptr); ptr +=4; + ptr+= state->state_diff_length; + for (i=0; i < keys; i++) { state->key_root[i]= mi_sizekorr(ptr); ptr +=8; @@ -875,7 +877,6 @@ char *mi_state_info_read(char *ptr, MI_STATE_INFO *state) { state->key_del[i] = mi_sizekorr(ptr); ptr +=8; } - ptr+= state->state_diff_length; state->sec_index_changed = mi_uint4korr(ptr); ptr +=4; state->sec_index_used = mi_uint4korr(ptr); ptr +=4; state->version = mi_uint4korr(ptr); ptr +=4; diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index 05317c0f845..1390141df51 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -244,3 +244,29 @@ a b 0 13 500 14 drop table t1; +create table t1 (a int not null auto_increment primary key); +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +last_insert_id() +1 +insert into t1 values (NULL); +select * from t1; +a +-1 +1 +2 +drop table t1; +create table t1 (a int not null auto_increment primary key) /*!41002 type=heap */; +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +last_insert_id() +1 +insert into t1 values (NULL); +select * from t1; +a +-1 +1 +2 +drop table t1; diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index 6021f02f2a6..dd5633af90d 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1145,3 +1145,14 @@ x 7 6 drop table t1; +create table t1 ( c char(8) not null ) type=bdb; +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; +create table t2 (c char(8) not null, b char(8) not null, a char(8) not null, primary key(a,b,c)) type=bdb; +insert into t2 select * from t1; +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; +drop table t1,t2; diff --git a/mysql-test/r/binary.result b/mysql-test/r/binary.result index 5da627a30b9..d4576791aed 100644 --- a/mysql-test/r/binary.result +++ b/mysql-test/r/binary.result @@ -66,6 +66,7 @@ concat("-",a,"-",b,"-") alter table t1 modify b tinytext not null, drop key b, add key (b(100)); select concat("-",a,"-",b,"-") from t1 where b="hello "; concat("-",a,"-",b,"-") +-hello-hello- select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; concat("-",a,"-",b,"-") -hello-hello- diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index bdac40d3378..ec00c850197 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -47,7 +47,7 @@ sum(all a) count(all a) avg(all a) std(all a) variance(all a) bit_or(all a) bit_ 21 6 3.5000 1.7078 2.9167 7 0 1 6 E select grp, sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; grp sum(a) count(a) avg(a) std(a) variance(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) -NULL NULL 0 NULL NULL NULL 0 0 NULL NULL +NULL NULL 0 NULL NULL NULL 0 1844674407379551615 NULL NULL 1 1 1 1.0000 0.0000 0.0000 1 1 1 1 a a 2 5 2 2.5000 0.5000 0.2500 3 2 2 3 b c 3 15 3 5.0000 0.8165 0.6667 7 4 4 6 C E @@ -632,3 +632,15 @@ select a from t1 having a=1; a 1 drop table t1; +create table t1 (col int); +insert into t1 values (-1), (-2), (-3); +select bit_and(col), bit_or(col) from t1; +bit_and(col) bit_or(col) +18446744073709551612 18446744073709551615 +select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; +bit_and(col) bit_or(col) +18446744073709551613 18446744073709551613 +18446744073709551614 18446744073709551614 +18446744073709551615 18446744073709551615 +drop table t1; + diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index 25a7ac20b66..fb1e715ac3b 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -17,3 +17,21 @@ Note 1003 select high_priority (1 | (1 + 1)) AS `1 | (1+1)`,(5 & 3) AS `5 & 3`,b select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60; 1 << 32 1 << 63 1 << 64 4 >> 2 4 >> 63 1<< 63 >> 60 4294967296 9223372036854775808 0 1 0 8 +select -1 | 0, -1 ^ 0, -1 & 0; +-1 | 0 -1 ^ 0 -1 & 0 +18446744073709551615 18446744073709551615 0 +select -1 | 1, -1 ^ 1, -1 & 1; +-1 | 1 -1 ^ 1 -1 & 1 +18446744073709551615 18446744073709551614 1 +select 1 | -1, 1 ^ -1, 1 & -1; +1 | -1 1 ^ -1 1 & -1 +18446744073709551615 18446744073709551614 1 +select 0 | -1, 0 ^ -1, 0 & -1; +0 | -1 0 ^ -1 0 & -1 +18446744073709551615 18446744073709551615 0 +select -1 >> 0, -1 << 0; +-1 >> 0 -1 << 0 +18446744073709551615 18446744073709551615 +select -1 >> 1, -1 << 1; +-1 >> 1 -1 << 1 +9223372036854775807 18446744073709551614 diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index ac075e129ee..aaebd33d010 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -144,12 +144,12 @@ montymontymontymontymonty * * select reverse('abc'),reverse('abcd'); reverse('abc') reverse('abcd') cba dcba -select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12'); -rpad('a',4,'1') rpad('a',4,'12') rpad('abcd',3,'12') -a111 a121 abc -select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12'); -lpad('a',4,'1') lpad('a',4,'12') lpad('abcd',3,'12') -111a 121a abc +select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12'), rpad(11, 10 , 22), rpad("ab", 10, 22); +rpad('a',4,'1') rpad('a',4,'12') rpad('abcd',3,'12') rpad(11, 10 , 22) rpad("ab", 10, 22) +a111 a121 abc 1122222222 ab22222222 +select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12'), lpad(11, 10 , 22); +lpad('a',4,'1') lpad('a',4,'12') lpad('abcd',3,'12') lpad(11, 10 , 22) +111a 121a abc 2222222211 select rpad(741653838,17,'0'),lpad(741653838,17,'0'); rpad(741653838,17,'0') lpad(741653838,17,'0') 74165383800000000 00000000741653838 @@ -159,6 +159,12 @@ abcdaba abaabcd select rpad('abcd',1,'ab'),lpad('abcd',1,'ab'); rpad('abcd',1,'ab') lpad('abcd',1,'ab') a a +select rpad('STRING', 20, CONCAT('p','a','d') ); +rpad('STRING', 20, CONCAT('p','a','d') ) +STRINGpadpadpadpadpa +select lpad('STRING', 20, CONCAT('p','a','d') ); +lpad('STRING', 20, CONCAT('p','a','d') ) +padpadpadpadpaSTRING select LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'),GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'); LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD') GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD') HAROLD HARRY @@ -183,6 +189,9 @@ NULL '\0\Z' select length(quote(concat(char(0),"test"))); length(quote(concat(char(0),"test"))) 8 +select hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))); +hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))) +27E0E3E6E7E8EAEB27 select reverse(""); reverse("") @@ -259,340 +268,3 @@ INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf'); SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password"); 1 DROP TABLE t1; -select 1=_latin1'1'; -1=_latin1'1' -1 -select _latin1'1'=1; -_latin1'1'=1 -1 -select _latin2'1'=1; -_latin2'1'=1 -1 -select 1=_latin2'1'; -1=_latin2'1' -1 -select _latin1'1'=_latin2'1'; -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation '=' -select row('a','b','c') = row('a','b','c'); -row('a','b','c') = row('a','b','c') -1 -select row('A','b','c') = row('a','b','c'); -row('A','b','c') = row('a','b','c') -1 -select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); -row('A' COLLATE latin1_bin,'b','c') = row('a','b','c') -0 -select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); -row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') -0 -select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' -select concat(_latin1'a',_latin2'a'); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat' -select concat(_latin1'a',_latin2'a',_latin5'a'); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin5_turkish_ci,COERCIBLE) for operation 'concat' -select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); -ERROR HY000: Illegal mix of collations for operation 'concat' -select FIELD('b','A','B'); -FIELD('b','A','B') -2 -select FIELD('B','A','B'); -FIELD('B','A','B') -2 -select FIELD('b' COLLATE latin1_bin,'A','B'); -FIELD('b' COLLATE latin1_bin,'A','B') -0 -select FIELD('b','A' COLLATE latin1_bin,'B'); -FIELD('b','A' COLLATE latin1_bin,'B') -0 -select FIELD(_latin2'b','A','B'); -ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' -select FIELD('b',_latin2'A','B'); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' -select FIELD('b',_latin2'A','B',1); -FIELD('b',_latin2'A','B',1) -1 -select POSITION(_latin1'B' IN _latin1'abcd'); -POSITION(_latin1'B' IN _latin1'abcd') -2 -select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); -POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin) -0 -select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd'); -POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd') -0 -select POSITION(_latin1'B' COLLATE latin1_general_ci IN _latin1'abcd' COLLATE latin1_bin); -ERROR HY000: Illegal mix of collations (latin1_bin,EXPLICIT) and (latin1_general_ci,EXPLICIT) for operation 'locate' -select POSITION(_latin1'B' IN _latin2'abcd'); -ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE) and (latin1_swedish_ci,COERCIBLE) for operation 'locate' -select FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'); -FIND_IN_SET(_latin1'B',_latin1'a,b,c,d') -2 -select FIND_IN_SET(_latin1'B' COLLATE latin1_general_ci,_latin1'a,b,c,d' COLLATE latin1_bin); -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'find_in_set' -select FIND_IN_SET(_latin1'B',_latin2'a,b,c,d'); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'find_in_set' -select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2); -SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2) -abcdabc -select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'substr_index' -select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2); -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'substr_index' -select _latin1'B' between _latin1'a' and _latin1'c'; -_latin1'B' between _latin1'a' and _latin1'c' -1 -select _latin1'B' collate latin1_bin between _latin1'a' and _latin1'c'; -_latin1'B' collate latin1_bin between _latin1'a' and _latin1'c' -0 -select _latin1'B' between _latin1'a' collate latin1_bin and _latin1'c'; -_latin1'B' between _latin1'a' collate latin1_bin and _latin1'c' -0 -select _latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin; -_latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin -0 -select _latin2'B' between _latin1'a' and _latin1'b'; -ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'between' -select _latin1'B' between _latin2'a' and _latin1'b'; -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'between' -select _latin1'B' between _latin1'a' and _latin2'b'; -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation 'between' -select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b'; -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation 'between' -select _latin1'B' in (_latin1'a',_latin1'b'); -_latin1'B' in (_latin1'a',_latin1'b') -1 -select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b'); -_latin1'B' collate latin1_bin in (_latin1'a',_latin1'b') -0 -select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b'); -_latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b') -0 -select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin); -_latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin) -0 -select _latin2'B' in (_latin1'a',_latin1'b'); -ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' -select _latin1'B' in (_latin2'a',_latin1'b'); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' -select _latin1'B' in (_latin1'a',_latin2'b'); -ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation ' IN ' -select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b'); -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' -select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin); -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_swedish_ci,COERCIBLE), (latin1_bin,EXPLICIT) for operation ' IN ' -select collation(bin(130)), coercibility(bin(130)); -collation(bin(130)) coercibility(bin(130)) -latin1_swedish_ci 3 -select collation(oct(130)), coercibility(oct(130)); -collation(oct(130)) coercibility(oct(130)) -latin1_swedish_ci 3 -select collation(conv(130,16,10)), coercibility(conv(130,16,10)); -collation(conv(130,16,10)) coercibility(conv(130,16,10)) -latin1_swedish_ci 3 -select collation(hex(130)), coercibility(hex(130)); -collation(hex(130)) coercibility(hex(130)) -latin1_swedish_ci 3 -select collation(char(130)), coercibility(hex(130)); -collation(char(130)) coercibility(hex(130)) -binary 3 -select collation(format(130,10)), coercibility(format(130,10)); -collation(format(130,10)) coercibility(format(130,10)) -latin1_swedish_ci 3 -select collation(lcase(_latin2'a')), coercibility(lcase(_latin2'a')); -collation(lcase(_latin2'a')) coercibility(lcase(_latin2'a')) -latin2_general_ci 3 -select collation(ucase(_latin2'a')), coercibility(ucase(_latin2'a')); -collation(ucase(_latin2'a')) coercibility(ucase(_latin2'a')) -latin2_general_ci 3 -select collation(left(_latin2'a',1)), coercibility(left(_latin2'a',1)); -collation(left(_latin2'a',1)) coercibility(left(_latin2'a',1)) -latin2_general_ci 3 -select collation(right(_latin2'a',1)), coercibility(right(_latin2'a',1)); -collation(right(_latin2'a',1)) coercibility(right(_latin2'a',1)) -latin2_general_ci 3 -select collation(substring(_latin2'a',1,1)), coercibility(substring(_latin2'a',1,1)); -collation(substring(_latin2'a',1,1)) coercibility(substring(_latin2'a',1,1)) -latin2_general_ci 3 -select collation(concat(_latin2'a',_latin2'b')), coercibility(concat(_latin2'a',_latin2'b')); -collation(concat(_latin2'a',_latin2'b')) coercibility(concat(_latin2'a',_latin2'b')) -latin2_general_ci 3 -select collation(lpad(_latin2'a',4,_latin2'b')), coercibility(lpad(_latin2'a',4,_latin2'b')); -collation(lpad(_latin2'a',4,_latin2'b')) coercibility(lpad(_latin2'a',4,_latin2'b')) -latin2_general_ci 3 -select collation(rpad(_latin2'a',4,_latin2'b')), coercibility(rpad(_latin2'a',4,_latin2'b')); -collation(rpad(_latin2'a',4,_latin2'b')) coercibility(rpad(_latin2'a',4,_latin2'b')) -latin2_general_ci 3 -select collation(concat_ws(_latin2'a',_latin2'b')), coercibility(concat_ws(_latin2'a',_latin2'b')); -collation(concat_ws(_latin2'a',_latin2'b')) coercibility(concat_ws(_latin2'a',_latin2'b')) -latin2_general_ci 3 -select collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')), coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c')); -collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')) coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c')) -latin2_general_ci 3 -select collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')), coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')); -collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')) coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')) -binary 3 -select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a ')); -collation(trim(_latin2' a ')) coercibility(trim(_latin2' a ')) -latin2_general_ci 3 -select collation(ltrim(_latin2' a ')), coercibility(ltrim(_latin2' a ')); -collation(ltrim(_latin2' a ')) coercibility(ltrim(_latin2' a ')) -latin2_general_ci 3 -select collation(rtrim(_latin2' a ')), coercibility(rtrim(_latin2' a ')); -collation(rtrim(_latin2' a ')) coercibility(rtrim(_latin2' a ')) -latin2_general_ci 3 -select collation(trim(LEADING _latin2' ' FROM _latin2'a')), coercibility(trim(LEADING _latin2'a' FROM _latin2'a')); -collation(trim(LEADING _latin2' ' FROM _latin2'a')) coercibility(trim(LEADING _latin2'a' FROM _latin2'a')) -latin2_general_ci 3 -select collation(trim(TRAILING _latin2' ' FROM _latin2'a')), coercibility(trim(TRAILING _latin2'a' FROM _latin2'a')); -collation(trim(TRAILING _latin2' ' FROM _latin2'a')) coercibility(trim(TRAILING _latin2'a' FROM _latin2'a')) -latin2_general_ci 3 -select collation(trim(BOTH _latin2' ' FROM _latin2'a')), coercibility(trim(BOTH _latin2'a' FROM _latin2'a')); -collation(trim(BOTH _latin2' ' FROM _latin2'a')) coercibility(trim(BOTH _latin2'a' FROM _latin2'a')) -latin2_general_ci 3 -select collation(repeat(_latin2'a',10)), coercibility(repeat(_latin2'a',10)); -collation(repeat(_latin2'a',10)) coercibility(repeat(_latin2'a',10)) -latin2_general_ci 3 -select collation(reverse(_latin2'ab')), coercibility(reverse(_latin2'ab')); -collation(reverse(_latin2'ab')) coercibility(reverse(_latin2'ab')) -latin2_general_ci 3 -select collation(quote(_latin2'ab')), coercibility(quote(_latin2'ab')); -collation(quote(_latin2'ab')) coercibility(quote(_latin2'ab')) -latin2_general_ci 3 -select collation(soundex(_latin2'ab')), coercibility(soundex(_latin2'ab')); -collation(soundex(_latin2'ab')) coercibility(soundex(_latin2'ab')) -latin2_general_ci 3 -select collation(substring(_latin2'ab',1)), coercibility(substring(_latin2'ab',1)); -collation(substring(_latin2'ab',1)) coercibility(substring(_latin2'ab',1)) -latin2_general_ci 3 -select collation(insert(_latin2'abcd',2,3,_latin2'ef')), coercibility(insert(_latin2'abcd',2,3,_latin2'ef')); -collation(insert(_latin2'abcd',2,3,_latin2'ef')) coercibility(insert(_latin2'abcd',2,3,_latin2'ef')) -latin2_general_ci 3 -select collation(replace(_latin2'abcd',_latin2'b',_latin2'B')), coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B')); -collation(replace(_latin2'abcd',_latin2'b',_latin2'B')) coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B')) -latin2_general_ci 3 -create table t1 -select -bin(130), -oct(130), -conv(130,16,10), -hex(130), -char(130), -format(130,10), -left(_latin2'a',1), -right(_latin2'a',1), -lcase(_latin2'a'), -ucase(_latin2'a'), -substring(_latin2'a',1,1), -concat(_latin2'a',_latin2'b'), -lpad(_latin2'a',4,_latin2'b'), -rpad(_latin2'a',4,_latin2'b'), -concat_ws(_latin2'a',_latin2'b'), -make_set(255,_latin2'a',_latin2'b',_latin2'c'), -export_set(255,_latin2'y',_latin2'n',_latin2' '), -trim(_latin2' a '), -ltrim(_latin2' a '), -rtrim(_latin2' a '), -trim(LEADING _latin2' ' FROM _latin2' a '), -trim(TRAILING _latin2' ' FROM _latin2' a '), -trim(BOTH _latin2' ' FROM _latin2' a '), -repeat(_latin2'a',10), -reverse(_latin2'ab'), -quote(_latin2'ab'), -soundex(_latin2'ab'), -substring(_latin2'ab',1), -insert(_latin2'abcd',2,3,_latin2'ef'), -replace(_latin2'abcd',_latin2'b',_latin2'B') -; -Warnings: -Warning 1264 Data truncated for column 'format(130,10)' at row 1 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `bin(130)` char(64) NOT NULL default '', - `oct(130)` char(64) NOT NULL default '', - `conv(130,16,10)` char(64) NOT NULL default '', - `hex(130)` char(6) NOT NULL default '', - `char(130)` char(1) NOT NULL default '', - `format(130,10)` char(4) NOT NULL default '', - `left(_latin2'a',1)` char(1) character set latin2 NOT NULL default '', - `right(_latin2'a',1)` char(1) character set latin2 NOT NULL default '', - `lcase(_latin2'a')` char(1) character set latin2 NOT NULL default '', - `ucase(_latin2'a')` char(1) character set latin2 NOT NULL default '', - `substring(_latin2'a',1,1)` char(1) character set latin2 NOT NULL default '', - `concat(_latin2'a',_latin2'b')` char(2) character set latin2 NOT NULL default '', - `lpad(_latin2'a',4,_latin2'b')` char(4) character set latin2 NOT NULL default '', - `rpad(_latin2'a',4,_latin2'b')` char(4) character set latin2 NOT NULL default '', - `concat_ws(_latin2'a',_latin2'b')` char(1) character set latin2 NOT NULL default '', - `make_set(255,_latin2'a',_latin2'b',_latin2'c')` char(5) character set latin2 NOT NULL default '', - `export_set(255,_latin2'y',_latin2'n',_latin2' ')` char(127) character set latin2 NOT NULL default '', - `trim(_latin2' a ')` char(3) character set latin2 NOT NULL default '', - `ltrim(_latin2' a ')` char(3) character set latin2 NOT NULL default '', - `rtrim(_latin2' a ')` char(3) character set latin2 NOT NULL default '', - `trim(LEADING _latin2' ' FROM _latin2' a ')` char(3) character set latin2 NOT NULL default '', - `trim(TRAILING _latin2' ' FROM _latin2' a ')` char(3) character set latin2 NOT NULL default '', - `trim(BOTH _latin2' ' FROM _latin2' a ')` char(3) character set latin2 NOT NULL default '', - `repeat(_latin2'a',10)` char(10) character set latin2 NOT NULL default '', - `reverse(_latin2'ab')` char(2) character set latin2 NOT NULL default '', - `quote(_latin2'ab')` char(6) character set latin2 NOT NULL default '', - `soundex(_latin2'ab')` char(4) character set latin2 NOT NULL default '', - `substring(_latin2'ab',1)` char(2) character set latin2 NOT NULL default '', - `insert(_latin2'abcd',2,3,_latin2'ef')` char(6) character set latin2 NOT NULL default '', - `replace(_latin2'abcd',_latin2'b',_latin2'B')` char(4) character set latin2 NOT NULL default '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1; -select SUBSTR('abcdefg',3,2); -SUBSTR('abcdefg',3,2) -cd -select SUBSTRING('abcdefg',3,2); -SUBSTRING('abcdefg',3,2) -cd -select SUBSTR('abcdefg',-3,2) FROM DUAL; -SUBSTR('abcdefg',-3,2) -ef -select SUBSTR('abcdefg',-1,5) FROM DUAL; -SUBSTR('abcdefg',-1,5) -g -select SUBSTR('abcdefg',0,0) FROM DUAL; -SUBSTR('abcdefg',0,0) - -select SUBSTR('abcdefg',-1,-1) FROM DUAL; -SUBSTR('abcdefg',-1,-1) - -select SUBSTR('abcdefg',1,-1) FROM DUAL; -SUBSTR('abcdefg',1,-1) - -create table t7 (s1 char); -select * from t7 -where concat(s1 collate latin1_general_ci,s1 collate latin1_swedish_ci) = 'AA'; -ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_swedish_ci,EXPLICIT) for operation 'concat' -drop table t7; -CREATE TABLE t1 ( -wid int(10) unsigned NOT NULL auto_increment, -data_podp date default NULL, -status_wnio enum('nowy','podp','real','arch') NOT NULL default 'nowy', -PRIMARY KEY(wid), -); -INSERT INTO t1 VALUES (8,NULL,'real'); -INSERT INTO t1 VALUES (9,NULL,'nowy'); -SELECT elt(status_wnio,data_podp) FROM t1 GROUP BY wid; -elt(status_wnio,data_podp) -NULL -NULL -DROP TABLE t1; -CREATE TABLE t1 (title text) ENGINE=MyISAM; -INSERT INTO t1 VALUES ('Congress reconvenes in September to debate welfare and adult education'); -INSERT INTO t1 VALUES ('House passes the CAREERS bill'); -SELECT CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) from t1; -CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) -NULL -</a>.......................... -DROP TABLE t1; -select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2); -substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2) substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2) -1abcd;2abcd 3abcd;4abcd -explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'mood' sounds like 'mud', aes_decrypt(aes_encrypt('abc','1'),'1'),concat('*',space(5),'*'), reverse('abc'), rpad('a',4,'1'), lpad('a',4,'1'), concat_ws(',','',NULL,'a'),make_set(255,_latin2'a',_latin2'b',_latin2'c'),elt(2,1),locate("a","b",2),format(130,10),char(0),conv(130,16,10),hex(130),binary 'HE', export_set(255,_latin2'y',_latin2'n',_latin2' '),FIELD('b' COLLATE latin1_bin,'A','B'),FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'),collation(conv(130,16,10)), coercibility(conv(130,16,10)),length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'),quote(1/0),crc32("123"),replace('aaaa','a','b'),insert('txs',2,1,'hi'),left(_latin2'a',1),right(_latin2'a',1),lcase(_latin2'a'),ucase(_latin2'a'),SUBSTR('abcdefg',3,2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),trim(_latin2' a '),ltrim(_latin2' a '),rtrim(_latin2' a '), decode(encode(repeat("a",100000),"monty"),"monty"); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used -Warnings: -Note 1003 select high_priority md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,(_latin1'HE' collate _latin1'BINARY') AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate _latin1'latin1_bin'),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")` diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index b3c3d8dff5c..c3f4b9475f9 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -95,11 +95,34 @@ week(19981231,2) week(19981231,3) week(20000101,2) week(20000101,3) 52 53 52 52 select week(20001231,2),week(20001231,3); week(20001231,2) week(20001231,3) -1 52 +53 52 +select week(19981231,0) as '0', week(19981231,1) as '1', week(19981231,2) as '2', week(19981231,3) as '3', week(19981231,4) as '4', week(19981231,5) as '5', week(19981231,6) as '6', week(19981231,7) as '7'; +0 1 2 3 4 5 6 7 +52 53 52 53 52 52 52 52 +select week(20000101,0) as '0', week(20000101,1) as '1', week(20000101,2) as '2', week(20000101,3) as '3', week(20000101,4) as '4', week(20000101,5) as '5', week(20000101,6) as '6', week(20000101,7) as '7'; +0 1 2 3 4 5 6 7 +0 0 52 52 0 0 52 52 +select week(20000106,0) as '0', week(20000106,1) as '1', week(20000106,2) as '2', week(20000106,3) as '3', week(20000106,4) as '4', week(20000106,5) as '5', week(20000106,6) as '6', week(20000106,7) as '7'; +0 1 2 3 4 5 6 7 +1 1 1 1 1 1 1 1 +select week(20001231,0) as '0', week(20001231,1) as '1', week(20001231,2) as '2', week(20001231,3) as '3', week(20001231,4) as '4', week(20001231,5) as '5', week(20001231,6) as '6', week(20001231,7) as '7'; +0 1 2 3 4 5 6 7 +53 52 53 52 53 52 1 52 +select week(20010101,0) as '0', week(20010101,1) as '1', week(20010101,2) as '2', week(20010101,3) as '3', week(20010101,4) as '4', week(20010101,5) as '5', week(20010101,6) as '6', week(20010101,7) as '7'; +0 1 2 3 4 5 6 7 +0 1 53 1 1 1 1 1 +select yearweek(20001231,0), yearweek(20001231,1), yearweek(20001231,2), yearweek(20001231,3), yearweek(20001231,4), yearweek(20001231,5), yearweek(20001231,6), yearweek(20001231,7); +yearweek(20001231,0) yearweek(20001231,1) yearweek(20001231,2) yearweek(20001231,3) yearweek(20001231,4) yearweek(20001231,5) yearweek(20001231,6) yearweek(20001231,7) +200053 200052 200053 200052 200101 200052 200101 200052 +set default_week_format = 6; +select week(20001231), week(20001231,6); +week(20001231) week(20001231,6) +1 1 +set default_week_format = 0; set default_week_format = 2; select week(20001231),week(20001231,2),week(20001231,0); week(20001231) week(20001231,2) week(20001231,0) -1 1 53 +53 53 53 set default_week_format = 0; select date_format('1998-12-31','%x-%v'),date_format('1999-01-01','%x-%v'); date_format('1998-12-31','%x-%v') date_format('1999-01-01','%x-%v') @@ -408,103 +431,3 @@ select * from t1, t3 where t1.start between t3.ctime1 and t3.ctime2; start ctime1 ctime2 2002-11-04 00:00:00 2002-10-29 16:51:06 2002-11-05 16:47:31 drop table t1,t2,t3; -CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time); -INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08"); -SELECT * from t1; -datetime timestamp date time -2001-01-02 03:04:05 2002-01-02 03:04:05 2003-01-02 06:07:08 -select date_add("1997-12-31",INTERVAL 1 SECOND); -date_add("1997-12-31",INTERVAL 1 SECOND) -1997-12-31 00:00:01 -select date_add("1997-12-31",INTERVAL "1 1" YEAR_MONTH); -date_add("1997-12-31",INTERVAL "1 1" YEAR_MONTH) -1999-01-31 -select date_add(datetime, INTERVAL 1 SECOND) from t1; -date_add(datetime, INTERVAL 1 SECOND) -2001-01-02 03:04:06 -select date_add(datetime, INTERVAL 1 YEAR) from t1; -date_add(datetime, INTERVAL 1 YEAR) -2002-01-02 03:04:05 -select date_add(date,INTERVAL 1 SECOND) from t1; -date_add(date,INTERVAL 1 SECOND) -2003-01-02 00:00:01 -select date_add(date,INTERVAL 1 MINUTE) from t1; -date_add(date,INTERVAL 1 MINUTE) -2003-01-02 00:01:00 -select date_add(date,INTERVAL 1 HOUR) from t1; -date_add(date,INTERVAL 1 HOUR) -2003-01-02 01:00:00 -select date_add(date,INTERVAL 1 DAY) from t1; -date_add(date,INTERVAL 1 DAY) -2003-01-03 -select date_add(date,INTERVAL 1 MONTH) from t1; -date_add(date,INTERVAL 1 MONTH) -2003-02-02 -select date_add(date,INTERVAL 1 YEAR) from t1; -date_add(date,INTERVAL 1 YEAR) -2004-01-02 -select date_add(date,INTERVAL "1:1" MINUTE_SECOND) from t1; -date_add(date,INTERVAL "1:1" MINUTE_SECOND) -2003-01-02 00:01:01 -select date_add(date,INTERVAL "1:1" HOUR_MINUTE) from t1; -date_add(date,INTERVAL "1:1" HOUR_MINUTE) -2003-01-02 01:01:00 -select date_add(date,INTERVAL "1:1" DAY_HOUR) from t1; -date_add(date,INTERVAL "1:1" DAY_HOUR) -2003-01-03 01:00:00 -select date_add(date,INTERVAL "1 1" YEAR_MONTH) from t1; -date_add(date,INTERVAL "1 1" YEAR_MONTH) -2004-02-02 -select date_add(date,INTERVAL "1:1:1" HOUR_SECOND) from t1; -date_add(date,INTERVAL "1:1:1" HOUR_SECOND) -2003-01-02 01:01:01 -select date_add(date,INTERVAL "1 1:1" DAY_MINUTE) from t1; -date_add(date,INTERVAL "1 1:1" DAY_MINUTE) -2003-01-03 01:01:00 -select date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) from t1; -date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) -2003-01-03 01:01:01 -select date_add(time,INTERVAL 1 SECOND) from t1; -date_add(time,INTERVAL 1 SECOND) -2006-07-08 00:00:01 -drop table t1; -select last_day('2000-02-05') as f1, last_day('2002-12-31') as f2, -last_day('2003-03-32') as f3, last_day('2003-04-01') as f4, -last_day('2001-01-01 01:01:01') as f5, last_day(NULL), -last_day('2001-02-12'); -f1 f2 f3 f4 f5 last_day(NULL) last_day('2001-02-12') -2000-02-29 2002-12-31 NULL 2003-04-30 2001-01-31 NULL 2001-02-28 -create table t1 select last_day('2000-02-05') as a; -describe t1; -Field Type Null Key Default Extra -a date 0000-00-00 -select * from t1; -a -2000-02-29 -drop table t1; -select last_day('2000-02-05'); -last_day('2000-02-05') -2000-02-29 -select strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0; -strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0 -1 -select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%T"), utc_time())=0; -strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%T"), utc_time())=0 -1 -select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%Y-%m-%d"), utc_date())=0; -strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%Y-%m-%d"), utc_date())=0 -1 -select strcmp(date_format(utc_timestamp(),"%T"), utc_time())=0; -strcmp(date_format(utc_timestamp(),"%T"), utc_time())=0 -1 -select strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0; -strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0 -1 -select strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0; -strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0 -1 -explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_days(to_days("960101")),dayofmonth("1997-01-02"), month("1997-01-02"), monthname("1972-03-04"),dayofyear("0000-00-00"),HOUR("1997-03-03 23:03:22"),MINUTE("23:03:22"),SECOND(230322),QUARTER(980303),WEEK("1998-03-03"),yearweek("2000-01-01",1),week(19950101,1),year("98-02-03"),weekday(curdate())-weekday(now()),dayname("1962-03-03"),unix_timestamp(),sec_to_time(time_to_sec("0:30:47")/6.21),curtime(),utc_time(),curdate(),utc_date(),utc_timestamp(),date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w"),from_unixtime(unix_timestamp("1994-03-02 10:11:12")),"1997-12-31 23:59:59" + INTERVAL 1 SECOND,"1998-01-01 00:00:00" - INTERVAL 1 SECOND,INTERVAL 1 DAY + "1997-12-31", extract(YEAR FROM "1999-01-02 10:11:12"),date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used -Warnings: -Note 1003 select high_priority no_cache period_add(_latin1'9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,_latin1'9404') AS `period_diff(199505,"9404")`,from_days(to_days(_latin1'960101')) AS `from_days(to_days("960101"))`,dayofmonth(_latin1'1997-01-02') AS `dayofmonth("1997-01-02")`,month(_latin1'1997-01-02') AS `month("1997-01-02")`,monthname(_latin1'1972-03-04') AS `monthname("1972-03-04")`,dayofyear(_latin1'0000-00-00') AS `dayofyear("0000-00-00")`,hour(_latin1'1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute(_latin1'23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week(_latin1'1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek(_latin1'2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year(_latin1'98-02-03') AS `year("98-02-03")`,(weekday(to_days(curdate())) - weekday(to_days(now()))) AS `weekday(curdate())-weekday(now())`,dayname(to_days(_latin1'1962-03-03')) AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec(_latin1'0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format(_latin1'1997-01-02 03:04:05',_latin1'%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp(_latin1'1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,(_latin1'1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,(_latin1'1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from _latin1'1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)` diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 853260a0164..98a4f9a390d 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -284,7 +284,6 @@ select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; spid count(*) 2 2 1 1 -explain extended select sql_big_result spid,sum(userid) from t1 group by spid desc; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort Warnings: @@ -600,3 +599,32 @@ count(*) category 1 3 1 4 drop table t1; +CREATE TABLE t1 ( +userid int(10) unsigned, +score smallint(5) unsigned, +key (score) +); +INSERT INTO t1 VALUES (1,1),(2,2),(1,1),(3,3),(3,3),(3,3),(3,3),(3,3); +SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +userid count(*) +3 5 +2 1 +1 2 +EXPLAIN SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +table type possible_keys key key_len ref rows Extra +t1 ALL NULL NULL NULL NULL 8 Using temporary; Using filesort +DROP TABLE t1; +CREATE TABLE t1 ( +i int(11) default NULL, +j int(11) default NULL +); +INSERT INTO t1 VALUES (1,2),(2,3),(4,5),(3,5),(1,5),(23,5); +SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +i COUNT(DISTINCT(i)) +1 1 +2 1 +4 4 +explain SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +table type possible_keys key key_len ref rows Extra +t1 ALL NULL NULL NULL NULL 6 Using filesort +DROP TABLE t1; diff --git a/mysql-test/r/have_mest_timezone.require b/mysql-test/r/have_mest_timezone.require deleted file mode 100644 index 2a219f39b7e..00000000000 --- a/mysql-test/r/have_mest_timezone.require +++ /dev/null @@ -1,2 +0,0 @@ -Variable_name Value -timezone MEST diff --git a/mysql-test/r/have_met_timezone.require b/mysql-test/r/have_met_timezone.require new file mode 100644 index 00000000000..b3fde075ebd --- /dev/null +++ b/mysql-test/r/have_met_timezone.require @@ -0,0 +1,2 @@ +FROM_UNIXTIME(24*3600) +1970-01-02 01:00:00 diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 58c0042e122..d7bcea22dbf 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1352,6 +1352,7 @@ id label 1822 Test 3 3524 Societe Test 3525 Fournisseur Test +drop table t1; drop table t1,t2; create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb; select * from t1; @@ -1390,3 +1391,24 @@ test.t2 968604391 test.t3 968604391 test.t4 NULL drop table t1,t2,t3; +create table t1 ( c char(8) not null ) type=innodb; +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; +create table t2 (c char(8) not null, b char(8) not null, a char(8) not null, primary key(a,b,c)) type=innodb; +insert into t2 select * from t1; +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; +drop table t1,t2; +SET AUTOCOMMIT=1; +create table t1 (a integer auto_increment primary key) type=innodb; +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +a +3 +4 +drop table t1; diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 23eef0b3c59..5af46e7db04 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -61,6 +61,7 @@ drop table t1; create table t1 (id int NOT NULL DEFAULT 8); insert into t1 values(NULL); ERROR 23000: Column 'id' cannot be null +ERROR 23000: Column 'id' cannot be null insert into t1 values (1), (NULL), (2); Warnings: Warning 1262 Data truncated, NULL supplied to NOT NULL column 'id' at row 2 @@ -73,7 +74,7 @@ drop table t1; create table t1 (email varchar(50)); insert into t1 values ('sasha@mysql.com'),('monty@mysql.com'),('foo@hotmail.com'),('foo@aol.com'),('bar@aol.com'); create table t2(id int not null auto_increment primary key, t2 varchar(50), unique(t2)); -insert into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; +insert delayed into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; select * from t2; id t2 1 mysql.com diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 76c1b06b638..19368ace977 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -4,6 +4,7 @@ grp int(11) default NULL, a bigint(20) unsigned default NULL, c char(10) NOT NULL default '' ) ENGINE=MyISAM; +) ENGINE=MyISAM; INSERT INTO t1 VALUES (1,1,'a'),(2,2,'b'),(2,3,'c'),(3,4,'E'),(3,5,'C'),(3,6,'D'),(NULL,NULL,''); create table t2 (id int, a bigint unsigned not null, c char(10), d int, primary key (a)); insert into t2 values (1,1,"a",1),(3,4,"A",4),(3,5,"B",5),(3,6,"C",6),(4,7,"D",7); @@ -665,3 +666,20 @@ left outer join t2 using (f2) left outer join t3 using (f3); ERROR 42S22: Unknown column 'test.t2.f3' in 'on clause' drop table t1,t2,t3; +create table t1 (a1 int, a2 int); +create table t2 (b1 int not null, b2 int); +create table t3 (c1 int, c2 int); +insert into t1 values (1,2), (2,2), (3,2); +insert into t2 values (1,3), (2,3); +insert into t3 values (2,4), (3,4); +select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; +a1 a2 b1 b2 c1 c2 +1 2 1 3 NULL NULL +2 2 2 3 NULL NULL +3 2 NULL NULL 3 4 +explain select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; +table type possible_keys key key_len ref rows Extra +t1 ALL NULL NULL NULL NULL 3 +t2 ALL NULL NULL NULL NULL 2 +t3 ALL NULL NULL NULL NULL 2 +drop table t1, t2, t3; diff --git a/mysql-test/r/limit.result b/mysql-test/r/limit.result index 5a8edc99c12..c82105e6a49 100644 --- a/mysql-test/r/limit.result +++ b/mysql-test/r/limit.result @@ -36,9 +36,7 @@ a b 3 4 drop table t1; create table t1 (i int); -insert into t1 (i) values(1); -insert into t1 (i) values(1); -insert into t1 (i) values(1); +insert into t1 (i) values(1),(1),(1); delete from t1 limit 1; update t1 set i=2 limit 1; delete from t1 limit 0; @@ -50,3 +48,22 @@ i drop table t1; select 0 limit 0; 0 +CREATE TABLE t1(id int auto_increment primary key, id2 int, index(id2)); +INSERT INTO t1 (id2) values (0),(0),(0); +DELETE FROM t1 WHERE id=1; +INSERT INTO t1 SET id2=0; +SELECT * FROM t1; +id id2 +4 0 +2 0 +3 0 +DELETE FROM t1 WHERE id2 = 0 ORDER BY id LIMIT 1; +SELECT * FROM t1; +id id2 +4 0 +3 0 +DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; +SELECT * FROM t1; +id id2 +3 0 +DROP TABLE t1; diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index d738431e016..d90ebb4cd79 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -40,3 +40,21 @@ Field 3,'Field 4| |Field 5' ,'Field 6| NULL |Field 6| | 'Field 7'| drop table t1; +create table t1 (a int, b char(10)); +load data infile '../../std_data/loaddata3.dat' into table t1 fields terminated by '' enclosed by '' ignore 1 lines; +select * from t1; +a b +1 row 1 +2 row 2 +0 1234567890 +3 row 3 +0 1234567890 +truncate table t1; +load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated by '' enclosed by '' lines terminated by '' ignore 1 lines; +select * from t1; +a b +1 row 1 +2 row 2 +3 row 3 +0 +drop table t1; diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result index 9c6b212a4b6..0ba4a4be945 100644 --- a/mysql-test/r/lowercase_table.result +++ b/mysql-test/r/lowercase_table.result @@ -1,6 +1,8 @@ -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,T1; create table T1 (id int primary key, Word varchar(40) not null, Index(Word)); +create table t4 (id int primary key, Word varchar(40) not null); INSERT INTO T1 VALUES (1, 'a'), (2, 'b'), (3, 'c'); +INSERT INTO T4 VALUES(1,'match'); SELECT * FROM t1; id Word 1 a @@ -12,6 +14,9 @@ id SELECT T2.id from t1 as T2 LIMIT 1; id 1 +SELECT * from t1 left join t4 on (test.t1.id= TEST.t4.id) where TEST.t1.id >= test.t4.id; +id Word id Word +1 a 1 match SELECT T2.id from t1 as t2 LIMIT 1; id 1 @@ -21,7 +26,8 @@ ALTER TABLE T2 RENAME T3; show tables like 't_'; Tables_in_test (t_) t3 -drop table t3; +t4 +drop table t3,t4; create table t1 (a int); select count(*) from T1; count(*) diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 38d60cd21d5..2e561452b8b 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -341,6 +341,39 @@ select t1.a, t1.b,t2.a, t2.b from t1 left join t2 on t1.a=t2.a where t1.b=1 and a b a b 2 2 NULL NULL drop table t1,t2; +create table t1 (a int not null auto_increment primary key, b int not null); +insert into t1 (b) values (1),(2),(3),(4); +update t1, t1 as t2 set t1.b=t2.b+1 where t1.a=t2.a; +select * from t1; +a b +1 2 +2 3 +3 4 +4 5 +drop table t1; +drop table if exists t1, t2; +create table t1(id1 smallint(5), field char(5)); +create table t2(id2 smallint(5), field char(5)); +insert into t1 values (1, 'a'), (2, 'aa'); +insert into t2 values (1, 'b'), (2, 'bb'); +select * from t1; +id1 field +1 a +2 aa +select * from t2; +id2 field +1 b +2 bb +update t2 inner join t1 on t1.id1=t2.id2 +set t2.field=t1.field +where 0=1; +update t2, t1 set t2.field=t1.field +where t1.id1=t2.id2 and 0=1; +delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 +where 0=1; +delete t1, t2 from t2,t1 +where t1.id1=t2.id2 and 0=1; +drop table t1,t2; create table t1 ( a int not null, b int not null) ; alter table t1 add index i1(a); delete from t1 where a > 2000000; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index b49f8012776..706a4d11241 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -18,6 +18,26 @@ INSERT INTO t1 VALUES (1), (2); </database> </mysqldump> DROP TABLE t1; +CREATE TABLE t1 (a decimal(240, 20)); +INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), +("0987654321098765432109876543210987654321"); +CREATE TABLE t1 ( + a decimal(240,20) default NULL +) TYPE=MyISAM; + +INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890.00000000000000000000"); +INSERT INTO t1 VALUES ("0987654321098765432109876543210987654321.00000000000000000000"); + +DROP TABLE t1; +CREATE TABLE t1 (a double); +INSERT INTO t1 VALUES (-9e999999); +CREATE TABLE t1 ( + a double default NULL +) TYPE=MyISAM; + +INSERT INTO t1 VALUES (RES); + +DROP TABLE t1; CREATE TABLE t1(a int, b text, c varchar(3)); INSERT INTO t1 VALUES (1, "test", "tes"), (2, "TEST", "TES"); <?xml version="1.0"?> diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index bf658bae89e..fe2ded691d4 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -370,16 +370,23 @@ insert into mysqltest.t1 (a) values (1); select * from mysqltest.t1 where i is null; i a 1 1 +create table t1(a int); +select * from t1; +a +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 select * from mysqltest.t1; i a 1 1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 2 drop database mysqltest; show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 +drop table t1; create table t1 (a char(1) not null collate koi8r_general_ci); insert into t1 values(_koi8r"á"); set CHARACTER SET koi8r; diff --git a/mysql-test/r/rpl_EE_error.result b/mysql-test/r/rpl_EE_error.result new file mode 100644 index 00000000000..a5043250df6 --- /dev/null +++ b/mysql-test/r/rpl_EE_error.result @@ -0,0 +1,16 @@ +slave stop; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +slave start; +create table t1 (a int) type=myisam; +flush tables; +drop table t1; +create table t1 (a int, unique(a)) type=myisam; +set sql_log_bin=0; +insert into t1 values(2); +set sql_log_bin=1; +insert into t1 values(1),(2); +Duplicate entry '2' for key 1 +drop table t1; diff --git a/mysql-test/r/rpl_multi_update.result b/mysql-test/r/rpl_multi_update.result new file mode 100644 index 00000000000..1fa1dd104d2 --- /dev/null +++ b/mysql-test/r/rpl_multi_update.result @@ -0,0 +1,27 @@ +slave stop; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +slave start; +drop table if exists t1,t2; +CREATE TABLE t1 ( +a int unsigned not null auto_increment primary key, +b int unsigned, +) TYPE=MyISAM; +CREATE TABLE t2 ( +a int unsigned not null auto_increment primary key, +b int unsigned +) TYPE=MyISAM; +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 SELECT NULL, 0 FROM t1; +INSERT INTO t2 VALUES (NULL, 0), (NULL,1); +SELECT * FROM t1 ORDER BY a; +a b +1 0 +2 0 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 +UPDATE t1, t2 SET t1.b = t2.b WHERE t1.a = t2.a; diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index 87ebf870f38..2264272051a 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -68,6 +68,9 @@ m create temporary table temp_table (a char(80) not null); insert into temp_table values ("testing temporary tables part 2"); create table t3 (n int); +select count(*) from t3 where n >= 4; +count(*) +100 create table t4 select * from temp_table; show binary logs; Log_name diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result index 42f7257dbba..e302a0cefeb 100644 --- a/mysql-test/r/select_found.result +++ b/mysql-test/r/select_found.result @@ -189,3 +189,22 @@ SELECT FOUND_ROWS(); FOUND_ROWS() 3 drop table t1; +create table t1 (id int, primary key (id)); +insert into t1 values (1), (2), (3), (4), (5); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 limit 0, 1; +id +4 +select FOUND_ROWS(); +FOUND_ROWS() +2 +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 AND 1=2 limit 0, 1; +id +select FOUND_ROWS(); +FOUND_ROWS() +0 +select SQL_CALC_FOUND_ROWS * from t1 where id > 6 limit 0, 1; +id +select FOUND_ROWS(); +FOUND_ROWS() +0 +drop table t1; diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index 48a44fc2b44..5f726476d96 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -64,3 +64,23 @@ t9 CREATE TABLE `t9` ( PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='TEST_DIR/var/tmp/' INDEX DIRECTORY='TEST_DIR/var/run/' drop database mysqltest; +create table t1 (a int not null) type=myisam; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0' +) TYPE=MyISAM +alter table t1 add b int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0', + `b` int(11) default NULL +) TYPE=MyISAM +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0', + `b` int(11) default NULL +) TYPE=MyISAM +drop table t1; diff --git a/mysql-test/r/timezone.result b/mysql-test/r/timezone.result index b82b39da262..20706408075 100644 --- a/mysql-test/r/timezone.result +++ b/mysql-test/r/timezone.result @@ -1,4 +1,13 @@ DROP TABLE IF EXISTS t1; +show variables like "timezone"; +Variable_name Value +timezone MET +select @a:=FROM_UNIXTIME(1); +@a:=FROM_UNIXTIME(1) +1970-01-01 01:00:01 +select unix_timestamp(@a); +unix_timestamp(@a) +1 CREATE TABLE t1 (ts int); INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); diff --git a/mysql-test/r/truncate.result b/mysql-test/r/truncate.result index 0e256c1bf8e..d777bd184b2 100644 --- a/mysql-test/r/truncate.result +++ b/mysql-test/r/truncate.result @@ -23,3 +23,12 @@ n drop table t1; truncate non_existing_table; ERROR 42S02: Table 'test.non_existing_table' doesn't exist +create table t1 (a integer auto_increment primary key); +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +a +1 +2 +drop table t1; diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index a69e3308f0a..f069114f752 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -510,3 +510,149 @@ show full fields from t1; Field Type Collation Null Key Default Extra Privileges Comment load_file('../../std_data/words.dat') longblob NULL YES NULL select,insert,update,references drop table t1; +create table t1 (id integer primary key auto_increment, txt text not null, unique index txt_index (txt (20))); +insert into t1 (txt) values ('Chevy'), ('Chevy '); +select * from t1 where txt='Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy ' or txt='Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy' or txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where id='1' or id='2'; +id txt +1 Chevy +2 Chevy +insert into t1 (txt) values('Ford'); +select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford'; +id txt +1 Chevy +2 Chevy +3 Ford +select * from t1 where txt='Chevy' or txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt in ('Chevy ','Chevy'); +id txt +1 Chevy +2 Chevy +select * from t1 where txt in ('Chevy'); +id txt +1 Chevy +2 Chevy +select * from t1 where txt between 'Chevy' and 'Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt between 'Chevy' and 'Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt < 'Chevy '; +id txt +select * from t1 where txt <= 'Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt > 'Chevy'; +id txt +3 Ford +select * from t1 where txt >= 'Chevy'; +id txt +1 Chevy +2 Chevy +3 Ford +drop table t1; +create table t1 (id integer primary key auto_increment, txt text, unique index txt_index (txt (20))); +insert into t1 (txt) values ('Chevy'), ('Chevy '), (NULL); +select * from t1 where txt='Chevy' or txt is NULL; +id txt +3 NULL +1 Chevy +2 Chevy +select * from t1 where txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy ' or txt='Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy' or txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where id='1' or id='2'; +id txt +1 Chevy +2 Chevy +insert into t1 (txt) values('Ford'); +select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford'; +id txt +1 Chevy +2 Chevy +4 Ford +select * from t1 where txt='Chevy' or txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt in ('Chevy ','Chevy'); +id txt +1 Chevy +2 Chevy +select * from t1 where txt in ('Chevy'); +id txt +1 Chevy +2 Chevy +select * from t1 where txt between 'Chevy' and 'Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt between 'Chevy' and 'Chevy '; +id txt +1 Chevy +2 Chevy +select * from t1 where txt < 'Chevy '; +id txt +select * from t1 where txt < 'Chevy ' or txt is NULL; +id txt +3 NULL +select * from t1 where txt <= 'Chevy'; +id txt +1 Chevy +2 Chevy +select * from t1 where txt > 'Chevy'; +id txt +4 Ford +select * from t1 where txt >= 'Chevy'; +id txt +1 Chevy +2 Chevy +4 Ford +drop table t1; diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 204266d6ec2..a32c97f1d49 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -1,6 +1,6 @@ drop table if exists t1; create table t1 (t datetime); -insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959); +insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460); select * from t1; t 2000-01-01 00:00:00 @@ -15,6 +15,11 @@ t 1999-12-31 23:59:59 1000-01-01 00:00:00 9999-12-31 23:59:59 +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 delete from t1 where t > 0; optimize table t1; Table Op Msg_type Msg_text @@ -22,7 +27,8 @@ test.t1 optimize status OK check table t1; Table Op Msg_type Msg_text test.t1 check status OK -insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"); +delete from t1; +insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460"); select * from t1; t 2000-01-01 00:00:00 @@ -38,6 +44,11 @@ t 1999-12-31 23:59:59 1000-01-01 00:00:00 9999-12-31 23:59:59 +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 drop table t1; CREATE TABLE t1 (a timestamp, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index da25394eb08..ee7d6583d64 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -444,3 +444,9 @@ CREATE TABLE t1 (a_dec DECIMAL(-2,1)); ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '-2,1))' at line 1 CREATE TABLE t1 (a_dec DECIMAL(-1,1)); ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '-1,1))' at line 1 +create table t1(a decimal(10,4)); +insert into t1 values ("+0000100000000"); +select * from t1; +a +9999999.9999 +drop table t1; diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index 1903037480a..e13a93a4156 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1636,6 +1636,16 @@ t1 CREATE TABLE `t1` ( `a` enum('','a','b') NOT NULL default 'b' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 (a enum ('0','1')); +insert into t1 set a='foobar'; +select * from t1; +a + +update t1 set a = replace(a,'x','y'); +select * from t1; +a + +drop table t1; create table t1 (a enum(0xE4, '1', '2') not null default 0xE4); show columns from t1; Field Type Null Key Default Extra diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 0c75155146d..a5d3abcdefc 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -24,6 +24,15 @@ a t 7 2002-03-05 00:00:00 8 0000-00-00 00:00:00 9 1970-01-01 03:20:38 +1 1970-01-01 03:20:34 +2 2002-03-03 00:00:00 +3 1970-01-01 03:20:35 +4 1970-01-01 03:20:36 +5 2002-03-04 00:00:00 +6 1970-01-01 03:20:37 +7 2002-03-05 00:00:00 +8 0000-00-00 00:00:00 +9 1970-01-01 03:20:38 drop table t1,t2; SET TIMESTAMP=1234; CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id)); @@ -43,7 +52,7 @@ date_format(a,"%Y %y") year(a) year(now()) 1970 70 1970 1970 drop table t1; create table t1 (ix timestamp); -insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); +insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000),(20030101010160),(20030101016001),(20030101240101),(20030132010101),(20031301010101); select ix+0 from t1; ix+0 19991101000000 @@ -55,6 +64,24 @@ ix+0 19990501000000 19991101000000 19990501000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +delete from t1; +insert into t1 values ("19991101000000"),("19990102030405"),("19990630232922"),("19990601000000"),("20030101010160"),("20030101016001"),("20030101240101"),("20030132010101"),("20031301010101"); +select * from t1; +ix +19991101000000 +19990102030405 +19990630232922 +19990601000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 drop table t1; CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); INSERT INTO t1 VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959); @@ -104,3 +131,5 @@ 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; +create table t1 (a timestamp default 1); +Invalid default value for 'a' diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index b3bf95bdf3d..1cfc6eedbaf 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -3,7 +3,7 @@ CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); -select a,b from t1 union select a,b from t2; +select a,b from t1 union distinct select a,b from t2; a b 1 a 2 b @@ -434,7 +434,14 @@ a 3 (SELECT * FROM t1) UNION all (SELECT SQL_CALC_FOUND_ROWS * FROM t2) LIMIT 1; ERROR 42000: Wrong usage/placement of 'SQL_CALC_FOUND_ROWS' +create temporary table t1 select a from t1 union select a from t2; +create table t1 select a from t1 union select a from t2; +INSERT TABLE 't1' isn't allowed in FROM table list drop table t1,t2; +select length(version()) > 1 as `*` UNION select 2; +* +1 +2 CREATE TABLE t1 ( id int(3) unsigned default '0') ENGINE=MyISAM; INSERT INTO t1 (id) VALUES("1"); CREATE TABLE t2 ( id int(3) unsigned default '0', id_master int(5) default '0', text1 varchar(5) default NULL, text2 varchar(5) default NULL) ENGINE=MyISAM; diff --git a/mysql-test/std_data/loaddata3.dat b/mysql-test/std_data/loaddata3.dat new file mode 100644 index 00000000000..4c82f1396c5 --- /dev/null +++ b/mysql-test/std_data/loaddata3.dat @@ -0,0 +1,6 @@ +number row data +1 row 1 +2 row 2 +error 12345678901234567890123456789012345678901234567890 +3 row 3 +wrong end 12345678901234567890123456789012345678901234567890 diff --git a/mysql-test/std_data/loaddata4.dat b/mysql-test/std_data/loaddata4.dat new file mode 100644 index 00000000000..9c0d744438c --- /dev/null +++ b/mysql-test/std_data/loaddata4.dat @@ -0,0 +1 @@ +test row data 1 row 1 2 row 2 3 row 3 diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index 6cf286f86c0..f2a769d9f06 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -74,6 +74,25 @@ check table t1; drop table t1; # +# Test negative values (Bug #1366) +# + +create table t1 (a int not null auto_increment primary key); +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +insert into t1 values (NULL); +select * from t1; +drop table t1; + +create table t1 (a int not null auto_increment primary key) /*!41002 type=heap */; +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +insert into t1 values (NULL); +select * from t1; +drop table t1; +# # last_insert_id() madness # create table t1 (i tinyint unsigned not null auto_increment primary key); diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index 44bb753d6a1..835253e3134 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -789,3 +789,22 @@ select * from t1 where x <= 10 and x >= 7 order by x desc; select * from t1 where x <= 8 and x >= 5 order by x desc; select * from t1 where x < 8 and x > 5 order by x desc; drop table t1; + +# +# Test of multi-table-updates (bug #1980). +# + +create table t1 ( c char(8) not null ) type=bdb; +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); + +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; + +create table t2 (c char(8) not null, b char(8) not null, a char(8) not null, primary key(a,b,c)) type=bdb; +insert into t2 select * from t1; + +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; +drop table t1,t2; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 17ed4c03b5a..ce89cbe1b22 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -370,3 +370,11 @@ insert into t1 values (1); select max(a) as b from t1 having b=1; select a from t1 having a=1; drop table t1; +# +# Bug #1972: test for bit_and(), bit_or() and negative values +# +create table t1 (col int); +insert into t1 values (-1), (-2), (-3); +select bit_and(col), bit_or(col) from t1; +select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; +drop table t1; diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index cb6ca58f193..33a2884b424 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -7,3 +7,12 @@ explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; select 1 | (1+1),5 & 3,bit_count(7) ; explain extended select 1 | (1+1),5 & 3,bit_count(7) ; select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60; +# +# bug #1993: bit functions must be unsigned +# +select -1 | 0, -1 ^ 0, -1 & 0; +select -1 | 1, -1 ^ 1, -1 & 1; +select 1 | -1, 1 ^ -1, 1 & -1; +select 0 | -1, 0 ^ -1, 0 & -1; +select -1 >> 0, -1 << 0; +select -1 >> 1, -1 << 1; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 0003f14c9ca..ad7b9b21b51 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -61,11 +61,13 @@ select aes_decrypt("a","a"); select aes_decrypt(aes_encrypt("","a"),"a"); select repeat('monty',5),concat('*',space(5),'*'); select reverse('abc'),reverse('abcd'); -select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12'); -select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12'); +select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12'), rpad(11, 10 , 22), rpad("ab", 10, 22); +select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12'), lpad(11, 10 , 22); select rpad(741653838,17,'0'),lpad(741653838,17,'0'); select rpad('abcd',7,'ab'),lpad('abcd',7,'ab'); select rpad('abcd',1,'ab'),lpad('abcd',1,'ab'); +select rpad('STRING', 20, CONCAT('p','a','d') ); +select lpad('STRING', 20, CONCAT('p','a','d') ); select LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'),GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'); select least(1,2,3) | greatest(16,32,8), least(5,4)*1,greatest(-1.0,1.0)*1,least(3,2,1)*1.0,greatest(1,1.1,1.0),least("10",9),greatest("A","B","0"); @@ -77,6 +79,7 @@ select quote('\'\"\\test'); select quote(concat('abc\'', '\\cba')); select quote(1/0), quote('\0\Z'); select length(quote(concat(char(0),"test"))); +select hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))); # # Wrong usage of functions diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 6f114fe18ae..06d0ff3fa1d 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -42,6 +42,18 @@ select yearweek("2000-01-06",1) as '2000', yearweek("2001-01-06",1) as '2001', y select week(19981231,2), week(19981231,3), week(20000101,2), week(20000101,3); select week(20001231,2),week(20001231,3); +select week(19981231,0) as '0', week(19981231,1) as '1', week(19981231,2) as '2', week(19981231,3) as '3', week(19981231,4) as '4', week(19981231,5) as '5', week(19981231,6) as '6', week(19981231,7) as '7'; +select week(20000101,0) as '0', week(20000101,1) as '1', week(20000101,2) as '2', week(20000101,3) as '3', week(20000101,4) as '4', week(20000101,5) as '5', week(20000101,6) as '6', week(20000101,7) as '7'; +select week(20000106,0) as '0', week(20000106,1) as '1', week(20000106,2) as '2', week(20000106,3) as '3', week(20000106,4) as '4', week(20000106,5) as '5', week(20000106,6) as '6', week(20000106,7) as '7'; +select week(20001231,0) as '0', week(20001231,1) as '1', week(20001231,2) as '2', week(20001231,3) as '3', week(20001231,4) as '4', week(20001231,5) as '5', week(20001231,6) as '6', week(20001231,7) as '7'; +select week(20010101,0) as '0', week(20010101,1) as '1', week(20010101,2) as '2', week(20010101,3) as '3', week(20010101,4) as '4', week(20010101,5) as '5', week(20010101,6) as '6', week(20010101,7) as '7'; + +select yearweek(20001231,0), yearweek(20001231,1), yearweek(20001231,2), yearweek(20001231,3), yearweek(20001231,4), yearweek(20001231,5), yearweek(20001231,6), yearweek(20001231,7); + +set default_week_format = 6; +select week(20001231), week(20001231,6); +set default_week_format = 0; + set default_week_format = 2; select week(20001231),week(20001231,2),week(20001231,0); set default_week_format = 0; @@ -194,6 +206,13 @@ select * from t1, t3 where t1.start between t3.ctime1 and t3.ctime2; drop table t1,t2,t3; # +# Test unix timestamp +# +select @a:=FROM_UNIXTIME(1); +select unix_timestamp(@a); +select unix_timestamp('1969-12-01 19:00:01'); + +# # Test types from + INTERVAL # diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 1e65bef19b7..d6d1922c10f 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -432,3 +432,27 @@ select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sum(q select count(*), case interval(qty,2,3,4,5,6,7,8) when -1 then NULL when 0 then "zero" when 1 then "one" when 2 then "two" end as category from t1 group by category; select count(*), interval(qty,2,3,4,5,6,7,8) as category from t1 group by category; drop table t1; +# +# Tests for bug #1355: 'Using filesort' is missing in EXPLAIN when ORDER BY +# NULL is used. +# +CREATE TABLE t1 ( + userid int(10) unsigned, + score smallint(5) unsigned, + key (score) +); +INSERT INTO t1 VALUES (1,1),(2,2),(1,1),(3,3),(3,3),(3,3),(3,3),(3,3); +# Here we select unordered GROUP BY into a temporary talbe, +# and then sort it with filesort (GROUP BY in MySQL +# implies sorted order of results) +SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +EXPLAIN SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +DROP TABLE t1; +CREATE TABLE t1 ( + i int(11) default NULL, + j int(11) default NULL +); +INSERT INTO t1 VALUES (1,2),(2,3),(4,5),(3,5),(1,5),(23,5); +SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +explain SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +DROP TABLE t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 6f7a0e100c3..5add6247eaa 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -902,6 +902,37 @@ update t1 set a=a+10+b where a=1 order by b; select * from t1 order by a,b; drop table t1; +# +# Test of multi-table-updates (bug #1980). +# + +create table t1 ( c char(8) not null ) type=innodb; +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); + +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; + +create table t2 (c char(8) not null, b char(8) not null, a char(8) not null, primary key(a,b,c)) type=innodb; +insert into t2 select * from t1; + +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; +drop table t1,t2; + +# +# test autoincrement with TRUNCATE +# + +SET AUTOCOMMIT=1; +create table t1 (a integer auto_increment primary key) type=innodb; +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +drop table t1; + CREATE TABLE t1 (col1 int(1))ENGINE=InnoDB; CREATE TABLE t2 (col1 int(1),stamp TIMESTAMP,INDEX stamp_idx diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 62d277bfad5..73b5f453bb4 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -71,7 +71,7 @@ drop table t1; create table t1 (email varchar(50)); insert into t1 values ('sasha@mysql.com'),('monty@mysql.com'),('foo@hotmail.com'),('foo@aol.com'),('bar@aol.com'); create table t2(id int not null auto_increment primary key, t2 varchar(50), unique(t2)); -insert into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; +insert delayed into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; select * from t2; drop table t1,t2; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index d048208a8ff..4ffe1c075b6 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -438,3 +438,16 @@ select * from t1 left outer join t2 using (f2) left outer join t3 using (f3); drop table t1,t2,t3; + +create table t1 (a1 int, a2 int); +create table t2 (b1 int not null, b2 int); +create table t3 (c1 int, c2 int); + +insert into t1 values (1,2), (2,2), (3,2); +insert into t2 values (1,3), (2,3); +insert into t3 values (2,4), (3,4); + +select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; +explain select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; + +drop table t1, t2, t3; diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test index 88a9831aa68..61c57c9b468 100644 --- a/mysql-test/t/limit.test +++ b/mysql-test/t/limit.test @@ -22,9 +22,7 @@ select * from t1; drop table t1; create table t1 (i int); -insert into t1 (i) values(1); -insert into t1 (i) values(1); -insert into t1 (i) values(1); +insert into t1 (i) values(1),(1),(1); delete from t1 limit 1; update t1 set i=2 limit 1; delete from t1 limit 0; @@ -32,4 +30,22 @@ update t1 set i=3 limit 0; select * from t1; drop table t1; +# LIMIT 0 + select 0 limit 0; + +# +# Test with DELETE, ORDER BY and limit (bug #1024) +# + +CREATE TABLE t1(id int auto_increment primary key, id2 int, index(id2)); +INSERT INTO t1 (id2) values (0),(0),(0); +DELETE FROM t1 WHERE id=1; +INSERT INTO t1 SET id2=0; +SELECT * FROM t1; +DELETE FROM t1 WHERE id2 = 0 ORDER BY id LIMIT 1; +# should have deleted WHERE id=2 +SELECT * FROM t1; +DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 1720ae69bbb..aa0ea0a2f55 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -20,3 +20,14 @@ create table t1 (a text, b text); load data infile '../../std_data/loaddata2.dat' into table t1 fields terminated by ',' enclosed by ''''; select concat('|',a,'|'), concat('|',b,'|') from t1; drop table t1; + +create table t1 (a int, b char(10)); +load data infile '../../std_data/loaddata3.dat' into table t1 fields terminated by '' enclosed by '' ignore 1 lines; +select * from t1; +truncate table t1; +load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated by '' enclosed by '' lines terminated by '' ignore 1 lines; + +# The empty line last comes from the end line field in the file +select * from t1; +drop table t1; + diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index 28e45bde5c5..601f1734ac6 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -3,21 +3,24 @@ # --disable_warnings -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,T1; --enable_warnings create table T1 (id int primary key, Word varchar(40) not null, Index(Word)); +create table t4 (id int primary key, Word varchar(40) not null); INSERT INTO T1 VALUES (1, 'a'), (2, 'b'), (3, 'c'); +INSERT INTO T4 VALUES(1,'match'); SELECT * FROM t1; SELECT T1.id from T1 LIMIT 1; SELECT T2.id from t1 as T2 LIMIT 1; +SELECT * from t1 left join t4 on (test.t1.id= TEST.t4.id) where TEST.t1.id >= test.t4.id; # This gave an error in 4.0, but it's fixed in 4.1 SELECT T2.id from t1 as t2 LIMIT 1; RENAME TABLE T1 TO T2; ALTER TABLE T2 ADD new_col int not null; ALTER TABLE T2 RENAME T3; show tables like 't_'; -drop table t3; +drop table t3,t4; # # Test alias # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 115007d9e63..4b69b002342 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -277,6 +277,42 @@ select t1.a, t1.b,t2.a, t2.b from t1 left join t2 on t1.a=t2.a where t1.b=1 and drop table t1,t2; # +# Test reuse of same table +# + +create table t1 (a int not null auto_increment primary key, b int not null); +insert into t1 (b) values (1),(2),(3),(4); +update t1, t1 as t2 set t1.b=t2.b+1 where t1.a=t2.a; +select * from t1; +drop table t1; + +# Test multi-update and multi-delete with impossible where + +drop table if exists t1, t2; +create table t1(id1 smallint(5), field char(5)); +create table t2(id2 smallint(5), field char(5)); + +insert into t1 values (1, 'a'), (2, 'aa'); +insert into t2 values (1, 'b'), (2, 'bb'); + +select * from t1; +select * from t2; + +update t2 inner join t1 on t1.id1=t2.id2 + set t2.field=t1.field + where 0=1; +update t2, t1 set t2.field=t1.field + where t1.id1=t2.id2 and 0=1; + +delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 + where 0=1; +delete t1, t2 from t2,t1 + where t1.id1=t2.id2 and 0=1; + +drop table t1,t2; + + +# # Test for bug #1820. # @@ -309,4 +345,4 @@ delete t1,t2 from t1,t2 where t1.b=t2.a and t1.a < 100*1000; select 't2 rows after big delete', count(*) from t2; select 't1 rows after big delete', count(*) from t1; -#drop table t1,t2; +drop table t1,t2; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 582fae0da36..c926c8e0b0d 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -6,7 +6,29 @@ DROP TABLE IF EXISTS t1, `"t"1`; CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); ---exec $MYSQL_DUMP --skip-all -X test t1 +--exec $MYSQL_DUMP --skip-comments -X test t1 +DROP TABLE t1; + +# +# Bug #2005 +# + +CREATE TABLE t1 (a decimal(240, 20)); +INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), +("0987654321098765432109876543210987654321"); +--exec $MYSQL_DUMP --skip-comments test t1 +DROP TABLE t1; + +# +# Bug #2055 +# + +CREATE TABLE t1 (a double); +INSERT INTO t1 VALUES (-9e999999); +# The following replaces is here because some systems replaces the above +# double with '-inf' and others with MAX_DOUBLE +--replace_result (-1.79769313486232e+308) (RES) (NULL) (RES) +--exec $MYSQL_DUMP --skip-comments test t1 DROP TABLE t1; CREATE TABLE t1(a int, b text, c varchar(3)); diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index c93d616b379..d7681e9c2ec 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -254,10 +254,14 @@ select * from mysqltest.t1 where i is null; # # drop db # +create table t1(a int); +select * from t1; +show status like "Qcache_queries_in_cache"; select * from mysqltest.t1; show status like "Qcache_queries_in_cache"; drop database mysqltest; show status like "Qcache_queries_in_cache"; +drop table t1; # # Charset convertion (cp1251_koi8 always present) diff --git a/mysql-test/t/rpl_EE_error.test b/mysql-test/t/rpl_EE_error.test new file mode 100644 index 00000000000..de69c4897c3 --- /dev/null +++ b/mysql-test/t/rpl_EE_error.test @@ -0,0 +1,30 @@ +# See if an EE_ error in one event of the master's binlog stops replication +# (it should not: in this configuration the EE_ error is probably not +# critical). Example: you do a DROP TABLE on a table which has no MYI file +# check if START SLAVE, RESET SLAVE, CHANGE MASTER reset Last_slave_error and +# Last_slave_errno in SHOW SLAVE STATUS (1st and 3rd commands did not: bug 986). + +source include/master-slave.inc; + +create table t1 (a int) type=myisam; +flush tables; +system rm ./var/master-data/test/t1.MYI ; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; + +# Now a real error. + +connection master; +create table t1 (a int, unique(a)) type=myisam; +set sql_log_bin=0; +insert into t1 values(2); +set sql_log_bin=1; +save_master_pos; +--error 1062; +insert into t1 values(1),(2); +drop table t1; +save_master_pos; +connection slave; +wait_for_slave_to_stop; diff --git a/mysql-test/t/rpl_multi_update.test b/mysql-test/t/rpl_multi_update.test new file mode 100644 index 00000000000..c44239594dd --- /dev/null +++ b/mysql-test/t/rpl_multi_update.test @@ -0,0 +1,25 @@ +source include/master-slave.inc; +drop table if exists t1,t2; + +CREATE TABLE t1 ( + a int unsigned not null auto_increment primary key, + b int unsigned, +) TYPE=MyISAM; + +CREATE TABLE t2 ( + a int unsigned not null auto_increment primary key, + b int unsigned +) TYPE=MyISAM; + +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 SELECT NULL, 0 FROM t1; + +INSERT INTO t2 VALUES (NULL, 0), (NULL,1); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +UPDATE t1, t2 SET t1.b = t2.b WHERE t1.a = t2.a; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index 7560d56af1c..0d447b8d1a3 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -130,6 +130,7 @@ while ($1) dec $1; } enable_query_log; +select count(*) from t3 where n >= 4; create table t4 select * from temp_table; show binary logs; show master status; diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test index f787cec6533..3cf736cafb0 100644 --- a/mysql-test/t/select_found.test +++ b/mysql-test/t/select_found.test @@ -95,3 +95,17 @@ SELECT FOUND_ROWS(); SELECT SQL_CALC_FOUND_ROWS * FROM t1 ORDER BY numeropost LIMIT 0; SELECT FOUND_ROWS(); drop table t1; + +# +# Test problem with impossible WHERE (Bug #1468) +# + +create table t1 (id int, primary key (id)); +insert into t1 values (1), (2), (3), (4), (5); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 limit 0, 1; +select FOUND_ROWS(); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 AND 1=2 limit 0, 1; +select FOUND_ROWS(); +select SQL_CALC_FOUND_ROWS * from t1 where id > 6 limit 0, 1; +select FOUND_ROWS(); +drop table t1; diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index 716eed7abc0..c0a9ce1bbcf 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -93,3 +93,25 @@ select count(*) from mysqltest.t9; --replace_result $MYSQL_TEST_DIR TEST_DIR show create table mysqltest.t9; drop database mysqltest; + +# +# Test changing data dir (Bug #1662) +# + +create table t1 (a int not null) type=myisam; +disable_query_log; +eval alter table t1 data directory="$MYSQL_TEST_DIR/var/tmp"; +enable_query_log; +--replace_result $MYSQL_TEST_DIR TEST_DIR +show create table t1; +alter table t1 add b int; +disable_query_log; +eval alter table t1 data directory="$MYSQL_TEST_DIR/var/log"; +enable_query_log; +--replace_result $MYSQL_TEST_DIR TEST_DIR +show create table t1; +disable_query_log; +eval alter table t1 index directory="$MYSQL_TEST_DIR/var/log"; +enable_query_log; +show create table t1; +drop table t1; diff --git a/mysql-test/t/timezone.test b/mysql-test/t/timezone.test index 14facc0374a..ab732c11a34 100644 --- a/mysql-test/t/timezone.test +++ b/mysql-test/t/timezone.test @@ -1,9 +1,9 @@ # -# Test of timezone handling. This script must be run with TZ=MEST +# Test of timezone handling. This script must be run with TZ=MET --- require r/have_mest_timezone.require +-- require r/have_met_timezone.require disable_query_log; -show variables like "timezone"; +select FROM_UNIXTIME(24*3600); enable_query_log; # Initialization @@ -11,6 +11,17 @@ enable_query_log; DROP TABLE IF EXISTS t1; --enable_warnings +show variables like "timezone"; + +# +# Test unix timestamp +# +select @a:=FROM_UNIXTIME(1); +select unix_timestamp(@a); + +# +# Test of some values, including some with daylight saving time +# CREATE TABLE t1 (ts int); INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); @@ -26,3 +37,4 @@ INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01')); SELECT ts,from_unixtime(ts) FROM t1; DROP TABLE t1; + diff --git a/mysql-test/t/truncate.test b/mysql-test/t/truncate.test index dd80baba269..434a1907e42 100644 --- a/mysql-test/t/truncate.test +++ b/mysql-test/t/truncate.test @@ -24,3 +24,15 @@ select * from t1; drop table t1; --error 1146 truncate non_existing_table; + +# +# test autoincrement with TRUNCATE +# + +create table t1 (a integer auto_increment primary key); +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +drop table t1; + diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index c9c3284fe0d..70fa2f9b172 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -308,3 +308,52 @@ drop table t1; create table t1 select load_file('../../std_data/words.dat'); show full fields from t1; drop table t1; + +# +# Test blob's with end space (Bug #1651) +# + +create table t1 (id integer primary key auto_increment, txt text not null, unique index txt_index (txt (20))); +insert into t1 (txt) values ('Chevy'), ('Chevy '); +select * from t1 where txt='Chevy'; +select * from t1 where txt='Chevy '; +select * from t1 where txt='Chevy ' or txt='Chevy'; +select * from t1 where txt='Chevy' or txt='Chevy '; +select * from t1 where id='1' or id='2'; +insert into t1 (txt) values('Ford'); +select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford'; +select * from t1 where txt='Chevy' or txt='Chevy '; +select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy'; +select * from t1 where txt in ('Chevy ','Chevy'); +select * from t1 where txt in ('Chevy'); +select * from t1 where txt between 'Chevy' and 'Chevy'; +select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy '; +select * from t1 where txt between 'Chevy' and 'Chevy '; +select * from t1 where txt < 'Chevy '; +select * from t1 where txt <= 'Chevy'; +select * from t1 where txt > 'Chevy'; +select * from t1 where txt >= 'Chevy'; +drop table t1; + +create table t1 (id integer primary key auto_increment, txt text, unique index txt_index (txt (20))); +insert into t1 (txt) values ('Chevy'), ('Chevy '), (NULL); +select * from t1 where txt='Chevy' or txt is NULL; +select * from t1 where txt='Chevy '; +select * from t1 where txt='Chevy ' or txt='Chevy'; +select * from t1 where txt='Chevy' or txt='Chevy '; +select * from t1 where id='1' or id='2'; +insert into t1 (txt) values('Ford'); +select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford'; +select * from t1 where txt='Chevy' or txt='Chevy '; +select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy'; +select * from t1 where txt in ('Chevy ','Chevy'); +select * from t1 where txt in ('Chevy'); +select * from t1 where txt between 'Chevy' and 'Chevy'; +select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy '; +select * from t1 where txt between 'Chevy' and 'Chevy '; +select * from t1 where txt < 'Chevy '; +select * from t1 where txt < 'Chevy ' or txt is NULL; +select * from t1 where txt <= 'Chevy'; +select * from t1 where txt > 'Chevy'; +select * from t1 where txt >= 'Chevy'; +drop table t1; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 7cedbc087e4..cec2aa3582b 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -7,12 +7,13 @@ drop table if exists t1; --enable_warnings create table t1 (t datetime); -insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959); +insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460); select * from t1; delete from t1 where t > 0; optimize table t1; check table t1; -insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"); +delete from t1; +insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460"); select * from t1; drop table t1; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 36bd8eb48e4..8250f40fc99 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -244,3 +244,9 @@ CREATE TABLE t1 (a_dec DECIMAL(-1,0)); CREATE TABLE t1 (a_dec DECIMAL(-2,1)); --error 1064 CREATE TABLE t1 (a_dec DECIMAL(-1,1)); + +# Zero prepend overflow bug +create table t1(a decimal(10,4)); +insert into t1 values ("+0000100000000"); +select * from t1; +drop table t1; diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index bcebb1a5b27..f9e5e6470c6 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -26,6 +26,17 @@ show create table t1; drop table t1; # +# Tests of wrong enum values (bug #2023) +# + +create table t1 (a enum ('0','1')); +insert into t1 set a='foobar'; +select * from t1; +update t1 set a = replace(a,'x','y'); +select * from t1; +drop table t1; + +# # Bug #2077 # diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index cd76dbe6ab0..fc7cd019171 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -37,8 +37,11 @@ select date_format(a,"%Y %y"),year(a),year(now()) from t1; drop table t1; create table t1 (ix timestamp); -insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); -select ix+0 from t1; +insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000),(20030101010160),(20030101016001),(20030101240101),(20030132010101),(20031301010101); +select ix+0 from t1; +delete from t1; +insert into t1 values ("19991101000000"),("19990102030405"),("19990630232922"),("19990601000000"),("20030101010160"),("20030101016001"),("20030101240101"),("20030132010101"),("20031301010101"); +select ix+0 from t1; drop table t1; CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); @@ -72,3 +75,9 @@ set new=1; select * from t1; drop table t1; +# +# Bug #1885 +# + +--error 1067 +create table t1 (a timestamp default 1); diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 6138bba5a31..fc986b05fa4 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -11,7 +11,7 @@ insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); -select a,b from t1 union select a,b from t2; +select a,b from t1 union distinct select a,b from t2; select a,b from t1 union all select a,b from t2; select a,b from t1 union all select a,b from t2 order by b; select a,b from t1 union all select a,b from t2 union select 7,'g'; @@ -247,9 +247,19 @@ SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a desc LIMIT 1; --error 1234 (SELECT * FROM t1) UNION all (SELECT SQL_CALC_FOUND_ROWS * FROM t2) LIMIT 1; +create temporary table t1 select a from t1 union select a from t2; +--error 1093 +create table t1 select a from t1 union select a from t2; drop table t1,t2; # +# Problem with alias '*' (BUG #1249) +# + +select length(version()) > 1 as `*` UNION select 2; + + +# # Test for another bug with UNION and LEFT JOIN # CREATE TABLE t1 ( id int(3) unsigned default '0') ENGINE=MyISAM; diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index b3aa347006e..e2e811fe89a 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -210,13 +210,13 @@ uint cleanup_dirname(register my_string to, const char *from) } /* cleanup_dirname */ - /* - On system where you don't have symbolic links, the following - code will allow you to create a file: - directory-name.lnk that should contain the real path - to the directory. This will be used if the directory name - doesn't exists - */ +/* + On system where you don't have symbolic links, the following + code will allow you to create a file: + directory-name.sym that should contain the real path + to the directory. This will be used if the directory name + doesn't exists +*/ my_bool my_use_symdir=0; /* Set this if you want to use symdirs */ @@ -228,16 +228,17 @@ void symdirget(char *dir) char *pos=strend(dir); if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK)) { - FILE *fp; + File file; + uint length; char temp= *(--pos); /* May be "/" or "\" */ strmov(pos,".sym"); - fp = my_fopen(dir, O_RDONLY,MYF(0)); + file= my_open(dir, O_RDONLY, MYF(0)); *pos++=temp; *pos=0; /* Restore old filename */ - if (fp) + if (file >= 0) { - if (fgets(buff, sizeof(buff)-1, fp)) + if ((length= my_read(file, buff, sizeof(buff), MYF(0))) > 0) { - for (pos=strend(buff); + for (pos= buff + length ; pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ; pos --); @@ -247,7 +248,7 @@ void symdirget(char *dir) strmake(dir,buff, (uint) (pos-buff)); } - my_fclose(fp,MYF(0)); + my_close(file, MYF(0)); } } } diff --git a/mysys/my_init.c b/mysys/my_init.c index 4a7e9194dae..d68af1400c5 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -61,13 +61,22 @@ static ulong atoi_octal(const char *str) } - /* Init my_sys functions and my_sys variabels */ +/* + Init my_sys functions and my_sys variabels + + SYNOPSIS + my_init() -void my_init(void) + RETURN + 0 ok + 1 Couldn't initialize environment +*/ + +my_bool my_init(void) { my_string str; if (my_init_done) - return; + return 0; my_init_done=1; #if defined(THREAD) && defined(SAFE_MUTEX) safe_mutex_global_init(); /* Must be called early */ @@ -77,7 +86,8 @@ void my_init(void) #if defined(HAVE_PTHREAD_INIT) pthread_init(); /* Must be called before DBUG_ENTER */ #endif - my_thread_global_init(); + if (my_thread_global_init()) + return 1; #if !defined( __WIN__) && !defined(OS2) && !defined(__NETWARE__) sigfillset(&my_signals); /* signals blocked by mf_brkhant */ #endif @@ -109,7 +119,7 @@ void my_init(void) #ifdef __WIN__ win32_init_tcp_ip(); #endif - DBUG_VOID_RETURN; + DBUG_RETURN(0); } } /* my_init */ diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 035bafd07b9..055e00d2efc 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -62,8 +62,15 @@ #define READDIR(A,B,C) (!(C=readdir(A))) #endif +/* + We are assuming that directory we are reading is either has less than + 100 files and so can be read in one initial chunk or has more than 1000 + files and so big increment are suitable. +*/ +#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO)) +#define ENTRIES_INCREMENT (65536/sizeof(FILEINFO)) +#define NAMES_START_SIZE 32768 -#define STARTSIZE ONCE_ALLOC_INIT*8 /* some mallocmargin */ static int comp_names(struct fileinfo *a,struct fileinfo *b); @@ -74,7 +81,13 @@ void my_dirend(MY_DIR *buffer) { DBUG_ENTER("my_dirend"); if (buffer) + { + delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer + + ALIGN_SIZE(sizeof(MY_DIR)))); + free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0)); my_free((gptr) buffer,MYF(0)); + } DBUG_VOID_RETURN; } /* my_dirend */ @@ -91,14 +104,14 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b) MY_DIR *my_dir(const char *path, myf MyFlags) { + char *buffer; + MY_DIR *result= 0; + FILEINFO finfo; + DYNAMIC_ARRAY *dir_entries_storage; + MEM_ROOT *names_storage; DIR *dirp; struct dirent *dp; - struct fileinfo *fnames; - char *buffer, *obuffer, *tempptr; - uint fcnt,i,size,firstfcnt, maxfcnt,length; char tmp_path[FN_REFLEN+1],*tmp_file; - my_ptrdiff_t diff; - bool eof; #ifdef THREAD char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1]; #endif @@ -110,74 +123,72 @@ MY_DIR *my_dir(const char *path, myf MyFlags) #endif dirp = opendir(directory_file_name(tmp_path,(my_string) path)); - size = STARTSIZE; #if defined(__amiga__) if ((dirp->dd_fd) < 0) /* Directory doesn't exists */ goto error; #endif - if (dirp == NULL || ! (buffer = (char *) my_malloc(size, MyFlags))) + if (dirp == NULL || + ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) + + sizeof(MEM_ROOT), MyFlags))) + goto error; + + dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); + names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))); + + if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO), + ENTRIES_START_SIZE, ENTRIES_INCREMENT)) + { + my_free((gptr) buffer,MYF(0)); goto error; + } + init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE); + + /* MY_DIR structure is allocated and completly initialized at this point */ + result= (MY_DIR*)buffer; - fcnt = 0; tmp_file=strend(tmp_path); - firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) / - (sizeof(struct fileinfo) + FN_LEN); - fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR)); - tempptr = (char *) (fnames + maxfcnt); #ifdef THREAD dp= (struct dirent*) dirent_tmp; #else dp=0; #endif - eof=0; - for (;;) + + while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp))) { - while (fcnt < maxfcnt && - !(eof= READDIR(dirp,(struct dirent*) dirent_tmp,dp))) + if (!(finfo.name= strdup_root(names_storage, dp->d_name))) + goto error; + + if (MyFlags & MY_WANT_STAT) { - bzero((gptr) (fnames+fcnt),sizeof(fnames[0])); /* for purify */ - fnames[fcnt].name = tempptr; - tempptr = strmov(tempptr,dp->d_name) + 1; - if (MyFlags & MY_WANT_STAT) - { - VOID(strmov(tmp_file,dp->d_name)); - VOID(my_stat(tmp_path, &fnames[fcnt].mystat, MyFlags)); - } - ++fcnt; + if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, + sizeof(MY_STAT)))) + goto error; + + bzero(finfo.mystat, sizeof(MY_STAT)); + VOID(strmov(tmp_file,dp->d_name)); + VOID(my_stat(tmp_path, finfo.mystat, MyFlags)); } - if (eof) - break; - size += STARTSIZE; obuffer = buffer; - if (!(buffer = (char *) my_realloc((gptr) buffer, size, - MyFlags | MY_FREE_ON_ERROR))) - goto error; /* No memory */ - length= (uint) (sizeof(struct fileinfo ) * firstfcnt); - diff= PTR_BYTE_DIFF(buffer , obuffer) + (int) length; - fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR)); - tempptr= ADD_TO_PTR(tempptr,diff,char*); - for (i = 0; i < maxfcnt; i++) - fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*); - - /* move filenames upp a bit */ - maxfcnt += firstfcnt; - bmove_upp(tempptr,tempptr-length, - (uint) (tempptr- (char*) (fnames+maxfcnt))); + else + finfo.mystat= NULL; + + if (push_dynamic(dir_entries_storage, (gptr)&finfo)) + goto error; } (void) closedir(dirp); - { - MY_DIR * s = (MY_DIR *) buffer; - s->number_off_files = (uint) fcnt; - s->dir_entry = fnames; - } - if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) fnames, (size_s) fcnt, sizeof(struct fileinfo), - (qsort_cmp) comp_names); #if defined(THREAD) && !defined(HAVE_READDIR_R) pthread_mutex_unlock(&THR_LOCK_open); #endif - DBUG_RETURN((MY_DIR *) buffer); + result->dir_entry= (FILEINFO *)dir_entries_storage->buffer; + result->number_off_files= dir_entries_storage->elements; + + if (!(MyFlags & MY_DONT_SORT)) + qsort((void *) result->dir_entry, result->number_off_files, + sizeof(FILEINFO), (qsort_cmp) comp_names); + DBUG_RETURN(result); error: #if defined(THREAD) && !defined(HAVE_READDIR_R) @@ -186,6 +197,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) my_errno=errno; if (dirp) (void) closedir(dirp); + my_dirend(result); if (MyFlags & (MY_FAE | MY_WME)) my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno); DBUG_RETURN((MY_DIR *) NULL); @@ -349,10 +361,11 @@ my_string directory_file_name (my_string dst, const char *src) MY_DIR *my_dir(const char *path, myf MyFlags) { - struct fileinfo *fnames; - char *buffer, *obuffer, *tempptr; - int eof,i,fcnt,firstfcnt,length,maxfcnt; - uint size; + char *buffer; + MY_DIR *result= 0; + FILEINFO finfo; + DYNAMIC_ARRAY *dir_entries_storage; + MEM_ROOT *names_storage; #ifdef __BORLANDC__ struct ffblk find; #else @@ -360,7 +373,6 @@ MY_DIR *my_dir(const char *path, myf MyFlags) #endif ushort mode; char tmp_path[FN_REFLEN],*tmp_file,attrib; - my_ptrdiff_t diff; #ifdef _WIN64 __int64 handle; #else @@ -392,85 +404,88 @@ MY_DIR *my_dir(const char *path, myf MyFlags) goto error; #endif - size = STARTSIZE; - firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) / - (sizeof(struct fileinfo) + FN_LEN); - if ((buffer = (char *) my_malloc(size, MyFlags)) == 0) + if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) + + sizeof(MEM_ROOT), MyFlags))) goto error; - fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR)); - tempptr = (char *) (fnames + maxfcnt); - fcnt = 0; - for (;;) + dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); + names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))); + + if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO), + ENTRIES_START_SIZE, ENTRIES_INCREMENT)) + { + my_free((gptr) buffer,MYF(0)); + goto error; + } + init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE); + + /* MY_DIR structure is allocated and completly initialized at this point */ + result= (MY_DIR*)buffer; + + do { - do +#ifdef __BORLANDC__ + if (!(finfo.name= strdup_root(names_storage, find.ff_name))) + goto error; +#else + if (!(finfo.name= strdup_root(names_storage, find.name))) + goto error; +#endif + if (MyFlags & MY_WANT_STAT) { - fnames[fcnt].name = tempptr; + if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, + sizeof(MY_STAT)))) + goto error; + + bzero(finfo.mystat, sizeof(MY_STAT)); #ifdef __BORLANDC__ - tempptr = strmov(tempptr,find.ff_name) + 1; - fnames[fcnt].mystat.st_size=find.ff_fsize; - fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0; + finfo.mystat->st_size=find.ff_fsize; mode=MY_S_IREAD; attrib=find.ff_attrib; #else - tempptr = strmov(tempptr,find.name) + 1; - fnames[fcnt].mystat.st_size=find.size; - fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0; + finfo.mystat->st_size=find.size; mode=MY_S_IREAD; attrib=find.attrib; #endif if (!(attrib & _A_RDONLY)) mode|=MY_S_IWRITE; if (attrib & _A_SUBDIR) mode|=MY_S_IFDIR; - fnames[fcnt].mystat.st_mode=mode; -#ifdef __BORLANDC__ - fnames[fcnt].mystat.st_mtime=((uint32) find.ff_ftime); -#else - fnames[fcnt].mystat.st_mtime=((uint32) find.time_write); -#endif - ++fcnt; + finfo.mystat->st_mode=mode; #ifdef __BORLANDC__ - } while ((eof= findnext(&find)) == 0 && fcnt < maxfcnt); + finfo.mystat->st_mtime=((uint32) find.ff_ftime); #else - } while ((eof= _findnext(handle,&find)) == 0 && fcnt < maxfcnt); + finfo.mystat->st_mtime=((uint32) find.time_write); #endif + } + else + finfo.mystat= NULL; - DBUG_PRINT("test",("eof: %d errno: %d",eof,errno)); - if (eof) - break; - size += STARTSIZE; obuffer = buffer; - if (!(buffer = (char *) my_realloc((gptr) buffer, size, - MyFlags | MY_FREE_ON_ERROR))) + if (push_dynamic(dir_entries_storage, (gptr)&finfo)) goto error; - length= sizeof(struct fileinfo ) * firstfcnt; - diff= PTR_BYTE_DIFF(buffer , obuffer) +length; - fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR)); - tempptr= ADD_TO_PTR(tempptr,diff,char*); - for (i = 0; i < maxfcnt; i++) - fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*); - - /* move filenames upp a bit */ - maxfcnt += firstfcnt; - bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*), - (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt)); - } - { - MY_DIR * s = (MY_DIR *) buffer; - s->number_off_files = (uint) fcnt; - s->dir_entry = fnames; - } - if (!(MyFlags & MY_DONT_SORT)) - qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names); -#ifndef __BORLANDC__ + +#ifdef __BORLANDC__ + } while (findnext(&find) == 0); +#else + } while (_findnext(handle,&find) == 0); + _findclose(handle); #endif - DBUG_RETURN((MY_DIR *) buffer); + result->dir_entry= (FILEINFO *)dir_entries_storage->buffer; + result->number_off_files= dir_entries_storage->elements; + + if (!(MyFlags & MY_DONT_SORT)) + qsort((void *) result->dir_entry, result->number_off_files, + sizeof(FILEINFO), (qsort_cmp) comp_names); + DBUG_RETURN(result); error: my_errno=errno; #ifndef __BORLANDC__ if (handle != -1) _findclose(handle); #endif + my_dirend(result); if (MyFlags & MY_FAE+MY_WME) my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno); DBUG_RETURN((MY_DIR *) NULL); @@ -485,14 +500,14 @@ error: MY_DIR *my_dir(const char* path, myf MyFlags) { - struct fileinfo *fnames; - char *buffer, *obuffer, *tempptr; - int eof,i,fcnt,firstfcnt,length,maxfcnt; - uint size; + char *buffer; + MY_DIR *result= 0; + FILEINFO finfo; + DYNAMIC_ARRAY *dir_entries_storage; + MEM_ROOT *names_storage; struct find_t find; ushort mode; char tmp_path[FN_REFLEN],*tmp_file,attrib; - my_ptrdiff_t diff; DBUG_ENTER("my_dir"); DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags)); @@ -514,63 +529,65 @@ MY_DIR *my_dir(const char* path, myf MyFlags) if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find)) goto error; - size = STARTSIZE; - firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) / - (sizeof(struct fileinfo) + FN_LEN); - if ((buffer = (char *) my_malloc(size, MyFlags)) == 0) + if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) + + sizeof(MEM_ROOT), MyFlags))) goto error; - fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR)); - tempptr = (char *) (fnames + maxfcnt); - fcnt = 0; - for (;;) + dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); + names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) + + ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))); + + if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO), + ENTRIES_START_SIZE, ENTRIES_INCREMENT)) + { + my_free((gptr) buffer,MYF(0)); + goto error; + } + init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE); + + /* MY_DIR structure is allocated and completly initialized at this point */ + result= (MY_DIR*)buffer; + + do { - do + if (!(finfo.name= strdup_root(names_storage, find.name))) + goto error; + + if (MyFlags & MY_WANT_STAT) { - fnames[fcnt].name = tempptr; - tempptr = strmov(tempptr,find.name) + 1; - fnames[fcnt].mystat.st_size=find.size; - fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0; - mode=MY_S_IREAD; attrib=find.attrib; + if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, + sizeof(MY_STAT)))) + goto error; + + bzero(finfo.mystat, sizeof(MY_STAT)); + finfo.mystat->st_size= find.size; + mode= MY_S_IREAD; attrib= find.attrib; if (!(attrib & _A_RDONLY)) - mode|=MY_S_IWRITE; + mode|= MY_S_IWRITE; if (attrib & _A_SUBDIR) - mode|=MY_S_IFDIR; - fnames[fcnt].mystat.st_mode=mode; - fnames[fcnt].mystat.st_mtime=((uint32) find.wr_date << 16) + - find.wr_time; - ++fcnt; - } while ((eof= _dos_findnext(&find)) == 0 && fcnt < maxfcnt); - - DBUG_PRINT("test",("eof: %d errno: %d",eof,errno)); - if (eof) - break; - size += STARTSIZE; obuffer = buffer; - if (!(buffer = (char *) my_realloc((gptr) buffer, size, - MyFlags | MY_FREE_ON_ERROR))) + mode|= MY_S_IFDIR; + finfo.mystat->st_mode= mode; + finfo.mystat->st_mtime= ((uint32) find.wr_date << 16) + find.wr_time; + } + else + finfo.mystat= NULL; + + if (push_dynamic(dir_entries_storage, (gptr)&finfo)) goto error; - length= sizeof(struct fileinfo ) * firstfcnt; - diff= PTR_BYTE_DIFF(buffer , obuffer) +length; - fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR)); - tempptr= ADD_TO_PTR(tempptr,diff,char*); - for (i = 0; i < maxfcnt; i++) - fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*); - - /* move filenames upp a bit */ - maxfcnt += firstfcnt; - bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*), - (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt)); - } - { - MY_DIR * s = (MY_DIR *) buffer; - s->number_off_files = (uint) fcnt; - s->dir_entry = fnames; - } + + } while (_dos_findnext(&find) == 0); + + result->dir_entry= (FILEINFO *)dir_entries_storage->buffer; + result->number_off_files= dir_entries_storage->elements; + if (!(MyFlags & MY_DONT_SORT)) - qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names); - DBUG_RETURN((MY_DIR *) buffer); + qsort((void *) result->dir_entry, result->number_off_files, + sizeof(FILEINFO), (qsort_cmp) comp_names); + DBUG_RETURN(result); error: + my_dirend(result); if (MyFlags & MY_FAE+MY_WME) my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno); DBUG_RETURN((MY_DIR *) NULL); @@ -602,9 +619,11 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) if ((m_used= (stat_area == NULL))) if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags))) goto error; - if ( ! stat((my_string) path, (struct stat *) stat_area) ) + if (! stat((my_string) path, (struct stat *) stat_area) ) DBUG_RETURN(stat_area); - my_errno=errno; + + DBUG_PRINT("error",("Got errno: %d from stat", errno)); + my_errno= errno; if (m_used) /* Free if new area */ my_free((gptr) stat_area,MYF(0)); diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index b9468d42cfc..045802c5e61 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -72,6 +72,7 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags) #else int result; DBUG_ENTER("my_symlink"); + DBUG_PRINT("enter",("content: %s linkname: %s", content, linkname)); result= 0; if (symlink(content, linkname)) diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index 68b034bec5c..913f632fbb4 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -31,9 +31,19 @@ File my_create_with_symlink(const char *linkname, const char *filename, File file; int tmp_errno; /* Test if we should create a link */ - int create_link=(linkname && strcmp(linkname,filename)); + int create_link; DBUG_ENTER("my_create_with_symlink"); + if (my_disable_symlinks) + { + /* Create only the file, not the link and file */ + create_link= 0; + if (linkname) + filename= linkname; + } + else + create_link= (linkname && strcmp(linkname,filename)); + if (!(MyFlags & MY_DELETE_OLD)) { if (!access(filename,F_OK)) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 1d4219e7bfb..237eeefa325 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -44,12 +44,23 @@ pthread_mutexattr_t my_fast_mutexattr; pthread_mutexattr_t my_errchk_mutexattr; #endif +/* + initialize thread environment + + SYNOPSIS + my_thread_global_init() + + RETURN + 0 ok + 1 error (Couldn't create THR_KEY_mysys) +*/ + my_bool my_thread_global_init(void) { - if (pthread_key_create(&THR_KEY_mysys,free)) + if (pthread_key_create(&THR_KEY_mysys,0)) { fprintf(stderr,"Can't initialize threads: error %d\n",errno); - exit(1); + return 1; } #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_init(&my_fast_mutexattr); @@ -78,15 +89,18 @@ my_bool my_thread_global_init(void) #ifndef HAVE_GETHOSTBYNAME_R pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW); #endif - return my_thread_init(); + if (my_thread_init()) + { + my_thread_global_end(); /* Clean up */ + return 1; + } + return 0; } void my_thread_global_end(void) { -#if defined(USE_TLS) - (void) TlsFree(THR_KEY_mysys); -#endif + pthread_key_delete(THR_KEY_mysys); #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_destroy(&my_fast_mutexattr); #endif @@ -155,6 +169,9 @@ my_bool my_thread_init(void) tmp= &THR_KEY_mysys; #endif tmp->id= ++thread_id; +#if defined(__WIN__) && defined(EMBEDDED_LIBRARY) + tmp->thread_self= (pthread_t)getpid(); +#endif pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&tmp->suspend, NULL); tmp->init= 1; diff --git a/regex/reginit.c b/regex/reginit.c index 09ffff37ef0..74ad3dc6de4 100644 --- a/regex/reginit.c +++ b/regex/reginit.c @@ -49,6 +49,16 @@ void regex_init(CHARSET_INFO *cs) for (i=0; i < CCLASS_LAST ; i++) { char *tmp=(char*) malloc(count[i]+1); + if (!tmp) + { + /* + This is very unlikely to happen as this function is called once + at program startup + */ + fprintf(stderr, + "Fatal error: Can't allocate memory in regex_init\n"); + exit(1); + } memcpy(tmp,buff[i],count[i]*sizeof(char)); tmp[count[i]]=0; cclasses[i].chars=tmp; diff --git a/sql/field.cc b/sql/field.cc index 23f6e1232b6..c54e27360b5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -791,7 +791,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) if (zerofill) { left_wall=to-1; - while (pos != left_wall) // Fill with zeros + while (pos > left_wall) // Fill with zeros *pos--='0'; } else @@ -799,7 +799,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) left_wall=to+(sign_char != 0)-1; if (!expo_sign_char) // If exponent was specified, ignore prezeros { - for (;pos != left_wall && pre_zeros_from !=pre_zeros_end; + for (;pos > left_wall && pre_zeros_from !=pre_zeros_end; pre_zeros_from++) *pos--= '0'; } @@ -1016,7 +1016,7 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr) return 0; if (*a_ptr == '-') return -1; - else if (*b_ptr == '-') + if (*b_ptr == '-') return 1; while (a_ptr != end) @@ -2853,34 +2853,71 @@ int Field_timestamp::store(double nr) function. */ -static longlong fix_datetime(longlong nr) +static longlong fix_datetime(longlong nr, TIME *time_res, + const char *field_name, bool *error) { - current_thd->last_cuted_field= 0; + long part1,part2; + + *error= 0; if (nr == LL(0) || nr >= LL(10000101000000)) - return nr; // Normal datetime >= Year 1000 + goto ok; if (nr < 101) goto err; if (nr <= (YY_PART_YEAR-1)*10000L+1231L) - return (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069 + { + nr= (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069 + goto ok; + } if (nr < (YY_PART_YEAR)*10000L+101L) goto err; if (nr <= 991231L) - return (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999 + { + nr= (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999 + goto ok; + } if (nr < 10000101L) goto err; if (nr <= 99991231L) - return nr*1000000L; + { + nr= nr*1000000L; + goto ok; + } if (nr < 101000000L) goto err; if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959)) - return nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069 + { + nr= nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069 + goto ok; + } if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000)) goto err; if (nr <= LL(991231235959)) - return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999 - + nr= nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999 + + ok: + part1=(long) (nr/LL(1000000)); + part2=(long) (nr - (longlong) part1*LL(1000000)); + time_res->year= (int) (part1/10000L); part1%=10000L; + time_res->month= (int) part1 / 100; + time_res->day= (int) part1 % 100; + time_res->hour= (int) (part2/10000L); part2%=10000L; + time_res->minute=(int) part2 / 100; + time_res->second=(int) part2 % 100; + + if (time_res->year <= 9999 && time_res->month <= 12 && + time_res->day <= 31 && time_res->hour <= 23 && + time_res->minute <= 59 && time_res->second <= 59) + return nr; + err: - current_thd->last_cuted_field= 1; + if (thd->count_cuted_fields) + { + thd->cuted_fields++; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED), + field_name, thd->row_count); + } + *error= 1; return LL(0); } @@ -2888,24 +2925,17 @@ static longlong fix_datetime(longlong nr) int Field_timestamp::store(longlong nr) { TIME l_time; - time_t timestamp; - long part1,part2; + time_t timestamp= 0; + bool error; - if ((nr=fix_datetime(nr))) + if ((nr= fix_datetime(nr, &l_time, field_name, &error))) { long not_used; - part1=(long) (nr/LL(1000000)); - part2=(long) (nr - (longlong) part1*LL(1000000)); - l_time.year= (int) (part1/10000L); part1%=10000L; - l_time.month= (int) part1 / 100; - l_time.day= (int) part1 % 100; - l_time.hour= (int) (part2/10000L); part2%=10000L; - l_time.minute=(int) part2 / 100; - l_time.second=(int) part2 % 100; - timestamp=my_gmt_sec(&l_time, ¬_used); - } - else - timestamp=0; + + if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1) + goto err; + timestamp= my_gmt_sec(&l_time, ¬_used); + } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -2914,9 +2944,14 @@ int Field_timestamp::store(longlong nr) else #endif longstore(ptr,(uint32) timestamp); - if (current_thd->last_cuted_field) - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); - return 0; + return error; + +err: + longstore(ptr,(uint32) 0); + if (current_thd->count_cuted_fields) + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, + field_name, 0); + return 1; } @@ -3350,7 +3385,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); return 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) + if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); if (nr != 0 || len != 4) { @@ -3363,6 +3398,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) return 0; } + int Field_year::store(double nr) { if (nr < 0.0 || nr >= 2155.0) @@ -3825,15 +3861,10 @@ int Field_datetime::store(double nr) int Field_datetime::store(longlong nr) { - int error= 0; - if (nr < 0 || nr > LL(99991231235959)) - { - nr=0; - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); - error= 1; - } - else - nr=fix_datetime(nr); + TIME not_used; + bool error; + + nr= fix_datetime(nr, ¬_used, field_name, &error); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -3842,11 +3873,10 @@ int Field_datetime::store(longlong nr) else #endif longlongstore(ptr,nr); - if (current_thd->last_cuted_field) - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return error; } + void Field_datetime::store_time(TIME *ltime,timestamp_type type) { longlong tmp; @@ -5064,7 +5094,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) uint tmp=find_type(typelib, from, length, 0); if (!tmp) { - if (length < 6) // Can't be more than 99999 enums + if (length < 6) // Can't be more than 99999 enums { /* This is for reading numbers with LOAD DATA INFILE */ char *end; @@ -5159,7 +5189,7 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)), { uint tmp=(uint) Field_enum::val_int(); if (!tmp || tmp > typelib->count) - val_ptr->length(0); + val_ptr->set((char*)"",0); else val_ptr->set((const char*) typelib->type_names[tmp-1], (uint) strlen(typelib->type_names[tmp-1]), @@ -5219,12 +5249,13 @@ void Field_enum::sql_type(String &res) const int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { - bool set_warning= 0; + bool got_warning= 0; int err= 0; char *not_used; uint not_used2; char buff[80]; String tmpstr(buff,sizeof(buff), &my_charset_bin); + /* Convert character set if nesessary */ if (use_conversion(cs, field_charset)) { @@ -5233,7 +5264,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) length= tmpstr.length(); } ulonglong tmp= find_set(typelib, from, length, ¬_used, ¬_used2, - &set_warning); + &got_warning); if (!tmp && length && length < 22) { /* This is for reading numbers with LOAD DATA INFILE */ @@ -5243,16 +5274,11 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { tmp=0; - THD *thd= current_thd; - if (thd->count_cuted_fields) - { - thd->cuted_fields++; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED), - field_name, 0); - } + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } } + else if (got_warning) + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); store_type(tmp); return err; } diff --git a/sql/field.h b/sql/field.h index 508fbad41a1..223ff4135d4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -872,11 +872,12 @@ public: enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, cs) {}; + unireg_check_arg, field_name_arg, table_arg, cs) + {} Field_varstring(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs) {}; + NONE, field_name_arg, table_arg, cs) + {} enum_field_types type() const { return FIELD_TYPE_VAR_STRING; } enum ha_base_keytype key_type() const @@ -927,6 +928,7 @@ public: { flags|= BLOB_FLAG; } + } enum_field_types type() const { return FIELD_TYPE_BLOB;} enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 7fc0664445d..4e42d629a0f 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1860,7 +1860,7 @@ ha_innobase::store_key_val_for_row( || mysql_type == FIELD_TYPE_BLOB || mysql_type == FIELD_TYPE_LONG_BLOB) { - ut_a(key_part->key_part_flag & HA_PART_KEY); + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); if (is_null) { buff += key_part->length + 2; @@ -3345,7 +3345,7 @@ create_index( for (i = 0; i < n_fields; i++) { key_part = key->key_part + i; - /* (The flag HA_PART_KEY denotes in MySQL a column prefix + /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix field in an index: we only store a specified number of first bytes of the column to the index field.) The flag does not seem to be properly set by MySQL. Let us fall back on testing diff --git a/sql/item.cc b/sql/item.cc index 072a7e5878f..9a9b8fe26a8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -101,6 +101,14 @@ void Item::print_item_w_name(String *str) } +Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, + const char *field_name_par) + :db_name(db_name_par),table_name(table_name_par),field_name(field_name_par), + depended_from(0) +{ + name = (char*) field_name_par; +} + // Constructor used by Item_field & Item_ref (see Item comment) Item_ident::Item_ident(THD *thd, Item_ident &item): Item(thd, item), @@ -1734,12 +1742,11 @@ Item_result item_cmp_type(Item_result a,Item_result b) { if (a == STRING_RESULT && b == STRING_RESULT) return STRING_RESULT; - else if (a == INT_RESULT && b == INT_RESULT) + if (a == INT_RESULT && b == INT_RESULT) return INT_RESULT; else if (a == ROW_RESULT || b == ROW_RESULT) return ROW_RESULT; - else - return REAL_RESULT; + return REAL_RESULT; } diff --git a/sql/item.h b/sql/item.h index a94a7a77597..90a0a706073 100644 --- a/sql/item.h +++ b/sql/item.h @@ -239,12 +239,7 @@ public: const char *field_name; st_select_lex *depended_from; Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par) - :db_name(db_name_par), table_name(table_name_par), - field_name(field_name_par), depended_from(0) - { name = (char*) field_name_par; } - // Constructor used by Item_field & Item_ref (see Item comment) - Item_ident(THD *thd, Item_ident &item); + const char *field_name_par); const char *full_name() const; bool remove_dependence_processor(byte * arg); diff --git a/sql/item_func.cc b/sql/item_func.cc index 0ccc7febd0a..7495987856a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -372,8 +372,7 @@ String *Item_real_func::val_str(String *str) double nr=val(); if (null_value) return 0; /* purecov: inspected */ - else - str->set(nr,decimals,default_charset()); + str->set(nr,decimals,default_charset()); return str; } @@ -385,7 +384,7 @@ String *Item_num_func::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; /* purecov: inspected */ - else if (!unsigned_flag) + if (!unsigned_flag) str->set(nr,default_charset()); else str->set((ulonglong) nr,default_charset()); @@ -395,8 +394,7 @@ String *Item_num_func::val_str(String *str) double nr=val(); if (null_value) return 0; /* purecov: inspected */ - else - str->set(nr,decimals,default_charset()); + str->set(nr,decimals,default_charset()); } return str; } @@ -422,7 +420,7 @@ String *Item_int_func::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; - else if (!unsigned_flag) + if (!unsigned_flag) str->set(nr,default_charset()); else str->set((ulonglong) nr,default_charset()); @@ -451,7 +449,7 @@ String *Item_num_op::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; /* purecov: inspected */ - else if (!unsigned_flag) + if (!unsigned_flag) str->set(nr,default_charset()); else str->set((ulonglong) nr,default_charset()); @@ -461,8 +459,7 @@ String *Item_num_op::val_str(String *str) double nr=val(); if (null_value) return 0; /* purecov: inspected */ - else - str->set(nr,decimals,default_charset()); + str->set(nr,decimals,default_charset()); } return str; } @@ -1032,7 +1029,7 @@ String *Item_func_min_max::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; - else if (!unsigned_flag) + if (!unsigned_flag) str->set(nr,default_charset()); else str->set((ulonglong) nr,default_charset()); @@ -1043,8 +1040,7 @@ String *Item_func_min_max::val_str(String *str) double nr=val(); if (null_value) return 0; /* purecov: inspected */ - else - str->set(nr,decimals,default_charset()); + str->set(nr,decimals,default_charset()); return str; } case STRING_RESULT: @@ -1672,8 +1668,7 @@ String *Item_func_udf_float::val_str(String *str) double nr=val(); if (null_value) return 0; /* purecov: inspected */ - else - str->set(nr,decimals,default_charset()); + str->set(nr,decimals,default_charset()); return str; } @@ -1693,7 +1688,7 @@ String *Item_func_udf_int::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; - else if (!unsigned_flag) + if (!unsigned_flag) str->set(nr,default_charset()); else str->set((ulonglong) nr,default_charset()); diff --git a/sql/item_func.h b/sql/item_func.h index 6b43ebaccbe..739110fd81f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -659,25 +659,31 @@ public: void fix_length_and_dec(); }; +/* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */ -class Item_func_bit_or :public Item_int_func +class Item_func_bit: public Item_int_func { public: - Item_func_bit_or(Item *a,Item *b) :Item_int_func(a,b) {} + Item_func_bit(Item *a, Item *b) :Item_int_func(a, b) {} + Item_func_bit(Item *a) :Item_int_func(a) {} + void fix_length_and_dec() { unsigned_flag= 1; } + void print(String *str) { print_op(str); } +}; + +class Item_func_bit_or :public Item_func_bit +{ +public: + Item_func_bit_or(Item *a, Item *b) :Item_func_bit(a, b) {} longlong val_int(); const char *func_name() const { return "|"; } - void fix_length_and_dec() { unsigned_flag=1; } - void print(String *str) { print_op(str); } }; -class Item_func_bit_and :public Item_int_func +class Item_func_bit_and :public Item_func_bit { public: - Item_func_bit_and(Item *a,Item *b) :Item_int_func(a,b) {} + Item_func_bit_and(Item *a, Item *b) :Item_func_bit(a, b) {} longlong val_int(); const char *func_name() const { return "&"; } - void fix_length_and_dec() { unsigned_flag=1; } - void print(String *str) { print_op(str); } }; class Item_func_bit_count :public Item_int_func @@ -689,32 +695,29 @@ public: void fix_length_and_dec() { max_length=2; } }; -class Item_func_shift_left :public Item_int_func +class Item_func_shift_left :public Item_func_bit { public: - Item_func_shift_left(Item *a,Item *b) :Item_int_func(a,b) {} + Item_func_shift_left(Item *a, Item *b) :Item_func_bit(a, b) {} longlong val_int(); const char *func_name() const { return "<<"; } - void fix_length_and_dec() { unsigned_flag=1; } - void print(String *str) { print_op(str); } }; -class Item_func_shift_right :public Item_int_func +class Item_func_shift_right :public Item_func_bit { public: - Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {} + Item_func_shift_right(Item *a, Item *b) :Item_func_bit(a, b) {} longlong val_int(); const char *func_name() const { return ">>"; } - void print(String *str) { print_op(str); } }; -class Item_func_bit_neg :public Item_int_func +class Item_func_bit_neg :public Item_func_bit { public: - Item_func_bit_neg(Item *a) :Item_int_func(a) {} + Item_func_bit_neg(Item *a) :Item_func_bit(a) {} longlong val_int(); const char *func_name() const { return "~"; } - void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { Item_func_int::print(str); } }; class Item_func_set_last_insert_id :public Item_int_func @@ -1021,14 +1024,12 @@ public: }; -class Item_func_bit_xor : public Item_int_func +class Item_func_bit_xor : public Item_func_bit { public: - Item_func_bit_xor(Item *a,Item *b) :Item_int_func(a,b) {} + Item_func_bit_xor(Item *a, Item *b) :Item_func_bit(a, b) {} longlong val_int(); const char *func_name() const { return "^"; } - void fix_length_xor_dec() { unsigned_flag=1; } - void print(String *str) { print_op(str); } }; class Item_func_is_free_lock :public Item_int_func diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index f40d38dd4a8..16c886b558e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1839,14 +1839,11 @@ inline String* alloc_buffer(String *res,String *str,String *tmp_value, str->length(length); return str; } - else - { - if (tmp_value->alloc(length)) - return 0; - (void) tmp_value->copy(*res); - tmp_value->length(length); - return tmp_value; - } + if (tmp_value->alloc(length)) + return 0; + (void) tmp_value->copy(*res); + tmp_value->length(length); + return tmp_value; } res->length(length); return res; @@ -1947,7 +1944,7 @@ String *Item_func_rpad::val_str(String *str) int32 count= (int32) args[1]->val_int(); int32 byte_count= count * collation.collation->mbmaxlen; String *res =args[0]->val_str(str); - String *rpad = args[2]->val_str(str); + String *rpad = args[2]->val_str(&rpad_str); if (!res || args[1]->null_value || !rpad || count < 0) goto err; @@ -2384,6 +2381,10 @@ String* Item_func_export_set::val_str(String* str) null_value=1; return 0; } + /* + Arg count can only be 3, 4 or 5 here. This is guaranteed from the + grammar for EXPORT_SET() + */ switch(arg_count) { case 5: num_set_values = (uint) args[4]->val_int(); @@ -2513,7 +2514,7 @@ String *Item_func_quote::val_str(String *str) new_length= arg_length+2; /* for beginning and ending ' signs */ for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++) - new_length+= get_esc_bit(escmask, *from); + new_length+= get_esc_bit(escmask, (uchar) *from); /* We have to use realloc() instead of alloc() as we want to keep the diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index a7949511f02..40b00cdd488 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -474,7 +474,7 @@ public: class Item_func_rpad :public Item_str_func { - String tmp_value; + String tmp_value, rpad_str; public: Item_func_rpad(Item *arg1,Item *arg2,Item *arg3) :Item_str_func(arg1,arg2,arg3) {} @@ -486,7 +486,7 @@ public: class Item_func_lpad :public Item_str_func { - String tmp_value; + String tmp_value, lpad_str; public: Item_func_lpad(Item *arg1,Item *arg2,Item *arg3) :Item_str_func(arg1,arg2,arg3) {} diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 62782e1f710..8d9973e78f8 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -148,10 +148,13 @@ Item_sum_num::val_str(String *str) String * Item_sum_int::val_str(String *str) { - longlong nr=val_int(); + longlong nr= val_int(); if (null_value) return 0; - str->set(nr,default_charset()); + if (unsigned_flag) + str->set((ulonglong) nr, &my_charset_bin); + else + str->set(nr, &my_charset_bin); return str; } @@ -776,9 +779,16 @@ void Item_sum_avg::reset_field() void Item_sum_bit::reset_field() { + reset(); + int8store(result_field->ptr, bits); +} + +void Item_sum_bit::update_field() +{ char *res=result_field->ptr; - ulonglong nr=(ulonglong) args[0]->val_int(); - int8store(res,nr); + bits= uint8korr(res); + add(); + int8store(res, bits); } /* @@ -916,37 +926,6 @@ Item_sum_hybrid::min_max_update_int_field() } -void Item_sum_or::update_field() -{ - ulonglong nr; - char *res=result_field->ptr; - - nr=uint8korr(res); - nr|= (ulonglong) args[0]->val_int(); - int8store(res,nr); -} - -void Item_sum_xor::update_field() -{ - ulonglong nr; - char *res=result_field->ptr; - - nr=uint8korr(res); - nr^= (ulonglong) args[0]->val_int(); - int8store(res,nr); -} - -void Item_sum_and::update_field() -{ - ulonglong nr; - char *res=result_field->ptr; - - nr=uint8korr(res); - nr&= (ulonglong) args[0]->val_int(); - int8store(res,nr); -} - - Item_avg_field::Item_avg_field(Item_sum_avg *item) { name=item->name; @@ -956,6 +935,7 @@ Item_avg_field::Item_avg_field(Item_sum_avg *item) maybe_null=1; } + double Item_avg_field::val() { double nr; @@ -1415,8 +1395,7 @@ String *Item_sum_udf_float::val_str(String *str) double nr=val(); if (null_value) return 0; /* purecov: inspected */ - else - str->set(nr,decimals,default_charset()); + str->set(nr,decimals, &my_charset_bin); return str; } @@ -1441,8 +1420,7 @@ String *Item_sum_udf_int::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; - else - str->set(nr,default_charset()); + str->set(nr, &my_charset_bin); return str; } diff --git a/sql/item_sum.h b/sql/item_sum.h index d454f06ccde..3fe40ca4c68 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -65,7 +65,18 @@ public: inline bool reset() { clear(); return add(); }; virtual void clear()= 0; virtual bool add()=0; + /* + Called when new group is started and results are being saved in + a temporary table. Similar to reset(), but must also store value in + result_field. Like reset() it is supposed to reset start value to + default. + */ virtual void reset_field()=0; + /* + Called for each new value in the group, when temporary table is in use. + Similar to add(), but uses temporary table field to obtain current value, + Updated value is then saved in the field. + */ virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } @@ -445,10 +456,10 @@ public: class Item_sum_bit :public Item_sum_int { - protected: +protected: ulonglong reset_bits,bits; - public: +public: Item_sum_bit(Item *item_par,ulonglong reset_arg) :Item_sum_int(item_par),reset_bits(reset_arg),bits(reset_arg) {} Item_sum_bit(THD *thd, Item_sum_bit &item): @@ -464,11 +475,10 @@ class Item_sum_bit :public Item_sum_int class Item_sum_or :public Item_sum_bit { - public: +public: Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_or(THD *thd, Item_sum_or &item) :Item_sum_bit(thd, item) {} bool add(); - void update_field(); const char *func_name() const { return "bit_or"; } Item *copy_or_same(THD* thd); }; @@ -477,10 +487,9 @@ class Item_sum_or :public Item_sum_bit class Item_sum_and :public Item_sum_bit { public: - Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {} + Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {} Item_sum_and(THD *thd, Item_sum_and &item) :Item_sum_bit(thd, item) {} bool add(); - void update_field(); const char *func_name() const { return "bit_and"; } Item *copy_or_same(THD* thd); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a5372a4ae60..9799c5814c4 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -526,8 +526,11 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, uint year; if (type == TIMESTAMP_TIME) return 1; - length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year), - intbuff, 10) - intbuff; + length= int10_to_str(calc_week(l_time, + (*ptr) == 'U' ? + WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST, + &year), + intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); } break; @@ -537,8 +540,12 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, uint year; if (type == TIMESTAMP_TIME) return 1; - length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year), - intbuff, 10) - intbuff; + length= int10_to_str(calc_week(l_time, + ((*ptr) == 'V' ? + (WEEK_YEAR | WEEK_FIRST_WEEKDAY) : + (WEEK_YEAR | WEEK_MONDAY_FIRST)), + &year), + intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); } break; @@ -548,7 +555,11 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, uint year; if (type == TIMESTAMP_TIME) return 1; - (void) calc_week(l_time, 1, (*ptr) == 'X', &year); + (void) calc_week(l_time, + ((*ptr) == 'X' ? + WEEK_YEAR | WEEK_FIRST_WEEKDAY : + WEEK_YEAR | WEEK_MONDAY_FIRST), + &year); length= int10_to_str(year, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 4, '0'); } @@ -718,27 +729,51 @@ longlong Item_func_second::val_int() } -/* - Returns the week of year. +uint week_mode(uint mode) +{ + uint week_format= (mode & 7); + if (!(week_format & WEEK_MONDAY_FIRST)) + week_format^= WEEK_FIRST_WEEKDAY; + return week_format; +} - The bits in week_format has the following meaning: - 0 If not set: USA format: Sunday is first day of week - If set: ISO format: Monday is first day of week - 1 If not set: Week is in range 0-53 - If set Week is in range 1-53. +/* + The bits in week_format(for calc_week() function) has the following meaning: + WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week + If set Monday is first day of week + WEEK_YEAR (1) If not set Week is in range 0-53 + + Week 0 is returned for the the last week of the previous year (for + a date at start of january) In this case one can get 53 for the + first week of next year. This flag ensures that the week is + relevant for the given year. Note that this flag is only + releveant if WEEK_JANUARY is not set. + + If set Week is in range 1-53. + + In this case one may get week 53 for a date in January (when + the week is that last week of previous year) and week 1 for a + date in December. + + WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according + to ISO 8601:1988 + If set The week that contains the first + 'first-day-of-week' is week 1. + + ISO 8601:1988 means that if the week containing January 1 has + four or more days in the new year, then it is week 1; + Otherwise it is the last week of the previous year, and the + next week is week 1. */ longlong Item_func_week::val_int() { uint year; - uint week_format; TIME ltime; if (get_arg0_date(<ime,0)) return 0; - week_format= (uint) args[1]->val_int(); - return (longlong) calc_week(<ime, - (week_format & 2) != 0, - (week_format & 1) == 0, + return (longlong) calc_week(<ime, + week_mode((uint) args[1]->val_int()), &year); } @@ -749,7 +784,9 @@ longlong Item_func_yearweek::val_int() TIME ltime; if (get_arg0_date(<ime,0)) return 0; - week=calc_week(<ime, 1, (args[1]->val_int() & 1) == 0, &year); + week= calc_week(<ime, + (week_mode((uint) args[1]->val_int()) | WEEK_YEAR), + &year); return week+year*100; } diff --git a/sql/log.cc b/sql/log.cc index 936373daf03..b490845c256 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -964,7 +964,7 @@ void MYSQL_LOG::new_file(bool need_lock) We log the whole file name for log file as the user may decide to change base names at some point. */ - THD* thd = current_thd; + THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */ Rotate_log_event r(thd,new_name+dirname_length(new_name)); r.set_log_pos(this); r.write(&log_file); @@ -1231,8 +1231,6 @@ bool MYSQL_LOG::write(Log_event* event_info) Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT, thd->current_insert_id); e.set_log_pos(this); - if (thd->server_id) - e.server_id = thd->server_id; if (e.write(file)) goto err; } @@ -1240,8 +1238,6 @@ bool MYSQL_LOG::write(Log_event* event_info) { Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id); e.set_log_pos(this); - if (thd->server_id) - e.server_id = thd->server_id; if (e.write(file)) goto err; } diff --git a/sql/log_event.cc b/sql/log_event.cc index d0dc0a83b11..b609e6c6b11 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -239,6 +239,13 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) } +/* + This minimal constructor is for when you are not even sure that there is a + valid THD. For example in the server when we are shutting down or flushing + logs after receiving a SIGHUP (then we must write a Rotate to the binlog but + we have no THD, so we need this minimal constructor). +*/ + Log_event::Log_event() :temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0), thd(0) @@ -1032,7 +1039,7 @@ Default database: '%s'", thd->variables.convert_set = 0; #endif close_thread_tables(thd); - free_root(&thd->mem_root,0); + free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC)); return (thd->query_error ? thd->query_error : Log_event::exec_event(rli)); } #endif @@ -1794,10 +1801,10 @@ Slave: load data infile on table '%s' at log position %s in log \ slave_print_error(rli,sql_errno,"\ Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'", err, (char*)table_name, print_slave_db_safe(db)); - free_root(&thd->mem_root,0); + free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC)); return 1; } - free_root(&thd->mem_root,0); + free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC)); if (thd->is_fatal_error) { diff --git a/sql/log_event.h b/sql/log_event.h index 6cc8a7ca06d..d615c0e361b 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -698,7 +698,7 @@ public: #ifndef MYSQL_CLIENT Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg) - :Log_event(),val(val_arg),type(type_arg) + :Log_event(thd_arg,0,0),val(val_arg),type(type_arg) {} #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); @@ -841,7 +841,7 @@ public: Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg, uint ident_len_arg = 0, ulonglong pos_arg = LOG_EVENT_OFFSET) - :Log_event(thd_arg,0,0), new_log_ident(new_log_ident_arg), + :Log_event(), new_log_ident(new_log_ident_arg), pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg : (uint) strlen(new_log_ident_arg)), alloced(0) {} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7164a4e496d..bff9ed94a23 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -283,6 +283,11 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define tmp_file_prefix "#sql" /* Prefix for tmp tables */ #define tmp_file_prefix_length 4 +/* Flags for calc_week() function. */ +#define WEEK_MONDAY_FIRST 1 +#define WEEK_YEAR 2 +#define WEEK_FIRST_WEEKDAY 4 + struct st_table; class THD; @@ -418,6 +423,7 @@ void mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); +bool check_dup(const char *db, const char *name, TABLE_LIST *tables); #ifndef EMBEDDED_LIBRARY bool check_stack_overrun(THD *thd,char *dummy); #else @@ -977,8 +983,7 @@ void filesort_free_buffers(TABLE *table); void change_double_for_sort(double nr,byte *to); int get_quick_record(SQL_SELECT *select); int calc_weekday(long daynr,bool sunday_first_day_of_week); -uint calc_week(TIME *ltime, bool with_year, bool sunday_first_day_of_week, - uint *year); +uint calc_week(TIME *l_time, uint week_behaviour, uint *year); 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); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 49f0b753549..36fa744e328 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -497,6 +497,8 @@ static uint set_maximum_open_files(uint max_file_limit); static ulong find_bit_type(const char *x, TYPELIB *bit_lib); static void clean_up(bool print_message); static void clean_up_mutexes(void); +static int test_if_case_insensitive(const char *dir_name); +static void create_pid_file(); #ifndef EMBEDDED_LIBRARY /**************************************************************************** @@ -1058,7 +1060,7 @@ static void set_user(const char *user) } return; } - else if (!user) + if (!user) { if (!opt_bootstrap) { @@ -1480,16 +1482,7 @@ static void start_signal_handler(void) { // Save vm id of this process if (!opt_bootstrap) - { - File pidFile; - if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0) - { - char buff[21]; - sprintf(buff,"%lu",(ulong) getpid()); - (void) my_write(pidFile, buff,strlen(buff),MYF(MY_WME)); - (void) my_close(pidFile,MYF(0)); - } - } + create_pid_file(); // no signal handler } @@ -1775,16 +1768,8 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) /* Save pid to this process (or thread on Linux) */ if (!opt_bootstrap) - { - File pidFile; - if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0) - { - char buff[21]; - ulong length= my_sprintf(buff, (buff,"%lu",(ulong) getpid())); - (void) my_write(pidFile, buff, length, MYF(MY_WME)); - (void) my_close(pidFile,MYF(0)); - } - } + create_pid_file(); + #ifdef HAVE_STACK_TRACE_ON_SEGV if (opt_do_pstack) { @@ -2756,7 +2741,7 @@ default_service_handling(char **argv, } /* We must have servicename last */ *pos++= ' '; - strmake(pos, servicename, (uint) (end+2 - pos)); + (void) add_quoted_string(pos, servicename, end); if (Service.got_service_option(argv, "install")) { @@ -4592,7 +4577,7 @@ The minimum value for this variable is 4096.", 1, 0}, {"table_cache", OPT_TABLE_CACHE, "The number of open tables for all threads.", (gptr*) &table_cache_size, - (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 16384, 0, 1, + (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, ~0L, 0, 1, 0}, {"thread_concurrency", OPT_THREAD_CONCURRENCY, "Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.", @@ -4635,7 +4620,7 @@ The minimum value for this variable is 4096.", "The default week format used by WEEK() functions.", (gptr*) &global_system_variables.default_week_format, (gptr*) &max_system_variables.default_week_format, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0}, + 0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 0, 1, 0}, { "date-format", OPT_DATE_FORMAT, "The DATE format (For future).", (gptr*) &opt_date_time_formats[TIMESTAMP_DATE], @@ -5373,11 +5358,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), my_use_symdir=0; break; case (int) OPT_BIND_ADDRESS: - if (!argument || - (my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE) + if ((my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE) { struct hostent *ent; - if (argument || argument[0]) + if (argument[0]) ent=gethostbyname(argument); else { @@ -5787,6 +5771,17 @@ static void fix_paths(void) exit(1); } #endif /* HAVE_REPLICATION */ + + /* + Ensure that lower_case_table_names is set on system where we have case + insensitive names. If this is not done the users MyISAM tables will + get corrupted if accesses with names of different case. + */ + if (!lower_case_table_names && + test_if_case_insensitive(mysql_real_data_home) == 1) + { + sql_print_error("Warning: Setting lower_case_table_names=1 because file system for '%s' is case insensitive", mysql_real_data_home); + } } @@ -5940,6 +5935,60 @@ skipp: ; } /* find_bit_type */ +/* + Check if file system used for databases is case insensitive + + SYNOPSIS + test_if_case_sensitive() + dir_name Directory to test + + RETURN + -1 Don't know (Test failed) + 0 File system is case sensitive + 1 File system is case insensitive +*/ + +static int test_if_case_insensitive(const char *dir_name) +{ + int result= 0; + File file; + char buff[FN_REFLEN], buff2[FN_REFLEN]; + MY_STAT stat_info; + + fn_format(buff, glob_hostname, dir_name, ".lower-test", + MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); + fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST", + MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); + (void) my_delete(buff2, MYF(0)); + if ((file= my_create(buff, 0666, O_RDWR, MYF(0))) < 0) + { + sql_print_error("Warning: Can't create test file %s", buff); + return -1; + } + my_close(file, MYF(0)); + if (my_stat(buff2, &stat_info, MYF(0))) + result= 1; // Can access file + (void) my_delete(buff, MYF(MY_WME)); + return result; +} + + +/* Create file to store pid number */ + +static void create_pid_file() +{ + File file; + if ((file = my_create(pidfile_name,0664, + O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0) + { + char buff[21]; + sprintf(buff,"%lu\n",(ulong) getpid()); + (void) my_write(file, buff,strlen(buff),MYF(MY_WME)); + (void) my_close(file, MYF(0)); + } +} + + /***************************************************************************** Instantiate templates *****************************************************************************/ diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc index 25fc010d9a5..3e9d68d5fdb 100644 --- a/sql/nt_servc.cc +++ b/sql/nt_servc.cc @@ -496,9 +496,9 @@ BOOL NTService::IsService(LPCSTR ServiceName) BOOL ret_value=FALSE; SC_HANDLE service, scm; - if (scm = OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE)) + if ((scm= OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE))) { - if ((service = OpenService(scm,ServiceName, SERVICE_ALL_ACCESS ))) + if ((service = OpenService(scm,ServiceName, SERVICE_QUERY_STATUS ))) { ret_value=TRUE; CloseServiceHandle(service); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index bbdc1913a8c..54c3f3c0ae3 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -966,9 +966,10 @@ static SEL_ARG * get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, Item_func::Functype type,Item *value) { - uint maybe_null=(uint) field->real_maybe_null(); + uint maybe_null=(uint) field->real_maybe_null(), copies; uint field_length=field->pack_length()+maybe_null; SEL_ARG *tree; + char *str, *str2; DBUG_ENTER("get_mm_leaf"); if (type == Item_func::LIKE_FUNC) @@ -1069,16 +1070,39 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, /* This happens when we try to insert a NULL field in a not null column */ DBUG_RETURN(&null_element); // cmp with NULL is never true } - // Get local copy of key - char *str= (char*) alloc_root(param->mem_root, - key_part->part_length+maybe_null); + /* Get local copy of key */ + copies= 1; + if (field->key_type() == HA_KEYTYPE_VARTEXT) + copies= 2; + str= str2= (char*) alloc_root(param->mem_root, + (key_part->part_length+maybe_null)*copies+1); if (!str) DBUG_RETURN(0); if (maybe_null) *str= (char) field->is_real_null(); // Set to 1 if null field->get_key_image(str+maybe_null,key_part->part_length, field->charset(),key_part->image_type); - if (!(tree=new SEL_ARG(field,str,str))) + if (copies == 2) + { + /* + The key is stored as 2 byte length + key + key doesn't match end space. In other words, a key 'X ' should match + all rows between 'X' and 'X ...' + */ + uint length= uint2korr(str+maybe_null); + char *end; + str2= str+ key_part->part_length + maybe_null; + /* remove end space */ + while (length > 0 && str[length+HA_KEY_BLOB_LENGTH+maybe_null-1] == ' ') + length--; + int2store(str+maybe_null, length); + /* Create key that is space filled */ + memcpy(str2, str, length + HA_KEY_BLOB_LENGTH + maybe_null); + bfill(str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null, + key_part->part_length-length - HA_KEY_BLOB_LENGTH, ' '); + int2store(str2+maybe_null, key_part->part_length - HA_KEY_BLOB_LENGTH); + } + if (!(tree=new SEL_ARG(field,str,str2))) DBUG_RETURN(0); // out of memory switch (type) { @@ -1460,7 +1484,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) } return 0; } - else if (!key2) + if (!key2) { key1->use_count--; key1->free_tree(); @@ -2219,7 +2243,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, param->range_count++; if (!tmp_min_flag && ! tmp_max_flag && (uint) key_tree->part+1 == param->table->key_info[keynr].key_parts && - (param->table->key_info[keynr].flags & HA_NOSAME) && + (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) == + HA_NOSAME && min_key_length == max_key_length && !memcmp(param->min_key,param->max_key,min_key_length)) tmp=1; // Max one record @@ -2373,7 +2398,8 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, { KEY *table_key=quick->head->key_info+quick->index; flag=EQ_RANGE; - if (table_key->flags & HA_NOSAME && key->part == table_key->key_parts-1) + if ((table_key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME && + key->part == table_key->key_parts-1) { if (!(table_key->flags & HA_NULL_PART_KEY) || !null_part_in_key(key, @@ -2419,7 +2445,7 @@ bool QUICK_SELECT::unique_key_range() if (((tmp=ranges.head())->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE) { KEY *key=head->key_info+index; - return ((key->flags & HA_NOSAME) && + return ((key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME && key->key_length == tmp->min_length); } } @@ -2454,6 +2480,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) QUICK_SELECT *quick=new QUICK_SELECT(thd, table, ref->key, 1); KEY *key_info = &table->key_info[ref->key]; KEY_PART *key_part; + QUICK_RANGE *range; uint part; if (!quick) @@ -2461,18 +2488,18 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) if (cp_buffer_from_ref(ref)) { if (thd->is_fatal_error) - return 0; // out of memory + goto err; // out of memory return quick; // empty range } - QUICK_RANGE *range= new QUICK_RANGE(); - if (!range) + if (!(range= new QUICK_RANGE())) goto err; // out of memory range->min_key=range->max_key=(char*) ref->key_buff; range->min_length=range->max_length=ref->key_length; range->flag= ((ref->key_length == key_info->key_length && - (key_info->flags & HA_NOSAME)) ? EQ_RANGE : 0); + (key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == + HA_NOSAME) ? EQ_RANGE : 0); if (!(quick->key_parts=key_part=(KEY_PART *) alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) diff --git a/sql/records.cc b/sql/records.cc index 7ba9ff0f42f..0feb873a6af 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -118,11 +118,12 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, info->read_record=rr_sequential; table->file->rnd_init(); /* We can use record cache if we don't update dynamic length tables */ - if (use_record_cache > 0 || - (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY || - !(table->db_options_in_use & HA_OPTION_PACK_RECORD) || - (use_record_cache < 0 && - !(table->file->table_flags() & HA_NOT_DELETE_WITH_CACHE))) + if (!table->no_cache && + (use_record_cache > 0 || + (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY || + !(table->db_options_in_use & HA_OPTION_PACK_RECORD) || + (use_record_cache < 0 && + !(table->file->table_flags() & HA_NOT_DELETE_WITH_CACHE)))) VOID(table->file->extra_opt(HA_EXTRA_CACHE, thd->variables.read_buff_size)); } diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 084f7386b7b..18456af8048 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -52,6 +52,13 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, const char* log_file_name, char* errmsg); +/* + All of the functions defined in this file which are not used (the ones to + handle failsafe) are not used; their code has not been updated for more than + one year now so should be considered as BADLY BROKEN. Do not enable it. + The used functions (to handle LOAD DATA FROM MASTER, plus some small + functions like register_slave()) are working. +*/ static int init_failsafe_rpl_thread(THD* thd) { @@ -418,7 +425,6 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, my_snprintf(errmsg, SLAVE_ERRMSG_SIZE, "Could not find slave event in log '%s'", (char*)log_file_name); - delete ev; return 0; } diff --git a/sql/slave.cc b/sql/slave.cc index b13ac799c9b..7f9967618ca 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2352,7 +2352,9 @@ improper_arguments: %d timed_out: %d", static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) { DBUG_ENTER("init_slave_thread"); - thd->system_thread = thd->bootstrap = 1; + thd->system_thread = (thd_type == SLAVE_THD_SQL) ? + SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; + thd->bootstrap= 1; thd->host_or_ip= ""; thd->client_capabilities = 0; my_net_init(&thd->net, 0); @@ -4036,8 +4038,20 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s", sizeof(rli->event_relay_log_name)-1); flush_relay_log_info(rli); } - - // next log is hot + + /* + Now we want to open this next log. To know if it's a hot log (the one + being written by the I/O thread now) or a cold log, we can use + is_active(); if it is hot, we use the I/O cache; if it's cold we open + the file normally. But if is_active() reports that the log is hot, this + may change between the test and the consequence of the test. So we may + open the I/O cache whereas the log is now cold, which is nonsense. + To guard against this, we need to have LOCK_log. + */ + + DBUG_PRINT("info",("hot_log: %d",hot_log)); + if (!hot_log) /* if hot_log, we already have this mutex */ + pthread_mutex_lock(log_lock); if (rli->relay_log.is_active(rli->linfo.log_file_name)) { #ifdef EXTRA_DEBUG @@ -4050,15 +4064,24 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s", /* Read pointer has to be at the start since we are the only - reader + reader. + We must keep the LOCK_log to read the 4 first bytes, as this is a hot + log (same as when we call read_log_event() above: for a hot log we + take the mutex). */ if (check_binlog_magic(cur_log,&errmsg)) + { + if (!hot_log) pthread_mutex_unlock(log_lock); goto err; + } + if (!hot_log) pthread_mutex_unlock(log_lock); continue; } + if (!hot_log) pthread_mutex_unlock(log_lock); /* - if we get here, the log was not hot, so we will have to - open it ourselves + if we get here, the log was not hot, so we will have to open it + ourselves. We are sure that the log is still not hot now (a log can get + from hot to cold, but not from cold to hot). No need for LOCK_log. */ #ifdef EXTRA_DEBUG sql_print_error("next log '%s' is not active", diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5364357a24b..c0f36f202f3 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -697,6 +697,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, If cipher name is specified, we compare it to actual cipher in use. */ + X509 *cert; if (vio_type(vio) != VIO_TYPE_SSL || SSL_get_verify_result(ssl) != X509_V_OK) break; @@ -717,7 +718,11 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, } /* Prepare certificate (if exists) */ DBUG_PRINT("info",("checkpoint 1")); - X509* cert=SSL_get_peer_certificate(ssl); + if (!(cert= SSL_get_peer_certificate(ssl))) + { + user_access=NO_ACCESS; + break; + } DBUG_PRINT("info",("checkpoint 2")); /* If X509 issuer is speified, we check it... */ if (acl_user->x509_issuer) @@ -1186,6 +1191,7 @@ bool change_password(THD *thd, const char *host, const char *user, acl_user->user ? acl_user->user : "", acl_user->host.hostname ? acl_user->host.hostname : "", new_password)); + thd->clear_error(); mysql_update_log.write(thd, buff, query_length); Query_log_event qinfo(thd, buff, query_length, 0); mysql_bin_log.write(&qinfo); @@ -1258,11 +1264,11 @@ static const char *calc_ip(const char *ip, long *val, char end) static void update_hostname(acl_host_and_ip *host, const char *hostname) { host->hostname=(char*) hostname; // This will not be modified! - if (hostname && + if (!hostname || (!(hostname=calc_ip(hostname,&host->ip,'/')) || !(hostname=calc_ip(hostname+1,&host->ip_mask,'\0')))) { - host->ip=host->ip_mask=0; // Not a masked ip + host->ip= host->ip_mask=0; // Not a masked ip } } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index a6c24a25d6e..9e73e06d9c6 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -213,8 +213,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) info->is_float = 1; // we can't use variable decimals here return 1; } - else - return 0; + return 0; } for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end if (str == end) // number was something like '123.000' @@ -229,11 +228,8 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) info->dval = atod(begin); return 1; } - else - return 0; } - else - return 0; + return 0; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 55ddfec6bfb..ebb94e11d9d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -513,8 +513,8 @@ void close_temporary_tables(THD *thd) if (query && found_user_tables && mysql_bin_log.is_open()) { /* The -1 is to remove last ',' */ + thd->clear_error(); Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0); - qinfo.error_code=0; mysql_bin_log.write(&qinfo); } thd->temporary_tables=0; @@ -1752,6 +1752,19 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, const char *table_name=item->table_name; const char *name=item->field_name; uint length=(uint) strlen(name); + char name_buff[NAME_LEN+1]; + + if (db && lower_case_table_names) + { + /* + convert database to lower case for comparision. + We can't do this in Item_field as this would change the + 'name' of the item which may be used in the select list + */ + strmake(name_buff, db, sizeof(name_buff)-1); + casedn_str(name_buff); + db= name_buff; + } if (table_name && table_name[0]) { /* Qualified field */ @@ -1969,7 +1982,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, while ( wild_num && (item= it++)) { if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name && - ((Item_field*) item)->field_name[0] == '*') + ((Item_field*) item)->field_name[0] == '*' && + !((Item_field*) item)->field) { uint elem= fields.elements; if (insert_fields(thd,tables,((Item_field*) item)->db_name, diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 396764cd532..71dd7123d98 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1206,9 +1206,29 @@ void Query_cache::invalidate(char *db) if (query_cache_size > 0) { DUMP(this); - /* invalidate_table reduce list while only root of list remain */ - while (tables_blocks !=0 ) - invalidate_table(tables_blocks); + restart_search: + if (tables_blocks) + { + Query_cache_block *curr= tables_blocks; + Query_cache_block *next; + do + { + next= curr->next; + if (strcmp(db, (char*)(curr->table()->db())) == 0) + invalidate_table(curr); + /* + invalidate_table can freed block on which point 'next' (if + table of this block used only in queries which was deleted + by invalidate_table). As far as we do not allocate new blocks + and mark all headers of freed blocks as 'FREE' (even if they are + merged with other blocks) we can just test type of block + to be sure that block is not deleted + */ + if (next->type == Query_cache_block::FREE) + goto restart_search; + curr= next; + } while (curr != tables_blocks); + } } STRUCT_UNLOCK(&structure_guard_mutex); } @@ -2218,9 +2238,11 @@ void Query_cache::free_memory_block(Query_cache_block *block) { DBUG_ENTER("Query_cache::free_memory_block"); block->used=0; - DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx", - (ulong) first_block, (ulong) block,block->pnext, - (ulong) block->pprev)); + block->type= Query_cache_block::FREE; // mark block as free in any case + DBUG_PRINT("qcache", + ("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx", + (ulong) first_block, (ulong) block, (ulong) block->pnext, + (ulong) block->pprev)); if (block->pnext != first_block && block->pnext->is_free()) block = join_free_blocks(block, block->pnext); diff --git a/sql/sql_class.h b/sql/sql_class.h index 1fce0049269..5479a3cecb6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -589,7 +589,7 @@ public: long dbug_thread_id; pthread_t real_id; uint current_tablenr,tmp_table; - uint server_status,open_options; + uint server_status,open_options,system_thread; uint32 query_length; uint32 db_length; uint select_number; //number of select (used for EXPLAIN) @@ -607,7 +607,7 @@ public: bool last_cuted_field; bool no_errors, allow_sum_func, password, is_fatal_error; bool query_start_used,last_insert_id_used,insert_id_used,rand_used; - bool system_thread,in_lock_tables,global_read_lock; + bool in_lock_tables,global_read_lock; bool query_error, bootstrap, cleanup_done; bool volatile killed; bool tmp_table_used; @@ -750,6 +750,11 @@ public: void update_charset(); }; +/* Flags for the THD::system_thread (bitmap) variable */ +#define SYSTEM_THREAD_DELAYED_INSERT 1 +#define SYSTEM_THREAD_SLAVE_IO 2 +#define SYSTEM_THREAD_SLAVE_SQL 4 + /* Used to hold information about file and file structure in exchainge via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) @@ -761,7 +766,7 @@ public: String *field_term,*enclosed,*line_term,*line_start,*escaped; bool opt_enclosed; bool dumpfile; - uint skip_lines; + ulong skip_lines; sql_exchange(char *name,bool dumpfile_flag); ~sql_exchange() {} }; @@ -1109,7 +1114,7 @@ class multi_delete :public select_result TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; THD *thd; - ha_rows deleted; + ha_rows deleted, found; uint num_of_tables; int error; bool do_delete, transactional_tables, log_delayed, normal_tables; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index c61e6800cfa..1f652524ed3 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -298,6 +298,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + thd->clear_error(); mysql_bin_log.write(&qinfo); } send_ok(thd, result); @@ -384,6 +385,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, query, query_length, 0); + thd->clear_error(); mysql_bin_log.write(&qinfo); } send_ok(thd,(ulong) deleted); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 94ae1743fd9..4ab0cfa20c1 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -135,14 +135,20 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || (table->sort.found_records = filesort(thd, table, sortorder, length, - (SQL_SELECT *) 0, HA_POS_ERROR, + select, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) { delete select; free_underlaid_joins(thd, &thd->lex.select_lex); - DBUG_RETURN(-1); // This will force out message + DBUG_RETURN(-1); // This will force out message } + /* + Filesort has already found and selected the rows we want to delete, + so we don't need the where clause + */ + delete select; + select= 0; } init_read_record(&info,thd,table,select,1,1); @@ -205,6 +211,8 @@ cleanup: mysql_update_log.write(thd,thd->query, thd->query_length); if (mysql_bin_log.is_open()) { + if (error <= 0) + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, log_delayed); if (mysql_bin_log.write(&qinfo) && transactional_table) @@ -251,7 +259,7 @@ extern "C" int refposcmp2(void* arg, const void *a,const void *b) multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg) - : delete_tables(dt), thd(thd_arg), deleted(0), + : delete_tables(dt), thd(thd_arg), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0) { @@ -355,6 +363,7 @@ bool multi_delete::send_data(List<Item> &values) continue; table->file->position(table->record[0]); + found++; if (secure_counter < 0) { @@ -430,7 +439,7 @@ int multi_delete::do_deletes(bool from_send_error) if (from_send_error) { - /* Found out table number for 'table_being_deleted' */ + /* Found out table number for 'table_being_deleted*/ for (TABLE_LIST *aux=delete_tables; aux != table_being_deleted; aux=aux->next) @@ -440,6 +449,8 @@ int multi_delete::do_deletes(bool from_send_error) table_being_deleted = delete_tables; do_delete= 0; + if (!found) + DBUG_RETURN(0); for (table_being_deleted=table_being_deleted->next; table_being_deleted ; table_being_deleted=table_being_deleted->next, counter++) @@ -510,6 +521,8 @@ bool multi_delete::send_eof() mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + if (error <= 0) + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, log_delayed); if (mysql_bin_log.write(&qinfo) && !normal_tables) @@ -621,6 +634,7 @@ end: mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, thd->tmp_table); mysql_bin_log.write(&qinfo); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4484cdbe248..46ff9770893 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -380,6 +380,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { + if (error <= 0) + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, log_delayed); if (mysql_bin_log.write(&qinfo) && transactional_table) @@ -645,7 +647,7 @@ public: thd.lex.current_select= 0; /* for my_message_sql */ bzero((char*) &thd.net,sizeof(thd.net)); // Safety - thd.system_thread=1; + thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT; thd.host_or_ip= ""; bzero((char*) &info,sizeof(info)); pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST); @@ -1512,6 +1514,8 @@ bool select_insert::send_eof() mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + if (!error) + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, table->file->has_transactions()); mysql_bin_log.write(&qinfo); @@ -1525,7 +1529,6 @@ bool select_insert::send_eof() ::send_error(thd); DBUG_RETURN(1); } - char buff[160]; if (info.handle_duplicates == DUP_IGNORE) sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0f39ab2663f..0c35e99ed08 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -72,10 +72,11 @@ public: }; static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table, - List<Item> &fields, READ_INFO &read_info); + List<Item> &fields, READ_INFO &read_info, + ulong skip_lines); static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, List<Item> &fields, READ_INFO &read_info, - String &enclosed); + String &enclosed, ulong skip_lines); int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, List<Item> &fields, enum enum_duplicates handle_duplicates, @@ -85,8 +86,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, File file; TABLE *table; int error; - String *field_term=ex->field_term,*escaped=ex->escaped, - *enclosed=ex->enclosed; + String *field_term=ex->field_term,*escaped=ex->escaped; + String *enclosed=ex->enclosed; bool is_fifo=0; #ifndef EMBEDDED_LIBRARY LOAD_FILE_INFO lf_info; @@ -95,6 +96,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* If no current database, use database where table is located */ char *tdb= thd->db ? thd->db : db; bool transactional_table, log_delayed; + ulong skip_lines= ex->skip_lines; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -254,16 +256,18 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; - if (ex->line_term->length() && field_term->length()) + /* Skip lines if there is a line terminator */ + if (ex->line_term->length()) { - // ex->skip_lines needs to be preserved for logging - uint skip_lines = ex->skip_lines; - while (skip_lines--) + /* ex->skip_lines needs to be preserved for logging */ + while (skip_lines > 0) { + skip_lines--; if (read_info.next_line()) break; } } + if (!(error=test(read_info.error))) { uint save_time_stamp=table->time_stamp; @@ -279,9 +283,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->file->deactivate_non_unique_index((ha_rows) 0); table->copy_blobs=1; if (!field_term->length() && !enclosed->length()) - error=read_fixed_length(thd,info,table,fields,read_info); + error=read_fixed_length(thd,info,table,fields,read_info, + skip_lines); else - error=read_sep_field(thd,info,table,fields,read_info,*enclosed); + error=read_sep_field(thd,info,table,fields,read_info,*enclosed, + skip_lines); if (table->file->extra(HA_EXTRA_NO_CACHE)) error=1; /* purecov: inspected */ if (table->file->activate_all_index(thd)) @@ -290,7 +296,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->time_stamp=save_time_stamp; table->next_number_field=0; } - if (file >= 0) my_close(file,MYF(0)); + if (file >= 0) + my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ table->copy_blobs=0; thd->count_cuted_fields= CHECK_FIELD_IGNORE; @@ -395,7 +402,7 @@ err: static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, - READ_INFO &read_info) + READ_INFO &read_info, ulong skip_lines) { List_iterator_fast<Item> it(fields); Item_field *sql_field; @@ -415,6 +422,17 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, my_error(ER_SERVER_SHUTDOWN,MYF(0)); DBUG_RETURN(1); } + if (skip_lines) + { + /* + We could implement this with a simple seek if: + - We are not using DATA INFILE LOCAL + - escape character is "" + - line starting prefix is "" + */ + skip_lines--; + continue; + } it.rewind(); byte *pos=read_info.row_start; #ifdef HAVE_purify @@ -485,7 +503,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, List<Item> &fields, READ_INFO &read_info, - String &enclosed) + String &enclosed, ulong skip_lines) { List_iterator_fast<Item> it(fields); Item_field *sql_field; @@ -536,6 +554,12 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, } if (read_info.error) break; + if (skip_lines) + { + if (!--skip_lines) + thd->cuted_fields= 0L; // Reset warnings + continue; + } if (sql_field) { // Last record if (sql_field == (Item_field*) fields.head()) @@ -875,7 +899,18 @@ found_eof: } /* -** One can't use fixed length with multi-byte charset ** + Read a row with fixed length. + + NOTES + The row may not be fixed size on disk if there are escape + characters in the file. + + IMPLEMENTATION NOTE + One can't use fixed length with multi-byte charset ** + + RETURN + 0 ok + 1 error */ int READ_INFO::read_fixed_length() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 92a21b5982d..6e6ec025a1f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -333,8 +333,7 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } } - else - send_ok(thd); + send_ok(thd); thd->password= test(passwd_len); // remember for error messages /* Ready to handle queries */ DBUG_RETURN(0); @@ -1815,9 +1814,18 @@ mysql_execute_command(THD *thd) } } } - if (&lex->select_lex != lex->all_selects_list && - lex->unit.create_total_list(thd, lex, &tables, 0)) - DBUG_VOID_RETURN; + if (&lex->select_lex != lex->all_selects_list) + { + byte *save= lex->select_lex.table_list.first; + if (lex->sql_command == SQLCOM_CREATE_TABLE) + { + /* Skip first table, which is the table we are creating */ + lex->select_lex.table_list.first= (byte*) (((TABLE_LIST *) save)->next); + } + if (lex->unit.create_total_list(thd, lex, &tables, 0)) + DBUG_VOID_RETURN; + lex->select_lex.table_list.first= save; + } /* When option readonly is set deny operations which change tables. @@ -2595,7 +2603,6 @@ mysql_execute_command(THD *thd) case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { - /* Check that we have modify privileges for the first table and select privileges for the rest @@ -2616,6 +2623,11 @@ mysql_execute_command(THD *thd) goto error; } #endif + + /* Fix lock for first table */ + if (tables->lock_type == TL_WRITE_DELAYED) + tables->lock_type == TL_WRITE; + /* Don't unlock tables until command is written to binary log */ select_lex->options|= SELECT_NO_UNLOCK; @@ -3247,6 +3259,7 @@ mysql_execute_command(THD *thd) mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } @@ -3267,6 +3280,7 @@ mysql_execute_command(THD *thd) mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } @@ -3780,7 +3794,9 @@ mysql_init_query(THD *thd) thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; thd->sent_row_count= thd->examined_row_count= 0; thd->is_fatal_error= thd->rand_used= 0; - thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS; + thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | + SERVER_QUERY_NO_INDEX_USED | + SERVER_QUERY_NO_GOOD_INDEX_USED); thd->tmp_table_used= 0; if (opt_bin_log) reset_dynamic(&thd->user_var_events); @@ -3987,7 +4003,12 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, if (default_value) { - if (default_value->type() == Item::NULL_ITEM) + if (type == FIELD_TYPE_TIMESTAMP) + { + net_printf(&thd->net, ER_INVALID_DEFAULT, field_name); + DBUG_RETURN(1); + } + else if (default_value->type() == Item::NULL_ITEM) { default_value=0; if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 19b4d299e59..3ab6621f35b 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -82,6 +82,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0bf493ee953..b2224d3ca9d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1119,6 +1119,21 @@ JOIN::exec() if (select_options & SELECT_DESCRIBE) { + /* + Check if we managed to optimize ORDER BY away and don't use temporary + table to resolve ORDER BY: in that case, we only may need to do + filesort for GROUP BY. + */ + if (!order && !no_order && (!skip_sort_order || !need_tmp)) + { + /* + Reset 'order' to 'group_list' and reinit variables describing + 'order' + */ + order= group_list; + simple_order= simple_group; + skip_sort_order= 0; + } if (!order && !no_order) order=group_list; if (order && @@ -1859,7 +1874,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, } while (keyuse->table == table && keyuse->key == key); if (eq_part.is_prefix(table->key_info[key].key_parts) && - (table->key_info[key].flags & HA_NOSAME) && + ((table->key_info[key].flags & (HA_NOSAME | HA_END_SPACE_KEY)) == + HA_NOSAME) && !table->fulltext_searched) { if (const_ref == eq_part) @@ -2343,10 +2359,6 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) } } } - /* Mark that we can optimize LEFT JOIN */ - if (key_field->val->type() == Item::NULL_ITEM && - !key_field->field->real_maybe_null()) - key_field->field->table->reginfo.not_exists_optimize=1; } @@ -2445,15 +2457,28 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, SELECT_LEX *select_lex) { uint and_level,i,found_eq_constant; - KEY_FIELD *key_fields,*end; + KEY_FIELD *key_fields, *end, *field; if (!(key_fields=(KEY_FIELD*) thd->alloc(sizeof(key_fields[0])* (thd->lex.current_select->cond_count+1)*2))) return TRUE; /* purecov: inspected */ - and_level=0; end=key_fields; + and_level= 0; + field= end= key_fields; + if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64)) + return TRUE; if (cond) + { add_key_fields(join_tab,&end,&and_level,cond,normal_tables); + for (; field != end ; field++) + { + add_key_part(keyuse,field); + /* Mark that we can optimize LEFT JOIN */ + if (field->val->type() == Item::NULL_ITEM && + !field->field->real_maybe_null()) + field->field->table->reginfo.not_exists_optimize=1; + } + } for (i=0 ; i < tables ; i++) { if (join_tab[i].on_expr) @@ -2465,7 +2490,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64)) return TRUE; /* fill keyuse with found key parts */ - for (KEY_FIELD *field=key_fields ; field != end ; field++) + for ( ; field != end ; field++) add_key_part(keyuse,field); if (select_lex->ftfunc_list->elements) @@ -2715,7 +2740,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, !found_ref_or_null) { /* use eq key */ max_key_part= (uint) ~0; - if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) + if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY | + HA_END_SPACE_KEY)) == HA_NOSAME) { tmp=prev_record_reads(join,found_ref); records=1.0; @@ -3228,9 +3254,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, return 0; if (j->type == JT_CONST) j->table->const_table= 1; - else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) - != HA_NOSAME) || keyparts != keyinfo->key_parts || - null_ref_key) + else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY | + HA_END_SPACE_KEY)) != HA_NOSAME) || + keyparts != keyinfo->key_parts || null_ref_key) { /* Must read with repeat */ j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; @@ -4051,6 +4077,8 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, } result->send_eof(); // Should be safe } + /* Update results for FOUND_ROWS */ + join->thd->limit_found_rows= join->thd->examined_row_count= 0; DBUG_RETURN(0); } @@ -6764,7 +6792,7 @@ part_of_refkey(TABLE *table,Field *field) for (uint part=0 ; part < ref_parts ; part++,key_part++) if (field->eq(key_part->field) && - !(key_part->key_part_flag & HA_PART_KEY)) + !(key_part->key_part_flag & HA_PART_KEY_SEG)) return table->reginfo.join_tab->ref.items[part]; } return (Item*) 0; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 855b5d1e97e..741c8e3a1f5 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -384,11 +384,23 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, #ifdef USE_SYMDIR char *ext; 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; *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)) + continue; + } else #endif { - if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) || + if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) || (wild && wild_compare(file->name,wild,0))) continue; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3a579986b6e..4b94559b5eb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -260,6 +260,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, tmp_table_deleted && !some_tables_deleted); mysql_bin_log.write(&qinfo); @@ -310,10 +311,10 @@ static int sort_keys(KEY *a, KEY *b) { if (!(b->flags & HA_NOSAME)) return -1; - if ((a->flags ^ b->flags) & HA_NULL_PART_KEY) + if ((a->flags ^ b->flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) { /* Sort NOT NULL keys before other keys */ - return (a->flags & HA_NULL_PART_KEY) ? 1 : -1; + return (a->flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; } if (a->name == primary_key_name) return -1; @@ -993,6 +994,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, mysql_update_log.write(thd,thd->query, thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, test(create_info->options & HA_LEX_CREATE_TMP_TABLE)); @@ -2082,6 +2084,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } @@ -2465,6 +2468,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } @@ -2596,6 +2600,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 95dff107350..9f54b838e41 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -352,6 +352,8 @@ int mysql_update(THD *thd, mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + if (error <= 0) + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, log_delayed); if (mysql_bin_log.write(&qinfo) && transactional_table) @@ -473,7 +475,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, :all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), - do_update(1), trans_safe(0) + do_update(1), trans_safe(0), transactional_tables(1) {} @@ -577,6 +579,26 @@ int multi_update::prepare(List<Item> ¬_used_values, for (i=0 ; i < table_count ; i++) set_if_bigger(max_fields, fields_for_table[i]->elements); copy_field= new Copy_field[max_fields]; + + /* + Mark all copies of tables that are updates to ensure that + init_read_record() will not try to enable a cache on them + + The problem is that for queries like + + UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a; + + the row buffer may contain things that doesn't match what is on disk + which will cause an error when reading a row. + (This issue is mostly relevent for MyISAM tables) + */ + for (table_ref= all_tables; table_ref; table_ref=table_ref->next) + { + TABLE *table=table_ref->table; + if (!(tables_to_update & table->map) && + check_dup(table_ref->db, table_ref->real_name, update_tables)) + table->no_cache= 1; // Disable row cache + } DBUG_RETURN(thd->is_fatal_error != 0); } @@ -718,7 +740,7 @@ multi_update::~multi_update() { TABLE_LIST *table; for (table= update_tables ; table; table= table->next) - table->table->no_keyread=0; + table->table->no_keyread= table->table->no_cache= 0; if (tmp_tables) { @@ -853,8 +875,11 @@ int multi_update::do_updates(bool from_send_error) ha_rows org_updated; TABLE *table; DBUG_ENTER("do_updates"); + - do_update= 0; // Don't retry this function + do_update= 0; // Don't retry this function + if (!found) + DBUG_RETURN(0); for (cur_table= update_tables; cur_table ; cur_table= cur_table->next) { table = cur_table->table; @@ -981,6 +1006,8 @@ bool multi_update::send_eof() mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { + if (local_error <= 0) + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, log_delayed); if (mysql_bin_log.write(&qinfo) && trans_safe) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3e013d89992..ef71036206a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5491,6 +5491,7 @@ order_or_limit: union_option: /* empty */ {} + | DISTINCT {} | ALL {Select->master_unit()->union_option|= UNION_ALL;}; singlerow_subselect: diff --git a/sql/table.cc b/sql/table.cc index e87cafd5275..fc1b8a13497 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -507,14 +507,17 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME)) { /* - If the UNIQUE key don't have NULL columns, declare this as - a primary key. + If the UNIQUE key doesn't have NULL columns and is not a part key + declare this as a primary key. */ primary_key=key; for (i=0 ; i < keyinfo->key_parts ;i++) { - if (!key_part[i].fieldnr || - outparam->field[key_part[i].fieldnr-1]->null_ptr) + uint fieldnr= key_part[i].fieldnr; + if (!fieldnr || + outparam->field[fieldnr-1]->null_ptr || + outparam->field[fieldnr-1]->key_length() != + key_part[i].length) { primary_key=MAX_KEY; // Can't be used break; @@ -554,6 +557,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, keyinfo->extra_length+=HA_KEY_BLOB_LENGTH; key_part->store_length+=HA_KEY_BLOB_LENGTH; keyinfo->key_length+= HA_KEY_BLOB_LENGTH; + /* + Mark that there may be many matching values for one key + combination ('a', 'a ', 'a '...) + */ + if (!(field->flags & BINARY_FLAG)) + keyinfo->flags|= HA_END_SPACE_KEY; } if (i == 0 && key != primary_key) field->flags |= @@ -591,7 +600,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, } if (field->key_length() != key_part->length) { - key_part->key_part_flag|= HA_PART_KEY; + key_part->key_part_flag|= HA_PART_KEY_SEG; if (!(field->flags & BLOB_FLAG)) { // Create a new field field=key_part->field=field->new_field(&outparam->mem_root, @@ -605,7 +614,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, as we need to test for NULL = NULL. */ if (field->real_maybe_null()) - key_part->key_part_flag|= HA_PART_KEY; + key_part->key_part_flag|= HA_PART_KEY_SEG; } else { // Error: shorten key @@ -1225,14 +1234,16 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res) char *get_field(MEM_ROOT *mem, Field *field) { - char buff[MAX_FIELD_WIDTH]; + char buff[MAX_FIELD_WIDTH] *to; String str(buff,sizeof(buff),&my_charset_bin); uint length; field->val_str(&str,&str); - if (!(length= str.length())) + if (!length || !(to= (char*) alloc_root(mem,length+1))) return NullS; - return strmake_root(mem, str.ptr(), length); + memcpy(to,str.ptr(),(uint) length); + to[length]=0; + return to; } diff --git a/sql/table.h b/sql/table.h index 4dcd24b2aff..00fe803cde2 100644 --- a/sql/table.h +++ b/sql/table.h @@ -116,7 +116,7 @@ struct st_table { my_bool fulltext_searched; my_bool crashed; my_bool is_view; - my_bool no_keyread; + my_bool no_keyread, no_cache; my_bool clear_query_id; /* To reset query_id for tables and cols */ my_bool auto_increment_field_not_null; Field *next_number_field, /* Set if next_number is activated */ diff --git a/sql/time.cc b/sql/time.cc index fe22b80d59d..9a18a150c50 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -124,6 +124,8 @@ long my_gmt_sec(TIME *t, long *my_timezone) tmp-=t->minute*60 + t->second; // Move to previous hour } *my_timezone= current_timezone; + if (tmp < 0 && t->year <= 1900+YY_PART_YEAR) + tmp= 0; return (long) tmp; } /* my_gmt_sec */ @@ -174,42 +176,72 @@ uint calc_days_in_year(uint year) 366 : 365; } -/* Calculate week. If 'with_year' is not set, then return a week 0-53, where - 0 means that it's the last week of the previous year. - If 'with_year' is set then the week will always be in the range 1-53 and - the year out parameter will contain the year for the week */ -uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week, - uint *year) +/* + The bits in week_format has the following meaning: + WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week + If set Monday is first day of week + WEEK_YEAR (1) If not set Week is in range 0-53 + + Week 0 is returned for the the last week of the previous year (for + a date at start of january) In this case one can get 53 for the + first week of next year. This flag ensures that the week is + relevant for the given year. Note that this flag is only + releveant if WEEK_JANUARY is not set. + + If set Week is in range 1-53. + + In this case one may get week 53 for a date in January (when + the week is that last week of previous year) and week 1 for a + date in December. + + WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according + to ISO 8601:1988 + If set The week that contains the first + 'first-day-of-week' is week 1. + + ISO 8601:1988 means that if the week containing January 1 has + four or more days in the new year, then it is week 1; + Otherwise it is the last week of the previous year, and the + next week is week 1. +*/ + +uint calc_week(TIME *l_time, uint week_behaviour, uint *year) { uint days; ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day); ulong first_daynr=calc_daynr(l_time->year,1,1); - uint weekday=calc_weekday(first_daynr,sunday_first_day_of_week); + bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST); + bool week_year= test(week_behaviour & WEEK_YEAR); + bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY); + + uint weekday=calc_weekday(first_daynr, !monday_first); *year=l_time->year; - if (l_time->month == 1 && l_time->day <= 7-weekday && - ((!sunday_first_day_of_week && weekday >= 4) || - (sunday_first_day_of_week && weekday != 0))) + + if (l_time->month == 1 && l_time->day <= 7-weekday) { - /* Last week of the previous year */ - if (!with_year) + if (!week_year && + (first_weekday && weekday != 0 || + !first_weekday && weekday >= 4)) return 0; - with_year=0; // Don't check the week again + week_year= 1; (*year)--; first_daynr-= (days=calc_days_in_year(*year)); weekday= (weekday + 53*7- days) % 7; } - if ((sunday_first_day_of_week && weekday != 0) || - (!sunday_first_day_of_week && weekday >= 4)) + + if ((first_weekday && weekday != 0) || + (!first_weekday && weekday >= 4)) days= daynr - (first_daynr+ (7-weekday)); else days= daynr - (first_daynr - weekday); - if (with_year && days >= 52*7) + + if (week_year && days >= 52*7) { - /* Check if we are on the first week of the next year (or week 53) */ weekday= (weekday + calc_days_in_year(*year)) % 7; - if (weekday < 4) - { // We are at first week on next year + if (!first_weekday && weekday < 4 || + first_weekday && weekday == 0) + { (*year)++; return 1; } @@ -605,7 +637,7 @@ time_t str_to_timestamp(const char *str,uint length) if (str_to_TIME(str,length,&l_time,0) <= TIMESTAMP_DATETIME_ERROR) return(0); - if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) + if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1) { current_thd->cuted_fields++; return(0); diff --git a/sql/uniques.cc b/sql/uniques.cc index f289fd11f5b..d060965aa66 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -37,14 +37,20 @@ int unique_write_to_file(gptr key, element_count count, Unique *unique) { + /* + Use unique->size (size of element stored in the tree) and not + unique->tree.size_of_element. The latter is different from unique->size + when tree implementation chooses to store pointer to key in TREE_ELEMENT + (instead of storing the element itself there) + */ return my_b_write(&unique->file, (byte*) key, - unique->tree.size_of_element) ? 1 : 0; + unique->size) ? 1 : 0; } int unique_write_to_ptrs(gptr key, element_count count, Unique *unique) { - memcpy(unique->record_pointers, key, unique->tree.size_of_element); - unique->record_pointers+=unique->tree.size_of_element; + memcpy(unique->record_pointers, key, unique->size); + unique->record_pointers+=unique->size; return 0; } @@ -132,8 +138,8 @@ bool Unique::get(TABLE *table) bzero((char*) &sort_param,sizeof(sort_param)); sort_param.max_rows= elements; sort_param.sort_form=table; - sort_param.rec_length= sort_param.sort_length=sort_param.ref_length= - tree.size_of_element; + sort_param.rec_length= sort_param.sort_length= sort_param.ref_length= + size; sort_param.keys= max_in_memory_size / sort_param.sort_length; sort_param.not_killable=1; diff --git a/strings/strto.c b/strings/strto.c index 0c215ff270c..6f12656cb20 100644 --- a/strings/strto.c +++ b/strings/strto.c @@ -35,8 +35,6 @@ it can be compiled with the UNSIGNED and/or LONGLONG flag set */ -#define strtoll glob_strtoll /* Fix for True64 */ - #include <my_global.h> #include "m_string.h" #include "m_ctype.h" diff --git a/strings/strtoll.c b/strings/strtoll.c index 8d0ba21d576..b0b4ef328fc 100644 --- a/strings/strtoll.c +++ b/strings/strtoll.c @@ -16,8 +16,9 @@ /* This is defines strtoll() if neaded */ +#define strtoll glob_strtoll /* Fix for True64 */ + #include <my_global.h> -#include <m_string.h> #if !defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG) #define USE_LONGLONG #include "strto.c" diff --git a/strings/strtoull.c b/strings/strtoull.c index 25201e546ce..f4f3ce19bf7 100644 --- a/strings/strtoull.c +++ b/strings/strtoull.c @@ -17,7 +17,6 @@ /* This is defines strtoull() */ #include <my_global.h> -#include <m_string.h> #if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG) #define USE_UNSIGNED #define USE_LONGLONG diff --git a/support-files/MacOSX/MySQL b/support-files/MacOSX/MySQL index dfba5f8f982..f6579700384 100755 --- a/support-files/MacOSX/MySQL +++ b/support-files/MacOSX/MySQL @@ -11,6 +11,13 @@ # Written by Lenz Grimmer <lenz@mysql.com> # +# Suppress the annoying "$1: unbound variable" error when no option +# was given +if [ -z $1 ] ; then + echo "Usage: $0 [start|stop|restart] " + exit 1 +fi + # Source the common setup functions for startup scripts test -r /etc/rc.common || exit 1 . /etc/rc.common diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 30ee4ab545f..5911ecd942b 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -145,7 +145,7 @@ case "$mode" in then # Give extra arguments to mysqld with the my.cnf file. This script may # be overwritten at next upgrade. - $bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file & + $bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file >/dev/null 2>&1 & # Make lock for RedHat / SuSE if test -w /var/lock/subsys then diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 0eb642650d7..5a9fbf64b1c 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -260,7 +260,7 @@ export PATH # If we want to compile with RAID using gcc 3, we need to use # gcc instead of g++ to avoid linking problems (RAID code is written in C++) -if gcc -v 2>&1 | grep 'version 3' > /dev/null 2>&1 +test -z $CXX && test -z $CC && if gcc -v 2>&1 | grep 'gcc version 3' > /dev/null 2>&1 then export CXX="gcc" fi @@ -443,11 +443,12 @@ fi [ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; %files server -%defattr(755 root, root) +%defattr(-,root,root,0755) -%doc %attr(644, root, root) COPYING README -%doc %attr(644, root, root) Docs/manual.{html,ps,texi,txt} Docs/manual_toc.html -%doc %attr(644, root, root) support-files/my-*.cnf +%doc COPYING README +%doc Docs/manual.{html,ps,texi,txt} +%doc Docs/manual_toc.html +%doc support-files/my-*.cnf %doc %attr(644, root, root) %{_infodir}/mysql.info* @@ -500,6 +501,7 @@ fi %attr(755, root, root) %{_datadir}/mysql/ %files client +%defattr(-, root, root, 0755) %attr(755, root, root) %{_bindir}/msql2mysql %attr(755, root, root) %{_bindir}/mysql %attr(755, root, root) %{_bindir}/mysql_find_rows @@ -527,7 +529,7 @@ fi /sbin/ldconfig %files devel -%defattr(644 root, root) +%defattr(-, root, root, 0755) %attr(755, root, root) %{_bindir}/comp_err %attr(755, root, root) %{_bindir}/mysql_config %dir %attr(755, root, root) %{_includedir}/mysql @@ -548,11 +550,12 @@ fi %{_libdir}/mysql/libvio.a %files shared -%defattr(755 root, root) +%defattr(-, root, root, 0755) # Shared libraries (omit for architectures that don't support them) %{_libdir}/*.so* %files bench +%defattr(-, root, root, 0755) %attr(-, root, root) %{_datadir}/sql-bench %attr(-, root, root) %{_datadir}/mysql-test %attr(755, root, root) %{_bindir}/mysqlmanager @@ -560,15 +563,25 @@ fi %attr(755, root, root) %{_bindir}/mysqlmanagerc %files Max +%defattr(-, root, root, 0755) %attr(755, root, root) %{_sbindir}/mysqld-max %attr(644, root, root) %{_libdir}/mysql/mysqld-max.sym %files embedded +%defattr(-, root, root, 0755) %attr(644, root, root) %{_libdir}/mysql/libmysqld.a # The spec file changelog only includes changes made to the spec file # itself %changelog +* Fri Dec 13 2003 Lenz Grimmer <lenz@mysql.com> + +- fixed file permissions (BUG 1672) + +* Thu Dec 11 2003 Lenz Grimmer <lenz@mysql.com> + +- made testing for gcc3 a bit more robust + * Fri Dec 05 2003 Lenz Grimmer <lenz@mysql.com> - added missing file mysql_create_system_tables to the server subpackage |