diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index 0cd782c023e..346c1958979 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -12,6 +12,7 @@ $opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_su $opt_tmp=$opt_version_suffix=""; $opt_bundled_zlib=$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_one_error=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_archive=$opt_with_cluster=$opt_with_csv=$opt_with_example=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=$opt_readline=0; $opt_skip_embedded_test=$opt_skip_ps_test=$opt_innodb=$opt_bdb=$opt_raid=$opt_libwrap=$opt_clearlogs=$opt_with_federated=0; +$global_step=""; GetOptions( "bdb", @@ -179,7 +180,8 @@ info("Compiling MySQL$opt_version_suffix at $host$opt_suffix, stage: $opt_stage\ info("LD_LIBRARY_PATH is $ENV{LD_LIBRARY_PATH}"); info("PATH is $ENV{PATH}"); -log_timestamp(); +$global_step= "Check MD5, shutdown"; +log_timestamp("START"); $md5_result= safe_system("perl $ENV{HOME}/my_md5sum -c ${opt_distribution}.md5"); @@ -207,9 +209,10 @@ kill_all("mysqlmanager"); kill_all("$pwd/host/mysql"); kill_all("$pwd/host/test"); +$global_step= "directory cleanup"; if ($opt_stage == 0) { - log_timestamp(); + log_timestamp("START"); print "$host: Removing old distribution\n" if ($opt_debug); if (!$opt_use_old_distribution) { @@ -255,10 +258,11 @@ safe_cd("$pwd/$host/$ver"); # # Configure the sources # +$global_step= "configure"; if ($opt_stage <= 1) { # Fix files if this is in another timezone than the build host - log_timestamp(); + log_timestamp("START"); unlink("config.cache"); unlink("bdb/build_unix/config.cache"); unlink("innobase/config.cache"); @@ -312,29 +316,33 @@ if ($opt_stage <= 1) { safe_system("cp -r $pwd/$host/include-mysql/* $pwd/$host/$ver/include"); } + log_timestamp("DONE "); } # # Compile the binaries # +$global_step= "compile + link"; if ($opt_stage <= 2) { my ($command); - log_timestamp(); + log_timestamp("START"); unlink($opt_distribution) if ($opt_delete && !$opt_use_old_distribution); $command=$make; $command.= " $opt_make_options" if (defined($opt_make_options) && $opt_make_options ne ""); safe_system($command); print LOG "Do-compile: Build successful\n"; + log_timestamp("DONE "); } # # Create the binary distribution # +$global_step= "pack binary distribution"; if ($opt_stage <= 3) { + log_timestamp("START"); my $flags= ""; - log_timestamp(); log_system("rm -fr mysql-{3,4,5}* $pwd/$host/mysql*.t*gz"); # No need to add the debug symbols, if the binaries are not stripped (saves space) unless ($opt_with_debug || $opt_no_strip) @@ -355,6 +363,7 @@ if ($opt_stage <= 3) safe_system("cp client/mysqladmin $pwd/$host/bin"); } safe_system("$make clean") if ($opt_with_small_disk); + log_timestamp("DONE "); } $tar_file=<$pwd/$host/mysql*.t*gz>; @@ -369,11 +378,13 @@ system("cd $pwd/$host; perl $ENV{HOME}/my_md5sum $tar_file_lite > ${tar_file_lit # Unpack the binary distribution # if ($opt_stage <= 4 && !$opt_no_test) +$global_step= "extract binary distribution"; { - log_timestamp(); + log_timestamp("START"); rm_all(<$pwd/$host/test/*>); safe_cd("$pwd/$host/test"); safe_system("gunzip < $tar_file | $tar xf -"); + log_timestamp("DONE "); } $tar_file =~ /(mysql[^\/]*)\.(tar\.gz|tgz)/; @@ -386,30 +397,36 @@ $ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" . # Run the test suite # if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest) +$global_step= "tests in default mode"; { + log_timestamp("START"); my $flags= ""; $flags.= " --with-ndbcluster" if ($opt_with_cluster); $flags.= " --force" if (!$opt_one_error); - log_timestamp(); info("Running test suite"); system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir); safe_cd("${test_dir}/mysql-test"); check_system("./mysql-test-run $flags --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --ndbcluster_port=$ndbcluster_port --manager-port=$manager_port --no-manager --sleep=10", "were successful"); + log_timestamp("DONE "); + $global_step= "tests using prepared statements"; unless ($opt_skip_ps_test) { - log_timestamp(); + log_timestamp("START"); info("Running test suite using prepared statements"); check_system("./mysql-test-run $flags --ps-protocol --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --ndbcluster_port=$ndbcluster_port --manager-port=$manager_port --no-manager --sleep=10", "were successful"); + log_timestamp("DONE "); } + $global_step= "tests using embedded server"; unless ($opt_skip_embedded_test) { - log_timestamp(); + log_timestamp("START"); info("Running embedded server test suite"); # Embedded server and NDB don't jive $flags=~ s/ --with-ndbcluster//; check_system("./mysql-test-run $flags --embedded-server --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "were successful"); + log_timestamp("DONE "); } # 'mysql-test-run' writes its own final message for log evaluation. } @@ -441,10 +458,11 @@ if (!$opt_no_test && !$opt_no_benchmark) # # Compile and install the required Perl modules # +$global_step= "installing Perl modules"; if ($opt_stage <= 7 && $opt_perl_files && !$opt_no_perl && !$opt_no_test && !$opt_no_benchmark) { - log_timestamp(); + log_timestamp("START"); safe_cd($test_dir); rm_all("perl"); safe_system("mkdir perl"); @@ -473,25 +491,29 @@ if ($opt_stage <= 7 && $opt_perl_files && !$opt_no_perl && !$opt_no_test && safe_system($opt_static_perl ? "perl Makefile.PL -static $options" : "perl Makefile.PL $options"); safe_system("$make ; $sur $make install"); } + log_timestamp("DONE "); } # # Run crash-me test # +$global_step= "crash-me checks"; if ($opt_stage <= 8 && !$opt_no_test && !$opt_no_crash_me) { - log_timestamp(); + log_timestamp("START"); safe_cd("$test_dir/sql-bench"); log_system("rm -f limits/mysql.cfg"); safe_system("perl ./crash-me --force --batch-mode $connect_option"); + log_timestamp("DONE "); } # # Run sql-bench Benchmarks # +$global_step= "benchmarks"; if ($opt_stage <= 9 && !$opt_no_test && !$opt_no_benchmark) { - log_timestamp(); + log_timestamp("START"); safe_cd("$test_dir/sql-bench"); log_system("rm -f output/*"); $tmp= $opt_fast_benchmark ? "--fast --user root --small-test" : ""; @@ -506,6 +528,7 @@ if ($opt_stage <= 9 && !$opt_no_test && !$opt_no_benchmark) { check_system("perl ./run-all-tests --log --suffix=\"_bdb\" --die-on-errors $connect_option $tmp --create-options=\"type=bdb\"","RUN-mysql"); } + log_timestamp("DONE "); } rm_all($bench_tmpdir); @@ -690,7 +713,7 @@ sub abort my($mail_header_file); print LOG "\n$message\n"; print "$host: $message\n" if ($opt_debug); - print LOG "Aborting\n"; + log_timestamp("ABORT"); close LOG; if ($opt_user) @@ -866,6 +889,7 @@ sub kill_all if (!open(PS, "$pscmd|")) { print "Warning: Can't run $pscmd: $!\n"; + log_timestamp("ABORT"); exit; } @@ -904,8 +928,10 @@ sub killpid # sub log_timestamp { + my ($message) = @_; my @ta=localtime(time()); - print LOG sprintf("%4d-%02d-%02d %02d:%02d:%02d\n", - $ta[5]+1900, $ta[4]+1, $ta[3], $ta[2], $ta[1], $ta[0]); + print LOG sprintf("%4d-%02d-%02d %02d:%02d:%02d %s %s\n", + $ta[5]+1900, $ta[4]+1, $ta[3], $ta[2], $ta[1], $ta[0], + $message, $global_step); } diff --git a/client/mysqldump.c b/client/mysqldump.c index 7d357b25541..46337c99732 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -875,8 +875,8 @@ static int dbConnect(char *host, char *user,char *passwd) cannot reconnect. */ sock->reconnect= 0; - sprintf(buff, "/*!40100 SET @@SQL_MODE='%s' */", - compatible_mode_normal_str); + my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */", + compatible_mode_normal_str); if (mysql_query_with_error_report(sock, 0, buff)) { mysql_close(sock); @@ -1111,8 +1111,9 @@ static uint getTableStructure(char *table, char* db) if (verbose) fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); - sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", - (opt_quoted || opt_keywords)); + my_snprintf(insert_pat, sizeof(insert_pat), + "SET OPTION SQL_QUOTE_SHOW_CREATE=%d", + (opt_quoted || opt_keywords)); if (!create_options) strmov(strend(insert_pat), "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */"); @@ -1131,7 +1132,7 @@ static uint getTableStructure(char *table, char* db) char buff[20+FN_REFLEN]; MYSQL_FIELD *field; - sprintf(buff,"show create table %s", result_table); + my_snprintf(buff, sizeof(buff), "show create table %s", result_table); if (mysql_query_with_error_report(sock, 0, buff)) { safe_exit(EX_MYSQLERR); @@ -1177,7 +1178,8 @@ static uint getTableStructure(char *table, char* db) check_io(sql_file); mysql_free_result(tableRes); } - sprintf(insert_pat,"show fields from %s", result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "show fields from %s", + result_table); if (mysql_query_with_error_report(sock, &tableRes, insert_pat)) { if (path) @@ -1187,11 +1189,12 @@ static uint getTableStructure(char *table, char* db) } if (cFlag) - sprintf(insert_pat, "INSERT %sINTO %s (", delayed, opt_quoted_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s (", + delayed, opt_quoted_table); else { - sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, - opt_quoted_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s VALUES ", + delayed, opt_quoted_table); if (!extended_insert) strcat(insert_pat,"("); } @@ -1218,7 +1221,8 @@ static uint getTableStructure(char *table, char* db) "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n", my_progname, mysql_error(sock)); - sprintf(insert_pat,"show fields from %s", result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "show fields from %s", + result_table); if (mysql_query_with_error_report(sock, &tableRes, insert_pat)) { safe_exit(EX_MYSQLERR); @@ -1253,10 +1257,12 @@ static uint getTableStructure(char *table, char* db) check_io(sql_file); } if (cFlag) - sprintf(insert_pat, "INSERT %sINTO %s (", delayed, result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s (", + delayed, result_table); else { - sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s VALUES ", + delayed, result_table); if (!extended_insert) strcat(insert_pat,"("); } @@ -1313,7 +1319,7 @@ static uint getTableStructure(char *table, char* db) /* Make an sql-file, if path was given iow. option -T was given */ char buff[20+FN_REFLEN]; uint keynr,primary_key; - sprintf(buff,"show keys from %s", result_table); + my_snprintf(buff, sizeof(buff), "show keys from %s", result_table); if (mysql_query_with_error_report(sock, &tableRes, buff)) { if (mysql_errno(sock) == ER_WRONG_OBJECT) @@ -1391,8 +1397,12 @@ static uint getTableStructure(char *table, char* db) if (create_options) { char show_name_buff[FN_REFLEN]; - sprintf(buff,"show table status like %s", - quote_for_like(table, show_name_buff)); + + /* Check memory for quote_for_like() */ + DBUG_ASSERT(2*sizeof(table) < sizeof(show_name_buff)); + my_snprintf(buff, sizeof(buff), "show table status like %s", + quote_for_like(table, show_name_buff)); + if (mysql_query_with_error_report(sock, &tableRes, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) @@ -1553,8 +1563,9 @@ static void dumpTable(uint numFields, char *table) my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if filename wasn't deleted */ to_unix_path(filename); - sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", - filename); + my_snprintf(query, QUERY_LENGTH, + "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", + filename); end= strend(query); if (fields_terminated || enclosed || opt_enclosed || escaped) @@ -1566,7 +1577,7 @@ static void dumpTable(uint numFields, char *table) end= add_load_option(end, lines_terminated, " LINES TERMINATED BY"); *end= '\0'; - sprintf(buff," FROM %s", result_table); + my_snprintf(buff, sizeof(buff), " FROM %s", result_table); end= strmov(end,buff); if (where || order_by) { @@ -1594,8 +1605,9 @@ static void dumpTable(uint numFields, char *table) result_table); check_io(md_result_file); } - sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", - result_table); + my_snprintf(query, QUERY_LENGTH, + "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", + result_table); if (where || order_by) { query = alloc_query_str((ulong) (strlen(query) + 1 + @@ -1693,8 +1705,9 @@ static void dumpTable(uint numFields, char *table) int is_blob; if (!(field = mysql_fetch_field(res))) { - sprintf(query,"%s: Not enough fields from table %s! Aborting.\n", - my_progname, result_table); + my_snprintf(query, QUERY_LENGTH, + "%s: Not enough fields from table %s! Aborting.\n", + my_progname, result_table); fputs(query,stderr); error= EX_CONSCHECK; goto err; @@ -1896,12 +1909,13 @@ static void dumpTable(uint numFields, char *table) check_io(md_result_file); if (mysql_errno(sock)) { - sprintf(query,"%s: Error %d: %s when dumping table %s at row: %ld\n", - my_progname, - mysql_errno(sock), - mysql_error(sock), - result_table, - rownr); + my_snprintf(query, QUERY_LENGTH, + "%s: Error %d: %s when dumping table %s at row: %ld\n", + my_progname, + mysql_errno(sock), + mysql_error(sock), + result_table, + rownr); fputs(query,stderr); error= EX_CONSCHECK; goto err; @@ -2045,8 +2059,9 @@ static int init_dumping(char *database) MYSQL_ROW row; MYSQL_RES *dbinfo; - sprintf(qbuf,"SHOW CREATE DATABASE IF NOT EXISTS %s", - qdatabase); + my_snprintf(qbuf, sizeof(qbuf), + "SHOW CREATE DATABASE IF NOT EXISTS %s", + qdatabase); if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) { @@ -2141,6 +2156,7 @@ static int dump_all_tables_in_db(char *database) return 0; } /* dump_all_tables_in_db */ + /* dump structure of views of database @@ -2195,6 +2211,7 @@ static my_bool dump_all_views_in_db(char *database) return 0; } /* dump_all_tables_in_db */ + /* get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual table name from the server for the table name given on the command line. @@ -2211,10 +2228,15 @@ static void get_actual_table_name(const char *old_table_name, { MYSQL_RES *tableRes; MYSQL_ROW row; - char query[ NAME_LEN + 50 ]; + char query[50 + 2*NAME_LEN]; + char show_name_buff[FN_REFLEN]; DBUG_ENTER("get_actual_table_name"); - sprintf( query, "SHOW TABLES LIKE '%s'", old_table_name); + /* Check memory for quote_for_like() */ + DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); + my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", + quote_for_like(old_table_name, show_name_buff)); + if (mysql_query_with_error_report(sock, 0, query)) { safe_exit(EX_MYSQLERR); @@ -2464,8 +2486,10 @@ static const char *check_if_ignore_table(const char *table_name) MYSQL_ROW row; const char *result= 0; - sprintf(buff,"show table status like %s", - quote_for_like(table_name, show_name_buff)); + /* Check memory for quote_for_like() */ + DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); + my_snprintf(buff, sizeof(buff), "show table status like %s", + quote_for_like(table_name, show_name_buff)); if (mysql_query_with_error_report(sock, &res, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) @@ -2523,7 +2547,8 @@ static char *primary_key_fields(const char *table_name) uint result_length = 0; char *result = 0; - sprintf(show_keys_buff, "SHOW KEYS FROM %s", table_name); + my_snprintf(show_keys_buff, sizeof(show_keys_buff), + "SHOW KEYS FROM %s", table_name); if (mysql_query(sock, show_keys_buff) || !(res = mysql_store_result(sock))) { diff --git a/heap/hp_create.c b/heap/hp_create.c index 55b8e1e2a33..8fcf7dde000 100644 --- a/heap/hp_create.c +++ b/heap/hp_create.c @@ -180,6 +180,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, share->keys= keys; share->max_key_length= max_length; share->changed= 0; + share->auto_key= create_info->auto_key; share->auto_key_type= create_info->auto_key_type; share->auto_increment= create_info->auto_increment; /* Must be allocated separately for rename to work */ diff --git a/include/heap.h b/include/heap.h index 51f7b0cfa6a..badec9ce2ef 100644 --- a/include/heap.h +++ b/include/heap.h @@ -181,8 +181,10 @@ typedef struct st_heap_info LIST open_list; } HP_INFO; + typedef struct st_heap_create_info { + uint auto_key; /* keynr [1 - maxkey] for auto key */ uint auto_key_type; ulong max_table_size; ulonglong auto_increment; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 4e970ca034d..92561496544 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -432,10 +432,10 @@ while test $# -gt 0; do TMP=`$ECHO "$1" | $SED -e "s;--valgrind-options=;;"` VALGRIND="$VALGRIND $TMP" ;; - --skip-ndbcluster) + --skip-ndbcluster | --skip-ndb) USE_NDBCLUSTER="" - EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1" - EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT $1" + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-ndbcluster" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-ndbcluster" ;; --skip-*) EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1" diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 893c7cc7039..7fe8e76cb5b 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -861,6 +861,13 @@ user c one two DROP TABLE t1; +create table t1 (f1 varchar(1) not null) default charset utf8; +insert into t1 values (''), (''); +select concat(concat(_latin1'->',f1),_latin1'<-') from t1; +concat(concat(_latin1'->',f1),_latin1'<-') +-><- +-><- +drop table t1; select convert(_koi8r'É' using utf8) < convert(_koi8r'Ê' using utf8); convert(_koi8r'É' using utf8) < convert(_koi8r'Ê' using utf8) 1 diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index bab9b543307..306376b13c3 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -8,7 +8,7 @@ n 3 flush tables with read lock; drop table t2; -ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +ERROR HY000: Can't execute the query because you have a conflicting read lock drop table t2; unlock tables; create database mysqltest; diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 06c1759bf1d..b5ffef1c582 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -469,3 +469,10 @@ group_concat(a) ABW ABW drop table t1; +create table r2 (a int, b int); +insert into r2 values (1,1), (2,2); +select b x, (select group_concat(x) from r2) from r2; +x (select group_concat(x) from r2) +1 1,1 +2 2,2 +drop table r2; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 92c7d46550f..15a650eccfa 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -515,7 +515,7 @@ collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')) coercibility(make_set( latin2_general_ci 4 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 4 +latin2_general_ci 4 select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a ')); collation(trim(_latin2' a ')) coercibility(trim(_latin2' a ')) latin2_general_ci 4 @@ -630,6 +630,15 @@ t1 CREATE TABLE `t1` ( `encode('abcd','ab')` varbinary(4) NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 (a char character set latin2); +insert into t1 values (null); +select charset(a), collation(a), coercibility(a) from t1; +charset(a) collation(a) coercibility(a) +latin2 latin2_general_ci 2 +drop table t1; +select charset(null), collation(null), coercibility(null); +charset(null) collation(null) coercibility(null) +binary binary 5 select SUBSTR('abcdefg',3,2); SUBSTR('abcdefg',3,2) cd diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 821f67536f3..e6c78fdfdd4 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -23,6 +23,7 @@ grant select on `my\_1`.* to mysqltest_4@localhost with grant option; ERROR 42000: 'mysqltest_1'@'localhost' is not allowed to create new users grant select on `my\_1`.* to mysqltest_4@localhost identified by 'mypass' with grant option; +ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysql' show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index e65924bfcbe..dc456e80e63 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -118,9 +118,9 @@ t2 t3 show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t2 MyISAM 9 Fixed 0 0 0 21474836479 1024 0 NULL # # NULL latin1_swedish_ci NULL -t3 MyISAM 9 Fixed 0 0 0 21474836479 1024 0 NULL # # NULL latin1_swedish_ci NULL -v1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view +t2 MyISAM 9 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +t3 MyISAM 9 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view show full columns from t3 like "a%"; Field Type Collation Null Key Default Extra Privileges Comment a int(11) NULL YES MUL NULL select,insert,update,references diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index a04fa75082f..b04cd6fd068 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -307,3 +307,75 @@ day sample not_cancelled 2004-06-07 1 0 NULL 3 1 DROP TABLE user_day; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +4 +14 +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +14 +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +4 1 +14 3 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +14 3 +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 +GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +1 4 +2 2 +2 4 +2 6 +4 4 +4 4 +NULL 14 +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +2 2 +2 4 +2 6 +4 4 +NULL 14 +DROP TABLE t1; diff --git a/mysql-test/r/rpl000005.result b/mysql-test/r/rpl000005.result index 0202e43dcb2..8acfa2cbfac 100644 --- a/mysql-test/r/rpl000005.result +++ b/mysql-test/r/rpl000005.result @@ -4,6 +4,9 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +SHOW VARIABLES LIKE 'relay_log_space_limit'; +Variable_name Value +relay_log_space_limit 0 CREATE TABLE t1 (name varchar(64), age smallint(3)); INSERT INTO t1 SET name='Andy', age=31; INSERT t1 SET name='Jacob', age=2; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index ac370db9ecc..4a9e95fb89e 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -219,3 +219,10 @@ select * from t1; id id_str 1 test1 drop table t1; +create table t1 (a int, b char(255), key(a, b(20))); +insert into t1 values (0, '1'); +update t1 set b = b + 1 where a = 0; +select * from t1; +a b +0 2 +drop table t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index ece710a7a1b..75459bd960b 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1115,8 +1115,8 @@ select * from v1; ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 9 Fixed 0 0 0 21474836479 1024 0 NULL # # NULL latin1_swedish_ci NULL -v1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL View 'test.v1' references invalid table(s) or column(s) or function(s) +t1 MyISAM 9 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL View 'test.v1' references invalid table(s) or column(s) or function(s) drop view v1; drop table t1; create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 35f2b2642be..2c498cd1922 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -694,6 +694,15 @@ SELECT CHARSET('a'); SELECT user, CONCAT('<', user, '>') AS c FROM t1; DROP TABLE t1; +# +# Bug#8785 +# the same problem with the above, but with nested CONCATs +# +create table t1 (f1 varchar(1) not null) default charset utf8; +insert into t1 values (''), (''); +select concat(concat(_latin1'->',f1),_latin1'<-') from t1; +drop table t1; + # # Bug#8385: utf8_general_ci treats Cyrillic letters I and SHORT I as the same # diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index 9ee6b5d76b8..62af9d4932b 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -37,7 +37,7 @@ connection con1; select * from t1; connection con2; flush tables with read lock; ---error 1099; +--error 1223 drop table t2; connection con1; send drop table t2; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index a1fac51371c..694e0223753 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -288,8 +288,16 @@ DROP TABLE t1; # # Bug #6475 # - create table t1 (a char(3), b char(20), primary key (a, b)); insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English'); select group_concat(a) from t1 group by b; drop table t1; + +# +# Bug #8656: Crash with group_concat on alias in outer table +# +create table r2 (a int, b int); +insert into r2 values (1,1), (2,2); +select b x, (select group_concat(x) from r2) from r2; +drop table r2; + diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 2fa6b603155..2041c776423 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -369,6 +369,15 @@ select show create table t1; drop table t1; +# +# Bug#9129 +# +create table t1 (a char character set latin2); +insert into t1 values (null); +select charset(a), collation(a), coercibility(a) from t1; +drop table t1; +select charset(null), collation(null), coercibility(null); + # # test for SUBSTR # diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 3b1200f8a6e..58f91fddcc2 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -36,6 +36,7 @@ set @@sql_mode='NO_AUTO_CREATE_USER'; select @@sql_mode; --error 1211 grant select on `my\_1`.* to mysqltest_4@localhost with grant option; +--error 1044 grant select on `my\_1`.* to mysqltest_4@localhost identified by 'mypass' with grant option; disconnect user1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 4319fec258c..209755a0dcc 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -37,8 +37,7 @@ select * from information_schema.STATISTICS where TABLE_SCHEMA = "testtets"; show keys from t3 where Key_name = "a_data"; show tables like 't%'; ---replace_column 12 # 13 # ---replace_result "2147483647 " "21474836479 " +--replace_column 8 # 12 # 13 # show table status; show full columns from t3 like "a%"; show full columns from mysql.db like "Insert%"; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 674b4ade097..6778af3d533 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -125,3 +125,33 @@ SELECT DROP TABLE user_day; +# +# Tests for bugs #8616, #8615: distinct sum with rollup +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 + GROUP BY a WITH ROLLUP; + +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; + +DROP TABLE t1; + diff --git a/mysql-test/t/rpl000005.test b/mysql-test/t/rpl000005.test index ae713633df3..b94695c72e1 100644 --- a/mysql-test/t/rpl000005.test +++ b/mysql-test/t/rpl000005.test @@ -1,5 +1,10 @@ source include/master-slave.inc; +# +# Bug#7100 relay_log_space_max missing from SHOW VARIABLES +# +SHOW VARIABLES LIKE 'relay_log_space_limit'; + CREATE TABLE t1 (name varchar(64), age smallint(3)); INSERT INTO t1 SET name='Andy', age=31; INSERT t1 SET name='Jacob', age=2; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 04192f25ac8..8eb3a924ee3 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -179,3 +179,13 @@ insert into t1 (id_str) values ("test"); update t1 set id_str = concat(id_str, id) where id = last_insert_id(); select * from t1; drop table t1; + +# +# Bug #8942: a problem with update and partial key part +# + +create table t1 (a int, b char(255), key(a, b(20))); +insert into t1 values (0, '1'); +update t1 set b = b + 1 where a = 0; +select * from t1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ff300235ea8..7a05ebb0204 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1117,8 +1117,7 @@ create view v1 as select x1() from t1; drop function x1; -- error 1356 select * from v1; ---replace_column 12 # 13 # ---replace_result "2147483647 " "21474836479 " +--replace_column 8 # 12 # 13 # show table status; drop view v1; drop table t1; diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index c8d0e5c1c18..de51fad4365 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -521,9 +521,17 @@ int ha_heap::create(const char *name, TABLE *table_arg, seg->null_bit= 0; seg->null_pos= 0; } - // We have to store field->key_type() as seg->type can differ from it - if (field->flags & AUTO_INCREMENT_FLAG) + if (field->flags & AUTO_INCREMENT_FLAG && + table_arg->found_next_number_field && + key == share->next_number_index) + { + /* + Store key number and type for found auto_increment key + We have to store type as seg->type can differ from it + */ + auto_key= key+ 1; auto_key_type= field->key_type(); + } } } mem_per_row+= MY_ALIGN(share->reclength + 1, sizeof(char*)); @@ -535,8 +543,8 @@ int ha_heap::create(const char *name, TABLE *table_arg, found_real_auto_increment= share->next_number_key_offset == 0; } HP_CREATE_INFO hp_create_info; + hp_create_info.auto_key= auto_key; hp_create_info.auto_key_type= auto_key_type; - hp_create_info.with_auto_increment= found_real_auto_increment; hp_create_info.auto_increment= (create_info->auto_increment_value ? create_info->auto_increment_value - 1 : 0); hp_create_info.max_table_size=current_thd->variables.max_heap_table_size; diff --git a/sql/handler.cc b/sql/handler.cc index 20c96849c0f..df0d7704163 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -762,6 +762,14 @@ static char* xid_to_str(char *buf, XID *xid) for (i=0; i < xid->gtrid_length+xid->bqual_length; i++) { uchar c=(uchar)xid->data[i]; + bool is_next_dig; + if (i < XIDDATASIZE) + { + char ch=xid->data[i+1]; + is_next_dig=(c >= '0' && c <='9'); + } + else + is_next_dig=FALSE; if (i == xid->gtrid_length) { *s++='\''; @@ -774,9 +782,11 @@ static char* xid_to_str(char *buf, XID *xid) if (c < 32 || c > 126) { *s++='\\'; - *s++='x'; - *s++=_dig_vec_lower[c >> 4]; - *s++=_dig_vec_lower[c & 15]; + if (c > 077 || is_next_dig) + *s++=_dig_vec_lower[c >> 6]; + if (c > 007 || is_next_dig) + *s++=_dig_vec_lower[(c >> 3) & 7]; + *s++=_dig_vec_lower[c & 7]; } else { @@ -862,6 +872,10 @@ int ha_recover(HASH *commit_list) my_xid x=list[i].get_my_xid(); if (!x) // not "mine" - that is generated by external TM { +#ifndef DBUG_OFF + char buf[XIDDATASIZE*4+6]; // see xid_to_str + sql_print_information("ignore xid %s", xid_to_str(buf, list+i)); +#endif found_foreign_xids++; continue; } @@ -962,9 +976,9 @@ bool mysql_xa_recover(THD *thd) if (xid->get_my_xid()) continue; // skip "our" xids protocol->prepare_for_resend(); - protocol->store_long((longlong)xid->formatID); - protocol->store_long((longlong)xid->gtrid_length); - protocol->store_long((longlong)xid->bqual_length); + protocol->store_longlong((longlong)xid->formatID, FALSE); + protocol->store_longlong((longlong)xid->gtrid_length, FALSE); + protocol->store_longlong((longlong)xid->bqual_length, FALSE); protocol->store(xid->data, xid->gtrid_length+xid->bqual_length, &my_charset_bin); if (protocol->write()) diff --git a/sql/item.cc b/sql/item.cc index e6be934e334..64fc2696f1f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -586,6 +586,18 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) return NULL; } conv->str_value.copy(); + /* + The above line executes str_value.realloc() internally, + which alligns Alloced_length using ALLIGN_SIZE. + In the case of Item_string::str_value we don't want + Alloced_length to be longer than str_length. + Otherwise, some functions like Item_func_concat::val_str() + try to reuse str_value as a buffer for concatenation result + for optimization purposes, so our string constant become + corrupted. See bug#8785 for more details. + Let's shrink Alloced_length to str_length to avoid this problem. + */ + conv->str_value.shrink_to_length(); return conv; } diff --git a/sql/item.h b/sql/item.h index a2bf33398cc..55c9af356a8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -790,6 +790,17 @@ public: Item *safe_charset_converter(CHARSET_INFO *tocs); }; +class Item_null_result :public Item_null +{ +public: + Field *result_field; + Item_null_result() : Item_null(), result_field(0) {} + bool is_result_field() { return result_field != 0; } + void save_in_result_field(bool no_conversions) + { + save_in_field(result_field, no_conversions); + } +}; /* Item represents one placeholder ('?') of prepared statement */ @@ -1274,12 +1285,12 @@ public: void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } + Field *get_tmp_table_field() { return result_field; } table_map used_tables() const { return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables(); } void set_result_field(Field *field) { result_field= field; } - Field *get_tmp_table_field() { return result_field; } bool is_result_field() { return 1; } void save_in_result_field(bool no_conversions) { diff --git a/sql/item_func.cc b/sql/item_func.cc index 684ba814cd4..5eb87c2e92b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2096,11 +2096,6 @@ longlong Item_func_char_length::val_int() longlong Item_func_coercibility::val_int() { DBUG_ASSERT(fixed == 1); - if (args[0]->null_value) - { - null_value= 1; - return 0; - } null_value= 0; return (longlong) args[0]->collation.derivation; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index a9ec7139ea7..81120bbe3f7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -267,8 +267,7 @@ String *Item_func_concat::val_str(String *str) current_thd->variables.max_allowed_packet); goto null; } - if (!args[0]->const_item() && - res->alloced_length() >= res->length()+res2->length()) + if (res->alloced_length() >= res->length()+res2->length()) { // Use old buffer res->append(*res2); } @@ -2308,12 +2307,11 @@ void Item_func_set_collation::print(String *str) String *Item_func_charset::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res = args[0]->val_str(str); uint dummy_errors; - if ((null_value=(args[0]->null_value || !res->charset()))) - return 0; - str->copy(res->charset()->csname,strlen(res->charset()->csname), + CHARSET_INFO *cs= args[0]->collation.collation; + null_value= 0; + str->copy(cs->csname, strlen(cs->csname), &my_charset_latin1, collation.collation, &dummy_errors); return str; } @@ -2321,12 +2319,11 @@ String *Item_func_charset::val_str(String *str) String *Item_func_collation::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res = args[0]->val_str(str); uint dummy_errors; + CHARSET_INFO *cs= args[0]->collation.collation; - if ((null_value=(args[0]->null_value || !res->charset()))) - return 0; - str->copy(res->charset()->name,strlen(res->charset()->name), + null_value= 0; + str->copy(cs->name, strlen(cs->name), &my_charset_latin1, collation.collation, &dummy_errors); return str; } @@ -2490,6 +2487,7 @@ String* Item_func_export_set::val_str(String* str) uint num_set_values = 64; ulonglong mask = 0x1; str->length(0); + str->set_charset(collation.collation); /* Check if some argument is a NULL value */ if (args[0]->null_value || args[1]->null_value || args[2]->null_value) diff --git a/sql/key.cc b/sql/key.cc index c5ed60b129c..3299c3db8f8 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -368,7 +368,7 @@ bool check_if_key_used(TABLE *table, uint idx, List &fields) f.rewind(); while ((field=(Item_field*) f++)) { - if (key_part->field == field->field) + if (key_part->field->eq(field->field)) return 1; } } diff --git a/sql/lock.cc b/sql/lock.cc index 507e802d2e8..266e8dc4d4d 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -800,8 +800,8 @@ bool lock_global_read_lock(THD *thd) if (!thd->global_read_lock) { - (void) pthread_mutex_lock(&LOCK_open); - const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open, + (void) pthread_mutex_lock(&LOCK_global_read_lock); + const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, "Waiting to get readlock"); DBUG_PRINT("info", ("waiting_for: %d protect_against: %d", @@ -809,7 +809,7 @@ bool lock_global_read_lock(THD *thd) waiting_for_read_lock++; while (protect_against_global_read_lock && !thd->killed) - pthread_cond_wait(&COND_refresh, &LOCK_open); + pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); waiting_for_read_lock--; if (thd->killed) { @@ -834,11 +834,11 @@ bool lock_global_read_lock(THD *thd) void unlock_global_read_lock(THD *thd) { uint tmp; - pthread_mutex_lock(&LOCK_open); + pthread_mutex_lock(&LOCK_global_read_lock); tmp= --global_read_lock; if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT) --global_read_lock_blocks_commit; - pthread_mutex_unlock(&LOCK_open); + pthread_mutex_unlock(&LOCK_global_read_lock); /* Send the signal outside the mutex to avoid a context switch */ if (!tmp) pthread_cond_broadcast(&COND_refresh); @@ -857,7 +857,7 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, DBUG_ENTER("wait_if_global_read_lock"); LINT_INIT(old_message); - (void) pthread_mutex_lock(&LOCK_open); + (void) pthread_mutex_lock(&LOCK_global_read_lock); if ((need_exit_cond= must_wait)) { if (thd->global_read_lock) // This thread had the read locks @@ -865,7 +865,7 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, if (is_not_commit) my_message(ER_CANT_UPDATE_WITH_READLOCK, ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0)); - (void) pthread_mutex_unlock(&LOCK_open); + (void) pthread_mutex_unlock(&LOCK_global_read_lock); /* We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does. This allowance is needed to not break existing versions of innobackup @@ -873,11 +873,11 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, */ DBUG_RETURN(is_not_commit); } - old_message=thd->enter_cond(&COND_refresh, &LOCK_open, + old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, "Waiting for release of readlock"); while (must_wait && ! thd->killed && (!abort_on_refresh || thd->version == refresh_version)) - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock); if (thd->killed) result=1; } @@ -890,7 +890,7 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, if (unlikely(need_exit_cond)) thd->exit_cond(old_message); else - pthread_mutex_unlock(&LOCK_open); + pthread_mutex_unlock(&LOCK_global_read_lock); DBUG_RETURN(result); } @@ -901,10 +901,10 @@ void start_waiting_global_read_lock(THD *thd) DBUG_ENTER("start_waiting_global_read_lock"); if (unlikely(thd->global_read_lock)) DBUG_VOID_RETURN; - (void) pthread_mutex_lock(&LOCK_open); + (void) pthread_mutex_lock(&LOCK_global_read_lock); tmp= (!--protect_against_global_read_lock && (waiting_for_read_lock || global_read_lock_blocks_commit)); - (void) pthread_mutex_unlock(&LOCK_open); + (void) pthread_mutex_unlock(&LOCK_global_read_lock); if (tmp) pthread_cond_broadcast(&COND_refresh); DBUG_VOID_RETURN; @@ -922,16 +922,16 @@ bool make_global_read_lock_block_commit(THD *thd) */ if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK) DBUG_RETURN(1); - pthread_mutex_lock(&LOCK_open); + pthread_mutex_lock(&LOCK_global_read_lock); /* increment this BEFORE waiting on cond (otherwise race cond) */ global_read_lock_blocks_commit++; /* For testing we set up some blocking, to see if we can be killed */ DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock++;); - old_message= thd->enter_cond(&COND_refresh, &LOCK_open, + old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, "Waiting for all running commits to finish"); while (protect_against_global_read_lock && !thd->killed) - pthread_cond_wait(&COND_refresh, &LOCK_open); + pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock--;); if (error= thd->killed) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c4de96c2db4..ba9f382fc33 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1102,7 +1102,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status, LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, - LOCK_slave_list, LOCK_active_mi, LOCK_manager, + LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock, LOCK_global_system_variables, LOCK_user_conn; extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c55700b4495..6747b79703b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -426,7 +426,7 @@ SHOW_COMP_OPTION have_crypt, have_compress; pthread_key(MEM_ROOT**,THR_MALLOC); pthread_key(THD*, THR_THD); pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, - LOCK_mapped_file, LOCK_status, + LOCK_mapped_file, LOCK_status, LOCK_global_read_lock, LOCK_error_log, LOCK_uuid_generator, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, @@ -1102,6 +1102,7 @@ static void clean_up_mutexes() (void) rwlock_destroy(&LOCK_sys_init_connect); (void) rwlock_destroy(&LOCK_sys_init_slave); (void) pthread_mutex_destroy(&LOCK_global_system_variables); + (void) pthread_mutex_destroy(&LOCK_global_read_lock); (void) pthread_cond_destroy(&COND_thread_count); (void) pthread_cond_destroy(&COND_refresh); (void) pthread_cond_destroy(&COND_thread_cache); @@ -2594,6 +2595,7 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); (void) my_rwlock_init(&LOCK_sys_init_connect, NULL); (void) my_rwlock_init(&LOCK_sys_init_slave, NULL); diff --git a/sql/set_var.cc b/sql/set_var.cc index 1f4713471ba..23dbb22399b 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -926,6 +926,7 @@ struct show_var_st init_vars[]= { {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, #ifdef HAVE_REPLICATION {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS}, + {"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG}, #endif {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3759840d3bb..c51e5e00aa1 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1642,17 +1642,6 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, } else { - /* - Check that the user isn't trying to change a password for another - user if he doesn't have UPDATE privilege to the MySQL database - */ - DBUG_ASSERT(combo.host.str != 0); - if (thd->user && combo.password.str && - (strcmp(thd->user,combo.user.str) || - my_strcasecmp(system_charset_info, - combo.host.str, thd->host_or_ip)) && - check_access(thd, UPDATE_ACL, "mysql",0,1,0)) - goto end; old_row_exists = 1; store_record(table,record[1]); // Save copy for update if (combo.password.str) // If password given diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4b069dd56e8..a39ccacfe00 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3626,6 +3626,24 @@ unsent_create_error: first_table ? 0 : 1, 0)) goto error; + if (thd->user) // If not replication + { + LEX_USER *user; + List_iterator user_list(lex->users_list); + while ((user=user_list++)) + { + if (user->password.str && + strcmp(thd->user, user->user.str) || + user->host.str && + my_strcasecmp(system_charset_info, + user->host.str, thd->host_or_ip)) + { + if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 0)) + goto error; + break; // We are allowed to do changes + } + } + } if (specialflag & SPECIAL_NO_RESOLVE) { LEX_USER *user; @@ -4381,6 +4399,8 @@ unsent_create_error: { if (!(res= !ha_commit_or_rollback_by_xid(&thd->lex->ident, 1))) my_error(ER_XAER_NOTA, MYF(0)); + else + send_ok(thd); break; } if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) @@ -4389,9 +4409,7 @@ unsent_create_error: if ((r= ha_commit(thd))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); else - { send_ok(thd); - } } else if (thd->transaction.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) @@ -4399,9 +4417,7 @@ unsent_create_error: if (ha_commit_one_phase(thd, 1)) my_error(ER_XAER_RMERR, MYF(0)); else - { send_ok(thd); - } } else { @@ -4418,6 +4434,8 @@ unsent_create_error: { if (!(res= !ha_commit_or_rollback_by_xid(&thd->lex->ident, 0))) my_error(ER_XAER_NOTA, MYF(0)); + else + send_ok(thd); break; } if (thd->transaction.xa_state != XA_IDLE && diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b970c184489..c461abfc635 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -191,7 +191,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, uint elements, List &items); static void init_tmptable_sum_functions(Item_sum **func); static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); -static void copy_sum_funcs(Item_sum **func_ptr); +static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr); static bool init_sum_functions(Item_sum **func, Item_sum **end); @@ -1447,7 +1447,7 @@ JOIN::exec() if (curr_join->tmp_having) curr_join->tmp_having->update_used_tables(); if (remove_duplicates(curr_join, curr_tmp_table, - curr_join->fields_list, curr_join->tmp_having)) + *curr_fields_list, curr_join->tmp_having)) DBUG_VOID_RETURN; curr_join->tmp_having=0; curr_join->select_distinct=0; @@ -10132,26 +10132,32 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (join->procedure) join->procedure->end_group(); - if (idx < (int) join->send_group_parts) + int send_group_parts= join->send_group_parts; + if (idx < send_group_parts) { if (!join->first_record) { /* No matching rows for group function */ join->clear(); } - copy_sum_funcs(join->sum_funcs); - if (!join->having || join->having->val_int()) + copy_sum_funcs(join->sum_funcs, + join->sum_funcs_end[send_group_parts]); + if (join->having && join->having->val_int() == 0) + error= -1; + else if ((error=table->file->write_row(table->record[0]))) { - if ((error=table->file->write_row(table->record[0]))) - { - if (create_myisam_from_heap(join->thd, table, - &join->tmp_table_param, - error, 0)) - DBUG_RETURN(-1); // Not a table_is_full error - } - else - join->send_records++; + if (create_myisam_from_heap(join->thd, table, + &join->tmp_table_param, + error, 0)) + DBUG_RETURN(-1); + } + if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0) + { + if (join->rollup_write_data((uint) (idx+1), table)) + error= 1; } + if (error > 0) + DBUG_RETURN(-1); if (end_of_records) DBUG_RETURN(0); } @@ -12413,11 +12419,10 @@ update_tmptable_sum_func(Item_sum **func_ptr, /* Copy result of sum functions to record in tmp_table */ static void -copy_sum_funcs(Item_sum **func_ptr) +copy_sum_funcs(Item_sum **func_ptr, Item_sum **end_ptr) { - Item_sum *func; - for (; (func = *func_ptr) ; func_ptr++) - (void) func->save_in_result_field(1); + for (; func_ptr != end_ptr ; func_ptr++) + (void) (*func_ptr)->save_in_result_field(1); return; } @@ -12539,14 +12544,16 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; - if (!(rollup.fields= (List*) thd->alloc((sizeof(Item*) + - sizeof(List) + - ref_pointer_array_size) - * send_group_parts))) + if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) + + sizeof(Item**) + + sizeof(List) + + ref_pointer_array_size) + * send_group_parts ))) return 1; + + rollup.fields= (List*) (rollup.null_items + send_group_parts); rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); - rollup.item_null= new (thd->mem_root) Item_null(); /* Prepare space for field list for the different levels @@ -12554,12 +12561,16 @@ bool JOIN::rollup_init() */ for (i= 0 ; i < send_group_parts ; i++) { + rollup.null_items[i]= new (thd->mem_root) Item_null_result(); List *rollup_fields= &rollup.fields[i]; rollup_fields->empty(); rollup.ref_pointer_arrays[i]= ref_array; ref_array+= all_fields.elements; + } + for (i= 0 ; i < send_group_parts; i++) + { for (j=0 ; j < fields_list.elements ; j++) - rollup_fields->push_back(rollup.item_null); + rollup.fields[i].push_back(rollup.null_items[i]); } return 0; } @@ -12663,7 +12674,8 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, { /* Check if this is something that is part of this group by */ ORDER *group_tmp; - for (group_tmp= start_group ; group_tmp ; group_tmp= group_tmp->next) + for (group_tmp= start_group, i-- ; + group_tmp ; group_tmp= group_tmp->next, i++) { if (*group_tmp->item == item) { @@ -12672,7 +12684,9 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, set to NULL in this level */ item->maybe_null= 1; // Value will be null sometimes - item= rollup.item_null; + Item_null_result *null_item= rollup.null_items[i]; + null_item->result_field= ((Item_field *) item)->result_field; + item= null_item; break; } } @@ -12732,6 +12746,58 @@ int JOIN::rollup_send_data(uint idx) return 0; } +/* + Write all rollup levels higher than the current one to a temp table + + SYNOPSIS: + rollup_write_data() + idx Level we are on: + 0 = Total sum level + 1 = First group changed (a) + 2 = Second group changed (a,b) + table reference to temp table + + SAMPLE + SELECT a, b, SUM(c) FROM t1 GROUP BY a,b WITH ROLLUP + + RETURN + 0 ok + 1 if write_data_failed() +*/ + +int JOIN::rollup_write_data(uint idx, TABLE *table) +{ + uint i; + for (i= send_group_parts ; i-- > idx ; ) + { + /* Get reference pointers to sum functions in place */ + memcpy((char*) ref_pointer_array, + (char*) rollup.ref_pointer_arrays[i], + ref_pointer_array_size); + if ((!having || having->val_int())) + { + int error; + Item *item; + List_iterator_fast it(rollup.fields[i]); + while ((item= it++)) + { + if (item->type() == Item::NULL_ITEM && item->is_result_field()) + item->save_in_result_field(1); + } + copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]); + if ((error= table->file->write_row(table->record[0]))) + { + if (create_myisam_from_heap(thd, table, &tmp_table_param, + error, 0)) + return 1; + } + } + } + /* Restore ref_pointer_array */ + set_items_ref_array(current_ref_pointer_array); + return 0; +} + /* clear results if there are not rows found for group (end_send_group/end_write_group) diff --git a/sql/sql_select.h b/sql/sql_select.h index f00fd476edd..02e1dde8a7f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -135,7 +135,7 @@ typedef struct st_rollup { enum State { STATE_NONE, STATE_INITED, STATE_READY }; State state; - Item *item_null; + Item_null_result **null_items; Item ***ref_pointer_arrays; List *fields; } ROLLUP; @@ -323,6 +323,7 @@ class JOIN :public Sql_alloc bool rollup_make_fields(List &all_fields, List &fields, Item_sum ***func); int rollup_send_data(uint idx); + int rollup_write_data(uint idx, TABLE *table); bool test_in_subselect(Item **where); void join_free(bool full); void clear(); diff --git a/sql/sql_string.h b/sql/sql_string.h index 2debeb61787..fc1e9f171b6 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -205,6 +205,10 @@ public: } } } + inline void shrink_to_length() + { + Alloced_length= str_length; + } bool is_alloced() { return alloced; } inline String& operator = (const String &s) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3cae2484ca2..8295e2f07ab 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -65,7 +65,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, my_bool drop_temporary) { - bool error= FALSE; + bool error= FALSE, need_start_waiters= FALSE; DBUG_ENTER("mysql_rm_table"); /* mark for close and remove all cached entries */ @@ -74,23 +74,19 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, thd->mysys_var->current_cond= &COND_refresh; VOID(pthread_mutex_lock(&LOCK_open)); - if (!drop_temporary && global_read_lock) + if (!drop_temporary) { - if (thd->global_read_lock) + if ((error= wait_if_global_read_lock(thd, 0, 1))) { my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name); - error= TRUE; goto err; } - while (global_read_lock && ! thd->killed) - { - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - } - + else + need_start_waiters= TRUE; } error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0); - err: +err: pthread_mutex_unlock(&LOCK_open); pthread_mutex_lock(&thd->mysys_var->mutex); @@ -98,6 +94,9 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); + if (need_start_waiters) + start_waiting_global_read_lock(thd); + if (error) DBUG_RETURN(TRUE); send_ok(thd); @@ -114,7 +113,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, tables List of tables to delete if_exists If 1, don't give error if one table doesn't exists dont_log_query Don't write query to log files. This will also not - generate warnings if the handler files doesn't exists + generate warnings if the handler files doesn't exists NOTES Works like documented in mysql_rm_table(), but don't check diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e215141ff0a..3ee656b00ce 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -219,7 +219,7 @@ int mysql_update(THD *thd, #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Check values */ table_list->grant.want_privilege= table->grant.want_privilege= - (SELECT_ACL & ~~table->grant.privilege); + (SELECT_ACL & ~table->grant.privilege); #endif if (setup_fields(thd, 0, table_list, values, 1, 0, 0)) { diff --git a/tests/grant.pl b/tests/grant.pl index cd6a2eb80de..4f2bd1a61cb 100644 --- a/tests/grant.pl +++ b/tests/grant.pl @@ -201,7 +201,7 @@ safe_query("select * from mysql.db where user = '$opt_user'"); safe_query("grant CREATE,UPDATE,DROP on $opt_database.* to $user"); user_connect(0); user_query("create table $opt_database.test2 (a int not null)"); -user_query("update test,test2 SET test.a=1 where 1"); +user_query("update test,test2 SET test.a=1 where 1",1); user_query("update test,test2 SET test.a=test2.a where 1",1); safe_query("grant SELECT on $opt_database.* to $user"); user_connect(0); @@ -375,7 +375,7 @@ user_query("delete from $opt_database.test where a=2"); user_query("delete from $opt_database.test where A=2"); user_query("update test set b=5 where b>0"); user_query("update test set a=11 where b>5",1); -user_query("update test,test2 SET test.b=5 where b>0"); +user_query("update test,test2 SET test.b=5 where b>0",1); user_query("update test,test2 SET test.a=11 where b>0",1); user_query("update test,test2 SET test.b=test2.a where b>0",1); user_query("update test,test2 SET test.b=11 where test2.a>0",1);