diff --git a/.bzrignore b/.bzrignore index 16211ff2ecf..50218bc2dc3 100644 --- a/.bzrignore +++ b/.bzrignore @@ -48,6 +48,7 @@ 50 =6 BUILD/compile-pentium-maintainer +BitKeeper/etc/RESYNC_TREE BitKeeper/etc/config BitKeeper/etc/csets BitKeeper/etc/csets-in @@ -295,6 +296,7 @@ libmysql/*.ds? libmysql/*.vcproj libmysql/conf_to_src libmysql/debug/libmysql.exp +libmysql/libmysql.ver libmysql/my_static.h libmysql/my_time.c libmysql/mysys_priv.h @@ -1611,4 +1613,3 @@ vio/viotest-sslconnect.cpp vio/viotest.cpp zlib/*.ds? zlib/*.vcproj -BitKeeper/etc/RESYNC_TREE diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 542c82d8f58..f512aa9e29e 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -45,22 +45,22 @@ CLEAN_FILES: $(TXT_FILES) GT = $(srcdir)/Support/generate-text-files.pl ../INSTALL-SOURCE: mysql.info $(GT) - perl -w $(GT) $< "installing-source" "windows-source-build" > $@ + perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@ ../INSTALL-WIN-SOURCE: mysql.info $(GT) - perl -w $(GT) $< "windows-source-build" "post-installation" > $@ + perl -w $(GT) mysql.info "windows-source-build" "post-installation" > $@ # We put the description for the binary installation here so that # people who download source wont have to see it. It is moved up to # the toplevel by the script that makes the binary tar files. INSTALL-BINARY: mysql.info $(GT) - perl -w $(GT) $< "installing-binary" "installing-source" > $@ + perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@ ../EXCEPTIONS-CLIENT: mysql.info $(GT) - perl -w $(GT) $< "mysql-floss-license-exception" "function-index" > $@ + perl -w $(GT) mysql.info "mysql-floss-license-exception" "function-index" > $@ ../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) - perl -w $(GT) $< "mac-os-x-installation" "netware-installation" > $@ + perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@ # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 8d2e040b21f..5b52d524f8e 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -569,6 +569,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return -1; } mysql_close(mysql); /* Close connection to avoid error messages */ + argc=1; /* force SHUTDOWN to be the last command */ if (got_pidfile) { if (opt_verbose) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index d86e3a44746..96792d0ffcb 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1293,12 +1293,13 @@ at offset %lu ; this could be a log format error or read error", } else if (buf[4] == ROTATE_EVENT) { + Log_event *ev; my_b_seek(file, tmp_pos); /* seek back to event's start */ - if (!Log_event::read_log_event(file, *description_event)) + if (!(ev= Log_event::read_log_event(file, *description_event))) /* EOF can't be hit here normally, so it's a real error */ - die("Could not read a Rotate_log_event event \ -at offset %lu ; this could be a log format error or read error", - tmp_pos); + die("Could not read a Rotate_log_event event at offset %lu ;" + " this could be a log format error or read error", tmp_pos); + delete ev; } else break; diff --git a/client/mysqldump.c b/client/mysqldump.c index 9c495a70ea9..6521e9183f3 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1316,7 +1316,7 @@ static uint dump_routines_for_db(char *db) fprintf(sql_file, "DELIMITER ;\n"); if (lock_tables) - mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); DBUG_RETURN(0); } @@ -2139,7 +2139,10 @@ static void dump_table(char *table, char *db) else res=mysql_store_result(sock); if (!res) + { DB_error(sock, "when retrieving data from server"); + goto err; + } if (verbose) fprintf(stderr, "-- Retrieving rows...\n"); if (mysql_num_fields(res) != num_fields) @@ -2794,7 +2797,7 @@ static int dump_all_tables_in_db(char *database) check_io(md_result_file); } if (lock_tables) - mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); return 0; } /* dump_all_tables_in_db */ @@ -2849,23 +2852,23 @@ static my_bool dump_all_views_in_db(char *database) check_io(md_result_file); } if (lock_tables) - mysql_query(sock,"UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); 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. - we do this because the table name given on the command line may be a + 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. + we do this because the table name given on the command line may be a different case (e.g. T1 vs t1) - + RETURN int - 0 if a tablename was retrieved. 1 if not */ -static int get_actual_table_name(const char *old_table_name, - char *new_table_name, +static int get_actual_table_name(const char *old_table_name, + char *new_table_name, int buf_size) { int retval; @@ -2877,7 +2880,7 @@ static int get_actual_table_name(const char *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", + 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)) @@ -2886,7 +2889,7 @@ static int get_actual_table_name(const char *old_table_name, } retval = 1; - + if ((table_res= mysql_store_result(sock))) { my_ulonglong num_rows= mysql_num_rows(table_res); @@ -3008,7 +3011,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) check_io(md_result_file); } if (lock_tables) - mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); DBUG_RETURN(0); } /* dump_selected_tables */ diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c index 1da6a864181..c0fa7cc717d 100644 --- a/cmd-line-utils/libedit/history.c +++ b/cmd-line-utils/libedit/history.c @@ -676,8 +676,8 @@ history_load(History *h, const char *fname) (void) strunvis(ptr, line); line[sz] = c; if (HENTER(h, &ev, ptr) == -1) { - h_free((ptr_t)ptr); - return -1; + i = -1; + goto oomem; } } oomem: diff --git a/configure.in b/configure.in index baed56cb914..bdaa1f5166e 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,8 @@ AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 DOT_FRM_VERSION=6 # See the libtool docs for information on how to do shared lib versions. -SHARED_LIB_VERSION=15:0:0 +SHARED_LIB_MAJOR_VERSION=15 +SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0 # Set all version vars based on $VERSION. How do we do this more elegant ? # Remember that regexps needs to quote [ and ] since this is run through m4 @@ -60,6 +61,7 @@ AC_DEFINE_UNQUOTED([PROTOCOL_VERSION], [$PROTOCOL_VERSION], AC_SUBST(DOT_FRM_VERSION) AC_DEFINE_UNQUOTED([DOT_FRM_VERSION], [$DOT_FRM_VERSION], [Version of .frm files]) +AC_SUBST(SHARED_LIB_MAJOR_VERSION) AC_SUBST(SHARED_LIB_VERSION) AC_SUBST(AVAILABLE_LANGUAGES) @@ -339,6 +341,13 @@ fi MYSQL_PROG_AR +# libmysqlclient versioning when linked with GNU ld. +if $LD --version 2>/dev/null|grep -q GNU; then + LD_VERSION_SCRIPT="-Wl,--version-script=\$(top_srcdir)/libmysql/libmysql.ver" + AC_CONFIG_FILES(libmysql/libmysql.ver) +fi +AC_SUBST(LD_VERSION_SCRIPT) + # Avoid bug in fcntl on some versions of linux AC_MSG_CHECKING("if we should use 'skip-locking' as default for $target_os") # Any variation of Linux @@ -2548,9 +2557,12 @@ AC_SUBST(CC) AC_SUBST(GXX) # Set configuration options for make_binary_distribution + +CONF_ARGS= case $SYSTEM_TYPE in *netware*) MAKE_BINARY_DISTRIBUTION_OPTIONS=--no-strip + CONF_ARGS=--host="$MACHINE_TYPE-$SYSTEM_TYPE" ;; *) MAKE_BINARY_DISTRIBUTION_OPTIONS= @@ -2558,7 +2570,7 @@ case $SYSTEM_TYPE in esac for CONF in $other_configures; do - (cd `dirname $CONF`; ./`basename $CONF` --build=$build_alias) + (cd `dirname $CONF`; ./`basename $CONF` $CONF_ARGS --build=$build_alias) done AC_SUBST(MAKE_BINARY_DISTRIBUTION_OPTIONS) diff --git a/include/config-netware.h b/include/config-netware.h index 5a8b926a669..e2fc75ab90d 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -19,6 +19,14 @@ #ifndef _config_netware_h #define _config_netware_h +#define __event_h__ +#define _EVENT_H_ +/* + These two #define(s) are needed as both libc of NetWare and MySQL have + files named event.h which causes compilation errors. +*/ + + /* required headers */ #include #include @@ -35,6 +43,12 @@ #include #include +#undef _EVENT_H_ +/* + This #undef exists here because both libc of NetWare and MySQL have + files named event.h which causes compilation errors. +*/ + #ifdef __cplusplus extern "C" { #endif @@ -65,6 +79,13 @@ extern "C" { #undef HAVE_STPCPY /* changes end */ +/* Changes made to make use of LibC-June-2005 for building purpose */ +#undef HAVE_GETPASS +#undef HAVE_GETRLIMIT +#undef HAVE_GETRUSAGE +#undef HAVE_INITGROUPS +/* Changes end - LibC-June-2005 */ + /* no libc crypt() function */ #ifdef HAVE_OPENSSL #define HAVE_CRYPT 1 diff --git a/include/my_base.h b/include/my_base.h index 5962775fb57..168625f4a87 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -426,7 +426,8 @@ enum ha_base_keytype { enum en_fieldtype { FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE, FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO, - FIELD_VARCHAR,FIELD_CHECK + FIELD_VARCHAR,FIELD_CHECK, + FIELD_enum_val_count }; enum data_file_type { diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index a4d616f936a..c4c9c0036e2 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -77,7 +77,7 @@ mysysobjects2 = my_lib.lo mysysobjects = $(mysysobjects1) $(mysysobjects2) target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \ $(sql_cmn_objects) $(vio_objects) $(sqlobjects) -target_ldflags = -version-info @SHARED_LIB_VERSION@ +target_ldflags = -version-info @SHARED_LIB_VERSION@ @LD_VERSION_SCRIPT@ vio_objects= vio.lo viosocket.lo viossl.lo viosslfactories.lo CLEANFILES = $(target_libadd) $(SHLIBOBJS) \ $(target) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index e2ee44efffb..a77d1408383 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -818,7 +818,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) if ((*options->local_infile_init)(&li_ptr, net_filename, options->local_infile_userdata)) { - my_net_write(net,"",0); /* Server needs one packet */ + VOID(my_net_write(net,"",0)); /* Server needs one packet */ net_flush(net); strmov(net->sqlstate, unknown_sqlstate); net->last_errno= (*options->local_infile_error)(li_ptr, @@ -2817,7 +2817,7 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, { switch (attr_type) { case STMT_ATTR_UPDATE_MAX_LENGTH: - *(ulong*) value= stmt->update_max_length; + *(my_bool*) value= stmt->update_max_length; break; case STMT_ATTR_CURSOR_TYPE: *(ulong*) value= stmt->flags; diff --git a/libmysql/libmysql.ver.in b/libmysql/libmysql.ver.in new file mode 100644 index 00000000000..20eb0fd41bb --- /dev/null +++ b/libmysql/libmysql.ver.in @@ -0,0 +1 @@ +libmysqlclient_@SHARED_LIB_MAJOR_VERSION@ { global: *; }; diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 90334b28439..a98a929b947 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -253,12 +253,17 @@ sub collect_one_test_case($$$$$$$) { } if ( ( $::opt_with_ndbcluster or $::glob_use_running_ndbcluster ) and - defined mtr_match_substring($tname,"ndb") ) + ( $::opt_with_ndbcluster_all or defined mtr_match_substring($tname,"ndb") )) { $tinfo->{'ndb_test'}= 1; } else { + if ( $::opt_with_ndbcluster_only ) + { + $tinfo->{'skip'}= 1; + return; + } $tinfo->{'ndb_test'}= 0; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 82b894c28af..1861b9e35e5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -304,11 +304,13 @@ our $opt_warnings; our $opt_udiff; -our $opt_skip_ndbcluster; +our $opt_skip_ndbcluster= 0; our $opt_with_ndbcluster; -our $opt_skip_ndbcluster_slave; +our $opt_skip_ndbcluster_slave= 0; our $opt_with_ndbcluster_slave; -our $opt_ndb_extra_test; +our $opt_with_ndbcluster_all= 0; +our $opt_with_ndbcluster_only= 0; +our $opt_ndb_extra_test= 0; our $exe_ndb_mgm; our $path_ndb_tools_dir; @@ -548,6 +550,8 @@ sub command_line_setup () { 'with-ndbcluster-slave' => \$opt_with_ndbcluster_slave, 'skip-ndbcluster-slave|skip-ndb-slave' => \$opt_skip_ndbcluster_slave, + 'with-ndbcluster-all' => \$opt_with_ndbcluster_all, + 'with-ndbcluster-only' => \$opt_with_ndbcluster_only, 'ndb-extra-test' => \$opt_ndb_extra_test, 'do-test=s' => \$opt_do_test, 'suite=s' => \$opt_suite, @@ -1938,6 +1942,10 @@ sub run_testcase ($) { mtr_report_test_name($tinfo); mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + if ( $master->[1]->{'pid'} ) + { + mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + } # FIXME test cases that depend on each other, prevent this from # being at this location. @@ -1986,6 +1994,7 @@ sub run_testcase ($) { } if ( $using_ndbcluster_master and ! $master->[1]->{'pid'} ) { + mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); $master->[1]->{'pid'}= mysqld_start('master',1,$tinfo->{'master_opt'},[], $using_ndbcluster_master); @@ -3038,7 +3047,9 @@ Options to control what engine/variation to run Options to control what test suites or cases to run force Continue to run the suite after failure - with-ndbcluster Use cluster, and enable test cases that requres it + with-ndbcluster Use cluster, and enable test cases that requires it + with-ndbcluster-all Use cluster in all tests + with-ndbcluster-only Run only tests that include "ndb" in the filename skip-ndb[cluster] Skip the ndb test cases, don't start cluster do-test=PREFIX Run test cases which name are prefixed with PREFIX start-from=PREFIX Run test cases starting from test prefixed with PREFIX diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 2e957ffe186..409a5a345f8 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -630,7 +630,7 @@ export MASTER_MYHOST MASTER_MYPORT SLAVE_MYHOST SLAVE_MYPORT MYSQL_TCP_PORT MAST NDBCLUSTER_OPTS="--port=$NDBCLUSTER_PORT --data-dir=$MYSQL_TEST_DIR/var --ndb_mgm-extra-opts=$NDB_MGM_EXTRA_OPTS --ndb_mgmd-extra-opts=$NDB_MGMD_EXTRA_OPTS --ndbd-extra-opts=$NDBD_EXTRA_OPTS" NDBCLUSTER_OPTS_SLAVE="--port=$NDBCLUSTER_PORT_SLAVE --data-dir=$MYSQL_TEST_DIR/var" if [ -n "$USE_NDBCLUSTER_SLAVE" ] ; then - USE_NDBCLUSTER_SLAVE="$USE_NDBCLUSTER_SLAVE --ndb-connectstring=localhost:$NDBCLUSTER_PORT_SLAVE" + USE_NDBCLUSTER_SLAVE="$USE_NDBCLUSTER_SLAVE --ndb-connectstring=localhost:$NDBCLUSTER_PORT_SLAVE --ndb-extra-logging" fi NDB_BACKUP_DIR=$MYSQL_TEST_DIR/var/ndbcluster-$NDBCLUSTER_PORT NDB_TOOLS_OUTPUT=$MYSQL_TEST_DIR/var/log/ndb_tools.log @@ -1016,6 +1016,10 @@ disable_test() { report_current_test () { tname=$1 echo "CURRENT_TEST: $tname" >> $MASTER_MYERR + eval "master1_running=\$MASTER1_RUNNING" + if [ x$master1_running = x1 ] ; then + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR"1" + fi if [ -n "$PURIFY_LOGS" ] ; then for log in $PURIFY_LOGS do @@ -1297,7 +1301,7 @@ start_ndbcluster() NDB_CONNECTSTRING="$USE_RUNNING_NDBCLUSTER" echo "Using ndbcluster at $NDB_CONNECTSTRING" fi - USE_NDBCLUSTER_OPT="$USE_NDBCLUSTER --ndb-connectstring=\"$NDB_CONNECTSTRING\"" + USE_NDBCLUSTER_OPT="$USE_NDBCLUSTER --ndb-connectstring=\"$NDB_CONNECTSTRING\" --ndb-extra-logging" export NDB_CONNECTSTRING fi } @@ -1876,6 +1880,7 @@ run_testcase () start_ndbcluster start_master if [ x$USING_NDBCLUSTER = x1 -a -z "$DO_BENCH" -a -z "$DO_STRESS" ] ; then + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR"1" start_master 1 fi TZ=$MY_TZ; export TZ @@ -1903,6 +1908,7 @@ run_testcase () start_ndbcluster start_master if [ x$USING_NDBCLUSTER = x1 -a -z "$DO_BENCH" -a -z "$DO_STRESS" ] ; then + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR"1" start_master 1 fi else diff --git a/mysql-test/r/fulltext2.result b/mysql-test/r/fulltext2.result index 72c6b2d22ed..f6a4b20bc22 100644 --- a/mysql-test/r/fulltext2.result +++ b/mysql-test/r/fulltext2.result @@ -234,5 +234,10 @@ insert into t1 values('test test '),('test'),('test'),('test'), ('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), ('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'); delete from t1 limit 1; +truncate table t1; +insert into t1 values('ab c d'); +update t1 set a='ab c d'; +select * from t1 where match a against('ab c' in boolean mode); +a drop table t1; set names latin1; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index e367e063201..fe3c409744d 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1126,6 +1126,19 @@ DROP TABLE t1; DROP VIEW v1; DROP FUNCTION func1; DROP FUNCTION func2; +create database mysqltest; +create table mysqltest.t1(a int); +select table_schema from information_schema.tables where table_schema='mysqltest'; +table_schema +drop database mysqltest; +select column_type, group_concat(table_schema, '.', table_name), count(*) as num +from information_schema.columns where +table_schema='information_schema' and +(column_type = 'varchar(7)' or column_type = 'varchar(20)') +group by column_type order by num; +column_type group_concat(table_schema, '.', table_name) num +varchar(7) information_schema.ROUTINES,information_schema.VIEWS 2 +varchar(20) information_schema.COLUMNS,information_schema.FILES,information_schema.FILES,information_schema.PLUGINS,information_schema.PLUGINS,information_schema.PLUGINS 6 select * from information_schema.engines WHERE ENGINE="MyISAM"; ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS MyISAM ENABLED Default engine as of MySQL 3.23 with great performance NO NO NO diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 282e9775825..776a98c7d4d 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -304,21 +304,56 @@ id select_type table partitions type possible_keys key key_len ref rows Extra explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2); id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p1_sp2,p2_sp2 system NULL NULL NULL NULL 1 -DROP TABLE IF EXISTS `t1`; +drop table t1; +create table t1 (a int) partition by list(a) ( +partition p0 values in (1,2), +partition p1 values in (3,4) +); +insert into t1 values (1),(1),(2),(2),(3),(4),(3),(4); +flush status; +update t1 set a=100 where a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +update t1 set a=100 where a+1=5+1; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 10 +flush status; +delete from t1 where a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete from t1 where a+1=5+1; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 10 +create table t2 like t1; +insert into t2 select * from t2; +flush status; +update t1,t2 set t1.a=1000, t2.a=1000 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete t1,t2 from t1, t2 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +drop table t1,t2; CREATE TABLE `t1` ( `a` int(11) default NULL ); INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); -DROP TABLE IF EXISTS `t2`; -Warnings: -Note 1051 Unknown table 't2' CREATE TABLE `t2` ( `a` int(11) default NULL, KEY `a` (`a`) ) ; insert into t2 select A.a + 10*(B.a + 10* C.a) from t1 A, t1 B, t1 C ; insert into t1 select a from t2; -DROP TABLE IF EXISTS `t2`; +drop table t2; CREATE TABLE `t2` ( `a` int(11) default NULL, `b` int(11) default NULL @@ -367,23 +402,23 @@ flush status; update t2 set a = 1002 where a = 1001; show status like 'Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 1015 +Handler_read_rnd_next 0 flush status; update t2 set b = 6 where a = 600; show status like 'Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 1015 +Handler_read_rnd_next 201 flush status; update t2 set b = 6 where a > 600 and a < 800; show status like 'Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 1015 +Handler_read_rnd_next 201 flush status; delete from t2 where a > 600; show status like 'Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 1015 -DROP TABLE IF EXISTS `t2`; +Handler_read_rnd_next 402 +drop table t2; CREATE TABLE `t2` ( `a` int(11) default NULL, `b` int(11) default NULL, diff --git a/mysql-test/r/rpl_multi_update4.result b/mysql-test/r/rpl_multi_update4.result new file mode 100644 index 00000000000..f6dde65a35d --- /dev/null +++ b/mysql-test/r/rpl_multi_update4.result @@ -0,0 +1,25 @@ +stop slave; +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; +start slave; +drop database if exists d1; +drop database if exists d2; +drop database if exists d2; +create database d1; +create table d1.t0 (id int); +create database d2; +use d2; +create table t1 (id int); +create table t2 (id int); +insert into t1 values (1), (2), (3), (4), (5); +insert into t2 select id + 3 from t1; +update t1 join t2 using (id) set t1.id = 0; +insert into d1.t0 values (0); +use d1; +select * from t0 where id=0; +id +0 +drop database d1; +drop database d2; diff --git a/mysql-test/r/rpl_ndb_blob.result b/mysql-test/r/rpl_ndb_blob.result new file mode 100644 index 00000000000..031b489f7da --- /dev/null +++ b/mysql-test/r/rpl_ndb_blob.result @@ -0,0 +1,126 @@ +stop slave; +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; +start slave; +create table t1 ( +a int not null primary key, +b text not null +) engine=ndb; +insert into t1 values(1, repeat('abc',10)); +insert into t1 values(2, repeat('def',200)); +insert into t1 values(3, repeat('ghi',3000)); +select 'M', a, sha1(b) from t1 +order by a; +M a sha1(b) +M 1 8a6c4cf7cf97e66c487c3e3b717e9ae13623d07d +M 2 0ccd08c0fa6ad6a4382b27b1d36586d6ceb4fffa +M 3 75e7b3299e0b776aeac2a4d1542d5b3c0ba2e05e +select 'S', a, sha1(b) from t1 +order by a; +S a sha1(b) +S 1 8a6c4cf7cf97e66c487c3e3b717e9ae13623d07d +S 2 0ccd08c0fa6ad6a4382b27b1d36586d6ceb4fffa +S 3 75e7b3299e0b776aeac2a4d1542d5b3c0ba2e05e +drop table t1; +create table t1 ( +a int not null primary key, +b text not null, +c int, +d longblob, +e tinyblob +) engine=ndbcluster; +insert into t1 values ( +0, repeat(@s2,454), 100, repeat(@s2,345), NULL); +insert into t1 values ( +1, repeat(@s0,504), NULL, repeat(@s1,732), repeat(@s1,1)); +insert into t1 values ( +2, '', 102, '', repeat(@s2,1)); +insert into t1 values ( +3, repeat(@s0,545), 103, repeat(@s2,788), repeat(@s0,1)); +insert into t1 values ( +4, repeat(@s1,38), 104, repeat(@s0,260), repeat(@s0,1)); +insert into t1 values ( +5, repeat(@s2,12), 105, repeat(@s2,40), repeat(@s1,1)); +insert into t1 values ( +6, repeat(@s1,242), 106, NULL, repeat(@s1,1)); +insert into t1 values ( +7, repeat(@s1,30), 107, repeat(@s0,161), ''); +insert into t1 values ( +8, repeat(@s1,719), 108, repeat(@s2,104), NULL); +insert into t1 values ( +9, repeat(@s2,427), NULL, NULL, NULL); +select 'M', a, sha1(b), c, sha1(d), sha1(e) +from t1 order by a; +M a sha1(b) c sha1(d) sha1(e) +M 0 9538f61e649383c0d1054de2a2f0171188129f33 100 2b6515f29c20b8e9e17cc597527e516c0de8d612 NULL +M 1 dcb9a12ca86e718ff2564be041b7c1b3ff5ea559 NULL f23e7439d9a73c3954979b85a7ef6ef35faf4e9d abfe8ae5212b22d023aa6de84beeb1344ac5668a +M 2 da39a3ee5e6b4b0d3255bfef95601890afd80709 102 da39a3ee5e6b4b0d3255bfef95601890afd80709 33deebe47470a40e960834bffa4cdc66790845a6 +M 3 ec8e06d9ac4695d6a898b519ba840590263a9bff 103 278629ad080c3c4377978c006c2e54d0992e43cc 700915801f853603510aeb67b331866d996fdbda +M 4 0392fa8c425d293c79291f0f34779d1101d13fcb 104 5084b602c7203e0e9590a163415ac605da17ac32 700915801f853603510aeb67b331866d996fdbda +M 5 0f9653f0c7a69cd1c617792d546582e974a7a24d 105 566588a04ff26d05160d61c83435292bfda2978e abfe8ae5212b22d023aa6de84beeb1344ac5668a +M 6 a37e8b0ff4fc13a42be02cdecb36186436959bae 106 NULL abfe8ae5212b22d023aa6de84beeb1344ac5668a +M 7 a6bae0cfe6b45ff8c3c12d2ce577a1cd3931190f 107 39ee712b4b9e47f2cf3ba7c9790b2bf0d8f378e8 da39a3ee5e6b4b0d3255bfef95601890afd80709 +M 8 e139adcb7b2974ee7ff227fd405709e5cb7c896c 108 ba8073b0e1a281d4111bd2d82c7722b01574c00b NULL +M 9 1fc5168fe4be566b17b658d94e7813f0b5032cdb NULL NULL NULL +select 'S', a, sha1(b), c, sha1(d), sha1(e) +from t1 order by a; +S a sha1(b) c sha1(d) sha1(e) +S 0 9538f61e649383c0d1054de2a2f0171188129f33 100 2b6515f29c20b8e9e17cc597527e516c0de8d612 NULL +S 1 dcb9a12ca86e718ff2564be041b7c1b3ff5ea559 NULL f23e7439d9a73c3954979b85a7ef6ef35faf4e9d abfe8ae5212b22d023aa6de84beeb1344ac5668a +S 2 da39a3ee5e6b4b0d3255bfef95601890afd80709 102 da39a3ee5e6b4b0d3255bfef95601890afd80709 33deebe47470a40e960834bffa4cdc66790845a6 +S 3 ec8e06d9ac4695d6a898b519ba840590263a9bff 103 278629ad080c3c4377978c006c2e54d0992e43cc 700915801f853603510aeb67b331866d996fdbda +S 4 0392fa8c425d293c79291f0f34779d1101d13fcb 104 5084b602c7203e0e9590a163415ac605da17ac32 700915801f853603510aeb67b331866d996fdbda +S 5 0f9653f0c7a69cd1c617792d546582e974a7a24d 105 566588a04ff26d05160d61c83435292bfda2978e abfe8ae5212b22d023aa6de84beeb1344ac5668a +S 6 a37e8b0ff4fc13a42be02cdecb36186436959bae 106 NULL abfe8ae5212b22d023aa6de84beeb1344ac5668a +S 7 a6bae0cfe6b45ff8c3c12d2ce577a1cd3931190f 107 39ee712b4b9e47f2cf3ba7c9790b2bf0d8f378e8 da39a3ee5e6b4b0d3255bfef95601890afd80709 +S 8 e139adcb7b2974ee7ff227fd405709e5cb7c896c 108 ba8073b0e1a281d4111bd2d82c7722b01574c00b NULL +S 9 1fc5168fe4be566b17b658d94e7813f0b5032cdb NULL NULL NULL +drop table t1; +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 102 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 102 Query 1 239 use `test`; create table t1 ( +a int not null primary key, +b text not null +) engine=ndb +master-bin.000001 239 Query 1 303 BEGIN +master-bin.000001 303 Table_map 1 65 cluster_replication.apply_status +master-bin.000001 368 Write_rows 1 107 +master-bin.000001 410 Table_map 1 147 test.t1 +master-bin.000001 450 Write_rows 1 818 +master-bin.000001 1121 Write_rows 1 9853 +master-bin.000001 10156 Query 1 10221 COMMIT +master-bin.000001 10221 Query 1 10285 BEGIN +master-bin.000001 10285 Table_map 1 65 cluster_replication.apply_status +master-bin.000001 10350 Write_rows 1 107 +master-bin.000001 10392 Query 1 10457 COMMIT +master-bin.000001 10457 Query 1 10533 use `test`; drop table t1 +master-bin.000001 10533 Query 1 10708 use `test`; create table t1 ( +a int not null primary key, +b text not null, +c int, +d longblob, +e tinyblob +) engine=ndbcluster +master-bin.000001 10708 Query 1 10772 BEGIN +master-bin.000001 10772 Table_map 1 65 cluster_replication.apply_status +master-bin.000001 10837 Write_rows 1 107 +master-bin.000001 10879 Table_map 1 150 test.t1 +master-bin.000001 10922 Write_rows 1 48934 +master-bin.000001 59706 Write_rows 1 124436 +master-bin.000001 135208 Write_rows 1 124542 +master-bin.000001 135314 Write_rows 1 205961 +master-bin.000001 216733 Write_rows 1 224245 +master-bin.000001 235017 Write_rows 1 227523 +master-bin.000001 238295 Write_rows 1 242391 +master-bin.000001 253163 Write_rows 1 254087 +master-bin.000001 264859 Write_rows 1 304335 +master-bin.000001 315107 Write_rows 1 330427 +master-bin.000001 341199 Query 1 341264 COMMIT +master-bin.000001 341264 Query 1 341328 BEGIN +master-bin.000001 341328 Table_map 1 65 cluster_replication.apply_status +master-bin.000001 341393 Write_rows 1 107 +master-bin.000001 341435 Query 1 341500 COMMIT +master-bin.000001 341500 Query 1 341576 use `test`; drop table t1 diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 1acb57f67d5..8aa0f445438 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -401,5 +401,18 @@ drop function f1; select * from t1; a 1 +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(col VARCHAR(10)); +CREATE PROCEDURE p1(arg VARCHAR(10)) +INSERT INTO t1 VALUES(arg); +CALL p1('test'); +SELECT * FROM t1; +col +test +SELECT * FROM t1; +col +test +DROP PROCEDURE p1; drop table t1; reset master; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index a74a18375d5..d26f0029001 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1115,3 +1115,22 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function drop function bug11555_1; drop table t1; drop view v1; +drop procedure if exists ` bug15658`; +create procedure ``() select 1; +ERROR 42000: Incorrect routine name '' +create procedure ` `() select 1; +ERROR 42000: Incorrect routine name ' ' +create procedure `bug15658 `() select 1; +ERROR 42000: Incorrect routine name 'bug15658 ' +create procedure ``.bug15658() select 1; +ERROR 42000: Incorrect database name '' +create procedure `x `.bug15658() select 1; +ERROR 42000: Incorrect database name 'x ' +create procedure ` bug15658`() select 1; +call ` bug15658`(); +1 +1 +show procedure status; +Db Name Type Definer Modified Created Security_type Comment +test bug15658 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +drop procedure ` bug15658`; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index 614e670f25d..fbc6d64f9c9 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -263,3 +263,24 @@ CREATE VIEW v1 AS SELECT test.bug12812()| ERROR 42000: execute command denied to user 'user_bug12812'@'localhost' for routine 'test.bug12812' DROP USER user_bug12812@localhost| drop function bug12812| +create database db_bug14834; +create user user1_bug14834@localhost identified by ''; +grant all on `db\_bug14834`.* to user1_bug14834@localhost; +create user user2_bug14834@localhost identified by ''; +grant all on `db\_bug14834`.* to user2_bug14834@localhost; +create user user3_bug14834@localhost identified by ''; +grant all on `db__ug14834`.* to user3_bug14834@localhost; +create procedure p_bug14834() select user(), current_user(); +call p_bug14834(); +user() current_user() +user1_bug14834@localhost user1_bug14834@localhost +call p_bug14834(); +user() current_user() +user2_bug14834@localhost user1_bug14834@localhost +call p_bug14834(); +user() current_user() +user3_bug14834@localhost user1_bug14834@localhost +drop user user1_bug14834@localhost; +drop user user2_bug14834@localhost; +drop user user3_bug14834@localhost; +drop database db_bug14834; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index a025c0503cd..ea4420c8e70 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1178,8 +1178,8 @@ drop view v2| delete from t1 | delete from t2 | drop table t4| -drop table if exists fac| -create table fac (n int unsigned not null primary key, f bigint unsigned)| +drop table if exists t3| +create table t3 (n int unsigned not null primary key, f bigint unsigned)| drop procedure if exists ifac| create procedure ifac(n int unsigned) begin @@ -1189,13 +1189,13 @@ set n = 20; # bigint overflow otherwise end if; while i <= n do begin -insert into test.fac values (i, fac(i)); +insert into test.t3 values (i, fac(i)); set i = i + 1; end; end while; end| call ifac(20)| -select * from fac| +select * from t3| n f 1 1 2 2 @@ -1217,7 +1217,7 @@ n f 18 6402373705728000 19 121645100408832000 20 2432902008176640000 -drop table fac| +drop table t3| show function status like '%f%'| Db Name Type Definer Modified Created Security_type Comment test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER @@ -1225,12 +1225,12 @@ drop procedure ifac| drop function fac| show function status like '%f%'| Db Name Type Definer Modified Created Security_type Comment -drop table if exists primes| -create table primes ( +drop table if exists t3| +create table t3 ( i int unsigned not null primary key, p bigint unsigned not null )| -insert into primes values +insert into t3 values ( 0, 3), ( 1, 5), ( 2, 7), ( 3, 11), ( 4, 13), ( 5, 17), ( 6, 19), ( 7, 23), ( 8, 29), ( 9, 31), (10, 37), (11, 41), (12, 43), (13, 47), (14, 53), @@ -1253,7 +1253,7 @@ set b = b+200, s = 0; else begin declare p bigint unsigned; -select t.p into p from test.primes t where t.i = s; +select t.p into p from test.t3 t where t.i = s; if b+p > r then set pp = 1; leave again; @@ -1278,7 +1278,7 @@ begin declare pp bool default 0; call opp(p, pp); if pp then -insert into test.primes values (i, p); +insert into test.t3 values (i, p); set i = i+1; end if; set p = p+2; @@ -1299,7 +1299,7 @@ set b = b+200, s = 0; else begin declare p bigint unsigned; -select t.p into p from test.primes t where t.i = s; +select t.p into p from test.t3 t where t.i = s; if b+p > r then set pp = 1; leave again; @@ -1318,47 +1318,47 @@ Db Name Type Definer Modified Created Security_type Comment test ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER test opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call ip(200)| -select * from primes where i=45 or i=100 or i=199| +select * from t3 where i=45 or i=100 or i=199| i p 45 211 100 557 199 1229 -drop table primes| +drop table t3| drop procedure opp| drop procedure ip| show procedure status like '%p%'| Db Name Type Definer Modified Created Security_type Comment -drop table if exists fib| -create table fib ( f bigint unsigned not null )| +drop table if exists t3| +create table t3 ( f bigint unsigned not null )| drop procedure if exists fib| create procedure fib(n int unsigned) begin if n > 1 then begin declare x, y bigint unsigned; -declare c cursor for select f from fib order by f desc limit 2; +declare c cursor for select f from t3 order by f desc limit 2; open c; fetch c into y; fetch c into x; close c; -insert into fib values (x+y); +insert into t3 values (x+y); call fib(n-1); end; end if; end| set @@max_sp_recursion_depth= 20| -insert into fib values (0), (1)| +insert into t3 values (0), (1)| call fib(3)| -select * from fib order by f asc| +select * from t3 order by f asc| f 0 1 1 2 -delete from fib| -insert into fib values (0), (1)| -call fib(20)| -select * from fib order by f asc| +delete from t3| +insert into t3 values (0), (1)| +call fib(10)| +select * from t3 order by f asc| f 0 1 @@ -1371,17 +1371,7 @@ f 21 34 55 -89 -144 -233 -377 -610 -987 -1597 -2584 -4181 -6765 -drop table fib| +drop table t3| drop procedure fib| set @@max_sp_recursion_depth= 0| drop procedure if exists bar| diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result index 8f2bd9985fc..e9289cf01c7 100644 --- a/mysql-test/r/sp_trans.result +++ b/mysql-test/r/sp_trans.result @@ -1,4 +1,4 @@ -drop table if exists t1, t2; +drop table if exists t1, t2, t3; drop procedure if exists bug8850| create table t1 (a int) engine=innodb| create procedure bug8850() diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 6094d23b0d0..85976c211c5 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -215,9 +215,9 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from a select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) -8 7.5000 -8 4.5000 -9 7.5000 +8 7.5 +8 4.5 +9 7.5 explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t4 ALL NULL NULL NULL NULL 3 diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 5f801ee71c5..bed5a2d4903 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -46,6 +46,7 @@ db CREATE TABLE `db` ( `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Execute_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Event_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Trigger_priv` enum('N','Y') character set utf8 NOT NULL default 'N', PRIMARY KEY (`Host`,`Db`,`User`), KEY `User` (`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Database privileges' @@ -71,6 +72,7 @@ host CREATE TABLE `host` ( `Create_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Execute_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Trigger_priv` enum('N','Y') character set utf8 NOT NULL default 'N', PRIMARY KEY (`Host`,`Db`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Host privileges; Merged with database privileges' show create table user; @@ -106,6 +108,7 @@ user CREATE TABLE `user` ( `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Create_user_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Event_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Trigger_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') character set utf8 NOT NULL default '', `ssl_cipher` blob NOT NULL, `x509_issuer` blob NOT NULL, @@ -134,7 +137,7 @@ tables_priv CREATE TABLE `tables_priv` ( `Table_name` char(64) collate utf8_bin NOT NULL default '', `Grantor` char(77) collate utf8_bin NOT NULL default '', `Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, - `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') character set utf8 NOT NULL default '', + `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') character set utf8 NOT NULL default '', `Column_priv` set('Select','Insert','Update','References') character set utf8 NOT NULL default '', PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`), KEY `Grantor` (`Grantor`) diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result index 60875d283c1..c3bbc82ef5b 100644 --- a/mysql-test/r/trigger-grant.result +++ b/mysql-test/r/trigger-grant.result @@ -110,109 +110,6 @@ user_str mysqltest_dfn@localhost mysqltest_dfn@localhost ----> connection: default -use mysqltest_db1; -REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; - ----> connection: wl2818_definer_con -use mysqltest_db1; -DROP TRIGGER trg1; -SET @new_sum = 0; -SET @old_sum = 0; ----> INSERT INTO statement; BEFORE timing -CREATE TRIGGER trg1 BEFORE INSERT ON t1 -FOR EACH ROW -SET @new_sum = @new_sum + NEW.num_value; -INSERT INTO t1 VALUES(4); -ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> INSERT INTO statement; AFTER timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 AFTER INSERT ON t1 -FOR EACH ROW -SET @new_sum = @new_sum + NEW.num_value; -INSERT INTO t1 VALUES(5); -ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> UPDATE statement; BEFORE timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 BEFORE UPDATE ON t1 -FOR EACH ROW -SET @old_sum = @old_sum + OLD.num_value; -UPDATE t1 SET num_value = 10; -ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> UPDATE statement; AFTER timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 AFTER UPDATE ON t1 -FOR EACH ROW -SET @new_sum = @new_sum + NEW.num_value; -UPDATE t1 SET num_value = 20; -ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> DELETE statement; BEFORE timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 BEFORE DELETE ON t1 -FOR EACH ROW -SET @old_sum = @old_sum + OLD.num_value; -DELETE FROM t1; -ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> DELETE statement; AFTER timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 AFTER DELETE ON t1 -FOR EACH ROW -SET @old_sum = @old_sum + OLD.num_value; -DELETE FROM t1; -ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' - ----> connection: default -use mysqltest_db1; -GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost; -REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; - ----> connection: wl2818_definer_con -use mysqltest_db1; -DROP TRIGGER trg1; -SET @new_sum = 0; -SET @old_sum = 0; ----> INSERT INTO statement; BEFORE timing -CREATE TRIGGER trg1 BEFORE INSERT ON t1 -FOR EACH ROW -SET @new_sum = @new_sum + NEW.num_value; -INSERT INTO t1 VALUES(4); -ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> INSERT INTO statement; AFTER timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 AFTER INSERT ON t1 -FOR EACH ROW -SET @new_sum = @new_sum + NEW.num_value; -INSERT INTO t1 VALUES(5); -ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> UPDATE statement; BEFORE timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 BEFORE UPDATE ON t1 -FOR EACH ROW -SET @old_sum = @old_sum + OLD.num_value; -UPDATE t1 SET num_value = 10; -ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> UPDATE statement; AFTER timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 AFTER UPDATE ON t1 -FOR EACH ROW -SET @new_sum = @new_sum + NEW.num_value; -UPDATE t1 SET num_value = 20; -ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> DELETE statement; BEFORE timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 BEFORE DELETE ON t1 -FOR EACH ROW -SET @old_sum = @old_sum + OLD.num_value; -DELETE FROM t1; -ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' ----> DELETE statement; AFTER timing -DROP TRIGGER trg1; -CREATE TRIGGER trg1 AFTER DELETE ON t1 -FOR EACH ROW -SET @old_sum = @old_sum + OLD.num_value; -DELETE FROM t1; -ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' - ---> connection: wl2818_definer_con use mysqltest_db1; DROP TRIGGER trg1; @@ -284,3 +181,185 @@ DROP USER mysqltest_inv@localhost; DROP DATABASE mysqltest_db1; Warnings: Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +use mysqltest_db1; +CREATE TABLE t1(col CHAR(20)); +CREATE TABLE t2(col CHAR(20)); +CREATE TABLE t3(col CHAR(20)); +CREATE TABLE t4(col CHAR(20)); +CREATE USER mysqltest_u1@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost; +GRANT TRIGGER ON mysqltest_db1.* TO mysqltest_u1@localhost; +SET @mysqltest_var = NULL; + +---> connection: default +use mysqltest_db1; +GRANT DELETE ON mysqltest_db1.* TO mysqltest_u1@localhost; +SHOW GRANTS FOR mysqltest_u1@localhost; +Grants for mysqltest_u1@localhost +GRANT USAGE ON *.* TO 'mysqltest_u1'@'localhost' +GRANT DELETE, TRIGGER ON `mysqltest_db1`.* TO 'mysqltest_u1'@'localhost' + +---> connection: bug15166_u1_con +use mysqltest_db1; +CREATE TRIGGER t1_trg_after_delete AFTER DELETE ON t1 +FOR EACH ROW +SET @mysqltest_var = 'Hello, world!'; + +---> connection: default +use mysqltest_db1; +GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost; + +---> connection: bug15166_u1_con +use mysqltest_db1; +CREATE TRIGGER t1_trg_err_1 BEFORE INSERT ON t1 +FOR EACH ROW +SET @mysqltest_var = NEW.col; +DROP TRIGGER t1_trg_err_1; +CREATE TRIGGER t1_trg_err_2 BEFORE DELETE ON t1 +FOR EACH ROW +SET @mysqltest_var = OLD.col; +DROP TRIGGER t1_trg_err_2; +CREATE TRIGGER t2_trg_before_insert BEFORE INSERT ON t2 +FOR EACH ROW +SET NEW.col = 't2_trg_before_insert'; +CREATE TRIGGER t3_trg_err_1 BEFORE INSERT ON t3 +FOR EACH ROW +SET @mysqltest_var = NEW.col; +DROP TRIGGER t3_trg_err_1; +CREATE TRIGGER t3_trg_err_2 BEFORE DELETE ON t3 +FOR EACH ROW +SET @mysqltest_var = OLD.col; +DROP TRIGGER t3_trg_err_2; +CREATE TRIGGER t4_trg_before_insert BEFORE INSERT ON t4 +FOR EACH ROW +SET NEW.col = 't4_trg_before_insert'; + +---> connection: default +use mysqltest_db1; +REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost; +REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost; +REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost; +REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost; +GRANT SELECT(col) on mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT SELECT(col) on mysqltest_db1.t4 TO mysqltest_u1@localhost; + +---> connection: bug15166_u1_con +use mysqltest_db1; +CREATE TRIGGER t1_trg_after_insert AFTER INSERT ON t1 +FOR EACH ROW +SET @mysqltest_var = NEW.col; +CREATE TRIGGER t1_trg_after_update AFTER UPDATE ON t1 +FOR EACH ROW +SET @mysqltest_var = OLD.col; +CREATE TRIGGER t2_trg_err_1 BEFORE UPDATE ON t2 +FOR EACH ROW +SET NEW.col = 't2_trg_err_1'; +DROP TRIGGER t2_trg_err_1; +CREATE TRIGGER t2_trg_err_2 BEFORE UPDATE ON t2 +FOR EACH ROW +SET NEW.col = CONCAT(OLD.col, '(updated)'); +DROP TRIGGER t2_trg_err_2; +CREATE TRIGGER t3_trg_after_insert AFTER INSERT ON t3 +FOR EACH ROW +SET @mysqltest_var = NEW.col; +CREATE TRIGGER t3_trg_after_update AFTER UPDATE ON t3 +FOR EACH ROW +SET @mysqltest_var = OLD.col; +CREATE TRIGGER t4_trg_err_1 BEFORE UPDATE ON t4 +FOR EACH ROW +SET NEW.col = 't4_trg_err_1'; +DROP TRIGGER t4_trg_err_1; +CREATE TRIGGER t4_trg_err_2 BEFORE UPDATE ON t4 +FOR EACH ROW +SET NEW.col = CONCAT(OLD.col, '(updated)'); +DROP TRIGGER t4_trg_err_2; + +---> connection: default +use mysqltest_db1; +REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost; +REVOKE SELECT ON mysqltest_db1.t2 FROM mysqltest_u1@localhost; +GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost; +REVOKE SELECT(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost; +REVOKE SELECT(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost; +INSERT INTO t1 VALUES('line1'); +ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't1' +SELECT * FROM t1; +col +line1 +SELECT @mysqltest_var; +@mysqltest_var +NULL +INSERT INTO t2 VALUES('line2'); +SELECT * FROM t2; +col +t2_trg_before_insert +INSERT INTO t3 VALUES('t3_line1'); +ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't3' +SELECT * FROM t3; +col +t3_line1 +SELECT @mysqltest_var; +@mysqltest_var +NULL +INSERT INTO t4 VALUES('t4_line2'); +SELECT * FROM t4; +col +t4_trg_before_insert + +---> connection: default +use mysqltest_db1; +REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost; +REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost; +REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost; +REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost; +GRANT SELECT(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT SELECT(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost; +INSERT INTO t1 VALUES('line3'); +SELECT * FROM t1; +col +line1 +line3 +SELECT @mysqltest_var; +@mysqltest_var +line3 +INSERT INTO t2 VALUES('line4'); +ERROR 42000: UPDATE command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't2' +SELECT * FROM t2; +col +t2_trg_before_insert +INSERT INTO t3 VALUES('t3_line2'); +SELECT * FROM t3; +col +t3_line1 +t3_line2 +SELECT @mysqltest_var; +@mysqltest_var +t3_line2 +INSERT INTO t4 VALUES('t4_line2'); +ERROR 42000: UPDATE command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't4' +SELECT * FROM t4; +col +t4_trg_before_insert +DELETE FROM t1; +SELECT @mysqltest_var; +@mysqltest_var +Hello, world! +DROP USER mysqltest_u1@localhost; +DROP DATABASE mysqltest_db1; diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 352dd55653b..1e5373ba766 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -240,6 +240,28 @@ t3 CREATE TABLE `t3` ( `d` double(22,9) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2, t3; +create table t1 select 105213674794682365.00 + 0.0 x; +show warnings; +Level Code Message +desc t1; +Field Type Null Key Default Extra +x decimal(21,2) unsigned NO 0.00 +drop table t1; +create table t1 select 0.0 x; +desc t1; +Field Type Null Key Default Extra +x decimal(2,1) unsigned NO 0.0 +create table t2 select 105213674794682365.00 y; +desc t2; +Field Type Null Key Default Extra +y decimal(20,2) unsigned NO 0.00 +create table t3 select x+y a from t1,t2; +show warnings; +Level Code Message +desc t3; +Field Type Null Key Default Extra +a decimal(21,2) unsigned NO 0.00 +drop table t1,t2,t3; create table t1 (s1 float(0,2)); ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). create table t1 (s1 float(1,2)); diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result index e3b12cc36e3..e74850bba33 100644 --- a/mysql-test/r/type_varchar.result +++ b/mysql-test/r/type_varchar.result @@ -415,3 +415,10 @@ t1 CREATE TABLE `t1` ( KEY `index1` (`f1`(10)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(f1 VARCHAR(100) DEFAULT 'test'); +INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3)); +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(f1 CHAR(100) DEFAULT 'test'); +INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3)); +DROP TABLE IF EXISTS t1; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 4007fdf406e..fd49bc21ae7 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -28,9 +28,6 @@ rpl_sp : Bug #16456 #ndb_dd_disk2memory : Bug #16466 ndb_autodiscover : Needs to be fixed w.r.t binlog ndb_autodiscover2 : Needs to be fixed w.r.t binlog -ndb_blob : BLOB replication causes core in master1 (Pekka will fix) -system_mysql_db : Needs fixing -system_mysql_db_fix : Needs fixing #ndb_alter_table_row : sometimes wrong error 1015!=1046 ndb_gis : garbled msgs from corrupt THD* ndb_binlog_ddl_multi : Bug #17038 diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test index 7a7b572d58f..fd97f795534 100644 --- a/mysql-test/t/fulltext2.test +++ b/mysql-test/t/fulltext2.test @@ -209,6 +209,14 @@ insert into t1 values('test test '),('test'),('test'),('test'), ('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), ('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'); delete from t1 limit 1; + +# +# BUG#16489: utf8 + fulltext leads to corrupt index file. +# +truncate table t1; +insert into t1 values('ab c d'); +update t1 set a='ab c d'; +select * from t1 where match a against('ab c' in boolean mode); drop table t1; set names latin1; diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 24dd18daab1..9cf0ee452cd 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -121,7 +121,9 @@ drop table t1; # # InnoDB is required to reproduce the fault, but it is okay if we default to # MyISAM when testing. +--disable_warnings create table t1 (a varchar(90), ts datetime not null, index (a)) engine=innodb default charset=utf8; +--enable_warnings insert into t1 values ('http://www.foo.com/', now()); select a from t1 where a='http://www.foo.com/' order by abs(timediff(ts, 0)); drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 7f61b4f080a..36374683e24 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -794,6 +794,29 @@ DROP TABLE t1; DROP VIEW v1; DROP FUNCTION func1; DROP FUNCTION func2; + +# +# Bug #15851 Unlistable directories yield no info from information_schema +# +create database mysqltest; +create table mysqltest.t1(a int); +--exec chmod -r $MYSQL_TEST_DIR/var/master-data/mysqltest +select table_schema from information_schema.tables where table_schema='mysqltest'; +--exec chmod +r $MYSQL_TEST_DIR/var/master-data/mysqltest +drop database mysqltest; + +# +# Bug#15307 GROUP_CONCAT() with ORDER BY returns empty set on information_schema +# +select column_type, group_concat(table_schema, '.', table_name), count(*) as num +from information_schema.columns where +table_schema='information_schema' and +(column_type = 'varchar(7)' or column_type = 'varchar(20)') +group by column_type order by num; + +# +# End of 5.0 tests. +# # Show engines # diff --git a/mysql-test/t/ndb_restore.test b/mysql-test/t/ndb_restore.test index 4a95559c914..f340b62adae 100644 --- a/mysql-test/t/ndb_restore.test +++ b/mysql-test/t/ndb_restore.test @@ -348,7 +348,7 @@ select count(*) select * from t9_c) a; drop table t1_c,t2_c,t3_c,t4_c,t5_c,t6_c,t7_c,t8_c,t9_c; ---exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 2 -n 1 -m -r --ndb-nodegroup_map '(0,1)' $NDB_BACKUP_DIR/BACKUP/BACKUP-2 2>&1 | grep Translate || true +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --core=0 -b 2 -n 1 -m -r --ndb-nodegroup_map '(0,1)' $NDB_BACKUP_DIR/BACKUP/BACKUP-2 2>&1 | grep Translate || true # # Cleanup diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index 55353a1a402..30f4f37ee04 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -269,26 +269,71 @@ insert into t1 values (1,1),(2,2),(3,3); explain partitions select * from t1 where b > 1 and b < 3; explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2); +drop table t1; -# WL# 2986 -DROP TABLE IF EXISTS `t1`; +# Test partition pruning for single-table UPDATE/DELETE. +# TODO: Currently we test only "all partitions pruned away" case. Add more +# tests when the patch that makes use of partition pruning results at +# execution phase is pushed. + +create table t1 (a int) partition by list(a) ( + partition p0 values in (1,2), + partition p1 values in (3,4) +); +insert into t1 values (1),(1),(2),(2),(3),(4),(3),(4); + +# This won't do any table access +flush status; +update t1 set a=100 where a=5; +show status like 'Handler_read_rnd_next'; + +# ... as compared to this, which will scan both partitions +flush status; +update t1 set a=100 where a+1=5+1; +show status like 'Handler_read_rnd_next'; + +# Same as above for DELETE: +flush status; +delete from t1 where a=5; +show status like 'Handler_read_rnd_next'; + +flush status; +delete from t1 where a+1=5+1; +show status like 'Handler_read_rnd_next'; + +# Same as above multi-table UPDATE/DELETE +create table t2 like t1; +insert into t2 select * from t2; + +flush status; +update t1,t2 set t1.a=1000, t2.a=1000 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +# ^ This shows 3 accesses, these are caused by const table reads. +# They should vanish when partition pruning results are used. + +flush status; +delete t1,t2 from t1, t2 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +drop table t1,t2; + +# +# WL#2986 Tests (Checking if partition pruning results are used at query +# execution phase) +# CREATE TABLE `t1` ( `a` int(11) default NULL ); - INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); -DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` ( `a` int(11) default NULL, KEY `a` (`a`) ) ; insert into t2 select A.a + 10*(B.a + 10* C.a) from t1 A, t1 B, t1 C ; - insert into t1 select a from t2; -DROP TABLE IF EXISTS `t2`; +drop table t2; CREATE TABLE `t2` ( `a` int(11) default NULL, `b` int(11) default NULL @@ -331,8 +376,7 @@ flush status; delete from t2 where a > 600; show status like 'Handler_read_rnd_next'; - -DROP TABLE IF EXISTS `t2`; +drop table t2; CREATE TABLE `t2` ( `a` int(11) default NULL, `b` int(11) default NULL, @@ -402,5 +446,6 @@ show status like 'Handler_read_prev'; show status like 'Handler_read_next'; drop table t1, t2; + # No tests for NULLs in RANGE(monotonic_expr()) - they depend on BUG#15447 # being fixed. diff --git a/mysql-test/t/rpl_multi_update4-slave.opt b/mysql-test/t/rpl_multi_update4-slave.opt new file mode 100644 index 00000000000..fea27db43ee --- /dev/null +++ b/mysql-test/t/rpl_multi_update4-slave.opt @@ -0,0 +1 @@ +--replicate-wild-do-table=d1.% diff --git a/mysql-test/t/rpl_multi_update4.test b/mysql-test/t/rpl_multi_update4.test new file mode 100644 index 00000000000..3d909b8e5cd --- /dev/null +++ b/mysql-test/t/rpl_multi_update4.test @@ -0,0 +1,44 @@ +# Let's verify that multi-update is not always skipped by slave if +# some replicate-* rules exist. +# (BUG#15699) + +source include/master-slave.inc; + +### Clean-up + +connection master; +--disable_warnings +drop database if exists d1; +drop database if exists d2; + +connection slave; +drop database if exists d2; +--enable_warnings + +### Test + +connection master; +create database d1; # accepted by slave +create table d1.t0 (id int); +create database d2; # ignored by slave +use d2; +create table t1 (id int); +create table t2 (id int); +insert into t1 values (1), (2), (3), (4), (5); +insert into t2 select id + 3 from t1; +# a problematic query which must be filter out by slave +update t1 join t2 using (id) set t1.id = 0; +insert into d1.t0 values (0); # replication works + +sync_slave_with_master; +use d1; +#connection slave; +select * from t0 where id=0; # must find + +### Clean-up +connection master; +drop database d1; +drop database d2; + + +# End of test diff --git a/mysql-test/t/rpl_ndb_blob.test b/mysql-test/t/rpl_ndb_blob.test new file mode 100644 index 00000000000..c31b629b9f8 --- /dev/null +++ b/mysql-test/t/rpl_ndb_blob.test @@ -0,0 +1,93 @@ +--source include/have_ndb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +# +# basic test of blob replication for NDB +# + +# easy test + +--connection master +create table t1 ( + a int not null primary key, + b text not null +) engine=ndb; + +insert into t1 values(1, repeat('abc',10)); +insert into t1 values(2, repeat('def',200)); +insert into t1 values(3, repeat('ghi',3000)); + +select 'M', a, sha1(b) from t1 +order by a; + +--sync_slave_with_master +--sleep 5 +--connection slave +select 'S', a, sha1(b) from t1 +order by a; + +--connection master +drop table t1; +--sync_slave_with_master + +# hard test + +--connection master +create table t1 ( + a int not null primary key, + b text not null, + c int, + d longblob, + e tinyblob +) engine=ndbcluster; + +--disable_query_log +# length 61 +set @s0 = 'rggurloniukyehuxdbfkkyzlceixzrehqhvxvxbpwizzvjzpucqmzrhzxzfau'; +set @s1 = 'ykyymbzqgqlcjhlhmyqelfoaaohvtbekvifukdtnvcrrjveevfakxarxexomz'; +set @s2 = 'dbnfqyzgtqxalcrwtfsqabknvtfcbpoonxsjiqvmhnfikxxhcgoexlkoezvah'; +--enable_query_log + +insert into t1 values ( + 0, repeat(@s2,454), 100, repeat(@s2,345), NULL); +insert into t1 values ( + 1, repeat(@s0,504), NULL, repeat(@s1,732), repeat(@s1,1)); +insert into t1 values ( + 2, '', 102, '', repeat(@s2,1)); +insert into t1 values ( + 3, repeat(@s0,545), 103, repeat(@s2,788), repeat(@s0,1)); +insert into t1 values ( + 4, repeat(@s1,38), 104, repeat(@s0,260), repeat(@s0,1)); +insert into t1 values ( + 5, repeat(@s2,12), 105, repeat(@s2,40), repeat(@s1,1)); +insert into t1 values ( + 6, repeat(@s1,242), 106, NULL, repeat(@s1,1)); +insert into t1 values ( + 7, repeat(@s1,30), 107, repeat(@s0,161), ''); +insert into t1 values ( + 8, repeat(@s1,719), 108, repeat(@s2,104), NULL); +insert into t1 values ( + 9, repeat(@s2,427), NULL, NULL, NULL); + +select 'M', a, sha1(b), c, sha1(d), sha1(e) +from t1 order by a; + +--sync_slave_with_master +--sleep 5 +--connection slave +select 'S', a, sha1(b), c, sha1(d), sha1(e) +from t1 order by a; + +--connection master +drop table t1; +--sync_slave_with_master + +# +# view the binlog +# + +--connection master +let $VERSION=`select version()`; +--replace_result $VERSION VERSION +show binlog events; diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index 64f99f3d8b9..708a3e0acaa 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -403,6 +403,42 @@ sync_slave_with_master; connection slave; select * from t1; +# +# Bug#16621 "INSERTs in Stored Procedures causes data corruption in the Binary +# Log for 5.0.18" +# + +# Prepare environment. + +connection master; + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +--enable_warnings + +# Test case. + +CREATE TABLE t1(col VARCHAR(10)); + +CREATE PROCEDURE p1(arg VARCHAR(10)) + INSERT INTO t1 VALUES(arg); + +CALL p1('test'); + +SELECT * FROM t1; + +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; + +# Cleanup. + +connection master; + +DROP PROCEDURE p1; + # cleanup connection master; drop table t1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index cabd00fe5f9..d7044bee632 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1534,6 +1534,7 @@ drop procedure bug13012_1| drop function bug13012_2| delimiter ;| +# # BUG#11555 "Stored procedures: current SP tables locking make # impossible view security". We should not expose names of tables # which are implicitly used by view (via stored routines/triggers). @@ -1594,7 +1595,33 @@ drop function bug11555_1; drop table t1; drop view v1; +# +# BUG#15658: Server crashes after creating function as empty string +# +--disable_warnings +drop procedure if exists ` bug15658`; +--enable_warnings +--error ER_SP_WRONG_NAME +create procedure ``() select 1; +--error ER_SP_WRONG_NAME +create procedure ` `() select 1; +--error ER_SP_WRONG_NAME +create procedure `bug15658 `() select 1; +--error ER_WRONG_DB_NAME +create procedure ``.bug15658() select 1; +--error ER_WRONG_DB_NAME +create procedure `x `.bug15658() select 1; + +# This should work +create procedure ` bug15658`() select 1; +call ` bug15658`(); +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +show procedure status; +drop procedure ` bug15658`; + + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 8d4f99abd71..0b24881a056 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -437,4 +437,48 @@ disconnect test_user_12812| DROP USER user_bug12812@localhost| drop function bug12812| delimiter ;| + + +# +# BUG#14834: Server denies to execute Stored Procedure +# +# The problem here was with '_' in the database name. +# +create database db_bug14834; + +create user user1_bug14834@localhost identified by ''; +# The exact name of the database (no wildcard) +grant all on `db\_bug14834`.* to user1_bug14834@localhost; + +create user user2_bug14834@localhost identified by ''; +# The exact name of the database (no wildcard) +grant all on `db\_bug14834`.* to user2_bug14834@localhost; + +create user user3_bug14834@localhost identified by ''; +# Wildcards in the database name +grant all on `db__ug14834`.* to user3_bug14834@localhost; + +connect (user1_bug14834,localhost,user1_bug14834,,db_bug14834); +# Create the procedure and check that we can call it +create procedure p_bug14834() select user(), current_user(); +call p_bug14834(); + +connect (user2_bug14834,localhost,user2_bug14834,,db_bug14834); +# This didn't work before +call p_bug14834(); + +connect (user3_bug14834,localhost,user3_bug14834,,db_bug14834); +# Should also work +call p_bug14834(); + +# Cleanup +connection default; +disconnect user1_bug14834; +disconnect user2_bug14834; +disconnect user3_bug14834; +drop user user1_bug14834@localhost; +drop user user2_bug14834@localhost; +drop user user3_bug14834@localhost; +drop database db_bug14834; + # End of 5.0 bugs. diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 836d24340ef..02772313d01 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1419,9 +1419,9 @@ drop table t4| # fac --disable_warnings -drop table if exists fac| +drop table if exists t3| --enable_warnings -create table fac (n int unsigned not null primary key, f bigint unsigned)| +create table t3 (n int unsigned not null primary key, f bigint unsigned)| --disable_warnings drop procedure if exists ifac| @@ -1435,15 +1435,15 @@ begin end if; while i <= n do begin - insert into test.fac values (i, fac(i)); + insert into test.t3 values (i, fac(i)); set i = i + 1; end; end while; end| call ifac(20)| -select * from fac| -drop table fac| +select * from t3| +drop table t3| --replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show function status like '%f%'| drop procedure ifac| @@ -1455,15 +1455,15 @@ show function status like '%f%'| # primes --disable_warnings -drop table if exists primes| +drop table if exists t3| --enable_warnings -create table primes ( +create table t3 ( i int unsigned not null primary key, p bigint unsigned not null )| -insert into primes values +insert into t3 values ( 0, 3), ( 1, 5), ( 2, 7), ( 3, 11), ( 4, 13), ( 5, 17), ( 6, 19), ( 7, 23), ( 8, 29), ( 9, 31), (10, 37), (11, 41), (12, 43), (13, 47), (14, 53), @@ -1492,7 +1492,7 @@ begin begin declare p bigint unsigned; - select t.p into p from test.primes t where t.i = s; + select t.p into p from test.t3 t where t.i = s; if b+p > r then set pp = 1; leave again; @@ -1523,7 +1523,7 @@ begin call opp(p, pp); if pp then - insert into test.primes values (i, p); + insert into test.t3 values (i, p); set i = i+1; end if; set p = p+2; @@ -1545,8 +1545,8 @@ call ip(200)| # 45 211 # 100 557 # 199 1229 -select * from primes where i=45 or i=100 or i=199| -drop table primes| +select * from t3 where i=45 or i=100 or i=199| +drop table t3| drop procedure opp| drop procedure ip| --replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' @@ -1556,9 +1556,9 @@ show procedure status like '%p%'| # Fibonacci, for recursion test. (Yet Another Numerical series :) # --disable_warnings -drop table if exists fib| +drop table if exists t3| --enable_warnings -create table fib ( f bigint unsigned not null )| +create table t3 ( f bigint unsigned not null )| # We deliberately do it the awkward way, fetching the last two # values from the table, in order to exercise various statements @@ -1571,13 +1571,13 @@ begin if n > 1 then begin declare x, y bigint unsigned; - declare c cursor for select f from fib order by f desc limit 2; + declare c cursor for select f from t3 order by f desc limit 2; open c; fetch c into y; fetch c into x; close c; - insert into fib values (x+y); + insert into t3 values (x+y); call fib(n-1); end; end if; @@ -1588,22 +1588,23 @@ set @@max_sp_recursion_depth= 20| # Minimum test: recursion of 3 levels -insert into fib values (0), (1)| +insert into t3 values (0), (1)| call fib(3)| -select * from fib order by f asc| +select * from t3 order by f asc| -delete from fib| +delete from t3| -# Original test: 20 levels (may run into memory limits!) +# The original test, 20 levels, ran into memory limits on some machines +# and builds. Try 10 instead... -insert into fib values (0), (1)| +insert into t3 values (0), (1)| -call fib(20)| +call fib(10)| -select * from fib order by f asc| -drop table fib| +select * from t3 order by f asc| +drop table t3| drop procedure fib| set @@max_sp_recursion_depth= 0| diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test index 308d4ad5c33..b9bd4c938b3 100644 --- a/mysql-test/t/sp_trans.test +++ b/mysql-test/t/sp_trans.test @@ -5,7 +5,7 @@ -- source include/have_innodb.inc --disable_warnings -drop table if exists t1, t2; +drop table if exists t1, t2, t3; --enable_warnings delimiter |; diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test index dfa3c3687f5..dc863bd8e32 100644 --- a/mysql-test/t/trigger-grant.test +++ b/mysql-test/t/trigger-grant.test @@ -8,8 +8,6 @@ # # Tests for WL#2818: # - Check that triggers are executed under the authorization of the definer. -# - Check that if trigger contains NEW/OLD variables, the definer must have -# SELECT privilege on the subject table. # - Check DEFINER clause of CREATE TRIGGER statement; # - Check that SUPER privilege required to create a trigger with different # definer. @@ -18,6 +16,8 @@ # - Check that the definer of a trigger does not exist, the trigger will # not be activated. # - Check that SHOW TRIGGERS statement provides "Definer" column. +# - Check that if trigger contains NEW/OLD variables, the definer must have +# SELECT privilege on the subject table (aka BUG#15166/BUG#15196). # # Let's also check that user name part of definer can contain '@' symbol (to # check that triggers are not affected by BUG#13310 "incorrect user parsing @@ -254,223 +254,6 @@ INSERT INTO t1 VALUES(3); SELECT * FROM t1; SELECT * FROM t2; -# -# Check that if trigger contains NEW/OLD variables, the definer must have -# SELECT/UPDATE privilege on the subject table: -# - drop the trigger; -# - create a new trigger, which will use NEW variable; -# - create another new trigger, which will use OLD variable; -# - revoke SELECT/UPDATE privilege on the first table from "definer"; -# - insert a row into the first table; -# - analyze error code; -# - -# -# SELECT privilege. -# - ---connection default ---echo ---echo ---> connection: default - -use mysqltest_db1; - -REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; - ---connection wl2818_definer_con ---echo ---echo ---> connection: wl2818_definer_con - -use mysqltest_db1; - -DROP TRIGGER trg1; - -SET @new_sum = 0; -SET @old_sum = 0; - -# INSERT INTO statement; BEFORE timing - ---echo ---> INSERT INTO statement; BEFORE timing - -CREATE TRIGGER trg1 BEFORE INSERT ON t1 - FOR EACH ROW - SET @new_sum = @new_sum + NEW.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -INSERT INTO t1 VALUES(4); - -# INSERT INTO statement; AFTER timing - ---echo ---> INSERT INTO statement; AFTER timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 AFTER INSERT ON t1 - FOR EACH ROW - SET @new_sum = @new_sum + NEW.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -INSERT INTO t1 VALUES(5); - -# UPDATE statement; BEFORE timing - ---echo ---> UPDATE statement; BEFORE timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 BEFORE UPDATE ON t1 - FOR EACH ROW - SET @old_sum = @old_sum + OLD.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -UPDATE t1 SET num_value = 10; - -# UPDATE statement; AFTER timing - ---echo ---> UPDATE statement; AFTER timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 AFTER UPDATE ON t1 - FOR EACH ROW - SET @new_sum = @new_sum + NEW.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -UPDATE t1 SET num_value = 20; - -# DELETE statement; BEFORE timing - ---echo ---> DELETE statement; BEFORE timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 BEFORE DELETE ON t1 - FOR EACH ROW - SET @old_sum = @old_sum + OLD.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -DELETE FROM t1; - -# DELETE statement; AFTER timing - ---echo ---> DELETE statement; AFTER timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 AFTER DELETE ON t1 - FOR EACH ROW - SET @old_sum = @old_sum + OLD.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -DELETE FROM t1; - -# -# UPDATE privilege -# -# NOTE: At the moment, UPDATE privilege is required if the trigger contains -# NEW/OLD variables, whenever the trigger modifies them or not. Moreover, -# UPDATE privilege is checked for whole table, not for individual columns. -# -# The following test cases should be changed when full support of UPDATE -# privilege will be done. -# - ---connection default ---echo ---echo ---> connection: default - -use mysqltest_db1; - -GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost; -REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; - ---connection wl2818_definer_con ---echo ---echo ---> connection: wl2818_definer_con - -use mysqltest_db1; - -DROP TRIGGER trg1; - -SET @new_sum = 0; -SET @old_sum = 0; - -# INSERT INTO statement; BEFORE timing - ---echo ---> INSERT INTO statement; BEFORE timing - -CREATE TRIGGER trg1 BEFORE INSERT ON t1 - FOR EACH ROW - SET @new_sum = @new_sum + NEW.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -INSERT INTO t1 VALUES(4); - -# INSERT INTO statement; AFTER timing - ---echo ---> INSERT INTO statement; AFTER timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 AFTER INSERT ON t1 - FOR EACH ROW - SET @new_sum = @new_sum + NEW.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -INSERT INTO t1 VALUES(5); - -# UPDATE statement; BEFORE timing - ---echo ---> UPDATE statement; BEFORE timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 BEFORE UPDATE ON t1 - FOR EACH ROW - SET @old_sum = @old_sum + OLD.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -UPDATE t1 SET num_value = 10; - -# UPDATE statement; AFTER timing - ---echo ---> UPDATE statement; AFTER timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 AFTER UPDATE ON t1 - FOR EACH ROW - SET @new_sum = @new_sum + NEW.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -UPDATE t1 SET num_value = 20; - -# DELETE statement; BEFORE timing - ---echo ---> DELETE statement; BEFORE timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 BEFORE DELETE ON t1 - FOR EACH ROW - SET @old_sum = @old_sum + OLD.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -DELETE FROM t1; - -# DELETE statement; AFTER timing - ---echo ---> DELETE statement; AFTER timing - -DROP TRIGGER trg1; - -CREATE TRIGGER trg1 AFTER DELETE ON t1 - FOR EACH ROW - SET @old_sum = @old_sum + OLD.num_value; - ---error ER_TABLEACCESS_DENIED_ERROR -DELETE FROM t1; - # # Check DEFINER clause of CREATE TRIGGER statement. # @@ -603,3 +386,310 @@ DROP USER mysqltest_dfn@localhost; DROP USER mysqltest_inv@localhost; DROP DATABASE mysqltest_db1; + + +########################################################################### +# +# BUG#15166: Wrong update [was: select/update] permissions required to execute +# triggers. +# +# BUG#15196: Wrong select permission required to execute triggers. +# +########################################################################### + +# +# Prepare environment. +# + +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; + +use mysqltest_db1; + +# Tables for tesing table-level privileges: +CREATE TABLE t1(col CHAR(20)); # table for "read-value" trigger +CREATE TABLE t2(col CHAR(20)); # table for "write-value" trigger + +# Tables for tesing column-level privileges: +CREATE TABLE t3(col CHAR(20)); # table for "read-value" trigger +CREATE TABLE t4(col CHAR(20)); # table for "write-value" trigger + +CREATE USER mysqltest_u1@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost; +GRANT TRIGGER ON mysqltest_db1.* TO mysqltest_u1@localhost; + +SET @mysqltest_var = NULL; + +--connect (bug15166_u1_con,localhost,mysqltest_u1,,mysqltest_db1) + +# parsing (CREATE TRIGGER) time: +# - check that nor SELECT either UPDATE is required to execute triggger w/o +# NEW/OLD variables. + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +GRANT DELETE ON mysqltest_db1.* TO mysqltest_u1@localhost; +SHOW GRANTS FOR mysqltest_u1@localhost; + +--connection bug15166_u1_con +--echo +--echo ---> connection: bug15166_u1_con + +use mysqltest_db1; + +CREATE TRIGGER t1_trg_after_delete AFTER DELETE ON t1 + FOR EACH ROW + SET @mysqltest_var = 'Hello, world!'; + +# parsing (CREATE TRIGGER) time: +# - check that UPDATE is not enough to read the value; +# - check that UPDATE is required to modify the value; + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost; + +GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost; + +--connection bug15166_u1_con +--echo +--echo ---> connection: bug15166_u1_con + +use mysqltest_db1; + +# - table-level privileges + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t1_trg_err_1 BEFORE INSERT ON t1 + FOR EACH ROW + SET @mysqltest_var = NEW.col; +DROP TRIGGER t1_trg_err_1; + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t1_trg_err_2 BEFORE DELETE ON t1 + FOR EACH ROW + SET @mysqltest_var = OLD.col; +DROP TRIGGER t1_trg_err_2; + +CREATE TRIGGER t2_trg_before_insert BEFORE INSERT ON t2 + FOR EACH ROW + SET NEW.col = 't2_trg_before_insert'; + +# - column-level privileges + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t3_trg_err_1 BEFORE INSERT ON t3 + FOR EACH ROW + SET @mysqltest_var = NEW.col; +DROP TRIGGER t3_trg_err_1; + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t3_trg_err_2 BEFORE DELETE ON t3 + FOR EACH ROW + SET @mysqltest_var = OLD.col; +DROP TRIGGER t3_trg_err_2; + +CREATE TRIGGER t4_trg_before_insert BEFORE INSERT ON t4 + FOR EACH ROW + SET NEW.col = 't4_trg_before_insert'; + +# parsing (CREATE TRIGGER) time: +# - check that SELECT is required to read the value; +# - check that SELECT is not enough to modify the value; + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost; +REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost; + +REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost; +REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost; +GRANT SELECT(col) on mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT SELECT(col) on mysqltest_db1.t4 TO mysqltest_u1@localhost; + +--connection bug15166_u1_con +--echo +--echo ---> connection: bug15166_u1_con + +use mysqltest_db1; + +# - table-level privileges + +CREATE TRIGGER t1_trg_after_insert AFTER INSERT ON t1 + FOR EACH ROW + SET @mysqltest_var = NEW.col; + +CREATE TRIGGER t1_trg_after_update AFTER UPDATE ON t1 + FOR EACH ROW + SET @mysqltest_var = OLD.col; + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t2_trg_err_1 BEFORE UPDATE ON t2 + FOR EACH ROW + SET NEW.col = 't2_trg_err_1'; +DROP TRIGGER t2_trg_err_1; + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t2_trg_err_2 BEFORE UPDATE ON t2 + FOR EACH ROW + SET NEW.col = CONCAT(OLD.col, '(updated)'); +DROP TRIGGER t2_trg_err_2; + +# - column-level privileges + +CREATE TRIGGER t3_trg_after_insert AFTER INSERT ON t3 + FOR EACH ROW + SET @mysqltest_var = NEW.col; + +CREATE TRIGGER t3_trg_after_update AFTER UPDATE ON t3 + FOR EACH ROW + SET @mysqltest_var = OLD.col; + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t4_trg_err_1 BEFORE UPDATE ON t4 + FOR EACH ROW + SET NEW.col = 't4_trg_err_1'; +DROP TRIGGER t4_trg_err_1; + +# TODO: check privileges at CREATE TRIGGER time. +# --error ER_COLUMNACCESS_DENIED_ERROR +CREATE TRIGGER t4_trg_err_2 BEFORE UPDATE ON t4 + FOR EACH ROW + SET NEW.col = CONCAT(OLD.col, '(updated)'); +DROP TRIGGER t4_trg_err_2; + +# execution time: +# - check that UPDATE is not enough to read the value; +# - check that UPDATE is required to modify the value; + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost; +REVOKE SELECT ON mysqltest_db1.t2 FROM mysqltest_u1@localhost; +GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost; + +REVOKE SELECT(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost; +REVOKE SELECT(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost; + +# - table-level privileges + +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES('line1'); + +SELECT * FROM t1; +SELECT @mysqltest_var; + +INSERT INTO t2 VALUES('line2'); + +SELECT * FROM t2; + +# - column-level privileges + +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t3 VALUES('t3_line1'); + +SELECT * FROM t3; +SELECT @mysqltest_var; + +INSERT INTO t4 VALUES('t4_line2'); + +SELECT * FROM t4; + +# execution time: +# - check that SELECT is required to read the value; +# - check that SELECT is not enough to modify the value; + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost; +REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost; +GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost; + +REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost; +REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost; +GRANT SELECT(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost; +GRANT SELECT(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost; + +# - table-level privileges + +INSERT INTO t1 VALUES('line3'); + +SELECT * FROM t1; +SELECT @mysqltest_var; + +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES('line4'); + +SELECT * FROM t2; + +# - column-level privileges + +INSERT INTO t3 VALUES('t3_line2'); + +SELECT * FROM t3; +SELECT @mysqltest_var; + +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t4 VALUES('t4_line2'); + +SELECT * FROM t4; + +# execution time: +# - check that nor SELECT either UPDATE is required to execute triggger w/o +# NEW/OLD variables. + +DELETE FROM t1; + +SELECT @mysqltest_var; + +# +# Cleanup. +# + +DROP USER mysqltest_u1@localhost; + +DROP DATABASE mysqltest_db1; diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 6a0814ef113..79f29624e89 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -159,6 +159,23 @@ show create table t3; drop table t1, t2, t3; +# +# Bug #9855 (inconsistent column type for create select +# +create table t1 select 105213674794682365.00 + 0.0 x; +show warnings; +desc t1; +drop table t1; + +create table t1 select 0.0 x; +desc t1; +create table t2 select 105213674794682365.00 y; +desc t2; +create table t3 select x+y a from t1,t2; +show warnings; +desc t3; +drop table t1,t2,t3; + # End of 4.1 tests # diff --git a/mysql-test/t/type_varchar.test b/mysql-test/t/type_varchar.test index 1a3a93018a4..2d2314f0a29 100644 --- a/mysql-test/t/type_varchar.test +++ b/mysql-test/t/type_varchar.test @@ -130,3 +130,19 @@ show create table t1; alter table t1 modify f1 tinytext; show create table t1; drop table t1; + +# +# BUG#15588: String overrun +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(f1 VARCHAR(100) DEFAULT 'test'); +INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3)); +DROP TABLE IF EXISTS t1; + +CREATE TABLE t1(f1 CHAR(100) DEFAULT 'test'); +INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3)); +DROP TABLE IF EXISTS t1; diff --git a/mysys/default_modify.c b/mysys/default_modify.c index de03d783c68..0f58b8a930c 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -197,7 +197,7 @@ int modify_defaults_file(const char *file_location, const char *option, goto err; } if (my_fclose(cnf_file, MYF(MY_WME))) - goto err; + DBUG_RETURN(1); my_free(file_buffer, MYF(0)); DBUG_RETURN(0); diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 1f3db84304e..e181ccfb88d 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -79,7 +79,7 @@ my_off_t my_b_safe_tell(IO_CACHE *info) void my_b_seek(IO_CACHE *info,my_off_t pos) { - my_off_t offset; + my_off_t offset; DBUG_ENTER("my_b_seek"); DBUG_PRINT("enter",("pos: %lu", (ulong) pos)); @@ -91,10 +91,10 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) b) see if there is a better way to make it work */ if (info->type == SEQ_READ_APPEND) - flush_io_cache(info); - + VOID(flush_io_cache(info)); + offset=(pos - info->pos_in_file); - + if (info->type == READ_CACHE || info->type == SEQ_READ_APPEND) { /* TODO: explain why this works if pos < info->pos_in_file */ @@ -119,7 +119,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) info->write_pos = info->write_buffer + offset; DBUG_VOID_RETURN; } - flush_io_cache(info); + VOID(flush_io_cache(info)); /* Correct buffer end so that we write in increments of IO_SIZE */ info->write_end=(info->write_buffer+info->buffer_length- (pos & (IO_SIZE-1))); diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index b4865557d80..91575d66368 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -114,7 +114,7 @@ my_bool bitmap_init(MY_BITMAP *map, uint32 *buf, uint n_bits, #endif ; if (!(buf= (uint32*) my_malloc(size_in_bytes, MYF(MY_WME)))) - return 1; + DBUG_RETURN(1); } #ifdef THREAD else diff --git a/mysys/my_error.c b/mysys/my_error.c index 0c18bbf6e8b..d7177e7a047 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -189,7 +189,10 @@ int my_error_register(const char **errmsgs, int first, int last) /* Error numbers must be unique. No overlapping is allowed. */ if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last)) + { + my_free((gptr)meh_p, MYF(0)); return 1; + } /* Insert header into the chain. */ meh_p->meh_next= *search_meh_pp; diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 1908c70f407..4ca343064d3 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -170,6 +170,8 @@ MY_DIR *my_dir(const char *path, myf MyFlags) bzero(finfo.mystat, sizeof(MY_STAT)); VOID(strmov(tmp_file,dp->d_name)); VOID(my_stat(tmp_path, finfo.mystat, MyFlags)); + if (!(finfo.mystat->st_mode & MY_S_IREAD)) + continue; } else finfo.mystat= NULL; diff --git a/netware/BUILD/compile-AUTOTOOLS b/netware/BUILD/compile-AUTOTOOLS index 57213b1b3d0..20e506aa683 100755 --- a/netware/BUILD/compile-AUTOTOOLS +++ b/netware/BUILD/compile-AUTOTOOLS @@ -6,7 +6,7 @@ # stop on errors set -e -for package in . ./innobase +for package in . ./storage/innobase do (cd $package rm -rf config.cache autom4te.cache diff --git a/netware/BUILD/compile-linux-tools b/netware/BUILD/compile-linux-tools index fab92b8d4df..02c11998365 100755 --- a/netware/BUILD/compile-linux-tools +++ b/netware/BUILD/compile-linux-tools @@ -37,11 +37,11 @@ make (cd dbug; make libdbug.a) (cd strings; make libmystrings.a) (cd mysys; make libmysys.a) -(cd heap; make libheap.a) +(cd storage/heap; make libheap.a) (cd vio; make libvio.a) (cd regex; make libregex.a) -(cd myisam; make libmyisam.a) -(cd myisammrg; make libmyisammrg.a) +(cd storage/myisam; make libmyisam.a) +(cd storage/myisammrg; make libmyisammrg.a) (cd extra; make comp_err) (cd libmysql; make conf_to_src) (cd libmysql_r; make conf_to_src) @@ -57,7 +57,7 @@ make cp extra/comp_err extra/comp_err.linux cp libmysql/conf_to_src libmysql/conf_to_src.linux #cp libmysql_r/conf_to_src libmysql_r/conf_to_src.linux -cp sql/.libs/gen_lex_hash sql/gen_lex_hash.linux +cp sql/gen_lex_hash sql/gen_lex_hash.linux cp strings/conf_to_src strings/conf_to_src.linux # Delete mysql_version.h diff --git a/netware/BUILD/compile-netware-END b/netware/BUILD/compile-netware-END index f7da0d9596e..0bb4e808b63 100755 --- a/netware/BUILD/compile-netware-END +++ b/netware/BUILD/compile-netware-END @@ -22,9 +22,8 @@ rm -rf Makefile.in.bk . $path/compile-AUTOTOOLS # For NetWare there is no comp_err but comp_err.linux -sed -e "s/comp_err/comp_err.linux/g" extra/Makefile.am > extra/Makefile.am.$$ -sed -e "s/replace comp_err.linux/replace comp_err/g" extra/Makefile.am.$$ > extra/Makefile.am -rm extra/Makefile.am.$$ +sed -e "s/comp_err\$(EXEEXT)/comp_err.linux/g" extra/Makefile.am > extra/Makefile.am.$$ +mv extra/Makefile.am.$$ extra/Makefile.am # configure ./configure $base_configs $extra_configs diff --git a/netware/BUILD/mwenv b/netware/BUILD/mwenv index fa52568fcd6..b88b6347668 100755 --- a/netware/BUILD/mwenv +++ b/netware/BUILD/mwenv @@ -4,10 +4,10 @@ # This values are normally changed by the nwbootstrap script # the default is "F:/mydev" -export MYDEV="F:/mydev" +export MYDEV=WINE_BUILD_DIR -export MWCNWx86Includes="$MYDEV/libc/include;$MYDEV/fs64/headers;$MYDEV/zlib-1.1.4;$MYDEV/mysql-VERSION/include;$MYDEV" -export MWNWx86Libraries="$MYDEV/libc/imports;$MYDEV/mw/lib;$MYDEV/fs64/imports;$MYDEV/zlib-1.1.4;$MYDEV/openssl;$MYDEV/mysql-VERSION/netware/BUILD" +export MWCNWx86Includes="$MYDEV/libc/include;$MYDEV/fs64/headers;$MYDEV/zlib-1.2.3;$MYDEV/mysql-VERSION/include;$MYDEV" +export MWNWx86Libraries="$MYDEV/libc/imports;$MYDEV/mw/lib;$MYDEV/fs64/imports;$MYDEV/zlib-1.2.3;$MYDEV/openssl;$MYDEV/mysql-VERSION/netware/BUILD" export MWNWx86LibraryFiles="libcpre.o;libc.imp;netware.imp;mwcrtl.lib;mwcpp.lib;libz.a;neb.imp;zPublics.imp;knetware.imp" export WINEPATH="$MYDEV/mw/bin" diff --git a/netware/BUILD/nwbootstrap b/netware/BUILD/nwbootstrap index 48ff2a49667..22e1569e7ca 100755 --- a/netware/BUILD/nwbootstrap +++ b/netware/BUILD/nwbootstrap @@ -160,6 +160,11 @@ sed -e "s;WINE_BUILD_DIR;$wine_build_dir;g" \ -e "s;VERSION;$version;g" $mwenv.org > $mwenv chmod +rwx $mwenv +PWD=`pwd` +SRC_DIR=`grep "^export MYDEV=" $mwenv | cut -d'=' -f2 | \ + sed -e 's;";;g' -e "s;^;echo ;g" -e "s;$;/\`basename $PWD\`;g" | /bin/sh` + + # edit the def file versions echo "updating *.def file versions..." nlm_version=`echo "$version" | sed -e "s;\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*;\1, \2, \3;"` @@ -167,13 +172,14 @@ nlm_version=`echo "$version" | sed -e "s;\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*;\1 for file in ./netware/*.def do mv -f $file $file.org - sed -e "s;VERSION.*;VERSION $nlm_version;g" $file.org > $file + sed -e "s;VERSION.*;VERSION $nlm_version;g" \ + -e "s;XDCDATA.*;XDCDATA $SRC_DIR/netware/mysql.xdc;g" $file.org > $file rm $file.org done # create the libmysql.imp file in netware folder from libmysql/libmysql.def # file -echo "generating llibmysql.imp file..." +echo "generating libmysql.imp file..." awk 'BEGIN{x=0;} END{printf("\n");} x==1 {printf(" %s",$1); x++; next} x>1 {printf(",\n %s", $1);next} /EXPORTS/{x=1}' libmysql/libmysql.def > netware/libmysql.imp # build linux tools echo "compiling linux tools..." diff --git a/netware/Makefile.am b/netware/Makefile.am index fdf4023aef2..e1c2eedc2b7 100644 --- a/netware/Makefile.am +++ b/netware/Makefile.am @@ -30,13 +30,16 @@ netware_build_files = client/mysql.def client/mysqladmin.def \ client/mysqldump.def client/mysqlimport.def \ client/mysqlshow.def client/mysqltest.def \ client/mysqlslap.def \ + sql/mysqld.def extra/mysql_waitpid.def \ extra/mysql_install.def extra/my_print_defaults.def \ extra/perror.def extra/replace.def \ extra/resolveip.def extra/comp_err.def \ - libmysqld/libmysqld.def myisam/myisamchk.def \ - myisam/myisamlog.def myisam/myisampack.def \ - sql/mysqld.def extra/mysql_waitpid.def \ - extra/resolve_stack_dump.def myisam/myisam_ftdump.def + extra/resolve_stack_dump.def \ + libmysqld/libmysqld.def \ + storage/myisam/myisamchk.def \ + storage/myisam/myisamlog.def \ + storage/myisam/myisampack.def \ + storage/myisam/myisam_ftdump.def link_sources: set -x; \ diff --git a/netware/my_manage.h b/netware/my_manage.h index 480eefbe55a..360f2f104be 100644 --- a/netware/my_manage.h +++ b/netware/my_manage.h @@ -54,7 +54,8 @@ bool skip_first_param; #define ARG_BUF 10 -#define TRY_MAX 5 +#define TRY_MAX 5 +#define NULL (char) 0 #ifdef __NETWARE__ #define strstr(A,B) strindex(A,B) diff --git a/netware/mysql_test_run.c b/netware/mysql_test_run.c index 6bab2f0149c..9b02f897a60 100644 --- a/netware/mysql_test_run.c +++ b/netware/mysql_test_run.c @@ -1189,7 +1189,7 @@ void setup(char *file) ******************************************************************************/ int main(int argc, char **argv) { - int is_ignore_list = 0; + int is_ignore_list= 0, autoclose= 0, individual_execution= 0; // setup setup(argv[0]); @@ -1236,16 +1236,22 @@ int main(int argc, char **argv) { int i; - // single test - single_test = TRUE; - for (i = 1 + is_ignore_list; i < argc; i++) { + if (!strncasecmp(argv[i], "--autoclose", 11)) + { + autoclose= 1; + continue; + } + // single test + single_test= TRUE; + individual_execution= 1; + // run given test run_test(argv[i]); } } - else + if (!individual_execution) { // run all tests DIR *dir = opendir(test_dir); @@ -1297,7 +1303,8 @@ int main(int argc, char **argv) if (log_fd) fclose(log_fd); // keep results up - pressanykey(); + if (!autoclose) + pressanykey(); return 0; } diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index f1ed07382b6..2f59c3e1d4c 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -129,8 +129,8 @@ copyfileto $BASE COPYING COPYING.LIB README Docs/INSTALL-BINARY \ BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \ extra/resolveip$BS extra/my_print_defaults$BS \ extra/resolve_stack_dump$BS extra/mysql_waitpid$BS \ - myisam/myisamchk$BS myisam/myisampack$BS myisam/myisamlog$BS \ - myisam/myisam_ftdump$BS \ + storage/myisam/myisamchk$BS storage/myisam/myisampack$BS \ + storage/myisam/myisamlog$BS storage/myisam/myisam_ftdump$BS \ sql/mysqld$BS sql/mysql_tzinfo_to_sql$BS \ server-tools/instance-manager/mysqlmanager$BS \ client/mysql$BS client/mysqlshow$BS client/mysqladmin$BS \ diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 73b4ce32640..0fbaf7bec8a 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -674,5 +674,9 @@ ALTER TABLE event ADD sql_mode SET @hadTriggerPriv := 0; SELECT @hadTriggerPriv :=1 FROM user WHERE Trigger_priv LIKE '%'; -ALTER TABLE user add Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE user ADD Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Event_priv; +ALTER TABLE host ADD Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE db ADD Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE tables_priv MODIFY Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') COLLATE utf8_general_ci DEFAULT '' NOT NULL; + UPDATE user SET Trigger_priv=Super_priv WHERE @hadTriggerPriv = 0; diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc index d83af2b9cf0..a79a6ad6742 100644 --- a/server-tools/instance-manager/parse.cc +++ b/server-tools/instance-manager/parse.cc @@ -107,7 +107,7 @@ Token shift_token(const char **text, uint *word_len) int get_text_id(const char **text, uint *word_len, const char **id) { get_word(text, word_len); - if (word_len == 0) + if (*word_len == 0) return 1; *id= *text; return 0; diff --git a/sql-common/client.c b/sql-common/client.c index 5d0370d950a..2d826df0662 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -599,7 +599,7 @@ net_safe_read(MYSQL *mysql) DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", vio_description(net->vio),len)); #ifdef MYSQL_SERVER - if (vio_was_interrupted(net->vio)) + if (net->vio && vio_was_interrupted(net->vio)) return (packet_error); #endif /*MYSQL_SERVER*/ end_server(mysql); diff --git a/sql/field.cc b/sql/field.cc index 37cab37f7d2..3d983bb4d12 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1565,7 +1565,6 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table, bool Field::quote_data(String *unquoted_string) { char escaped_string[IO_SIZE]; - char *unquoted_string_buffer= (char *)(unquoted_string->ptr()); DBUG_ENTER("Field::quote_data"); if (!needs_quotes()) @@ -4545,8 +4544,6 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) error= 1; } } - if (error > 1) - error= 2; #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -5880,7 +5877,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) field_length/ field_charset->mbmaxlen, &well_formed_error); - memcpy(ptr,from,copy_length); + memmove(ptr, from, copy_length); /* Append spaces if the string was shorter than the field. */ if (copy_length < field_length) @@ -6296,7 +6293,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) field_length/ field_charset->mbmaxlen, &well_formed_error); - memcpy(ptr + length_bytes, from, copy_length); + memmove(ptr + length_bytes, from, copy_length); if (length_bytes == 1) *ptr= (uchar) copy_length; else @@ -7113,7 +7110,7 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type) } get_ptr(&blob); gobj= Geometry::construct(&buffer, blob, blob_length); - if (gobj->get_mbr(&mbr, &dummy)) + if (!gobj || gobj->get_mbr(&mbr, &dummy)) bzero(buff, SIZEOF_STORED_DOUBLE*4); else { @@ -7442,7 +7439,7 @@ void Field_geom::get_key_image(char *buff, uint length, imagetype type) } get_ptr(&blob); gobj= Geometry::construct(&buffer, blob, blob_length); - if (gobj->get_mbr(&mbr, &dummy)) + if (!gobj || gobj->get_mbr(&mbr, &dummy)) bzero(buff, SIZEOF_STORED_DOUBLE*4); else { @@ -8239,16 +8236,13 @@ const char *Field_bit::unpack(char *to, const char *from) */ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - uchar *bit_ptr_arg, uchar bit_ofs_arg, - enum utype unireg_check_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) - :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, bit_ptr_arg, - bit_ofs_arg, unireg_check_arg, field_name_arg), + :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, 0, + unireg_check_arg, field_name_arg), create_length(len_arg) { - bit_ptr= 0; - bit_ofs= 0; bit_len= 0; field_length= ((len_arg + 7) & ~7) / 8; } @@ -8950,10 +8944,10 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length, field_charset); case FIELD_TYPE_BIT: return f_bit_as_char(pack_flag) ? - new Field_bit_as_char(ptr, field_length, null_pos, null_bit, - bit_ptr, bit_offset, unireg_check, field_name) : - new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr, - bit_offset, unireg_check, field_name); + new Field_bit_as_char(ptr, field_length, null_pos, null_bit, + unireg_check, field_name) : + new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr, + bit_offset, unireg_check, field_name); default: // Impossible (Wrong version) break; diff --git a/sql/field.h b/sql/field.h index 806d0c3328a..15c54f65ef7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1373,12 +1373,12 @@ public: } }; - + class Field_bit_as_char: public Field_bit { public: uchar create_length; Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, + uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg); enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } uint32 max_length() { return (uint32) create_length; } diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 65049bac135..2a2ac475c0b 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -139,6 +139,10 @@ static HASH archive_open_tables; /* Static declarations for handerton */ static handler *archive_create_handler(TABLE_SHARE *table); +/* + Number of rows that will force a bulk insert. +*/ +#define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2 /* dummy handlerton - only to have something to return from archive_db_init */ @@ -1302,7 +1306,8 @@ void ha_archive::info(uint flag) void ha_archive::start_bulk_insert(ha_rows rows) { DBUG_ENTER("ha_archive::start_bulk_insert"); - bulk_insert= TRUE; + if (!rows || rows >= ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT) + bulk_insert= TRUE; DBUG_VOID_RETURN; } diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2e785f13ea3..5f0adba6e8c 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -286,7 +286,8 @@ int ha_myisam::dump(THD* thd, int fd) if (fd < 0) { - my_net_write(net, "", 0); + if (my_net_write(net, "", 0)) + error = errno ? errno : EPIPE; net_flush(net); } @@ -420,12 +421,14 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) { uint old_testflag=param.testflag; param.testflag|=T_MEDIUM; - init_io_cache(¶m.read_cache, file->dfile, - my_default_record_cache_size, READ_CACHE, - share->pack.header_length, 1, MYF(MY_WME)); - error |= chk_data_link(¶m, file, param.testflag & T_EXTEND); - end_io_cache(&(param.read_cache)); - param.testflag=old_testflag; + if (!(error= init_io_cache(¶m.read_cache, file->dfile, + my_default_record_cache_size, READ_CACHE, + share->pack.header_length, 1, MYF(MY_WME)))) + { + error= chk_data_link(¶m, file, param.testflag & T_EXTEND); + end_io_cache(&(param.read_cache)); + } + param.testflag= old_testflag; } } if (!error) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index dc513087638..0518fbd9abe 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -840,51 +840,51 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, { Field *field= table->field[i]; NdbValue value= value_array[i]; - if (value.ptr != NULL && (field->flags & BLOB_FLAG)) + if (! (field->flags & BLOB_FLAG)) + continue; + if (value.blob == NULL) { - Field_blob *field_blob= (Field_blob *)field; - NdbBlob *ndb_blob= value.blob; - int isNull; - ndb_blob->getDefined(isNull); - if (isNull == 0) { // XXX -1 should be allowed only for events - Uint64 blob_len= 0; - if (ndb_blob->getLength(blob_len) != 0) - DBUG_RETURN(-1); - // Align to Uint64 - uint32 blob_size= blob_len; - if (blob_size % 8 != 0) - blob_size+= 8 - blob_size % 8; - if (loop == 1) - { - char *buf= buffer + offset; - uint32 len= 0xffffffff; // Max uint32 - DBUG_PRINT("info", ("read blob ptr=%p len=%u", - buf, (uint) blob_len)); - if (ndb_blob->readData(buf, len) != 0) - DBUG_RETURN(-1); - DBUG_PRINT("info", ("blob field %d offset=%u len=%u [ptrdiff=%d]", - i, offset, len, (int)ptrdiff)); - DBUG_ASSERT(len == blob_len); - // Ugly hack assumes only ptr needs to be changed - field_blob->ptr+= ptrdiff; - field_blob->set_ptr(len, buf); - field_blob->ptr-= ptrdiff; - } - offset+= blob_size; - } - else + DBUG_PRINT("info",("[%u] skipped", i)); + continue; + } + Field_blob *field_blob= (Field_blob *)field; + NdbBlob *ndb_blob= value.blob; + int isNull; + if (ndb_blob->getNull(isNull) != 0) + ERR_RETURN(ndb_blob->getNdbError()); + if (isNull == 0) { + Uint64 len64= 0; + if (ndb_blob->getLength(len64) != 0) + ERR_RETURN(ndb_blob->getNdbError()); + // Align to Uint64 + uint32 size= len64; + if (size % 8 != 0) + size+= 8 - size % 8; + if (loop == 1) { - if (loop == 1) - { - // have to set length even in this case - char *buf= buffer + offset; - uint32 len= 0; - field_blob->ptr+= ptrdiff; - field_blob->set_ptr(len, buf); - field_blob->ptr-= ptrdiff; - DBUG_PRINT("info", ("blob field %d isNull=%d", i, isNull)); - } + char *buf= buffer + offset; + uint32 len= 0xffffffff; // Max uint32 + if (ndb_blob->readData(buf, len) != 0) + ERR_RETURN(ndb_blob->getNdbError()); + DBUG_PRINT("info", ("[%u] offset=%u buf=%p len=%u [ptrdiff=%d]", + i, offset, buf, len, (int)ptrdiff)); + DBUG_ASSERT(len == len64); + // Ugly hack assumes only ptr needs to be changed + field_blob->ptr+= ptrdiff; + field_blob->set_ptr(len, buf); + field_blob->ptr-= ptrdiff; } + offset+= size; + } + else if (loop == 1) // undefined or null + { + // have to set length even in this case + char *buf= buffer + offset; // or maybe NULL + uint32 len= 0; + field_blob->ptr+= ptrdiff; + field_blob->set_ptr(len, buf); + field_blob->ptr-= ptrdiff; + DBUG_PRINT("info", ("[%u] isNull=%d", i, isNull)); } } if (loop == 0 && offset > buffer_size) @@ -4770,13 +4770,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) "Creating event for logging table failed. " "See error log for details."); } - if (is_old_table_tmpfile) - ndbcluster_log_schema_op(current_thd, share, - current_thd->query, current_thd->query_length, - m_dbname, new_tabname, - 0, 0, - SOT_ALTER_TABLE); - else + if (!is_old_table_tmpfile) ndbcluster_log_schema_op(current_thd, share, current_thd->query, current_thd->query_length, m_dbname, new_tabname, diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 5ce5fa79d89..0fa9daa66b4 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -441,6 +441,7 @@ ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command, break; case LOGCOM_ALTER_TABLE: type= SOT_ALTER_TABLE; + log= 1; break; case LOGCOM_RENAME_TABLE: type= SOT_RENAME_TABLE; @@ -461,8 +462,10 @@ ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command, break; } if (log) + { ndbcluster_log_schema_op(thd, 0, query, query_length, db, table_name, 0, 0, type); + } DBUG_VOID_RETURN; } @@ -891,6 +894,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, } char tmp_buf2[FN_REFLEN]; + int get_a_share= 0; switch (type) { case SOT_DROP_TABLE: @@ -900,13 +904,15 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, /* redo the drop table query as is may contain several tables */ query= tmp_buf2; query_length= (uint) (strxmov(tmp_buf2, "drop table `", - table_name, "`", NullS) - tmp_buf2); - break; + table_name, "`", NullS) - tmp_buf2); + // fall through case SOT_CREATE_TABLE: - break; + // fall through case SOT_RENAME_TABLE: - break; + // fall through case SOT_ALTER_TABLE: + if (!share) + get_a_share= 1; break; case SOT_DROP_DB: break; @@ -922,6 +928,14 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, abort(); /* should not happen, programming error */ } + if (get_a_share) + { + char key[FN_REFLEN]; + (void)strxnmov(key, FN_REFLEN, share_prefix, db, + "/", table_name, NullS); + share= get_share(key, 0, false, false); + } + const NdbError *ndb_error= 0; uint32 node_id= g_ndb_cluster_connection->node_id(); Uint64 epoch= 0; @@ -956,7 +970,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, } Ndb *ndb= thd_ndb->ndb; - char old_db[128]; + char old_db[FN_REFLEN]; strcpy(old_db, ndb->getDatabaseName()); char tmp_buf[SCHEMA_QUERY_SIZE]; @@ -974,9 +988,8 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, strcmp(NDB_SCHEMA_TABLE, table_name)) { ndb_error= &dict->getNdbError(); - goto end; } - DBUG_RETURN(0); + goto end; } { @@ -1119,6 +1132,10 @@ end: } (void) pthread_mutex_unlock(&share->mutex); } + + if (get_a_share) + free_share(&share); + DBUG_RETURN(0); } @@ -1328,7 +1345,10 @@ static int ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, NdbEventOperation *pOp, List - *schema_list, MEM_ROOT *mem_root) + *post_epoch_log_list, + List + *post_epoch_unlock_list, + MEM_ROOT *mem_root) { DBUG_ENTER("ndb_binlog_thread_handle_schema_event"); NDB_SHARE *share= (NDB_SHARE *)pOp->getCustomData(); @@ -1357,7 +1377,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, { case SOT_DROP_TABLE: /* binlog dropping table after any table operations */ - schema_list->push_back(schema, mem_root); + post_epoch_log_list->push_back(schema, mem_root); log_query= 0; break; case SOT_RENAME_TABLE: @@ -1389,7 +1409,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, TRUE, /* print error */ TRUE); /* don't binlog the query */ /* binlog dropping database after any table operations */ - schema_list->push_back(schema, mem_root); + post_epoch_log_list->push_back(schema, mem_root); log_query= 0; break; case SOT_CREATE_DB: @@ -1431,7 +1451,18 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, { DBUG_DUMP("slock", (char*)schema->slock, schema->slock_length); if (bitmap_is_set(&slock, node_id)) - ndbcluster_update_slock(thd, schema->db, schema->name); + { + /* + If it is an SOT_ALTER_TABLE we need to acknowledge the + schema operation _after_ all the events have been + processed so that all schema events coming through + the event operation has been processed + */ + if ((enum SCHEMA_OP_TYPE)schema->type == SOT_ALTER_TABLE) + post_epoch_unlock_list->push_back(schema, mem_root); + else + ndbcluster_update_slock(thd, schema->db, schema->name); + } } if (log_query) @@ -2084,6 +2115,20 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, DBUG_PRINT("info", ("%s blob", col_name)); attr0.blob= op->getBlobHandle(col_name); attr1.blob= op->getPreBlobHandle(col_name); + if (attr0.blob == NULL || attr1.blob == NULL) + { + sql_print_error("NDB Binlog: Creating NdbEventOperation" + " blob field %u handles failed (code=%d) for %s", + j, op->getNdbError().code, event_name); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_GET_ERRMSG, ER(ER_GET_ERRMSG), + op->getNdbError().code, + op->getNdbError().message, + "NDB"); + ndb->dropEventOperation(op); + pthread_mutex_unlock(&injector_mutex); + DBUG_RETURN(-1); + } } } else @@ -2724,7 +2769,8 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) MEM_ROOT *old_root= *root_ptr; MEM_ROOT mem_root; init_sql_alloc(&mem_root, 4096, 0); - List schema_list; + List post_epoch_log_list; + List post_epoch_unlock_list; *root_ptr= &mem_root; if (unlikely(schema_res > 0)) @@ -2737,7 +2783,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) { if (!pOp->hasError()) ndb_binlog_thread_handle_schema_event(thd, schema_ndb, pOp, - &schema_list, &mem_root); + &post_epoch_log_list, + &post_epoch_unlock_list, + &mem_root); else sql_print_error("NDB: error %lu (%s) on handling " "binlog schema event", @@ -2864,9 +2912,17 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) } } + /* + process any operations that should be done after + the epoch is complete + */ { Cluster_replication_schema *schema; - while ((schema= schema_list.pop())) + while ((schema= post_epoch_unlock_list.pop())) + { + ndbcluster_update_slock(thd, schema->db, schema->name); + } + while ((schema= post_epoch_log_list.pop())) { char *thd_db_save= thd->db; thd->db= schema->db; diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h index 4739c77a1bd..a297f80f6ab 100644 --- a/sql/ha_ndbcluster_binlog.h +++ b/sql/ha_ndbcluster_binlog.h @@ -29,18 +29,24 @@ extern ulong ndb_extra_logging; #define INJECTOR_EVENT_LEN 200 +/* + The numbers below must not change as they + are passed between mysql servers, and if changed + would break compatablility. Add new numbers to + the end. +*/ enum SCHEMA_OP_TYPE { - SOT_DROP_TABLE, - SOT_CREATE_TABLE, - SOT_RENAME_TABLE, - SOT_ALTER_TABLE, - SOT_DROP_DB, - SOT_CREATE_DB, - SOT_ALTER_DB, - SOT_CLEAR_SLOCK, - SOT_TABLESPACE, - SOT_LOGFILE_GROUP + SOT_DROP_TABLE= 0, + SOT_CREATE_TABLE= 1, + SOT_RENAME_TABLE= 2, + SOT_ALTER_TABLE= 3, + SOT_DROP_DB= 4, + SOT_CREATE_DB= 5, + SOT_ALTER_DB= 6, + SOT_CLEAR_SLOCK= 7, + SOT_TABLESPACE= 8, + SOT_LOGFILE_GROUP= 9 }; const uint max_ndb_nodes= 64; /* multiple of 32 */ diff --git a/sql/handler.cc b/sql/handler.cc index b40a40684fe..24e9f6aa1e2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2529,12 +2529,11 @@ struct binlog_log_query_st const char *table_name; }; -static my_bool binlog_log_query_handlerton(THD *thd, - st_plugin_int *plugin, - void *args) +static my_bool binlog_log_query_handlerton2(THD *thd, + const handlerton *hton, + void *args) { struct binlog_log_query_st *b= (struct binlog_log_query_st*)args; - handlerton *hton= (handlerton *) plugin->plugin->info; if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query) hton->binlog_log_query(thd, b->binlog_command, @@ -2545,7 +2544,15 @@ static my_bool binlog_log_query_handlerton(THD *thd, return FALSE; } -void ha_binlog_log_query(THD *thd, enum_binlog_command binlog_command, +static my_bool binlog_log_query_handlerton(THD *thd, + st_plugin_int *plugin, + void *args) +{ + return binlog_log_query_handlerton2(thd, (const handlerton *) plugin->plugin->info, args); +} + +void ha_binlog_log_query(THD *thd, const handlerton *hton, + enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name) { @@ -2555,8 +2562,11 @@ void ha_binlog_log_query(THD *thd, enum_binlog_command binlog_command, b.query_length= query_length; b.db= db; b.table_name= table_name; - plugin_foreach(thd, binlog_log_query_handlerton, - MYSQL_STORAGE_ENGINE_PLUGIN, &b); + if (hton == 0) + plugin_foreach(thd, binlog_log_query_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, &b); + else + binlog_log_query_handlerton2(thd, hton, &b); } #endif diff --git a/sql/handler.h b/sql/handler.h index 80395d9fb50..de4623b39b9 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2020,7 +2020,8 @@ int ha_repl_report_replication_stop(THD *thd); int ha_reset_logs(THD *thd); int ha_binlog_index_purge_file(THD *thd, const char *file); void ha_reset_slave(THD *thd); -void ha_binlog_log_query(THD *thd, enum_binlog_command binlog_command, +void ha_binlog_log_query(THD *thd, const handlerton *db_type, + enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name); void ha_binlog_wait(THD *thd); diff --git a/sql/item.cc b/sql/item.cc index fa5c2b5cc3b..3bc11102667 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -985,7 +985,7 @@ Item_case_expr::this_item_addr(THD *thd, Item **) void Item_case_expr::print(String *str) { - str->append(STRING_WITH_LEN("case_expr@")); + VOID(str->append(STRING_WITH_LEN("case_expr@"))); str->qs_append(m_case_expr_id); } @@ -3868,7 +3868,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) name); break; case MYSQL_TYPE_BIT: - field= new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0, + field= new Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, name); break; default: @@ -5257,6 +5257,7 @@ void Item_insert_value::print(String *str) setup_field() thd - current thread context table - table of trigger (and where we looking for fields) + table_grant_info - GRANT_INFO of the subject table NOTE This function does almost the same as fix_fields() for Item_field @@ -5270,7 +5271,8 @@ void Item_insert_value::print(String *str) table of trigger which uses this item. */ -void Item_trigger_field::setup_field(THD *thd, TABLE *table) +void Item_trigger_field::setup_field(THD *thd, TABLE *table, + GRANT_INFO *table_grant_info) { bool save_set_query_id= thd->set_query_id; @@ -5284,6 +5286,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table) 0, &field_idx); thd->set_query_id= save_set_query_id; triggers= table->triggers; + table_grants= table_grant_info; } @@ -5302,22 +5305,42 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) Since trigger is object tightly associated with TABLE object most of its set up can be performed during trigger loading i.e. trigger parsing! So we have little to do in fix_fields. :) - FIXME may be we still should bother about permissions here. */ + DBUG_ASSERT(fixed == 0); + /* Set field. */ + if (field_idx != (uint)-1) { +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* + Check access privileges for the subject table. We check privileges only + in runtime. + */ + + if (table_grants) + { + table_grants->want_privilege= + access_type == AT_READ ? SELECT_ACL : UPDATE_ACL; + + if (check_grant_column(thd, table_grants, triggers->table->s->db.str, + triggers->table->s->table_name.str, field_name, + strlen(field_name), thd->security_ctx)) + return TRUE; + } +#endif // NO_EMBEDDED_ACCESS_CHECKS + field= (row_version == OLD_ROW) ? triggers->old_field[field_idx] : triggers->new_field[field_idx]; set_field(field); fixed= 1; - return 0; + return FALSE; } my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name, (row_version == NEW_ROW) ? "NEW" : "OLD"); - return 1; + return TRUE; } diff --git a/sql/item.h b/sql/item.h index fa2c1b53426..030b2c40b4a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2172,6 +2172,8 @@ public: /* Is this item represents row from NEW or OLD row ? */ enum row_version_type {OLD_ROW, NEW_ROW}; row_version_type row_version; + /* Is this item used for reading or updating the value? */ + enum access_types { AT_READ = 0x1, AT_UPDATE = 0x2 }; /* Next in list of all Item_trigger_field's in trigger */ Item_trigger_field *next_trg_field; /* Index of the field in the TABLE::field array */ @@ -2181,18 +2183,24 @@ public: Item_trigger_field(Name_resolution_context *context_arg, row_version_type row_ver_arg, - const char *field_name_arg) + const char *field_name_arg, + access_types access_type_arg) :Item_field(context_arg, (const char *)NULL, (const char *)NULL, field_name_arg), - row_version(row_ver_arg), field_idx((uint)-1) + row_version(row_ver_arg), field_idx((uint)-1), + access_type(access_type_arg), table_grants(NULL) {} - void setup_field(THD *thd, TABLE *table); + void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); enum Type type() const { return TRIGGER_FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); void print(String *str); table_map used_tables() const { return (table_map)0L; } void cleanup(); + +private: + access_types access_type; + GRANT_INFO *table_grants; }; diff --git a/sql/item_func.cc b/sql/item_func.cc index c4c03e1cbf2..60b0dafefc5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -431,12 +431,19 @@ my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value) void Item_func::fix_num_length_and_dec() { - decimals= 0; + uint fl_length= 0; + decimals=0; for (uint i=0 ; i < arg_count ; i++) { - set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(decimals,args[i]->decimals); + set_if_bigger(fl_length, args[i]->max_length); + } + max_length=float_length(decimals); + if (fl_length > max_length) + { + decimals= NOT_FIXED_DEC; + max_length= float_length(NOT_FIXED_DEC); } - max_length= float_length(decimals); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 15eb4c3aaf0..64a692d394d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3342,6 +3342,10 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) case INSERT_ID_EVENT: msg="INSERT_ID"; break; + case INVALID_INT_EVENT: + default: // cannot happen + msg="INVALID_INT"; + break; } fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); fflush(file); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f5b93e6a5e5..be476c11533 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -134,6 +134,13 @@ int deny_severity = LOG_WARNING; #define zVOLSTATE_DEACTIVE 2 #define zVOLSTATE_MAINTENANCE 3 +#undef __event_h__ +#include <../include/event.h> +/* + This #undef exists here because both libc of NetWare and MySQL have + files named event.h which causes compilation errors. +*/ + #include #include #include @@ -3305,6 +3312,10 @@ server."); mysql_bin_log.purge_logs_before_date(purge_time); } #endif +#ifdef __NETWARE__ + /* Increasing stacksize of threads on NetWare */ + pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE); +#endif if (opt_myisam_log) (void) mi_log(1); @@ -3538,7 +3549,6 @@ int main(int argc, char **argv) #endif #ifdef __NETWARE__ /* Increasing stacksize of threads on NetWare */ - pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE); #endif @@ -5120,7 +5130,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, "Set to 0 (write and flush once per second), 1 (write and flush at each commit) or 2 (write at commit, flush once per second).", (gptr*) &innobase_flush_log_at_trx_commit, (gptr*) &innobase_flush_log_at_trx_commit, - 0, GET_UINT, OPT_ARG, 1, 0, 2, 0, 0, 0}, + 0, GET_ULONG, OPT_ARG, 1, 0, 2, 0, 0, 0}, {"innodb_flush_method", OPT_INNODB_FLUSH_METHOD, "With which method to flush data.", (gptr*) &innobase_unix_file_flush_method, (gptr*) &innobase_unix_file_flush_method, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 9e20fa28239..887690aecc1 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -753,7 +753,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, bool allow_null_cond, int *error) - { SQL_SELECT *select; DBUG_ENTER("make_select"); @@ -7059,10 +7058,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, if (!quick) return 0; /* no ranges found */ if (quick->init()) - { - delete quick; goto err; - } quick->records= records; if (cp_buffer_from_ref(thd,ref) && thd->is_fatal_error || @@ -8404,7 +8400,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) ha_rows cur_records; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; - uint cur_param_idx; + uint cur_param_idx=MAX_KEY; key_map cur_used_key_parts; uint pk= param->table->s->primary_key; @@ -8620,6 +8616,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) { + DBUG_ASSERT(tree != 0 || cur_param_idx == MAX_KEY); index_info= cur_index_info; index= cur_index; best_read_cost= cur_read_cost; diff --git a/sql/opt_range.h b/sql/opt_range.h index a27b3607d73..bc2496b0769 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -706,7 +706,7 @@ class SQL_SELECT :public Sql_alloc { class FT_SELECT: public QUICK_RANGE_SELECT { public: FT_SELECT(THD *thd, TABLE *table, uint key) : - QUICK_RANGE_SELECT (thd, table, key, 1) { init(); } + QUICK_RANGE_SELECT (thd, table, key, 1) { VOID(init()); } ~FT_SELECT() { file->ft_end(); } int init() { return error=file->ft_init(); } int reset() { return 0; } diff --git a/sql/protocol.cc b/sql/protocol.cc index 98cded56871..650bd8fc58f 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -601,9 +601,23 @@ bool Protocol::send_fields(List *list, uint flags) else { /* With conversion */ + uint max_char_len; int2store(pos, thd_charset->number); - uint char_len= field.length / item->collation.collation->mbmaxlen; - int4store(pos+2, char_len * thd_charset->mbmaxlen); + /* + For TEXT/BLOB columns, field_length describes the maximum data + length in bytes. There is no limit to the number of characters + that a TEXT column can store, as long as the data fits into + the designated space. + For the rest of textual columns, field_length is evaluated as + char_count * mbmaxlen, where character count is taken from the + definition of the column. In other words, the maximum number + of characters here is limited by the column definition. + */ + max_char_len= (field.type >= (int) MYSQL_TYPE_TINY_BLOB && + field.type <= (int) MYSQL_TYPE_BLOB) ? + field.length / item->collation.collation->mbminlen : + field.length / item->collation.collation->mbmaxlen; + int4store(pos+2, max_char_len * thd_charset->mbmaxlen); } pos[6]= field.type; int2store(pos+7,field.flags); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 960e0ac86cc..34dcd80a236 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -930,7 +930,8 @@ bool load_master_data(THD* thd) host was specified; there could have been a problem when replication started, which led to relay log's IO_CACHE to not be inited. */ - flush_master_info(active_mi, 0); + if (flush_master_info(active_mi, 0)) + sql_print_error("Failed to flush master info file"); } mysql_free_result(master_status_res); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 1a86cd1aef7..a6c2fca7fc5 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -215,8 +215,9 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout", &delayed_insert_timeout); sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); -sys_var_event_executor sys_event_executor("event_scheduler", - (my_bool *)&event_executor_running_global_var); +sys_var_event_executor sys_event_executor("event_scheduler", + (my_bool *) + &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", &expire_logs_days); sys_var_bool_ptr sys_flush("flush", &myisam_flush); @@ -2495,7 +2496,6 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var) bool sys_var_sync_binlog_period::update(THD *thd, set_var *var) { - pthread_mutex_t *lock_log= mysql_bin_log.get_log_lock(); sync_binlog_period= (ulong) var->save_result.ulonglong_value; return 0; } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 2e8eb285a01..346393041e9 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5798,3 +5798,5 @@ ER_CANT_WRITE_LOCK_LOG_TABLE eng "You can't write-lock a log table. Only read access is possible." ER_CANT_READ_LOCK_LOG_TABLE eng "You can't use usual read lock with log tables. Try READ LOCAL instead." +ER_SP_WRONG_NAME 42000 + eng "Incorrect routine name '%-.64s'" diff --git a/sql/slave.cc b/sql/slave.cc index edca614159a..763db31c05d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1742,7 +1742,8 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi) " to the relay log, " "SHOW SLAVE STATUS may be inaccurate"); rli->relay_log.harvest_bytes_written(&rli->log_space_total); - flush_master_info(mi, 1); + if (flush_master_info(mi, 1)) + sql_print_error("Failed to flush master info file"); delete ev; } else @@ -2233,7 +2234,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); - + if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(TRUE); } @@ -2241,8 +2242,13 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) DBUG_RETURN(FALSE); } - -bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) +/* + RETURN + 2 - flush relay log failed + 1 - flush master info failed + 0 - all ok +*/ +int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) { IO_CACHE* file = &mi->file; char lbuf[22]; @@ -2261,8 +2267,9 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) When we come to this place in code, relay log may or not be initialized; the caller is responsible for setting 'flush_relay_log_cache' accordingly. */ - if (flush_relay_log_cache) - flush_io_cache(mi->rli.relay_log.get_log_file()); + if (flush_relay_log_cache && + flush_io_cache(mi->rli.relay_log.get_log_file())) + DBUG_RETURN(2); /* We flushed the relay log BEFORE the master.info file, because if we crash @@ -2274,13 +2281,13 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) */ /* - In certain cases this code may create master.info files that seems - corrupted, because of extra lines filled with garbage in the end - file (this happens if new contents take less space than previous - contents of file). But because of number of lines in the first line + In certain cases this code may create master.info files that seems + corrupted, because of extra lines filled with garbage in the end + file (this happens if new contents take less space than previous + contents of file). But because of number of lines in the first line of file we don't care about this garbage. */ - + my_b_seek(file, 0L); my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n", LINES_IN_MASTER_INFO_WITH_SSL, @@ -2289,8 +2296,7 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key); - flush_io_cache(file); - DBUG_RETURN(0); + DBUG_RETURN(-flush_io_cache(file)); } @@ -3355,7 +3361,11 @@ reconnect done to recover from failed read"); sql_print_error("Slave I/O thread could not queue event from master"); goto err; } - flush_master_info(mi, 1); /* sure that we can flush the relay log */ + if (flush_master_info(mi, 1)) + { + sql_print_error("Failed to flush master info file"); + goto err; + } /* See if the relay logs take too much space. We don't lock mi->rli.log_space_lock here; this dirty read saves time diff --git a/sql/slave.h b/sql/slave.h index 6870aaca752..0b77d7f7c4f 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -231,7 +231,7 @@ int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); int init_slave(); void init_slave_skip_errors(const char* arg); -bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache); +int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache); bool flush_relay_log_info(RELAY_LOG_INFO* rli); int register_slave_on_master(MYSQL* mysql); int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e1af0b7d939..e4e87eb5620 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -105,21 +105,27 @@ sp_get_item_value(Item *item, String *str) case STRING_RESULT: { - char buf_holder[STRING_BUFFER_USUAL_SIZE]; - String buf(buf_holder, sizeof(buf_holder), &my_charset_latin1); String *result= item->val_str(str); if (!result) return NULL; - buf.append('_'); - buf.append(result->charset()->csname); - buf.append('\''); - buf.append(*result); - buf.append('\''); - str->copy(buf); + { + char buf_holder[STRING_BUFFER_USUAL_SIZE]; + String buf(buf_holder, sizeof(buf_holder), result->charset()); - return str; + /* We must reset length of the buffer, because of String specificity. */ + buf.length(0); + + buf.append('_'); + buf.append(result->charset()->csname); + buf.append('\''); + buf.append(*result); + buf.append('\''); + str->copy(buf); + + return str; + } } case ROW_RESULT: @@ -389,6 +395,23 @@ sp_name_current_db_new(THD *thd, LEX_STRING name) return qname; } +/* + Check that the name 'ident' is ok. It's assumed to be an 'ident' + from the parser, so we only have to check length and trailing spaces. + The former is a standard requirement (and 'show status' assumes a + non-empty name), the latter is a mysql:ism as trailing spaces are + removed by get_field(). + + RETURN + TRUE - bad name + FALSE - name is ok +*/ + +bool +check_routine_name(LEX_STRING ident) +{ + return (!ident.str || !ident.str[0] || ident.str[ident.length-1] == ' '); +} /* ------------------------------------------------------------------ */ @@ -3083,9 +3106,16 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) void sp_instr_set_case_expr::print(String *str) { - str->append(STRING_WITH_LEN("set_case_expr ")); + const char CASE_EXPR_TAG[]= "set_case_expr "; + const int CASE_EXPR_TAG_LEN= sizeof(CASE_EXPR_TAG) - 1; + const int INT_STRING_MAX_LEN= 10; + + /* We must call reserve(), because qs_append() doesn't care about memory. */ + str->reserve(CASE_EXPR_TAG_LEN + INT_STRING_MAX_LEN + 2); + + str->qs_append(CASE_EXPR_TAG, CASE_EXPR_TAG_LEN); str->qs_append(m_case_expr_id); - str->append(' '); + str->qs_append(' '); m_case_expr->print(str); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 37ab486c6f3..c4b6cb36090 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -103,6 +103,8 @@ public: sp_name * sp_name_current_db_new(THD *thd, LEX_STRING name); +bool +check_routine_name(LEX_STRING name); class sp_head :private Query_arena { diff --git a/sql/spatial.h b/sql/spatial.h index 4253689c078..527dc750bdc 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -142,7 +142,7 @@ struct MBR bool inner_point(double x, double y) const { /* The following should be safe, even if we compare doubles */ - return (xminx) && (yminx); + return (xminx) && (yminy); } int overlaps(const MBR *mbr) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index dc56880a1a0..cfcdd6d9e61 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -951,7 +951,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'", (host ? host : "(NULL)"), (ip ? ip : "(NULL)"), - (user ? user : "(NULL)"), (db ? db : "(NULL)"))); + user, (db ? db : "(NULL)"))); sctx->user= user; sctx->host= host; sctx->ip= ip; @@ -980,7 +980,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, for (i=0 ; i < acl_users.elements ; i++) { acl_user= dynamic_element(&acl_users,i,ACL_USER*); - if ((!acl_user->user && (!user || !user[0])) || + if ((!acl_user->user && !user[0]) || (acl_user->user && strcmp(user, acl_user->user) == 0)) { if (compare_hostname(&acl_user->host, host, ip)) @@ -1001,7 +1001,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, { if (compare_hostname(&acl_db->host, host, ip)) { - if (!acl_db->db || (db && !strcmp(acl_db->db, db))) + if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0))) { sctx->db_access= acl_db->access; break; @@ -4980,8 +4980,6 @@ static int handle_grant_struct(uint struct_no, bool drop, } if (! user) user= ""; - if (! host) - host= ""; #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'", struct_no, idx, user, host)); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 959e4912c1c..5833842f660 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2264,6 +2264,7 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id, return pending; /* This is the current pending event */ } +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION /* Instansiate the versions we need, we have -fno-implicit-template as compiling option. @@ -2282,6 +2283,7 @@ template Rows_log_event* THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*, my_size_t colcnt, my_size_t, bool, Update_rows_log_event *); +#endif static char const* field_type_name(enum_field_types type) { diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 5ffa4fd76ed..3dcf49b4517 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -287,7 +287,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) } -/* +/* Load database options file load_db_opt() @@ -313,68 +313,72 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) bzero((char*) create,sizeof(*create)); create->default_table_charset= thd->variables.collation_server; - + /* Check if options for this database are already in the hash */ if (!get_dbopt(path, create)) - DBUG_RETURN(0); - - /* Otherwise, load options from the .opt file */ - if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0) - { - IO_CACHE cache; - init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)); + DBUG_RETURN(0); - while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) + /* Otherwise, load options from the .opt file */ + if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) + goto err1; + + IO_CACHE cache; + if (init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0))) + goto err2; + + while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) + { + char *pos= buf+nbytes-1; + /* Remove end space and control characters */ + while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1])) + pos--; + *pos=0; + if ((pos= strchr(buf, '='))) { - char *pos= buf+nbytes-1; - /* Remove end space and control characters */ - while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1])) - pos--; - *pos=0; - if ((pos= strchr(buf, '='))) + if (!strncmp(buf,"default-character-set", (pos-buf))) { - if (!strncmp(buf,"default-character-set", (pos-buf))) - { - /* - Try character set name, and if it fails - try collation name, probably it's an old - 4.1.0 db.opt file, which didn't have - separate default-character-set and - default-collation commands. - */ - if (!(create->default_table_charset= - get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) && - !(create->default_table_charset= - get_charset_by_name(pos+1, MYF(0)))) - { - sql_print_error("Error while loading database options: '%s':",path); - sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); - create->default_table_charset= default_charset_info; - } - } - else if (!strncmp(buf,"default-collation", (pos-buf))) - { - if (!(create->default_table_charset= get_charset_by_name(pos+1, - MYF(0)))) - { - sql_print_error("Error while loading database options: '%s':",path); - sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1); - create->default_table_charset= default_charset_info; - } - } + /* + Try character set name, and if it fails + try collation name, probably it's an old + 4.1.0 db.opt file, which didn't have + separate default-character-set and + default-collation commands. + */ + if (!(create->default_table_charset= + get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) && + !(create->default_table_charset= + get_charset_by_name(pos+1, MYF(0)))) + { + sql_print_error("Error while loading database options: '%s':",path); + sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); + create->default_table_charset= default_charset_info; + } + } + else if (!strncmp(buf,"default-collation", (pos-buf))) + { + if (!(create->default_table_charset= get_charset_by_name(pos+1, + MYF(0)))) + { + sql_print_error("Error while loading database options: '%s':",path); + sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1); + create->default_table_charset= default_charset_info; + } } } - end_io_cache(&cache); - my_close(file,MYF(0)); - /* - Put the loaded value into the hash. - Note that another thread could've added the same - entry to the hash after we called get_dbopt(), - but it's not an error, as put_dbopt() takes this - possibility into account. - */ - error= put_dbopt(path, create); } + /* + Put the loaded value into the hash. + Note that another thread could've added the same + entry to the hash after we called get_dbopt(), + but it's not an error, as put_dbopt() takes this + possibility into account. + */ + error= put_dbopt(path, create); + + end_io_cache(&cache); +err2: + my_close(file,MYF(0)); +err1: DBUG_RETURN(error); } @@ -497,7 +501,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, query_length= thd->query_length; } - ha_binlog_log_query(thd, LOGCOM_CREATE_DB, + ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB, query, query_length, db, ""); @@ -575,7 +579,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) thd->variables.collation_database= thd->db_charset; } - ha_binlog_log_query(thd, LOGCOM_ALTER_DB, + ha_binlog_log_query(thd, 0, LOGCOM_ALTER_DB, thd->query, thd->query_length, db, ""); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7d8f8f12383..c9cb1ccd5c2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -52,7 +52,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; table->map=1; @@ -79,6 +78,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && !(table->triggers && table->triggers->has_delete_triggers())) { + /* Update the table->file->records number */ + table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); ha_rows const maybe_deleted= table->file->records; /* If all rows shall be deleted, we always log this statement-based @@ -100,6 +101,18 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* Handler didn't support fast delete; Delete rows one by one */ } +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (prune_partitions(thd, table, conds)) + { + free_underlaid_joins(thd, select_lex); + thd->row_count_func= 0; + send_ok(thd); // No matching records + DBUG_RETURN(0); + } +#endif + /* Update the table->file->records number */ + table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + table->used_keys.clear_all(); table->quick_keys.clear_all(); // Can't use 'only index' select=make_select(table, 0, 0, conds, 0, &error); @@ -111,13 +124,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, select_lex); thd->row_count_func= 0; send_ok(thd,0L); - /* We don't need to call reset_auto_increment in this case, because mysql_truncate always gives a NULL conds argument, hence we never get here. */ - DBUG_RETURN(0); // Nothing to delete } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 0715aeeaa5b..ea9bca57cc6 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -567,7 +567,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error); if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) || - (res->quick && res->quick->reset())) + (res && res->quick && res->quick->reset())) { delete res; res=0; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a265d32e7c2..6655491ca57 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -686,7 +686,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) DBUG_ASSERT(view->table != 0 && view->field_translation != 0); - bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0); + VOID(bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0)); bitmap_clear_all(&used_fields); view->contain_auto_increment= 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ed7e7dfb684..279a02fa1d1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1615,6 +1615,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_other, &LOCK_status); thd->enable_slow_log= opt_log_slow_admin_statements; db= thd->alloc(db_len + tbl_len + 2); + if (!db) + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + break; + } tbl_name= strmake(db, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); mysql_table_dump(thd, db, tbl_name, -1); @@ -1628,14 +1633,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_other, &LOCK_status); char *user= (char*) packet; char *passwd= strend(user)+1; - /* + /* Old clients send null-terminated string ('\0' for empty string) for password. New clients send the size (1 byte) + string (not null terminated, so also '\0' for empty string). */ - char db_buff[NAME_LEN+1]; // buffer to store db in utf8 + char db_buff[NAME_LEN+1]; // buffer to store db in utf8 char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? *passwd++ : strlen(passwd); db+= passwd_len + 1; #ifndef EMBEDDED_LIBRARY @@ -2414,23 +2419,26 @@ mysql_execute_command(THD *thd) } } else -#endif /* HAVE_REPLICATION */ - - /* - When option readonly is set deny operations which change non-temporary - tables. Except for the replication thread and the 'super' users. - */ - if (opt_readonly && - !(thd->security_ctx->master_access & SUPER_ACL) && - uc_update_queries[lex->sql_command] && - !((lex->sql_command == SQLCOM_CREATE_TABLE) && - (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && - ((lex->sql_command != SQLCOM_UPDATE_MULTI) && - some_non_temp_table_to_be_updated(thd, all_tables))) { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); - DBUG_RETURN(-1); - } +#endif /* HAVE_REPLICATION */ + /* + When option readonly is set deny operations which change non-temporary + tables. Except for the replication thread and the 'super' users. + */ + if (opt_readonly && + !(thd->security_ctx->master_access & SUPER_ACL) && + uc_update_queries[lex->sql_command] && + !((lex->sql_command == SQLCOM_CREATE_TABLE) && + (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && + ((lex->sql_command != SQLCOM_UPDATE_MULTI) && + some_non_temp_table_to_be_updated(thd, all_tables))) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + DBUG_RETURN(-1); + } +#ifdef HAVE_REPLICATION + } /* endif unlikely slave */ +#endif if(lex->orig_sql_command == SQLCOM_END) statistic_increment(thd->status_var.com_stat[lex->sql_command], &LOCK_status); @@ -3226,8 +3234,7 @@ end_with_restore_list: else res= 0; - if ((res= mysql_multi_update_prepare(thd))) - break; + res= mysql_multi_update_prepare(thd); #ifdef HAVE_REPLICATION /* Check slave filtering rules */ @@ -3235,20 +3242,33 @@ end_with_restore_list: { if (all_tables_not_ok(thd, all_tables)) { + if (res!= 0) + { + res= 0; /* don't care of prev failure */ + thd->clear_error(); /* filters are of highest prior */ + } /* we warn the slave SQL thread */ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); break; } + if (res) + break; } else -#endif /* HAVE_REPLICATION */ - if (opt_readonly && - !(thd->security_ctx->master_access & SUPER_ACL) && - some_non_temp_table_to_be_updated(thd, all_tables)) { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); - break; - } +#endif /* HAVE_REPLICATION */ + if (res) + break; + if (opt_readonly && + !(thd->security_ctx->master_access & SUPER_ACL) && + some_non_temp_table_to_be_updated(thd, all_tables)) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + break; + } +#ifdef HAVE_REPLICATION + } /* unlikely */ +#endif res= mysql_multi_update(thd, all_tables, &select_lex->item_list, @@ -6631,6 +6651,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #ifdef HAVE_REPLICATION if (options & REFRESH_MASTER) { + DBUG_ASSERT(thd); tmp_write_to_binlog= 0; if (reset_master(thd)) { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index b66e617c06e..cb080ba68e0 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2120,6 +2120,8 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) were closed in the end of previous prepare or execute call. */ tables->table= 0; + /* Reset is_schema_table_processed value(needed for I_S tables */ + tables->is_schema_table_processed= FALSE; if (tables->prep_on_expr) { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ed056f62fe3..bf9a6078a8f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1201,7 +1201,12 @@ bool change_master(THD* thd, MASTER_INFO* mi) Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never a slave before). */ - flush_master_info(mi, 0); + if (flush_master_info(mi, 0)) + { + my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file"); + unlock_slave_threads(mi); + DBUG_RETURN(TRUE); + } if (need_relay_log_purge) { relay_log_purge= 1; @@ -1311,14 +1316,15 @@ bool mysql_show_binlog_events(THD* thd) bool ret = TRUE; IO_CACHE log; File file = -1; - Format_description_log_event *description_event= new - Format_description_log_event(3); /* MySQL 4.0 by default */ Log_event::init_show_field_list(&field_list); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + Format_description_log_event *description_event= new + Format_description_log_event(3); /* MySQL 4.0 by default */ + /* Wait for handlers to insert any pending information into the binlog. For e.g. ndb which updates the binlog asynchronously diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 47f970a4f82..47aa53d25e2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9117,7 +9117,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List &field_list) field++; } - *field= NULL; /* mark the end of the list */ + *field= NULL; /* mark the end of the list */ share->blob_field[blob_count]= 0; /* mark the end of the list */ share->blob_fields= blob_count; @@ -11659,6 +11659,12 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, goto err; } } + + /* Fill schema tables with data before filesort if it's necessary */ + if ((join->select_lex->options & OPTION_SCHEMA_TABLE) && + get_schema_tables_result(join)) + goto err; + if (table->s->tmp_table) table->file->info(HA_STATUS_VARIABLE); // Get record count table->sort.found_records=filesort(thd, table,sortorder, length, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1e051ab34c4..d30ce8d6b59 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -781,7 +781,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) it's a keyword */ - packet->reserve(length*2 + 2); + VOID(packet->reserve(length*2 + 2)); quote_char= (char) q; packet->append("e_char, 1, system_charset_info); @@ -1097,13 +1097,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, if (key_part->field) append_identifier(thd,packet,key_part->field->field_name, strlen(key_part->field->field_name)); - if (!key_part->field || + if (key_part->field && (key_part->length != table->field[key_part->fieldnr-1]->key_length() && !(key_info->flags & HA_FULLTEXT))) { buff[0] = '('; - char* end=int10_to_str((long) key_part->length / + char* end=int10_to_str((long) key_part->length / key_part->field->charset()->mbmaxlen, buff + 1,10); *end++ = ')'; @@ -1856,7 +1856,8 @@ LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str, { MEM_ROOT *mem= thd->mem_root; if (allocate_lex_string) - lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)); + if (!(lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)))) + return 0; lex_str->str= strmake_root(mem, str, length); lex_str->length= length; return lex_str; @@ -3115,7 +3116,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, /* I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS rather than in SHOW KEYS - */ + */ if (!tables->view) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); @@ -3128,7 +3129,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, { TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++,key_info++) @@ -3140,7 +3141,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, restore_record(table, s->default_values); table->field[1]->store(base_name, strlen(base_name), cs); table->field[2]->store(file_name, strlen(file_name), cs); - table->field[3]->store((longlong) ((key_info->flags & + table->field[3]->store((longlong) ((key_info->flags & HA_NOSAME) ? 0 : 1), TRUE); table->field[4]->store(base_name, strlen(base_name), cs); table->field[5]->store(key_info->name, strlen(key_info->name), cs); @@ -3163,12 +3164,12 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, table->field[9]->store((longlong) records, TRUE); table->field[9]->set_notnull(); } - if (!(key_info->flags & HA_FULLTEXT) && - (!key_part->field || - key_part->length != + if (!(key_info->flags & HA_FULLTEXT) && + (key_part->field && + key_part->length != show_table->field[key_part->fieldnr-1]->key_length())) { - table->field[10]->store((longlong) key_part->length / + table->field[10]->store((longlong) key_part->length / key_part->field->charset()->mbmaxlen); table->field[10]->set_notnull(); } @@ -4549,7 +4550,16 @@ bool get_schema_tables_result(JOIN *join) TABLE_LIST *table_list= tab->table->pos_in_table_list; if (table_list->schema_table && thd->fill_derived_tables()) { - if (&lex->unit != lex->current_select->master_unit()) // is subselect + bool is_subselect= (&lex->unit != lex->current_select->master_unit()); + /* + The schema table is already processed and + the statement is not a subselect. + So we don't need to handle this table again. + */ + if (table_list->is_schema_table_processed && !is_subselect) + continue; + + if (is_subselect) // is subselect { table_list->table->file->extra(HA_EXTRA_RESET_STATE); table_list->table->file->delete_all_rows(); @@ -4562,6 +4572,7 @@ bool get_schema_tables_result(JOIN *join) if (table_list->schema_table->fill_table(thd, table_list, tab->select_cond)) result= 1; + table_list->is_schema_table_processed= TRUE; } } thd->no_warnings_for_error= 0; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a6447aefdf7..e1a83a4ecf8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4974,6 +4974,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } thd->proc_info="end"; + ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, + thd->query, thd->query_length, + db, table_name); + DBUG_ASSERT(!(mysql_bin_log.is_open() && binlog_row_based && (create_info->options & HA_LEX_CREATE_TMP_TABLE))); write_bin_log(thd, TRUE, thd->query, thd->query_length); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index c4448ff8abe..bf86630d28c 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -450,7 +450,7 @@ void mysql_print_status() calc_sum_of_all_status(&tmp); printf("\nStatus information:\n\n"); - my_getwd(current_dir, sizeof(current_dir),MYF(0)); + VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0))); printf("Current dir: %s\n", current_dir); printf("Running threads: %d Stack size: %ld\n", thread_count, (long) thread_stack); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ec41e02f439..f653033b9cb 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -390,7 +390,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, for (trg_field= (Item_trigger_field *)(lex->trg_table_fields.first); trg_field; trg_field= trg_field->next_trg_field) { - trg_field->setup_field(thd, table); + /* + NOTE: now we do not check privileges at CREATE TRIGGER time. This will + be changed in the future. + */ + trg_field->setup_field(thd, table, NULL); + if (!trg_field->fixed && trg_field->fix_fields(thd, (Item **)0)) return 1; @@ -826,8 +831,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, char *trg_name_buff; List_iterator_fast itm(triggers->definition_modes_list); - List_iterator_fast it_definer(triggers-> - definers_list); + List_iterator_fast it_definer(triggers->definers_list); LEX *old_lex= thd->lex, lex; sp_rcontext *save_spcont= thd->spcont; ulong save_sql_mode= thd->variables.sql_mode; @@ -842,6 +846,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, { trg_sql_mode= itm++; LEX_STRING *trg_definer= it_definer++; + thd->variables.sql_mode= (ulong)*trg_sql_mode; lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length); @@ -915,11 +920,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, (Item_trigger_field *)(lex.trg_table_fields.first); trg_field; trg_field= trg_field->next_trg_field) - trg_field->setup_field(thd, table); - - triggers->m_spec_var_used[lex.trg_chistics.event] - [lex.trg_chistics.action_time]= - lex.trg_table_fields.first ? TRUE : FALSE; + { + trg_field->setup_field(thd, table, + &triggers->subject_table_grants[lex.trg_chistics.event] + [lex.trg_chistics.action_time]); + } lex_end(&lex); } @@ -1159,38 +1164,30 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, if (sp_change_security_context(thd, sp_trigger, &save_ctx)) return TRUE; + /* + Fetch information about table-level privileges to GRANT_INFO structure for + subject table. Check of privileges that will use it and information about + column-level privileges will happen in Item_trigger_field::fix_fields(). + */ + + fill_effective_table_privileges(thd, + &subject_table_grants[event][time_type], + table->s->db.str, table->s->table_name.str); + + /* Check that the definer has TRIGGER privilege on the subject table. */ + + if (!(subject_table_grants[event][time_type].privilege & TRIGGER_ACL)) { - TABLE_LIST table_list, **save_query_tables_own_last; - ulong wanted_access = TRIGGER_ACL; - - bzero((char *) &table_list, sizeof (table_list)); - table_list.db= (char *) table->s->db.str; - table_list.db_length= table->s->db.length; - table_list.table_name= table->s->table_name.str; - table_list.table_name_length= table->s->table_name.length; - table_list.alias= (char *) table->alias; - table_list.table= table; - save_query_tables_own_last= thd->lex->query_tables_own_last; - thd->lex->query_tables_own_last= 0; - - /* - If the trigger uses special variables (NEW/OLD), check that we have - SELECT and UPDATE privileges on the subject table. - */ + char priv_desc[128]; + get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL); - if (is_special_var_used(event, time_type)) - wanted_access|= SELECT_ACL | UPDATE_ACL; + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc, + thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, + table->s->table_name); - err_status= check_table_access(thd, wanted_access, &table_list, 0); - - thd->lex->query_tables_own_last= save_query_tables_own_last; - if (err_status) - { - sp_restore_security_context(thd, save_ctx); - return TRUE; - } + sp_restore_security_context(thd, save_ctx); + return TRUE; } - #endif // NO_EMBEDDED_ACCESS_CHECKS thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 51002683897..8992de63b37 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -56,10 +56,9 @@ class Table_triggers_list: public Sql_alloc LEX_STRING sroutines_key; /* - is_special_var_used specifies whether trigger body contains special - variables (NEW/OLD). + Grant information for each trigger (pair: subject table, trigger definer). */ - bool m_spec_var_used[TRG_EVENT_MAX][TRG_ACTION_MAX]; + GRANT_INFO subject_table_grants[TRG_EVENT_MAX][TRG_ACTION_MAX]; public: /* @@ -78,6 +77,7 @@ public: record1_field(0), table(table_arg) { bzero((char *)bodies, sizeof(bodies)); + bzero((char *)&subject_table_grants, sizeof(subject_table_grants)); } ~Table_triggers_list(); @@ -109,11 +109,6 @@ public: return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]); } - inline bool is_special_var_used(int event, int action_time) const - { - return m_spec_var_used[event][action_time]; - } - void set_table(TABLE *new_table); friend class Item_trigger_field; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 62ea4e89eff..d6bf01f5a25 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -168,7 +168,6 @@ int mysql_update(THD *thd, thd->proc_info="init"; table= table_list->table; - table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); /* Calculate "table->used_keys" based on the WHERE */ table->used_keys= table->s->keys_in_use; @@ -244,6 +243,18 @@ int mysql_update(THD *thd, } // Don't count on usage of 'only index' when calculating which key to use table->used_keys.clear_all(); + +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (prune_partitions(thd, table, conds)) + { + free_underlaid_joins(thd, select_lex); + send_ok(thd); // No matching records + DBUG_RETURN(0); + } +#endif + /* Update the table->file->records number */ + table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + select= make_select(table, 0, 0, conds, 0, &error); if (error || !limit || (select && select->check_quick(thd, safe_update, limit))) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a116dc27891..01166e352c3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1642,11 +1642,26 @@ clear_privileges: sp_name: ident '.' ident { + if (!$1.str || check_db_name($1.str)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); + YYABORT; + } + if (check_routine_name($3)) + { + my_error(ER_SP_WRONG_NAME, MYF(0), $3.str); + YYABORT; + } $$= new sp_name($1, $3); $$->init_qname(YYTHD); } | ident { + if (check_routine_name($1)) + { + my_error(ER_SP_WRONG_NAME, MYF(0), $1.str); + YYABORT; + } $$= sp_name_current_db_new(YYTHD, $1); } ; @@ -9028,7 +9043,8 @@ simple_ident_q: new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, - $3.str))) + $3.str, + Item_trigger_field::AT_READ))) YYABORT; /* @@ -9712,7 +9728,9 @@ sys_option_value: if (!(trg_fld= new Item_trigger_field(Lex->current_context(), Item_trigger_field::NEW_ROW, - $2.base_name.str)) || + $2.base_name.str, + Item_trigger_field::AT_UPDATE) + ) || !(sp_fld= new sp_instr_set_trigger_field(lex->sphead-> instructions(), lex->spcont, diff --git a/sql/table.cc b/sql/table.cc index b912683d371..b7920d0d530 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1640,7 +1640,10 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names) ret_value=uint4korr(pos); } if (! save_names) - my_free((gptr) buf,MYF(0)); + { + if (names) + my_free((gptr) buf,MYF(0)); + } else if (!names) bzero((char*) save_names,sizeof(save_names)); else diff --git a/sql/table.h b/sql/table.h index bcc2f89655b..a799d4389fb 100644 --- a/sql/table.h +++ b/sql/table.h @@ -560,6 +560,7 @@ typedef struct st_table_list st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ st_select_lex *schema_select_lex; + bool is_schema_table_processed; /* True when the view field translation table is used to convert schema table fields for backwards compatibility with SHOW command. diff --git a/sql/uniques.cc b/sql/uniques.cc index 367aed2d113..ad074f8b2b0 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -38,8 +38,8 @@ 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 + 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) */ @@ -63,27 +63,27 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, comp_func_fixed_arg); /* If the following fail's the next add will also fail */ my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); - /* + /* If you change the following, change it in get_max_elements function, too. */ max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); - open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, - MYF(MY_WME)); + VOID(open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, + MYF(MY_WME))); } /* Calculate log2(n!) - + NOTES Stirling's approximate formula is used: - - n! ~= sqrt(2*M_PI*n) * (n/M_E)^n - + + n! ~= sqrt(2*M_PI*n) * (n/M_E)^n + Derivation of formula used for calculations is as follows: log2(n!) = log(n!)/log(2) = log(sqrt(2*M_PI*n)*(n/M_E)^n) / log(2) = - + = (log(2*M_PI*n)/2 + n*log(n/M_E)) / log(2). */ @@ -94,7 +94,7 @@ inline double log2_n_fact(double x) /* - Calculate cost of merge_buffers function call for given sequence of + Calculate cost of merge_buffers function call for given sequence of input stream lengths and store the number of rows in result stream in *last. SYNOPSIS @@ -103,21 +103,21 @@ inline double log2_n_fact(double x) elem_size Size of element stored in buffer first Pointer to first merged element size last Pointer to last merged element size - + RETURN Cost of merge_buffers operation in disk seeks. - + NOTES It is assumed that no rows are eliminated during merge. - The cost is calculated as - + The cost is calculated as + cost(read_and_write) + cost(merge_comparisons). - - All bytes in the sequences is read and written back during merge so cost + + All bytes in the sequences is read and written back during merge so cost of disk io is 2*elem_size*total_buf_elems/IO_SIZE (2 is for read + write) - + For comparisons cost calculations we assume that all merged sequences have - the same length, so each of total_buf_size elements will be added to a sort + the same length, so each of total_buf_size elements will be added to a sort heap with (n_buffers-1) elements. This gives the comparison cost: total_buf_elems* log2(n_buffers) / TIME_FOR_COMPARE_ROWID; @@ -125,16 +125,16 @@ inline double log2_n_fact(double x) static double get_merge_buffers_cost(uint *buff_elems, uint elem_size, uint *first, uint *last) -{ +{ uint total_buf_elems= 0; for (uint *pbuf= first; pbuf <= last; pbuf++) total_buf_elems+= *pbuf; *last= total_buf_elems; - + int n_buffers= last - first + 1; /* Using log2(n)=log(n)/log(2) formula */ - return 2*((double)total_buf_elems*elem_size) / IO_SIZE + + return 2*((double)total_buf_elems*elem_size) / IO_SIZE + total_buf_elems*log((double) n_buffers) / (TIME_FOR_COMPARE_ROWID * M_LN2); } @@ -142,13 +142,13 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size, /* Calculate cost of merging buffers into one in Unique::get, i.e. calculate how long (in terms of disk seeks) the two calls - merge_many_buffs(...); - merge_buffers(...); + merge_many_buffs(...); + merge_buffers(...); will take. SYNOPSIS get_merge_many_buffs_cost() - buffer buffer space for temporary data, at least + buffer buffer space for temporary data, at least Unique::get_cost_calc_buff_size bytes maxbuffer # of full buffers max_n_elems # of elements in first maxbuffer buffers @@ -156,12 +156,12 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size, elem_size size of buffer element NOTES - maxbuffer+1 buffers are merged, where first maxbuffer buffers contain + maxbuffer+1 buffers are merged, where first maxbuffer buffers contain max_n_elems elements each and last buffer contains last_n_elems elements. The current implementation does a dumb simulation of merge_many_buffs function actions. - + RETURN Cost of merge in disk seeks. */ @@ -173,17 +173,17 @@ static double get_merge_many_buffs_cost(uint *buffer, register int i; double total_cost= 0.0; uint *buff_elems= buffer; /* #s of elements in each of merged sequences */ - - /* + + /* Set initial state: first maxbuffer sequences contain max_n_elems elements each, last sequence contains last_n_elems elements. */ for (i = 0; i < (int)maxbuffer; i++) - buff_elems[i]= max_n_elems; + buff_elems[i]= max_n_elems; buff_elems[maxbuffer]= last_n_elems; - /* - Do it exactly as merge_many_buff function does, calling + /* + Do it exactly as merge_many_buff function does, calling get_merge_buffers_cost to get cost of merge_buffers. */ if (maxbuffer >= MERGEBUFF2) @@ -194,17 +194,17 @@ static double get_merge_many_buffs_cost(uint *buffer, for (i = 0; i <= (int) maxbuffer - MERGEBUFF*3/2; i += MERGEBUFF) { total_cost+=get_merge_buffers_cost(buff_elems, elem_size, - buff_elems + i, + buff_elems + i, buff_elems + i + MERGEBUFF-1); lastbuff++; } total_cost+=get_merge_buffers_cost(buff_elems, elem_size, - buff_elems + i, + buff_elems + i, buff_elems + maxbuffer); maxbuffer= lastbuff; } } - + /* Simulate final merge_buff call. */ total_cost += get_merge_buffers_cost(buff_elems, elem_size, buff_elems, buff_elems + maxbuffer); @@ -213,7 +213,7 @@ static double get_merge_many_buffs_cost(uint *buffer, /* - Calculate cost of using Unique for processing nkeys elements of size + Calculate cost of using Unique for processing nkeys elements of size key_size using max_in_memory_size memory. SYNOPSIS @@ -223,12 +223,12 @@ static double get_merge_many_buffs_cost(uint *buffer, nkeys #of elements in Unique key_size size of each elements in bytes max_in_memory_size amount of memory Unique will be allowed to use - + RETURN Cost in disk seeks. - + NOTES - cost(using_unqiue) = + cost(using_unqiue) = cost(create_trees) + (see #1) cost(merge) + (see #2) cost(read_result) (see #3) @@ -237,42 +237,42 @@ static double get_merge_many_buffs_cost(uint *buffer, For each Unique::put operation there will be 2*log2(n+1) elements comparisons, where n runs from 1 tree_size (we assume that all added elements are different). Together this gives: - + n_compares = 2*(log2(2) + log2(3) + ... + log2(N+1)) = 2*log2((N+1)!) - + then cost(tree_creation) = n_compares*ROWID_COMPARE_COST; Total cost of creating trees: (n_trees - 1)*max_size_tree_cost + non_max_size_tree_cost. Approximate value of log2(N!) is calculated by log2_n_fact function. - + 2. Cost of merging. If only one tree is created by Unique no merging will be necessary. Otherwise, we model execution of merge_many_buff function and count - #of merges. (The reason behind this is that number of buffers is small, - while size of buffers is big and we don't want to loose precision with + #of merges. (The reason behind this is that number of buffers is small, + while size of buffers is big and we don't want to loose precision with O(x)-style formula) - + 3. If only one tree is created by Unique no disk io will happen. - Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume + Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume these will be random seeks. */ -double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, +double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, ulong max_in_memory_size) { ulong max_elements_in_tree; ulong last_tree_elems; int n_full_trees; /* number of trees in unique - 1 */ double result; - - max_elements_in_tree= + + max_elements_in_tree= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size); n_full_trees= nkeys / max_elements_in_tree; last_tree_elems= nkeys % max_elements_in_tree; - + /* Calculate cost of creating trees */ result= 2*log2_n_fact(last_tree_elems + 1.0); if (n_full_trees) @@ -285,13 +285,13 @@ double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, if (!n_full_trees) return result; - - /* + + /* There is more then one tree and merging is necessary. First, add cost of writing all trees to disk, assuming that all disk writes are sequential. */ - result += DISK_SEEK_BASE_COST * n_full_trees * + result += DISK_SEEK_BASE_COST * n_full_trees * ceil(((double) key_size)*max_elements_in_tree / IO_SIZE); result += DISK_SEEK_BASE_COST * ceil(((double) key_size)*last_tree_elems / IO_SIZE); @@ -303,8 +303,8 @@ double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, return merge_cost; result += merge_cost; - /* - Add cost of reading the resulting sequence, assuming there were no + /* + Add cost of reading the resulting sequence, assuming there were no duplicate elements. */ result += ceil((double)key_size*nkeys/IO_SIZE); @@ -320,7 +320,7 @@ Unique::~Unique() } - /* Write tree to disk; clear tree */ + /* Write tree to disk; clear tree */ bool Unique::flush() { BUFFPEK file_ptr; @@ -359,7 +359,7 @@ Unique::reset() } elements= 0; } - + /* The comparison function, passed to queue_init() in merge_walk() must use comparison function of Uniques::tree, but compare members of struct @@ -386,7 +386,7 @@ C_MODE_END /* DESCRIPTION - Function is very similar to merge_buffers, but instead of writing sorted + Function is very similar to merge_buffers, but instead of writing sorted unique keys to the output file, it invokes walk_action for each key. This saves I/O if you need to pass through all unique keys only once. SYNOPSIS @@ -601,7 +601,7 @@ bool Unique::get(TABLE *table) bool error=1; /* Open cached file if it isn't open */ - outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), MYF(MY_ZEROFILL)); if (!outfile || ! my_b_inited(outfile) && @@ -618,7 +618,7 @@ bool Unique::get(TABLE *table) sort_param.keys= max_in_memory_size / sort_param.sort_length; sort_param.not_killable=1; - if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * + if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * sort_param.sort_length, MYF(0)))) return 1; @@ -633,7 +633,7 @@ bool Unique::get(TABLE *table) goto err; if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr, file_ptr, file_ptr+maxbuffer,0)) - goto err; + goto err; error=0; err: x_free((gptr) sort_buffer); diff --git a/storage/innobase/os/os0thread.c b/storage/innobase/os/os0thread.c index 1d1cb77b336..c0e66ff2b7e 100644 --- a/storage/innobase/os/os0thread.c +++ b/storage/innobase/os/os0thread.c @@ -156,6 +156,15 @@ os_thread_create( "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret); exit(1); } +#endif +#ifdef __NETWARE__ + ret = pthread_attr_setstacksize(&attr, + (size_t)NW_THD_STACKSIZE); + if (ret) { + fprintf(stderr, + "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret); + exit(1); + } #endif os_mutex_enter(os_sync_mutex); os_thread_count++; diff --git a/storage/myisam/ft_update.c b/storage/myisam/ft_update.c index a280a98cf90..1ec91b41218 100644 --- a/storage/myisam/ft_update.c +++ b/storage/myisam/ft_update.c @@ -174,6 +174,10 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2) FT_SEG_ITERATOR ftsi1, ftsi2; CHARSET_INFO *cs=info->s->keyinfo[keynr].seg->charset; DBUG_ENTER("_mi_ft_cmp"); +#ifndef MYSQL_HAS_TRUE_CTYPE_IMPLEMENTATION + if (cs->mbmaxlen > 1) + DBUG_RETURN(THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT); +#endif _mi_ft_segiterator_init(info, keynr, rec1, &ftsi1); _mi_ft_segiterator_init(info, keynr, rec2, &ftsi2); diff --git a/storage/myisam/mi_delete.c b/storage/myisam/mi_delete.c index 416d951d138..2010b684300 100644 --- a/storage/myisam/mi_delete.c +++ b/storage/myisam/mi_delete.c @@ -276,7 +276,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (subkeys == -1) { /* the last entry in sub-tree */ - _mi_dispose(info, keyinfo, root,DFLT_INIT_HITS); + if (_mi_dispose(info, keyinfo, root,DFLT_INIT_HITS)) + DBUG_RETURN(-1); /* fall through to normal delete */ } else diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c index c7f8c8d6e7f..7c418cb9531 100644 --- a/storage/myisam/mi_locking.c +++ b/storage/myisam/mi_locking.c @@ -84,14 +84,16 @@ int mi_lock_database(MI_INFO *info, int lock_type) (uint) share->changed, share->w_locks)); if (share->changed && !share->w_locks) { - if (info->s->mmaped_length != info->s->state.state.data_file_length) - { - if (info->s->concurrent_insert) - rw_wrlock(&info->s->mmap_lock); - mi_remap_file(info, info->s->state.state.data_file_length); - if (info->s->concurrent_insert) - rw_unlock(&info->s->mmap_lock); - } +#ifdef HAVE_MMAP + if (info->s->mmaped_length != info->s->state.state.data_file_length) + { + if (info->s->concurrent_insert) + rw_wrlock(&info->s->mmap_lock); + mi_remap_file(info, info->s->state.state.data_file_length); + if (info->s->concurrent_insert) + rw_unlock(&info->s->mmap_lock); + } +#endif share->state.process= share->last_process=share->this_process; share->state.unique= info->last_unique= info->this_unique; share->state.update_count= info->last_loop= ++info->this_loop; diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c index d691c24e890..e80a3ffacd9 100644 --- a/storage/myisam/myisampack.c +++ b/storage/myisam/myisampack.c @@ -1159,7 +1159,7 @@ static int compare_huff_elements(void *not_used __attribute__((unused)), static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records) { - uint space_fields,fill_zero_fields,field_count[(int) FIELD_VARCHAR+1]; + uint space_fields,fill_zero_fields,field_count[(int) FIELD_enum_val_count]; my_off_t old_length,new_length,length; DBUG_ENTER("check_counts"); diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c index c3eaddb3e92..c9562461f56 100644 --- a/storage/myisam/sort.c +++ b/storage/myisam/sort.c @@ -376,7 +376,10 @@ pthread_handler_t thr_find_all_keys(void *arg) { if (my_init_dynamic_array(&info->buffpek, sizeof(BUFFPEK), maxbuffer, maxbuffer/2)) + { my_free((gptr) sort_keys,MYF(0)); + sort_keys= (uchar **) NULL; /* for err: label */ + } else break; } diff --git a/storage/ndb/include/logger/LogHandler.hpp b/storage/ndb/include/logger/LogHandler.hpp index 7df6ad864e5..8b9aa43d7a9 100644 --- a/storage/ndb/include/logger/LogHandler.hpp +++ b/storage/ndb/include/logger/LogHandler.hpp @@ -125,6 +125,18 @@ public: */ void setErrorCode(int code); + /** + * Returns the error string. + */ + char* getErrorStr(); + + /** + * Sets the error string. + * + * @param str the error string. + */ + void setErrorStr(char* str); + /** * Parse logstring parameters * @@ -195,6 +207,7 @@ private: const char* m_pDateTimeFormat; int m_errorCode; + char* m_errorStr; // for handling repeated messages unsigned m_count_repeated_messages; diff --git a/storage/ndb/include/logger/Logger.hpp b/storage/ndb/include/logger/Logger.hpp index ee762098fb6..3414468d42d 100644 --- a/storage/ndb/include/logger/Logger.hpp +++ b/storage/ndb/include/logger/Logger.hpp @@ -178,8 +178,11 @@ public: * Add a new handler * * @param logstring string describing the handler to add + * @param err OS errno in event of error + * @param len max length of errStr buffer + * @param errStr logger error string in event of error */ - bool addHandler(const BaseString &logstring); + bool addHandler(const BaseString &logstring, int *err, int len, char* errStr); /** * Remove a log handler. diff --git a/storage/ndb/include/mgmapi/mgmapi.h b/storage/ndb/include/mgmapi/mgmapi.h index 2675502b6ad..9d74be5d603 100644 --- a/storage/ndb/include/mgmapi/mgmapi.h +++ b/storage/ndb/include/mgmapi/mgmapi.h @@ -992,6 +992,22 @@ extern "C" { int ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned version, int nodetype); + /** + * End Session + * + * This function tells the mgm server to free all resources associated with + * this connection. It will also close it. + * + * This differs from just disconnecting as we now synchronously clean up, + * so that a quickly restarting server that needs the same node id can + * get it when it restarts. + * + * @param handle NDB management handle + * @return 0 on success + * + * @note you still have to destroy the NdbMgmHandle. + */ + int ndb_mgm_end_session(NdbMgmHandle handle); /** * Get the node id of the mgm server we're connected to diff --git a/storage/ndb/include/mgmcommon/ConfigRetriever.hpp b/storage/ndb/include/mgmcommon/ConfigRetriever.hpp index c0b877af07d..1b4ecd56f80 100644 --- a/storage/ndb/include/mgmcommon/ConfigRetriever.hpp +++ b/storage/ndb/include/mgmcommon/ConfigRetriever.hpp @@ -78,6 +78,7 @@ public: const char *get_connectstring(char *buf, int buf_sz) const; NdbMgmHandle get_mgmHandle() { return m_handle; }; NdbMgmHandle* get_mgmHandlePtr() { return &m_handle; }; + void end_session(bool end) { m_end_session= end; }; Uint32 get_configuration_nodeid() const; private: @@ -92,6 +93,8 @@ private: void setError(ErrorType, const char * errorMsg); Uint32 _ownNodeId; + bool m_end_session; + /* Uint32 m_mgmd_port; const char *m_mgmd_host; diff --git a/storage/ndb/include/ndbapi/NdbBlob.hpp b/storage/ndb/include/ndbapi/NdbBlob.hpp index 5d6022862b8..92265b4feef 100644 --- a/storage/ndb/include/ndbapi/NdbBlob.hpp +++ b/storage/ndb/include/ndbapi/NdbBlob.hpp @@ -76,8 +76,8 @@ class NdbEventOperationImpl; * handle can be read after next event on main table has been retrieved. * The data is available immediately. See NdbEventOperation. * - * NdbBlob methods return -1 on error and 0 on success, and use output - * parameters when necessary. + * Non-void NdbBlob methods return -1 on error and 0 on success. Output + * parameters are used when necessary. * * Operation types: * - insertTuple must use setValue if blob column is non-nullable @@ -116,6 +116,11 @@ public: * Get the state of a NdbBlob object. */ State getState(); + /** + * Returns -1 for normal statement based blob and 0/1 for event + * operation post/pre data blob. Always succeeds. + */ + void getVersion(int& version); /** * Inline blob header. */ @@ -150,16 +155,15 @@ public: * then the callback is invoked. */ int setActiveHook(ActiveHook* activeHook, void* arg); - /** - * Check if blob value is defined (NULL or not). Used as first call - * on event based blob. The argument is set to -1 for not defined. - * Unlike getNull() this does not cause error on the handle. - */ +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED int getDefined(int& isNull); - /** - * Check if blob is null. - */ int getNull(bool& isNull); +#endif + /** + * Return -1, 0, 1 if blob is undefined, non-null, or null. For + * non-event blob, undefined causes a state error. + */ + int getNull(int& isNull); /** * Set blob to NULL. */ @@ -208,8 +212,8 @@ public: */ static int getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char* columnName); /** - * Return error object. The error may be blob specific (below) or may - * be copied from a failed implicit operation. + * Return error object. The error may be blob specific or may be + * copied from a failed implicit operation. */ const NdbError& getNdbError() const; /** diff --git a/storage/ndb/src/common/logger/FileLogHandler.cpp b/storage/ndb/src/common/logger/FileLogHandler.cpp index 8678b999b6f..3d29e63ac1f 100644 --- a/storage/ndb/src/common/logger/FileLogHandler.cpp +++ b/storage/ndb/src/common/logger/FileLogHandler.cpp @@ -187,6 +187,7 @@ FileLogHandler::setParam(const BaseString ¶m, const BaseString &value){ return setMaxSize(value); if(param == "maxfiles") return setMaxFiles(value); + setErrorStr("Invalid parameter"); return false; } @@ -196,16 +197,18 @@ FileLogHandler::setFilename(const BaseString &filename) { if(m_pLogFile) delete m_pLogFile; m_pLogFile = new File_class(filename.c_str(), "a+"); - open(); - return true; + return open(); } bool FileLogHandler::setMaxSize(const BaseString &size) { char *end; long val = strtol(size.c_str(), &end, 0); /* XXX */ - if(size.c_str() == end) + if(size.c_str() == end || val < 0) + { + setErrorStr("Invalid file size"); return false; + } if(end[0] == 'M') val *= 1024*1024; if(end[0] == 'k') @@ -220,8 +223,11 @@ bool FileLogHandler::setMaxFiles(const BaseString &files) { char *end; long val = strtol(files.c_str(), &end, 0); - if(files.c_str() == end) + if(files.c_str() == end || val < 1) + { + setErrorStr("Invalid maximum number of files"); return false; + } m_maxNoFiles = val; return true; @@ -230,6 +236,9 @@ FileLogHandler::setMaxFiles(const BaseString &files) { bool FileLogHandler::checkParams() { if(m_pLogFile == NULL) + { + setErrorStr("Log file cannot be null."); return false; + } return true; } diff --git a/storage/ndb/src/common/logger/LogHandler.cpp b/storage/ndb/src/common/logger/LogHandler.cpp index 521bd346fd3..c11f962d4fb 100644 --- a/storage/ndb/src/common/logger/LogHandler.cpp +++ b/storage/ndb/src/common/logger/LogHandler.cpp @@ -23,7 +23,8 @@ // LogHandler::LogHandler() : m_pDateTimeFormat("%d-%.2d-%.2d %.2d:%.2d:%.2d"), - m_errorCode(0) + m_errorCode(0), + m_errorStr(NULL) { m_max_repeat_frequency= 3; // repeat messages maximum every 3 seconds m_count_repeated_messages= 0; @@ -155,6 +156,19 @@ LogHandler::setErrorCode(int code) m_errorCode = code; } + +char* +LogHandler::getErrorStr() +{ + return m_errorStr; +} + +void +LogHandler::setErrorStr(char* str) +{ + m_errorStr= str; +} + bool LogHandler::parseParams(const BaseString &_params) { Vector v_args; @@ -165,9 +179,18 @@ LogHandler::parseParams(const BaseString &_params) { for(size_t i=0; i < v_args.size(); i++) { Vector v_param_value; if(v_args[i].split(v_param_value, "=", 2) != 2) + { ret = false; - else if (!setParam(v_param_value[0], v_param_value[1])) - ret = false; + setErrorStr("Can't find key=value pair."); + } + else + { + v_param_value[0].trim(" \t"); + if (!setParam(v_param_value[0], v_param_value[1])) + { + ret = false; + } + } } if(!checkParams()) diff --git a/storage/ndb/src/common/logger/Logger.cpp b/storage/ndb/src/common/logger/Logger.cpp index 4a48236053d..48e084a782b 100644 --- a/storage/ndb/src/common/logger/Logger.cpp +++ b/storage/ndb/src/common/logger/Logger.cpp @@ -167,7 +167,7 @@ Logger::addHandler(LogHandler* pHandler) } bool -Logger::addHandler(const BaseString &logstring) { +Logger::addHandler(const BaseString &logstring, int *err, int len, char* errStr) { size_t i; Vector logdest; Vectorloghandlers; @@ -200,9 +200,18 @@ Logger::addHandler(const BaseString &logstring) { handler = new ConsoleLogHandler(); if(handler == NULL) + { + snprintf(errStr,len,"Could not create log destination: %s", + logdest[i].c_str()); DBUG_RETURN(false); + } if(!handler->parseParams(params)) + { + *err= handler->getErrorCode(); + if(handler->getErrorStr()) + strncpy(errStr, handler->getErrorStr(), len); DBUG_RETURN(false); + } loghandlers.push_back(handler); } diff --git a/storage/ndb/src/common/logger/SysLogHandler.cpp b/storage/ndb/src/common/logger/SysLogHandler.cpp index 5b1b8d85ca7..c7fcb102dd4 100644 --- a/storage/ndb/src/common/logger/SysLogHandler.cpp +++ b/storage/ndb/src/common/logger/SysLogHandler.cpp @@ -154,5 +154,6 @@ SysLogHandler::setFacility(const BaseString &facility) { return true; } } + setErrorStr("Invalid syslog facility name"); return false; } diff --git a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp index 3b843b6708b..97de5c7f83d 100644 --- a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -52,6 +52,7 @@ ConfigRetriever::ConfigRetriever(const char * _connect_string, m_version = version; m_node_type = node_type; _ownNodeId= 0; + m_end_session= true; m_handle= ndb_mgm_create_handle(); @@ -76,6 +77,8 @@ ConfigRetriever::~ConfigRetriever() { DBUG_ENTER("ConfigRetriever::~ConfigRetriever"); if (m_handle) { + if(m_end_session) + ndb_mgm_end_session(m_handle); ndb_mgm_disconnect(m_handle); ndb_mgm_destroy_handle(&m_handle); } diff --git a/storage/ndb/src/common/util/SocketServer.cpp b/storage/ndb/src/common/util/SocketServer.cpp index 15dca2d96b1..481c656b78b 100644 --- a/storage/ndb/src/common/util/SocketServer.cpp +++ b/storage/ndb/src/common/util/SocketServer.cpp @@ -42,6 +42,8 @@ SocketServer::~SocketServer() { delete m_sessions[i].m_session; } for(i = 0; iword+ZPAGE_HEADER_SIZE, sz); handleTabInfoInit(r, &parseRecord); - ndbrequire(parseRecord.errorCode == 0); + if (parseRecord.errorCode != 0) + { + char buf[255]; + BaseString::snprintf(buf, sizeof(buf), + "Unable to restart, fail while creating table %d" + " error: %d. Most likely change of configuration", + c_readTableRecord.tableId, + parseRecord.errorCode); + progError(__LINE__, + ERR_INVALID_CONFIG, + buf); + ndbrequire(parseRecord.errorCode == 0); + } /* ---------------------------------------------------------------- */ // We have read the table description from disk as part of system restart. @@ -7123,7 +7135,7 @@ void Dbdict::execGET_TABINFOREQ(Signal* signal) return; } - sendGET_TABINFOREF(signal, req, GetTabInfoRef::Busy, __LINE__); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::Busy); return; } @@ -7144,7 +7156,7 @@ void Dbdict::execGET_TABINFOREQ(Signal* signal) if(len > MAX_TAB_NAME_SIZE){ jam(); releaseSections(signal); - sendGET_TABINFOREF(signal,req,GetTabInfoRef::TableNameTooLong, __LINE__); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNameTooLong); return; } @@ -7156,7 +7168,7 @@ void Dbdict::execGET_TABINFOREQ(Signal* signal) if(!r0.getWords((Uint32*)tableName, (len+3)/4)){ jam(); releaseSections(signal); - sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined, __LINE__); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); return; } releaseSections(signal); @@ -7178,14 +7190,14 @@ void Dbdict::execGET_TABINFOREQ(Signal* signal) // The table seached for was not found if(objEntry == 0){ jam(); - sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined, __LINE__); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); return; }//if if (objEntry->m_tableState != SchemaFile::TABLE_ADD_COMMITTED && objEntry->m_tableState != SchemaFile::ALTER_TABLE_COMMITTED){ jam(); - sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined, __LINE__); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); return; }//if @@ -7199,7 +7211,7 @@ void Dbdict::execGET_TABINFOREQ(Signal* signal) tabPtr.p->tabState != TableRecord::BACKUP_ONGOING) { jam(); - sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined, __LINE__); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); return; } } @@ -7290,8 +7302,7 @@ void Dbdict::sendGetTabResponse(Signal* signal) void Dbdict::sendGET_TABINFOREF(Signal* signal, GetTabInfoReq * req, - GetTabInfoRef::ErrorCode errorCode, - Uint32 line) + GetTabInfoRef::ErrorCode errorCode) { jamEntry(); GetTabInfoRef * const ref = (GetTabInfoRef *)&signal->theData[0]; @@ -7300,9 +7311,8 @@ void Dbdict::sendGET_TABINFOREF(Signal* signal, */ BlockReference retRef = req->senderRef; ref->errorCode = errorCode; - signal->theData[GetTabInfoRef::SignalLength] = line; - sendSignal(retRef, GSN_GET_TABINFOREF, signal, - GetTabInfoRef::SignalLength+1, JBB); + + sendSignal(retRef, GSN_GET_TABINFOREF, signal, signal->length(), JBB); }//sendGET_TABINFOREF() void diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index 08ddf819a09..293632bb8b8 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -2135,8 +2135,7 @@ private: /* ------------------------------------------------------------ */ void sendGET_TABINFOREF(Signal* signal, GetTabInfoReq*, - GetTabInfoRef::ErrorCode errorCode, - Uint32 line); + GetTabInfoRef::ErrorCode errorCode); void sendGET_TABLEID_REF(Signal* signal, GetTableIdReq * req, diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 6211853f6df..91daed0e105 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -10886,7 +10886,6 @@ void Dblqh::execLCP_FRAG_ORD(Signal* signal) LcpRecord::FragOrd fragOrd; fragOrd.fragPtrI = fragptr.i; fragOrd.lcpFragOrd = * lcpFragOrd; - ndbout_c("tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE -> sendLCP_FRAG_REP"); sendLCP_FRAG_REP(signal, fragOrd); return; } @@ -10910,7 +10909,7 @@ void Dblqh::execLCP_PREPARE_REF(Signal* signal) jamEntry(); LcpPrepareRef* ref= (LcpPrepareRef*)signal->getDataPtr(); - + lcpPtr.i = ref->senderData; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_FRAGID); @@ -11182,10 +11181,6 @@ void Dblqh::sendLCP_FRAGIDREQ(Signal* signal) /** * Fake that the fragment is done */ - ndbout_c("tableStatus->contChkpNextFragLab tab: %d frag: %d", - lcpPtr.p->currentFragment.lcpFragOrd.tableId, - lcpPtr.p->currentFragment.lcpFragOrd.fragmentId); - contChkpNextFragLab(signal); return; } @@ -16026,8 +16021,22 @@ void Dblqh::findLogfile(Signal* signal, }//if locLogFilePtr.i = locLogFilePtr.p->nextLogFile; loopCount++; + if (loopCount >= flfLogPartPtr.p->noLogFiles && + getNodeState().startLevel != NodeState::SL_STARTED) + { + goto error; + } ndbrequire(loopCount < flfLogPartPtr.p->noLogFiles); }//while + +error: + char buf[255]; + BaseString::snprintf(buf, sizeof(buf), + "Unable to restart, failed while reading redo." + " Likely invalid change of configuration"); + progError(__LINE__, + ERR_INVALID_CONFIG, + buf); }//Dblqh::findLogfile() /* ------------------------------------------------------------------------- */ diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp index 3fc6184f63e..2319b84568e 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp @@ -896,6 +896,23 @@ Dbtup::disk_page_tup_scan_callback(Signal* signal, Uint32 scanPtrI, Uint32 page_ void Dbtup::scanClose(Signal* signal, ScanOpPtr scanPtr) { + ScanOp& scan = *scanPtr.p; + ndbrequire(! (scan.m_bits & ScanOp::SCAN_LOCK_WAIT) && scan.m_accLockOp == RNIL); + // unlock all not unlocked by LQH + LocalDLFifoList list(c_scanLockPool, scan.m_accLockOps); + ScanLockPtr lockPtr; + while (list.first(lockPtr)) { + jam(); + AccLockReq* const lockReq = (AccLockReq*)signal->getDataPtrSend(); + lockReq->returnCode = RNIL; + lockReq->requestInfo = AccLockReq::Abort; + lockReq->accOpPtr = lockPtr.p->m_accLockOp; + EXECUTE_DIRECT(DBACC, GSN_ACC_LOCKREQ, signal, AccLockReq::UndoSignalLength); + jamEntry(); + ndbrequire(lockReq->returnCode == AccLockReq::Success); + list.release(lockPtr); + } + // send conf NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); conf->scanPtr = scanPtr.p->m_userPtr; conf->accOperationPtr = RNIL; diff --git a/storage/ndb/src/kernel/main.cpp b/storage/ndb/src/kernel/main.cpp index 2374cce5f35..4bc9fbf76e5 100644 --- a/storage/ndb/src/kernel/main.cpp +++ b/storage/ndb/src/kernel/main.cpp @@ -307,8 +307,11 @@ int main(int argc, char** argv) /** * We no longer need the mgm connection in this process * (as we are the angel, not ndb) + * + * We don't want to purge any allocated resources (nodeid), so + * we set that option to false */ - theConfig->closeConfiguration(); + theConfig->closeConfiguration(false); int status = 0, error_exit = 0, signum = 0; while(waitpid(child, &status, 0) != child); diff --git a/storage/ndb/src/kernel/vm/Configuration.cpp b/storage/ndb/src/kernel/vm/Configuration.cpp index fe7d474b578..771fa6f5fe4 100644 --- a/storage/ndb/src/kernel/vm/Configuration.cpp +++ b/storage/ndb/src/kernel/vm/Configuration.cpp @@ -172,7 +172,8 @@ Configuration::~Configuration(){ } void -Configuration::closeConfiguration(){ +Configuration::closeConfiguration(bool end_session){ + m_config_retriever->end_session(end_session); if (m_config_retriever) { delete m_config_retriever; } diff --git a/storage/ndb/src/kernel/vm/Configuration.hpp b/storage/ndb/src/kernel/vm/Configuration.hpp index 5043d1f0bee..243ecbee4e7 100644 --- a/storage/ndb/src/kernel/vm/Configuration.hpp +++ b/storage/ndb/src/kernel/vm/Configuration.hpp @@ -35,7 +35,7 @@ public: void fetch_configuration(); void setupConfiguration(); - void closeConfiguration(); + void closeConfiguration(bool end_session= true); bool lockPagesInMainMemory() const; diff --git a/storage/ndb/src/mgmapi/mgmapi.cpp b/storage/ndb/src/mgmapi/mgmapi.cpp index 79284964186..eb93ec88b6f 100644 --- a/storage/ndb/src/mgmapi/mgmapi.cpp +++ b/storage/ndb/src/mgmapi/mgmapi.cpp @@ -2321,4 +2321,23 @@ int ndb_mgm_report_event(NdbMgmHandle handle, Uint32 *data, Uint32 length) DBUG_RETURN(0); } +extern "C" +int ndb_mgm_end_session(NdbMgmHandle handle) +{ + DBUG_ENTER("ndb_mgm_end_session"); + CHECK_HANDLE(handle, 0); + CHECK_CONNECTED(handle, 0); + + SocketOutputStream s_output(handle->socket); + s_output.println("end session"); + s_output.println(""); + + SocketInputStream in(handle->socket, handle->read_timeout); + char buf[32]; + + in.gets(buf, sizeof(buf)); + + DBUG_RETURN(0); +} + template class Vector*>; diff --git a/storage/ndb/src/mgmclient/CommandInterpreter.cpp b/storage/ndb/src/mgmclient/CommandInterpreter.cpp index b398ed46514..5496b2dadc3 100644 --- a/storage/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/storage/ndb/src/mgmclient/CommandInterpreter.cpp @@ -928,26 +928,21 @@ CommandInterpreter::executeShutdown(char* parameters) int result = 0; result = ndb_mgm_stop(m_mgmsrv, 0, 0); if (result < 0) { - ndbout << "Shutdown off NDB Cluster storage node(s) failed." << endl; + ndbout << "Shutdown of NDB Cluster node(s) failed." << endl; printError(); return result; } - ndbout << result << " NDB Cluster storage node(s) have shutdown." << endl; + ndbout << result << " NDB Cluster node(s) have shutdown." << endl; int mgm_id= 0; - for(int i=0; i < state->no_of_nodes; i++) { - if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_MGM && - state->node_states[i].version != 0){ - if (mgm_id == 0) - mgm_id= state->node_states[i].node_id; - else { - ndbout << "Unable to locate management server, " - << "shutdown manually with STOP" - << endl; - return 1; - } - } + mgm_id= ndb_mgm_get_mgmd_nodeid(m_mgmsrv); + if (mgm_id == 0) + { + ndbout << "Unable to locate management server, " + << "shutdown manually with STOP" + << endl; + return 1; } result = ndb_mgm_stop(m_mgmsrv, 1, &mgm_id); diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp index cf9965b94e0..b60679f700e 100644 --- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -60,6 +60,9 @@ #include +extern bool g_StopServer; +extern bool g_RestartServer; + //#define MGM_SRV_DEBUG #ifdef MGM_SRV_DEBUG #define DEBUG(x) do ndbout << x << endl; while(0) @@ -179,6 +182,8 @@ MgmtSrvr::startEventLog() } const char * tmp; + char errStr[100]; + int err= 0; BaseString logdest; char *clusterLog= NdbConfig_ClusterLogFileName(_ownNodeId); NdbAutoPtr tmp_aptr(clusterLog); @@ -192,9 +197,17 @@ MgmtSrvr::startEventLog() logdest.assfmt("FILE:filename=%s,maxsize=1000000,maxfiles=6", clusterLog); } - if(!g_eventLogger.addHandler(logdest)) { + errStr[0]='\0'; + if(!g_eventLogger.addHandler(logdest, &err, sizeof(errStr), errStr)) { ndbout << "Warning: could not add log destination \"" - << logdest.c_str() << "\"" << endl; + << logdest.c_str() << "\". Reason: "; + if(err) + ndbout << strerror(err); + if(err && errStr[0]!='\0') + ndbout << ", "; + if(errStr[0]!='\0') + ndbout << errStr; + ndbout << endl; } } @@ -373,7 +386,8 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _ownReference(0), theSignalIdleList(NULL), theWaitState(WAIT_SUBSCRIBE_CONF), - m_event_listner(this) + m_event_listner(this), + m_local_mgm_handle(0) { DBUG_ENTER("MgmtSrvr::MgmtSrvr"); @@ -537,6 +551,8 @@ MgmtSrvr::check_start() bool MgmtSrvr::start(BaseString &error_string) { + int mgm_connect_result; + DBUG_ENTER("MgmtSrvr::start"); if (_props == NULL) { if (!check_start()) { @@ -574,6 +590,13 @@ MgmtSrvr::start(BaseString &error_string) DBUG_RETURN(false); } + if((mgm_connect_result= connect_to_self()) < 0) + { + ndbout_c("Unable to connect to our own ndb_mgmd (Error %d)", + mgm_connect_result); + ndbout_c("This is probably a bug."); + } + TransporterRegistry *reg = theFacade->get_registry(); for(unsigned int i=0;im_transporter_interface.size();i++) { BaseString msg; @@ -831,9 +854,81 @@ MgmtSrvr::sendVersionReq(int v_nodeId, Uint32 &version, const char **address) return 0; } +int MgmtSrvr::sendStopMgmd(NodeId nodeId, + bool abort, + bool stop, + bool restart, + bool nostart, + bool initialStart) +{ + const char* hostname; + Uint32 port; + BaseString connect_string; + + { + Guard g(m_configMutex); + { + ndb_mgm_configuration_iterator + iter(* _config->m_configValues, CFG_SECTION_NODE); + + if(iter.first()) return SEND_OR_RECEIVE_FAILED; + if(iter.find(CFG_NODE_ID, nodeId)) return SEND_OR_RECEIVE_FAILED; + if(iter.get(CFG_NODE_HOST, &hostname)) return SEND_OR_RECEIVE_FAILED; + } + { + ndb_mgm_configuration_iterator + iter(* _config->m_configValues, CFG_SECTION_NODE); + + if(iter.first()) return SEND_OR_RECEIVE_FAILED; + if(iter.find(CFG_NODE_ID, nodeId)) return SEND_OR_RECEIVE_FAILED; + if(iter.get(CFG_MGM_PORT, &port)) return SEND_OR_RECEIVE_FAILED; + } + if( strlen(hostname) == 0 ) + return SEND_OR_RECEIVE_FAILED; + } + connect_string.assfmt("%s:%u",hostname,port); + + DBUG_PRINT("info",("connect string: %s",connect_string.c_str())); + + NdbMgmHandle h= ndb_mgm_create_handle(); + if ( h && connect_string.length() > 0 ) + { + ndb_mgm_set_connectstring(h,connect_string.c_str()); + if(ndb_mgm_connect(h,1,0,0)) + { + DBUG_PRINT("info",("failed ndb_mgm_connect")); + return SEND_OR_RECEIVE_FAILED; + } + if(!restart) + { + if(ndb_mgm_stop(h, 1, (const int*)&nodeId) < 0) + { + return SEND_OR_RECEIVE_FAILED; + } + } + else + { + int nodes[1]; + nodes[0]= (int)nodeId; + if(ndb_mgm_restart2(h, 1, nodes, initialStart, nostart, abort) < 0) + { + return SEND_OR_RECEIVE_FAILED; + } + } + } + ndb_mgm_destroy_handle(&h); + + return 0; +} + /* * Common method for handeling all STOP_REQ signalling that * is used by Stopping, Restarting and Single user commands + * + * In the event that we need to stop a mgmd, we create a mgm + * client connection to that mgmd and stop it that way. + * This allows us to stop mgm servers when there isn't any real + * distributed communication up. */ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId, @@ -845,6 +940,8 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId, bool nostart, bool initialStart) { + int error = 0; + stoppedNodes.clear(); SignalSender ss(theFacade); @@ -883,18 +980,34 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId, NodeBitmask nodes; if (nodeId) { + if(nodeId==getOwnNodeId()) + { + if(restart) + g_RestartServer= true; + g_StopServer= true; + return 0; + } + if(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) { int r; - if((r = okToSendTo(nodeId, true)) != 0) - return r; - } - { + if((r= okToSendTo(nodeId, true)) != 0) + return r; if (ss.sendSignal(nodeId, &ssig) != SEND_OK) return SEND_OR_RECEIVE_FAILED; } + else if(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) + { + error= sendStopMgmd(nodeId, abort, stop, restart, nostart, initialStart); + if(error==0) + stoppedNodes.set(nodeId); + return error; + } + else + return WRONG_PROCESS_TYPE; nodes.set(nodeId); } else + { while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) { if(okToSendTo(nodeId, true) == 0) @@ -904,9 +1017,17 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId, nodes.set(nodeId); } } + nodeId= 0; + while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_MGM)) + { + if(nodeId==getOwnNodeId()) + continue; + if(sendStopMgmd(nodeId, abort, stop, restart, nostart, initialStart)==0) + stoppedNodes.set(nodeId); + } + } // now wait for the replies - int error = 0; while (!nodes.isclear()) { SimpleSignal *signal = ss.waitFor(); @@ -2552,9 +2673,23 @@ void MgmtSrvr::transporter_connect(NDB_SOCKET_TYPE sockfd) } } -int MgmtSrvr::set_connect_string(const char *str) +int MgmtSrvr::connect_to_self(void) { - return ndb_mgm_set_connectstring(m_config_retriever->get_mgmHandle(),str); + int r= 0; + m_local_mgm_handle= ndb_mgm_create_handle(); + snprintf(m_local_mgm_connect_string,sizeof(m_local_mgm_connect_string), + "localhost:%u",getPort()); + ndb_mgm_set_connectstring(m_local_mgm_handle, m_local_mgm_connect_string); + + if((r= ndb_mgm_connect(m_local_mgm_handle, 0, 0, 0)) < 0) + { + ndb_mgm_destroy_handle(&m_local_mgm_handle); + return r; + } + // TransporterRegistry now owns this NdbMgmHandle and will destroy it. + theFacade->get_registry()->set_mgm_handle(m_local_mgm_handle); + + return 0; } diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp index ec6ab47bc2a..20e6ff1bc43 100644 --- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -466,7 +466,7 @@ public: int getConnectionDbParameter(int node1, int node2, int param, int *value, BaseString& msg); - int set_connect_string(const char *str); + int connect_to_self(void); void transporter_connect(NDB_SOCKET_TYPE sockfd); @@ -482,6 +482,13 @@ private: int send(SignalSender &ss, SimpleSignal &ssig, Uint32 node, Uint32 node_type); + int sendStopMgmd(NodeId nodeId, + bool abort, + bool stop, + bool restart, + bool nostart, + bool initialStart); + int sendSTOP_REQ(NodeId nodeId, NodeBitmask &stoppedNodes, Uint32 singleUserNodeId, @@ -625,6 +632,8 @@ private: // signal arrives. // We wait in receiveOptimisedResponse and signal in handleReceivedSignal. + NdbMgmHandle m_local_mgm_handle; + char m_local_mgm_connect_string[20]; class TransporterFacade * theFacade; int sendVersionReq( int processId, Uint32 &version, const char **address); diff --git a/storage/ndb/src/mgmsrv/Services.cpp b/storage/ndb/src/mgmsrv/Services.cpp index ee24cf18941..80f0aa2eda8 100644 --- a/storage/ndb/src/mgmsrv/Services.cpp +++ b/storage/ndb/src/mgmsrv/Services.cpp @@ -203,6 +203,8 @@ ParserRow commands[] = { MGM_CMD("bye", &MgmApiSession::bye, ""), + MGM_CMD("end session", &MgmApiSession::endSession, ""), + MGM_CMD("set loglevel", &MgmApiSession::setLogLevel, ""), MGM_ARG("node", Int, Mandatory, "Node"), MGM_ARG("category", Int, Mandatory, "Event category"), @@ -719,10 +721,21 @@ MgmApiSession::dumpState(Parser::Context &, void MgmApiSession::bye(Parser::Context &, - Properties const &) { + Properties const &) { m_stop = true; } +void +MgmApiSession::endSession(Parser::Context &, + Properties const &) { + if(m_allocated_resources) + delete m_allocated_resources; + + m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv); + + m_output->println("end session reply"); +} + void MgmApiSession::setClusterLogLevel(Parser::Context &, Properties const &args) { diff --git a/storage/ndb/src/mgmsrv/Services.hpp b/storage/ndb/src/mgmsrv/Services.hpp index 30f220cd060..f97223750a1 100644 --- a/storage/ndb/src/mgmsrv/Services.hpp +++ b/storage/ndb/src/mgmsrv/Services.hpp @@ -79,6 +79,7 @@ public: void start(Parser_t::Context &ctx, const class Properties &args); void startAll(Parser_t::Context &ctx, const class Properties &args); void bye(Parser_t::Context &ctx, const class Properties &args); + void endSession(Parser_t::Context &ctx, const class Properties &args); void setLogLevel(Parser_t::Context &ctx, const class Properties &args); void setClusterLogLevel(Parser_t::Context &ctx, const class Properties &args); diff --git a/storage/ndb/src/mgmsrv/main.cpp b/storage/ndb/src/mgmsrv/main.cpp index f0c2ac298a5..5960a3517b5 100644 --- a/storage/ndb/src/mgmsrv/main.cpp +++ b/storage/ndb/src/mgmsrv/main.cpp @@ -132,6 +132,7 @@ static MgmGlobals *glob= 0; * Global variables */ bool g_StopServer; +bool g_RestartServer; extern EventLogger g_eventLogger; extern int global_mgmt_server_check; @@ -191,7 +192,22 @@ static void usage() */ int main(int argc, char** argv) { + int mgm_connect_result; + NDB_INIT(argv[0]); + + const char *load_default_groups[]= { "mysql_cluster","ndb_mgmd",0 }; + load_defaults("my",load_default_groups,&argc,&argv); + + int ho_error; +#ifndef DBUG_OFF + opt_debug= "d:t:O,/tmp/ndb_mgmd.trace"; +#endif + if ((ho_error=handle_options(&argc, &argv, my_long_options, + ndb_std_get_one_option))) + exit(ho_error); + +start: glob= new MgmGlobals; /** @@ -204,17 +220,6 @@ int main(int argc, char** argv) #endif global_mgmt_server_check = 1; - - const char *load_default_groups[]= { "mysql_cluster","ndb_mgmd",0 }; - load_defaults("my",load_default_groups,&argc,&argv); - - int ho_error; -#ifndef DBUG_OFF - opt_debug= "d:t:O,/tmp/ndb_mgmd.trace"; -#endif - if ((ho_error=handle_options(&argc, &argv, my_long_options, - ndb_std_get_one_option))) - exit(ho_error); if (opt_interactive || opt_non_interactive || @@ -293,34 +298,12 @@ int main(int argc, char** argv) goto error_end; } - /* Construct a fake connectstring to connect back to ourselves */ - char connect_str[20]; - if(!opt_connect_str) { - snprintf(connect_str,20,"localhost:%u",glob->mgmObject->getPort()); - opt_connect_str= connect_str; - } - glob->mgmObject->set_connect_string(opt_connect_str); - if(!glob->mgmObject->check_start()){ ndbout_c("Unable to check start management server."); ndbout_c("Probably caused by illegal initial configuration file."); goto error_end; } - /* - * Connect back to ourselves so we can use mgmapi to fetch - * config info - */ - int mgm_connect_result; - mgm_connect_result = glob->mgmObject->get_config_retriever()-> - do_connect(0,0,0); - - if(mgm_connect_result<0) { - ndbout_c("Unable to connect to our own ndb_mgmd (Error %d)", - mgm_connect_result); - ndbout_c("This is probably a bug."); - } - if (opt_daemon) { // Become a daemon char *lockfile= NdbConfig_PidFileName(glob->localNodeId); @@ -361,6 +344,7 @@ int main(int argc, char** argv) g_eventLogger.info(msg); g_StopServer = false; + g_RestartServer= false; glob->socketServer->startServer(); #if ! defined NDB_OSE && ! defined NDB_SOFTOSE @@ -378,14 +362,19 @@ int main(int argc, char** argv) while(g_StopServer != true) NdbSleep_MilliSleep(500); } - - g_eventLogger.info("Shutting down server..."); + + if(g_RestartServer) + g_eventLogger.info("Restarting server..."); + else + g_eventLogger.info("Shutting down server..."); glob->socketServer->stopServer(); - glob->mgmObject->get_config_retriever()->disconnect(); + // We disconnect from the ConfigRetreiver mgmd when we delete glob below glob->socketServer->stopSessions(true); g_eventLogger.info("Shutdown complete"); the_end: delete glob; + if(g_RestartServer) + goto start; ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); return 0; error_end: diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 349ec6f4a7b..695781bddb9 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -31,7 +31,21 @@ */ static const bool g_ndb_blob_ok_to_read_index_table = false; -// state (inline) +// get state + +NdbBlob::State +NdbBlob::getState() +{ + return theState; +} + +void +NdbBlob::getVersion(int& version) +{ + version = theEventBlobVersion; +} + +// set state (inline) inline void NdbBlob::setState(State newState) @@ -608,7 +622,7 @@ NdbBlob::setActiveHook(ActiveHook activeHook, void* arg) // misc operations int -NdbBlob::getDefined(int& isNull) +NdbBlob::getDefined(int& isNull) // deprecated { DBUG_ENTER("NdbBlob::getDefined"); if (theState == Prepared && theSetFlag) { @@ -620,7 +634,7 @@ NdbBlob::getDefined(int& isNull) } int -NdbBlob::getNull(bool& isNull) +NdbBlob::getNull(bool& isNull) // deprecated { DBUG_ENTER("NdbBlob::getNull"); if (theState == Prepared && theSetFlag) { @@ -635,6 +649,23 @@ NdbBlob::getNull(bool& isNull) DBUG_RETURN(0); } +int +NdbBlob::getNull(int& isNull) +{ + DBUG_ENTER("NdbBlob::getNull"); + if (theState == Prepared && theSetFlag) { + isNull = (theSetBuf == NULL); + DBUG_RETURN(0); + } + isNull = theNullFlag; + if (isNull == -1 && theEventBlobVersion == -1) { + setErrorCode(NdbBlobImpl::ErrState); + DBUG_RETURN(-1); + } + DBUG_PRINT("info", ("isNull=%d", isNull)); + DBUG_RETURN(0); +} + int NdbBlob::setNull() { @@ -1085,6 +1116,8 @@ NdbBlob::deletePartsUnknown(Uint32 part) { DBUG_ENTER("NdbBlob::deletePartsUnknown"); DBUG_PRINT("info", ("part=%u count=all", part)); + if (thePartSize == 0) // tinyblob + DBUG_RETURN(0); static const unsigned maxbat = 256; static const unsigned minbat = 1; unsigned bat = minbat; diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 75760fb4019..31234d683d7 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -87,7 +87,12 @@ NdbColumnImpl::operator=(const NdbColumnImpl& col) m_arrayType = col.m_arrayType; m_storageType = col.m_storageType; m_keyInfoPos = col.m_keyInfoPos; - m_blobTable = col.m_blobTable; + if (col.m_blobTable == NULL) + m_blobTable = NULL; + else { + m_blobTable = new NdbTableImpl(); + m_blobTable->assign(*col.m_blobTable); + } m_column_no = col.m_column_no; // Do not copy m_facade !! @@ -2747,14 +2752,25 @@ NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl) } int -NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl) +NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl, bool lock) { const char * internalTableName = impl.m_internalName.c_str(); + if (lock) + m_globalHash->lock(); + if (impl.m_noOfBlobs != 0) { + for (uint i = 0; i < impl.m_columns.size(); i++) { + NdbColumnImpl& c = *impl.m_columns[i]; + if (! c.getBlobType() || c.getPartSize() == 0) + continue; + assert(c.m_blobTable != NULL); + removeCachedObject(*c.m_blobTable, false); + } + } m_localHash.drop(internalTableName); - m_globalHash->lock(); m_globalHash->release(&impl); - m_globalHash->unlock(); + if (lock) + m_globalHash->unlock(); return 0; } diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 6b20625bcdc..1685c3122a3 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -545,7 +545,7 @@ public: int dropTable(NdbTableImpl &); int dropBlobTables(NdbTableImpl &); int invalidateObject(NdbTableImpl &); - int removeCachedObject(NdbTableImpl &); + int removeCachedObject(NdbTableImpl &, bool lock = true); int createIndex(NdbIndexImpl &ix); int dropIndex(const char * indexName, diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index 0a9993e33a1..82bfb8e2228 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -342,15 +342,18 @@ NdbEventOperationImpl::getBlobHandle(const NdbColumnImpl *tAttrInfo, int n) tBlobOp = tBlobOp->m_next; } - DBUG_PRINT("info", ("%s op %s", tBlobOp ? " reuse" : " create", bename)); + DBUG_PRINT("info", ("%s blob event op for %s", + tBlobOp ? " reuse" : " create", bename)); // create blob event op if not found if (tBlobOp == NULL) { // to hide blob op it is linked under main op, not under m_ndb NdbEventOperation* tmp = m_ndb->theEventBuffer->createEventOperation(bename, m_error); - if (tmp == NULL) + if (tmp == NULL) { + m_error.code = m_ndb->theEventBuffer->m_error.code; DBUG_RETURN(NULL); + } tBlobOp = &tmp->m_impl; // pointer to main table op @@ -367,11 +370,14 @@ NdbEventOperationImpl::getBlobHandle(const NdbColumnImpl *tAttrInfo, int n) } tBlob = m_ndb->getNdbBlob(); - if (tBlob == NULL) + if (tBlob == NULL) { + m_error.code = m_ndb->getNdbError().code; DBUG_RETURN(NULL); + } // calls getValue on inline and blob part if (tBlob->atPrepare(this, tBlobOp, tAttrInfo, n) == -1) { + m_error.code = tBlob->getNdbError().code; m_ndb->releaseNdbBlob(tBlob); DBUG_RETURN(NULL); } diff --git a/storage/ndb/tools/ndb_size.pl b/storage/ndb/tools/ndb_size.pl index e0085c619f0..c285a7590fd 100644 --- a/storage/ndb/tools/ndb_size.pl +++ b/storage/ndb/tools/ndb_size.pl @@ -147,7 +147,7 @@ foreach(@{$tables}) { my $fixed= 1+$size; my @dynamic=$dbh->selectrow_array("select avg(length(`" - .$name. + .$name ."`)) from `".$table.'`'); $dynamic[0]=0 if !$dynamic[0]; @realsize= ($fixed,$fixed,ceil($dynamic[0])); diff --git a/storage/ndb/tools/restore/consumer_restore.cpp b/storage/ndb/tools/restore/consumer_restore.cpp index ad33cbe7b85..200925bf8bb 100644 --- a/storage/ndb/tools/restore/consumer_restore.cpp +++ b/storage/ndb/tools/restore/consumer_restore.cpp @@ -453,15 +453,15 @@ BackupRestore::object(Uint32 type, const void * ptr) { NdbDictionary::LogfileGroup * lg = m_logfilegroups[old.getDefaultLogfileGroupId()]; old.setDefaultLogfileGroup(* lg); + info << "Creating tablespace: " << old.getName() << "..." << flush; int ret = dict->createTablespace(old); if (ret) { NdbError errobj= dict->getNdbError(); - err << "Failed to create tablespace \"" << old.getName() << "\": " - << errobj << endl; + info << "FAILED " << errobj << endl; return false; } - debug << "Created tablespace: " << old.getName() << endl; + info << "done" << endl; } NdbDictionary::Tablespace curr = dict->getTablespace(old.getName()); @@ -491,15 +491,15 @@ BackupRestore::object(Uint32 type, const void * ptr) if (!m_no_restore_disk) { + info << "Creating logfile group: " << old.getName() << "..." << flush; int ret = dict->createLogfileGroup(old); if (ret) { NdbError errobj= dict->getNdbError(); - err << "Failed to create logfile group \"" << old.getName() << "\": " - << errobj << endl; + info << "FAILED" << errobj << endl; return false; } - debug << "Created logfile group: " << old.getName() << endl; + info << "done" << endl; } NdbDictionary::LogfileGroup curr = dict->getLogfileGroup(old.getName()); @@ -532,12 +532,13 @@ BackupRestore::object(Uint32 type, const void * ptr) << " to tablespace: oldid: " << old.getTablespaceId() << " newid: " << ts->getObjectId() << endl; old.setTablespace(* ts); + info << "Creating datafile \"" << old.getPath() << "\"..." << flush; if (dict->createDatafile(old)) { - err << "Failed to create datafile \"" << old.getPath() << "\": " - << dict->getNdbError() << endl; + info << "FAILED " << dict->getNdbError() << endl; return false; } + info << "done" << endl; } return true; break; @@ -554,12 +555,13 @@ BackupRestore::object(Uint32 type, const void * ptr) << " newid: " << lg->getObjectId() << " " << (void*)lg << endl; old.setLogfileGroup(* lg); + info << "Creating undofile \"" << old.getPath() << "\"..." << flush; if (dict->createUndofile(old)) { - err << "Failed to create undofile \"" << old.getPath() << "\": " - << dict->getNdbError() << endl; + info << "FAILED " << dict->getNdbError() << endl; return false; } + info << "done" << endl; } return true; break; diff --git a/support-files/MySQL-shared-compat.spec.sh b/support-files/MySQL-shared-compat.spec.sh index ffc96fd6fff..72ebf4d4d2b 100644 --- a/support-files/MySQL-shared-compat.spec.sh +++ b/support-files/MySQL-shared-compat.spec.sh @@ -23,16 +23,19 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA +# For 5.0 and up, this is needed because of "libndbclient". +%define _unpackaged_files_terminate_build 0 + # # Change this to match the version of the shared libs you want to include # %define version50 @MYSQL_NO_DASH_VERSION@ -%define version41 4.1.9 -%define version40 4.0.23 +%define version41 4.1.16 +%define version40 4.0.26 %define version3 3.23.58 Name: MySQL-shared-compat -Packager: Lenz Grimmer +Packager: MySQL Product Engineering team Vendor: MySQL AB License: GPL Group: Applications/Databases @@ -47,7 +50,7 @@ Summary: MySQL shared client libraries for MySQL %{version}, %{version41}, # We simply use the "MySQL-shared" subpackages as input sources instead of # rebuilding all from source Source0: MySQL-shared-%{version50}-0.%{_arch}.rpm -Source1: MySQL-shared-%{version41}-0.%{_arch}.rpm +Source1: MySQL-shared-%{version41}-1.%{_arch}.rpm Source2: MySQL-shared-%{version40}-0.%{_arch}.rpm Source3: MySQL-shared-%{version3}-1.%{_arch}.rpm # No need to include the RPMs once more - they can be downloaded seperately diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index d33654d8810..e118289101e 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14697,7 +14697,86 @@ static void test_opt_reconnect() mysql_close(lmysql); } +/* Bug #16144: mysql_stmt_attr_get type error */ +static void test_bug16144() +{ + const my_bool flag_orig= (my_bool) 0xde; + my_bool flag= flag_orig; + MYSQL_STMT *stmt; + myheader("test_bug16144"); + + /* Check that attr_get returns correct data on little and big endian CPUs */ + stmt= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void*) &flag); + mysql_stmt_attr_get(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &flag); + DIE_UNLESS(flag == flag_orig); + mysql_stmt_close(stmt); +} + +/* + Bug #15613: "libmysqlclient API function mysql_stmt_prepare returns wrong + field length" +*/ + +static void test_bug15613() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + MYSQL_RES *metadata; + MYSQL_FIELD *field; + int rc; + myheader("test_bug15613"); + + /* I. Prepare the table */ + rc= mysql_query(mysql, "set names latin1"); + myquery(rc); + mysql_query(mysql, "drop table if exists t1"); + rc= mysql_query(mysql, + "create table t1 (t text character set utf8, " + "tt tinytext character set utf8, " + "mt mediumtext character set utf8, " + "lt longtext character set utf8, " + "vl varchar(255) character set latin1," + "vb varchar(255) character set binary," + "vu varchar(255) character set utf8)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + /* II. Check SELECT metadata */ + stmt_text= ("select t, tt, mt, lt, vl, vb, vu from t1"); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_fields(metadata); + if (!opt_silent) + { + printf("Field lengths (client character set is latin1):\n" + "text character set utf8:\t\t%lu\n" + "tinytext character set utf8:\t\t%lu\n" + "mediumtext character set utf8:\t\t%lu\n" + "longtext character set utf8:\t\t%lu\n" + "varchar(255) character set latin1:\t%lu\n" + "varchar(255) character set binary:\t%lu\n" + "varchar(255) character set utf8:\t%lu\n", + field[0].length, field[1].length, field[2].length, field[3].length, + field[4].length, field[5].length, field[6].length); + } + DIE_UNLESS(field[0].length == 65535); + DIE_UNLESS(field[1].length == 255); + DIE_UNLESS(field[2].length == 16777215); + DIE_UNLESS(field[3].length == 4294967295UL); + DIE_UNLESS(field[4].length == 255); + DIE_UNLESS(field[5].length == 255); + DIE_UNLESS(field[6].length == 255); + + /* III. Cleanup */ + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + rc= mysql_query(mysql, "set names default"); + myquery(rc); + mysql_stmt_close(stmt); +} /* Read and parse arguments and MySQL options from my.cnf */ @@ -14957,9 +15036,10 @@ static struct my_tests_st my_tests[]= { { "test_bug13488", test_bug13488 }, { "test_bug13524", test_bug13524 }, { "test_bug14845", test_bug14845 }, - { "test_bug15510", test_bug15510 }, { "test_opt_reconnect", test_opt_reconnect }, - + { "test_bug15510", test_bug15510}, + { "test_bug16144", test_bug16144 }, + { "test_bug15613", test_bug15613 }, { 0, 0 } }; diff --git a/zlib/Makefile.am b/zlib/Makefile.am index 11b1991fa62..71619ce40c1 100644 --- a/zlib/Makefile.am +++ b/zlib/Makefile.am @@ -16,6 +16,8 @@ # Process this file with automake to create Makefile.in +INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include + pkglib_LTLIBRARIES=libz.la libz_la_LDFLAGS= -version-info 3:3:2 diff --git a/zlib/README.MySQL b/zlib/README.MySQL index 355dfb62d71..c17d3eeb6f9 100644 --- a/zlib/README.MySQL +++ b/zlib/README.MySQL @@ -5,3 +5,12 @@ original zlib distribution. You can find the original distribution at http://www.gzip.org/zlib/ or http://www.zlib.net/ + +Revision history: + +20.01.2006. The following files were changed as part of #15787 fix: + makefile.am + gzio.c + zconf.h + README.mysql + diff --git a/zlib/gzio.c b/zlib/gzio.c index 7e90f4928fc..afac5352323 100644 --- a/zlib/gzio.c +++ b/zlib/gzio.c @@ -7,10 +7,10 @@ /* @(#) $Id$ */ -#include - #include "zutil.h" +#include + #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif diff --git a/zlib/zconf.h b/zlib/zconf.h index 03a9431c8be..d983fa3eed4 100644 --- a/zlib/zconf.h +++ b/zlib/zconf.h @@ -8,6 +8,10 @@ #ifndef ZCONF_H #define ZCONF_H +#ifdef HAVE_CONFIG_H +#include +#endif + /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. @@ -284,7 +288,7 @@ typedef uLong FAR uLongf; typedef Byte *voidp; #endif -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +#ifdef HAVE_UNISTD_H # include /* for off_t */ # include /* for SEEK_* and off_t */ # ifdef VMS