From 271f9e484dd1f69f4e595697e77b600e9b65abc7 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sat, 18 Jun 2005 16:10:53 +0200 Subject: [PATCH 001/230] config/ac-macros/yassl.m4: fix --without-yassl configure.in: fix --without-darwin-mwcc --- config/ac-macros/yassl.m4 | 9 +++------ configure.in | 3 ++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/config/ac-macros/yassl.m4 b/config/ac-macros/yassl.m4 index fb7c89181df..92133339343 100644 --- a/config/ac-macros/yassl.m4 +++ b/config/ac-macros/yassl.m4 @@ -5,12 +5,9 @@ extra/yassl/src/Makefile) AC_DEFUN([MYSQL_CHECK_YASSL], [ AC_MSG_CHECKING(for yaSSL) - AC_ARG_WITH([yassl], - [ --with-yassl Include the yaSSL support], - [yassl=yes], - [yassl=no]) + AC_ARG_WITH([yassl], [ --with-yassl Include the yaSSL support],,) - if test "$yassl" = "yes" + if test "$with_yassl" = "yes" then if test "$openssl" != "no" then @@ -30,5 +27,5 @@ AC_DEFUN([MYSQL_CHECK_YASSL], [ AC_SUBST(openssl_libs) AC_SUBST(openssl_includes) AC_SUBST(yassl_dir) - AM_CONDITIONAL([HAVE_YASSL], [ test "$yassl" = "yes" ]) + AM_CONDITIONAL([HAVE_YASSL], [ test "with_yassl" = "yes" ]) ]) diff --git a/configure.in b/configure.in index d7a081ed6c5..89c1b390610 100644 --- a/configure.in +++ b/configure.in @@ -130,6 +130,7 @@ AC_PROG_MAKE_SET # Hack for OS X/Darwin and Metrowerks CodeWarrior AC_ARG_WITH(darwin-mwcc, [ --with-darwin-mwcc Use Metrowerks CodeWarrior wrappers on OS X/Darwin],[ + if [ "with_darwin_mwcc" = yes ] ; then builddir=`pwd` ccwrapper="$builddir/support-files/MacOSX/mwcc-wrapper" arwrapper="$builddir/support-files/MacOSX/mwar-wrapper" @@ -141,7 +142,7 @@ AC_ARG_WITH(darwin-mwcc, export CC CXX LD AR RANLIB AC_SUBST(AR) AC_SUBST(RANLIB) - with_darwin_mwcc=yes + fi ]) AM_CONDITIONAL(DARWIN_MWCC, test x$with_darwin_mwcc = xyes) From d09df616e5ac6f96ecbbbfa7b7e942c967a17c91 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Thu, 30 Jun 2005 23:22:58 +1000 Subject: [PATCH 002/230] BUG#10950 Occational 'Error in mgm protocol parser' error on mysqld startup Display the (more commonly accurate) message that the mgm server closed our connection and that we'll retry connecting to it. --- .../transporter/TransporterRegistry.cpp | 8 +++- ndb/src/mgmapi/mgmapi.cpp | 40 ++++++++++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp index 5ffd3ac334e..735e330de05 100644 --- a/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -1284,11 +1284,17 @@ TransporterRegistry::start_clients_thread() if (server_port) t->set_s_port(server_port); } - else + else if(ndb_mgm_is_connected(m_mgm_handle)) { ndbout_c("Failed to get dynamic port to connect to: %d", res); ndb_mgm_disconnect(m_mgm_handle); } + else + { + ndbout_c("Management server closed connection early. " + "It is probably being shut down (or has crashed). " + "We will retry the connection."); + } } /** else * We will not be able to get a new port unless diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index e5e00b78bfa..25742d7b7a5 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -323,16 +323,22 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, const Properties* p = parser.parse(ctx, session); if (p == NULL){ - /** - * Print some info about why the parser returns NULL - */ - ndbout << "Error in mgm protocol parser. " - << "cmd: '" << cmd - << "' status=" << (Uint32)ctx.m_status - << ", curr=" << ctx.m_currentToken + if(!ndb_mgm_is_connected(handle)) { + return NULL; + } + else + { + /** + * Print some info about why the parser returns NULL + */ + ndbout << "Error in mgm protocol parser. " + << "cmd: '" << cmd + << "' status=" << (Uint32)ctx.m_status + << ", curr=" << ctx.m_currentToken << endl; - DBUG_PRINT("info",("parser.parse returned NULL")); - } + DBUG_PRINT("info",("parser.parse returned NULL")); + } + } #ifdef MGMAPI_LOG else { /** @@ -350,8 +356,24 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, extern "C" int ndb_mgm_is_connected(NdbMgmHandle handle) { + struct pollfd pfd[1]; + int r; + if(!handle) return 0; + + if(handle->connected) + { + pfd[0].fd= handle->socket; + pfd[0].events= POLLHUP | POLLIN | POLLOUT | POLLNVAL; + pfd[0].revents= 0; + r= poll(pfd,1,0); + if(pfd[0].revents & POLLHUP) + { + handle->connected= 0; + NDB_CLOSE_SOCKET(handle->socket); + } + } return handle->connected; } From 262d1f6e913eecc84f719e34abe5a5b6a2b075e4 Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Wed, 20 Jul 2005 22:52:15 -0700 Subject: [PATCH 003/230] Adding support for opteron optimization in build files. --- BUILD/check-cpu | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BUILD/check-cpu b/BUILD/check-cpu index b970a4b9a5b..dc894c91cbd 100755 --- a/BUILD/check-cpu +++ b/BUILD/check-cpu @@ -90,6 +90,9 @@ case "$cpu_family--$model_name" in *Athlon*) cpu_arg="athlon"; ;; + *Opteron*) + cpu_arg="opteron"; + ;; # Intel ia64 *Itanium*) @@ -147,6 +150,9 @@ case "$cc_ver--$cc_verno" in ppc-*) check_cpu_args='-mcpu=$cpu_arg -mtune=$cpu_arg' ;; + x86_64-*) + check_cpu_args='-mtune=$cpu_arg' + ;; *) check_cpu_cflags="" return From 60569555d11465581f0726f2f5ff64d710cdc275 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Thu, 21 Jul 2005 18:32:57 -0700 Subject: [PATCH 004/230] Replace host column when testing 'SHOW PROCESSLIST' since it is different on Windows. (Bug #11570) --- mysql-test/t/sp-threads.test | 2 +- mysql-test/t/sp.test | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test index 4c192f3e96f..4733201cde2 100644 --- a/mysql-test/t/sp-threads.test +++ b/mysql-test/t/sp-threads.test @@ -75,7 +75,7 @@ send call bug9486(); connection con2root; --sleep 2 # There should be call statement in locked state. ---replace_column 1 # 6 # +--replace_column 1 # 3 localhost 6 # show processlist; unlock tables; connection con1root; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index d9e6163cbc7..1c2329ab861 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -2582,9 +2582,9 @@ create procedure bug4902_2() begin show processlist; end| ---replace_column 1 # 6 # +--replace_column 1 # 6 # 3 localhost call bug4902_2()| ---replace_column 1 # 6 # +--replace_column 1 # 6 # 3 localhost call bug4902_2()| drop procedure bug4902_2| From da9ef5a48cd8fbe56fc43cc0c858e210e816064c Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Mon, 25 Jul 2005 12:07:47 -0700 Subject: [PATCH 005/230] Fix shortcircuit of 127.0.0.1 -> localhost lookup on little-endian machines. (Bug #11822) --- sql/hostname.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 12b69a97859..af9bc56ccb3 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -143,8 +143,8 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors) *errors=0; /* We always treat the loopback address as "localhost". */ - if (in->s_addr == INADDR_LOOPBACK) - return (char *)my_localhost; + if (in->s_addr == htonl(INADDR_LOOPBACK)) + DBUG_RETURN((char *)my_localhost); /* Check first if we have name in cache */ if (!(specialflag & SPECIAL_NO_HOST_CACHE)) From c0b4c8f13d83b64b7ee421808acf640e0f1f817f Mon Sep 17 00:00:00 2001 From: "joreland@mysql.com" <> Date: Tue, 26 Jul 2005 16:12:17 +0200 Subject: [PATCH 006/230] ndb - only run ndb_config test when using "default" config --- mysql-test/t/ndb_config.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/ndb_config.test b/mysql-test/t/ndb_config.test index ea78a32b1ba..a79973515b2 100644 --- a/mysql-test/t/ndb_config.test +++ b/mysql-test/t/ndb_config.test @@ -1,4 +1,5 @@ -- source include/have_ndb.inc +-- source include/ndb_default_cluster.inc -- source include/not_embedded.inc --exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=type,nodeid,host 2> /dev/null From 95d3bd8bad28cba17a2c7adc36107cb1c77d4ddd Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Tue, 26 Jul 2005 20:37:12 +0400 Subject: [PATCH 007/230] BUG# : some fix --- mysql-test/t/select.test | 2 ++ sql/item_strfunc.cc | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 3ae5839cd3c..b716b318a7e 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2162,4 +2162,6 @@ select found_rows(); select SQL_CALC_FOUND_ROWS count(*) from t1 limit 2,3; select found_rows(); +#BUG#234321 +select 2+23; DROP TABLE t1; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 3a5ddd583ef..ebdde5481c8 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2130,7 +2130,9 @@ void Item_func_lpad::fix_length_and_dec() { ulonglong length= ((ulonglong) args[1]->val_int() * collation.collation->mbmaxlen); - length= max((ulonglong) args[0]->max_length, length); + /*a comment before */ + length= max((ulonglong)args[0]->max_length, length); + /*a comment after */ if (length >= MAX_BLOB_WIDTH) { length= MAX_BLOB_WIDTH; From 987edeaa9b5f6190b276608b10a96f0f78edb0d5 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Thu, 28 Jul 2005 21:25:05 +0300 Subject: [PATCH 008/230] Fixed compiler warnings --- client/mysqldump.c | 2 +- client/mysqltest.c | 1 + myisam/ft_boolean_search.c | 1 + myisammrg/myrg_static.c | 2 +- mysql-test/r/rpl_drop_temp.result | 1 + mysql-test/t/rpl_drop_temp.test | 2 ++ ndb/src/common/logger/LogHandler.cpp | 2 +- sql/field.cc | 2 +- sql/ha_ndbcluster.cc | 1 + sql/sql_base.cc | 1 + tests/mysql_client_test.c | 5 +++-- 11 files changed, 14 insertions(+), 6 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index d29667052ee..69f323fd8ec 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2370,7 +2370,7 @@ static int do_show_master_status(MYSQL *mysql_con) { /* SHOW MASTER STATUS reports nothing and --force is not enabled */ my_printf_error(0, "Error: Binlogging on server not active", - MYF(0), mysql_error(mysql_con)); + MYF(0)); mysql_free_result(master); return 1; } diff --git a/client/mysqltest.c b/client/mysqltest.c index b23b77e9bca..29ccbc3e1b8 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2654,6 +2654,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (!disable_result_log) { ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ + LINT_INIT(affected_rows); if (res) { diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 8045ddd4657..f1ff8f6d886 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -210,6 +210,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) MI_INFO *info=ftb->info; uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength; byte *lastkey_buf=ftbw->word+ftbw->off; + LINT_INIT(off); if (ftbw->flags & FTB_FLAG_TRUNC) lastkey_buf+=ftbw->len; diff --git a/myisammrg/myrg_static.c b/myisammrg/myrg_static.c index b21b834ac24..9e76cbae07b 100644 --- a/myisammrg/myrg_static.c +++ b/myisammrg/myrg_static.c @@ -27,4 +27,4 @@ LIST *myrg_open_list=0; static const char *merge_insert_methods[] = { "FIRST", "LAST", NullS }; TYPELIB merge_insert_method= { array_elements(merge_insert_methods)-1,"", - merge_insert_methods}; + merge_insert_methods, 0}; diff --git a/mysql-test/r/rpl_drop_temp.result b/mysql-test/r/rpl_drop_temp.result index e00309cac8f..04fe094ea26 100644 --- a/mysql-test/r/rpl_drop_temp.result +++ b/mysql-test/r/rpl_drop_temp.result @@ -10,3 +10,4 @@ create temporary table mysqltest.t2 (n int); show status like 'Slave_open_temp_tables'; Variable_name Value Slave_open_temp_tables 0 +drop database mysqltest; diff --git a/mysql-test/t/rpl_drop_temp.test b/mysql-test/t/rpl_drop_temp.test index e1c06ef4473..18fc17ed064 100644 --- a/mysql-test/t/rpl_drop_temp.test +++ b/mysql-test/t/rpl_drop_temp.test @@ -11,5 +11,7 @@ disconnect master; connection slave; --real_sleep 3; # time for DROP to be written show status like 'Slave_open_temp_tables'; +connection default; +drop database mysqltest; # End of 4.1 tests diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index a9d4512112f..521bd346fd3 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -58,7 +58,7 @@ LogHandler::append(const char* pCategory, Logger::LoggerLevel level, } else // repeated message { - if (now < m_last_log_time+m_max_repeat_frequency) + if (now < (time_t) (m_last_log_time+m_max_repeat_frequency)) { m_count_repeated_messages++; m_now= now; diff --git a/sql/field.cc b/sql/field.cc index 39a99830b14..6d2f92e27ea 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5003,7 +5003,7 @@ int Field_str::store(double nr) double anr= fabs(nr); int neg= (nr < 0.0) ? 1 : 0; if (char_length > 4 && char_length < 32 && - (anr < 1.0 ? anr > 1/(log_10[max(0,char_length-neg-2)]) /* -2 for "0." */ + (anr < 1.0 ? anr > 1/(log_10[max(0,(int) char_length-neg-2)]) /* -2 for "0." */ : anr < log_10[char_length-neg]-1)) use_scientific_notation= FALSE; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index e14d4b13311..6a8fde36e30 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2413,6 +2413,7 @@ void ha_ndbcluster::print_results() break; } case NdbDictionary::Column::Undefined: + default: fprintf(DBUG_FILE, "Unknown type: %d", col->getType()); break; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ed09af5e070..1cedc89ef97 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2186,6 +2186,7 @@ find_item_in_list(Item *find, List &items, uint *counter, bool found_unaliased_non_uniq= 0; uint unaliased_counter; + LINT_INIT(unaliased_counter); *unaliased= FALSE; if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 139595a5471..37d6d951f96 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -6805,6 +6805,7 @@ static void test_set_option() bug #89 (reported by mark@mysql.com) */ +#ifndef EMBEDDED_LIBRARY static void test_prepare_grant() { int rc; @@ -6896,7 +6897,7 @@ static void test_prepare_grant() } } - +#endif /* EMBEDDED_LIBRARY */ /* Test a crash when invalid/corrupted .frm is used in the @@ -11566,7 +11567,7 @@ static void test_bug8330() const char *stmt_text; MYSQL_STMT *stmt[2]; int i, rc; - char *query= "select a,b from t1 where a=?"; + const char *query= "select a,b from t1 where a=?"; MYSQL_BIND bind[2]; long lval[2]; From 7bf65299ccb758665d2d265f318085b87a3ff54d Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Sun, 31 Jul 2005 02:47:54 +0000 Subject: [PATCH 009/230] Fix for BUG#12082 (assert failure when the query fails to get a lock for record in 'const' table): Set table->key_read back to 0 regardless of whether join_read_const() succeeded or not. --- sql/sql_select.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 117e16a2db3..6d3382e3354 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9717,7 +9717,13 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) table->file->extra(HA_EXTRA_KEYREAD); tab->index= tab->ref.key; } - if ((error=join_read_const(tab))) + error=join_read_const(tab); + if (table->key_read) + { + table->key_read=0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } + if (error) { tab->info="unique row not found"; /* Mark for EXPLAIN that the row was not found */ @@ -9725,11 +9731,6 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) if (!table->maybe_null || error > 0) DBUG_RETURN(error); } - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } } if (*tab->on_expr_ref && !table->null_row) { From 8109934e1d7af65d16eae90c0d301aa95f138d03 Mon Sep 17 00:00:00 2001 From: "patg@krsna.patg.net" <> Date: Sun, 31 Jul 2005 21:28:52 -0700 Subject: [PATCH 010/230] BUG 11104 (same as changeset 1.1891 on the 5.0 tree, but realised this needed to be fixed in earlier versions) Fixed the iteration of how substrings are handled with negative indexes in SUBSTRING_INDEX --- mysql-test/r/func_str.result | 117 +++++++++++++++++++++++++++++++++++ mysql-test/t/func_str.test | 39 ++++++++++++ sql/item_strfunc.cc | 16 ++++- 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 6fe71f97edd..6fefbb16353 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -38,6 +38,123 @@ www. .se select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); substring_index('.tcx.se','.',-2) substring_index('.tcx.se','.tcx',-1) tcx.se .se +select substring_index('aaaaaaaaa1','a',1); +substring_index('aaaaaaaaa1','a',1) + +select substring_index('aaaaaaaaa1','aa',1); +substring_index('aaaaaaaaa1','aa',1) + +select substring_index('aaaaaaaaa1','aa',2); +substring_index('aaaaaaaaa1','aa',2) +aa +select substring_index('aaaaaaaaa1','aa',3); +substring_index('aaaaaaaaa1','aa',3) +aaaa +select substring_index('aaaaaaaaa1','aa',4); +substring_index('aaaaaaaaa1','aa',4) +aaaaaa +select substring_index('aaaaaaaaa1','aa',5); +substring_index('aaaaaaaaa1','aa',5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',1); +substring_index('aaaaaaaaa1','aaa',1) + +select substring_index('aaaaaaaaa1','aaa',2); +substring_index('aaaaaaaaa1','aaa',2) +aaa +select substring_index('aaaaaaaaa1','aaa',3); +substring_index('aaaaaaaaa1','aaa',3) +aaaaaa +select substring_index('aaaaaaaaa1','aaa',4); +substring_index('aaaaaaaaa1','aaa',4) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaaa',1); +substring_index('aaaaaaaaa1','aaaa',1) + +select substring_index('aaaaaaaaa1','aaaa',2); +substring_index('aaaaaaaaa1','aaaa',2) +aaaa +select substring_index('aaaaaaaaa1','1',1); +substring_index('aaaaaaaaa1','1',1) +aaaaaaaaa +select substring_index('aaaaaaaaa1','a',-1); +substring_index('aaaaaaaaa1','a',-1) +1 +select substring_index('aaaaaaaaa1','aa',-1); +substring_index('aaaaaaaaa1','aa',-1) +1 +select substring_index('aaaaaaaaa1','aa',-2); +substring_index('aaaaaaaaa1','aa',-2) +aa1 +select substring_index('aaaaaaaaa1','aa',-3); +substring_index('aaaaaaaaa1','aa',-3) +aaaa1 +select substring_index('aaaaaaaaa1','aa',-4); +substring_index('aaaaaaaaa1','aa',-4) +aaaaaa1 +select substring_index('aaaaaaaaa1','aa',-5); +substring_index('aaaaaaaaa1','aa',-5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-1); +substring_index('aaaaaaaaa1','aaa',-1) +1 +select substring_index('aaaaaaaaa1','aaa',-2); +substring_index('aaaaaaaaa1','aaa',-2) +aaa1 +select substring_index('aaaaaaaaa1','aaa',-3); +substring_index('aaaaaaaaa1','aaa',-3) +aaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-4); +substring_index('aaaaaaaaa1','aaa',-4) + +select substring_index('the king of thethe hill','the',-2); +substring_index('the king of thethe hill','the',-2) +the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill',' the ',-1); +substring_index('the king of the the hill',' the ',-1) +hill +select substring_index('the king of the the hill',' the ',-2); +substring_index('the king of the the hill',' the ',-2) + the hill +select substring_index('the king of the the hill',' ',-1); +substring_index('the king of the the hill',' ',-1) +hill +select substring_index('the king of the the hill',' ',-2); +substring_index('the king of the the hill',' ',-2) +the hill +select substring_index('the king of the the hill',' ',-3); +substring_index('the king of the the hill',' ',-3) + the hill +select substring_index('the king of the the hill',' ',-4); +substring_index('the king of the the hill',' ',-4) +the the hill +select substring_index('the king of the the hill',' ',-5); +substring_index('the king of the the hill',' ',-5) +of the the hill +select substring_index('the king of the.the hill','the',-2); +substring_index('the king of the.the hill','the',-2) +.the hill +select substring_index('the king of thethethe.the hill','the',-3); +substring_index('the king of thethethe.the hill','the',-3) +the.the hill +select substring_index('the king of thethethe.the hill','the',-1); +substring_index('the king of thethethe.the hill','the',-1) + hill +select substring_index('the king of the the hill','the',1); +substring_index('the king of the the hill','the',1) + +select substring_index('the king of the the hill','the',2); +substring_index('the king of the the hill','the',2) +the king of +select substring_index('the king of the the hill','the',3); +substring_index('the king of the the hill','the',3) +the king of the select concat(':',ltrim(' left '),':',rtrim(' right '),':'); concat(':',ltrim(' left '),':',rtrim(' right '),':') :left : right: diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9dac1d823d9..81d5daaf0ba 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -19,6 +19,45 @@ select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',s select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1); select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1); select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); +select substring_index('aaaaaaaaa1','a',1); +select substring_index('aaaaaaaaa1','aa',1); +select substring_index('aaaaaaaaa1','aa',2); +select substring_index('aaaaaaaaa1','aa',3); +select substring_index('aaaaaaaaa1','aa',4); +select substring_index('aaaaaaaaa1','aa',5); +select substring_index('aaaaaaaaa1','aaa',1); +select substring_index('aaaaaaaaa1','aaa',2); +select substring_index('aaaaaaaaa1','aaa',3); +select substring_index('aaaaaaaaa1','aaa',4); +select substring_index('aaaaaaaaa1','aaaa',1); +select substring_index('aaaaaaaaa1','aaaa',2); +select substring_index('aaaaaaaaa1','1',1); +select substring_index('aaaaaaaaa1','a',-1); +select substring_index('aaaaaaaaa1','aa',-1); +select substring_index('aaaaaaaaa1','aa',-2); +select substring_index('aaaaaaaaa1','aa',-3); +select substring_index('aaaaaaaaa1','aa',-4); +select substring_index('aaaaaaaaa1','aa',-5); +select substring_index('aaaaaaaaa1','aaa',-1); +select substring_index('aaaaaaaaa1','aaa',-2); +select substring_index('aaaaaaaaa1','aaa',-3); +select substring_index('aaaaaaaaa1','aaa',-4); +select substring_index('the king of thethe hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill',' the ',-1); +select substring_index('the king of the the hill',' the ',-2); +select substring_index('the king of the the hill',' ',-1); +select substring_index('the king of the the hill',' ',-2); +select substring_index('the king of the the hill',' ',-3); +select substring_index('the king of the the hill',' ',-4); +select substring_index('the king of the the hill',' ',-5); +select substring_index('the king of the.the hill','the',-2); +select substring_index('the king of thethethe.the hill','the',-3); +select substring_index('the king of thethethe.the hill','the',-1); +select substring_index('the king of the the hill','the',1); +select substring_index('the king of the the hill','the',2); +select substring_index('the king of the the hill','the',3); select concat(':',ltrim(' left '),':',rtrim(' right '),':'); select concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':'); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 930014de771..f070382e5c1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1084,11 +1084,23 @@ String *Item_func_substr_index::val_str(String *str) } } else - { // Start counting at end - for (offset=res->length() ; ; offset-=delimeter_length-1) + { + /* + Negative index, start counting at the end + */ + for (offset=res->length(); offset ;) { + /* + this call will result in finding the position pointing to one + address space less than where the found substring is located + in res + */ if ((int) (offset=res->strrstr(*delimeter,offset)) < 0) return res; // Didn't find, return org string + /* + At this point, we've searched for the substring + the number of times as supplied by the index value + */ if (!++count) { offset+=delimeter_length; From 302c85cbb3cb282c50b424f6913b2a441035930a Mon Sep 17 00:00:00 2001 From: "sasha@asksasha.com" <> Date: Tue, 2 Aug 2005 15:13:56 -0600 Subject: [PATCH 011/230] Added a test case for BUG#10456 --- mysql-test/r/rpl_insert_select.result | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 mysql-test/r/rpl_insert_select.result diff --git a/mysql-test/r/rpl_insert_select.result b/mysql-test/r/rpl_insert_select.result new file mode 100644 index 00000000000..1aff39e0026 --- /dev/null +++ b/mysql-test/r/rpl_insert_select.result @@ -0,0 +1,17 @@ +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 (n int not null primary key); +insert into t1 values (1); +create table t2 (n int); +insert into t2 values (1); +insert ignore into t1 select * from t2; +insert into t1 values (2); +select * from t1; +n +1 +2 +drop table t1,t2; From bb76e143a3b151572a55ef702b1c72a45a0b73f4 Mon Sep 17 00:00:00 2001 From: "sasha@asksasha.com" <> Date: Tue, 2 Aug 2005 15:15:28 -0600 Subject: [PATCH 012/230] The earlier commit for BUG#10456 did not add the test file --- mysql-test/t/rpl_insert_select.test | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 mysql-test/t/rpl_insert_select.test diff --git a/mysql-test/t/rpl_insert_select.test b/mysql-test/t/rpl_insert_select.test new file mode 100644 index 00000000000..677be526982 --- /dev/null +++ b/mysql-test/t/rpl_insert_select.test @@ -0,0 +1,19 @@ +# Testcase for BUG#10456 - INSERT INTO ... SELECT violating a primary key +# breaks replication + +-- source include/master-slave.inc +connection master; + +create table t1 (n int not null primary key); +insert into t1 values (1); +create table t2 (n int); +insert into t2 values (1); +insert ignore into t1 select * from t2; +insert into t1 values (2); +sync_slave_with_master; +connection slave; +select * from t1; + +connection master; +drop table t1,t2; +sync_slave_with_master; From fac058502b57538d84c32458839b2150e4a9ff9a Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Tue, 2 Aug 2005 15:28:09 -0700 Subject: [PATCH 013/230] Generate a warning/error when DATE_SUB/ADD() functions calculate a date that is outside the acceptable date range. (Bug #10627) --- mysql-test/r/func_date_add.result | 26 ++++++++++++++++++++++++++ mysql-test/t/func_date_add.test | 23 +++++++++++++++++++++++ sql/item_timefunc.cc | 13 +++++++++---- sql/share/errmsg.txt | 2 ++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index 50889943b56..15ec80426ea 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -45,3 +45,29 @@ visitor_id mts 465931136 2000-03-18 16:09:53 1092858576 2000-03-19 01:34:45 drop table t1; +set sql_mode='traditional'; +create table t1 (d date); +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +ERROR 22008: Datetime function: datetime field overflow +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +ERROR 22008: Datetime function: datetime field overflow +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +set sql_mode=''; +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +Warnings: +Warning 1437 Datetime function: datetime field overflow +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +Warnings: +Warning 1437 Datetime function: datetime field overflow +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +select * from t1; +d +NULL +NULL +NULL +NULL +NULL +NULL +drop table t1; diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test index b768e4fec61..e01fce30577 100644 --- a/mysql-test/t/func_date_add.test +++ b/mysql-test/t/func_date_add.test @@ -41,4 +41,27 @@ select visitor_id,max(ts) as mts from t1 group by visitor_id having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW(); drop table t1; +# +# Bug #10627: Invalid date turned to NULL from date_sub/date_add in +# traditional mode +# +set sql_mode='traditional'; +create table t1 (d date); +--error S22008 +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +--error S22008 +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +# No warnings/errors from the next two +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +set sql_mode=''; +# These will all work now, and we'll end up with some NULL entries in the +# table and some warnings. +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +select * from t1; +drop table t1; + # End of 4.1 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a6fbbee6f23..dfbfca3b078 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1938,7 +1938,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) daynr= calc_daynr(ltime->year,ltime->month,1) + days; /* Day number from year 0 to 9999-12-31 */ if ((ulonglong) daynr >= MAX_DAY_NUMBER) - goto null_date; + goto invalid_date; get_date_from_daynr((long) daynr, <ime->year, <ime->month, <ime->day); break; @@ -1949,13 +1949,13 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) sign * (long) interval.day); /* Daynumber from year 0 to 9999-12-31 */ if ((ulong) period >= MAX_DAY_NUMBER) - goto null_date; + goto invalid_date; get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day); break; case INTERVAL_YEAR: ltime->year+= sign * (long) interval.year; if ((ulong) ltime->year >= 10000L) - goto null_date; + goto invalid_date; if (ltime->month == 2 && ltime->day == 29 && calc_days_in_year(ltime->year) != 366) ltime->day=28; // Was leap-year @@ -1966,7 +1966,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) period= (ltime->year*12 + sign * (long) interval.year*12 + ltime->month-1 + sign * (long) interval.month); if ((ulong) period >= 120000L) - goto null_date; + goto invalid_date; ltime->year= (uint) (period / 12); ltime->month= (uint) (period % 12L)+1; /* Adjust day if the new month doesn't have enough days */ @@ -1982,6 +1982,11 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) } return 0; // Ok +invalid_date: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_DATETIME_FUNCTION_OVERFLOW, + ER(ER_DATETIME_FUNCTION_OVERFLOW), + "datetime"); null_date: return (null_value=1); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 459560ccac8..c157d823483 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5386,3 +5386,5 @@ ER_TRG_IN_WRONG_SCHEMA eng "Trigger in wrong schema" ER_STACK_OVERRUN_NEED_MORE eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack." +ER_DATETIME_FUNCTION_OVERFLOW 22008 + eng "Datetime function: %-.32s field overflow" From 98d8c2fbe8d09a26ad92d1d21683af305e642cfe Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Wed, 3 Aug 2005 17:52:43 +1000 Subject: [PATCH 014/230] BUG#11538 mysql compile fails with certain ndb options --with-ndb-ccflags would include "yes" as a CFLAG and pass it to GCC (who didn't agree). --- acinclude.m4 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index f868489f2d2..9c7271f7cc9 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1723,10 +1723,19 @@ AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [ [ndb_debug="$withval"], [ndb_debug="default"]) AC_ARG_WITH([ndb-ccflags], - [ - --with-ndb-ccflags Extra CC options for ndb compile], - [ndb_cxxflags_fix="$ndb_cxxflags_fix $withval"], - [ndb_cxxflags_fix=$ndb_cxxflags_fix]) + AC_HELP_STRING([--with-ndb-ccflags=CFLAGS], + [Extra CFLAGS for ndb compile]), + [ndb_ccflags=${withval}], + [ndb_ccflags=""]) + + case "$ndb_ccflags" in + "yes") + AC_MSG_RESULT([The --ndb-ccflags option requires a parameter (passed to CC for ndb compilation)]) + ;; + *) + ndb_cxxflags_fix="$ndb_cxxflags_fix $ndb_ccflags" + ;; + esac AC_MSG_CHECKING([for NDB Cluster options]) AC_MSG_RESULT([]) From c44fe70d02163125ecc2a16e798fcea7cb073651 Mon Sep 17 00:00:00 2001 From: "sasha@asksasha.com" <> Date: Wed, 3 Aug 2005 18:08:20 -0600 Subject: [PATCH 015/230] patch for BUG#4680 - drop database breaking replication if there were extra files in the database directory on the master --- mysql-test/r/rpl_drop_db.result | 30 ++++++++++++++++++++++ mysql-test/t/rpl_drop_db.test | 39 ++++++++++++++++++++++++++++ sql/mysql_priv.h | 2 +- sql/sql_db.cc | 45 +++++++++++++++++++++++++++++---- sql/sql_table.cc | 20 ++++++++++++++- 5 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 mysql-test/r/rpl_drop_db.result create mode 100644 mysql-test/t/rpl_drop_db.test diff --git a/mysql-test/r/rpl_drop_db.result b/mysql-test/r/rpl_drop_db.result new file mode 100644 index 00000000000..bafbfe3a1ed --- /dev/null +++ b/mysql-test/r/rpl_drop_db.result @@ -0,0 +1,30 @@ +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; +create database d1; +create table d1.t1 (n int); +insert into d1.t1 values (1); +select * from d1.t1 into outfile 'd1/f1.txt'; +create table d1.t2 (n int); +create table d1.t3 (n int); +drop database d1; +ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17) +use d1; +show tables; +Tables_in_d1 +use test; +create table t1 (n int); +insert into t1 values (1234); +use d1; +show tables; +Tables_in_d1 +use test; +select * from t1; +n +1234 +drop table t1; +stop slave; diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test new file mode 100644 index 00000000000..ef0ab4be6fd --- /dev/null +++ b/mysql-test/t/rpl_drop_db.test @@ -0,0 +1,39 @@ +# test case for BUG#4680 -- if there are extra files in the db directory +# dropping the db on the master causes replication problems + +-- source include/master-slave.inc +connection master; + +--disable_warnings +drop database if exists d1; +--enable_warnings +create database d1; +create table d1.t1 (n int); +insert into d1.t1 values (1); +select * from d1.t1 into outfile 'd1/f1.txt'; +create table d1.t2 (n int); +create table d1.t3 (n int); +--error 1010 +drop database d1; +use d1; +show tables; +use test; +create table t1 (n int); +insert into t1 values (1234); +sync_slave_with_master; + +connection slave; +use d1; +show tables; +use test; +select * from t1; + +connection master; +drop table t1; +sync_slave_with_master; + +#cleanup +connection slave; +stop slave; +system rm -rf var/master-data/d1; + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6969433649f..9d46cc507df 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -441,7 +441,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool log_query); int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, - bool log_query); + bool log_query, List *dropped_tables); int quick_rm_table(enum db_type base,const char *db, const char *table_name); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index ad6845572e1..0155fca0466 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -31,7 +31,7 @@ static TYPELIB deletable_extentions= static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, const char *path, - uint level); + uint level, List *dropped_tables); /* Database options hash */ static HASH dboptions; @@ -584,6 +584,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) int error= 0; char path[FN_REFLEN+16], tmp_db[NAME_LEN+1]; MY_DIR *dirp; + List dropped_tables; uint length; DBUG_ENTER("mysql_rm_db"); @@ -621,8 +622,10 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) remove_db_from_cache(db); pthread_mutex_unlock(&LOCK_open); + error= -1; - if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0)) >= 0) + if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0, + &dropped_tables)) >= 0) { ha_drop_database(path); query_cache_invalidate1(db); @@ -672,6 +675,37 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) send_ok(thd, (ulong) deleted); thd->server_status&= ~SERVER_STATUS_DB_DROPPED; } + else if (!dropped_tables.is_empty() && mysql_bin_log.is_open()) + { + List_iterator it(dropped_tables); + String* dropped_table; + int q_len= 11; /* drop table */ + int db_len= strlen(db); + + for (;(dropped_table= it++);) + { + q_len += dropped_table->length() + 2 + db_len; + } + q_len--; /* no last comma */ + + char* query= thd->alloc(q_len); + if (!query) + goto exit; /* not much else we can do */ + char* p= strmov(query,"drop table "); + it.rewind(); + + for (;(dropped_table= it++);) + { + p= strmov(p,db); + *p++ = '.'; + p= strnmov(p,dropped_table->ptr(),dropped_table->length()); + *p++ = ','; + } + *--p= 0; + Query_log_event qinfo(thd, query, q_len, 0, 0); + qinfo.error_code= 0; + mysql_bin_log.write(&qinfo); + } exit: start_waiting_global_read_lock(thd); @@ -716,7 +750,7 @@ exit2: */ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, - const char *org_path, uint level) + const char *org_path, uint level, List *dropped_tables) { long deleted=0; ulong found_other_files=0; @@ -758,7 +792,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) { DBUG_PRINT("my",("New subdir found: %s", newpath)); - if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0) + if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0) goto err; if (!(copy_of_path= thd->memdup(newpath, length+1)) || !(dir= new (thd->mem_root) String(copy_of_path, length, @@ -805,7 +839,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } } if (thd->killed || - (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) + (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, + 1,dropped_tables))) goto err; /* Remove RAID directories */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 87b864c73fa..e948a65f301 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -156,7 +156,8 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, - bool drop_temporary, bool dont_log_query) + bool drop_temporary, bool dont_log_query, + List* dropped_tables) { int error; thd->mysys_var->current_mutex= &LOCK_open; @@ -165,6 +166,23 @@ int mysql_rm_table_part2_with_lock(THD *thd, error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, dont_log_query); + /* + For now we assume that if we got success all the tables in the list + were actually dropped, otherwise, assume none were dropped. + TODO: fix it to work with a partial drop - extremely rare case, but + can happen. + */ + if (!error && dropped_tables) + { + TABLE_LIST* tbl; + + for (tbl= tables; tbl; tbl= tbl->next) + { + String *dropped_table= new (thd->mem_root) + String(tbl->real_name,&my_charset_latin1); + dropped_tables->push_back(dropped_table); + } + } pthread_mutex_unlock(&LOCK_open); From 1b40adcb064b96064bc71d975f054579b41fa378 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 4 Aug 2005 15:25:03 +0500 Subject: [PATCH 016/230] grant.result, grant.test: fixing tests accordingly item.cc: Bug #10892 user variables not auto cast for comparisons When mixing strings with different character sets, and coercibility is the same, we allow conversion if one character set is superset for other character set. --- mysql-test/r/grant.result | 3 +++ mysql-test/t/grant.test | 7 +++++++ sql/item.cc | 10 ++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index e9e1d4cd620..a50293752ec 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -440,3 +440,6 @@ insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_gr flush privileges; delete from tables_priv where host = '' and user = 'mysqltest_1'; flush privileges; +set @user123="non-existent"; +select * from mysql.db where user=@user123; +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 50255d515e0..b0de62e679c 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -402,4 +402,11 @@ flush privileges; delete from tables_priv where host = '' and user = 'mysqltest_1'; flush privileges; +# +# Bug #10892 user variables not auto cast for comparisons +# Check that we don't get illegal mix of collations +# +set @user123="non-existent"; +select * from mysql.db where user=@user123; + # End of 4.1 tests diff --git a/sql/item.cc b/sql/item.cc index 84dbc382a52..41cda365750 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -455,14 +455,16 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) ; // Do nothing } else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && - derivation < dt.derivation && - collation->state & MY_CS_UNICODE) + derivation <= dt.derivation && + collation->state & MY_CS_UNICODE && + !(dt.collation->state & MY_CS_UNICODE)) { // Do nothing } else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && - dt.derivation < derivation && - dt.collation->state & MY_CS_UNICODE) + dt.derivation <= derivation && + dt.collation->state & MY_CS_UNICODE && + !(collation->state & MY_CS_UNICODE)) { set(dt); } From 697836c77fb9af725a5d9698bd6a169096b2b36c Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Thu, 4 Aug 2005 18:05:33 +0400 Subject: [PATCH 017/230] Fix bug#12266 GROUP BY DATE(LEFT(column,8)) returns result strings with reduced length. When temporary field created for DATE(LEFT(column,8)) expression, max_length value is taken from Item_date_typecast, and it is getting it from underlaid Item_func_left and it's max_length is 8 in given expression. And all this results in stripping last 2 digits. To Item_date_typecast class added its own fix_length_and_dec() function that sets max_length value to 10, which is proper for DATE field. --- mysql-test/r/group_by.result | 7 +++++++ mysql-test/t/group_by.test | 10 ++++++++++ sql/item_timefunc.h | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 295663fe1d3..8287a042d60 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -757,3 +757,10 @@ SELECT n+1 AS n FROM t1 GROUP BY n; n 2 DROP TABLE t1; +create table t1 (f1 date); +insert into t1 values('2005-06-06'); +insert into t1 values('2005-06-06'); +select date(left(f1+0,8)) from t1 group by 1; +date(left(f1+0,8)) +2005-06-06 +drop table t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index c07d309005e..815da66c717 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -590,4 +590,14 @@ INSERT INTO t1 VALUES (1); SELECT n+1 AS n FROM t1 GROUP BY n; DROP TABLE t1; +# +# Bug #12266 GROUP BY expression on DATE column produces result with +# reduced length +# +create table t1 (f1 date); +insert into t1 values('2005-06-06'); +insert into t1 values('2005-06-06'); +select date(left(f1+0,8)) from t1 group by 1; +drop table t1; + # End of 4.1 tests diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 1a30b24b7ce..0df84d14bea 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -709,6 +709,12 @@ public: { return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); } + void fix_length_and_dec() + { + collation.set(&my_charset_bin); + max_length= 10; + maybe_null= 1; + } }; From c9e04f4642e8f77ffa3ae7e0f79ddd1896648577 Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Fri, 5 Aug 2005 15:37:24 +0200 Subject: [PATCH 018/230] Bug#9459 - deadlock with flush with lock, and lock table write Added a check before taking a global read lock if the own thread has a write locked table. --- mysql-test/r/flush.result | 21 +++++++++++++++++++++ mysql-test/t/flush.test | 31 +++++++++++++++++++++++++++++++ sql/sql_parse.cc | 17 +++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index bab9b543307..384bdc1214b 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -27,3 +27,24 @@ select * from t1; n 345 drop table t1; +create table t1 (c1 int); +lock table t1 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +lock table t1 read; +flush tables with read lock; +lock table t1 write; +ERROR HY000: Can't execute the query because you have a conflicting read lock +lock table t1 read; +lock table t1 write; +ERROR HY000: Can't execute the query because you have a conflicting read lock +unlock tables; +create table t2 (c1 int); +create table t3 (c1 int); +lock table t1 read, t2 read, t3 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +lock table t1 read, t2 read, t3 read; +flush tables with read lock; +unlock tables; +drop table t1, t2, t3; diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index 5a9ab8db740..21ba9e8e9e7 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -70,4 +70,35 @@ insert into t1 values (345); select * from t1; drop table t1; +# +# Bug#9459 - deadlock with flush with lock, and lock table write +# +create table t1 (c1 int); +lock table t1 write; +# Cannot get the global read lock with write locked tables. +--error 1192 +flush tables with read lock; +lock table t1 read; +# Can get the global read lock with read locked tables. +flush tables with read lock; +--error 1223 +lock table t1 write; +lock table t1 read; +--error 1223 +lock table t1 write; +# Release all table locks and the global read lock. +unlock tables; +create table t2 (c1 int); +create table t3 (c1 int); +lock table t1 read, t2 read, t3 write; +# Cannot get the global read lock with write locked tables. +--error 1192 +flush tables with read lock; +lock table t1 read, t2 read, t3 read; +# Can get the global read lock with read locked tables. +flush tables with read lock; +# Release all table locks and the global read lock. +unlock tables; +drop table t1, t2, t3; + # End of 4.1 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c32cbff0f5e..135cef43e90 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5027,6 +5027,23 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, { if ((options & REFRESH_READ_LOCK) && thd) { + /* + We must not try to aspire a global read lock if we have a write + locked table. This would lead to a deadlock when trying to + reopen (and re-lock) the table after the flush. + */ + if (thd->locked_tables) + { + THR_LOCK_DATA **lock_p= thd->locked_tables->locks; + THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count; + + for (; lock_p < end_p; lock_p++) + if ((*lock_p)->type == TL_WRITE) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + return 1; + } + } /* Writing to the binlog could cause deadlocks, as we don't log UNLOCK TABLES From 9959482c950856551c0517373d6144b5c409d036 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Fri, 5 Aug 2005 21:13:06 +0200 Subject: [PATCH 019/230] Ensure version is 5.0.12 (block the clone's "11" from the main tree). --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 8a5220dbf38..8c591bfddf8 100644 --- a/configure.in +++ b/configure.in @@ -6,7 +6,7 @@ AC_PREREQ(2.57)dnl Minimum Autoconf version required. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # Don't forget to also update the NDB lines below. -AM_INIT_AUTOMAKE(mysql, 5.0.11-beta) +AM_INIT_AUTOMAKE(mysql, 5.0.12-beta) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -17,7 +17,7 @@ SHARED_LIB_VERSION=15:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=11 +NDB_VERSION_BUILD=12 NDB_VERSION_STATUS="beta" # Set all version vars based on $VERSION. How do we do this more elegant ? From 47a63206571b2dadc5e1a71418dc0fd384f1c2a7 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Fri, 5 Aug 2005 13:19:48 -0700 Subject: [PATCH 020/230] Always report row type of 'Fixed' for MEMORY tables. (Bug #3094) --- mysql-test/r/heap.result | 7 +++++++ mysql-test/t/heap.test | 10 ++++++++++ sql/ha_heap.h | 2 ++ 3 files changed, 19 insertions(+) diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index b905dae3aba..4725ff6b814 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -701,3 +701,10 @@ insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 1 drop table t1; +create table t1 (c char(10)) engine=memory; +create table t2 (c varchar(10)) engine=memory; +show table status like 't_'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MEMORY 10 Fixed 0 11 0 720192 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 12 0 785664 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +drop table t1, t2; diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index 6a9ff5c8284..922bd4b9bf0 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -437,3 +437,13 @@ insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd drop table t1; # End of 4.1 tests + +# +# Bug #3094: Row format of memory tables should always be reported as Fixed +# +create table t1 (c char(10)) engine=memory; +create table t2 (c varchar(10)) engine=memory; +show table status like 't_'; +drop table t1, t2; + +# End of 5.0 tests diff --git a/sql/ha_heap.h b/sql/ha_heap.h index f7368436456..7c4227e952c 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -43,6 +43,8 @@ public: return ((table->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ? "BTREE" : "HASH"); } + /* Rows also use a fixed-size format */ + enum row_type get_row_type() const { return ROW_TYPE_FIXED; } const char **bas_ext() const; ulong table_flags() const { From 73db3fdf46adadf2372d6e46e18ad4e211605157 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Fri, 5 Aug 2005 16:43:35 -0700 Subject: [PATCH 021/230] mysql_priv.h: Fixed bug #12154: a query returned: Column cannot be null. The problem was due to a bug in the function setup_table_map: the flag maybe_null was set up incorrectly for inner tables of nested outer joins. join_nested.result, join_nested.test: Added a test case for bug #12154. --- mysql-test/r/join_nested.result | 55 +++++++++++++++++++++++++++++++++ mysql-test/t/join_nested.test | 48 ++++++++++++++++++++++++++++ sql/mysql_priv.h | 6 ++++ 3 files changed, 109 insertions(+) diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 27edac1b30b..1fd7e6f4390 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1343,3 +1343,58 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 0 1 SIMPLE t3 ALL NULL NULL NULL NULL 0 DROP TABLE t1,t2,t3; +CREATE TABLE t1 (goods int(12) NOT NULL, price varchar(128) NOT NULL); +INSERT INTO t1 VALUES (23, 2340), (26, 9900); +CREATE TABLE t2 (goods int(12), name varchar(50), shop char(2)); +INSERT INTO t2 VALUES (23, 'as300', 'fr'), (26, 'as600', 'fr'); +create table t3 (groupid int(12) NOT NULL, goodsid int(12) NOT NULL); +INSERT INTO t3 VALUES (3,23), (6,26); +CREATE TABLE t4 (groupid int(12)); +INSERT INTO t4 VALUES (1), (2), (3), (4), (5), (6); +SELECT * FROM +(SELECT DISTINCT gl.groupid, gp.price +FROM t4 gl +LEFT JOIN +(t3 g INNER JOIN t2 p ON g.goodsid = p.goods +INNER JOIN t1 gp ON p.goods = gp.goods) +ON gl.groupid = g.groupid and p.shop = 'fr') t; +groupid price +1 NULL +2 NULL +3 2340 +4 NULL +5 NULL +6 9900 +CREATE VIEW v1 AS +SELECT g.groupid groupid, p.goods goods, +p.name name, p.shop shop, +gp.price price +FROM t3 g INNER JOIN t2 p ON g.goodsid = p.goods +INNER JOIN t1 gp on p.goods = gp.goods; +CREATE VIEW v2 AS +SELECT DISTINCT g.groupid, fr.price +FROM t4 g +LEFT JOIN +v1 fr on g.groupid = fr.groupid and fr.shop = 'fr'; +SELECT * FROM v2; +groupid price +1 NULL +2 NULL +3 2340 +4 NULL +5 NULL +6 9900 +SELECT * FROM +(SELECT DISTINCT g.groupid, fr.price +FROM t4 g +LEFT JOIN +v1 fr on g.groupid = fr.groupid and fr.shop = 'fr') t; +groupid price +1 NULL +2 NULL +3 2340 +4 NULL +5 NULL +6 9900 +DROP VIEW v1,v2; +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 992217d0391..10b2dac5c8b 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -770,3 +770,51 @@ SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21; EXPLAIN SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21; DROP TABLE t1,t2,t3; + +# +# Bug #12154: creation of temp table for a query with nested outer join +# + +CREATE TABLE t1 (goods int(12) NOT NULL, price varchar(128) NOT NULL); +INSERT INTO t1 VALUES (23, 2340), (26, 9900); + +CREATE TABLE t2 (goods int(12), name varchar(50), shop char(2)); +INSERT INTO t2 VALUES (23, 'as300', 'fr'), (26, 'as600', 'fr'); + +create table t3 (groupid int(12) NOT NULL, goodsid int(12) NOT NULL); +INSERT INTO t3 VALUES (3,23), (6,26); + +CREATE TABLE t4 (groupid int(12)); +INSERT INTO t4 VALUES (1), (2), (3), (4), (5), (6); + +SELECT * FROM +(SELECT DISTINCT gl.groupid, gp.price + FROM t4 gl + LEFT JOIN + (t3 g INNER JOIN t2 p ON g.goodsid = p.goods + INNER JOIN t1 gp ON p.goods = gp.goods) + ON gl.groupid = g.groupid and p.shop = 'fr') t; + +CREATE VIEW v1 AS +SELECT g.groupid groupid, p.goods goods, + p.name name, p.shop shop, + gp.price price + FROM t3 g INNER JOIN t2 p ON g.goodsid = p.goods + INNER JOIN t1 gp on p.goods = gp.goods; + +CREATE VIEW v2 AS +SELECT DISTINCT g.groupid, fr.price + FROM t4 g + LEFT JOIN + v1 fr on g.groupid = fr.groupid and fr.shop = 'fr'; + +SELECT * FROM v2; + +SELECT * FROM +(SELECT DISTINCT g.groupid, fr.price + FROM t4 g + LEFT JOIN + v1 fr on g.groupid = fr.groupid and fr.shop = 'fr') t; + +DROP VIEW v1,v2; +DROP TABLE t1,t2,t3,t4; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c56496c394d..3251a2d34a9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1450,6 +1450,12 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->status= STATUS_NO_RECORD; table->keys_in_use_for_query= table->s->keys_in_use; table->maybe_null= table_list->outer_join; + TABLE_LIST *embedding= table_list->embedding; + while (!table->maybe_null && embedding) + { + table->maybe_null= embedding->outer_join; + embedding= embedding->embedding; + } table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; From 268a68ad08a0f2a19d863b19485bf1444a1519d3 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Fri, 5 Aug 2005 17:22:53 -0700 Subject: [PATCH 022/230] Fix error message when creating a non-string field with a display width beyond the maximum. (Bug #6080) --- mysql-test/r/errors.result | 5 +++++ mysql-test/r/type_bit.result | 2 +- mysql-test/r/type_bit_innodb.result | 2 +- mysql-test/t/errors.test | 11 +++++++++++ mysql-test/t/type_bit_innodb.test | 2 +- sql/share/errmsg.txt | 2 ++ sql/sql_parse.cc | 7 +++++-- 7 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result index d0011c8deb6..9a91c088aca 100644 --- a/mysql-test/r/errors.result +++ b/mysql-test/r/errors.result @@ -23,3 +23,8 @@ ERROR 42S22: Unknown column 't1.b' in 'order clause' select count(*),b from t1; ERROR 42S22: Unknown column 'b' in 'field list' drop table t1; +create table t1 (a int(256)); +ERROR 42000: Display width out of range for column 'a' (max = 255) +set sql_mode='traditional'; +create table t1 (a varchar(66000)); +ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 4aa8587d6e1..035af0d82ac 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -36,7 +36,7 @@ select 0 + b'1000000000000001'; 32769 drop table if exists t1; create table t1 (a bit(65)); -ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead +ERROR 42000: Display width out of range for column 'a' (max = 64) create table t1 (a bit(0)); show create table t1; Table Create Table diff --git a/mysql-test/r/type_bit_innodb.result b/mysql-test/r/type_bit_innodb.result index f3e9dad3baa..8d9c9756a33 100644 --- a/mysql-test/r/type_bit_innodb.result +++ b/mysql-test/r/type_bit_innodb.result @@ -36,7 +36,7 @@ select 0 + b'1000000000000001'; 32769 drop table if exists t1; create table t1 (a bit(65)) engine=innodb; -ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead +ERROR 42000: Display width out of range for column 'a' (max = 64) create table t1 (a bit(0)) engine=innodb; show create table t1; Table Create Table diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index 93668ffdd3d..f7913ab402c 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -31,3 +31,14 @@ select count(*),b from t1; drop table t1; # End of 4.1 tests + +# +# Bug #6080: Error message for a field with a display width that is too long +# +--error 1438 +create table t1 (a int(256)); +set sql_mode='traditional'; +--error 1074 +create table t1 (a varchar(66000)); + +# End of 5.0 tests diff --git a/mysql-test/t/type_bit_innodb.test b/mysql-test/t/type_bit_innodb.test index 693fc169717..090b7aef218 100644 --- a/mysql-test/t/type_bit_innodb.test +++ b/mysql-test/t/type_bit_innodb.test @@ -20,7 +20,7 @@ select 0 + b'1000000000000001'; drop table if exists t1; --enable_warnings ---error 1074 +--error 1438 create table t1 (a bit(65)) engine=innodb; create table t1 (a bit(0)) engine=innodb; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5dd5cd9c775..5462aa94516 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5388,3 +5388,5 @@ ER_STACK_OVERRUN_NEED_MORE eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack." ER_TOO_LONG_BODY 42000 S1009 eng "Routine body for '%-.100s' is too long" +ER_TOO_BIG_DISPLAYWIDTH 42000 S1009 + eng "Display width out of range for column '%-.64s' (max = %d)" diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 677b3a98174..0794de6c191 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5819,7 +5819,7 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, new_field->length= 1; if (new_field->length > MAX_BIT_FIELD_LENGTH) { - my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name, + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_BIT_FIELD_LENGTH); DBUG_RETURN(NULL); } @@ -5838,7 +5838,10 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, type != MYSQL_TYPE_STRING && type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY))) { - my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), + my_error((type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_VARCHAR || + type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : + ER_TOO_BIG_DISPLAYWIDTH, + MYF(0), field_name, max_field_charlength); /* purecov: inspected */ DBUG_RETURN(NULL); } From 94722a380148be59f2cdad566b4a67e782acd1e0 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Sat, 6 Aug 2005 03:10:35 +0200 Subject: [PATCH 023/230] make_win_src_distribution.sh: Added missing backslashes --- scripts/make_win_src_distribution.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh index 8183370f220..0d2a8cdd5d7 100644 --- a/scripts/make_win_src_distribution.sh +++ b/scripts/make_win_src_distribution.sh @@ -343,8 +343,8 @@ mv $BASE/sql/sql_yacc.cpp-new $BASE/sql/sql_yacc.cpp # Search the tree for plain text files and adapt the line end marker # find $BASE \( -name "*.dsp" -o -name "*.dsw" -o -name "*.cnf" -o -name "*.ini" \ - -o -name COPYING -o -name ChangeLog -o -name EXCEPTIONS-CLIENT - -o -name "INSTALL*" -o -name LICENSE -o -name "README*" + -o -name COPYING -o -name ChangeLog -o -name EXCEPTIONS-CLIENT \ + -o -name "INSTALL*" -o -name LICENSE -o -name "README*" \ -o -name "*.vcproj" -o -name "*.sln" \) -type f -print \ | while read v do From 154d4f8485132db0ca4cea5aac3c42b7a05b036c Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sat, 6 Aug 2005 12:48:41 +0200 Subject: [PATCH 024/230] log_event.h: extra safety for OPTIONS_WRITTEN_TO_BIN_LOG --- sql/log_event.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/log_event.h b/sql/log_event.h index 9f4681ae2c5..3ac1cfaf4bc 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -393,6 +393,10 @@ struct sql_ex_info #define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \ OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS) +#if OPTIONS_WRITTEN_TO_BIN_LOG != ((1L << 14) | (1L << 26) | (1L << 27)) +#error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values! +#endif + enum Log_event_type { /* From 5e9545d4c4769ffdd54f64359bd3c534a102b89c Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Sat, 6 Aug 2005 21:08:28 +0000 Subject: [PATCH 025/230] BUG#11869 (cont'd, eliminating "table type doesn't support FULLTEXT" error): When creating temporary table for UNION, pass TMP_TABLE_FORCE_MYISAM flag to create_tmp_table if we will be using fulltext function(s) when reading from the temp. table. --- mysql-test/r/fulltext_order_by.result | 10 ++++++++++ mysql-test/t/fulltext_order_by.test | 11 +++++++++++ sql/mysql_priv.h | 6 ++++++ sql/sql_select.cc | 2 +- sql/sql_union.cc | 16 ++++++++++++---- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 130d096e00f..5f40e43f0c0 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -159,4 +159,14 @@ match(c.beitrag) against ('+abc' in boolean mode) order by match(betreff) against ('+abc' in boolean mode) desc; text id betreff +(select b.id, b.betreff from t3 b) union +(select b.id, b.betreff from t3 b) +order by match(betreff) against ('+abc' in boolean mode) desc; +id betreff +select distinct b.id, b.betreff from t3 b +order by match(betreff) against ('+abc' in boolean mode) desc; +id betreff +select b.id, b.betreff from t3 b group by b.id+1 +order by match(betreff) against ('+abc' in boolean mode) desc; +id betreff drop table t1,t2,t3; diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 1a70ac3880b..fec74b5dc54 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -133,6 +133,17 @@ where order by match(betreff) against ('+abc' in boolean mode) desc; +# BUG#11869 part2: used table type doesn't support FULLTEXT indexes error +(select b.id, b.betreff from t3 b) union +(select b.id, b.betreff from t3 b) +order by match(betreff) against ('+abc' in boolean mode) desc; + +select distinct b.id, b.betreff from t3 b +order by match(betreff) against ('+abc' in boolean mode) desc; + +select b.id, b.betreff from t3 b group by b.id+1 +order by match(betreff) against ('+abc' in boolean mode) desc; + drop table t1,t2,t3; # End of 4.1 tests diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c8a4c4740ef..0af3ea3af63 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -215,6 +215,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; in the user query has requested */ #define SELECT_ALL (1L << 29) +/* + Force the used temporary table to be a MyISAM table (because we will use + fulltext functions when reading from it. +*/ +#define TMP_TABLE_FORCE_MYISAM (1L << 30) + /* If set to 0, then the thread will ignore all warnings with level notes. Set by executing SET SQL_NOTES=1 */ #define OPTION_SQL_NOTES (1L << 31) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1bde62276b8..54afe5bb7a6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5290,7 +5290,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, /* If result table is small; use a heap */ if (blob_count || using_unique_constraint || (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == - OPTION_BIG_TABLES) + OPTION_BIG_TABLES ||(select_options & TMP_TABLE_FORCE_MYISAM)) { table->file=get_new_handler(table,table->db_type=DB_TYPE_MYISAM); if (group && diff --git a/sql/sql_union.cc b/sql/sql_union.cc index a54fb613fd2..eeb8dfdfef5 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -296,15 +296,23 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, goto err; } } + + ulong create_options= first_select_in_union()->options | thd_arg->options | + TMP_TABLE_ALL_COLUMNS; + /* + Force the temporary table to be a MyISAM table if we're going to use + fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading + from it. + */ + if (global_parameters->ftfunc_list->elements) + create_options= create_options | TMP_TABLE_FORCE_MYISAM; union_result->tmp_table_param.field_count= types.elements; if (!(table= create_tmp_table(thd_arg, &union_result->tmp_table_param, types, (ORDER*) 0, (bool) union_distinct, 1, - (first_select_in_union()->options | - thd_arg->options | - TMP_TABLE_ALL_COLUMNS), - HA_POS_ERROR, (char *) tmp_table_alias))) + create_options, HA_POS_ERROR, + (char *) tmp_table_alias))) goto err; table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); From 015447b21191ee5dce8f08631ff111595b3533ea Mon Sep 17 00:00:00 2001 From: "acurtis@xiphis.org" <> Date: Sun, 7 Aug 2005 03:16:15 +0100 Subject: [PATCH 026/230] Bug#10109 "INSERT .. SELECT ... ON DUPLICATE KEY UPDATE fails" Ensure that check_insert_fields() is only called once when doing an INSERT..SELECT --- mysql-test/r/insert_update.result | 6 ++++++ mysql-test/t/insert_update.test | 14 ++++++++++++ sql/sql_class.h | 14 +++++++++--- sql/sql_insert.cc | 36 +++++++++++++++++++++---------- sql/sql_parse.cc | 3 ++- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 150f4ef26c7..9e674cc4aae 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -191,3 +191,9 @@ ERROR 23000: Column 'a' in field list is ambiguous insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; ERROR 23000: Column 't1.a' in field list is ambiguous drop table t1; +CREATE TABLE t1 ( +a BIGINT(20) NOT NULL DEFAULT 0, +PRIMARY KEY (a) +) ENGINE=MyISAM; +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ; +DROP TABLE t1; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index d0e75f0fa2a..8038bd7bfe7 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -101,4 +101,18 @@ insert into t1 select a from t1 on duplicate key update a=a+1 ; insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; drop table t1; +# +# Bug#10109 - INSERT .. SELECT ... ON DUPLICATE KEY UPDATE fails +# Bogus "Duplicate columns" error message +# + +CREATE TABLE t1 ( + a BIGINT(20) NOT NULL DEFAULT 0, + PRIMARY KEY (a) +) ENGINE=MyISAM; + +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/sql_class.h b/sql/sql_class.h index b6bf0dcdc45..bc651b32d94 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1236,19 +1236,27 @@ class select_insert :public select_result_interceptor { List *fields; ulonglong last_insert_id; COPY_INFO info; + TABLE_LIST *insert_table_list; + TABLE_LIST *dup_table_list; select_insert(TABLE *table_par, List *fields_par, enum_duplicates duplic, bool ignore) - :table(table_par), fields(fields_par), last_insert_id(0) + :table(table_par), fields(fields_par), last_insert_id(0), + insert_table_list(0), dup_table_list(0) { bzero((char*) &info,sizeof(info)); info.ignore= ignore; info.handle_duplicates=duplic; } - select_insert(TABLE *table_par, List *fields_par, + select_insert(TABLE *table_par, + TABLE_LIST *insert_table_list_par, + TABLE_LIST *dup_table_list_par, + List *fields_par, List *update_fields, List *update_values, enum_duplicates duplic, bool ignore) - :table(table_par), fields(fields_par), last_insert_id(0) + :table(table_par), fields(fields_par), last_insert_id(0), + insert_table_list(insert_table_list_par), + dup_table_list(dup_table_list_par) { bzero((char*) &info,sizeof(info)); info.ignore= ignore; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7d613ad6fbf..8c6fed26f8e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -543,18 +543,22 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!table->insert_values) DBUG_RETURN(-1); } - if ((values && check_insert_fields(thd, table, fields, *values)) || - setup_tables(insert_table_list) || - (values && setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0)) || - (duplic == DUP_UPDATE && - (check_update_fields(thd, table, insert_table_list, update_fields) || - setup_fields(thd, 0, dup_table_list, update_values, 1, 0, 0)))) + if (setup_tables(insert_table_list)) DBUG_RETURN(-1); - if (values && find_real_table_in_list(table_list->next, table_list->db, - table_list->real_name)) + if (values) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); - DBUG_RETURN(-1); + if (check_insert_fields(thd, table, fields, *values) || + setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || + (duplic == DUP_UPDATE && + (check_update_fields(thd, table, insert_table_list, update_fields) || + setup_fields(thd, 0, dup_table_list, update_values, 1, 0, 0)))) + DBUG_RETURN(-1); + if (find_real_table_in_list(table_list->next, table_list->db, + table_list->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); @@ -1601,6 +1605,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) int res; LEX *lex= thd->lex; SELECT_LEX *lex_current_select_save= lex->current_select; + bool lex_select_no_error= lex->select_lex.no_error; DBUG_ENTER("select_insert::prepare"); unit= u; @@ -1608,10 +1613,19 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) Since table in which we are going to insert is added to the first select, LEX::current_select should point to the first select while we are fixing fields from insert list. + Since these checks may cause the query to fail, we don't want the + error messages to be converted into warnings, must force no_error=0 */ lex->current_select= &lex->select_lex; - res= check_insert_fields(thd, table, *fields, values); + lex->select_lex.no_error= 0; + res= + check_insert_fields(thd, table, *fields, values) || + setup_fields(thd, 0, insert_table_list, values, 0, 0, 0) || + (info.handle_duplicates == DUP_UPDATE && + (check_update_fields(thd, table, insert_table_list, *info.update_fields) || + setup_fields(thd, 0, dup_table_list, *info.update_values, 1, 0, 0))); lex->current_select= lex_current_select_save; + lex->select_lex.no_error= lex_select_no_error; if (res) DBUG_RETURN(1); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c32cbff0f5e..9fb431df318 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2877,7 +2877,8 @@ unsent_create_error: lex->field_list, 0, lex->update_list, lex->value_list, lex->duplicates)) && - (result= new select_insert(insert_table, &lex->field_list, + (result= new select_insert(insert_table, first_local_table, + &dup_tables, &lex->field_list, &lex->update_list, &lex->value_list, lex->duplicates, lex->ignore))) { From 1147e0027424acfed7cd833d0edbd6f111208f8a Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Sun, 7 Aug 2005 20:39:17 +0200 Subject: [PATCH 027/230] Bug#10473 - Can't set 'key_buffer_size' system variable to ZERO Give the user a warning if he tries to destroy the default key cache. --- mysql-test/r/key_cache.result | 6 ++++++ mysql-test/t/key_cache.test | 7 +++++++ sql/set_var.cc | 5 +++++ sql/share/errmsg.txt | 3 +++ 4 files changed, 21 insertions(+) diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result index b3aa4c5061c..de9a2b2c003 100644 --- a/mysql-test/r/key_cache.result +++ b/mysql-test/r/key_cache.result @@ -289,3 +289,9 @@ check table t1; Table Op Msg_type Msg_text test.t1 check status OK drop table t1; +set @@global.key_buffer_size=0; +Warnings: +Warning 1438 Cannot drop default keycache +select @@global.key_buffer_size; +@@global.key_buffer_size +2097152 diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test index 5d0f904a716..df584021af1 100644 --- a/mysql-test/t/key_cache.test +++ b/mysql-test/t/key_cache.test @@ -168,4 +168,11 @@ check table t1; drop table t1; +# +# Bug#10473 - Can't set 'key_buffer_size' system variable to ZERO +# (One cannot drop the default key cache.) +# +set @@global.key_buffer_size=0; +select @@global.key_buffer_size; + # End of 4.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index ff37c46349d..637b33f18d2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2293,7 +2293,12 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) if (!tmp) // Zero size means delete { if (key_cache == dflt_key_cache) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, + ER(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE)); goto end; // Ignore default key cache + } if (key_cache->key_cache_inited) // If initied { diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5dd5cd9c775..c47b3bb7dd9 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5388,3 +5388,6 @@ ER_STACK_OVERRUN_NEED_MORE eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack." ER_TOO_LONG_BODY 42000 S1009 eng "Routine body for '%-.100s' is too long" +ER_WARN_CANT_DROP_DEFAULT_KEYCACHE + eng "Cannot drop default keycache" + ger "Der Default-Keycache kann nicht gelöscht werden" From d820a09a6817ac6105b908393a78091cac62e525 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Sun, 7 Aug 2005 21:03:45 +0000 Subject: [PATCH 028/230] BUG#11869: part2: post-review fixes: In init_prepare_fake_select_lex() don't empty ftfunc_list. UNION's ORDER BY clause may contain MATCH(...), for which fix_index() should be called. --- mysql-test/r/fulltext_order_by.result | 4 ++++ mysql-test/t/fulltext_order_by.test | 5 +++++ sql/sql_union.cc | 5 ++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 5f40e43f0c0..0b77153248e 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -163,6 +163,10 @@ text id betreff (select b.id, b.betreff from t3 b) order by match(betreff) against ('+abc' in boolean mode) desc; id betreff +(select b.id, b.betreff from t3 b) union +(select b.id, b.betreff from t3 b) +order by match(betreff) against ('+abc') desc; +ERROR HY000: Can't find FULLTEXT index matching the column list select distinct b.id, b.betreff from t3 b order by match(betreff) against ('+abc' in boolean mode) desc; id betreff diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index fec74b5dc54..da05fd494c4 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -138,6 +138,11 @@ order by (select b.id, b.betreff from t3 b) order by match(betreff) against ('+abc' in boolean mode) desc; +--error 1191 +(select b.id, b.betreff from t3 b) union +(select b.id, b.betreff from t3 b) +order by match(betreff) against ('+abc') desc; + select distinct b.id, b.betreff from t3 b order by match(betreff) against ('+abc' in boolean mode) desc; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index eeb8dfdfef5..c33444fd73e 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -132,8 +132,6 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) options_tmp&= ~OPTION_FOUND_ROWS; else if (found_rows_for_union && !thd->lex->describe) options_tmp|= OPTION_FOUND_ROWS; - fake_select_lex->ftfunc_list_alloc.empty(); - fake_select_lex->ftfunc_list= &fake_select_lex->ftfunc_list_alloc; fake_select_lex->table_list.link_in_list((byte *)&result_table_list, (byte **) &result_table_list.next); @@ -302,7 +300,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading - from it. + from it (this should be removed in 5.2 when fulltext search is moved + out of MyISAM). */ if (global_parameters->ftfunc_list->elements) create_options= create_options | TMP_TABLE_FORCE_MYISAM; From b2a189ab0739294409cfc62be6ef7e5d431464fb Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sun, 7 Aug 2005 14:03:46 -0700 Subject: [PATCH 029/230] subselect.result: Added test case for bug #11867. Fixed results for two existing test cases. subselect.test: Added test case for bug #11867. item_subselect.cc: Fixed bug #11867. Added missing code in Item_in_subselect::row_value_transformer that caused problems for queries with ROW(elems) IN (SELECT DISTINCT cols FROM ...). --- mysql-test/r/subselect.result | 19 +++++++++++++++++-- mysql-test/t/subselect.test | 15 +++++++++++++++ sql/item_subselect.cc | 13 +++++++++---- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8615c8e661b..25d9a39705d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -932,7 +932,7 @@ ROW(1, 1, 'a') IN (select a,b,c from t1) 1 select ROW(1, 2, 'a') IN (select a,b,c from t1); ROW(1, 2, 'a') IN (select a,b,c from t1) -NULL +0 select ROW(1, 1, 'a') IN (select b,a,c from t1); ROW(1, 1, 'a') IN (select b,a,c from t1) 1 @@ -950,7 +950,7 @@ ROW(1, 1, 'a') IN (select a,b,c from t1 where c='b' or c='a') 1 select ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a'); ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a') -NULL +0 select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a'); ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a') 1 @@ -2727,3 +2727,18 @@ select * from (select max(fld) from t1) as foo; max(fld) 1 drop table t1; +CREATE TABLE t1 (one int, two int, flag char(1)); +CREATE TABLE t2 (one int, two int, flag char(1)); +INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); +INSERT INTO t2 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); +SELECT * FROM t1 +WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t2 WHERE flag = 'N'); +one two flag +5 6 N +7 8 N +SELECT * FROM t1 +WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); +one two flag +5 6 N +7 8 N +DROP TABLE t1,t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index e58d6c490a5..0b4791b0023 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1754,5 +1754,20 @@ insert into t1 values ('1'); select * from (select max(fld) from t1) as foo; drop table t1; +# +# Bug #11867: queries with ROW(,elems>) IN (SELECT DISTINCT FROM ...) +# + +CREATE TABLE t1 (one int, two int, flag char(1)); +CREATE TABLE t2 (one int, two int, flag char(1)); +INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); +INSERT INTO t2 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); + +SELECT * FROM t1 + WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t2 WHERE flag = 'N'); +SELECT * FROM t1 + WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); + +DROP TABLE t1,t2; # End of 4.1 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 82954a664c0..6ec8b11d863 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -951,14 +951,19 @@ Item_in_subselect::row_value_transformer(JOIN *join) List_iterator_fast li(select_lex->item_list); for (uint i= 0; i < n; i++) { + Item *func; DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->el(i)->cols())) DBUG_RETURN(RES_ERROR); - Item *func= new Item_ref_null_helper(this, - select_lex->ref_pointer_array+i, - (char *) "", - (char *) ""); + if (join->having || select_lex->with_sum_func || + select_lex->group_list.elements) + func= new Item_ref_null_helper(this, + select_lex->ref_pointer_array+i, + (char *) "", + (char *) ""); + else + func= li++; func= eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> addr(i), From d9ce6e8f2534e894ce7a92e18c9c154fdf201da9 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Sun, 7 Aug 2005 21:21:30 +0000 Subject: [PATCH 030/230] BUG#11869:part 2: post-review fixes: merging into 5.0 We're out of bits in st_select_lex->options so make TMP_TABLE_FORCE_MYISAM == OPTION_FOUND_COMMENT (the latter is not used by create_tmp_table). --- mysql-test/r/create.result | 2 +- mysql-test/r/fulltext_order_by.result | 2 +- mysql-test/t/fulltext_order_by.test | 4 +--- sql/item_sum.cc | 6 ++++-- sql/mysql_priv.h | 12 +++++++----- sql/sql_derived.cc | 3 ++- sql/sql_select.cc | 5 +++-- sql/sql_show.cc | 3 ++- sql/sql_union.cc | 6 +++--- 9 files changed, 24 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 293be36e5ab..82a5ccc3e82 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -606,6 +606,6 @@ create database mysqltest; use mysqltest; create view v1 as select 'foo' from dual; create table t1 like v1; -ERROR HY000: 'mysqltest.v1' is not a table +ERROR HY000: 'mysqltest.v1' is not BASE TABLE drop view v1; drop database mysqltest; diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 5f40e43f0c0..adcceea408e 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1,t2,t3; CREATE TABLE t1 ( a INT AUTO_INCREMENT PRIMARY KEY, message CHAR(20), diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 5bad8161a0a..dcda00fecba 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -1,5 +1,5 @@ --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings CREATE TABLE t1 ( @@ -117,8 +117,6 @@ where order by match(b.betreff) against ('+abc' in boolean mode) desc; --- todo psergey: fix ---error 1214 select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b669a8c426d..3ba9cd10831 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2275,7 +2275,8 @@ bool Item_sum_count_distinct::setup(THD *thd) DBUG_ASSERT(table == 0); if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, 0, - select_lex->options | thd->options, + (select_lex->options | thd->options) & + ~TMP_TABLE_FORCE_MYISAM, HA_POS_ERROR, (char*)""))) return TRUE; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows @@ -3057,7 +3058,8 @@ bool Item_func_group_concat::setup(THD *thd) */ if (!(table= create_tmp_table(thd, tmp_table_param, all_fields, (ORDER*) 0, 0, TRUE, - select_lex->options | thd->options, + (select_lex->options | thd->options) & + ~TMP_TABLE_FORCE_MYISAM, HA_POS_ERROR, (char*) ""))) DBUG_RETURN(TRUE); table->file->extra(HA_EXTRA_NO_ROWS); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 20898a4b654..ef7d6a1da96 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -256,6 +256,13 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_WARNINGS (1L << 13) // THD, user #define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog #define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser +/* + Force the used temporary table to be a MyISAM table (because we will use + fulltext functions when reading from it. This uses the same constant as + OPTION_FOUND_COMMENT because we've run out of bits and these two values + are not used together. +*/ +#define TMP_TABLE_FORCE_MYISAM (1L << 15) #define OPTION_SAFE_UPDATES (1L << 16) // THD, user #define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user #define OPTION_BIN_LOG (1L << 18) // THD, user @@ -284,11 +291,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_SETUP_TABLES_DONE (1L << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ #define OPTION_SQL_NOTES (1L << 31) // THD, user -/* - Force the used temporary table to be a MyISAM table (because we will use - fulltext functions when reading from it. -*/ -#define TMP_TABLE_FORCE_MYISAM (1L << 30) /* Maximum length of time zone name that we support diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index fc9d15e94c4..afcf7dbd93f 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -142,7 +142,8 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) unit->types, (ORDER*) 0, FALSE, 1, (first_select->options | thd->options | - TMP_TABLE_ALL_COLUMNS), + TMP_TABLE_ALL_COLUMNS) & + ~TMP_TABLE_FORCE_MYISAM, HA_POS_ERROR, orig_table_list->alias))) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3f2f72fb768..a5527d8684c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1016,7 +1016,7 @@ JOIN::optimize() group_list : (ORDER*) 0), group_list ? 0 : select_distinct, group_list && simple_group, - select_options, + select_options & ~TMP_TABLE_FORCE_MYISAM, (order == 0 || skip_sort_order) ? select_limit : HA_POS_ERROR, (char *) ""))) @@ -1396,7 +1396,8 @@ JOIN::exec() (ORDER*) 0, curr_join->select_distinct && !curr_join->group_list, - 1, curr_join->select_options, + 1, curr_join->select_options + & ~TMP_TABLE_FORCE_MYISAM, HA_POS_ERROR, (char *) ""))) DBUG_VOID_RETURN; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 56272b4fdaf..a63ef8d689c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3319,7 +3319,8 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->options | - TMP_TABLE_ALL_COLUMNS), + TMP_TABLE_ALL_COLUMNS) & + ~TMP_TABLE_FORCE_MYISAM, HA_POS_ERROR, table_list->alias))) DBUG_RETURN(0); table_list->schema_table_param= tmp_table_param; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 55c2524ca42..ed77de87fe4 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -296,8 +296,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - ulong create_options= first_select_in_union()->options | thd_arg->options | - TMP_TABLE_ALL_COLUMNS; + ulong create_options= (first_select_in_union()->options | thd_arg->options | + TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading @@ -310,7 +310,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (!(table= create_tmp_table(thd_arg, &union_result->tmp_table_param, types, (ORDER*) 0, (bool) union_distinct, 1, - create_options, HA_POS_ERROR, + create_options, HA_POS_ERROR, (char *) tmp_table_alias))) goto err; table->file->extra(HA_EXTRA_WRITE_CACHE); From e554e61734f11b794c648c4f7f0f50b6dc1272eb Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Sun, 7 Aug 2005 22:10:05 +0000 Subject: [PATCH 031/230] Post-merge fixes --- mysql-test/r/group_by.result | 10 +++++----- mysql-test/t/group_by.test | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index f7742178cbe..f4cf5217fa7 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -751,11 +751,6 @@ COUNT(DISTINCT(t1.id)) comment 1 NULL 1 a problem DROP TABLE t1, t2; -CREATE TABLE t1 (n int); -INSERT INTO t1 VALUES (1); -SELECT n+1 AS n FROM t1 GROUP BY n; -n -2 create table t1 (f1 date); insert into t1 values('2005-06-06'); insert into t1 values('2005-06-06'); @@ -763,6 +758,11 @@ select date(left(f1+0,8)) from t1 group by 1; date(left(f1+0,8)) 2005-06-06 drop table t1; +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +SELECT n+1 AS n FROM t1 GROUP BY n; +n +2 Warnings: Warning 1052 Column 'n' in group statement is ambiguous DROP TABLE t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 434c2662614..8300b502518 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -575,6 +575,11 @@ CREATE TABLE t1 (id varchar(20) NOT NULL); INSERT INTO t1 VALUES ('trans1'), ('trans2'); CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); INSERT INTO t2 VALUES ('trans1', 'a problem'); +SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment + FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; + +DROP TABLE t1, t2; + # # Bug #12266 GROUP BY expression on DATE column produces result with @@ -586,11 +591,6 @@ insert into t1 values('2005-06-06'); select date(left(f1+0,8)) from t1 group by 1; drop table t1; -SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment - FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; - -DROP TABLE t1, t2; - # # Test for bug #11414: crash on Windows for a simple GROUP BY query # From dafbb34dfe2800eab3b3faf32acf58d9c0422d5b Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sun, 7 Aug 2005 15:10:07 -0700 Subject: [PATCH 032/230] subselect.result: Correction after manual merge. --- mysql-test/r/subselect.result | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index e73d4677cf5..9606ed97ee7 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2754,7 +2754,6 @@ one two flag 5 6 N 7 8 N DROP TABLE t1,t2; -drop table t1; create table t1 (df decimal(5,1)); insert into t1 values(1.1); insert into t1 values(2.2); From 701703824fb43f37ba65b59b461bda0a19083b90 Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Mon, 8 Aug 2005 13:18:18 +0300 Subject: [PATCH 033/230] Fix for BUG #11642: [Patch]es x86 Assembler and text relocations Changed assembler functions to not access global variables or variables in text segement Added wrapper function in C to longlong2str() to pass _dig_vec_upper as an argument --- mysql-test/r/bigint.result | 9 ++++++ mysql-test/t/bigint.test | 3 ++ strings/Makefile.am | 4 +-- strings/longlong2str-x86.s | 35 ++++++++++----------- strings/longlong2str_asm.c | 33 ++++++++++++++++++++ strings/my_strtoll10-x86.s | 62 ++++++++++++++++++++++++-------------- 6 files changed, 104 insertions(+), 42 deletions(-) create mode 100644 strings/longlong2str_asm.c diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index eb3d0da3f23..e9a457c9dfa 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -17,6 +17,15 @@ select 9223372036854775808+1; select -(0-3),round(-(0-3)), round(9999999999999999999); -(0-3) round(-(0-3)) round(9999999999999999999) 3 3 10000000000000000000 +select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001; +1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 +1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 +select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000000 +select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); +conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16) +1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5 create table t1 (a bigint unsigned not null, primary key(a)); insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612); select * from t1; diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index 741c7ec360b..8a238d33e08 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -14,6 +14,9 @@ select +9999999999999999999,-9999999999999999999; select cast(9223372036854775808 as unsigned)+1; select 9223372036854775808+1; select -(0-3),round(-(0-3)), round(9999999999999999999); +select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001; +select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; +select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); # # In 3.23 we have to disable the test of column to bigint as diff --git a/strings/Makefile.am b/strings/Makefile.am index 3f954f3c6a0..97b35075277 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -23,7 +23,7 @@ pkglib_LIBRARIES = libmystrings.a # Exact one of ASSEMBLER_X if ASSEMBLER_x86 ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s -CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c +CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c longlong2str_asm.c else if ASSEMBLER_sparc32 # These file MUST all be on the same line!! Otherwise automake @@ -46,7 +46,7 @@ EXTRA_DIST = ctype-big5.c ctype-cp932.c ctype-czech.c ctype-euc_kr.c ctype-win1 ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \ ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \ xml.c strto.c strings-x86.s \ - longlong2str.c longlong2str-x86.s \ + longlong2str.c longlong2str-x86.s longlong2str_asm.c \ my_strtoll10.c my_strtoll10-x86.s \ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \ diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s index fcc57810224..1840bab3f47 100644 --- a/strings/longlong2str-x86.s +++ b/strings/longlong2str-x86.s @@ -16,26 +16,26 @@ # Optimized longlong2str function for Intel 80x86 (gcc/gas syntax) # Some set sequences are optimized for pentuimpro II - .file "longlong2str.s" - .version "1.01" + .file "longlong2str-x86.s" + .version "1.02" .text .align 4 -.globl longlong2str - .type longlong2str,@function +.globl longlong2str_with_dig_vector + .type longlong2str_with_dig_vector,@function -longlong2str: +longlong2str_with_dig_vector: subl $80,%esp pushl %ebp pushl %esi pushl %edi pushl %ebx movl 100(%esp),%esi # Lower part of val - movl 104(%esp),%ebp # Higher part of val - movl 108(%esp),%edi # get dst movl 112(%esp),%ebx # Radix + movl 104(%esp),%ebp # Higher part of val movl %ebx,%eax + movl 108(%esp),%edi # get dst testl %eax,%eax jge .L144 @@ -69,6 +69,8 @@ longlong2str: .L150: leal 92(%esp),%ecx # End of buffer + movl %edi, 108(%esp) # Store possible modified dest + movl 116(%esp), %edi # dig_vec_upper jmp .L155 .align 4 @@ -83,7 +85,7 @@ longlong2str: divl %ebx decl %ecx movl %eax,%esi # quotent in ebp:esi - movb _dig_vec_upper(%edx),%al # al is faster than dl + movb (%edx,%edi),%al # al is faster than dl movb %al,(%ecx) # store value in buff .align 4 .L155: @@ -91,20 +93,22 @@ longlong2str: ja .L153 testl %esi,%esi # rest value jl .L153 - je .L10_mov # Ready + je .L160 # Ready movl %esi,%eax - movl $_dig_vec_upper,%ebp .align 4 .L154: # Do rest with integer precision cltd divl %ebx decl %ecx - movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36 + movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36 testl %eax,%eax movb %dl,(%ecx) jne .L154 +.L160: + movl 108(%esp),%edi # get dst + .L10_mov: movl %ecx,%esi leal 92(%esp),%ecx # End of buffer @@ -129,7 +133,7 @@ longlong2str: jmp .L165 .Lfe3: - .size longlong2str,.Lfe3-longlong2str + .size longlong2str_with_dig_vector,.Lfe3-longlong2str_with_dig_vector # # This is almost equal to the above, except that we can do the final @@ -137,9 +141,6 @@ longlong2str: # .align 4 -.Ltmp: - .long 0xcccccccd - .align 4 .globl longlong10_to_str .type longlong10_to_str,@function @@ -202,8 +203,8 @@ longlong10_to_str: # The following code uses some tricks to change division by 10 to # multiplication and shifts - movl .Ltmp,%esi # set %esi to 0xcccccccd - + movl $0xcccccccd,%esi + .L10_40: movl %ebx,%eax mull %esi diff --git a/strings/longlong2str_asm.c b/strings/longlong2str_asm.c new file mode 100644 index 00000000000..e38a8328b91 --- /dev/null +++ b/strings/longlong2str_asm.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Wrapper for longlong2str.s + + We need this because the assembler code can't access the local variable + _dig_vector in a portable manner. +*/ + +#include +#include "m_string.h" + +extern char *longlong2str_with_dig_vector(longlong val,char *dst,int radix, + const char *dig_vector); + +char *longlong2str(longlong val,char *dst,int radix) +{ + return longlong2str_with_dig_vector(val, dst, radix, _dig_vec_upper); +} diff --git a/strings/my_strtoll10-x86.s b/strings/my_strtoll10-x86.s index c04384667a7..1d8b8f2bbce 100644 --- a/strings/my_strtoll10-x86.s +++ b/strings/my_strtoll10-x86.s @@ -17,21 +17,8 @@ # For documentation, check my_strtoll.c .file "my_strtoll10-x86.s" - .version "01.01" -.data - .align 32 - .type lfactor,@object - .size lfactor,36 -lfactor: - .long 1 - .long 10 - .long 100 - .long 1000 - .long 10000 - .long 100000 - .long 1000000 - .long 10000000 - .long 100000000 + .version "01.02" + .text .align 4 @@ -209,14 +196,16 @@ my_strtoll10: jne .L500 cmpl -36(%ebp),%esi # Test if string is less than 18 digits jne .Lend_i_and_j - jmp .Lend3 # 18 digit string +.L499: + movl $1000000000,%eax + jmp .Lgot_factor # 18 digit string # Handle the possible next to last digit and store in ecx .L500: movb (%esi),%al addb $-48,%al cmpb $9,%al - ja .Lend3 + ja .L499 # 18 digit string incl %esi movzbl %al,%ecx @@ -315,14 +304,41 @@ my_strtoll10: .Lend_i_and_j: movl %esi,%ecx subl -12(%ebp),%ecx # ecx= number of digits in second part - movl lfactor(,%ecx,4),%eax - jmp .L523 - # Return -8(%ebp) * $1000000000 + edi + # Calculate %eax= 10 ** %cl, where %cl <= 8 + # With an array one could do this with: + # movl 10_factor_table(,%ecx,4),%eax + # We calculate the table here to avoid problems in + # position independent code (gcc -pic) + + cmpb $3,%cl + ja .L4_to_8 + movl $1000, %eax + je .Lgot_factor # %cl=3, eax= 1000 + movl $10, %eax + cmpb $1,%cl # %cl is here 0 - 2 + je .Lgot_factor # %cl=1, eax= 10 + movl $100, %eax + ja .Lgot_factor # %cl=2, eax=100 + movl $1, %eax + jmp .Lgot_factor # %cl=0, eax=1 + +.L4_to_8: # %cl is here 4-8 + cmpb $5,%cl + movl $100000, %eax + je .Lgot_factor # %cl=5, eax=100000 + movl $10000, %eax + jbe .Lgot_factor # %cl=4, eax=10000 + movl $10000000, %eax + cmpb $7,%cl + je .Lgot_factor # %cl=7, eax=10000000 + movl $100000000, %eax + ja .Lgot_factor # %cl=8, eax=100000000 + movl $1000000, %eax # %cl=6, eax=1000000 + + # Return -8(%ebp) * %eax + edi .p2align 4,,7 -.Lend3: - movl $1000000000,%eax -.L523: +.Lgot_factor: mull -8(%ebp) addl %edi,%eax adcl $0,%edx From 2c8fc886b91903d0cbb9064c64c7209ee816369e Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 8 Aug 2005 16:20:46 +0500 Subject: [PATCH 034/230] item.cc: After review fix --- sql/item.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 41cda365750..b3d2932acf6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -455,16 +455,18 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) ; // Do nothing } else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && - derivation <= dt.derivation && collation->state & MY_CS_UNICODE && - !(dt.collation->state & MY_CS_UNICODE)) + (derivation < dt.derivation || + (derivation == dt.derivation && + !(dt.collation->state & MY_CS_UNICODE)))) { // Do nothing } else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && - dt.derivation <= derivation && dt.collation->state & MY_CS_UNICODE && - !(collation->state & MY_CS_UNICODE)) + (dt.derivation < derivation || + (dt.derivation == derivation && + !(collation->state & MY_CS_UNICODE)))) { set(dt); } From 615baa9f237b30ec590a4405ecb222643d1792a5 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Mon, 8 Aug 2005 17:46:06 +0400 Subject: [PATCH 035/230] Fix for bug #10055 "Using stored function with information_schema causes empty result set". To enable full access to contents of I_S tables from stored functions or statements that use them, we manipulate with thread's open tables state and ensure that we won't cause deadlock when we open tables by ignoring flushes and name-locks. Building of contents of I_S.TABLES no longer requires locking of tables since we use use handler::info() method with HA_STATUS_AUTO flag instead of handler::update_auto_increment() for obtaining information about auto-increment values. But this also means that handlers have to implement support for HA_STATUS_AUTO flag (particularly InnoDB needs it). --- mysql-test/r/alter_table.result | 4 +- mysql-test/r/information_schema.result | 12 ++++- mysql-test/r/sp.result | 9 ++++ mysql-test/t/information_schema.test | 6 ++- mysql-test/t/sp.test | 15 ++++++ sql/mysql_priv.h | 7 ++- sql/sp.cc | 39 +++++++------- sql/sp.h | 7 +++ sql/sql_base.cc | 24 +++++---- sql/sql_class.cc | 49 ++++++++--------- sql/sql_class.h | 13 +++-- sql/sql_handler.cc | 2 +- sql/sql_prepare.cc | 4 +- sql/sql_show.cc | 73 +++++++++++++------------- sql/sql_update.cc | 5 +- 15 files changed, 160 insertions(+), 109 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 74f0e3d9425..9f127181fc2 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -314,7 +314,7 @@ INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); SHOW INDEX FROM t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE -t1 0 PRIMARY 2 User A 3 NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE ALTER TABLE t1 ENABLE KEYS; UNLOCK TABLES; CHECK TABLES t1; @@ -338,7 +338,7 @@ INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); SHOW INDEX FROM t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE -t1 0 PRIMARY 2 User A 2 NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE t1 1 Host 1 Host A NULL NULL NULL BTREE disabled ALTER TABLE t1 ENABLE KEYS; SHOW INDEX FROM t1; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 98f3d59485f..3464793eb2c 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t0,t1,t2; +DROP TABLE IF EXISTS t0,t1,t2,t3,t5; show variables where variable_name like "skip_show_database"; Variable_name Value skip_show_database OFF @@ -30,6 +30,8 @@ create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b)); create table test.t2(a int); create table t3(a int, KEY a_data (a)); create table mysqltest.t4(a int); +create table t5 (id int auto_increment primary key); +insert into t5 values (10); create view v1 (c) as select table_name from information_schema.TABLES; select * from v1; c @@ -69,6 +71,7 @@ t1 t4 t2 t3 +t5 v1 select c,table_name from v1 inner join information_schema.TABLES v2 on (v1.c=v2.table_name) @@ -87,6 +90,7 @@ t1 t1 t4 t4 t2 t2 t3 t3 +t5 t5 select c,table_name from v1 left join information_schema.TABLES v2 on (v1.c=v2.table_name) where v1.c like "t%"; @@ -104,6 +108,7 @@ t1 t1 t4 t4 t2 t2 t3 t3 +t5 t5 select c, v2.table_name from v1 right join information_schema.TABLES v2 on (v1.c=v2.table_name) where v1.c like "t%"; @@ -121,6 +126,7 @@ t1 t1 t4 t4 t2 t2 t3 t3 +t5 t5 select table_name from information_schema.TABLES where table_schema = "mysqltest" and table_name like "t%"; table_name @@ -136,10 +142,12 @@ show tables like 't%'; Tables_in_test (t%) t2 t3 +t5 show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL t3 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +t5 MyISAM 10 Fixed 1 7 7 # 2048 0 11 # # NULL latin1_swedish_ci NULL v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view show full columns from t3 like "a%"; Field Type Collation Null Key Default Extra Privileges Comment @@ -173,7 +181,7 @@ where table_schema = 'mysqltest' and table_name = 'v1'; table_name column_name privileges v1 c select drop view v1, mysqltest.v1; -drop tables mysqltest.t4, mysqltest.t1, t2, t3; +drop tables mysqltest.t4, mysqltest.t1, t2, t3, t5; drop database mysqltest; select * from information_schema.CHARACTER_SETS where CHARACTER_SET_NAME like 'latin1%'; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 74c03987a6a..aebb2c22dd3 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3062,4 +3062,13 @@ l drop procedure bug6063| drop procedure bug7088_1| drop procedure bug7088_2| +drop function if exists bug10055| +create function bug10055(v char(255)) returns char(255) return lower(v)| +select t.column_name, bug10055(t.column_name) +from information_schema.columns as t +where t.table_schema = 'test' and t.table_name = 't1'| +column_name bug10055(t.column_name) +id id +data data +drop function bug10055| drop table t1,t2; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 7c0624b67fd..6d5bfe79560 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -5,7 +5,7 @@ # show databases --disable_warnings -DROP TABLE IF EXISTS t0,t1,t2; +DROP TABLE IF EXISTS t0,t1,t2,t3,t5; --enable_warnings @@ -30,6 +30,8 @@ create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b)); create table test.t2(a int); create table t3(a int, KEY a_data (a)); create table mysqltest.t4(a int); +create table t5 (id int auto_increment primary key); +insert into t5 values (10); create view v1 (c) as select table_name from information_schema.TABLES; select * from v1; @@ -76,7 +78,7 @@ where table_schema = 'mysqltest' and table_name = 'v1'; connection default; drop view v1, mysqltest.v1; -drop tables mysqltest.t4, mysqltest.t1, t2, t3; +drop tables mysqltest.t4, mysqltest.t1, t2, t3, t5; drop database mysqltest; # Test for information_schema.CHARACTER_SETS & diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 4df49c5f934..51b1254a05c 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3833,6 +3833,21 @@ drop procedure bug7088_1| drop procedure bug7088_2| +# +# Bug#10055 "Using stored function with information_schema causes empty +# result set" +# +--disable_warnings +drop function if exists bug10055| +--enable_warnings +create function bug10055(v char(255)) returns char(255) return lower(v)| +# This select should not crash server and should return all fields in t1 +select t.column_name, bug10055(t.column_name) +from information_schema.columns as t +where t.table_schema = 'test' and t.table_name = 't1'| +drop function bug10055| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 70b6bc24467..66c38d2f24f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -482,8 +482,7 @@ typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); void free_items(Item *item); void cleanup_items(Item *item); class THD; -void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0, - TABLE *stopper= 0); +void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0); bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables); bool check_routine_access(THD *thd,ulong want_access,char *db,char *name, @@ -924,10 +923,10 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_refresh(THD *thd); -int open_tables(THD *thd, TABLE_LIST **tables, uint *counter); +int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); -bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables); +bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); diff --git a/sql/sp.cc b/sql/sp.cc index 55087f47f5e..5c95d12872b 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -68,13 +68,16 @@ bool mysql_proc_table_exists= 1; SYNOPSIS close_proc_table() - thd Thread context + thd Thread context + backup Pointer to Open_tables_state instance which holds + information about tables which were open before we + decided to access mysql.proc. */ -static void close_proc_table(THD *thd) +void close_proc_table(THD *thd, Open_tables_state *backup) { close_thread_tables(thd); - thd->pop_open_tables_state(); + thd->restore_backup_open_tables_state(backup); } @@ -83,7 +86,10 @@ static void close_proc_table(THD *thd) SYNOPSIS open_proc_table_for_read() - thd Thread context + thd Thread context + backup Pointer to Open_tables_state instance where information about + currently open tables will be saved, and from which will be + restored when we will end work with mysql.proc. NOTES Thanks to restrictions which we put on opening and locking of @@ -97,11 +103,10 @@ static void close_proc_table(THD *thd) # Pointer to TABLE object of mysql.proc */ -static TABLE *open_proc_table_for_read(THD *thd) +TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) { TABLE_LIST tables; TABLE *table; - bool old_open_tables= thd->open_tables != 0; bool refresh; DBUG_ENTER("open_proc_table"); @@ -112,8 +117,7 @@ static TABLE *open_proc_table_for_read(THD *thd) if (!mysql_proc_table_exists) DBUG_RETURN(0); - if (thd->push_open_tables_state()) - DBUG_RETURN(0); + thd->reset_n_backup_open_tables_state(backup); bzero((char*) &tables, sizeof(tables)); tables.db= (char*) "mysql"; @@ -121,7 +125,7 @@ static TABLE *open_proc_table_for_read(THD *thd) if (!(table= open_table(thd, &tables, thd->mem_root, &refresh, MYSQL_LOCK_IGNORE_FLUSH))) { - thd->pop_open_tables_state(); + thd->restore_backup_open_tables_state(backup); mysql_proc_table_exists= 0; DBUG_RETURN(0); } @@ -130,15 +134,13 @@ static TABLE *open_proc_table_for_read(THD *thd) table->reginfo.lock_type= TL_READ; /* - If we have other tables opened, we have to ensure we are not blocked - by a flush tables or global read lock, as this could lead to a deadlock + We have to ensure we are not blocked by a flush tables, as this + could lead to a deadlock if we have other tables opened. */ if (!(thd->lock= mysql_lock_tables(thd, &table, 1, - old_open_tables ? - (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | - MYSQL_LOCK_IGNORE_FLUSH) : 0))) + MYSQL_LOCK_IGNORE_FLUSH))) { - close_proc_table(thd); + close_proc_table(thd, backup); DBUG_RETURN(0); } DBUG_RETURN(table); @@ -271,12 +273,13 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) char buff[65]; String str(buff, sizeof(buff), &my_charset_bin); ulong sql_mode; + Open_tables_state open_tables_state_backup; DBUG_ENTER("db_find_routine"); DBUG_PRINT("enter", ("type: %d name: %*s", type, name->m_name.length, name->m_name.str)); *sphp= 0; // In case of errors - if (!(table= open_proc_table_for_read(thd))) + if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup))) DBUG_RETURN(SP_OPEN_TABLE_FAILED); if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) @@ -371,7 +374,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) chistics.comment.str= ptr; chistics.comment.length= length; - close_proc_table(thd); + close_proc_table(thd, &open_tables_state_backup); table= 0; { @@ -449,7 +452,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) done: if (table) - close_proc_table(thd); + close_proc_table(thd, &open_tables_state_backup); DBUG_RETURN(ret); } diff --git a/sql/sp.h b/sql/sp.h index b8af8d3a321..29ba5625e37 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -90,6 +90,13 @@ void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first); +/* + Routines which allow open/lock and close mysql.proc table even when + we already have some tables open and locked. +*/ +TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup); +void close_proc_table(THD *thd, Open_tables_state *backup); + // // Utilities... // diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2ee1c8c24cc..3a650b50b23 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -401,8 +401,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) upper level) and will leave prelocked mode if needed. */ -void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived, - TABLE *stopper) +void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) { bool found_old_table; prelocked_mode_type prelocked_mode= thd->prelocked_mode; @@ -508,7 +507,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived, DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables)); found_old_table= 0; - while (thd->open_tables != stopper) + while (thd->open_tables) found_old_table|=close_thread_table(thd, &thd->open_tables); thd->some_tables_deleted=0; @@ -1771,6 +1770,9 @@ err: thd - thread handler start - list of tables in/out counter - number of opened tables will be return using this parameter + flags - bitmap of flags to modify how the tables will be open: + MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has + done a flush or namelock on it. NOTE Unless we are already in prelocked mode, this function will also precache @@ -1788,7 +1790,7 @@ err: -1 - error */ -int open_tables(THD *thd, TABLE_LIST **start, uint *counter) +int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) { TABLE_LIST *tables; bool refresh; @@ -1863,7 +1865,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) } (*counter)++; if (!tables->table && - !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, 0))) + !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags))) { free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC)); if (tables->view) @@ -2089,7 +2091,8 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("simple_open_n_lock_tables"); uint counter; - if (open_tables(thd, &tables, &counter) || lock_tables(thd, tables, counter)) + if (open_tables(thd, &tables, &counter, 0) || + lock_tables(thd, tables, counter)) DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(0); } @@ -2116,7 +2119,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) { uint counter; DBUG_ENTER("open_and_lock_tables"); - if (open_tables(thd, &tables, &counter) || + if (open_tables(thd, &tables, &counter, 0) || lock_tables(thd, tables, counter) || mysql_handle_derived(thd->lex, &mysql_derived_prepare) || (thd->fill_derived_tables() && @@ -2133,6 +2136,9 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) open_normal_and_derived_tables thd - thread handler tables - list of tables for open + flags - bitmap of flags to modify how the tables will be open: + MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has + done a flush or namelock on it. RETURN FALSE - ok @@ -2143,12 +2149,12 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) data from the tables. */ -bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables) +bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags) { uint counter; DBUG_ENTER("open_normal_and_derived_tables"); DBUG_ASSERT(!thd->fill_derived_tables()); - if (open_tables(thd, &tables, &counter) || + if (open_tables(thd, &tables, &counter, flags) || mysql_handle_derived(thd->lex, &mysql_derived_prepare)) DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(0); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d0ac1a16f6b..16959fdd033 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -157,8 +157,8 @@ bool foreign_key_prefix(Key *a, Key *b) ** Thread specific functions ****************************************************************************/ -Open_tables_state::Open_tables_state() - :version(refresh_version) +Open_tables_state::Open_tables_state(ulong version_arg) + :version(version_arg) { reset_open_tables_state(); } @@ -172,7 +172,7 @@ Open_tables_state::Open_tables_state() THD::THD() :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), - Open_tables_state(), + Open_tables_state(refresh_version), user_time(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), @@ -1789,31 +1789,26 @@ void THD::set_status_var_init() access to mysql.proc table to find definitions of stored routines. ****************************************************************************/ -bool THD::push_open_tables_state() +void THD::reset_n_backup_open_tables_state(Open_tables_state *backup) { - Open_tables_state *state; - DBUG_ENTER("push_open_table_state"); - /* Currently we only push things one level */ - DBUG_ASSERT(open_state_list.elements == 0); - - if (!(state= (Open_tables_state*) alloc(sizeof(*state)))) - DBUG_RETURN(1); // Fatal error is set - /* Store state for currently open tables */ - state->set_open_tables_state(this); - if (open_state_list.push_back(state, mem_root)) - DBUG_RETURN(1); // Fatal error is set + DBUG_ENTER("reset_n_backup_open_tables_state"); + backup->set_open_tables_state(this); reset_open_tables_state(); - DBUG_RETURN(0); -} - -void THD::pop_open_tables_state() -{ - Open_tables_state *state; - DBUG_ENTER("pop_open_table_state"); - /* Currently we only push things one level */ - DBUG_ASSERT(open_state_list.elements == 1); - - state= open_state_list.pop(); - set_open_tables_state(state); + DBUG_VOID_RETURN; +} + + +void THD::restore_backup_open_tables_state(Open_tables_state *backup) +{ + DBUG_ENTER("restore_backup_open_tables_state"); + /* + Before we will throw away current open tables state we want + to be sure that it was properly cleaned up. + */ + DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 && + handler_tables == 0 && derived_tables == 0 && + lock == 0 && locked_tables == 0 && + prelocked_mode == NON_PRELOCKED); + set_open_tables_state(backup); DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 625b9c27b44..12c0f384046 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -996,7 +996,13 @@ public: ulong version; uint current_tablenr; - Open_tables_state(); + /* + This constructor serves for creation of Open_tables_state instances + which are used as backup storage. + */ + Open_tables_state() {}; + + Open_tables_state(ulong version_arg); void set_open_tables_state(Open_tables_state *state) { @@ -1203,7 +1209,6 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; - List open_state_list; /* Id of current query. Statement can be reused to execute several queries query_id is global in context of the whole MySQL server. @@ -1457,8 +1462,8 @@ public: (variables.sql_mode & MODE_STRICT_ALL_TABLES))); } void set_status_var_init(); - bool push_open_tables_state(); - void pop_open_tables_state(); + void reset_n_backup_open_tables_state(Open_tables_state *backup); + void restore_backup_open_tables_state(Open_tables_state *backup); }; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e109600bcd0..169132e2185 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -187,7 +187,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* for now HANDLER can be used only for real TABLES */ tables->required_type= FRMTYPE_TABLE; - error= open_tables(thd, &tables, &counter); + error= open_tables(thd, &tables, &counter, 0); HANDLER_TABLES_HACK(thd); if (error) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index e163e71e416..413ee486e55 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -925,7 +925,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, If we would use locks, then we have to ensure we are not using TL_WRITE_DELAYED as having two such locks can cause table corruption. */ - if (open_normal_and_derived_tables(thd, table_list)) + if (open_normal_and_derived_tables(thd, table_list, 0)) goto error; if ((values= its++)) @@ -1005,7 +1005,7 @@ static int mysql_test_update(Prepared_statement *stmt, if (update_precheck(thd, table_list)) goto error; - if (open_tables(thd, &table_list, &table_count)) + if (open_tables(thd, &table_list, &table_count, 0)) goto error; if (table_list->multitable_view) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8343f9ec582..d3861be721c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -20,6 +20,7 @@ #include "mysql_priv.h" #include "sql_select.h" // For select_describe #include "repl_failsafe.h" +#include "sp.h" #include "sp_head.h" #include @@ -351,7 +352,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) thd->lex->view_prepare_mode= TRUE; /* Only one table for now, but VIEW can involve several tables */ - if (open_normal_and_derived_tables(thd, table_list)) + if (open_normal_and_derived_tables(thd, table_list, 0)) { DBUG_RETURN(TRUE); } @@ -550,7 +551,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) DBUG_ENTER("mysqld_list_fields"); DBUG_PRINT("enter",("table: %s",table_list->table_name)); - if (open_normal_and_derived_tables(thd, table_list)) + if (open_normal_and_derived_tables(thd, table_list, 0)) DBUG_VOID_RETURN; table= table_list->table; @@ -1934,6 +1935,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX *old_all_select_lex= lex->all_selects_list; + TABLE_LIST **save_query_tables_last= lex->query_tables_last; + enum_sql_command save_sql_command= lex->sql_command; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; SELECT_LEX sel; @@ -1942,40 +1945,49 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) uint len; bool with_i_schema; enum enum_schema_tables schema_table_idx; - thr_lock_type lock_type; List bases; List_iterator_fast it(bases); COND *partial_cond; uint derived_tables= lex->derived_tables; int error= 1; + Open_tables_state open_tables_state_backup; DBUG_ENTER("get_all_tables"); LINT_INIT(end); LINT_INIT(len); + /* + Let us set fake sql_command so views won't try to merge + themselves into main statement. + */ + lex->sql_command= SQLCOM_SHOW_FIELDS; + + /* + We should not introduce deadlocks even if we already have some + tables open and locked, since we won't lock tables which we will + open and will ignore possible name-locks for these tables. + */ + thd->reset_n_backup_open_tables_state(&open_tables_state_backup); + if (lsel) { - TABLE *old_open_tables= thd->open_tables; TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first; bool res; lex->all_selects_list= lsel; - res= open_normal_and_derived_tables(thd, show_table_list); + res= open_normal_and_derived_tables(thd, show_table_list, + MYSQL_LOCK_IGNORE_FLUSH); if (schema_table->process_table(thd, show_table_list, table, res, show_table_list->db, show_table_list->alias)) goto err; - close_thread_tables(thd, 0, 0, old_open_tables); + close_thread_tables(thd); show_table_list->table= 0; error= 0; goto err; } schema_table_idx= get_schema_table_idx(schema_table); - lock_type= TL_UNLOCK; - - if (schema_table_idx == SCH_TABLES) - lock_type= TL_READ; if (make_db_list(thd, &bases, &idx_field_vals, &with_i_schema, 0)) @@ -2058,19 +2070,18 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) else { int res; - TABLE *old_open_tables= thd->open_tables; if (make_table_list(thd, &sel, base_name, file_name)) goto err; TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; - show_table_list->lock_type= lock_type; lex->all_selects_list= &sel; lex->derived_tables= 0; - res= open_normal_and_derived_tables(thd, show_table_list); + res= open_normal_and_derived_tables(thd, show_table_list, + MYSQL_LOCK_IGNORE_FLUSH); if (schema_table->process_table(thd, show_table_list, table, res, base_name, show_table_list->alias)) goto err; - close_thread_tables(thd, 0, 0, old_open_tables); + close_thread_tables(thd); } } } @@ -2084,8 +2095,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) error= 0; err: + thd->restore_backup_open_tables_state(&open_tables_state_backup); lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; + lex->query_tables_last= save_query_tables_last; + *save_query_tables_last= 0; + lex->sql_command= save_sql_command; DBUG_RETURN(error); } @@ -2190,7 +2205,8 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, TABLE_SHARE *share= show_table->s; handler *file= show_table->file; - file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK); + file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO | + HA_STATUS_NO_LOCK); if (share->tmp_table == TMP_TABLE) table->field[3]->store("TEMPORARY", 9, cs); else @@ -2246,13 +2262,8 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, table->field[12]->store((longlong) file->delete_length); if (show_table->found_next_number_field) { - show_table->next_number_field=show_table->found_next_number_field; - show_table->next_number_field->reset(); - file->update_auto_increment(); - table->field[13]->store((longlong) show_table-> - next_number_field->val_int()); + table->field[13]->store((longlong) file->auto_increment_value); table->field[13]->set_notnull(); - show_table->next_number_field=0; } if (file->create_time) { @@ -2711,12 +2722,14 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) TABLE_LIST proc_tables; const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; int res= 0; - TABLE *table= tables->table, *old_open_tables= thd->open_tables; + TABLE *table= tables->table; bool full_access; char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + Open_tables_state open_tables_state_backup; DBUG_ENTER("fill_schema_proc"); strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS); + /* We use this TABLE_LIST instance only for checking of privileges. */ bzero((char*) &proc_tables,sizeof(proc_tables)); proc_tables.db= (char*) "mysql"; proc_tables.db_length= 5; @@ -2724,7 +2737,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) proc_tables.table_name_length= 4; proc_tables.lock_type= TL_READ; full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1); - if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ))) + if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup))) { DBUG_RETURN(1); } @@ -2750,7 +2763,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) err: proc_table->file->ha_index_end(); - close_thread_tables(thd, 0, 0, old_open_tables); + close_proc_table(thd, &open_tables_state_backup); DBUG_RETURN(res); } @@ -3567,11 +3580,6 @@ 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()) { - TABLE_LIST **query_tables_last= lex->query_tables_last; - TABLE *old_derived_tables= thd->derived_tables; - MYSQL_LOCK *sql_lock= thd->lock; - lex->sql_command= SQLCOM_SHOW_FIELDS; - DBUG_ASSERT(!*query_tables_last); if (&lex->unit != lex->current_select->master_unit()) // is subselect { table_list->table->file->extra(HA_EXTRA_RESET_STATE); @@ -3582,16 +3590,9 @@ bool get_schema_tables_result(JOIN *join) else table_list->table->file->records= 0; - thd->derived_tables= 0; - thd->lock=0; if (table_list->schema_table->fill_table(thd, table_list, tab->select_cond)) result= 1; - thd->lock= sql_lock; - lex->sql_command= SQLCOM_SELECT; - thd->derived_tables= old_derived_tables; - lex->query_tables_last= query_tables_last; - *query_tables_last= 0; } } thd->no_warnings_for_error= 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8a5b4ad8eae..6deff6b0040 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -138,7 +138,7 @@ int mysql_update(THD *thd, LINT_INIT(timestamp_query_id); - if (open_tables(thd, &table_list, &table_count)) + if (open_tables(thd, &table_list, &table_count, 0)) DBUG_RETURN(1); if (table_list->multitable_view) @@ -632,7 +632,8 @@ bool mysql_multi_update_prepare(THD *thd) thd->lex->sql_command= SQLCOM_UPDATE_MULTI; /* open tables and create derived ones, but do not lock and fill them */ - if ((original_multiupdate && open_tables(thd, &table_list, & table_count)) || + if ((original_multiupdate && + open_tables(thd, &table_list, &table_count, 0)) || mysql_handle_derived(lex, &mysql_derived_prepare)) DBUG_RETURN(TRUE); /* From d7bbabf989820f911b74f97d2be73c8f8e4ab9c8 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 8 Aug 2005 19:04:11 +0500 Subject: [PATCH 036/230] grant.result: After merge fix --- mysql-test/r/grant.result | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 19982c7bb60..14393be1cc8 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -591,3 +591,6 @@ insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_gr flush privileges; delete from tables_priv where host = '' and user = 'mysqltest_1'; flush privileges; +set @user123="non-existent"; +select * from mysql.db where user=@user123; +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv From e6f96b49396edcc85e97e5eebb43f8a9e13bb994 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 8 Aug 2005 19:09:54 +0500 Subject: [PATCH 037/230] func_system.result, func_system.test: adding test case item_strfunc.cc: Bug#12351 CONCAT with USER()/DATEBASE() and a column gets strange results. Mark created Item_str as constant, so CONCAT cannot reuse it for optimization purposes. --- mysql-test/r/func_system.result | 15 +++++++++++++++ mysql-test/t/func_system.test | 12 ++++++++++++ sql/item_strfunc.cc | 1 + 3 files changed, 28 insertions(+) diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result index 137c25a2db5..d49da90fa28 100644 --- a/mysql-test/r/func_system.result +++ b/mysql-test/r/func_system.result @@ -68,6 +68,21 @@ drop table t1; select TRUE,FALSE,NULL; TRUE FALSE NULL 1 0 NULL +create table t1 (c1 char(5)) character set=latin1; +insert into t1 values('row 1'); +insert into t1 values('row 2'); +insert into t1 values('row 3'); +select concat(user(), '--', c1) from t1; +concat(user(), '--', c1) +root@localhost--row 1 +root@localhost--row 2 +root@localhost--row 3 +select concat(database(), '--', c1) from t1; +concat(database(), '--', c1) +test--row 1 +test--row 2 +test--row 3 +drop table t1; create table t1 (a char(10)) character set latin1; select * from t1 where a=version(); a diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test index d7e215f5d48..4a526935491 100644 --- a/mysql-test/t/func_system.test +++ b/mysql-test/t/func_system.test @@ -31,6 +31,18 @@ drop table t1; select TRUE,FALSE,NULL; +# +# Bug#12351: CONCAT with USER()/DATEBASE() and +# a constant and a column gets strange results +# +create table t1 (c1 char(5)) character set=latin1; +insert into t1 values('row 1'); +insert into t1 values('row 2'); +insert into t1 values('row 3'); +select concat(user(), '--', c1) from t1; +select concat(database(), '--', c1) from t1; +drop table t1; + # # Bug#8291 Illegal collation mix with USER() function # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d316c7eaf72..7a66a57c84b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1550,6 +1550,7 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs) return NULL; } conv->str_value.copy(); + conv->str_value.shrink_to_length(); return conv; } From 281c8ec163a6a9624ea992da31b1488731d1e857 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 8 Aug 2005 19:52:30 +0500 Subject: [PATCH 038/230] Bug#5439 : mysql_server_init() crashes if ShiftJIS path is passed (important for Adobe). mf_pack.c, mf_dirname.c, charset.c, my_sys.h: - adding fs_character_set() function on Windows - ignoring fake slashes which are just multibyte parts in several functions in /mysys Verified by Shu to work on WinXP and Win2k. Test is not possible, or very hard to do. --- include/my_sys.h | 5 +++++ mysys/charset.c | 26 ++++++++++++++++++++++++++ mysys/mf_dirname.c | 33 ++++++++++++++++++++++++++++++++- mysys/mf_pack.c | 12 ++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/my_sys.h b/include/my_sys.h index e56f07a8140..8752aa30772 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -788,6 +788,11 @@ extern my_bool init_compiled_charsets(myf flags); extern void add_compiled_collation(CHARSET_INFO *cs); extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); +#ifdef __WIN__ +#define BACKSLASH_MBTAIL +/* File system character set */ +extern CHARSET_INFO *fs_character_set(void); +#endif #ifdef __WIN__ extern my_bool have_tcpip; /* Is set if tcpip is used */ diff --git a/mysys/charset.c b/mysys/charset.c index cabdbad3413..3a39fce9437 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -637,3 +637,29 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, *to= 0; return (ulong) (to - to_start); } + + +#ifdef BACKSLASH_MBTAIL +static CHARSET_INFO *fs_cset_cache= NULL; + +CHARSET_INFO *fs_character_set() +{ + if (!fs_cset_cache) + { + char buf[10]= "cp"; + GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, + buf+2, sizeof(buf)-3); + /* + We cannot call get_charset_by_name here + because fs_character_set() is executed before + LOCK_THD_charset mutex initialization, which + is used inside get_charset_by_name. + As we're now interested in cp932 only, + let's just detect it using strcmp(). + */ + fs_cset_cache= !strcmp(buf, "cp932") ? + &my_charset_cp932_japanese_ci : &my_charset_bin; + } + return fs_cset_cache; +} +#endif diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c index 3de82c05b87..45bf4d56c31 100644 --- a/mysys/mf_dirname.c +++ b/mysys/mf_dirname.c @@ -22,6 +22,9 @@ uint dirname_length(const char *name) { register my_string pos,gpos; +#ifdef BASKSLASH_MBTAIL + CHARSET_INFO *fs= fs_character_set(); +#endif #ifdef FN_DEVCHAR if ((pos=(char*)strrchr(name,FN_DEVCHAR)) == 0) #endif @@ -29,12 +32,22 @@ uint dirname_length(const char *name) gpos= pos++; for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */ + { +#ifdef BASKSLASH_MBTAIL + uint l; + if (use_mb(fs) && (l= my_ismbchar(fs, pos, pos + 3))) + { + pos+= l - 1; + continue; + } +#endif if (*pos == FN_LIBCHAR || *pos == '/' #ifdef FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2 #endif ) gpos=pos; + } return ((uint) (uint) (gpos+1-(char*) name)); } @@ -85,6 +98,9 @@ uint dirname_part(my_string to, const char *name) char *convert_dirname(char *to, const char *from, const char *from_end) { char *to_org=to; +#ifdef BACKSLASH_MBTAIL + CHARSET_INFO *fs= fs_character_set(); +#endif /* We use -2 here, becasue we need place for the last FN_LIBCHAR */ if (!from_end || (from_end - from) > FN_REFLEN-2) @@ -103,7 +119,22 @@ char *convert_dirname(char *to, const char *from, const char *from_end) *to++= FN_C_AFTER_DIR; #endif else - *to++= *from; + { +#ifdef BACKSLASH_MBTAIL + uint l; + if (use_mb(fs) && (l= my_ismbchar(fs, from, from + 3))) + { + memmove(to, from, l); + to+= l; + from+= l - 1; + to_org= to; /* Don't look inside mbchar */ + } + else +#endif + { + *to++= *from; + } + } } *to=0; } diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 86172f648f4..049aa59a578 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -124,6 +124,9 @@ uint cleanup_dirname(register my_string to, const char *from) reg4 my_string start; char parent[5], /* for "FN_PARENTDIR" */ buff[FN_REFLEN+1],*end_parentdir; +#ifdef BACKSLASH_MBTAIL + CHARSET_INFO *fs= fs_character_set(); +#endif DBUG_ENTER("cleanup_dirname"); DBUG_PRINT("enter",("from: '%s'",from)); @@ -141,6 +144,15 @@ uint cleanup_dirname(register my_string to, const char *from) length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent); for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++) { +#ifdef BACKSLASH_MBTAIL + uint l; + if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2))) + { + for (l-- ; l ; *++pos= *from_ptr++, l--); + start= pos + 1; /* Don't look inside multi-byte char */ + continue; + } +#endif if (*pos == '/') *pos = FN_LIBCHAR; if (*pos == FN_LIBCHAR) From 043f77ccdf67a9102c59828bed6b76e5e3840c2f Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Mon, 8 Aug 2005 19:24:56 +0400 Subject: [PATCH 039/230] A fix and a test case for Bug#11909 "mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY nested queries corrupt result" --- sql/sql_prepare.cc | 7 ++- sql/sql_select.cc | 1 + sql/sql_select.h | 1 + tests/mysql_client_test.c | 120 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 18707cc6c87..0861bd1b0b2 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -88,6 +88,7 @@ class Prepared_statement: public Statement { public: THD *thd; + Protocol *protocol; Item_param **param_array; uint param_count; uint last_errno; @@ -2021,6 +2022,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) DBUG_VOID_RETURN; /* If lex->result is set, mysql_execute_command will use it */ stmt->lex->result= &cursor->result; + stmt->protocol= &cursor->protocol; thd->lock_id= &cursor->lock_id; } } @@ -2055,7 +2057,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) } mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query); - thd->protocol= &thd->protocol_prep; // Switch to binary protocol + thd->protocol= stmt->protocol; // Switch to binary protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); mysql_execute_command(thd); @@ -2247,7 +2249,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), QUERY_PRIOR); - thd->protocol= &thd->protocol_prep; // Switch to binary protocol + thd->protocol= stmt->protocol; // Switch to binary protocol cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol @@ -2419,6 +2421,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg) thd_arg->variables.query_alloc_block_size, thd_arg->variables.query_prealloc_size), thd(thd_arg), + protocol(&thd_arg->protocol_prep), param_array(0), param_count(0), last_errno(0) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1f89f04a19a..137e422a7d3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1715,6 +1715,7 @@ JOIN::destroy() Cursor::Cursor(THD *thd) :Query_arena(&main_mem_root, INITIALIZED), join(0), unit(0), + protocol(thd), close_at_commit(FALSE) { /* We will overwrite it at open anyway. */ diff --git a/sql/sql_select.h b/sql/sql_select.h index 1fa246370c6..c950444e1c6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -396,6 +396,7 @@ class Cursor: public Sql_alloc, public Query_arena }; Engine_info ht_info[MAX_HA]; public: + Protocol_prep protocol; Item_change_list change_list; select_send result; THR_LOCK_OWNER lock_id; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 53708a7a741..5e6de152f40 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13932,6 +13932,125 @@ static void test_bug12001() DIE_UNLESS(res==1); } + +/* Bug#11909: wrong metadata if fetching from two cursors */ + +static void test_bug11909() +{ + MYSQL_STMT *stmt1, *stmt2; + MYSQL_BIND bind[7]; + int rc; + char firstname[20], midinit[20], lastname[20], workdept[20]; + ulong firstname_len, midinit_len, lastname_len, workdept_len; + uint32 empno; + double salary; + float bonus; + const char *stmt_text; + + myheader("test_bug11909"); + + stmt_text= "drop table if exists t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (" + " empno int(11) not null, firstname varchar(20) not null," + " midinit varchar(20) not null, lastname varchar(20) not null," + " workdept varchar(6) not null, salary double not null," + " bonus float not null, primary key (empno)" + ") default charset=latin1 collate=latin1_bin"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "insert into t1 values " + "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000), " + "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800)," + "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800)," + "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), " + "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* ****** Begin of trace ****** */ + + stmt1= open_cursor("SELECT empno, firstname, midinit, lastname," + "workdept, salary, bonus FROM t1"); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void*) &empno; + + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void*) firstname; + bind[1].buffer_length= sizeof(firstname); + bind[1].length= &firstname_len; + + bind[2].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[2].buffer= (void*) midinit; + bind[2].buffer_length= sizeof(midinit); + bind[2].length= &midinit_len; + + bind[3].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[3].buffer= (void*) lastname; + bind[3].buffer_length= sizeof(lastname); + bind[3].length= &lastname_len; + + bind[4].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[4].buffer= (void*) workdept; + bind[4].buffer_length= sizeof(workdept); + bind[4].length= &workdept_len; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void*) &salary; + + bind[6].buffer_type= MYSQL_TYPE_FLOAT; + bind[6].buffer= (void*) &bonus; + rc= mysql_stmt_bind_result(stmt1, bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == 0); + DIE_UNLESS(empno == 10); + DIE_UNLESS(strcmp(firstname, "CHRISTINE") == 0); + DIE_UNLESS(strcmp(midinit, "I") == 0); + DIE_UNLESS(strcmp(lastname, "HAAS") == 0); + DIE_UNLESS(strcmp(workdept, "A00") == 0); + DIE_UNLESS(salary == (double) 52750.0); + DIE_UNLESS(bonus == (float) 1000.0); + + stmt2= open_cursor("SELECT empno, firstname FROM t1"); + rc= mysql_stmt_bind_result(stmt2, bind); + check_execute(stmt2, rc); + + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + + rc= mysql_stmt_fetch(stmt2); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(empno == 10); + DIE_UNLESS(strcmp(firstname, "CHRISTINE") == 0); + + rc= mysql_stmt_reset(stmt2); + check_execute(stmt2, rc); + + /* ERROR: next statement should return 0 */ + + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == 0); + + mysql_stmt_close(stmt1); + mysql_stmt_close(stmt2); + rc= mysql_rollback(mysql); + myquery(rc); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14178,6 +14297,7 @@ static struct my_tests_st my_tests[]= { { "test_bug11037", test_bug11037 }, { "test_bug10760", test_bug10760 }, { "test_bug12001", test_bug12001 }, + { "test_bug11909", test_bug11909 }, { 0, 0 } }; From 0952c3ea53bc2bb794de02749528f8755181c1e9 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 8 Aug 2005 20:35:51 +0200 Subject: [PATCH 040/230] void handler::print_error(): cleanup --- sql/handler.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 1f13f0d5e36..5a8762a615e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1660,7 +1660,7 @@ void handler::print_error(int error, myf errflag) } case HA_ERR_NULL_IN_SPATIAL: textno= ER_UNKNOWN_ERROR; - DBUG_VOID_RETURN; + break; case HA_ERR_FOUND_DUPP_UNIQUE: textno=ER_DUP_UNIQUE; break; @@ -1683,8 +1683,8 @@ void handler::print_error(int error, myf errflag) textno=ER_CRASHED_ON_REPAIR; break; case HA_ERR_OUT_OF_MEM: - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), errflag); - DBUG_VOID_RETURN; + textno=ER_OUT_OF_RESOURCES; + break; case HA_ERR_WRONG_COMMAND: textno=ER_ILLEGAL_HA; break; @@ -1695,10 +1695,8 @@ void handler::print_error(int error, myf errflag) textno=ER_UNSUPPORTED_EXTENSION; break; case HA_ERR_RECORD_FILE_FULL: - textno=ER_RECORD_FILE_FULL; - break; case HA_ERR_INDEX_FILE_FULL: - textno= errno; + textno=ER_RECORD_FILE_FULL; break; case HA_ERR_LOCK_WAIT_TIMEOUT: textno=ER_LOCK_WAIT_TIMEOUT; From 253d528b143d64889b517a184d5591b724452b36 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Mon, 8 Aug 2005 11:42:09 -0700 Subject: [PATCH 041/230] Fix error code in some tests because of merge --- mysql-test/t/errors.test | 2 +- mysql-test/t/type_bit.test | 2 +- mysql-test/t/type_bit_innodb.test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index f7913ab402c..a3aeee2ce66 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -35,7 +35,7 @@ drop table t1; # # Bug #6080: Error message for a field with a display width that is too long # ---error 1438 +--error 1439 create table t1 (a int(256)); set sql_mode='traditional'; --error 1074 diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index fd5eb49858c..005a2c78a14 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -19,7 +19,7 @@ select 0 + b'1000000000000001'; drop table if exists t1; --enable_warnings ---error 1074 +--error 1439 create table t1 (a bit(65)); create table t1 (a bit(0)); diff --git a/mysql-test/t/type_bit_innodb.test b/mysql-test/t/type_bit_innodb.test index 090b7aef218..ec433f40a88 100644 --- a/mysql-test/t/type_bit_innodb.test +++ b/mysql-test/t/type_bit_innodb.test @@ -20,7 +20,7 @@ select 0 + b'1000000000000001'; drop table if exists t1; --enable_warnings ---error 1438 +--error 1439 create table t1 (a bit(65)) engine=innodb; create table t1 (a bit(0)) engine=innodb; From 10e5ee5196408cda111a29c124216660b91e8121 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 8 Aug 2005 21:43:08 +0300 Subject: [PATCH 042/230] ha_innodb.cc: Add a forgotten newline to a print --- sql/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 8dd45c03350..d5d79b51f60 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2150,7 +2150,7 @@ innobase_close_connection( ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: Warning: MySQL is closing a connection" +" InnoDB: Warning: MySQL is closing a connection\n" "InnoDB: that has an active InnoDB transaction. We roll back that\n" "InnoDB: transaction. %lu row modifications to roll back.\n", (ulong)trx->undo_no.low); From 2b041344393c742eae1e1f0e3d426662c5a53102 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Mon, 8 Aug 2005 12:59:04 -0700 Subject: [PATCH 043/230] Report 'SYSTEM VIEW' as table_type of INFORMATION_SCHEMA views. (Bug #11711) --- mysql-test/r/information_schema.result | 12 ++++++------ sql/sql_show.cc | 8 +++++--- sql/table.h | 3 ++- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index e6a929d7e3e..687c653b4f7 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -577,8 +577,8 @@ select TABLE_NAME,TABLE_TYPE,ENGINE from information_schema.tables where table_schema='information_schema' limit 2; TABLE_NAME TABLE_TYPE ENGINE -SCHEMATA TEMPORARY MEMORY -TABLES TEMPORARY MEMORY +SCHEMATA SYSTEM VIEW MEMORY +TABLES SYSTEM VIEW MEMORY show tables from information_schema like "T%"; Tables_in_information_schema (T%) TABLES @@ -590,10 +590,10 @@ ERROR HY000: Can't create database 'information_schema'; database exists use information_schema; show full tables like "T%"; Tables_in_information_schema (T%) Table_type -TABLES TEMPORARY -TABLE_PRIVILEGES TEMPORARY -TABLE_CONSTRAINTS TEMPORARY -TRIGGERS TEMPORARY +TABLES SYSTEM VIEW +TABLE_PRIVILEGES SYSTEM VIEW +TABLE_CONSTRAINTS SYSTEM VIEW +TRIGGERS SYSTEM VIEW create table t1(a int); ERROR 42S02: Unknown table 't1' in information_schema use test; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 56272b4fdaf..c51da657b0f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2034,7 +2034,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { if (with_i_schema) { - table->field[3]->store("TEMPORARY", 9, system_charset_info); + table->field[3]->store("SYSTEM VIEW", 11, system_charset_info); } else { @@ -2193,7 +2193,9 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, handler *file= show_table->file; file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK); - if (share->tmp_table == TMP_TABLE) + if (share->tmp_table == SYSTEM_TMP_TABLE) + table->field[3]->store("SYSTEM VIEW", 11, cs); + else if (share->tmp_table) table->field[3]->store("TEMPORARY", 9, cs); else table->field[3]->store("BASE TABLE", 10, cs); @@ -3532,7 +3534,7 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { DBUG_RETURN(1); } - table->s->tmp_table= TMP_TABLE; + table->s->tmp_table= SYSTEM_TMP_TABLE; table->grant.privilege= SELECT_ACL; /* This test is necessary to make diff --git a/sql/table.h b/sql/table.h index 13d44766804..2cebbcd93cd 100644 --- a/sql/table.h +++ b/sql/table.h @@ -49,7 +49,8 @@ typedef struct st_grant_info ulong want_privilege; } GRANT_INFO; -enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2}; +enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2, + SYSTEM_TMP_TABLE=3}; enum frm_type_enum { From 6128521b5bd11f9a27520f25d5673f3042390e99 Mon Sep 17 00:00:00 2001 From: "patg@krsna.patg.net" <> Date: Mon, 8 Aug 2005 13:46:13 -0700 Subject: [PATCH 044/230] item_strfunc.cc: BUG #11104 Took out the offset-=delimiter_length-1 out of the for loop. It was causing basically this: select substring_index('the king of the the hill', 'the', -2) to not work. The first iteration, offset would be initialised to 24, then strstr would point at 'the king of the the* hill' ('*'means right before the character following), returning a offset of 16. The for loop would then decrement offset by two (3 - 1), to 14, now pointing at "the king of th*e the hill", _skipping_ past the 'e' in the second to last 'the', and therefore strstr would never have a chance of matching the second to last 'the', then moving on to the 'the' at the begginning of the string! In a nutshell, offset was being decremented by too great a value, preventing the second to last 'the' from being ever found, hence the result of 'king of the the hill' from the query that is reported in the bug report func_str.test: BUG #11104 Added tests to make sure fix addresses issues in original bug report func_str.result: BUG #11104 New results for new tests --- mysql-test/r/func_str.result | 117 +++++++++++++++++++++++++++++++++++ mysql-test/t/func_str.test | 39 ++++++++++++ sql/item_strfunc.cc | 16 ++++- 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 4c3a03b8066..ae6578795f6 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -45,6 +45,123 @@ www. .se select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); substring_index('.tcx.se','.',-2) substring_index('.tcx.se','.tcx',-1) tcx.se .se +select substring_index('aaaaaaaaa1','a',1); +substring_index('aaaaaaaaa1','a',1) + +select substring_index('aaaaaaaaa1','aa',1); +substring_index('aaaaaaaaa1','aa',1) + +select substring_index('aaaaaaaaa1','aa',2); +substring_index('aaaaaaaaa1','aa',2) +aa +select substring_index('aaaaaaaaa1','aa',3); +substring_index('aaaaaaaaa1','aa',3) +aaaa +select substring_index('aaaaaaaaa1','aa',4); +substring_index('aaaaaaaaa1','aa',4) +aaaaaa +select substring_index('aaaaaaaaa1','aa',5); +substring_index('aaaaaaaaa1','aa',5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',1); +substring_index('aaaaaaaaa1','aaa',1) + +select substring_index('aaaaaaaaa1','aaa',2); +substring_index('aaaaaaaaa1','aaa',2) +aaa +select substring_index('aaaaaaaaa1','aaa',3); +substring_index('aaaaaaaaa1','aaa',3) +aaaaaa +select substring_index('aaaaaaaaa1','aaa',4); +substring_index('aaaaaaaaa1','aaa',4) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaaa',1); +substring_index('aaaaaaaaa1','aaaa',1) + +select substring_index('aaaaaaaaa1','aaaa',2); +substring_index('aaaaaaaaa1','aaaa',2) +aaaa +select substring_index('aaaaaaaaa1','1',1); +substring_index('aaaaaaaaa1','1',1) +aaaaaaaaa +select substring_index('aaaaaaaaa1','a',-1); +substring_index('aaaaaaaaa1','a',-1) +1 +select substring_index('aaaaaaaaa1','aa',-1); +substring_index('aaaaaaaaa1','aa',-1) +1 +select substring_index('aaaaaaaaa1','aa',-2); +substring_index('aaaaaaaaa1','aa',-2) +aa1 +select substring_index('aaaaaaaaa1','aa',-3); +substring_index('aaaaaaaaa1','aa',-3) +aaaa1 +select substring_index('aaaaaaaaa1','aa',-4); +substring_index('aaaaaaaaa1','aa',-4) +aaaaaa1 +select substring_index('aaaaaaaaa1','aa',-5); +substring_index('aaaaaaaaa1','aa',-5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-1); +substring_index('aaaaaaaaa1','aaa',-1) +1 +select substring_index('aaaaaaaaa1','aaa',-2); +substring_index('aaaaaaaaa1','aaa',-2) +aaa1 +select substring_index('aaaaaaaaa1','aaa',-3); +substring_index('aaaaaaaaa1','aaa',-3) +aaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-4); +substring_index('aaaaaaaaa1','aaa',-4) + +select substring_index('the king of thethe hill','the',-2); +substring_index('the king of thethe hill','the',-2) +the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill',' the ',-1); +substring_index('the king of the the hill',' the ',-1) +hill +select substring_index('the king of the the hill',' the ',-2); +substring_index('the king of the the hill',' the ',-2) + the hill +select substring_index('the king of the the hill',' ',-1); +substring_index('the king of the the hill',' ',-1) +hill +select substring_index('the king of the the hill',' ',-2); +substring_index('the king of the the hill',' ',-2) +the hill +select substring_index('the king of the the hill',' ',-3); +substring_index('the king of the the hill',' ',-3) + the hill +select substring_index('the king of the the hill',' ',-4); +substring_index('the king of the the hill',' ',-4) +the the hill +select substring_index('the king of the the hill',' ',-5); +substring_index('the king of the the hill',' ',-5) +of the the hill +select substring_index('the king of the.the hill','the',-2); +substring_index('the king of the.the hill','the',-2) +.the hill +select substring_index('the king of thethethe.the hill','the',-3); +substring_index('the king of thethethe.the hill','the',-3) +the.the hill +select substring_index('the king of thethethe.the hill','the',-1); +substring_index('the king of thethethe.the hill','the',-1) + hill +select substring_index('the king of the the hill','the',1); +substring_index('the king of the the hill','the',1) + +select substring_index('the king of the the hill','the',2); +substring_index('the king of the the hill','the',2) +the king of +select substring_index('the king of the the hill','the',3); +substring_index('the king of the the hill','the',3) +the king of the select concat(':',ltrim(' left '),':',rtrim(' right '),':'); concat(':',ltrim(' left '),':',rtrim(' right '),':') :left : right: diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index ddfc83e620a..8afbe673ce3 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -23,6 +23,45 @@ select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',s select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1); select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1); select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); +select substring_index('aaaaaaaaa1','a',1); +select substring_index('aaaaaaaaa1','aa',1); +select substring_index('aaaaaaaaa1','aa',2); +select substring_index('aaaaaaaaa1','aa',3); +select substring_index('aaaaaaaaa1','aa',4); +select substring_index('aaaaaaaaa1','aa',5); +select substring_index('aaaaaaaaa1','aaa',1); +select substring_index('aaaaaaaaa1','aaa',2); +select substring_index('aaaaaaaaa1','aaa',3); +select substring_index('aaaaaaaaa1','aaa',4); +select substring_index('aaaaaaaaa1','aaaa',1); +select substring_index('aaaaaaaaa1','aaaa',2); +select substring_index('aaaaaaaaa1','1',1); +select substring_index('aaaaaaaaa1','a',-1); +select substring_index('aaaaaaaaa1','aa',-1); +select substring_index('aaaaaaaaa1','aa',-2); +select substring_index('aaaaaaaaa1','aa',-3); +select substring_index('aaaaaaaaa1','aa',-4); +select substring_index('aaaaaaaaa1','aa',-5); +select substring_index('aaaaaaaaa1','aaa',-1); +select substring_index('aaaaaaaaa1','aaa',-2); +select substring_index('aaaaaaaaa1','aaa',-3); +select substring_index('aaaaaaaaa1','aaa',-4); +select substring_index('the king of thethe hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill',' the ',-1); +select substring_index('the king of the the hill',' the ',-2); +select substring_index('the king of the the hill',' ',-1); +select substring_index('the king of the the hill',' ',-2); +select substring_index('the king of the the hill',' ',-3); +select substring_index('the king of the the hill',' ',-4); +select substring_index('the king of the the hill',' ',-5); +select substring_index('the king of the.the hill','the',-2); +select substring_index('the king of thethethe.the hill','the',-3); +select substring_index('the king of thethethe.the hill','the',-1); +select substring_index('the king of the the hill','the',1); +select substring_index('the king of the the hill','the',2); +select substring_index('the king of the the hill','the',3); select concat(':',ltrim(' left '),':',rtrim(' right '),':'); select concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':'); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d316c7eaf72..52a2dedb67c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -42,7 +42,7 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) { my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), + c1.collation->name,c1.derivation_name(), c2.collation->name,c2.derivation_name(), fname); } @@ -1188,10 +1188,22 @@ String *Item_func_substr_index::val_str(String *str) } else { // Start counting at end - for (offset=res->length() ; ; offset-=delimeter_length-1) + /* + Negative index, start counting at the end + */ + for (offset=res->length(); offset ;) { + /* + this call will result in finding the position pointing to one + address space less than where the found substring is located + in res + */ if ((int) (offset=res->strrstr(*delimeter,offset)) < 0) return res; // Didn't find, return org string + /* + At this point, we've searched for the substring + the number of times as supplied by the index value + */ if (!++count) { offset+=delimeter_length; From 74c71689926802047d249684501d433ae86f324d Mon Sep 17 00:00:00 2001 From: "patg@krsna.patg.net" <> Date: Mon, 8 Aug 2005 13:50:10 -0700 Subject: [PATCH 045/230] BUG #12119 Removed unnecessary error message from mysql.cc (client program) --- client/mysql.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 5454c76e720..63173aab20d 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1563,11 +1563,8 @@ You can turn off this feature to get a quicker startup with -A\n\n"); mysql_free_result(fields); } else - { - tee_fprintf(stdout, - "Didn't find any fields in table '%s'\n",table_row[0]); field_names[i]= 0; - } + i++; } mysql_free_result(tables); From 99cb083549fb13a5f9e6d13617e75f1fadf65236 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Tue, 9 Aug 2005 00:13:49 +0300 Subject: [PATCH 046/230] Review of new pushed code - Fixed some error condtion when handling dates with 'T' - Added extra test for bug #11867 (Wrong result with "... WHERE ROW( a, b ) IN ( SELECT DISTINCT a, b WHERE ...)" to show it's not yet fixed - Safety fixes and cleanups --- mysql-test/r/subselect.result | 15 +++++++++++++++ mysql-test/r/type_datetime.result | 23 +++++++++++++---------- mysql-test/t/subselect.test | 4 ++++ mysql-test/t/type_datetime.test | 21 +++++++++++---------- sql-common/my_time.c | 6 ++++-- sql/slave.cc | 4 ++-- sql/sql_parse.cc | 12 ++++++++---- sql/sql_select.cc | 6 ++---- sql/sql_union.cc | 6 ++++-- 9 files changed, 63 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 25d9a39705d..863a250c670 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2741,4 +2741,19 @@ WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); one two flag 5 6 N 7 8 N +insert into t2 values (null,null,'N'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +one two test +1 2 0 +2 3 0 +3 4 0 +5 6 1 +7 8 1 +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; +one two test +1 2 NULL +2 3 NULL +3 4 NULL +5 6 1 +7 8 1 DROP TABLE t1,t2; diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 8d28504d790..f313a6b934b 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -26,6 +26,8 @@ Table Op Msg_type Msg_text test.t1 check status OK delete from t1; insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000"); +insert into t1 values ("2003-003-03"); +insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01"); select * from t1; t 2000-01-01 00:00:00 @@ -43,6 +45,17 @@ t 9999-12-31 23:59:59 2003-01-00 00:00:00 2003-00-00 00:00:00 +2003-03-03 00:00:00 +2003-01-02 13:14:15 +2001-01-01 01:01:01 +2001-01-01 01:01:01 +truncate table t1; +insert into t1 values("2003-0303 12:13:14"); +Warnings: +Warning 1264 Data truncated; out of range for column 't' at row 1 +select * from t1; +t +0000-00-00 00:00:00 drop table t1; CREATE TABLE t1 (a timestamp, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); @@ -153,13 +166,3 @@ dt 0000-00-00 00:00:00 0000-00-00 00:00:00 drop table t1; -create table t1 (dt datetime); -insert into t1 values ("20010101T010101"); -insert into t1 values ("2001-01-01T01:01:01"); -insert into t1 values ("2001-1-1T1:01:01"); -select * from t1; -dt -2001-01-01 01:01:01 -2001-01-01 01:01:01 -2001-01-01 01:01:01 -drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 0b4791b0023..ecd553ee8f8 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1768,6 +1768,10 @@ SELECT * FROM t1 SELECT * FROM t1 WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); +insert into t2 values (null,null,'N'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; + DROP TABLE t1,t2; # End of 4.1 tests diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index ca70e35d3cd..4b6741b4242 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -14,6 +14,17 @@ optimize table t1; check table t1; delete from t1; insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000"); + +# Strange dates +insert into t1 values ("2003-003-03"); + +# Bug #7308: ISO-8601 date format not handled correctly +insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01"); +select * from t1; + +# Test some wrong dates +truncate table t1; +insert into t1 values("2003-0303 12:13:14"); select * from t1; drop table t1; @@ -102,14 +113,4 @@ insert into t1 values ("00-00-00"), ("00-00-00 00:00:00"); select * from t1; drop table t1; -# -# Bug #7308: ISO-8601 date format not handled correctly -# -create table t1 (dt datetime); -insert into t1 values ("20010101T010101"); -insert into t1 values ("2001-01-01T01:01:01"); -insert into t1 values ("2001-1-1T1:01:01"); -select * from t1; -drop table t1; - # End of 4.1 tests diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 1726a9a6e78..40d7799e274 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -137,7 +137,9 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ - for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) + for (pos=str; + pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T'); + pos++) ; digits= (uint) (pos-str); @@ -203,7 +205,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, const char *start= str; ulong tmp_value= (uint) (uchar) (*str++ - '0'); while (str != end && my_isdigit(&my_charset_latin1,str[0]) && - --field_length) + (!is_internal_format || --field_length)) { tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0'); str++; diff --git a/sql/slave.cc b/sql/slave.cc index a0cc773d44f..9ff7a432b89 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2186,8 +2186,8 @@ int show_master_info(THD* thd, MASTER_INFO* mi) &my_charset_bin); protocol->store((ulonglong) mi->rli.group_relay_log_pos); protocol->store(mi->rli.group_master_log_name, &my_charset_bin); - protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT - ? "Yes":"No", &my_charset_bin); + protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ? + "Yes" : "No", &my_charset_bin); protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin); protocol->store(&replicate_do_db); protocol->store(&replicate_ignore_db); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 135cef43e90..869e8e5063f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4211,10 +4211,12 @@ void create_select_for_variable(const char *var_name) We set the name of Item to @@session.var_name because that then is used as the column name in the output. */ - var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string); - end= strxmov(buff, "@@session.", var_name, NullS); - var->set_name(buff, end-buff, system_charset_info); - add_item_to_list(thd, var); + if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string))) + { + end= strxmov(buff, "@@session.", var_name, NullS); + var->set_name(buff, end-buff, system_charset_info); + add_item_to_list(thd, var); + } DBUG_VOID_RETURN; } @@ -5038,11 +5040,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count; for (; lock_p < end_p; lock_p++) + { if ((*lock_p)->type == TL_WRITE) { my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); return 1; } + } } /* Writing to the binlog could cause deadlocks, as we don't log diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 54afe5bb7a6..353ccf79ab8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2260,11 +2260,9 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, We use null_rejecting in add_not_null_conds() to add 'othertbl.field IS NOT NULL' to tab->select_cond. */ - (*key_fields)->null_rejecting= (cond->functype() == Item_func::EQ_FUNC) && + (*key_fields)->null_rejecting= ((cond->functype() == Item_func::EQ_FUNC) && ((*value)->type() == Item::FIELD_ITEM) && - - (((Item_field*)*value)->field->maybe_null() || - ((Item_field *)*value)->field->table->maybe_null); + ((Item_field*)*value)->field->maybe_null()); (*key_fields)++; } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index c33444fd73e..8bb53f7b573 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -285,6 +285,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, List_iterator_fast tp(types); Item_arena *arena= thd->current_arena; Item *type; + ulong create_options; + while ((type= tp++)) { if (type->result_type() == STRING_RESULT && @@ -295,8 +297,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - ulong create_options= first_select_in_union()->options | thd_arg->options | - TMP_TABLE_ALL_COLUMNS; + create_options= (first_select_in_union()->options | thd_arg->options | + TMP_TABLE_ALL_COLUMNS); /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading From c6db76b07611a5cbe85048320a543c026bbf8c2c Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Mon, 8 Aug 2005 23:23:34 +0000 Subject: [PATCH 047/230] Fix for BUG#12228: SP cache code: * Cleanup SP Cache code, now SP Cache only deletes sp_head objects in sp_cache_flush_obsolete() invalidates all pointers to routines in the cache. * Use new SP Cache use contract in the code. There is no test case because it doesn't seem to be possible to cause thread races to end the same way they end in heavy-load test. This patch removes the crash in heavy test. --- mysql-test/r/type_bit.result | 2 +- mysql-test/r/view.result | 2 + mysql-test/t/type_bit.test | 2 +- mysql-test/t/view.test | 4 + sql/sp.cc | 16 +-- sql/sp_cache.cc | 211 +++++++++++++++++++++++++---------- sql/sp_cache.h | 105 +++++------------ sql/sql_parse.cc | 3 +- sql/sql_prepare.cc | 5 + 9 files changed, 196 insertions(+), 154 deletions(-) diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 4aa8587d6e1..c22ceba70d8 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -34,7 +34,7 @@ select 0 + b'1111111111111111'; select 0 + b'1000000000000001'; 0 + b'1000000000000001' 32769 -drop table if exists t1; +drop table if exists t1,t2; create table t1 (a bit(65)); ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead create table t1 (a bit(0)); diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index f6b5018cf3a..98020c7ec33 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1880,6 +1880,8 @@ test.v5 check error View 'test.v5' references invalid table(s) or column(s) or f test.v6 check status OK drop view v1, v2, v3, v4, v5, v6; drop table t2; +drop function if exists f1; +drop function if exists f2; CREATE TABLE t1 (col1 time); CREATE TABLE t2 (col1 time); CREATE TABLE t3 (col1 time); diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index fd5eb49858c..a56b697ea6b 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -16,7 +16,7 @@ select 0 + b'1111111111111111'; select 0 + b'1000000000000001'; --disable_warnings -drop table if exists t1; +drop table if exists t1,t2; --enable_warnings --error 1074 diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 9885566442f..cba2d75fb7c 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1711,6 +1711,10 @@ CHECK TABLE v1, v2, v3, v4, v5, v6; drop view v1, v2, v3, v4, v5, v6; drop table t2; +--disable_warnings +drop function if exists f1; +drop function if exists f2; +--enable_warnings CREATE TABLE t1 (col1 time); CREATE TABLE t2 (col1 time); CREATE TABLE t3 (col1 time); diff --git a/sql/sp.cc b/sql/sp.cc index 297e17de689..e875c30ab1b 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -986,13 +986,11 @@ int sp_drop_procedure(THD *thd, sp_name *name) { int ret; - bool found; DBUG_ENTER("sp_drop_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_proc_cache, name); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1002,13 +1000,11 @@ int sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; - bool found; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_proc_cache, name); ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1099,13 +1095,11 @@ int sp_drop_function(THD *thd, sp_name *name) { int ret; - bool found; DBUG_ENTER("sp_drop_function"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_func_cache, name); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1115,13 +1109,11 @@ int sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; - bool found; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_func_cache, name); ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index c8f0ed6ba2d..135000d1443 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -24,17 +24,78 @@ static pthread_mutex_t Cversion_lock; static ulong Cversion = 0; -void -sp_cache_init() + +/* + Cache of stored routines. +*/ + +class sp_cache +{ +public: + ulong version; + + sp_cache(); + ~sp_cache(); + + inline void insert(sp_head *sp) + { + /* TODO: why don't we check return value? */ + my_hash_insert(&m_hashtable, (const byte *)sp); + } + + inline sp_head *lookup(char *name, uint namelen) + { + return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen); + } + +#ifdef NOT_USED + inline bool remove(char *name, uint namelen) + { + sp_head *sp= lookup(name, namelen); + if (sp) + { + hash_delete(&m_hashtable, (byte *)sp); + return TRUE; + } + return FALSE; + } +#endif + + inline void remove_all() + { + cleanup(); + init(); + } + +private: + void init(); + void cleanup(); + + /* All routines in this cache */ + HASH m_hashtable; +}; // class sp_cache + + +/* Initialize the SP caching once at startup */ + +void sp_cache_init() { pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST); } -void -sp_cache_clear(sp_cache **cp) + +/* + Clear the cache *cp and set *cp to NULL. + SYNOPSIS + sp_cache_clear() + cp Pointer to cache to clear + NOTE + This function doesn't invalidate other caches. +*/ + +void sp_cache_clear(sp_cache **cp) { sp_cache *c= *cp; - if (c) { delete c; @@ -42,86 +103,119 @@ sp_cache_clear(sp_cache **cp) } } -void -sp_cache_insert(sp_cache **cp, sp_head *sp) + +/* + Insert a routine into the cache. + + SYNOPSIS + sp_cache_insert() + cp The cache to put routine into + sp Routine to insert. +*/ + +void sp_cache_insert(sp_cache **cp, sp_head *sp) { sp_cache *c= *cp; if (! c) - c= new sp_cache(); - if (c) { ulong v; - + c= new sp_cache(); pthread_mutex_lock(&Cversion_lock); // LOCK v= Cversion; pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - if (*cp) - c->remove_all(); - c->version= v; - } + c->version= v; + } + if (c) + { + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, sp->m_qname.str)); c->insert(sp); if (*cp == NULL) *cp= c; } } -sp_head * -sp_cache_lookup(sp_cache **cp, sp_name *name) + +/* + Look up a routine in the cache. + SYNOPSIS + sp_cache_lookup() + cp Cache to look into + name Name of rutine to find + + NOTE + An obsolete (but not more obsolete then since last + sp_cache_flush_obsolete call) routine may be returned. + + RETURN + The routine or + NULL if the routine not found. +*/ + +sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) { - ulong v; sp_cache *c= *cp; - - if (! c) + if (!c) return NULL; - - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - c->remove_all(); - c->version= v; - return NULL; - } return c->lookup(name->m_qname.str, name->m_qname.length); } -bool -sp_cache_remove(sp_cache **cp, sp_name *name) -{ - sp_cache *c= *cp; - bool found= FALSE; - - if (c) - { - ulong v; - - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion++; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - c->remove_all(); - else - found= c->remove(name->m_qname.str, name->m_qname.length); - c->version= v+1; - } - return found; -} - -void -sp_cache_invalidate() + +/* + Invalidate all routines in all caches. + + SYNOPSIS + sp_cache_invalidate() + + NOTE + This is called when a VIEW definition is modifed. We can't destroy sp_head + objects here as one may modify VIEW definitions from prelocking-free SPs. +*/ + +void sp_cache_invalidate() { + DBUG_PRINT("info",("sp_cache: invalidating")); pthread_mutex_lock(&Cversion_lock); // LOCK Cversion++; pthread_mutex_unlock(&Cversion_lock); // UNLOCK } + +/* + Remove out-of-date SPs from the cache. + + SYNOPSIS + sp_cache_flush_obsolete() + cp Cache to flush + + NOTE + This invalidates pointers to sp_head objects this thread uses. + In practice that means 'dont call this function when inside SP'. +*/ + +void sp_cache_flush_obsolete(sp_cache **cp) +{ + sp_cache *c= *cp; + if (c) + { + ulong v; + pthread_mutex_lock(&Cversion_lock); // LOCK + v= Cversion; + pthread_mutex_unlock(&Cversion_lock); // UNLOCK + if (c->version < v) + { + DBUG_PRINT("info",("sp_cache: deleting all functions")); + /* We need to delete all elements. */ + c->remove_all(); + c->version= v; + } + } +} + +/************************************************************************* + Internal functions + *************************************************************************/ + static byte * hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) @@ -136,7 +230,6 @@ static void hash_free_sp_head(void *p) { sp_head *sp= (sp_head *)p; - delete sp; } diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 14b2db97f5f..402647db9ea 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -25,94 +25,39 @@ /* Stored procedures/functions cache. This is used as follows: * Each thread has its own cache. - * Each sp_head object is put into its thread cache before it is used, and + * Each sp_head object is put into its thread cache before it is used, and then remains in the cache until deleted. */ class sp_head; class sp_cache; -/* Initialize the SP caching once at startup */ -void sp_cache_init(); - -/* Clear the cache *cp and set *cp to NULL */ -void sp_cache_clear(sp_cache **cp); - -/* Insert an SP into cache. If 'cp' points to NULL, it's set to a new cache */ -void sp_cache_insert(sp_cache **cp, sp_head *sp); - -/* Lookup an SP in cache */ -sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); - -/* - Remove an SP from cache, and also bump the Cversion number so all other - caches are invalidated. - Returns true if something was removed. -*/ -bool sp_cache_remove(sp_cache **cp, sp_name *name); - -/* Invalidate all existing SP caches by bumping Cversion number. */ -void sp_cache_invalidate(); - - /* - * - * The cache class. Don't use this directly, use the C API above - * - */ + Cache usage scenarios: + 1. Application-wide init: + sp_cache_init(); -class sp_cache -{ -public: + 2. SP execution in thread: + 2.1 While holding sp_head* pointers: + + // look up a routine in the cache (no checks if it is up to date or not) + sp_cache_lookup(); + + sp_cache_insert(); + sp_cache_invalidate(); + + 2.2 When not holding any sp_head* pointers (at query end): + sp_cache_flush_obsolete(); + + 3. Before thread exit: + sp_cache_clear(); +*/ - ulong version; - - sp_cache(); - - ~sp_cache(); - - void - init(); - - void - cleanup(); - - inline void - insert(sp_head *sp) - { - my_hash_insert(&m_hashtable, (const byte *)sp); - } - - inline sp_head * - lookup(char *name, uint namelen) - { - return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen); - } - - inline bool - remove(char *name, uint namelen) - { - sp_head *sp= lookup(name, namelen); - - if (sp) - { - hash_delete(&m_hashtable, (byte *)sp); - return TRUE; - } - return FALSE; - } - - inline void - remove_all() - { - cleanup(); - init(); - } - -private: - - HASH m_hashtable; - -}; // class sp_cache +void sp_cache_init(); +void sp_cache_clear(sp_cache **cp); +void sp_cache_insert(sp_cache **cp, sp_head *sp); +sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); +void sp_cache_invalidate(); +void sp_cache_flush_obsolete(sp_cache **cp); #endif /* _SP_CACHE_H_ */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 677b3a98174..00463dc0a3b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5347,7 +5347,8 @@ void mysql_init_multi_delete(LEX *lex) void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); - + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); mysql_init_query(thd, (uchar*) inBuf, length); if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 18707cc6c87..f8b19dac3d1 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -73,6 +73,7 @@ Long data handling: #include // for isspace() #include "sp_head.h" #include "sp.h" +#include "sp_cache.h" #ifdef EMBEDDED_LIBRARY /* include MYSQL_BIND headers */ #include @@ -1729,6 +1730,8 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, DBUG_ENTER("mysql_stmt_prepare"); DBUG_PRINT("prep_query", ("%s", packet)); + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); /* If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql. @@ -1978,6 +1981,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_execute"); + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); packet+= 9; /* stmt_id + 5 bytes of flags */ statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); From 73be194f966428646ed13eea0c7b73034cff9f8b Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 8 Aug 2005 16:51:12 -0700 Subject: [PATCH 048/230] subselect.test, subselect.result: Added a test case for bug #12392. item_cmpfunc.cc: Fixed bug #12392. Missing handling of rows containing NULL components when evaluating IN predicates caused a crash. --- mysql-test/r/subselect.result | 6 ++++++ mysql-test/t/subselect.test | 11 +++++++++++ sql/item_cmpfunc.cc | 2 ++ 3 files changed, 19 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 25d9a39705d..eaacf5ba2d0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2742,3 +2742,9 @@ one two flag 5 6 N 7 8 N DROP TABLE t1,t2; +CREATE TABLE t1 (a char(5), b char(5)); +INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); +SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); +a b +aaa aaa +DROP TABLE t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 0b4791b0023..951dc31006e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1770,4 +1770,15 @@ SELECT * FROM t1 DROP TABLE t1,t2; +# +# Bug #12392: where cond with IN predicate for rows and NULL values in table +# + +CREATE TABLE t1 (a char(5), b char(5)); +INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); + +SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f24638d1a93..9146b3c3b9e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1551,6 +1551,8 @@ in_row::~in_row() byte *in_row::get_value(Item *item) { tmp.store_value(item); + if (item->is_null()) + return 0; return (byte *)&tmp; } From d6a8330e393a4668050150f2db3d80c6dcd448d0 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Mon, 8 Aug 2005 18:05:27 -0700 Subject: [PATCH 049/230] Avoid problems on shutdown by shutting down replication slave threads after normal connection threads. (Bug #11796) --- sql/mysqld.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 896114f98c6..394dd3294de 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -648,7 +648,6 @@ static void close_connections(void) } #endif end_thr_alarm(0); // Abort old alarms. - end_slave(); /* First signal all threads that it's time to die @@ -664,6 +663,9 @@ static void close_connections(void) { DBUG_PRINT("quit",("Informing thread %ld that it's time to die", tmp->thread_id)); + /* We skip slave threads on this first loop through. */ + if (tmp->slave_thread) continue; + tmp->killed= 1; if (tmp->mysys_var) { @@ -680,6 +682,8 @@ static void close_connections(void) } (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list + end_slave(); + if (thread_count) sleep(2); // Give threads time to die From c954c09a1196386feb3ff3232c5016845b9f68f2 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Tue, 9 Aug 2005 11:21:45 +0300 Subject: [PATCH 050/230] Fixed test that failed on 32 bit systems --- mysql-test/r/heap.result | 4 ++-- mysql-test/t/heap.test | 1 + sql/ha_innodb.cc | 15 ++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 4725ff6b814..969cb06e9fe 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -705,6 +705,6 @@ create table t1 (c char(10)) engine=memory; create table t2 (c varchar(10)) engine=memory; show table status like 't_'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 11 0 720192 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 12 0 785664 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL drop table t1, t2; diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index 922bd4b9bf0..fcaa4c41ece 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -443,6 +443,7 @@ drop table t1; # create table t1 (c char(10)) engine=memory; create table t2 (c varchar(10)) engine=memory; +--replace_column 8 # show table status like 't_'; drop table t1, t2; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d5d79b51f60..d98222975c5 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2146,15 +2146,12 @@ innobase_close_connection( ut_a(trx); - if (trx->conc_state != TRX_NOT_STARTED) { - ut_print_timestamp(stderr); - - fprintf(stderr, -" InnoDB: Warning: MySQL is closing a connection\n" -"InnoDB: that has an active InnoDB transaction. We roll back that\n" -"InnoDB: transaction. %lu row modifications to roll back.\n", - (ulong)trx->undo_no.low); - } + if (trx->conc_state != TRX_NOT_STARTED && + global_system_variables.log_warnings) + sql_print_warning("MySQL is closing a connection that has an active " + "InnoDB transaction. %lu row modifications will " + "roll back.", + (ulong)trx->undo_no.low); innobase_rollback_trx(trx); From 9a29c1f49e7cd0a421e7b1aec22d85e5c5fc6279 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Tue, 9 Aug 2005 12:56:55 +0400 Subject: [PATCH 051/230] Fix after merging patch solving bug #10055 "Using stored function with information_schema causes empty result set" with main tree. --- sql/sp_head.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 3a386356335..eb671b5bcd0 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -929,7 +929,7 @@ sp_head::execute_procedure(THD *thd, List *args) we'll leave it here. */ if (!thd->in_sub_stmt) - close_thread_tables(thd, 0, 0, 0); + close_thread_tables(thd, 0, 0); DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str)); // The rest of the frame are local variables which are all IN. From b7474403d64ac63b5d677f604a0c0deae6e4e24d Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Tue, 9 Aug 2005 10:09:11 +0000 Subject: [PATCH 052/230] BUG#12228: Pre-review fixes: Fix coding style, handle the case when we're out of memory. --- sql/sp_cache.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 135000d1443..1763432f2bc 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -111,6 +111,11 @@ void sp_cache_clear(sp_cache **cp) sp_cache_insert() cp The cache to put routine into sp Routine to insert. + + TODO: Perhaps it will be more straightforward if in case we returned an + error from this function when we couldn't allocate sp_cache. (right + now failure to put routine into cache will cause a 'SP not found' + error to be reported at some later time) */ void sp_cache_insert(sp_cache **cp, sp_head *sp) @@ -124,11 +129,13 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp) pthread_mutex_lock(&Cversion_lock); // LOCK v= Cversion; pthread_mutex_unlock(&Cversion_lock); // UNLOCK - c->version= v; + if (c) + c->version= v; } if (c) { - DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, sp->m_qname.str)); + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + sp->m_qname.str)); c->insert(sp); if (*cp == NULL) *cp= c; From 083da3ecee010fc0deae65aba6d61da8cf8433d9 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Tue, 9 Aug 2005 15:29:33 +0300 Subject: [PATCH 053/230] Merged code. --- sql/sql_parse.cc | 51 +++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c1d4fae5253..685044fb79b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4060,8 +4060,8 @@ end_with_restore_list: name= thd->strdup(name); db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length); res= (result= lex->sphead->create(thd)); - switch (result) { - case SP_OK: + if (result == SP_OK) + { lex->unit.cleanup(); delete lex->sphead; lex->sphead= 0; @@ -4081,33 +4081,26 @@ end_with_restore_list: } #endif send_ok(thd); - break; - case SP_WRITE_ROW_FAILED: - my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name); - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - goto error; - case SP_NO_DB_ERROR: - my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str); - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - goto error; - case SP_BAD_IDENTIFIER: - my_error(ER_TOO_LONG_IDENT, MYF(0), name); - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - goto error; - case SP_BODY_TOO_LONG: - my_error(ER_TOO_LONG_BODY, MYF(0), name); - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - goto error; - default: - my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); + } + else + { + switch (result) { + case SP_WRITE_ROW_FAILED: + my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name); + break; + case SP_NO_DB_ERROR: + my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str); + break; + case SP_BAD_IDENTIFIER: + my_error(ER_TOO_LONG_IDENT, MYF(0), name); + break; + case SP_BODY_TOO_LONG: + my_error(ER_TOO_LONG_BODY, MYF(0), name); + break; + default: + my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); + break; + } lex->unit.cleanup(); delete lex->sphead; lex->sphead= 0; From 633e62bd778d04d7be8d954726f7737c12692905 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Tue, 9 Aug 2005 16:57:35 +0300 Subject: [PATCH 054/230] Added missing cast. --- mysys/my_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_init.c b/mysys/my_init.c index 410cb2e7ee7..abb1ad27f7b 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -395,7 +395,7 @@ static void netware_init() } /* Parse program name and change to base format */ - name= my_progname; + name= (char*) my_progname; for (; *name; name++) { if (*name == '\\') From 850f53bbf49fd00a55ee89837b0fd131bb6cc5a2 Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Tue, 9 Aug 2005 07:57:36 -0600 Subject: [PATCH 055/230] small corrections to the IM. --- server-tools/instance-manager/IMService.cpp | 12 ++++++------ server-tools/instance-manager/user_map.cc | 17 +++++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp index b6195d15603..a5070dcf0f6 100644 --- a/server-tools/instance-manager/IMService.cpp +++ b/server-tools/instance-manager/IMService.cpp @@ -44,24 +44,24 @@ int HandleServiceOptions(Options options) if (options.install_as_service) { if (winService.IsInstalled()) - log_info("Service is already installed\n"); + log_info("Service is already installed"); else if (winService.Install()) - log_info("Service installed successfully\n"); + log_info("Service installed successfully"); else { - log_info("Service failed to install\n"); + log_info("Service failed to install"); ret_val= -1; } } else if (options.remove_service) { if (! winService.IsInstalled()) - log_info("Service is not installed\n"); + log_info("Service is not installed"); else if (winService.Remove()) - log_info("Service removed successfully\n"); + log_info("Service removed successfully"); else { - log_info("Service failed to remove\n"); + log_info("Service failed to remove"); ret_val= -1; } } diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc index 1498f2fa947..7fce2f75e28 100644 --- a/server-tools/instance-manager/user_map.cc +++ b/server-tools/instance-manager/user_map.cc @@ -25,12 +25,6 @@ #include "log.h" -#ifdef __WIN__ -#define NEWLINE_LEN 2 -#else -#define NEWLINE_LEN 1 -#endif - struct User { char user[USERNAME_LENGTH + 1]; @@ -43,6 +37,7 @@ struct User int User::init(const char *line) { const char *name_begin, *name_end, *password; + int line_ending_len= 1; if (line[0] == '\'' || line[0] == '"') { @@ -64,8 +59,14 @@ int User::init(const char *line) if (user_length > USERNAME_LENGTH) goto err; - /* assume that newline characater is present */ - if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + NEWLINE_LEN) + /* + assume that newline characater is present + we support reading password files that end in \n or \r\n on + either platform. + */ + if (password[strlen(password)-2] == '\r') + line_ending_len= 2; + if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + line_ending_len) goto err; memcpy(user, name_begin, user_length); From 2a00611f9c3540c934b53f82573b7b10e5410e4e Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Tue, 9 Aug 2005 07:57:37 -0600 Subject: [PATCH 056/230] changes to IM that came from Petr and JimW's review. --- server-tools/instance-manager/IMService.cpp | 6 +- server-tools/instance-manager/mysqlmanager.cc | 15 ++-- server-tools/instance-manager/options.cc | 81 +++++++------------ 3 files changed, 40 insertions(+), 62 deletions(-) diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp index b6195d15603..4e53fe15ef4 100644 --- a/server-tools/instance-manager/IMService.cpp +++ b/server-tools/instance-manager/IMService.cpp @@ -50,7 +50,7 @@ int HandleServiceOptions(Options options) else { log_info("Service failed to install\n"); - ret_val= -1; + ret_val= 1; } } else if (options.remove_service) @@ -62,10 +62,10 @@ int HandleServiceOptions(Options options) else { log_info("Service failed to remove\n"); - ret_val= -1; + ret_val= 1; } } else - return (int)winService.Init(); + ret_val= winService.Init() ? 0 : 1; return ret_val; } diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index de80878e283..a1420a639cb 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -79,6 +79,7 @@ int HandleServiceOptions(Options options); int main(int argc, char *argv[]) { + int return_value= 1; init_environment(argv[0]); Options options; struct passwd *user_info; @@ -90,10 +91,7 @@ int main(int argc, char *argv[]) if ((user_info= check_user(options.user))) { if (set_user(options.user, user_info)) - { - options.cleanup(); goto err; - } } if (options.run_as_service) @@ -105,17 +103,18 @@ int main(int argc, char *argv[]) } #else #ifdef NDEBUG - return HandleServiceOptions(options); + return_value= HandleServiceOptions(options); + goto err; /* this is not always an error but we reuse the label */ #endif #endif manager(options); + return_value= 0; + +err: options.cleanup(); my_end(0); - return 0; -err: - my_end(0); - return 1; + return return_value; } /******************* Auxilary functions implementation **********************/ diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index a9d31457d98..118ea5b6374 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -30,18 +30,20 @@ #define QUOTE2(x) #x #define QUOTE(x) QUOTE2(x) -const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); -const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); #ifdef __WIN__ -char windows_config_file[FN_REFLEN]; - char Options::install_as_service; char Options::remove_service; +char windows_config_file[FN_REFLEN]; +char default_password_file_name[FN_REFLEN]; +char default_log_file_name[FN_REFLEN]; +const char *Options::config_file= windows_config_file; #else char Options::run_as_service; const char *Options::user= 0; /* No default value */ -#endif +const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); +const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE); +#endif const char *Options::log_file_name= default_log_file_name; const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); @@ -51,7 +53,7 @@ const char *Options::bind_address= 0; /* No default value */ uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL; uint Options::port_number= DEFAULT_PORT; /* just to declare */ -char **Options::saved_argv; +char **Options::saved_argv= NULL; /* List of options, accepted by the instance manager. @@ -262,30 +264,8 @@ int Options::load(int argc, char **argv) } #ifdef __WIN__ - setup_windows_defaults(*argv); - - /* - On Windows, there are two possibilities. Either we are given - a defaults file on the command line or we use the my.ini file - that is in our app dir - */ - if (Options::config_file == NULL) - { - char *filename; - static const char default_win_config_file_name[]= "\\my.ini"; - - if (!GetModuleFileName(NULL, windows_config_file, - sizeof(windows_config_file))) - goto err; - - filename= strrchr(windows_config_file, "\\"); - /* - Don't check for the overflow as strlen("\\my.ini") is less - then strlen("mysqlmanager") (the binary name) - */ - strcpy(filename, default_win_config_file_name); - Options::config_file= windows_config_file; - } + if (setup_windows_defaults()) + goto err; #endif /* config-file options are prepended to command-line ones */ @@ -305,33 +285,32 @@ err: void Options::cleanup() { /* free_defaults returns nothing */ - free_defaults(Options::saved_argv); -#ifdef __WIN__ - free((char*)default_password_file_name); -#endif + if (Options::saved_argv != NULL) + free_defaults(Options::saved_argv); } #ifdef __WIN__ -char* change_extension(const char *src, const char *newext) +void Options::setup_windows_defaults() { - char *dot= (char*)strrchr(src, '.'); - if (!dot) return (char*)src; + if (!GetModuleFileName(NULL, default_password_file_name, + sizeof(default_password_file_name))) + return -1; + char *filename = strstr(default_password_file_name, ".exe"); + strcpy(filename, ".passwd"); + + if (!GetModuleFileName(NULL, default_log_file_name, + sizeof(default_log_file_name))) + return -1; + filename = strstr(default_log_file_name, ".exe"); + strcpy(filename, ".log"); - int newlen= dot-src+strlen(newext)+1; - char *temp= (char*)malloc(newlen); - bzero(temp, newlen); - strncpy(temp, src, dot-src+1); - strcat(temp, newext); - return temp; -} - -void Options::setup_windows_defaults(const char *progname) -{ - Options::password_file_name= default_password_file_name= - change_extension(progname, "passwd"); - Options::log_file_name= default_log_file_name= - change_extension(progname, "log"); + if (!GetModuleFileName(NULL, windows_config_file, + sizeof(windows_config_file))) + return -1; + char *slash = strrchr(windows_config_file, '\\'); + strcpy(slash, "\\my.ini"); + return 0; } #endif From 7fa1779d62400e9b7091ffa10b993f20159e1dda Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Tue, 9 Aug 2005 07:57:38 -0600 Subject: [PATCH 057/230] fixed assignments to meet server coding guidelines --- server-tools/instance-manager/options.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index 118ea5b6374..fac399eacb2 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -296,19 +296,19 @@ void Options::setup_windows_defaults() if (!GetModuleFileName(NULL, default_password_file_name, sizeof(default_password_file_name))) return -1; - char *filename = strstr(default_password_file_name, ".exe"); + char *filename= strstr(default_password_file_name, ".exe"); strcpy(filename, ".passwd"); if (!GetModuleFileName(NULL, default_log_file_name, sizeof(default_log_file_name))) return -1; - filename = strstr(default_log_file_name, ".exe"); + filename= strstr(default_log_file_name, ".exe"); strcpy(filename, ".log"); if (!GetModuleFileName(NULL, windows_config_file, sizeof(windows_config_file))) return -1; - char *slash = strrchr(windows_config_file, '\\'); + char *slash= strrchr(windows_config_file, '\\'); strcpy(slash, "\\my.ini"); return 0; } From 88ebfb5bc69ddeb52f56f2ca8787482a3bd78dee Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Tue, 9 Aug 2005 07:57:39 -0600 Subject: [PATCH 058/230] removing trailing spaces --- server-tools/instance-manager/user_map.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc index 7fce2f75e28..4e47127bba1 100644 --- a/server-tools/instance-manager/user_map.cc +++ b/server-tools/instance-manager/user_map.cc @@ -59,9 +59,9 @@ int User::init(const char *line) if (user_length > USERNAME_LENGTH) goto err; - /* - assume that newline characater is present - we support reading password files that end in \n or \r\n on + /* + assume that newline characater is present + we support reading password files that end in \n or \r\n on either platform. */ if (password[strlen(password)-2] == '\r') From 153ad3f687c6e92b64e4a5d041d961fe685353ca Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Tue, 9 Aug 2005 07:57:40 -0600 Subject: [PATCH 059/230] changes to IM code that came from Petr's review --- server-tools/instance-manager/IMService.cpp | 2 +- server-tools/instance-manager/options.cc | 10 +++++----- server-tools/instance-manager/options.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp index 4e53fe15ef4..428667d51fd 100644 --- a/server-tools/instance-manager/IMService.cpp +++ b/server-tools/instance-manager/IMService.cpp @@ -66,6 +66,6 @@ int HandleServiceOptions(Options options) } } else - ret_val= winService.Init() ? 0 : 1; + ret_val= !winService.Init(); return ret_val; } diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index fac399eacb2..6fd11471fc6 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -291,23 +291,23 @@ void Options::cleanup() #ifdef __WIN__ -void Options::setup_windows_defaults() +int Options::setup_windows_defaults() { if (!GetModuleFileName(NULL, default_password_file_name, sizeof(default_password_file_name))) - return -1; + return 1; char *filename= strstr(default_password_file_name, ".exe"); strcpy(filename, ".passwd"); - + if (!GetModuleFileName(NULL, default_log_file_name, sizeof(default_log_file_name))) - return -1; + return 1; filename= strstr(default_log_file_name, ".exe"); strcpy(filename, ".log"); if (!GetModuleFileName(NULL, windows_config_file, sizeof(windows_config_file))) - return -1; + return 1; char *slash= strrchr(windows_config_file, '\\'); strcpy(slash, "\\my.ini"); return 0; diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h index 537316fedfc..5cc14e7ee7f 100644 --- a/server-tools/instance-manager/options.h +++ b/server-tools/instance-manager/options.h @@ -52,7 +52,7 @@ struct Options int load(int argc, char **argv); void cleanup(); #ifdef __WIN__ - void setup_windows_defaults(const char *progname); + int setup_windows_defaults(const char *progname); #endif }; From 2a025ffbebfbe7ee9cdf90ba5a1a317818c32fdb Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 9 Aug 2005 22:05:07 +0400 Subject: [PATCH 060/230] Fix bug #12340 Wrong comparison in ha_innobase::cmp_ref() When PRIMARY KEY is present ha_innobase::cmp_ref() uses it to compare refs. After comparing part of key it moves pointers to compare next part. For varchar parts pointers were moved only by length of parts, not including bytes containig part length itself. This results in wrong comparision and wrong number of deleted records. --- mysql-test/r/innodb.result | 8 ++++++++ mysql-test/t/innodb.test | 10 ++++++++++ sql/ha_innodb.cc | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 2bdec5125dd..e0b477ab543 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -2475,3 +2475,11 @@ SELECT GRADE FROM t1 WHERE GRADE= 151; GRADE 151 DROP TABLE t1; +create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb; +create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb; +insert into t2 values ('aa','cc'); +insert into t1 values ('aa','bb'),('aa','cc'); +delete t1 from t1,t2 where f1=f3 and f4='cc'; +select * from t1; +f1 f2 +drop table t1,t2; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 05f47f36e42..0ec7faa8ade 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1394,3 +1394,13 @@ SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; SELECT GRADE FROM t1 WHERE GRADE= 151; DROP TABLE t1; +# +# Bug #12340 multitable delete deletes only one record +# +create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb; +create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb; +insert into t2 values ('aa','cc'); +insert into t1 values ('aa','bb'),('aa','cc'); +delete t1 from t1,t2 where f1=f3 and f4='cc'; +select * from t1; +drop table t1,t2; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d98222975c5..026bc0da13d 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -6852,8 +6852,8 @@ ha_innobase::cmp_ref( return(result); } - ref1 += key_part->length; - ref2 += key_part->length; + ref1 += key_part->store_length; + ref2 += key_part->store_length; } return(0); From 03060be40f7d0de0c4f9aa802903dee572dc5539 Mon Sep 17 00:00:00 2001 From: "reggie@monster." <> Date: Tue, 9 Aug 2005 14:48:43 -0500 Subject: [PATCH 061/230] Some changes to project files str_alloc had been added but was not added to mysqlclient and strings libmysql should have had strings as a dependent. --- VC++Files/client/mysqlclient.vcproj | 3 +++ VC++Files/mysql.sln | 1 + VC++Files/strings/strings.vcproj | 3 +++ 3 files changed, 7 insertions(+) diff --git a/VC++Files/client/mysqlclient.vcproj b/VC++Files/client/mysqlclient.vcproj index 8e01db86c70..eebba9ebe0e 100755 --- a/VC++Files/client/mysqlclient.vcproj +++ b/VC++Files/client/mysqlclient.vcproj @@ -2730,6 +2730,9 @@ PreprocessorDefinitions=""/> + + + + Date: Wed, 10 Aug 2005 00:23:56 +0400 Subject: [PATCH 062/230] Clumsy but working fix for bug #11973 "SELECT .. INTO var_name; in trigger cause crash on update". Let us update "thd" pointer in LEX, all its units and in LEX::result before executing statement in trigger body, since triggers are associated with TABLE object and because of this can be used in different threads. --- mysql-test/r/trigger.result | 13 +++++++++++++ mysql-test/t/trigger.test | 23 +++++++++++++++++++++++ sql/item_subselect.cc | 8 ++++++++ sql/item_subselect.h | 7 +++++-- sql/sql_class.h | 7 +++---- sql/sql_delete.cc | 5 ++--- sql/sql_lex.h | 1 + sql/sql_parse.cc | 2 +- sql/sql_prepare.cc | 11 +++++++++++ sql/sql_update.cc | 6 +++--- 10 files changed, 70 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 52bf307a686..99abfc6db96 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -635,3 +635,16 @@ show triggers; Trigger Event Table Statement Timing Created sql_mode t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # drop table t1; +create table t1 (id int, data int, username varchar(16)); +insert into t1 (id, data) values (1, 0); +create trigger t1_whoupdated before update on t1 for each row +begin +declare user varchar(32); +declare i int; +select user() into user; +set NEW.username = user; +select count(*) from ((select 1) union (select 2)) as d1 into i; +end| +update t1 set data = 1; +update t1 set data = 2; +drop table t1; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 7bf8b1a4e2b..3d5d3448a1b 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -642,3 +642,26 @@ show create table t1; --replace_column 6 # show triggers; drop table t1; + +# Test for bug #11973 "SELECT .. INTO var_name; in trigger cause +# crash on update" +create table t1 (id int, data int, username varchar(16)); +insert into t1 (id, data) values (1, 0); +delimiter |; +create trigger t1_whoupdated before update on t1 for each row +begin + declare user varchar(32); + declare i int; + select user() into user; + set NEW.username = user; + select count(*) from ((select 1) union (select 2)) as d1 into i; +end| +delimiter ;| +update t1 set data = 1; + +connect (addconroot, localhost, root,,); +connection addconroot; +update t1 set data = 2; + +connection default; +drop table t1; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index ad1c9977e5b..3cc75242ccb 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1271,6 +1271,14 @@ void Item_allany_subselect::print(String *str) } +void subselect_engine::set_thd(THD *thd_arg) +{ + thd= thd_arg; + if (result) + result->set_thd(thd_arg); +} + + subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, select_subselect *result, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0b5736169fa..46623f76170 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -299,8 +299,11 @@ public: virtual ~subselect_engine() {}; // to satisfy compiler virtual void cleanup()= 0; - // set_thd should be called before prepare() - void set_thd(THD *thd_arg) { thd= thd_arg; } + /* + Also sets "thd" for subselect_engine::result. + Should be called before prepare(). + */ + void set_thd(THD *thd_arg); THD * get_thd() { return thd; } virtual int prepare()= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index ad4f38946a3..5e796c7297f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1560,6 +1560,7 @@ public: statement/stored procedure. */ virtual void cleanup(); + void set_thd(THD *thd_arg) { thd= thd_arg; } }; @@ -1915,14 +1916,13 @@ class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; - THD *thd; ha_rows deleted, found; uint num_of_tables; int error; bool do_delete, transactional_tables, normal_tables, delete_while_scanning; public: - multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); + multi_delete(TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &items); @@ -1938,7 +1938,6 @@ class multi_update :public select_result_interceptor TABLE_LIST *all_tables; /* query/update command tables */ TABLE_LIST *leaves; /* list of leves of join table tree */ TABLE_LIST *update_tables, *table_being_updated; - THD *thd; TABLE **tmp_tables, *main_table, *table_to_update; TMP_TABLE_PARAM *tmp_table_param; ha_rows updated, found; @@ -1950,7 +1949,7 @@ class multi_update :public select_result_interceptor bool do_update, trans_safe, transactional_tables, ignore; public: - multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list, + multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list, List *fields, List *values, enum_duplicates handle_duplicates, bool ignore); ~multi_update(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d83937098e2..b6183bf5acb 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -407,9 +407,8 @@ bool mysql_multi_delete_prepare(THD *thd) } -multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, - uint num_of_tables_arg) - : delete_tables(dt), thd(thd_arg), deleted(0), found(0), +multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) + : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), do_delete(0), transactional_tables(0), normal_tables(0) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4bba0c432c7..e8c65ba5100 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -458,6 +458,7 @@ public: inline bool is_prepared() { return prepared; } bool change_result(select_subselect *result, select_subselect *old_result); void set_limit(st_select_lex *values); + void set_thd(THD *thd_arg) { thd= thd_arg; } friend void lex_start(THD *thd, uchar *buf, uint length); friend int subselect_union_engine::exec(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 677b3a98174..265c6e1d60d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3318,7 +3318,7 @@ end_with_restore_list: if ((res= mysql_multi_delete_prepare(thd))) goto error; - if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, + if (!thd->is_fatal_error && (result= new multi_delete(aux_tables, lex->table_count))) { res= mysql_select(thd, &select_lex->ref_pointer_array, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 18707cc6c87..3b0efd75426 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1850,6 +1850,13 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) SELECT_LEX *sl= lex->all_selects_list; DBUG_ENTER("reinit_stmt_before_use"); + /* + We have to update "thd" pointer in LEX, all its units and in LEX::result, + since statements which belong to trigger body are associated with TABLE + object and because of this can be used in different threads. + */ + lex->thd= thd; + if (lex->empty_field_list_on_rset) { lex->empty_field_list_on_rset= 0; @@ -1888,6 +1895,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) unit->types.empty(); /* for derived tables & PS (which can't be reset by Item_subquery) */ unit->reinit_exec_mechanism(); + unit->set_thd(thd); } } @@ -1926,7 +1934,10 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) lex->select_lex.leaf_tables= lex->leaf_tables_insert; if (lex->result) + { lex->result->cleanup(); + lex->result->set_thd(thd); + } DBUG_VOID_RETURN; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8a5b4ad8eae..cc7dff50551 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -820,7 +820,7 @@ bool mysql_multi_update(THD *thd, if (mysql_multi_update_prepare(thd)) DBUG_RETURN(TRUE); - if (!(result= new multi_update(thd, table_list, + if (!(result= new multi_update(table_list, thd->lex->select_lex.leaf_tables, fields, values, handle_duplicates, ignore))) @@ -846,13 +846,13 @@ bool mysql_multi_update(THD *thd, } -multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, +multi_update::multi_update(TABLE_LIST *table_list, TABLE_LIST *leaves_list, List *field_list, List *value_list, enum enum_duplicates handle_duplicates_arg, bool ignore_arg) :all_tables(table_list), leaves(leaves_list), update_tables(0), - thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list), + tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), transactional_tables(1), ignore(ignore_arg) From 194360397c1c174884dcec02704a9bc820fa96dc Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Tue, 9 Aug 2005 18:02:36 -0700 Subject: [PATCH 063/230] Rename rest() macro in my_list.h to list_rest(). (Bug #12327) --- include/my_list.h | 2 +- mysys/list.c | 2 +- mysys/thr_lock.c | 3 ++- sql/sql_test.cc | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/my_list.h b/include/my_list.h index f786621e311..92598696fc4 100644 --- a/include/my_list.h +++ b/include/my_list.h @@ -36,7 +36,7 @@ extern void list_free(LIST *root,unsigned int free_data); extern unsigned int list_length(LIST *); extern int list_walk(LIST *,list_walk_action action,gptr argument); -#define rest(a) ((a)->next) +#define list_rest(a) ((a)->next) #define list_push(a,b) (a)=list_cons((b),(a)) #define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old) ; my_free((gptr) old,MYF(MY_FAE)); } diff --git a/mysys/list.c b/mysys/list.c index 64fca10dc0b..480c1080a45 100644 --- a/mysys/list.c +++ b/mysys/list.c @@ -109,7 +109,7 @@ int list_walk(LIST *list, list_walk_action action, gptr argument) { if ((error = (*action)(list->data,argument))) return error; - list=rest(list); + list=list_rest(list); } return 0; } diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index dc4959f23c1..d6443539216 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -1127,7 +1127,8 @@ void thr_print_locks(void) pthread_mutex_lock(&THR_LOCK_lock); puts("Current locks:"); - for (list=thr_lock_thread_list ; list && count++ < MAX_THREADS ; list=rest(list)) + for (list= thr_lock_thread_list; list && count++ < MAX_THREADS; + list= list_rest(list)) { THR_LOCK *lock=(THR_LOCK*) list->data; VOID(pthread_mutex_lock(&lock->mutex)); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index d992c93f8fc..8af7903a910 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -271,7 +271,7 @@ static void display_table_locks(void) VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50)); VOID(pthread_mutex_lock(&THR_LOCK_lock)); - for (list=thr_lock_thread_list ; list ; list=rest(list)) + for (list= thr_lock_thread_list; list; list= list_rest(list)) { THR_LOCK *lock=(THR_LOCK*) list->data; From 51537c057d3c42957c567598016b0ea353b7acdb Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Wed, 10 Aug 2005 10:31:32 +0400 Subject: [PATCH 064/230] Fix for bug #12280 "Triggers: crash if flush tables". We should not allow FLUSH statement to be executed inside both triggers and stored functions. --- mysql-test/r/sp-error.result | 4 ++-- mysql-test/r/trigger.result | 16 ++++++++++++++++ mysql-test/t/sp-error.test | 4 ++-- mysql-test/t/trigger.test | 20 ++++++++++++++++++++ sql/share/errmsg.txt | 4 ++-- sql/sql_parse.cc | 7 +++++++ sql/sql_yacc.yy | 11 ++++++++--- 7 files changed, 57 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 13f46e507ba..bd383379abc 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -247,7 +247,7 @@ end| ERROR 42000: Duplicate cursor: c create procedure u() use sptmp| -ERROR 42000: USE is not allowed in a stored procedure +ERROR 0A000: USE is not allowed in stored procedures create procedure p() begin declare c cursor for select * from t1; @@ -616,7 +616,7 @@ begin flush tables; return 5; end| -ERROR 0A000: FLUSH is not allowed in stored procedures +ERROR 0A000: FLUSH is not allowed in stored function or trigger create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123() begin end| diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 52bf307a686..284e4c1556b 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -2,6 +2,7 @@ drop table if exists t1, t2, t3; drop view if exists v1; drop database if exists mysqltest; drop function if exists f1; +drop procedure if exists p1; create table t1 (i int); create trigger trg before insert on t1 for each row set @a:=1; set @a:=0; @@ -635,3 +636,18 @@ show triggers; Trigger Event Table Statement Timing Created sql_mode t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # drop table t1; +create table t1 (id int); +create trigger t1_ai after insert on t1 for each row flush tables; +ERROR 0A000: FLUSH is not allowed in stored function or trigger +create trigger t1_ai after insert on t1 for each row flush privileges; +ERROR 0A000: FLUSH is not allowed in stored function or trigger +create procedure p1() flush tables; +create trigger t1_ai after insert on t1 for each row call p1(); +insert into t1 values (0); +ERROR 0A000: FLUSH is not allowed in stored function or trigger +drop procedure p1; +create procedure p1() flush privileges; +insert into t1 values (0); +ERROR 0A000: FLUSH is not allowed in stored function or trigger +drop procedure p1; +drop table t1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 7f567449311..349bd148814 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -334,7 +334,7 @@ begin end| # USE is not allowed ---error 1336 +--error ER_SP_BADSTATEMENT create procedure u() use sptmp| @@ -885,7 +885,7 @@ create procedure bug10537() --disable_warnings drop function if exists bug8409| --enable_warnings ---error ER_SP_BADSTATEMENT +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function bug8409() returns int begin diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 7bf8b1a4e2b..789405696c2 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -7,6 +7,7 @@ drop table if exists t1, t2, t3; drop view if exists v1; drop database if exists mysqltest; drop function if exists f1; +drop procedure if exists p1; --enable_warnings create table t1 (i int); @@ -642,3 +643,22 @@ show create table t1; --replace_column 6 # show triggers; drop table t1; + +# Test for bug #12280 "Triggers: crash if flush tables" +# FLUSH TABLES and FLUSH PRIVILEGES should be disallowed inside +# of functions and triggers. +create table t1 (id int); +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +create trigger t1_ai after insert on t1 for each row flush tables; +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +create trigger t1_ai after insert on t1 for each row flush privileges; +create procedure p1() flush tables; +create trigger t1_ai after insert on t1 for each row call p1(); +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +insert into t1 values (0); +drop procedure p1; +create procedure p1() flush privileges; +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +insert into t1 values (0); +drop procedure p1; +drop table t1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5dd5cd9c775..dd9cbd8d500 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5137,8 +5137,8 @@ ER_SP_CANT_ALTER eng "Failed to ALTER %s %s" ER_SP_SUBSELECT_NYI 0A000 eng "Subselect value not supported" -ER_SP_NO_USE 42000 - eng "USE is not allowed in a stored procedure" +ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 0A000 + eng "%s is not allowed in stored function or trigger" ER_SP_VARCOND_AFTER_CURSHNDLR 42000 eng "Variable or condition declaration after cursor or handler declaration" ER_SP_CURSOR_AFTER_HANDLER 42000 diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 677b3a98174..885bf63cb2d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6395,6 +6395,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, bool result=0; select_errors=0; /* Write if more errors */ bool tmp_write_to_binlog= 1; + + if (thd->in_sub_stmt) + { + my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH"); + return 1; + } + #ifndef NO_EMBEDDED_ACCESS_CHECKS if (options & REFRESH_GRANT) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b680787b9a3..849987a267c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1960,7 +1960,7 @@ sp_proc_stmt: } if (lex->sql_command == SQLCOM_CHANGE_DB) { /* "USE db" doesn't work in a procedure */ - my_message(ER_SP_NO_USE, ER(ER_SP_NO_USE), MYF(0)); + my_error(ER_SP_BADSTATEMENT, MYF(0), "USE"); YYABORT; } /* @@ -6642,9 +6642,14 @@ flush: FLUSH_SYM opt_no_write_to_binlog { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_FUNCTION) + if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) { - my_error(ER_SP_BADSTATEMENT, MYF(0), "FLUSH"); + /* + Note that both FLUSH TABLES and FLUSH PRIVILEGES will break + execution in prelocked mode. So it is better to disable + FLUSH in stored functions and triggers completely. + */ + my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH"); YYABORT; } lex->sql_command= SQLCOM_FLUSH; lex->type=0; From 7ccf9b970839a25e92e2e8e9ce85c5efa4a38f65 Mon Sep 17 00:00:00 2001 From: "mskold@mysql.com" <> Date: Wed, 10 Aug 2005 09:38:36 +0200 Subject: [PATCH 065/230] Added support for ha_ndbcluster::info(HA_STATUS_AUTO) --- sql/ha_ndbcluster.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index e14d4b13311..ac99506bb79 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2826,7 +2826,16 @@ void ha_ndbcluster::info(uint flag) errkey= m_dupkey; } if (flag & HA_STATUS_AUTO) + { DBUG_PRINT("info", ("HA_STATUS_AUTO")); + if (m_table) + { + Ndb *ndb= get_ndb(); + + auto_increment_value= + ndb->readAutoIncrementValue((const NDBTAB *) m_table); + } + } DBUG_VOID_RETURN; } From f6306a8db10a17d5ad560b8e53b0ec3d425bb977 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 10 Aug 2005 12:25:26 +0400 Subject: [PATCH 066/230] A fix for Bug#11901 "mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY join in subqry order by server crash": failing DBUG_ASSERT(curr_join == this) when opening a cursor. Ensure that for top-level join curr_join == join (always), and thus fix the failing assert. curr_join is a hack to ensure that uncacheable subqueries can be re-evaluated safely, and should be never different from main join in case of top-level join. --- sql/sql_select.cc | 9 ++- sql/sql_select.h | 5 ++ tests/mysql_client_test.c | 123 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fb0407e1405..630406dba07 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1090,9 +1090,10 @@ JOIN::optimize() order=0; } } - - if (thd->lex->subqueries) + + if (select_lex->uncacheable && !is_top_level_join()) { + /* If this join belongs to an uncacheable subquery */ if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN)))) DBUG_RETURN(-1); error= 0; // Ensure that tmp_join.error= 0 @@ -1636,9 +1637,7 @@ JOIN::exec() curr_join->fields= curr_fields_list; curr_join->procedure= procedure; - if (unit == &thd->lex->unit && - (unit->fake_select_lex == 0 || select_lex == unit->fake_select_lex) && - thd->cursor && tables != const_tables) + if (is_top_level_join() && thd->cursor && tables != const_tables) { /* We are here if this is JOIN::exec for the last select of the main unit diff --git a/sql/sql_select.h b/sql/sql_select.h index c950444e1c6..3b9a3093682 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -366,6 +366,11 @@ class JOIN :public Sql_alloc !group_list); } bool change_result(select_result *result); + bool is_top_level_join() const + { + return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 || + select_lex == unit->fake_select_lex)); + } }; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 5e6de152f40..fad36bf8c38 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14051,6 +14051,128 @@ static void test_bug11909() myquery(rc); } +/* Cursors: opening a cursor to a compilicated query with ORDER BY */ + +static void test_bug11901() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[2]; + int rc; + char workdept[20]; + ulong workdept_len; + uint32 empno; + const char *stmt_text; + + myheader("test_bug11901"); + + stmt_text= "drop table if exists t1, t2"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (" + " empno int(11) not null, firstname varchar(20) not null," + " midinit varchar(20) not null, lastname varchar(20) not null," + " workdept varchar(6) not null, salary double not null," + " bonus float not null, primary key (empno), " + " unique key (workdept, empno) " + ") default charset=latin1 collate=latin1_bin"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "insert into t1 values " + "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000)," + "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800), " + "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800), " + "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), " + "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500), " + "(70, 'EVA', 'D', 'PULASKI', 'D21', 36170, 700), " + "(90, 'EILEEN', 'W', 'HENDERSON', 'E11', 29750, 600), " + "(100, 'THEODORE', 'Q', 'SPENSER', 'E21', 26150, 500), " + "(110, 'VINCENZO', 'G', 'LUCCHESSI', 'A00', 46500, 900), " + "(120, 'SEAN', '', 'O\\'CONNELL', 'A00', 29250, 600), " + "(130, 'DOLORES', 'M', 'QUINTANA', 'C01', 23800, 500), " + "(140, 'HEATHER', 'A', 'NICHOLLS', 'C01', 28420, 600), " + "(150, 'BRUCE', '', 'ADAMSON', 'D11', 25280, 500), " + "(160, 'ELIZABETH', 'R', 'PIANKA', 'D11', 22250, 400), " + "(170, 'MASATOSHI', 'J', 'YOSHIMURA', 'D11', 24680, 500), " + "(180, 'MARILYN', 'S', 'SCOUTTEN', 'D11', 21340, 500), " + "(190, 'JAMES', 'H', 'WALKER', 'D11', 20450, 400), " + "(200, 'DAVID', '', 'BROWN', 'D11', 27740, 600), " + "(210, 'WILLIAM', 'T', 'JONES', 'D11', 18270, 400), " + "(220, 'JENNIFER', 'K', 'LUTZ', 'D11', 29840, 600), " + "(230, 'JAMES', 'J', 'JEFFERSON', 'D21', 22180, 400), " + "(240, 'SALVATORE', 'M', 'MARINO', 'D21', 28760, 600), " + "(250, 'DANIEL', 'S', 'SMITH', 'D21', 19180, 400), " + "(260, 'SYBIL', 'P', 'JOHNSON', 'D21', 17250, 300), " + "(270, 'MARIA', 'L', 'PEREZ', 'D21', 27380, 500), " + "(280, 'ETHEL', 'R', 'SCHNEIDER', 'E11', 26250, 500), " + "(290, 'JOHN', 'R', 'PARKER', 'E11', 15340, 300), " + "(300, 'PHILIP', 'X', 'SMITH', 'E11', 17750, 400), " + "(310, 'MAUDE', 'F', 'SETRIGHT', 'E11', 15900, 300), " + "(320, 'RAMLAL', 'V', 'MEHTA', 'E21', 19950, 400), " + "(330, 'WING', '', 'LEE', 'E21', 25370, 500), " + "(340, 'JASON', 'R', 'GOUNOT', 'E21', 23840, 500)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t2 (" + " deptno varchar(6) not null, deptname varchar(20) not null," + " mgrno int(11) not null, location varchar(20) not null," + " admrdept varchar(6) not null, refcntd int(11) not null," + " refcntu int(11) not null, primary key (deptno)" + ") default charset=latin1 collate=latin1_bin"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "insert into t2 values " + "('A00', 'SPIFFY COMPUTER SERV', 10, '', 'A00', 0, 0), " + "('B01', 'PLANNING', 20, '', 'A00', 0, 0), " + "('C01', 'INFORMATION CENTER', 30, '', 'A00', 0, 0), " + "('D01', 'DEVELOPMENT CENTER', 0, '', 'A00', 0, 0)," + "('D11', 'MANUFACTURING SYSTEM', 60, '', 'D01', 0, 0), " + "('D21', 'ADMINISTRATION SYSTE', 70, '', 'D01', 0, 0), " + "('E01', 'SUPPORT SERVICES', 50, '', 'A00', 0, 0), " + "('E11', 'OPERATIONS', 90, '', 'E01', 0, 0), " + "('E21', 'SOFTWARE SUPPORT', 100,'', 'E01', 0, 0)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* ****** Begin of trace ****** */ + + stmt= open_cursor("select t1.empno, t1.workdept " + "from (t1 left join t2 on t2.deptno = t1.workdept) " + "where t2.deptno in " + " (select t2.deptno " + " from (t1 left join t2 on t2.deptno = t1.workdept) " + " where t1.empno = ?) " + "order by 1"); + bzero(bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= &empno; + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void*) workdept; + bind[1].buffer_length= sizeof(workdept); + bind[1].length= &workdept_len; + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + empno= 10; + /* ERROR: next statement causes a server crash */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14298,6 +14420,7 @@ static struct my_tests_st my_tests[]= { { "test_bug10760", test_bug10760 }, { "test_bug12001", test_bug12001 }, { "test_bug11909", test_bug11909 }, + { "test_bug11901", test_bug11901 }, { 0, 0 } }; From 88b01808d9f999b118593dcc69781a14ce40f4ff Mon Sep 17 00:00:00 2001 From: "hf@deer.(none)" <> Date: Wed, 10 Aug 2005 16:02:36 +0500 Subject: [PATCH 067/230] error message fixed --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2cc8780b07a..bc5505bb790 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3638,7 +3638,7 @@ end_with_restore_list: if (!(res = mysql_create_function(thd, &lex->udf))) send_ok(thd); #else - net_printf_error(thd, ER_CANT_OPEN_LIBRARY, lex->udf.dl, 0, "feature disabled"); + my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled"); res= TRUE; #endif break; From baf0c9ad084a915f785b91608ecdf0e3f0122d30 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 10 Aug 2005 17:45:00 +0400 Subject: [PATCH 068/230] Fix bug #11864 non unique names are allowed in subquery Column names weren't checked for uniqueness for subqueries. Code for names uniqueness checking used for view creation moved into separate function named check_duplicate_names(). It's called on preparation of subqueries to check uniqueness of names. If duplicate names are found then error is raised. --- mysql-test/r/derived.result | 7 ++- mysql-test/r/select_safe.result | 2 +- mysql-test/t/derived.test | 11 +++- mysql-test/t/select_safe.test | 2 +- sql/sql_derived.cc | 5 ++ sql/sql_view.cc | 96 +++++++++++++++++++++++---------- sql/sql_view.h | 2 + 7 files changed, 92 insertions(+), 33 deletions(-) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index fd6a834c694..af0f190d917 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -111,7 +111,7 @@ a b 1 a 2 b 3 c -explain select * from (select * from t1,t2 where t1.a=t2.a) t1; +explain select * from (select t1.*, t2.a as t2a from t1,t2 where t1.a=t2.a) t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 2 DERIVED t2 system NULL NULL NULL NULL 1 @@ -363,3 +363,8 @@ a 3 3 drop table t1, t2, t3; +create table t1 (a int); +create table t2 (a int); +select * from (select * from t1,t2) foo; +ERROR 42S21: Duplicate column name 'a' +drop table t1,t2; diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index 5d458c40f34..feac9efcb13 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -84,7 +84,7 @@ set local max_join_size=8; select * from (select * from t1) x; ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; -select * from (select * from t1 a, t1 b) x; +select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select 1 union select 2 union select 3) x; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 8d51b4666e7..f52e12849e4 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -42,7 +42,7 @@ CREATE TABLE t2 (a int not null); insert into t2 values(1); select * from (select * from t1 where t1.a=(select a from t2 where t2.a=t1.a)) a; select * from (select * from t1 where t1.a=(select t2.a from t2 where t2.a=t1.a) union select t1.a, t1.b from t1) a; -explain select * from (select * from t1,t2 where t1.a=t2.a) t1; +explain select * from (select t1.*, t2.a as t2a from t1,t2 where t1.a=t2.a) t1; drop table t1, t2; create table t1(a int not null, t char(8), index(a)); disable_query_log; @@ -249,4 +249,13 @@ select * from t1 union distinct select * from t2 union all select * from t3; select * from (select * from t1 union distinct select * from t2 union all select * from t3) X; drop table t1, t2, t3; +# +# Bug #11864 non unique names are allowed in subquery +# +create table t1 (a int); +create table t2 (a int); +--error 1060 +select * from (select * from t1,t2) foo; +drop table t1,t2; + # End of 4.1 tests diff --git a/mysql-test/t/select_safe.test b/mysql-test/t/select_safe.test index 1da700c9adf..481779e76d7 100644 --- a/mysql-test/t/select_safe.test +++ b/mysql-test/t/select_safe.test @@ -78,7 +78,7 @@ select * from (select * from t1) x; set local max_join_size=1; --error 1104 -select * from (select * from t1 a, t1 b) x; +select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; set local max_join_size=1; --error 1104 diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index fc9d15e94c4..7b9191cd841 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -125,6 +125,11 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) if ((res= unit->prepare(thd, derived_result, 0, orig_table_list->alias))) goto exit; + if (check_duplicate_names(unit->types, 0)) + { + res= -1; + goto exit; + } derived_result->tmp_table_param.init(); derived_result->tmp_table_param.field_count= unit->types.elements; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index aedff648e5c..ecaab9db0cd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -94,6 +94,71 @@ static void make_unique_view_field_name(Item *target, target->set_name(buff, name_len, system_charset_info); } + +/* + Check if items with same names are present in list and possibly + generate unique names for them. + + SYNOPSIS + item_list list of Items which should be checked for duplicates + gen_unique_view_name flag: generate unique name or return with error when + duplicate names are found. + + DESCRIPTION + This function is used on view creation and preparation of derived tables. + It checks item_list for items with duplicate names. If it founds two + items with same name and conversion to unique names isn't allowed, or + names for both items are set by user - function fails. + Otherwise it generates unique name for one item with autogenerated name + using make_unique_view_field_name() + + RETURN VALUE + FALSE no duplicate names found, or they are converted to unique ones + TRUE duplicate names are found and they can't be converted or conversion + isn't allowed +*/ + +bool check_duplicate_names(List &item_list, bool gen_unique_view_name) +{ + DBUG_ENTER("check_duplicate_names"); + /* Test absence of duplicates names */ + { + Item *item; + List_iterator_fast it(item_list); + List_iterator_fast itc(item_list); + while ((item= it++)) + { + Item *check; + /* treat underlying fields like set by user names */ + if (item->real_item()->type() == Item::FIELD_ITEM) + item->is_autogenerated_name= FALSE; + itc.rewind(); + while ((check= itc++) && check != item) + { + if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) + { + if (!gen_unique_view_name) + { + my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + DBUG_RETURN(TRUE); + } + else if (item->is_autogenerated_name) + make_unique_view_field_name(item, item_list, item); + else if (check->is_autogenerated_name) + make_unique_view_field_name(check, item_list, item); + else + { + my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + DBUG_RETURN(TRUE); + } + } + } + } + } + DBUG_RETURN(FALSE); +} + + /* Creating/altering VIEW procedure @@ -308,35 +373,8 @@ bool mysql_create_view(THD *thd, } } - /* Test absence of duplicates names */ - { - Item *item; - List_iterator_fast it(select_lex->item_list); - List_iterator_fast itc(select_lex->item_list); - while ((item= it++)) - { - Item *check; - /* treat underlying fields like set by user names */ - if (item->real_item()->type() == Item::FIELD_ITEM) - item->is_autogenerated_name= FALSE; - itc.rewind(); - while ((check= itc++) && check != item) - { - if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) - { - if (item->is_autogenerated_name) - make_unique_view_field_name(item, select_lex->item_list, item); - else if (check->is_autogenerated_name) - make_unique_view_field_name(check, select_lex->item_list, item); - else - { - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); - DBUG_RETURN(TRUE); - } - } - } - } - } + if (check_duplicate_names(select_lex->item_list, 1)) + DBUG_RETURN(TRUE); #ifndef NO_EMBEDDED_ACCESS_CHECKS /* diff --git a/sql/sql_view.h b/sql/sql_view.h index 3246dbae383..9d961feb143 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -33,5 +33,7 @@ int view_checksum(THD *thd, TABLE_LIST *view); extern TYPELIB updatable_views_with_limit_typelib; +bool check_duplicate_names(List& item_list, bool gen_unique_view_names); + #define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL) From 3a73ef8a86d853700e42b9e936132d74e3c23ddf Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 10 Aug 2005 17:45:42 +0400 Subject: [PATCH 069/230] Fix coding style. --- tests/mysql_client_test.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index fad36bf8c38..15cba906f6b 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13893,10 +13893,10 @@ static void test_bug12001() MYSQL *mysql_local; MYSQL_RES *result; const char *query= "DROP TABLE IF EXISTS test_table;" - "CREATE TABLE test_table(id INT);" - "INSERT INTO test_table VALUES(10);" - "UPDATE test_table SET id=20 WHERE id=10;" - "SELECT * FROM test_table;" + "CREATE TABLE test_table(id INT);" + "INSERT INTO test_table VALUES(10);" + "UPDATE test_table SET id=20 WHERE id=10;" + "SELECT * FROM test_table;" "INSERT INTO non_existent_table VALUES(11);"; int rc, res; @@ -13911,7 +13911,9 @@ static void test_bug12001() /* Create connection that supports multi statements */ if (!mysql_real_connect(mysql_local, opt_host, opt_user, opt_password, current_db, opt_port, - opt_unix_socket, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS)) { + opt_unix_socket, CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS)) + { fprintf(stdout, "\n mysql_real_connect() failed"); exit(1); } @@ -13919,12 +13921,16 @@ static void test_bug12001() rc= mysql_query(mysql_local, query); myquery(rc); - do { - if (mysql_field_count(mysql_local) && (result= mysql_use_result(mysql_local))) { - mysql_free_result(result); + do + { + if (mysql_field_count(mysql_local) && + (result= mysql_use_result(mysql_local))) + { + mysql_free_result(result); } - } while (!(res= mysql_next_result(mysql_local))); - + } + while (!(res= mysql_next_result(mysql_local))); + rc= mysql_query(mysql_local, "DROP TABLE IF EXISTS test_table"); myquery(rc); From 8392a814af9c80c7c6b8c1a4819b278e43a7e93d Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 10 Aug 2005 18:36:13 +0400 Subject: [PATCH 070/230] A fix and a test case for Bug#12243 "MySQL Server crashes with 2 cursors (+ commit)" and Bug#11832 "Server crash with InnoDB + Cursors" See comments to the changed files. --- innobase/include/read0read.h | 3 ++ innobase/read/read0read.c | 9 ++++++ innobase/row/row0sel.c | 12 ------- sql/ha_innodb.cc | 9 ++++++ tests/mysql_client_test.c | 61 ++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/innobase/include/read0read.h b/innobase/include/read0read.h index b5edcefb544..7a91248cf7f 100644 --- a/innobase/include/read0read.h +++ b/innobase/include/read0read.h @@ -136,6 +136,9 @@ struct cursor_view_struct{ /* Memory heap for the cursor view */ read_view_t* read_view; /* Consistent read view of the cursor*/ + ulint n_mysql_tables_in_use; + /* number of Innobase tables used in the + processing of this cursor */ }; #ifndef UNIV_NONINL diff --git a/innobase/read/read0read.c b/innobase/read/read0read.c index 334f9a8a85a..dc1ae2f1a16 100644 --- a/innobase/read/read0read.c +++ b/innobase/read/read0read.c @@ -286,6 +286,11 @@ read_cursor_view_create_for_mysql( curview = (cursor_view_t*) mem_heap_alloc(heap, sizeof(cursor_view_t)); curview->heap = heap; + /* Drop cursor tables from consideration when evaluating the need of + auto-commit */ + curview->n_mysql_tables_in_use = cr_trx->n_mysql_tables_in_use; + cr_trx->n_mysql_tables_in_use = 0; + mutex_enter(&kernel_mutex); curview->read_view = read_view_create_low( @@ -360,6 +365,10 @@ read_cursor_view_close_for_mysql( ut_a(curview->read_view); ut_a(curview->heap); + /* Add cursor's tables to the global count of active tables that + belong to this transaction */ + trx->n_mysql_tables_in_use += curview->n_mysql_tables_in_use; + mutex_enter(&kernel_mutex); read_view_close(curview->read_view); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 15881cb8c5d..57689520bfb 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -3101,12 +3101,6 @@ row_search_for_mysql( "InnoDB: how you can resolve the problem.\n", prebuilt->table->name); - /* Restore a global read view back to a transaction. This - forces MySQL always to set a cursor view before fetch from - a cursor. */ - - trx->read_view = trx->global_read_view; - return(DB_ERROR); } @@ -4098,12 +4092,6 @@ normal_return: } func_exit: - /* Restore a global read view back to a transaction. This - forces MySQL always to set a cursor view before fetch from - a cursor. */ - - trx->read_view = trx->global_read_view; - trx->op_info = ""; if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 026bc0da13d..0a01c08c916 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2146,6 +2146,15 @@ innobase_close_connection( ut_a(trx); + if (trx->active_trans == 0 + && trx->conc_state != TRX_NOT_STARTED) { + + fprintf(stderr, +"InnoDB: Error: trx->active_trans == 0\n" +"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + } + + if (trx->conc_state != TRX_NOT_STARTED && global_system_variables.log_warnings) sql_print_warning("MySQL is closing a connection that has an active " diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 15cba906f6b..75f57436c38 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14179,6 +14179,66 @@ static void test_bug11901() myquery(rc); } +/* Bug#12243: multiple cursors, crash in a fetch after commit. */ + +static void test_bug12243() +{ + MYSQL_STMT *stmt1, *stmt2; + int rc; + const char *stmt_text; + ulong type; + + myheader("test_bug12243"); + + if (! have_innodb) + { + if (!opt_silent) + printf("This test requires InnoDB.\n"); + return; + } + + /* create tables */ + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int) engine=InnoDB"); + rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)"); + myquery(rc); + mysql_autocommit(mysql, FALSE); + /* create statement */ + stmt1= mysql_stmt_init(mysql); + stmt2= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + stmt_text= "select a from t1"; + + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text)); + check_execute(stmt2, rc); + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + rc= mysql_stmt_fetch(stmt2); + check_execute(stmt2, rc); + + rc= mysql_stmt_close(stmt1); + check_execute(stmt1, rc); + rc= mysql_commit(mysql); + myquery(rc); + rc= mysql_stmt_fetch(stmt2); + check_execute(stmt2, rc); + + mysql_stmt_close(stmt2); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + mysql_autocommit(mysql, TRUE); /* restore default */ +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14427,6 +14487,7 @@ static struct my_tests_st my_tests[]= { { "test_bug12001", test_bug12001 }, { "test_bug11909", test_bug11909 }, { "test_bug11901", test_bug11901 }, + { "test_bug12243", test_bug12243 }, { 0, 0 } }; From 1dff783854d165611beb35a14f7ee7c853903bd6 Mon Sep 17 00:00:00 2001 From: "bell@52.0.168.192.in-addr.arpa" <> Date: Wed, 10 Aug 2005 18:58:55 +0300 Subject: [PATCH 071/230] block using QC in case of having tables locked by LOCK... (BUG#12385) --- mysql-test/r/query_cache_noembeded.result | 18 +++++++++++++ mysql-test/t/query_cache_noembeded.test | 33 +++++++++++++++++++++++ sql/sql_cache.cc | 7 +++-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 mysql-test/r/query_cache_noembeded.result create mode 100644 mysql-test/t/query_cache_noembeded.test diff --git a/mysql-test/r/query_cache_noembeded.result b/mysql-test/r/query_cache_noembeded.result new file mode 100644 index 00000000000..f2b06eea45d --- /dev/null +++ b/mysql-test/r/query_cache_noembeded.result @@ -0,0 +1,18 @@ +set GLOBAL query_cache_size=1355776; +reset query cache; +flush status; +CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE = +MyISAM; +LOCK TABLE t1 READ LOCAL; +INSERT INTO t1 VALUES (), (), (); +SELECT * FROM t1; +a +SELECT * FROM t1; +a +1 +2 +3 +SELECT * FROM t1; +a +drop table t1; +set GLOBAL query_cache_size=default; diff --git a/mysql-test/t/query_cache_noembeded.test b/mysql-test/t/query_cache_noembeded.test new file mode 100644 index 00000000000..c909bfcdf3b --- /dev/null +++ b/mysql-test/t/query_cache_noembeded.test @@ -0,0 +1,33 @@ +-- source include/have_query_cache.inc +-- source include/not_embedded.inc + +# +# Tests with query cache +# +set GLOBAL query_cache_size=1355776; + +# Reset query cache variables. + +reset query cache; +flush status; + +# +# do not use QC if tables locked (BUG#12385) +# +connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root; +CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE = +MyISAM; +LOCK TABLE t1 READ LOCAL; +connect (root2,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root2; +INSERT INTO t1 VALUES (), (), (); +connection root; +SELECT * FROM t1; +connection root2; +SELECT * FROM t1; +connection root; +SELECT * FROM t1; +drop table t1; + +set GLOBAL query_cache_size=default; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index d729a6cc301..667b6e546d3 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -739,7 +739,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) TABLE_COUNTER_TYPE local_tables; ulong tot_length; DBUG_ENTER("Query_cache::store_query"); - if (query_cache_size == 0) + if (query_cache_size == 0 || thd->locked_tables) DBUG_VOID_RETURN; if ((local_tables= is_cacheable(thd, thd->query_length, @@ -750,7 +750,10 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size == 0) + { + STRUCT_UNLOCK(&structure_guard_mutex); DBUG_VOID_RETURN; + } DUMP(this); /* Key is query + database + flag */ @@ -874,7 +877,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) byte flags; DBUG_ENTER("Query_cache::send_result_to_client"); - if (query_cache_size == 0 || + if (query_cache_size == 0 || thd->locked_tables || /* it is not possible to check has_transactions() function of handler because tables not opened yet From afb43a6397a5979b6e6131761c7041958fe82801 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 10 Aug 2005 13:30:53 -0700 Subject: [PATCH 072/230] Fix rpl_openssl test to actually work. (Bug #12457, Bug #10860) --- mysql-test/r/rpl_openssl.result | 6 +++--- mysql-test/t/rpl_openssl.test | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/rpl_openssl.result b/mysql-test/r/rpl_openssl.result index a4ed922d9d4..d916e9f2c5c 100644 --- a/mysql-test/r/rpl_openssl.result +++ b/mysql-test/r/rpl_openssl.result @@ -4,7 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -grant replication slave on *.* to replssl@'%' require ssl; +grant replication slave on *.* to replssl@localhost require ssl; create table t1 (t int); stop slave; change master to master_user='replssl',master_password=''; @@ -20,11 +20,11 @@ t 1 show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 392 # # master-bin.000001 Yes Yes 0 0 392 # None 0 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem # +# 127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 398 # # master-bin.000001 Yes Yes 0 0 398 # None 0 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem # stop slave; change master to master_user='root',master_password='', master_ssl=0; start slave; drop table t1; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 468 # # master-bin.000001 Yes Yes 0 0 468 # None 0 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 474 # # master-bin.000001 Yes Yes 0 0 474 # None 0 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem # diff --git a/mysql-test/t/rpl_openssl.test b/mysql-test/t/rpl_openssl.test index 78731e4dc7d..e15eb9b179a 100644 --- a/mysql-test/t/rpl_openssl.test +++ b/mysql-test/t/rpl_openssl.test @@ -1,4 +1,4 @@ -source include/have_openssl_1.inc; +source include/have_openssl.inc; source include/master-slave.inc; # We don't test all types of ssl auth params here since it's a bit hard @@ -7,7 +7,7 @@ source include/master-slave.inc; # creating replication user for whom ssl auth is required # preparing playground connection master; -grant replication slave on *.* to replssl@'%' require ssl; +grant replication slave on *.* to replssl@localhost require ssl; create table t1 (t int); save_master_pos; From fbab5fc5685076a43f52f55a1633207709ef953c Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Wed, 10 Aug 2005 21:17:02 +0000 Subject: [PATCH 073/230] BUG#12228: Post review fixes: Added test case, code cleanup. --- mysql-test/r/sp-threads.result | 25 ++++++++++++++++++++ mysql-test/t/sp-threads.test | 43 ++++++++++++++++++++++++++++++++++ sql/sp_cache.cc | 10 +++----- sql/sp_cache.h | 2 +- sql/sql_parse.cc | 4 ++-- sql/sql_prepare.cc | 9 +++---- 6 files changed, 79 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result index 2f7e8021aa7..c516d7a643f 100644 --- a/mysql-test/r/sp-threads.result +++ b/mysql-test/r/sp-threads.result @@ -37,6 +37,7 @@ Id User Host db Command Time State Info # root localhost test Sleep # NULL # root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2 # root localhost test Query # NULL show processlist +# root localhost test Sleep # NULL unlock tables; drop procedure bug9486; drop table t1, t2; @@ -64,3 +65,27 @@ insert into t1 (select f from v1); drop function bug11554; drop table t1; drop view v1; +drop procedure if exists p1; +drop procedure if exists p2; +create table t1 (s1 int)| +create procedure p1() select * from t1| +create procedure p2() +begin +insert into t1 values (1); +call p1(); +select * from t1; +end| +use test; +lock table t1 write; + call p2(); +use test; +drop procedure p1; +create procedure p1() select * from t1; +unlock tables; +s1 +1 +s1 +1 +drop procedure p1; +drop procedure p2; +drop table t1; diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test index 4c192f3e96f..5e51c1034e0 100644 --- a/mysql-test/t/sp-threads.test +++ b/mysql-test/t/sp-threads.test @@ -5,6 +5,7 @@ connect (con1root,localhost,root,,); connect (con2root,localhost,root,,); +connect (con3root,localhost,root,,); connection con1root; use test; @@ -130,6 +131,48 @@ drop function bug11554; drop table t1; drop view v1; + +# BUG#12228 +--disable_warnings +drop procedure if exists p1; +drop procedure if exists p2; +--enable_warnings + +connection con1root; +delimiter |; +create table t1 (s1 int)| +create procedure p1() select * from t1| +create procedure p2() +begin + insert into t1 values (1); + call p1(); + select * from t1; +end| +delimiter ;| + +connection con2root; +use test; +lock table t1 write; + +connection con1root; +send call p2(); + +connection con3root; +use test; +drop procedure p1; +create procedure p1() select * from t1; + +connection con2root; +unlock tables; + +connection con1root; +# Crash will be here if we hit BUG#12228 +reap; + +drop procedure p1; +drop procedure p2; +drop table t1; + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 1763432f2bc..68e8dbb3252 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -122,19 +122,15 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp) { sp_cache *c= *cp; - if (! c) + if (!c && (c= new sp_cache())) { - ulong v; - c= new sp_cache(); pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; + c->version= Cversion; pthread_mutex_unlock(&Cversion_lock); // UNLOCK - if (c) - c->version= v; } if (c) { - DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, sp->m_qname.str)); c->insert(sp); if (*cp == NULL) diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 402647db9ea..1021d17b9e2 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -46,7 +46,7 @@ class sp_cache; sp_cache_insert(); sp_cache_invalidate(); - 2.2 When not holding any sp_head* pointers (at query end): + 2.2 When not holding any sp_head* pointers: sp_cache_flush_obsolete(); 3. Before thread exit: diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 00463dc0a3b..1a3f6f6f656 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5347,12 +5347,12 @@ void mysql_init_multi_delete(LEX *lex) void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); - sp_cache_flush_obsolete(&thd->sp_proc_cache); - sp_cache_flush_obsolete(&thd->sp_func_cache); mysql_init_query(thd, (uchar*) inBuf, length); if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex= thd->lex; + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); if (!yyparse((void *)thd) && ! thd->is_fatal_error) { #ifndef NO_EMBEDDED_ACCESS_CHECKS diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index f8b19dac3d1..4eb8c00ae16 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1730,8 +1730,6 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, DBUG_ENTER("mysql_stmt_prepare"); DBUG_PRINT("prep_query", ("%s", packet)); - sp_cache_flush_obsolete(&thd->sp_proc_cache); - sp_cache_flush_obsolete(&thd->sp_func_cache); /* If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql. @@ -1785,6 +1783,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, lex= thd->lex; lex->safe_to_cache_query= 0; + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); + error= yyparse((void *)thd) || thd->is_fatal_error || thd->net.report_error || init_param_array(stmt); /* @@ -1981,8 +1982,6 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_execute"); - sp_cache_flush_obsolete(&thd->sp_proc_cache); - sp_cache_flush_obsolete(&thd->sp_func_cache); packet+= 9; /* stmt_id + 5 bytes of flags */ statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); @@ -2063,6 +2062,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) thd->protocol= &thd->protocol_prep; // Switch to binary protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); mysql_execute_command(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); From 8c83f14b762bf0923727a7d4804b3ffb267f4428 Mon Sep 17 00:00:00 2001 From: "patg@radha.local" <> Date: Wed, 10 Aug 2005 23:37:17 +0200 Subject: [PATCH 074/230] BUG #12253. Fixed logic the prevented repair when "--fast" was included in invoking mysqlcheck. --- client/mysqlcheck.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 07f3f25b50c..ee99d359000 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -575,8 +575,13 @@ static void print_result() if (status) { + /* + if there was an error with the table, we have --auto-repair set, + and this isn't a repair op, then add the table to the tables4repair + list + */ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR && - (!opt_fast || strcmp(row[3],"OK"))) + strcmp(row[3],"OK")) insert_dynamic(&tables4repair, prev); found_error=0; if (opt_silent) @@ -595,8 +600,8 @@ static void print_result() strmov(prev, row[0]); putchar('\n'); } - if (found_error && opt_auto_repair && what_to_do != DO_REPAIR && - !opt_fast) + /* add the last table to be repaired to the list */ + if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) insert_dynamic(&tables4repair, prev); mysql_free_result(res); } From 078e0c39020bc809a0e6bede47693ecb828493fb Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 10 Aug 2005 18:32:17 -0700 Subject: [PATCH 075/230] Fix mysql_info() returning bad data in the results of a multi-statement query that mixed statements that do and do not return info. (Bug #11688) --- mysql-test/r/metadata.result | 11 +++++++++++ mysql-test/t/metadata.test | 12 ++++++++++++ sql-common/client.c | 5 +++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 8f25e6b7f4a..6297f9cdcb5 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -85,3 +85,14 @@ def aaa 1 1 8 20 1 N 32769 0 63 1 1 drop table t1; +create table t1 (i int); +insert into t1 values (1),(2),(3); +select * from t1 where i = 2; +drop table t1;// +affected rows: 0 +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +i +2 +affected rows: 1 +affected rows: 0 diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test index b4edd15f5ef..65338448555 100644 --- a/mysql-test/t/metadata.test +++ b/mysql-test/t/metadata.test @@ -49,4 +49,16 @@ drop table t1; --disable_metadata +# +# Bug #11688: Bad mysql_info() results in multi-results +# +--enable_info +delimiter //; +create table t1 (i int); +insert into t1 values (1),(2),(3); +select * from t1 where i = 2; +drop table t1;// +delimiter ;// +--disable_info + # End of 4.1 tests diff --git a/sql-common/client.c b/sql-common/client.c index 860db63c531..73e136f7366 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -713,8 +713,9 @@ void free_old_query(MYSQL *mysql) if (mysql->fields) free_root(&mysql->field_alloc,MYF(0)); init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */ - mysql->fields=0; - mysql->field_count=0; /* For API */ + mysql->fields= 0; + mysql->field_count= 0; /* For API */ + mysql->info= 0; DBUG_VOID_RETURN; } From 66a055b4d6e944dd3e8467b67743954000c72bba Mon Sep 17 00:00:00 2001 From: "bell@51.0.168.192.in-addr.arpa" <> Date: Thu, 11 Aug 2005 09:29:50 +0300 Subject: [PATCH 076/230] make the same filenames as in 4.1 --- ...uery_cache_noembeded.result => query_cache_notembedded.result} | 0 .../{query_cache_noembeded.test => query_cache_notembedded.test} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mysql-test/r/{query_cache_noembeded.result => query_cache_notembedded.result} (100%) rename mysql-test/t/{query_cache_noembeded.test => query_cache_notembedded.test} (100%) diff --git a/mysql-test/r/query_cache_noembeded.result b/mysql-test/r/query_cache_notembedded.result similarity index 100% rename from mysql-test/r/query_cache_noembeded.result rename to mysql-test/r/query_cache_notembedded.result diff --git a/mysql-test/t/query_cache_noembeded.test b/mysql-test/t/query_cache_notembedded.test similarity index 100% rename from mysql-test/t/query_cache_noembeded.test rename to mysql-test/t/query_cache_notembedded.test From 3b64651683a6f8d9276fd49843832f672312f880 Mon Sep 17 00:00:00 2001 From: "sanja@arthur.local" <> Date: Thu, 11 Aug 2005 13:07:08 +0300 Subject: [PATCH 077/230] query_cache_notembedded.test, query_cache_notembedded.result: postmerge fix --- mysql-test/r/query_cache_notembedded.result | 14 ++++++++++++++ mysql-test/t/query_cache_notembedded.test | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/mysql-test/r/query_cache_notembedded.result b/mysql-test/r/query_cache_notembedded.result index 16a397f78b6..e773a63525b 100644 --- a/mysql-test/r/query_cache_notembedded.result +++ b/mysql-test/r/query_cache_notembedded.result @@ -80,4 +80,18 @@ show status like "Qcache_free_blocks"; Variable_name Value Qcache_free_blocks 1 drop table t1, t2, t3, t11, t21; +CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE = +MyISAM; +LOCK TABLE t1 READ LOCAL; +INSERT INTO t1 VALUES (), (), (); +SELECT * FROM t1; +a +SELECT * FROM t1; +a +1 +2 +3 +SELECT * FROM t1; +a +drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/query_cache_notembedded.test b/mysql-test/t/query_cache_notembedded.test index d29dc10ccae..fd4785ffe95 100644 --- a/mysql-test/t/query_cache_notembedded.test +++ b/mysql-test/t/query_cache_notembedded.test @@ -78,4 +78,23 @@ show status like "Qcache_total_blocks"; show status like "Qcache_free_blocks"; drop table t1, t2, t3, t11, t21; +# +# do not use QC if tables locked (BUG#12385) +# +connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root; +CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE = +MyISAM; +LOCK TABLE t1 READ LOCAL; +connect (root2,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root2; +INSERT INTO t1 VALUES (), (), (); +connection root; +SELECT * FROM t1; +connection root2; +SELECT * FROM t1; +connection root; +SELECT * FROM t1; +drop table t1; + set GLOBAL query_cache_size=0; From fd4880814c69252f32becbb1e9eef56f10cdd116 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Thu, 11 Aug 2005 13:47:24 +0200 Subject: [PATCH 078/230] Makefile.am: config.cpp => ndb_config.cpp, solves link problems on case insensitive OS ndb_config.cpp: Rename: ndb/tools/config.cpp -> ndb/tools/ndb_config.cpp --- ndb/tools/Makefile.am | 2 +- ndb/tools/{config.cpp => ndb_config.cpp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ndb/tools/{config.cpp => ndb_config.cpp} (100%) diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 1f11122fb70..89830129576 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -32,7 +32,7 @@ ndb_restore_SOURCES = restore/restore_main.cpp \ restore/consumer_printer.cpp \ restore/Restore.cpp -ndb_config_SOURCES = config.cpp \ +ndb_config_SOURCES = ndb_config.cpp \ ../src/mgmsrv/Config.cpp \ ../src/mgmsrv/ConfigInfo.cpp \ ../src/mgmsrv/InitConfigFileParser.cpp diff --git a/ndb/tools/config.cpp b/ndb/tools/ndb_config.cpp similarity index 100% rename from ndb/tools/config.cpp rename to ndb/tools/ndb_config.cpp From 7b80e62528abfa3b6dd5eb4d94cc6cee27ad590d Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Thu, 11 Aug 2005 15:58:15 +0300 Subject: [PATCH 079/230] Cleanups during review of new code --- mysql-test/t/sp.test | 123 +++++++++++++------------ sql/lock.cc | 6 +- sql/mysqld.cc | 6 +- sql/sp_cache.cc | 53 ++++++----- sql/sp_head.cc | 214 ++++++++++++++++++++++++++----------------- sql/sql_base.cc | 3 +- sql/sql_parse.cc | 41 +++++---- 7 files changed, 251 insertions(+), 195 deletions(-) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 2cd8ccda90c..877be9607a9 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -2468,25 +2468,26 @@ drop table t3| # # BUG#4318 # -#QQ Don't know if HANDLER commands can work with SPs, or at all... -# -#create table t3 (s1 int)| -#insert into t3 values (3), (4)| -# -#--disable_warnings -#drop procedure if exists bug4318| -#--enable_warnings -#create procedure bug4318() -# handler t3 read next| -# -#handler t3 open| -## Expect no results, as tables are closed, but there shouldn't be any errors -#call bug4318()| -#call bug4318()| -#handler t3 close| -# -#drop procedure bug4318| -#drop table t3| + +--disable_parsing Don't know if HANDLER commands can work with SPs, or at all.. +create table t3 (s1 int)| +insert into t3 values (3), (4)| + +--disable_warnings +drop procedure if exists bug4318| +--enable_warnings +create procedure bug4318() + handler t3 read next| + +handler t3 open| +# Expect no results, as tables are closed, but there shouldn't be any errors +call bug4318()| +call bug4318()| +handler t3 close| + +drop procedure bug4318| +drop table t3| +--enable_parsing # # BUG#4902: Stored procedure with SHOW WARNINGS leads to packet error @@ -2834,26 +2835,27 @@ drop table t3| # # BUG#6022: Stored procedure shutdown problem with self-calling function. # -# This part of test is disabled until we implement support for -# recursive stored functions. -#--disable_warnings -#drop function if exists bug6022| -#--enable_warnings -# -#--disable_warnings -#drop function if exists bug6022| -#--enable_warnings -#create function bug6022(x int) returns int -#begin -# if x < 0 then -# return 0; -# else -# return bug6022(x-1); -# end if; -#end| -# -#select bug6022(5)| -#drop function bug6022| + +--disable_parsing until we implement support for recursive stored functions. +--disable_warnings +drop function if exists bug6022| +--enable_warnings + +--disable_warnings +drop function if exists bug6022| +--enable_warnings +create function bug6022(x int) returns int +begin + if x < 0 then + return 0; + else + return bug6022(x-1); + end if; +end| + +select bug6022(5)| +drop function bug6022| +--enable_parsing # # BUG#6029: Stored procedure specific handlers should have priority @@ -3760,27 +3762,28 @@ drop procedure if exists bug7088_1| drop procedure if exists bug7088_2| --enable_warnings -# psergey: temporarily disabled until Bar fixes BUG#11986 -# create procedure bug6063() -# lâbel: begin end| -# call bug6063()| -# # QQ Known bug: this will not show the label correctly. -# show create procedure bug6063| -# -# set character set utf8| -# create procedure bug7088_1() -# label1: begin end label1| -# create procedure bug7088_2() -# läbel1: begin end| -# call bug7088_1()| -# call bug7088_2()| -# set character set default| -# show create procedure bug7088_1| -# show create procedure bug7088_2| -# -# drop procedure bug6063| -# drop procedure bug7088_1| -# drop procedure bug7088_2| +--disable_parsing temporarily disabled until Bar fixes BUG#11986 +create procedure bug6063() + lâbel: begin end| +call bug6063()| +# QQ Known bug: this will not show the label correctly. +show create procedure bug6063| + +set character set utf8| +create procedure bug7088_1() + label1: begin end label1| +create procedure bug7088_2() + läbel1: begin end| +call bug7088_1()| +call bug7088_2()| +set character set default| +show create procedure bug7088_1| +show create procedure bug7088_2| + +drop procedure bug6063| +drop procedure bug7088_1| +drop procedure bug7088_2| +--enable_parsing # # BUG#9565: "Wrong locking in stored procedure if a sub-sequent procedure diff --git a/sql/lock.cc b/sql/lock.cc index 568ca2b68af..941d7baa76e 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -849,10 +849,6 @@ static void print_lock_error(int error, const char *table) So in this exceptional case the COMMIT should not be blocked by the FLUSH TABLES WITH READ LOCK. - TODO in MySQL 5.x: make_global_read_lock_block_commit() should be - killable. Normally CPU does not spend a long time in this function (COMMITs - are quite fast), but it would still be nice. - ****************************************************************************/ volatile uint global_read_lock=0; @@ -1003,7 +999,7 @@ bool make_global_read_lock_block_commit(THD *thd) pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock--;); - if (error= thd->killed) + if ((error= test(thd->killed))) global_read_lock_blocks_commit--; // undo what we did else thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f8bfcb75be2..4989b0e623c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1908,7 +1908,8 @@ static void check_data_home(const char *path) static void sig_reload(int signo) { // Flush everything - reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0, NULL); + bool not_used; + reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0, ¬_used); signal(signo, SIG_ACK); } @@ -2267,12 +2268,13 @@ static void *signal_hand(void *arg __attribute__((unused))) case SIGHUP: if (!abort_loop) { + bool not_used; mysql_print_status(); // Print some debug info reload_acl_and_cache((THD*) 0, (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS), - (TABLE_LIST*) 0, NULL); // Flush logs + (TABLE_LIST*) 0, ¬_used); // Flush logs } break; #ifdef USE_ONE_SIGNAL_HAND diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index c8f0ed6ba2d..31cecff6e50 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -22,7 +22,7 @@ #include "sp_head.h" static pthread_mutex_t Cversion_lock; -static ulong Cversion = 0; +static ulong volatile Cversion = 0; void sp_cache_init() @@ -30,6 +30,7 @@ sp_cache_init() pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST); } + void sp_cache_clear(sp_cache **cp) { @@ -42,33 +43,31 @@ sp_cache_clear(sp_cache **cp) } } + void sp_cache_insert(sp_cache **cp, sp_head *sp) { sp_cache *c= *cp; + ulong v; if (! c) - c= new sp_cache(); - if (c) { - ulong v; - - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - if (*cp) - c->remove_all(); - c->version= v; - } - c->insert(sp); - if (*cp == NULL) - *cp= c; + if (!(c= new sp_cache())) + return; // End of memory error } + + v= Cversion; /* No need to lock when reading long variable */ + if (c->version < v) + { + if (*cp) + c->remove_all(); + c->version= v; + } + c->insert(sp); + *cp= c; // Update *cp if it was NULL } + sp_head * sp_cache_lookup(sp_cache **cp, sp_name *name) { @@ -78,10 +77,8 @@ sp_cache_lookup(sp_cache **cp, sp_name *name) if (! c) return NULL; - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - + + v= Cversion; /* No need to lock when reading long variable */ if (c->version < v) { c->remove_all(); @@ -91,6 +88,7 @@ sp_cache_lookup(sp_cache **cp, sp_name *name) return c->lookup(name->m_qname.str, name->m_qname.length); } + bool sp_cache_remove(sp_cache **cp, sp_name *name) { @@ -114,14 +112,14 @@ sp_cache_remove(sp_cache **cp, sp_name *name) return found; } + void sp_cache_invalidate() { - pthread_mutex_lock(&Cversion_lock); // LOCK - Cversion++; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK + thread_safe_increment(Cversion, &Cversion_lock); // UNLOCK } + static byte * hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) @@ -132,6 +130,7 @@ hash_get_key_for_sp_head(const byte *ptr, uint *plen, return (byte*) sp->m_qname.str; } + static void hash_free_sp_head(void *p) { @@ -140,16 +139,19 @@ hash_free_sp_head(void *p) delete sp; } + sp_cache::sp_cache() { init(); } + sp_cache::~sp_cache() { hash_free(&m_hashtable); } + void sp_cache::init() { @@ -158,6 +160,7 @@ sp_cache::init() version= 0; } + void sp_cache::cleanup() { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 3a386356335..102363b9130 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -678,12 +678,14 @@ sp_head::execute(THD *thd) cleanup_items(i->free_list); i->state= Query_arena::EXECUTED; - // Check if an exception has occurred and a handler has been found - // Note: We havo to check even if ret==0, since warnings (and some - // errors don't return a non-zero value. - // We also have to check even if thd->killed != 0, since some - // errors return with this even when a handler has been found - // (e.g. "bad data"). + /* + Check if an exception has occurred and a handler has been found + Note: We havo to check even if ret==0, since warnings (and some + errors don't return a non-zero value. + We also have to check even if thd->killed != 0, since some + errors return with this even when a handler has been found + (e.g. "bad data"). + */ if (ctx) { uint hf; @@ -759,8 +761,10 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) if (argcount != params) { - // Need to use my_printf_error here, or it will not terminate the - // invoking query properly. + /* + Need to use my_printf_error here, or it will not terminate the + invoking query properly. + */ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "FUNCTION", m_qname.str, params, argcount); DBUG_RETURN(-1); @@ -784,9 +788,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) DBUG_RETURN(-1); } } - // The rest of the frame are local variables which are all IN. - // Default all variables to null (those with default clauses will - // be set by an set instruction). + /* + The rest of the frame are local variables which are all IN. + Default all variables to null (those with default clauses will + be set by an set instruction). + */ { Item_null *nit= NULL; // Re-use this, and only create if needed for (; i < csize ; i++) @@ -803,9 +809,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) ret= execute(thd); - // Partially restore context now. - // We still need the call mem root and free list for processing - // of the result. + /* + Partially restore context now. + We still need the call mem root and free list for processing + of the result. + */ thd->restore_backup_item_arena(&call_arena, &backup_arena); if (m_type == TYPE_ENUM_FUNCTION && ret == 0) @@ -932,9 +940,11 @@ sp_head::execute_procedure(THD *thd, List *args) close_thread_tables(thd, 0, 0, 0); DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str)); - // The rest of the frame are local variables which are all IN. - // Default all variables to null (those with default clauses will - // be set by an set instruction). + /* + The rest of the frame are local variables which are all IN. + Default all variables to null (those with default clauses will + be set by an set instruction). + */ for (; i < csize ; i++) { if (! nit) @@ -956,8 +966,10 @@ sp_head::execute_procedure(THD *thd, List *args) List_iterator li(*args); Item *it; - // Copy back all OUT or INOUT values to the previous frame, or - // set global user variables + /* + Copy back all OUT or INOUT values to the previous frame, or + set global user variables + */ for (uint i = 0 ; (it= li++) && i < params ; i++) { sp_pvar_t *pvar= m_pcont->find_pvar(i); @@ -987,8 +999,10 @@ sp_head::execute_procedure(THD *thd, List *args) octx->set_item(offset, copy); if (orig && copy == orig) { - // A reused item slot, where the constructor put it in the - // free_list, so we have to restore the list. + /* + A reused item slot, where the constructor put it in the + free_list, so we have to restore the list. + */ thd->free_list= o_free_list; copy->next= o_item_next; } @@ -1420,8 +1434,6 @@ sp_head::opt_mark(uint ip) ip= i->opt_mark(this); } -// ------------------------------------------------------------------ - /* Prepare LEX and thread for execution of instruction, if requested open @@ -1513,6 +1525,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, thd->proc_info="closing tables"; close_thread_tables(thd); + thd->proc_info= 0; if (m_lex->query_tables_own_last) { @@ -1549,9 +1562,10 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, } -// -// sp_instr -// +/* + sp_instr class functions +*/ + int sp_instr::exec_core(THD *thd, uint *nextp) { DBUG_ASSERT(0); @@ -1559,9 +1573,10 @@ int sp_instr::exec_core(THD *thd, uint *nextp) } -// -// sp_instr_stmt -// +/* + sp_instr_stmt class functions +*/ + int sp_instr_stmt::execute(THD *thd, uint *nextp) { @@ -1606,9 +1621,11 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp) return res; } -// -// sp_instr_set -// + +/* + sp_instr_set class functions +*/ + int sp_instr_set::execute(THD *thd, uint *nextp) { @@ -1618,6 +1635,7 @@ sp_instr_set::execute(THD *thd, uint *nextp) DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } + int sp_instr_set::exec_core(THD *thd, uint *nextp) { @@ -1638,9 +1656,10 @@ sp_instr_set::print(String *str) } -// -// sp_instr_set_trigger_field -// +/* + sp_instr_set_trigger_field class functions +*/ + int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { @@ -1671,9 +1690,11 @@ sp_instr_set_trigger_field::print(String *str) value->print(str); } -// -// sp_instr_jump -// + +/* + sp_instr_jump class functions +*/ + int sp_instr_jump::execute(THD *thd, uint *nextp) { @@ -1732,9 +1753,10 @@ sp_instr_jump::opt_move(uint dst, List *bp) m_ip= dst; } -// -// sp_instr_jump_if -// + +/* + sp_instr_jump_if class functions +*/ int sp_instr_jump_if::execute(THD *thd, uint *nextp) @@ -1790,9 +1812,11 @@ sp_instr_jump_if::opt_mark(sp_head *sp) return m_ip+1; } -// -// sp_instr_jump_if_not -// + +/* + sp_instr_jump_if_not class functions +*/ + int sp_instr_jump_if_not::execute(THD *thd, uint *nextp) { @@ -1823,6 +1847,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) return res; } + void sp_instr_jump_if_not::print(String *str) { @@ -1833,6 +1858,7 @@ sp_instr_jump_if_not::print(String *str) m_expr->print(str); } + uint sp_instr_jump_if_not::opt_mark(sp_head *sp) { @@ -1848,9 +1874,10 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) return m_ip+1; } -// -// sp_instr_freturn -// + +/* + sp_instr_freturn class functions +*/ int sp_instr_freturn::execute(THD *thd, uint *nextp) @@ -1889,9 +1916,10 @@ sp_instr_freturn::print(String *str) m_value->print(str); } -// -// sp_instr_hpush_jump -// +/* + sp_instr_hpush_jump class functions +*/ + int sp_instr_hpush_jump::execute(THD *thd, uint *nextp) { @@ -1935,9 +1963,11 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp) return m_ip+1; } -// -// sp_instr_hpop -// + +/* + sp_instr_hpop class functions +*/ + int sp_instr_hpop::execute(THD *thd, uint *nextp) { @@ -1962,9 +1992,10 @@ sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx) } -// -// sp_instr_hreturn -// +/* + sp_instr_hreturn class functions +*/ + int sp_instr_hreturn::execute(THD *thd, uint *nextp) { @@ -1980,6 +2011,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_hreturn::print(String *str) { @@ -1990,6 +2022,7 @@ sp_instr_hreturn::print(String *str) str->qs_append(m_dest); } + uint sp_instr_hreturn::opt_mark(sp_head *sp) { @@ -2003,9 +2036,10 @@ sp_instr_hreturn::opt_mark(sp_head *sp) } -// -// sp_instr_cpush -// +/* + sp_instr_cpush class functions +*/ + int sp_instr_cpush::execute(THD *thd, uint *nextp) { @@ -2015,15 +2049,18 @@ sp_instr_cpush::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_cpush::print(String *str) { str->append("cpush"); } -// -// sp_instr_cpop -// + +/* + sp_instr_cpop class functions +*/ + int sp_instr_cpop::execute(THD *thd, uint *nextp) { @@ -2033,6 +2070,7 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_cpop::print(String *str) { @@ -2047,9 +2085,11 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx) m_count= m_ctx->diff_cursors(dst_ctx); } -// -// sp_instr_copen -// + +/* + sp_instr_copen class functions +*/ + int sp_instr_copen::execute(THD *thd, uint *nextp) { @@ -2117,9 +2157,11 @@ sp_instr_copen::print(String *str) str->qs_append(m_cursor); } -// -// sp_instr_cclose -// + +/* + sp_instr_cclose class functions +*/ + int sp_instr_cclose::execute(THD *thd, uint *nextp) { @@ -2135,6 +2177,7 @@ sp_instr_cclose::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } + void sp_instr_cclose::print(String *str) { @@ -2143,9 +2186,11 @@ sp_instr_cclose::print(String *str) str->qs_append(m_cursor); } -// -// sp_instr_cfetch -// + +/* + sp_instr_cfetch class functions +*/ + int sp_instr_cfetch::execute(THD *thd, uint *nextp) { @@ -2161,6 +2206,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } + void sp_instr_cfetch::print(String *str) { @@ -2178,9 +2224,11 @@ sp_instr_cfetch::print(String *str) } } -// -// sp_instr_error -// + +/* + sp_instr_error class functions +*/ + int sp_instr_error::execute(THD *thd, uint *nextp) { @@ -2191,6 +2239,7 @@ sp_instr_error::execute(THD *thd, uint *nextp) DBUG_RETURN(-1); } + void sp_instr_error::print(String *str) { @@ -2199,12 +2248,12 @@ sp_instr_error::print(String *str) str->qs_append(m_errcode); } + /* ------------------------------------------------------------------ */ - -// -// Security context swapping -// +/* + Security context swapping +*/ #ifndef NO_EMBEDDED_ACCESS_CHECKS void @@ -2453,11 +2502,12 @@ sp_head::add_used_tables_to_table_list(THD *thd, DBUG_RETURN(result); } + /* - * Simple function for adding an explicetly named (systems) table to - * the global table list, e.g. "mysql", "proc". - * - */ + Simple function for adding an explicetly named (systems) table to + the global table list, e.g. "mysql", "proc". +*/ + TABLE_LIST * sp_add_to_query_tables(THD *thd, LEX *lex, const char *db, const char *name, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5ff5e580f81..692eb2fccbe 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1919,8 +1919,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) has added its base tables after itself, adjust the boundary pointer accordingly. */ - if (query_tables_last_own && - query_tables_last_own == &(tables->next_global) && + if (query_tables_last_own == &(tables->next_global) && tables->view->query_tables) query_tables_last_own= tables->view->query_tables_last; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c1d4fae5253..51a2eadc132 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1863,17 +1863,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } #endif case COM_REFRESH: - { - statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH], - &LOCK_status); - ulong options= (ulong) (uchar) packet[0]; - if (check_global_access(thd,RELOAD_ACL)) - break; - mysql_log.write(thd,command,NullS); - if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL)) - send_ok(thd); + { + bool not_used; + statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH], + &LOCK_status); + ulong options= (ulong) (uchar) packet[0]; + if (check_global_access(thd,RELOAD_ACL)) break; - } + mysql_log.write(thd,command,NullS); + if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) + send_ok(thd); + break; + } #ifndef EMBEDDED_LIBRARY case COM_SHUTDOWN: { @@ -3822,13 +3823,13 @@ end_with_restore_list: lex->no_write_to_binlog= 1; case SQLCOM_FLUSH: { + bool write_to_binlog; if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables)) goto error; /* reload_acl_and_cache() will tell us if we are allowed to write to the binlog or not. */ - bool write_to_binlog; if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog)) { /* @@ -6383,13 +6384,13 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) tables Tables to flush (if any) write_to_binlog Depending on 'options', it may be very bad to write the query to the binlog (e.g. FLUSH SLAVE); this is a - pointer where, if it is not NULL, reload_acl_and_cache() - will put 0 if it thinks we really should not write to - the binlog. Otherwise it will put 1. + pointer where reload_acl_and_cache() will put 0 if + it thinks we really should not write to the binlog. + Otherwise it will put 1. RETURN 0 ok - !=0 error + !=0 error. thd->killed or thd->net.report_error is set */ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, @@ -6475,10 +6476,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, */ tmp_write_to_binlog= 0; if (lock_global_read_lock(thd)) - return 1; + return 1; // Killed result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables); - if (make_global_read_lock_block_commit(thd)) + if (make_global_read_lock_block_commit(thd)) // Killed { /* Don't leave things in a half-locked state */ unlock_global_read_lock(thd); @@ -6500,7 +6501,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, { tmp_write_to_binlog= 0; if (reset_master(thd)) + { result=1; + thd->fatal_error(); // Ensure client get error + } } #endif #ifdef OPENSSL @@ -6522,8 +6526,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #endif if (options & REFRESH_USER_RESOURCES) reset_mqh((LEX_USER *) NULL); - if (write_to_binlog) - *write_to_binlog= tmp_write_to_binlog; + *write_to_binlog= tmp_write_to_binlog; return result; } From fc22a36d782f79d1b94a25db0dd0a7e9bb5bcc3a Mon Sep 17 00:00:00 2001 From: "vtkachenko@quadxeon.mysql.com" <> Date: Thu, 11 Aug 2005 18:03:01 +0200 Subject: [PATCH 080/230] set_var.cc, mysqld.cc, ha_innodb.h, ha_innodb.cc, srv0srv.c, srv0srv.h: Added innodb_commit_concurrency variable --- innobase/include/srv0srv.h | 1 + innobase/srv/srv0srv.c | 1 + sql/ha_innodb.cc | 47 +++++++++++++++++++++++++++++++++++--- sql/ha_innodb.h | 1 + sql/mysqld.cc | 4 ++++ sql/set_var.cc | 4 ++++ 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 116ae7b6438..11347f430d4 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -94,6 +94,7 @@ extern ulint srv_max_dirty_pages_pct; extern ulint srv_force_recovery; extern ulong srv_thread_concurrency; +extern ulong srv_commit_concurrency; extern ulint srv_max_n_threads; diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index dc85750f0be..64cbae3644a 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -261,6 +261,7 @@ Value 10 should be good if there are less than 4 processors + 4 disks in the computer. Bigger computers need bigger values. */ ulong srv_thread_concurrency = SRV_CONCURRENCY_THRESHOLD; +ulong srv_commit_concurrency = 0; os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data structures */ diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0a01c08c916..c0aa7cc78c7 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -48,6 +48,10 @@ have disables the InnoDB inlining in this file. */ pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */ prepare_commit_mutex; /* to force correct commit order in binlog */ +ulong commit_threads= 0; +pthread_mutex_t commit_threads_m; +pthread_cond_t commit_cond; +pthread_mutex_t commit_cond_m; bool innodb_inited= 0; /*-----------------------------------------------------------------*/ @@ -1367,6 +1371,9 @@ innobase_init(void) (hash_get_key) innobase_get_key, 0, 0); pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST); pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); + pthread_cond_init(&commit_cond, NULL); innodb_inited= 1; /* If this is a replication slave and we needed to do a crash recovery, @@ -1416,6 +1423,9 @@ innobase_end(void) MYF(MY_ALLOW_ZERO_PTR)); pthread_mutex_destroy(&innobase_share_mutex); pthread_mutex_destroy(&prepare_commit_mutex); + pthread_mutex_destroy(&commit_threads_m); + pthread_mutex_destroy(&commit_cond_m); + pthread_cond_destroy(&commit_cond); } DBUG_RETURN(err); @@ -1542,8 +1552,10 @@ innobase_commit( reserve the kernel mutex, we have to release the search system latch first to obey the latching order. */ - innobase_release_stat_resources(trx); - + if (trx->has_search_latch) { + trx_search_latch_release_if_reserved(trx); + } + /* The flag trx->active_trans is set to 1 in 1. ::external_lock(), @@ -1575,18 +1587,43 @@ innobase_commit( /* We need current binlog position for ibbackup to work. Note, the position is current because of prepare_commit_mutex */ +retry: + if (srv_commit_concurrency > 0) + { + pthread_mutex_lock(&commit_cond_m); + commit_threads++; + if (commit_threads > srv_commit_concurrency) + { + commit_threads--; + pthread_cond_wait(&commit_cond, &commit_cond_m); + pthread_mutex_unlock(&commit_cond_m); + goto retry; + } + else + pthread_mutex_unlock(&commit_cond_m); + } + trx->mysql_log_file_name = mysql_bin_log.get_log_fname(); trx->mysql_log_offset = (ib_longlong)mysql_bin_log.get_log_file()->pos_in_file; innobase_commit_low(trx); + if (srv_commit_concurrency > 0) + { + pthread_mutex_lock(&commit_cond_m); + commit_threads--; + pthread_cond_signal(&commit_cond); + pthread_mutex_unlock(&commit_cond_m); + } + if (trx->active_trans == 2) { pthread_mutex_unlock(&prepare_commit_mutex); } + trx->active_trans = 0; - + } else { /* We just mark the SQL statement ended and do not do a transaction commit */ @@ -1606,7 +1643,11 @@ innobase_commit( /* Tell the InnoDB server that there might be work for utility threads: */ + if (trx->declared_to_be_inside_innodb) { + /* Release our possible ticket in the FIFO */ + srv_conc_force_exit_innodb(trx); + } srv_active_wake_master_thread(); DBUG_RETURN(0); diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 3bc1fc5b2c8..4817ab9b682 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -232,6 +232,7 @@ extern ulong srv_n_spin_wait_rounds; extern ulong srv_n_free_tickets_to_enter; extern ulong srv_thread_sleep_delay; extern ulong srv_thread_concurrency; +extern ulong srv_commit_concurrency; } extern TYPELIB innobase_lock_typelib; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f8bfcb75be2..4dddac6b2d1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5314,6 +5314,10 @@ log and this option does nothing anymore.", "Helps in performance tuning in heavily concurrent environments.", (gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency, 0, GET_LONG, REQUIRED_ARG, 20, 1, 1000, 0, 1, 0}, + {"innodb_commit_concurrency", OPT_INNODB_THREAD_CONCURRENCY, + "Helps in performance tuning in heavily concurrent environments.", + (gptr*) &srv_commit_concurrency, (gptr*) &srv_commit_concurrency, + 0, GET_LONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0}, {"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0" " disable a sleep", diff --git a/sql/set_var.cc b/sql/set_var.cc index 637b33f18d2..53f3d45e522 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -411,6 +411,8 @@ sys_var_long_ptr sys_innodb_thread_sleep_delay("innodb_thread_sleep_delay", &srv_thread_sleep_delay); sys_var_long_ptr sys_innodb_thread_concurrency("innodb_thread_concurrency", &srv_thread_concurrency); +sys_var_long_ptr sys_innodb_commit_concurrency("innodb_commit_concurrency", + &srv_commit_concurrency); #endif /* Condition pushdown to storage engine */ @@ -708,6 +710,7 @@ sys_var *sys_variables[]= &sys_innodb_concurrency_tickets, &sys_innodb_thread_sleep_delay, &sys_innodb_thread_concurrency, + &sys_innodb_commit_concurrency, #endif &sys_trust_routine_creators, &sys_engine_condition_pushdown, @@ -828,6 +831,7 @@ struct show_var_st init_vars[]= { {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS}, {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS}, + {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS}, {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, From 1a7af25913d07e9cf2b4b19794e78796dd58f1bf Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Thu, 11 Aug 2005 19:19:20 +0300 Subject: [PATCH 081/230] Fixed some warning and error messages so that they use sql_print_warning() and sql_print_error() instead of fprintf to stderr. Above functions are tuned for different platforms so that the behavior is consistent around platforms. Using fprintf() different behavior can be expected at least on Windows and Unix. --- sql/ha_innodb.cc | 127 ++++++++++------------------------------------- 1 file changed, 25 insertions(+), 102 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0a01c08c916..e7a6d7d5524 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -948,9 +948,7 @@ innobase_query_caching_of_table_permitted( trx = check_trx_exists(thd); if (trx->has_search_latch) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: the calling thread is holding the adaptive search\n" -"InnoDB: latch though calling innobase_query_caching_of_table_permitted\n"); + sql_print_error("The calling thread is holding the adaptive search, latch though calling innobase_query_caching_of_table_permitted."); } innobase_release_stat_resources(trx); @@ -1266,9 +1264,7 @@ innobase_init(void) &srv_log_group_home_dirs); if (ret == FALSE || innobase_mirrored_log_groups != 1) { - fprintf(stderr, - "InnoDB: syntax error in innodb_log_group_home_dir\n" - "InnoDB: or a wrong number of mirrored log groups\n"); + sql_print_error("syntax error in innodb_log_group_home_dir, or a wrong number of mirrored log groups"); my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); @@ -1562,11 +1558,8 @@ innobase_commit( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - fprintf(stderr, -"InnoDB: Error: trx->active_trans == 0\n" -"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); } - if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { @@ -1813,21 +1806,7 @@ try_again: if (ret != 0) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: MySQL synchronous replication\n" -"InnoDB: was not able to send the binlog to the slave within the\n" -"InnoDB: timeout %lu. We assume that the slave has become inaccessible,\n" -"InnoDB: and switch off synchronous replication until the communication.\n" -"InnoDB: to the slave works again.\n", - thd->variables.sync_replication_timeout); - fprintf(stderr, -"InnoDB: MySQL synchronous replication has sent binlog\n" -"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name, - (ulong)innobase_repl_pos); - fprintf(stderr, -"InnoDB: This transaction needs it to be sent up to\n" -"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name, - (ulong)trx->repl_wait_binlog_pos); + sql_print_error("MySQL synchronous replication was not able to send the binlog to the slave within the timeout %lu. We assume that the slave has become inaccessible, and switch off synchronous replication until the communication to the slave works again. MySQL synchronous replication has sent binlog to the slave up to file %s, position %lu. This transaction needs it to be sent up to file %s, position %lu.", thd->variables.sync_replication_timeout, innobase_repl_file_name, (ulong)innobase_repl_pos, trx->repl_wait_binlog_name, (ulong)trx->repl_wait_binlog_pos); innobase_repl_state = 0; @@ -1878,9 +1857,7 @@ innobase_repl_report_sent_binlog( if (innobase_repl_state == 0) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Switching MySQL synchronous replication on again at\n" -"InnoDB: binlog file %s, position %lu\n", log_file_name, (ulong)end_offset); + sql_print_warning("Switching MySQL synchronous replication on again at binlog file %s, position %lu", log_file_name, (ulong) end_offset); innobase_repl_state = 1; } @@ -1897,14 +1874,7 @@ innobase_repl_report_sent_binlog( || (cmp == 0 && end_offset < innobase_repl_pos)) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: MySQL synchronous replication has sent binlog\n" -"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name, - (ulong)innobase_repl_pos); - fprintf(stderr, -"InnoDB: but now MySQL reports that it sent the binlog only up to\n" -"InnoDB: file %s, position %lu\n", log_file_name, (ulong)end_offset); - + sql_print_error("MySQL synchronous replication has sent binlog to the slave up to file %s, position %lu, but now MySQL reports that it sent the binlog only up to file %s, position %lu", innobase_repl_file_name, (ulong)innobase_repl_pos, log_file_name, (ulong) end_offset); } } @@ -2149,9 +2119,7 @@ innobase_close_connection( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - fprintf(stderr, -"InnoDB: Error: trx->active_trans == 0\n" -"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); } @@ -2363,9 +2331,7 @@ ha_innobase::open( if (!row_table_got_default_clust_index(ib_table)) { if (primary_key >= MAX_KEY) { - fprintf(stderr, - "InnoDB: Error: table %s has a primary key in InnoDB\n" - "InnoDB: data dictionary, but not in MySQL!\n", name); + sql_print_error("Table %s has a primary key in InnoDB data dictionary, but not in MySQL!", name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -2379,16 +2345,7 @@ ha_innobase::open( ref_length = table->key_info[primary_key].key_length; } else { if (primary_key != MAX_KEY) { - fprintf(stderr, - "InnoDB: Error: table %s has no primary key in InnoDB\n" - "InnoDB: data dictionary, but has one in MySQL!\n" - "InnoDB: If you created the table with a MySQL\n" - "InnoDB: version < 3.23.54 and did not define a primary\n" - "InnoDB: key, but defined a unique key with all non-NULL\n" - "InnoDB: columns, then MySQL internally treats that key\n" - "InnoDB: as the primary key. You can fix this error by\n" - "InnoDB: dump + DROP + CREATE + reimport of the table.\n", - name); + sql_print_error("Table %s has no primary key in InnoDB data dictionary, but has one in MySQL! If you created the table with a MySQL version < 3.23.54 and did not define a primary key, but defined a unique key with all non-NULL columns, then MySQL internally treats that key as the primary key. You can fix this error by dump + DROP + CREATE + reimport of the table.", name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -2405,10 +2362,7 @@ ha_innobase::open( and it will never be updated anyway. */ if (key_used_on_scan != MAX_KEY) { - fprintf(stderr, -"InnoDB: Warning: table %s key_used_on_scan is %lu even though there is no\n" -"InnoDB: primary key inside InnoDB.\n", - name, (ulong)key_used_on_scan); + sql_print_warning("Table %s key_used_on_scan is %lu even though there is no primary key inside InnoDB.", name, (ulong) key_used_on_scan); } } @@ -2563,9 +2517,7 @@ innobase_mysql_cmp( charset = get_charset(charset_number, MYF(MY_WME)); if (charset == NULL) { - fprintf(stderr, -"InnoDB: fatal error: InnoDB needs charset %lu for doing a comparison,\n" -"InnoDB: but MySQL cannot find that charset.\n", (ulong)charset_number); + sql_print_error("InnoDB needs charset %lu for doing a comparison, but MySQL cannot find that charset.", (ulong) charset_number); ut_a(0); } } @@ -3131,11 +3083,8 @@ ha_innobase::write_row( if (prebuilt->trx != (trx_t*) current_thd->ha_data[innobase_hton.slot]) { - fprintf(stderr, -"InnoDB: Error: the transaction object for the table handle is at\n" -"InnoDB: %p, but for the current thread it is at %p\n", - prebuilt->trx, - (trx_t*) current_thd->ha_data[innobase_hton.slot]); + sql_print_error("The transaction object for the table handle is at %p, but for the current thread it is at %p", prebuilt->trx, (trx_t*) current_thd->ha_data[innobase_hton.slot]); + fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr); ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200); fputs("\n" @@ -3622,9 +3571,7 @@ ha_innobase::unlock_row(void) if (last_query_id != user_thd->query_id) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: last_query_id is %lu != user_thd_query_id is %lu\n", - (ulong)last_query_id, (ulong)user_thd->query_id); + sql_print_error("last_query_id is %lu != user_thd_query_id is %lu", (ulong) last_query_id, (ulong) user_thd->query_id); mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } @@ -4284,9 +4231,8 @@ ha_innobase::position( table. */ if (len != ref_length) { - fprintf(stderr, - "InnoDB: Error: stored ref len is %lu, but table ref len is %lu\n", - (ulong)len, (ulong)ref_length); + sql_print_error("Stored ref len is %lu, but table ref len is %lu", + (ulong) len, (ulong) ref_length); } } @@ -4491,11 +4437,8 @@ create_index( || col_type == DATA_FLOAT || col_type == DATA_DOUBLE || col_type == DATA_DECIMAL) { - fprintf(stderr, -"InnoDB: error: MySQL is trying to create a column prefix index field\n" -"InnoDB: on an inappropriate data type. Table name %s, column name %s.\n", - table_name, key_part->field->field_name); - + sql_print_error("MySQL is trying to create a column prefix index field, on an inappropriate data type. Table name %s, column name %s.", table_name, key_part->field->field_name); + prefix_len = 0; } } else { @@ -5378,12 +5321,7 @@ ha_innobase::info( for (i = 0; i < table->s->keys; i++) { if (index == NULL) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: table %s contains less indexes inside InnoDB\n" -"InnoDB: than are defined in the MySQL .frm file. Have you mixed up\n" -"InnoDB: .frm files from different installations? See section\n" -"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n", - ib_table->name); + sql_print_error("Table %s contains less indexes inside InnoDB than are defined in the MySQL .frm file. Have you mixed up .frm files from different installations? See section 15.1 at http://www.innodb.com/ibman.html", ib_table->name); break; } @@ -5391,15 +5329,7 @@ ha_innobase::info( if (j + 1 > index->n_uniq) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: index %s of %s has %lu columns unique inside InnoDB\n" -"InnoDB: but MySQL is asking statistics for %lu columns. Have you mixed up\n" -"InnoDB: .frm files from different installations? See section\n" -"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n", - index->name, - ib_table->name, - (unsigned long) index->n_uniq, - j + 1); + sql_print_error("Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking statistics for %lu columns. Have you mixed up .frm files from different installations? See section 15.1 at http://www.innodb.com/ibman.html", index->name, ib_table->name, (unsigned long) index->n_uniq, j + 1); break; } @@ -5947,9 +5877,7 @@ ha_innobase::start_stmt( if (prebuilt->stored_select_lock_type != LOCK_S && prebuilt->stored_select_lock_type != LOCK_X) { - fprintf(stderr, -"InnoDB: Error: stored_select_lock_type is %lu inside ::start_stmt()!\n", - prebuilt->stored_select_lock_type); + sql_print_error("stored_select_lock_type is %lu inside ::start_stmt()!", prebuilt->stored_select_lock_type); /* Set the value to LOCK_X: this is just fault tolerance, we do not know what the correct value @@ -6725,9 +6653,7 @@ ha_innobase::innobase_read_and_init_auto_inc( error = 0; } else { /* This should not happen in a consistent read */ - fprintf(stderr, -"InnoDB: Error: consistent read of auto-inc column returned %lu\n", - (ulong)error); + sql_print_error("Consistent read of auto-inc column returned %lu", (ulong) error); auto_inc = -1; goto func_exit; @@ -6784,9 +6710,8 @@ ha_innobase::get_auto_increment() initialized. */ ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: error %lu in ::get_auto_increment()\n", - (ulong)error); + sql_print_error("Error %lu in ::get_auto_increment()", + (ulong) error); return(~(ulonglong) 0); } @@ -7053,9 +6978,7 @@ innobase_xa_prepare( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - fprintf(stderr, -"InnoDB: Error: trx->active_trans == 0\n" -"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); } if (all From 597b7412c78a463d7a0bbc20b861bc8f1c3e28a5 Mon Sep 17 00:00:00 2001 From: "acurtis@xiphis.org" <> Date: Thu, 11 Aug 2005 18:42:22 +0100 Subject: [PATCH 082/230] fix after merge --- mysql-test/r/bigint.result | 2 +- mysql-test/r/query_cache.result | 6 ------ mysql-test/r/type_datetime.result | 2 +- sql/sql_union.cc | 4 ++-- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 35374024649..1b5619eb18d 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -22,7 +22,7 @@ select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000 1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; -1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 --1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000000 +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16) 1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5 diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 6ff49951d27..0efd5ac1566 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -947,24 +947,18 @@ COUNT(*) Warnings: Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 invalid'; COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1 Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1 -Warning 1292 Truncated incorrect INTEGER value: '20050328 invalid' -Warning 1292 Truncated incorrect INTEGER value: '20050328 invalid' SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 invalid'; COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 3aaa0e5f151..85f899be5d8 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -52,7 +52,7 @@ t truncate table t1; insert into t1 values("2003-0303 12:13:14"); Warnings: -Warning 1264 Data truncated; out of range for column 't' at row 1 +Warning 1264 Out of range value adjusted for column 't' at row 1 select * from t1; t 0000-00-00 00:00:00 diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 05472058489..c2888bee4c6 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -301,8 +301,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - ulong create_options= (first_select_in_union()->options | thd_arg->options | - TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; + create_options= (first_select_in_union()->options | thd_arg->options | + TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading From 776bf91371de97dc892e4b1ae329005ee9002e82 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Thu, 11 Aug 2005 20:13:12 +0200 Subject: [PATCH 083/230] - Make sure the Mac OS X support files are built, but not installed by "make install" (the previous change was too drastic) (BUG#12506) --- support-files/MacOSX/Makefile.am | 6 ++++++ support-files/Makefile.am | 3 +++ 2 files changed, 9 insertions(+) diff --git a/support-files/MacOSX/Makefile.am b/support-files/MacOSX/Makefile.am index a4915deccf6..cc22d08daea 100644 --- a/support-files/MacOSX/Makefile.am +++ b/support-files/MacOSX/Makefile.am @@ -28,6 +28,12 @@ EXTRA_DIST = Info.plist.sh \ StartupItem.Info.plist \ StartupItem.postinstall +noinst_DATA = Info.plist \ + Description.plist \ + StartupParameters.plist \ + postinstall \ + preinstall + CLEANFILES = Info.plist \ Description.plist \ StartupParameters.plist \ diff --git a/support-files/Makefile.am b/support-files/Makefile.am index 59ee837825b..eba3a534489 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -41,6 +41,9 @@ pkgdata_DATA = my-small.cnf \ pkgdata_SCRIPTS = mysql.server +noinst_DATA = mysql-@VERSION@.spec \ + MySQL-shared-compat.spec + CLEANFILES = my-small.cnf \ my-medium.cnf \ my-large.cnf \ From c1c336f84b803bf42cba93d3260d2138225685e8 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Thu, 11 Aug 2005 20:23:12 +0200 Subject: [PATCH 084/230] - Fix for BUG#11380 (as recommened by JimW): renamed the preinstall/postinstall scripts to preflight/postflight instead, so they are run every time a PKG is installed, not only for a fresh installation --- support-files/MacOSX/Makefile.am | 12 ++++++------ .../MacOSX/{postinstall.sh => postflight.sh} | 2 +- support-files/MacOSX/{preinstall.sh => preflight.sh} | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) rename support-files/MacOSX/{postinstall.sh => postflight.sh} (85%) rename support-files/MacOSX/{preinstall.sh => preflight.sh} (77%) diff --git a/support-files/MacOSX/Makefile.am b/support-files/MacOSX/Makefile.am index cc22d08daea..d23ea142170 100644 --- a/support-files/MacOSX/Makefile.am +++ b/support-files/MacOSX/Makefile.am @@ -20,8 +20,8 @@ EXTRA_DIST = Info.plist.sh \ Description.plist.sh \ StartupParameters.plist.sh \ - postinstall.sh \ - preinstall.sh \ + postflight.sh \ + preflight.sh \ ReadMe.txt \ MySQL \ StartupItem.Description.plist \ @@ -31,14 +31,14 @@ EXTRA_DIST = Info.plist.sh \ noinst_DATA = Info.plist \ Description.plist \ StartupParameters.plist \ - postinstall \ - preinstall + postflight \ + preflight CLEANFILES = Info.plist \ Description.plist \ StartupParameters.plist \ - postinstall \ - preinstall + postflight \ + preflight SUFFIXES = .sh diff --git a/support-files/MacOSX/postinstall.sh b/support-files/MacOSX/postflight.sh similarity index 85% rename from support-files/MacOSX/postinstall.sh rename to support-files/MacOSX/postflight.sh index f46f4480e3e..df3cd419360 100644 --- a/support-files/MacOSX/postinstall.sh +++ b/support-files/MacOSX/postflight.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# postinstall - this script will be executed after the MySQL PKG +# postfligh - this script will be executed after the MySQL PKG # installation has been performed. # # This script will install the MySQL privilege tables using the diff --git a/support-files/MacOSX/preinstall.sh b/support-files/MacOSX/preflight.sh similarity index 77% rename from support-files/MacOSX/preinstall.sh rename to support-files/MacOSX/preflight.sh index 62772573c46..700d0640a9e 100644 --- a/support-files/MacOSX/preinstall.sh +++ b/support-files/MacOSX/preflight.sh @@ -1,10 +1,10 @@ #!/bin/sh # -# preinstall - this script will be executed before the MySQL PKG +# preflight - this script will be executed before the MySQL PKG # installation will be performed. # # If this package has been compiled with a prefix ending with "mysql" (e.g. -# /usr/local/mysql or /opt/mysql), it will rename any previosuly existing +# /usr/local/mysql or /opt/mysql), it will rename any previously existing # directory with this name before installing the new package (which includes # a symlink named "mysql", pointing to the newly installed directory, which # is named mysql-) From 16b696a60e42a581372efab73508efb67ebc6df2 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Thu, 11 Aug 2005 21:18:45 +0200 Subject: [PATCH 085/230] - another comment typo fixed --- support-files/MacOSX/postflight.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/MacOSX/postflight.sh b/support-files/MacOSX/postflight.sh index df3cd419360..c253ccbc6f2 100644 --- a/support-files/MacOSX/postflight.sh +++ b/support-files/MacOSX/postflight.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# postfligh - this script will be executed after the MySQL PKG +# postflight - this script will be executed after the MySQL PKG # installation has been performed. # # This script will install the MySQL privilege tables using the From d1db84639c741f252150c9ad3f503d9fddfba38c Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Thu, 11 Aug 2005 12:26:17 -0700 Subject: [PATCH 086/230] Build YASSL libraries with libtool so correct PIC settings are used automatically. (Bug #12324) --- extra/yassl/src/Makefile.am | 4 ++-- extra/yassl/taocrypt/src/Makefile.am | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am index 4ebb9a2d862..83397e24168 100644 --- a/extra/yassl/src/Makefile.am +++ b/extra/yassl/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I../include -I../taocrypt/include -I../mySTL -noinst_LIBRARIES = libyassl.a -libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ +noinst_LTLIBRARIES = libyassl.la +libyassl_la_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \ template_instnt.cpp timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp EXTRA_DIST = ../include/*.hpp ../include/openssl/*.h diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am index 5bf45074a98..4549c218d87 100644 --- a/extra/yassl/taocrypt/src/Makefile.am +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I../include -I../../mySTL -noinst_LIBRARIES = libtaocrypt.a -libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ +noinst_LTLIBRARIES = libtaocrypt.la +libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp integer.cpp \ md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \ template_instnt.cpp From 0aff8a13dc69af818a6419c91433b9d8e3728ee3 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Thu, 11 Aug 2005 16:10:34 -0700 Subject: [PATCH 087/230] sql_base.cc: Fixed bug #12382. INSERT statement effectively changed thd->set_query_id to 0, while SELECT statement changed it to 0. As a result the insert_fields function that expanded '*' was called with different values of thd->set_query_id for the query SELECT * FROM view depending on whether it was run after an INSERT or after a SELECT statement. This was corrected by restoring the old value of thd->set_query_id when returning from the function setup_fields where possible reset could occur. If the value of thd->set_query_id == 0 then the fields substituted instead of '*' were not registered as used for bitmaps used_keys. This caused selection of an invalid execution plan for the query SELECT * from . view.result, view.test: Added a test case for bug #12382. --- mysql-test/r/view.result | 14 ++++++++++++++ mysql-test/t/view.test | 19 +++++++++++++++++++ sql/sql_base.cc | 5 ++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 98020c7ec33..dcbdf3a99c4 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2065,3 +2065,17 @@ pid GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) 2 c d DROP VIEW v1; DROP TABLE t1,t2; +CREATE TABLE t1 (id int PRIMARY KEY, f varchar(255)); +CREATE VIEW v1 AS SELECT id, f FROM t1 WHERE id <= 2; +INSERT INTO t1 VALUES (2, 'foo2'); +INSERT INTO t1 VALUES (1, 'foo1'); +SELECT * FROM v1; +id f +1 foo1 +2 foo2 +SELECT * FROM v1; +id f +1 foo1 +2 foo2 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index cba2d75fb7c..07724e8ff8d 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1901,3 +1901,22 @@ SELECT pid,GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) FROM v1 GROUP BY pid; DROP VIEW v1; DROP TABLE t1,t2; + +# +# Test for bug #12382: SELECT * FROM view after INSERT command +# + +CREATE TABLE t1 (id int PRIMARY KEY, f varchar(255)); +CREATE VIEW v1 AS SELECT id, f FROM t1 WHERE id <= 2; +INSERT INTO t1 VALUES (2, 'foo2'); +INSERT INTO t1 VALUES (1, 'foo1'); + +SELECT * FROM v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; + + + + diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0895901508d..949c398309c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3181,6 +3181,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, List *sum_func_list, bool allow_sum_func) { reg2 Item *item; + bool save_set_query_id= thd->set_query_id; List_iterator it(fields); DBUG_ENTER("setup_fields"); @@ -3208,6 +3209,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, if (!item->fixed && item->fix_fields(thd, it.ref()) || (item= *(it.ref()))->check_cols(1)) { + thd->set_query_id= save_set_query_id; DBUG_RETURN(TRUE); /* purecov: inspected */ } if (ref) @@ -3215,8 +3217,9 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && sum_func_list) item->split_sum_func(thd, ref_pointer_array, *sum_func_list); - thd->used_tables|=item->used_tables(); + thd->used_tables|= item->used_tables(); } + thd->set_query_id= save_set_query_id; DBUG_RETURN(test(thd->net.report_error)); } From 3a815f45bd7030cddf636d5018faf13918f99ca6 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Thu, 11 Aug 2005 17:04:16 -0700 Subject: [PATCH 088/230] Avoid spurious error when restoring INFORMATION_SCHEMA as the current database after failing to execute a stored procedure in an inaccessible database. (Bug #12318) --- mysql-test/r/sp-security.result | 13 ++++ mysql-test/t/sp-security.test | 36 +++++++++++ sql/mysql_priv.h | 2 +- sql/sp.cc | 110 ++------------------------------ sql/sp.h | 4 -- sql/sql_db.cc | 52 ++++++++------- sql/sql_parse.cc | 18 +++--- 7 files changed, 92 insertions(+), 143 deletions(-) diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index 184978e4a0d..d78f5fc36ea 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -236,3 +236,16 @@ drop procedure bug7291_2; drop procedure bug7291_0; REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost; drop user user1@localhost; +drop database if exists mysqltest_1; +create database mysqltest_1; +create procedure mysqltest_1.p1() +begin +select 1 from dual; +end// +grant usage on *.* to mysqltest_1@localhost; +call mysqltest_1.p1(); +ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1' +drop procedure mysqltest_1.p1; +drop database mysqltest_1; +revoke usage on *.* from mysqltest_1@localhost; +drop user mysqltest_1@localhost; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 15fcba5ebe9..c7c7ef20a5b 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -371,3 +371,39 @@ drop procedure bug7291_0; disconnect user1; REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost; drop user user1@localhost; + +# +# Bug #12318: Wrong error message when accessing an inaccessible stored +# procedure in another database when the current database is +# information_schema. +# + +--disable_warnings +drop database if exists mysqltest_1; +--enable_warnings + +create database mysqltest_1; +delimiter //; +create procedure mysqltest_1.p1() +begin + select 1 from dual; +end// +delimiter ;// + +grant usage on *.* to mysqltest_1@localhost; + +connect (n1,localhost,mysqltest_1,,information_schema,$MASTER_MYPORT,$MASTER_MYSOCK); +connection n1; +--error 1370 +call mysqltest_1.p1(); +disconnect n1; + +connection default; + +drop procedure mysqltest_1.p1; +drop database mysqltest_1; + +revoke usage on *.* from mysqltest_1@localhost; +drop user mysqltest_1@localhost; + +# End of 5.0 bugs. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dae564a15c0..21fea8e5975 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -587,7 +587,7 @@ int quick_rm_table(enum db_type base,const char *db, const char *table_name); void close_cached_table(THD *thd, TABLE *table); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); -bool mysql_change_db(THD *thd,const char *name); +bool mysql_change_db(THD *thd,const char *name,bool no_access_check); void mysql_parse(THD *thd,char *inBuf,uint length); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); diff --git a/sql/sp.cc b/sql/sp.cc index 5dd7c613a10..4b50cf00119 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -427,7 +427,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) LEX *newlex= thd->lex; sp_head *sp= newlex->sphead; - if (dbchanged && (ret= sp_change_db(thd, olddb, 1))) + if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) goto done; if (sp) { @@ -438,7 +438,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) } else { - if (dbchanged && (ret= sp_change_db(thd, olddb, 1))) + if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) goto done; *sphp= thd->lex->sphead; (*sphp)->set_info((char *)definer, (uint)strlen(definer), @@ -594,7 +594,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) done: close_thread_tables(thd); if (dbchanged) - (void)sp_change_db(thd, olddb, 1); + (void)mysql_change_db(thd, olddb, 1); DBUG_RETURN(ret); } @@ -1612,112 +1612,10 @@ sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen, } else { - int ret= sp_change_db(thd, newdb, no_access_check); + int ret= mysql_change_db(thd, newdb, no_access_check); if (! ret) *dbchangedp= TRUE; DBUG_RETURN(ret); } } - -/* - Change database. - - SYNOPSIS - sp_change_db() - thd Thread handler - name Database name - empty_is_ok True= it's ok with "" as name - no_access_check True= don't do access check - - DESCRIPTION - This is the same as mysql_change_db(), but with some extra - arguments for Stored Procedure usage; doing implicit "use" - when executing an SP in a different database. - We also use different error routines, since this might be - invoked from a function when executing a query or statement. - Note: We would have prefered to reuse mysql_change_db(), but - the error handling in particular made that too awkward, so - we (reluctantly) have a "copy" here. - - RETURN VALUES - 0 ok - 1 error -*/ - -int -sp_change_db(THD *thd, char *name, bool no_access_check) -{ - int length, db_length; - char *dbname=my_strdup((char*) name,MYF(MY_WME)); - char path[FN_REFLEN]; - HA_CREATE_INFO create; - DBUG_ENTER("sp_change_db"); - DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check)); - - db_length= (!dbname ? 0 : strip_sp(dbname)); - if (dbname && db_length) - { - if ((db_length > NAME_LEN) || check_db_name(dbname)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), dbname); - x_free(dbname); - DBUG_RETURN(1); - } - } - - if (dbname && db_length) - { -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (! no_access_check) - { - ulong db_access; - - if (test_all_bits(thd->master_access,DB_ACLS)) - db_access=DB_ACLS; - else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); - if (!(db_access & DB_ACLS) && - (!grant_option || check_grant_db(thd,dbname))) - { - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, - dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); - } - } -#endif - (void) sprintf(path,"%s/%s",mysql_data_home,dbname); - length=unpack_dirname(path,path); // Convert if not unix - if (length && path[length-1] == FN_LIBCHAR) - path[length-1]=0; // remove ending '\' - if (access(path,F_OK)) - { - my_error(ER_BAD_DB_ERROR, MYF(0), dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); - } - } - - x_free(thd->db); - thd->db=dbname; // THD::~THD will free this - thd->db_length=db_length; - - if (dbname && db_length) - { - strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); - load_db_opt(thd, path, &create); - thd->db_charset= create.default_table_charset ? - create.default_table_charset : - thd->variables.collation_server; - thd->variables.collation_database= thd->db_charset; - } - DBUG_RETURN(0); -} diff --git a/sql/sp.h b/sql/sp.h index 9f110f87807..c278da863e0 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -112,8 +112,4 @@ int sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax, bool no_access_check, bool *dbchangedp); -// Like mysql_change_db() but handles empty db name and the send_ok() problem. -int -sp_change_db(THD *thd, char *db, bool no_access_check); - #endif /* _SP_H_ */ diff --git a/sql/sql_db.cc b/sql/sql_db.cc index d110ff6f778..67fc1053774 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -996,8 +996,9 @@ err: SYNOPSIS mysql_change_db() - thd Thread handler - name Databasename + thd Thread handler + name Databasename + no_access_check True= don't do access check DESCRIPTION Becasue the database name may have been given directly from the @@ -1009,15 +1010,16 @@ err: replication slave SQL thread (for that thread, setting of thd->db is done in ::exec_event() methods of log_event.cc). - This function does not send the error message to the client, if that - should be sent to the client, call net_send_error after this function + This function does not send anything, including error messages to the + client, if that should be sent to the client, call net_send_error after + this function. RETURN VALUES 0 ok 1 error */ -bool mysql_change_db(THD *thd, const char *name) +bool mysql_change_db(THD *thd, const char *name, bool no_access_check) { int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); @@ -1053,23 +1055,25 @@ bool mysql_change_db(THD *thd, const char *name) } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (test_all_bits(thd->master_access,DB_ACLS)) - db_access=DB_ACLS; - else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); - if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) - { - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, - dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); + if (!no_access_check) { + if (test_all_bits(thd->master_access,DB_ACLS)) + db_access=DB_ACLS; + else + db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | + thd->master_access); + if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) + { + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->priv_user, + thd->priv_host, + dbname); + mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), + thd->priv_user, + thd->priv_host, + dbname); + my_free(dbname,MYF(0)); + DBUG_RETURN(1); + } } #endif (void) sprintf(path,"%s/%s",mysql_data_home,dbname); @@ -1083,12 +1087,12 @@ bool mysql_change_db(THD *thd, const char *name) DBUG_RETURN(1); } end: - send_ok(thd); x_free(thd->db); thd->db=dbname; // THD::~THD will free this thd->db_length=db_length; #ifndef NO_EMBEDDED_ACCESS_CHECKS - thd->db_access=db_access; + if (!no_access_check) + thd->db_access=db_access; #endif if (schema_db) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fefe670432c..2c53dbbd2a3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -275,7 +275,7 @@ int check_user(THD *thd, enum enum_server_command command, { thd->db= 0; thd->db_length= 0; - if (mysql_change_db(thd, db)) + if (mysql_change_db(thd, db, FALSE)) { /* Send the error to the client */ net_send_error(thd); @@ -284,8 +284,7 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } } - else - send_ok(thd); + send_ok(thd); DBUG_RETURN(0); #else @@ -410,7 +409,7 @@ int check_user(THD *thd, enum enum_server_command command, /* Change database if necessary */ if (db && db[0]) { - if (mysql_change_db(thd, db)) + if (mysql_change_db(thd, db, FALSE)) { /* Send error to the client */ net_send_error(thd); @@ -419,8 +418,7 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } } - else - send_ok(thd); + send_ok(thd); thd->password= test(passwd_len); // remember for error messages /* Ready to handle queries */ DBUG_RETURN(0); @@ -1514,8 +1512,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, &LOCK_status); thd->convert_string(&tmp, system_charset_info, packet, strlen(packet), thd->charset()); - if (!mysql_change_db(thd, tmp.str)) + if (!mysql_change_db(thd, tmp.str, FALSE)) + { mysql_log.write(thd,command,"%s",thd->db); + send_ok(thd); + } break; } #ifdef HAVE_REPLICATION @@ -3407,7 +3408,8 @@ end_with_restore_list: } #endif case SQLCOM_CHANGE_DB: - mysql_change_db(thd,select_lex->db); + if (!mysql_change_db(thd,select_lex->db,FALSE)) + send_ok(thd); break; case SQLCOM_LOAD: From 7d1c4bc3c96bccdae1289bf40eb6464c7d1ec2d8 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Thu, 11 Aug 2005 17:14:11 -0700 Subject: [PATCH 089/230] Fix which include file is used to decide whether to skip rpl_openssl, the earlier change wasn't correct. (But the other changes to the test were.) --- mysql-test/t/rpl_openssl.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/rpl_openssl.test b/mysql-test/t/rpl_openssl.test index e15eb9b179a..3c151721d8e 100644 --- a/mysql-test/t/rpl_openssl.test +++ b/mysql-test/t/rpl_openssl.test @@ -1,4 +1,4 @@ -source include/have_openssl.inc; +source include/have_openssl_1.inc; source include/master-slave.inc; # We don't test all types of ssl auth params here since it's a bit hard From 898aae5e0f13a3461699e447a559247474a5b2e1 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Thu, 11 Aug 2005 18:58:22 -0700 Subject: [PATCH 090/230] Add SLEEP(seconds) function, which always returns 0 after the given number of seconds (which can include microseconds). (Bug #6760) --- mysql-test/r/func_misc.result | 11 +++++++++++ mysql-test/t/func_misc.test | 9 +++++++++ sql/item_create.cc | 5 +++++ sql/item_create.h | 1 + sql/item_func.cc | 11 +++++++++++ sql/item_func.h | 11 +++++++++++ sql/lex.h | 1 + 7 files changed, 49 insertions(+) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 5e74e6fa68a..670b8754e30 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -59,3 +59,14 @@ t1 CREATE TABLE `t1` ( `length(uuid())` int(10) NOT NULL default '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 (a timestamp default '2005-05-05 01:01:01', +b timestamp default '2005-05-05 01:01:01'); +insert into t1 set a = now(); +select sleep(3); +sleep(3) +0 +update t1 set b = now(); +select timediff(b, a) >= '00:00:03' from t1; +timediff(b, a) >= '00:00:03' +1 +drop table t1; diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 5079e2605ce..f4cbacb93bb 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -46,3 +46,12 @@ drop table t1; create table t1 as select uuid(), length(uuid()); show create table t1; drop table t1; + +# Bug #6760: Add SLEEP() function +create table t1 (a timestamp default '2005-05-05 01:01:01', + b timestamp default '2005-05-05 01:01:01'); +insert into t1 set a = now(); +select sleep(3); +update t1 set b = now(); +select timediff(b, a) >= '00:00:03' from t1; +drop table t1; diff --git a/sql/item_create.cc b/sql/item_create.cc index b7d8d50f9b3..8798bf889fc 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -354,6 +354,11 @@ Item *create_func_sha(Item* a) return new Item_func_sha(a); } +Item *create_func_sleep(Item* a) +{ + return new Item_func_sleep(a); +} + Item *create_func_space(Item *a) { CHARSET_INFO *cs= current_thd->variables.collation_connection; diff --git a/sql/item_create.h b/sql/item_create.h index 0a9af144ec0..d757318bfc1 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -83,6 +83,7 @@ Item *create_func_sec_to_time(Item* a); Item *create_func_sign(Item* a); Item *create_func_sin(Item* a); Item *create_func_sha(Item* a); +Item *create_func_sleep(Item* a); Item *create_func_soundex(Item* a); Item *create_func_space(Item *); Item *create_func_sqrt(Item* a); diff --git a/sql/item_func.cc b/sql/item_func.cc index 71e0f29ffc7..ef1c85f6120 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3259,6 +3259,17 @@ void Item_func_benchmark::print(String *str) str->append(')'); } +/* This function is just used to create tests with time gaps */ + +longlong Item_func_sleep::val_int() +{ + DBUG_ASSERT(fixed == 1); + double time= args[0]->val_real(); + my_sleep((ulong)time*1000000L); + return 0; +} + + #define extra_size sizeof(double) static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, diff --git a/sql/item_func.h b/sql/item_func.h index e8db9d70ae7..1f25b762b70 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -874,6 +874,7 @@ public: } }; + class Item_func_benchmark :public Item_int_func { ulong loop_count; @@ -888,6 +889,16 @@ public: }; +class Item_func_sleep :public Item_int_func +{ +public: + Item_func_sleep(Item *a) :Item_int_func(a) {} + const char *func_name() const { return "sleep"; } + longlong val_int(); +}; + + + #ifdef HAVE_DLOPEN class Item_udf_func :public Item_func diff --git a/sql/lex.h b/sql/lex.h index 122e7040c80..7b6d86e327e 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -734,6 +734,7 @@ static SYMBOL sql_functions[] = { { "SIN", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sin)}, { "SHA", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sha)}, { "SHA1", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sha)}, + { "SLEEP", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sleep)}, { "SOUNDEX", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_soundex)}, { "SPACE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_space)}, { "SQRT", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sqrt)}, From da441e949cdf873e54dc26600265e9a7f16a40df Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Fri, 12 Aug 2005 01:27:04 -0700 Subject: [PATCH 091/230] sql_base.cc: Fixed bug #12470. A misplaced initialization of the cond_count counter resulted in a wrong calculation of it. This caused a memory corruption since this counter was used as a parameter of some memory allocation. view.test: Added a test case for bug #12470. --- mysql-test/r/view.result | 13 +++++++++++++ mysql-test/t/view.test | 19 ++++++++++++++++++- sql/sql_base.cc | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index dcbdf3a99c4..87e80a03c08 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2079,3 +2079,16 @@ id f 2 foo2 DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (pk int PRIMARY KEY, b int); +CREATE TABLE t2 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE TABLE t3 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE TABLE t4 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE TABLE t5 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE VIEW v1 AS +SELECT t1.pk as a FROM t1,t2,t3,t4,t5 +WHERE t1.b IS NULL AND +t1.pk=t2.fk AND t2.pk=t3.fk AND t3.pk=t4.fk AND t4.pk=t5.fk; +SELECT a FROM v1; +a +DROP VIEW v1; +DROP TABLE t1,t2,t3,t4,t5; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 07724e8ff8d..961b8ec13d6 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1917,6 +1917,23 @@ SELECT * FROM v1; DROP VIEW v1; DROP TABLE t1; - +# +# Test for bug #12470: crash for a simple select from a view defined +# as a join over 5 tables + +CREATE TABLE t1 (pk int PRIMARY KEY, b int); +CREATE TABLE t2 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE TABLE t3 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE TABLE t4 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE TABLE t5 (pk int PRIMARY KEY, fk int, INDEX idx(fk)); +CREATE VIEW v1 AS + SELECT t1.pk as a FROM t1,t2,t3,t4,t5 + WHERE t1.b IS NULL AND + t1.pk=t2.fk AND t2.pk=t3.fk AND t3.pk=t4.fk AND t4.pk=t5.fk; + +SELECT a FROM v1; + +DROP VIEW v1; +DROP TABLE t1,t2,t3,t4,t5; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 949c398309c..b7b1fb7ff13 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3660,6 +3660,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, arena= 0; // For easier test thd->set_query_id=1; + select_lex->cond_count= 0; for (table= tables; table; table= table->next_local) { @@ -3667,7 +3668,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, goto err_no_arena; } - select_lex->cond_count= 0; if (*conds) { thd->where="where clause"; From 04056ffd3d6f300bc16d738f9450e93d42ef9f0b Mon Sep 17 00:00:00 2001 From: "osku@127.(none)" <> Date: Fri, 12 Aug 2005 11:39:19 +0300 Subject: [PATCH 092/230] InnoDB: Print more than 300 characters of queries in various error conditions, most notably deadlocked ones in SHOW INNODB STATUS. Fixes bug #7819. --- innobase/btr/btr0pcur.c | 2 +- innobase/include/trx0trx.h | 15 +++++---- innobase/lock/lock0lock.c | 8 ++--- innobase/row/row0ins.c | 6 ++-- innobase/row/row0sel.c | 6 ++-- innobase/row/row0umod.c | 2 +- innobase/row/row0upd.c | 2 +- innobase/srv/srv0srv.c | 2 +- innobase/trx/trx0trx.c | 25 ++++++++------- sql/ha_innodb.cc | 65 ++++++++++++++++++++++++++------------ 10 files changed, 81 insertions(+), 52 deletions(-) diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c index cb398b4afab..5dbbca0b17d 100644 --- a/innobase/btr/btr0pcur.c +++ b/innobase/btr/btr0pcur.c @@ -210,7 +210,7 @@ btr_pcur_restore_position( && cursor->pos_state != BTR_PCUR_IS_POSITIONED)) { ut_print_buf(stderr, (const byte*)cursor, sizeof(btr_pcur_t)); if (cursor->trx_if_known) { - trx_print(stderr, cursor->trx_if_known); + trx_print(stderr, cursor->trx_if_known, 0); } ut_error; diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index a3ef755348c..5dbf003594f 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -329,17 +329,20 @@ trx_commit_step( /*============*/ /* out: query thread to run next, or NULL */ que_thr_t* thr); /* in: query thread */ + /************************************************************************** -Prints info about a transaction to the standard output. The caller must -own the kernel mutex and must have called -innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL or -InnoDB cannot meanwhile change the info printed here. */ +Prints info about a transaction to the given file. The caller must own the +kernel mutex and must have called +innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL +or InnoDB cannot meanwhile change the info printed here. */ void trx_print( /*======*/ - FILE* f, /* in: output stream */ - trx_t* trx); /* in: transaction */ + FILE* f, /* in: output stream */ + trx_t* trx, /* in: transaction */ + uint max_query_len); /* in: max query length to print, or 0 to + use the default max length */ #ifndef UNIV_HOTBACKUP /************************************************************************** diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 280c4871ee9..1f222d71d6a 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -3297,7 +3297,7 @@ lock_deadlock_recursive( fputs("\n*** (1) TRANSACTION:\n", ef); - trx_print(ef, wait_lock->trx); + trx_print(ef, wait_lock->trx, 3000); fputs( "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n", ef); @@ -3310,7 +3310,7 @@ lock_deadlock_recursive( fputs("*** (2) TRANSACTION:\n", ef); - trx_print(ef, lock->trx); + trx_print(ef, lock->trx, 3000); fputs("*** (2) HOLDS THE LOCK(S):\n", ef); @@ -4207,7 +4207,7 @@ lock_print_info_all_transactions( while (trx) { if (trx->conc_state == TRX_NOT_STARTED) { fputs("---", file); - trx_print(file, trx); + trx_print(file, trx, 600); } trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); @@ -4239,7 +4239,7 @@ loop: if (nth_lock == 0) { fputs("---", file); - trx_print(file, trx); + trx_print(file, trx, 600); if (trx->read_view) { fprintf(file, diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index bce775c25d6..75d8117a73e 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -602,7 +602,7 @@ row_ins_foreign_report_err( rewind(ef); ut_print_timestamp(ef); fputs(" Transaction:\n", ef); - trx_print(ef, trx); + trx_print(ef, trx, 600); fputs("Foreign key constraint fails for table ", ef); ut_print_name(ef, trx, foreign->foreign_table_name); @@ -653,7 +653,7 @@ row_ins_foreign_report_add_err( rewind(ef); ut_print_timestamp(ef); fputs(" Transaction:\n", ef); - trx_print(ef, trx); + trx_print(ef, trx, 600); fputs("Foreign key constraint fails for table ", ef); ut_print_name(ef, trx, foreign->foreign_table_name); fputs(":\n", ef); @@ -1228,7 +1228,7 @@ run_again: rewind(ef); ut_print_timestamp(ef); fputs(" Transaction:\n", ef); - trx_print(ef, trx); + trx_print(ef, trx, 600); fputs("Foreign key constraint fails for table ", ef); ut_print_name(ef, trx, foreign->foreign_table_name); fputs(":\n", ef); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 57689520bfb..7328db1c65d 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2685,7 +2685,7 @@ row_sel_get_clust_rec_for_mysql( "InnoDB: clust index record ", stderr); rec_print(stderr, clust_rec, clust_index); putc('\n', stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 600); fputs("\n" "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); @@ -3128,7 +3128,7 @@ row_search_for_mysql( "InnoDB: Error: MySQL is trying to perform a SELECT\n" "InnoDB: but it has not locked any tables in ::external_lock()!\n", stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 600); fputc('\n', stderr); } @@ -3455,7 +3455,7 @@ shortcut_fails_too_big_rec: fputs( "InnoDB: Error: MySQL is trying to perform a consistent read\n" "InnoDB: but the read view is not assigned!\n", stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 600); fputc('\n', stderr); ut_a(0); } diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c index 0225a9faec5..f906027033f 100644 --- a/innobase/row/row0umod.c +++ b/innobase/row/row0umod.c @@ -431,7 +431,7 @@ row_undo_mod_del_unmark_sec_and_undo_update( "InnoDB: record ", stderr); rec_print(stderr, btr_pcur_get_rec(&pcur), index); putc('\n', stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 0); fputs("\n" "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } else { diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 514fb6bd577..4f44dbeae67 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -1279,7 +1279,7 @@ row_upd_sec_index_entry( rec_print(stderr, rec, index); putc('\n', stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 0); fputs("\n" "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index dc85750f0be..7e23b5c6090 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -999,7 +999,7 @@ retry: fputs( " InnoDB: Error: trying to declare trx to enter InnoDB, but\n" "InnoDB: it already is declared.\n", stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 0); putc('\n', stderr); os_fast_mutex_unlock(&srv_conc_mutex); diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 1681bed9af2..078befb81d2 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -30,8 +30,9 @@ Created 3/26/1996 Heikki Tuuri copy MUST be equal to the one in mysql/sql/ha_innodb.cc ! */ void innobase_mysql_print_thd( - FILE* f, - void* thd); + FILE* f, + void* thd, + uint max_query_len); /* Dummy session used currently in MySQL interface */ sess_t* trx_dummy_sess = NULL; @@ -262,7 +263,7 @@ trx_free( fputs( " InnoDB: Error: Freeing a trx which is declared to be processing\n" "InnoDB: inside InnoDB.\n", stderr); - trx_print(stderr, trx); + trx_print(stderr, trx, 600); putc('\n', stderr); } @@ -277,7 +278,7 @@ trx_free( (ulong)trx->n_mysql_tables_in_use, (ulong)trx->mysql_n_tables_locked); - trx_print(stderr, trx); + trx_print(stderr, trx, 600); ut_print_buf(stderr, (byte*)trx, sizeof(trx_t)); } @@ -1651,16 +1652,18 @@ trx_mark_sql_stat_end( } /************************************************************************** -Prints info about a transaction to the standard output. The caller must -own the kernel mutex and must have called -innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL or -InnoDB cannot meanwhile change the info printed here. */ +Prints info about a transaction to the given file. The caller must own the +kernel mutex and must have called +innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL +or InnoDB cannot meanwhile change the info printed here. */ void trx_print( /*======*/ - FILE* f, /* in: output stream */ - trx_t* trx) /* in: transaction */ + FILE* f, /* in: output stream */ + trx_t* trx, /* in: transaction */ + uint max_query_len) /* in: max query length to print, or 0 to + use the default max length */ { ibool newline; @@ -1755,7 +1758,7 @@ trx_print( } if (trx->mysql_thd != NULL) { - innobase_mysql_print_thd(f, trx->mysql_thd); + innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len); } } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0a01c08c916..9f1b5d34cce 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -550,19 +550,20 @@ innobase_mysql_end_print_arbitrary_thd(void) } /***************************************************************** -Prints info of a THD object (== user session thread) to the -standard output. NOTE that /mysql/innobase/trx/trx0trx.c must contain -the prototype for this function! */ +Prints info of a THD object (== user session thread) to the given file. +NOTE that /mysql/innobase/trx/trx0trx.c must contain the prototype for +this function! */ extern "C" void innobase_mysql_print_thd( /*=====================*/ - FILE* f, /* in: output stream */ - void* input_thd)/* in: pointer to a MySQL THD object */ + FILE* f, /* in: output stream */ + void* input_thd, /* in: pointer to a MySQL THD object */ + uint max_query_len) /* in: max query length to print, or 0 to + use the default max length */ { const THD* thd; const char* s; - char buf[301]; thd = (const THD*) input_thd; @@ -589,25 +590,47 @@ innobase_mysql_print_thd( } if ((s = thd->query)) { - /* determine the length of the query string */ - uint32 i, len; - - len = thd->query_length; + /* 3100 is chosen because currently 3000 is the maximum + max_query_len we ever give this. */ + char buf[3100]; + uint len; - if (len > 300) { - len = 300; /* ADDITIONAL SAFETY: print at most - 300 chars to reduce the probability of - a seg fault if there is a race in - thd->query_length in MySQL; after - May 14, 2004 probably no race any more, - but better be safe */ + /* If buf is too small, we dynamically allocate storage + in this. */ + char* dyn_str = NULL; + + /* Points to buf or dyn_str. */ + char* str = buf; + + if (max_query_len == 0) + { + /* ADDITIONAL SAFETY: the default is to print at + most 300 chars to reduce the probability of a + seg fault if there is a race in + thd->query_length in MySQL; after May 14, 2004 + probably no race any more, but better be + safe */ + max_query_len = 300; + } + + len = min(thd->query_length, max_query_len); + + if (len > (sizeof(buf) - 1)) + { + dyn_str = my_malloc(len + 1, MYF(0)); + str = dyn_str; } - /* Use strmake to reduce the timeframe - for a race, compared to fwrite() */ - i= (uint) (strmake(buf, s, len) - buf); + /* Use strmake to reduce the timeframe for a race, + compared to fwrite() */ + len = (uint) (strmake(str, s, len) - str); putc('\n', f); - fwrite(buf, 1, i, f); + fwrite(str, 1, len, f); + + if (dyn_str) + { + my_free(dyn_str, MYF(0)); + } } putc('\n', f); From 3f1f7102caf120c8ac0fc23eddce5c6ab0554209 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Fri, 12 Aug 2005 02:17:27 -0700 Subject: [PATCH 093/230] sql_view.cc: A safety correction. --- sql/sql_view.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index aedff648e5c..a910cdb2fbc 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1110,7 +1110,10 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) for (Field_translator *fld= trans; fld < end_of_trans; fld++) { if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item)) + { + thd->set_query_id= save_set_query_id; return TRUE; + } } thd->set_query_id= save_set_query_id; } From 869869fa0cc8c26ea7ee7474b016fd3cca5637e5 Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Fri, 12 Aug 2005 04:44:04 -0600 Subject: [PATCH 094/230] Bug #6581 Failure to start mysql server on Windows with AWE option enabled --- innobase/srv/srv0start.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 62df7301cc9..87f4c31257a 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1052,7 +1052,8 @@ innobase_start_or_create_for_mysql(void) fprintf(stderr, "InnoDB: Error: You have specified innodb_buffer_pool_awe_mem_mb\n" -"InnoDB: in my.cnf, but AWE can only be used in Windows 2000 and later.\n"); +"InnoDB: in my.cnf, but AWE can only be used in Windows 2000 and later.\n" +"InnoDB: To use AWE, InnoDB must be compiled with __WIN2000__ defined.\n"); return(DB_ERROR); } From 4c0d23e156d1148243ae8439c1115280e78ad04c Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Fri, 12 Aug 2005 13:54:42 +0300 Subject: [PATCH 095/230] Fixes during review of new pushed code Removed duplicate usage of TMP_TABLE_FORCE_MYISAM by making 'options' longlong --- sql/ha_berkeley.cc | 18 +++++------------- sql/ha_berkeley.h | 5 ++--- sql/ha_ndbcluster.cc | 2 ++ sql/init.cc | 3 +-- sql/item_sum.cc | 6 ++---- sql/mysql_priv.h | 19 +++++++++---------- sql/mysqld.cc | 4 ++-- sql/sql_class.h | 5 +++-- sql/sql_delete.cc | 4 ++-- sql/sql_derived.cc | 3 +-- sql/sql_lex.h | 2 +- sql/sql_parse.cc | 6 ++++-- sql/sql_select.cc | 17 ++++++++++++----- sql/sql_select.h | 8 ++++---- sql/sql_show.cc | 3 +-- sql/sql_union.cc | 5 +++-- sql/sql_update.cc | 2 +- sql/sql_yacc.yy | 22 ++++++++++++---------- 18 files changed, 67 insertions(+), 67 deletions(-) diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 793029ab4c7..105e4e26534 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -958,8 +958,6 @@ int ha_berkeley::write_row(byte * record) { DB_TXN *sub_trans = transaction; /* Don't use sub transactions in temporary tables */ - ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ? - table->in_use->options : 0); for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) { key_map changed_keys(0); @@ -1070,7 +1068,7 @@ int ha_berkeley::key_cmp(uint keynr, const byte * old_row, int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, const byte * old_row, DBT *old_key, const byte * new_row, DBT *new_key, - ulong thd_options, bool local_using_ignore) + bool local_using_ignore) { DBT row; int error; @@ -1119,8 +1117,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys, uint primary_key, const byte *old_row, DBT *old_key, - const byte *new_row, DBT *new_key, - ulong thd_options) + const byte *new_row, DBT *new_key) { int error; DBT tmp_key; @@ -1130,7 +1127,7 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys, /* Restore the old primary key, and the old row, but don't ignore duplicate key failure */ if ((error=update_primary_key(trans, TRUE, new_row, new_key, - old_row, old_key, thd_options, FALSE))) + old_row, old_key, FALSE))) goto err; /* purecov: inspected */ /* Remove the new key, and put back the old key @@ -1167,8 +1164,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) DBT prim_key, key, old_prim_key; int error; DB_TXN *sub_trans; - ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ? - table->in_use->options : 0); bool primary_key_changed; DBUG_ENTER("update_row"); LINT_INIT(error); @@ -1204,7 +1199,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) if (!(error=update_primary_key(sub_trans, primary_key_changed, old_row, &old_prim_key, new_row, &prim_key, - thd_options, using_ignore))) + using_ignore))) { // Update all other keys for (uint keynr=0 ; keynr < table->s->keys ; keynr++) @@ -1239,8 +1234,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) int new_error = 0; if (!changed_keys.is_clear_all()) new_error=restore_keys(transaction, &changed_keys, primary_key, - old_row, &old_prim_key, new_row, &prim_key, - thd_options); + old_row, &old_prim_key, new_row, &prim_key); if (new_error) { /* This shouldn't happen */ @@ -1342,8 +1336,6 @@ int ha_berkeley::delete_row(const byte * record) int error; DBT row, prim_key; key_map keys= table->s->keys_in_use; - ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ? - table->in_use->options : 0); DBUG_ENTER("delete_row"); statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status); diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index aa92908ecde..282641e3f25 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -74,13 +74,12 @@ class ha_berkeley: public handler DBT *prim_key, key_map *keys); int restore_keys(DB_TXN *trans, key_map *changed_keys, uint primary_key, const byte *old_row, DBT *old_key, - const byte *new_row, DBT *new_key, - ulong thd_options); + const byte *new_row, DBT *new_key); int key_cmp(uint keynr, const byte * old_row, const byte * new_row); int update_primary_key(DB_TXN *trans, bool primary_key_changed, const byte * old_row, DBT *old_key, const byte * new_row, DBT *prim_key, - ulong thd_options, bool local_using_ignore); + bool local_using_ignore); int read_row(int error, char *buf, uint keynr, DBT *row, DBT *key, bool); DBT *get_pos(DBT *to, byte *pos); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 7637b08c8ca..96d380d5ebb 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6997,6 +6997,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, break; Ndb_item *a= cond->next->ndb_item; Ndb_item *b, *field, *value= NULL; + LINT_INIT(field); + switch (cond->ndb_item->argument_count()) { case 1: field= diff --git a/sql/init.cc b/sql/init.cc index 4beb8db0c6f..e53eeab8902 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -39,12 +39,11 @@ void unireg_init(ulong options) #endif VOID(strmov(reg_ext,".frm")); - specialflag=SPECIAL_SAME_DB_NAME; + specialflag=SPECIAL_SAME_DB_NAME | options; /* Set options from argv */ /* Make a tab of powers of 10 */ for (i=0,nr=1.0; i < array_elements(log_10) ; i++) { /* It's used by filesort... */ log_10[i]= nr ; nr*= 10.0; } - specialflag|=options; /* Set options from argv */ DBUG_VOID_RETURN; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2d80a19aa55..e86d4f0d8ba 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2291,8 +2291,7 @@ bool Item_sum_count_distinct::setup(THD *thd) DBUG_ASSERT(table == 0); if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, 0, - (select_lex->options | thd->options) & - ~TMP_TABLE_FORCE_MYISAM, + (select_lex->options | thd->options), HA_POS_ERROR, (char*)""))) return TRUE; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows @@ -3074,8 +3073,7 @@ bool Item_func_group_concat::setup(THD *thd) */ if (!(table= create_tmp_table(thd, tmp_table_param, all_fields, (ORDER*) 0, 0, TRUE, - (select_lex->options | thd->options) & - ~TMP_TABLE_FORCE_MYISAM, + (select_lex->options | thd->options), HA_POS_ERROR, (char*) ""))) DBUG_RETURN(TRUE); table->file->extra(HA_EXTRA_NO_ROWS); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dae564a15c0..3dfd47d15c4 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -256,13 +256,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_WARNINGS (1L << 13) // THD, user #define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog #define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser -/* - Force the used temporary table to be a MyISAM table (because we will use - fulltext functions when reading from it. This uses the same constant as - OPTION_FOUND_COMMENT because we've run out of bits and these two values - are not used together. -*/ -#define TMP_TABLE_FORCE_MYISAM (1L << 15) #define OPTION_SAFE_UPDATES (1L << 16) // THD, user #define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user #define OPTION_BIN_LOG (1L << 18) // THD, user @@ -291,6 +284,11 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_SETUP_TABLES_DONE (1L << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ #define OPTION_SQL_NOTES (1L << 31) // THD, user +/* + Force the used temporary table to be a MyISAM table (because we will use + fulltext functions when reading from it. +*/ +#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32) /* Maximum length of time zone name that we support @@ -726,7 +724,7 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List &fields, enum enum_duplicates handle_duplicates, bool ignore); bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, - COND *conds, ulong options, + COND *conds, ulonglong options, enum enum_duplicates handle_duplicates, bool ignore, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, @@ -742,7 +740,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list); bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order, - ha_rows rows, ulong options); + ha_rows rows, ulonglong options); bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); @@ -1107,6 +1105,7 @@ extern char log_error_file[FN_REFLEN], *opt_tc_log_file; extern double log_10[32]; extern ulonglong log_10_int[20]; extern ulonglong keybuff_size; +extern ulonglong thd_startup_options; extern ulong refresh_version,flush_version, thread_id; extern ulong binlog_cache_use, binlog_cache_disk_use; extern ulong aborted_threads,aborted_connects; @@ -1116,7 +1115,7 @@ extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; -extern ulong thd_startup_options, slow_launch_threads, slow_launch_time; +extern ulong slow_launch_threads, slow_launch_time; extern ulong table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout, slave_trans_retries; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4989b0e623c..005232d48d9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -387,8 +387,8 @@ uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; uint volatile thread_count, thread_running; -ulong back_log, connect_timeout, concurrency; -ulong server_id, thd_startup_options; +ulonglong thd_startup_options; +ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, thread_stack, what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d3361d6c51..0b8205dfdb3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1246,7 +1246,8 @@ public: update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id, warn_id; - ulong options, thread_id, col_access; + ulonglong options; + ulong thread_id, col_access; /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; @@ -1498,7 +1499,7 @@ public: #define tmp_disable_binlog(A) \ - {ulong tmp_disable_binlog__save_options= (A)->options; \ + {ulonglong tmp_disable_binlog__save_options= (A)->options; \ (A)->options&= ~OPTION_BIN_LOG #define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;} diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b6183bf5acb..6c35653291d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -30,7 +30,7 @@ #include "sql_trigger.h" bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_LIST *order, ha_rows limit, ulong options) + SQL_LIST *order, ha_rows limit, ulonglong options) { int error; TABLE *table; @@ -807,7 +807,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) ha_enable_transaction(thd, FALSE); mysql_init_select(thd->lex); error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, - HA_POS_ERROR, 0); + HA_POS_ERROR, LL(0)); ha_enable_transaction(thd, TRUE); thd->options= save_options; DBUG_RETURN(error); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index afcf7dbd93f..fc9d15e94c4 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -142,8 +142,7 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) unit->types, (ORDER*) 0, FALSE, 1, (first_select->options | thd->options | - TMP_TABLE_ALL_COLUMNS) & - ~TMP_TABLE_FORCE_MYISAM, + TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, orig_table_list->alias))) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e8c65ba5100..977885e64f2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -305,7 +305,7 @@ protected: *link_next, **link_prev; /* list of whole SELECT_LEX */ public: - ulong options; + ulonglong options; /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dbf30cc0c56..8895130e6e9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2943,8 +2943,8 @@ end_with_restore_list: */ if (thd->locked_tables || thd->active_transaction()) { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), - MYF(0)); + my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, + ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); goto error; } { @@ -6465,11 +6465,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count; for (; lock_p < end_p; lock_p++) + { if ((*lock_p)->type == TL_WRITE) { my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); return 1; } + } } /* Writing to the binlog could cause deadlocks, as we don't log diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 630406dba07..bcc2b59e89d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1016,7 +1016,7 @@ JOIN::optimize() group_list : (ORDER*) 0), group_list ? 0 : select_distinct, group_list && simple_group, - select_options & ~TMP_TABLE_FORCE_MYISAM, + select_options, (order == 0 || skip_sort_order) ? select_limit : HA_POS_ERROR, (char *) ""))) @@ -1287,7 +1287,15 @@ JOIN::exec() if (need_tmp) { if (tmp_join) + { + /* + We are in a non cacheable sub query. Get the saved join structure + after optimization. + (curr_join may have been modified during last exection and we need + to reset it) + */ curr_join= tmp_join; + } curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ @@ -1397,8 +1405,7 @@ JOIN::exec() (ORDER*) 0, curr_join->select_distinct && !curr_join->group_list, - 1, curr_join->select_options - & ~TMP_TABLE_FORCE_MYISAM, + 1, curr_join->select_options, HA_POS_ERROR, (char *) ""))) DBUG_VOID_RETURN; @@ -8128,7 +8135,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, - ulong select_options, ha_rows rows_limit, + ulonglong select_options, ha_rows rows_limit, char *table_alias) { TABLE *table; @@ -8382,7 +8389,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, /* If result table is small; use a heap */ if (blob_count || using_unique_constraint || (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == - OPTION_BIG_TABLES ||(select_options & TMP_TABLE_FORCE_MYISAM)) + OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM)) { table->file=get_new_handler(table,table->s->db_type= DB_TYPE_MYISAM); if (group && diff --git a/sql/sql_select.h b/sql/sql_select.h index 3b9a3093682..78fa88801be 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -202,7 +202,7 @@ class JOIN :public Sql_alloc Item *having; Item *tmp_having; // To store having when processed temporary table Item *having_history; // Store having for explain - uint select_options; + ulonglong select_options; select_result *result; TMP_TABLE_PARAM tmp_table_param; MYSQL_LOCK *lock; @@ -258,14 +258,14 @@ class JOIN :public Sql_alloc bool union_part; // this subselect is part of union bool optimized; // flag to avoid double optimization in EXPLAIN - JOIN(THD *thd_arg, List &fields_arg, ulong select_options_arg, + JOIN(THD *thd_arg, List &fields_arg, ulonglong select_options_arg, select_result *result_arg) :fields_list(fields_arg) { init(thd_arg, fields_arg, select_options_arg, result_arg); } - void init(THD *thd_arg, List &fields_arg, ulong select_options_arg, + void init(THD *thd_arg, List &fields_arg, ulonglong select_options_arg, select_result *result_arg) { join_tab= join_tab_save= 0; @@ -437,7 +437,7 @@ void TEST_join(JOIN *join); bool store_val_in_field(Field *field,Item *val); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, - ulong select_options, ha_rows rows_limit, + ulonglong select_options, ha_rows rows_limit, char* alias); TABLE *create_virtual_tmp_table(THD *thd, List &field_list); void free_tmp_table(THD *thd, TABLE *entry); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1c0519475b4..c558d5de7bf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3332,8 +3332,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->options | - TMP_TABLE_ALL_COLUMNS) & - ~TMP_TABLE_FORCE_MYISAM, + TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, table_list->alias))) DBUG_RETURN(0); table_list->schema_table_param= tmp_table_param; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index cdbe8a986b2..72c96e81682 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -289,6 +289,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, List_iterator_fast tp(types); Query_arena *arena= thd->current_arena; Item *type; + ulonglong create_options; while ((type= tp++)) { @@ -300,8 +301,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - ulong create_options= (first_select_in_union()->options | thd_arg->options | - TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; + create_options= (first_select_in_union()->options | thd_arg->options | + TMP_TABLE_ALL_COLUMNS); /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading diff --git a/sql/sql_update.cc b/sql/sql_update.cc index aa39140f9b1..1a9ef2fff62 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -811,7 +811,7 @@ bool mysql_multi_update(THD *thd, List *fields, List *values, COND *conds, - ulong options, + ulonglong options, enum enum_duplicates handle_duplicates, bool ignore, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 849987a267c..1d9413d2cf7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7752,7 +7752,8 @@ sys_option_value: /* We are in trigger and assigning value to field of new row */ Item *it; Item_trigger_field *trg_fld; - sp_instr_set_trigger_field *i; + sp_instr_set_trigger_field *sp_fld; + LINT_INIT(sp_fld); if ($1) { yyerror(ER(ER_SYNTAX_ERROR)); @@ -7770,10 +7771,11 @@ sys_option_value: context, Item_trigger_field::NEW_ROW, $2.base_name.str)) || - !(i= new sp_instr_set_trigger_field(lex->sphead-> - instructions(), - lex->spcont, trg_fld, - it, lex))) + !(sp_fld= new sp_instr_set_trigger_field(lex->sphead-> + instructions(), + lex->spcont, + trg_fld, + it, lex))) YYABORT; /* @@ -7783,7 +7785,7 @@ sys_option_value: lex->trg_table_fields.link_in_list((byte *)trg_fld, (byte **)&trg_fld->next_trg_field); - lex->sphead->add_instr(i); + lex->sphead->add_instr(sp_fld); } else if ($2.var) { /* System variable */ @@ -7797,7 +7799,7 @@ sys_option_value: /* An SP local variable */ sp_pcontext *ctx= lex->spcont; sp_pvar_t *spv; - sp_instr_set *i; + sp_instr_set *sp_set; Item *it; if ($1) { @@ -7813,9 +7815,9 @@ sys_option_value: it= spv->dflt; else it= new Item_null(); - i= new sp_instr_set(lex->sphead->instructions(), ctx, - spv->offset, it, spv->type, lex, TRUE); - lex->sphead->add_instr(i); + sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, + spv->offset, it, spv->type, lex, TRUE); + lex->sphead->add_instr(sp_set); spv->isset= TRUE; } } From 4a071b48333d0be0c53a50c99d6abc544f293645 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Fri, 12 Aug 2005 18:13:42 +0500 Subject: [PATCH 096/230] item_strfunc.cc: After merge change. 4.1 method was replaced in 5.0. --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 11c763ee173..094a0c56319 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1570,7 +1570,7 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs) return NULL; } conv->str_value.copy(); - conv->str_value.shrink_to_length(); + conv->str_value.mark_as_const(); return conv; } From a247282aa6270e809f4ad3f5205dc79ca7be8ec0 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Fri, 12 Aug 2005 17:57:19 +0300 Subject: [PATCH 097/230] Implementation of WL#2486 - "Process NATURAL and USING joins according to SQL:2003". * Some of the main problems fixed by the patch: - in "select *" queries the * expanded correctly according to ANSI for arbitrary natural/using joins - natural/using joins are correctly transformed into JOIN ... ON for any number/nesting of the joins. - column references are correctly resolved against natural joins of any nesting and combined with arbitrary other joins. * This patch also contains a fix for name resolution of items inside the ON condition of JOIN ... ON - in this case items must be resolved only against the JOIN operands. To support such 'local' name resolution, the patch introduces a stack of name resolution contexts used at parse time. NOTICE: - This patch is not complete in the sense that - there are 2 test cases that still do not pass - one in join.test, one in select.test. Both are marked with a comment "TODO: WL#2486". - it does not include a new test specific for the task --- mysql-test/include/ps_query.inc | 12 +- mysql-test/r/bdb.result | 4 +- mysql-test/r/derived.result | 4 +- mysql-test/r/errors.result | 4 +- mysql-test/r/fulltext.result | 16 +- mysql-test/r/fulltext_order_by.result | 4 +- mysql-test/r/innodb.result | 4 +- mysql-test/r/insert_select.result | 4 +- mysql-test/r/join.result | 99 +- mysql-test/r/join_crash.result | 15 +- mysql-test/r/join_nested.result | 87 +- mysql-test/r/join_outer.result | 134 +- mysql-test/r/multi_update.result | 16 +- mysql-test/r/null_key.result | 14 +- mysql-test/r/order_by.result | 8 +- mysql-test/r/ps_2myisam.result | 174 +-- mysql-test/r/ps_3innodb.result | 174 +-- mysql-test/r/ps_4heap.result | 174 +-- mysql-test/r/ps_5merge.result | 348 ++--- mysql-test/r/ps_6bdb.result | 174 +-- mysql-test/r/ps_7ndb.result | 174 +-- mysql-test/r/select.result | 304 ++--- mysql-test/r/subselect.result | 8 +- mysql-test/r/type_ranges.result | 6 +- mysql-test/r/union.result | 2 +- mysql-test/t/bdb.test | 4 +- mysql-test/t/errors.test | 4 +- mysql-test/t/fulltext.test | 12 +- mysql-test/t/fulltext_order_by.test | 4 +- mysql-test/t/innodb.test | 4 +- mysql-test/t/insert_select.test | 4 +- mysql-test/t/join.test | 20 +- mysql-test/t/join_crash.test | 15 +- mysql-test/t/join_nested.test | 61 +- mysql-test/t/join_outer.test | 33 +- mysql-test/t/null_key.test | 16 +- mysql-test/t/order_by.test | 8 +- mysql-test/t/select.test | 26 +- mysql-test/t/subselect.test | 8 +- mysql-test/t/type_ranges.test | 6 +- mysql-test/t/union.test | 2 +- sql/item.cc | 29 +- sql/item.h | 31 +- sql/mysql_priv.h | 39 +- sql/sp.cc | 3 +- sql/sql_acl.cc | 27 +- sql/sql_base.cc | 1799 +++++++++++++++++-------- sql/sql_class.h | 6 + sql/sql_delete.cc | 2 + sql/sql_help.cc | 8 +- sql/sql_insert.cc | 126 +- sql/sql_lex.cc | 20 +- sql/sql_lex.h | 46 +- sql/sql_load.cc | 1 + sql/sql_olap.cc | 2 +- sql/sql_parse.cc | 204 ++- sql/sql_select.cc | 19 +- sql/sql_show.cc | 5 + sql/sql_update.cc | 4 +- sql/sql_yacc.yy | 191 ++- sql/table.cc | 473 +++++++ sql/table.h | 213 ++- tests/mysql_client_test.c | 4 +- 63 files changed, 3549 insertions(+), 1893 deletions(-) diff --git a/mysql-test/include/ps_query.inc b/mysql-test/include/ps_query.inc index 27a86f88231..97653c0b9f8 100644 --- a/mysql-test/include/ps_query.inc +++ b/mysql-test/include/ps_query.inc @@ -349,14 +349,14 @@ drop table if exists t2 ; --enable_warnings create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; let $1= 9 ; while ($1) { diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index 876da3cb964..a0b68bfbc13 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -732,7 +732,7 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=bdb; insert into t1 (a) values(1),(2),(3); -select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; +select a from t1 natural join t1 as t2 where b >= @a order by a; a 1 2 @@ -906,7 +906,7 @@ create temporary table tmp1 select branch_id, target_id, platform_id, product_id from t1, t2, t3, t4 ; create temporary table tmp2 -select tmp1.branch_id, tmp1.target_id, tmp1.platform_id, tmp1.product_id +select branch_id, target_id, platform_id, product_id from tmp1 left join t8 using (branch_id,target_id,platform_id,product_id) where t8.archive_id is null ; diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index fd6a834c694..586be94301f 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -149,8 +149,8 @@ SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b; (SELECT * FROM (SELECT 1 as a) as a ) 1 select * from (select 1 as a) b left join (select 2 as a) c using(a); -a a -1 NULL +a +1 SELECT * FROM (SELECT 1 UNION SELECT a) b; ERROR 42S22: Unknown column 'a' in 'field list' SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result index d0011c8deb6..6a0791c8ca3 100644 --- a/mysql-test/r/errors.result +++ b/mysql-test/r/errors.result @@ -9,9 +9,9 @@ create table t1 (a int); select count(test.t1.b) from t1; ERROR 42S22: Unknown column 'test.t1.b' in 'field list' select count(not_existing_database.t1) from t1; -ERROR 42S02: Unknown table 'not_existing_database' in field list +ERROR 42S22: Unknown column 'not_existing_database.t1' in 'field list' select count(not_existing_database.t1.a) from t1; -ERROR 42S02: Unknown table 'not_existing_database.t1' in field list +ERROR 42S22: Unknown column 'not_existing_database.t1.a' in 'field list' select count(not_existing_database.t1.a) from not_existing_database.t1; Got one of the listed errors select 1 from t1 order by 2; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 1a79f6d9736..27b3be39161 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -221,14 +221,14 @@ select t1.id FROM t2 as ttxt,t1,t1 as ticket2 WHERE ticket2.id = ttxt.ticket AND t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); id -select t1.id FROM t2 as ttxt,t1 INNER JOIN t1 as ticket2 ON -ticket2.id = ttxt.ticket -WHERE t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); +select ticket2.id FROM t2 as ttxt,t2 INNER JOIN t1 as ticket2 ON +ticket2.id = t2.ticket +WHERE ticket2.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); id INSERT INTO t1 VALUES (3,3); -select t1.id FROM t2 as ttxt,t1 -INNER JOIN t1 as ticket2 ON ticket2.id = ttxt.ticket -WHERE t1.id = ticket2.ticket and +select ticket2.id FROM t2 as ttxt,t2 +INNER JOIN t1 as ticket2 ON ticket2.id = t2.ticket +WHERE ticket2.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); id 3 @@ -337,8 +337,8 @@ insert into t2 values (1, 1, 'xxfoo'); insert into t2 values (2, 1, 'xxbar'); insert into t2 values (3, 1, 'xxbuz'); select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); -t1_id name t2_id t1_id name -1 data1 1 1 xxfoo +t1_id name t2_id name +1 data1 1 xxfoo select * from t2 where match name against ('*a*b*c*d*e*f*' in boolean mode); t2_id t1_id name drop table t1,t2; diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index 3b52be4b1f2..e80a4daefe8 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -126,7 +126,7 @@ group by a.text, b.id, b.betreff order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42S02: Unknown table 'b' in order clause +ERROR 42S22: Unknown column 'b.betreff' in 'order clause' select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -142,7 +142,7 @@ where match(c.beitrag) against ('+abc' in boolean mode) order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42S02: Unknown table 'b' in order clause +ERROR 42S22: Unknown column 'b.betreff' in 'order clause' select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 2bdec5125dd..ffdc3f1ca59 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -750,7 +750,7 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb; insert into t1 (a) values(1),(2),(3); -select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; +select a from t1 natural join t1 as t2 where b >= @a order by a; a 1 2 @@ -1377,7 +1377,7 @@ ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fail update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -ERROR 42S02: Unknown table 't1' in where clause +ERROR 42S22: Unknown column 't1.id' in 'where clause' drop table t3,t2,t1; create table t1( id int primary key, diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index f745af182eb..17f65d96abc 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -664,7 +664,7 @@ insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; ERROR 23000: Column 'a' in field list is ambiguous insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; -ERROR 42S02: Unknown table 't2' in field list +ERROR 42S22: Unknown column 't2.a' in 'field list' insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; -ERROR 42S02: Unknown table 't2' in field list +ERROR 42S22: Unknown column 't2.b' in 'field list' drop table t1,t2,t3; diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index dc763472b0e..5ea863b4bdb 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -10,21 +10,21 @@ SELECT * FROM t1 INNER JOIN t2; S1 S1 1 2 SELECT * from t1 JOIN t2 USING (S1); -S1 S1 +S1 SELECT * FROM t1 INNER JOIN t2 USING (S1); -S1 S1 +S1 SELECT * from t1 CROSS JOIN t2; S1 S1 1 2 SELECT * from t1 LEFT JOIN t2 USING(S1); -S1 S1 -1 NULL +S1 +1 SELECT * from t1 LEFT JOIN t2 ON(t2.S1=2); S1 S1 1 2 SELECT * from t1 RIGHT JOIN t2 USING(S1); -S1 S1 -NULL 2 +S1 +2 SELECT * from t1 RIGHT JOIN t2 ON(t1.S1=1); S1 S1 1 2 @@ -121,11 +121,11 @@ id catid stateid countyid drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); -select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); a 1 2 -select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); ERROR HY000: Too many tables; MySQL can only use XX tables in a join drop table t1; CREATE TABLE t1 ( @@ -145,10 +145,9 @@ DROP TABLE t1, t2; CREATE TABLE t1 (d DATE NOT NULL); CREATE TABLE t2 (d DATE NOT NULL); INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00'); -SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL; -d d -2001-08-01 NULL -0000-00-00 NULL +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL; +d +0000-00-00 SELECT * from t1 WHERE t1.d IS NULL; d 0000-00-00 @@ -265,10 +264,10 @@ PRIMARY KEY (siteid,rate_code), FULLTEXT KEY rate_code (rate_code) ) ENGINE=MyISAM; INSERT INTO t2 VALUES ('rivercats','cust',20); -SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats'; rate_code base_rate cust 20 -SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith'; rate_code base_rate cust 20 drop table t1,t2; @@ -296,79 +295,79 @@ insert into t1 values(1),(2); insert into t2 values(2),(3); insert into t3 values (2),(4); select * from t1 natural left join t2; -i i -1 NULL -2 2 +i +1 +2 select * from t1 left join t2 on (t1.i=t2.i); i i 1 NULL 2 2 select * from t1 natural left join t2 natural left join t3; -i i i -1 NULL NULL -2 2 2 +i +1 +2 select * from t1 left join t2 on (t1.i=t2.i) left join t3 on (t2.i=t3.i); i i i 1 NULL NULL 2 2 2 select * from t3 natural right join t2; -i i -2 2 -NULL 3 +i +2 +3 select * from t3 right join t2 on (t3.i=t2.i); i i 2 2 NULL 3 select * from t3 natural right join t2 natural right join t1; -i i i -NULL NULL 1 -2 2 2 +i +1 +2 select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); i i i NULL NULL 1 2 2 2 -select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; -i i i -1 2 2 -1 3 NULL -2 2 2 -2 3 NULL +select * from t1,t2 natural left join t3 order by 1,2; +i i +1 2 +1 3 +2 2 +2 3 select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; i i i 1 2 2 1 3 NULL 2 2 2 2 3 NULL -select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; -i i i -1 2 2 -1 3 NULL -2 2 2 -2 3 NULL +select * from t2 natural left join t3,t1 order by t1.i; +i i +2 1 +3 1 +2 2 +3 2 select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; i i i 1 2 2 1 3 NULL 2 2 2 2 3 NULL -select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; -i i i -1 NULL 4 -1 2 2 -2 NULL 4 -2 2 2 +select * from t1,t2 natural right join t3 order by 1,2; +i i +1 2 +1 4 +2 2 +2 4 select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; i i i 1 NULL 4 1 2 2 2 NULL 4 2 2 2 -select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; -i i i -1 NULL 4 -1 2 2 -2 NULL 4 -2 2 2 +select * from t2 natural right join t3,t1 order by t1.i; +i i +2 1 +4 1 +2 2 +4 2 select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; i i i 1 NULL 4 diff --git a/mysql-test/r/join_crash.result b/mysql-test/r/join_crash.result index c1671ea7e20..f1a3b4956a8 100644 --- a/mysql-test/r/join_crash.result +++ b/mysql-test/r/join_crash.result @@ -75,18 +75,11 @@ t1.client_ptr as client_ptr, t1.comments as comments, sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget from -t1 , t2 as client_period , -t2 as project_period -left join -t3 -on -t3.project_ptr = t1.project_id -and t3.date_received <= '2001-03-22 14:15:09' - left join -t4 -on -t4.client_id = t1.client_ptr +t2 as project_period, +t3 left join t1 on (t3.project_ptr = t1.project_id and +t3.date_received <= '2001-03-22 14:15:09') +left join t4 on t4.client_id = t1.client_ptr where 1 and ( client_period.period_type = 'client_table' diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 27edac1b30b..8bc2b1843b2 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -223,8 +223,7 @@ a b 1 2 EXPLAIN EXTENDED SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b -FROM t6, -t7 +FROM (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10; @@ -235,8 +234,7 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select `test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b` from `test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t7`.`b` = `test`.`t8`.`b`) and (`test`.`t6`.`b` < 10))) where 1 SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b -FROM t6, -t7 +FROM (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10; @@ -260,8 +258,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b FROM t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -279,8 +276,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b FROM t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -312,8 +308,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -357,8 +352,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -397,8 +391,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -470,8 +463,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -537,8 +529,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -575,8 +566,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -625,8 +615,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -679,8 +668,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -825,44 +813,38 @@ a b a b a b a b 1 3 5 3 NULL NULL NULL NULL 2 2 5 3 NULL NULL NULL NULL SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b -FROM t1, t3, t4 +FROM t1, (t3, t4) RIGHT JOIN t2 ON t3.a=1 AND t2.b=t4.b WHERE t1.a <= 2; a b a b a b a b -1 3 3 3 1 2 NULL NULL -1 3 3 3 2 2 NULL NULL -2 2 3 3 1 2 NULL NULL -2 2 3 3 2 2 NULL NULL +1 3 3 3 NULL NULL NULL NULL +2 2 3 3 NULL NULL NULL NULL 1 3 4 2 1 2 3 2 1 3 4 2 1 2 4 2 -1 3 4 2 2 2 NULL NULL 2 2 4 2 1 2 3 2 2 2 4 2 1 2 4 2 -2 2 4 2 2 2 NULL NULL -1 3 5 3 1 2 NULL NULL -1 3 5 3 2 2 NULL NULL -2 2 5 3 1 2 NULL NULL -2 2 5 3 2 2 NULL NULL +1 3 5 3 NULL NULL NULL NULL +2 2 5 3 NULL NULL NULL NULL EXPLAIN EXTENDED SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b -FROM t1, t3, t4 +FROM t1, (t3, t4) RIGHT JOIN t2 ON t3.a=1 AND t2.b=t4.b WHERE t1.a <= 2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 1 SIMPLE t4 ALL NULL NULL NULL NULL 2 Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t3` join `test`.`t2` left join `test`.`t4` on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) where (`test`.`t1`.`a` <= 2) +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) where (`test`.`t1`.`a` <= 2) CREATE INDEX idx_b ON t2(b); EXPLAIN EXTENDED SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b -FROM t3,t4 +FROM (t3,t4) LEFT JOIN (t1,t2) ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; @@ -874,7 +856,7 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t3` join `test`.`t4` left join (`test`.`t1` join `test`.`t2`) on(((`test`.`t3`.`a` = 1) and (`test`.`t3`.`b` = `test`.`t2`.`b`) and (`test`.`t2`.`b` = `test`.`t4`.`b`))) where 1 SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b -FROM t3,t4 +FROM (t3,t4) LEFT JOIN (t1,t2) ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; @@ -900,8 +882,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -951,8 +932,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -1001,8 +981,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -1052,8 +1031,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -1100,8 +1078,7 @@ ON t3.a=1 AND t2.b=t4.b, t5 LEFT JOIN ( -t6, -t7 +(t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -1176,13 +1153,13 @@ a b a1 b 4 2 1 2 4 2 2 2 5 3 NULL NULL -SELECT t2.a,t2.b,t3.a1,t3.b +SELECT * FROM t2 NATURAL LEFT JOIN t3 WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); -a b a1 b -4 2 1 2 -4 2 2 2 -5 3 NULL NULL +b a c a1 c1 +2 4 0 1 0 +2 4 0 2 0 +3 5 0 NULL NULL DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; CREATE TABLE t1 (a int); CREATE TABLE t2 (a int); diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index b75eadd5291..9bc85dfa987 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -36,7 +36,16 @@ grp a c id a c d 3 5 C 3 5 B 5 3 6 D 3 6 C 6 NULL NULL NULL 4 7 D 7 -select t1.*,t2.* from t1 left join t2 using (a); +select * from t1 left join t2 using (a); +a grp c id c d +1 1 a 1 a 1 +2 2 b NULL NULL NULL +3 2 c NULL NULL NULL +4 3 E 3 A 4 +5 3 C 3 B 5 +6 3 D 3 C 6 +NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 left join t2 on t1.a=t2.a; grp a c id a c d 1 1 a 1 1 a 1 2 2 b NULL NULL NULL NULL @@ -45,40 +54,34 @@ grp a c id a c d 3 5 C 3 5 B 5 3 6 D 3 6 C 6 NULL NULL NULL NULL NULL NULL -select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a; -grp a c id a c d -1 1 a 1 1 a 1 -3 4 E 3 4 A 4 -3 5 C 3 5 B 5 -3 6 D 3 6 C 6 -select t1.*,t2.* from t1 left join t2 using (a,c); -grp a c id a c d -1 1 a 1 1 a 1 -2 2 b NULL NULL NULL NULL -2 3 c NULL NULL NULL NULL -3 4 E NULL NULL NULL NULL -3 5 C NULL NULL NULL NULL -3 6 D NULL NULL NULL NULL -NULL NULL NULL NULL NULL NULL -select t1.*,t2.* from t1 left join t2 using (c); -grp a c id a c d -1 1 a 1 1 a 1 -1 1 a 3 4 A 4 -2 2 b 3 5 B 5 -2 3 c 3 6 C 6 -3 4 E NULL NULL NULL NULL -3 5 C 3 6 C 6 -3 6 D 4 7 D 7 -NULL NULL NULL NULL NULL NULL -select t1.*,t2.* from t1 natural left outer join t2; -grp a c id a c d -1 1 a 1 1 a 1 -2 2 b NULL NULL NULL NULL -2 3 c NULL NULL NULL NULL -3 4 E NULL NULL NULL NULL -3 5 C NULL NULL NULL NULL -3 6 D NULL NULL NULL NULL -NULL NULL NULL NULL NULL NULL +select * from t1 left join t2 using (a,c); +a c grp id d +1 a 1 1 1 +2 b 2 NULL NULL +3 c 2 NULL NULL +4 E 3 NULL NULL +5 C 3 NULL NULL +6 D 3 NULL NULL +NULL NULL NULL NULL +select * from t1 left join t2 using (c); +c grp a id a d +a 1 1 1 1 1 +a 1 1 3 4 4 +b 2 2 3 5 5 +c 2 3 3 6 6 +E 3 4 NULL NULL NULL +C 3 5 3 6 6 +D 3 6 4 7 7 + NULL NULL NULL NULL NULL +select * from t1 natural left outer join t2; +a c grp id d +1 a 1 1 1 +2 b 2 NULL NULL +3 c 2 NULL NULL +4 E 3 NULL NULL +5 C 3 NULL NULL +6 D 3 NULL NULL +NULL NULL NULL NULL select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3; grp a c id a c d 3 4 E 3 4 A 4 @@ -106,26 +109,26 @@ grp a c id a c d a 3 6 D 3 6 C 6 6 NULL NULL NULL NULL NULL NULL NULL explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); -ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions +ERROR 42S22: Unknown column 't3.a' in 'on clause' select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); -ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions +ERROR 42S22: Unknown column 't3.a' in 'on clause' select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); -ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions -select t1.*,t2.* from t1 inner join t2 using (a); -grp a c id a c d -1 1 a 1 1 a 1 -3 4 E 3 4 A 4 -3 5 C 3 5 B 5 -3 6 D 3 6 C 6 +ERROR 42S22: Unknown column 't3.a' in 'on clause' +select * from t1 inner join t2 using (a); +a grp c id c d +1 1 a 1 a 1 +4 3 E 3 A 4 +5 3 C 3 B 5 +6 3 D 3 C 6 select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a); grp a c id a c d 1 1 a 1 1 a 1 3 4 E 3 4 A 4 3 5 C 3 5 B 5 3 6 D 3 6 C 6 -select t1.*,t2.* from t1 natural join t2; -grp a c id d -1 1 a 1 1 +select * from t1 natural join t2; +a c grp id d +1 a 1 1 1 drop table t1,t2; CREATE TABLE t1 ( usr_id INT unsigned NOT NULL, @@ -400,7 +403,7 @@ insert into t3 values (1); insert into t4 values (1,1); insert into t5 values (1,1); explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23; -ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions +ERROR 42S22: Unknown column 't2.t2_id' in 'on clause' drop table t1,t2,t3,t4,t5; create table t1 (n int, m int, o int, key(n)); create table t2 (n int not null, m int, o int, primary key(n)); @@ -432,7 +435,7 @@ INSERT INTO t2 VALUES (3,'z'); SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL; id2 3 -SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; +SELECT id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; id2 3 drop table t1,t2; @@ -461,10 +464,10 @@ count color 15 white 7 green select * from t2 natural join t1; -count color name -10 green lime -7 green lime -5 black grape +color count name +green 10 lime +green 7 lime +black 5 grape select t2.count, t1.name from t2 natural join t1; count name 10 lime @@ -647,16 +650,15 @@ insert into t1 values(1),(2); insert into t2 values(2),(3); insert into t3 values(2),(4); select * from t1 natural left join t2 natural left join t3; -i i i -1 NULL NULL -2 2 2 -select * from t1 natural left join t2 where (t2.i is not null)=0; -i i -1 NULL -select * from t1 natural left join t2 where (t2.i is not null) is not null; -i i -1 NULL -2 2 +i +1 +2 +select * from t1 natural left join t2 where (i is not null)=0; +i +select * from t1 natural left join t2 where (i is not null) is not null; +i +1 +2 drop table t1,t2,t3; create table t1 (f1 integer,f2 integer,f3 integer); create table t2 (f2 integer,f4 integer); @@ -664,7 +666,7 @@ create table t3 (f3 integer,f5 integer); select * from t1 left outer join t2 using (f2) left outer join t3 using (f3); -ERROR 42S22: Unknown column 'test.t2.f3' in 'on clause' +f3 f2 f1 f4 f5 drop table t1,t2,t3; create table t1 (a1 int, a2 int); create table t2 (b1 int not null, b2 int); @@ -929,13 +931,13 @@ create table t1 (a int, b varchar(20)); create table t2 (a int, c varchar(20)); insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); -select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; group_concat(t1.b,t2.c) aaaaa bbbbb Warnings: Warning 1260 2 line(s) were cut by GROUP_CONCAT() -select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; group_concat(t1.b,t2.c) aaaaa bbbbb diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index f5c4e19af64..ea02a703c65 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -135,16 +135,16 @@ create table t1 (n numeric(10)); create table t2 (n numeric(10)); insert into t2 values (1),(2),(4),(8),(16),(32); select * from t2 left outer join t1 using (n); -n n -1 NULL -2 NULL -4 NULL -8 NULL -16 NULL -32 NULL +n +1 +2 +4 +8 +16 +32 delete t1,t2 from t2 left outer join t1 using (n); select * from t2 left outer join t1 using (n); -n n +n drop table t1,t2 ; create table t1 (n int(10) not null primary key, d int(10)); create table t2 (n int(10) not null primary key, d int(10)); diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 7f746a3dbd8..5c2141befa6 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -313,12 +313,16 @@ INSERT INTO t1 (order_id, product_id, product_type) VALUES ('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); INSERT INTO t2 (order_id, product_id, product_type) VALUES ('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); -select t1.* from t1 -left join t2 using(order_id, product_id, product_type) -where t2.order_id=NULL; +select t1.* from t1 left join t2 +on (t1.order_id = t2.order_id and +t1.product_id = t2.product_id and +t1.product_type = t2.product_type) +where t2.order_id = NULL; order_id product_id product_type -select t1.* from t1 -left join t2 using(order_id, product_id, product_type) +select t1.* from t1 left join t2 +on (t1.order_id = t2.order_id and +t1.product_id = t2.product_id and +t1.product_type = t2.product_type) where t2.order_id is NULL; order_id product_id product_type 3d7ce39b5d4b3e3d22aaafe9b633de51 1206029 3 diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 628ca5fd958..b766f146254 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -180,7 +180,7 @@ INSERT INTO t3 VALUES (1,'123 Park Place'); INSERT INTO t3 VALUES (2,'453 Boardwalk'); SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 -LEFT JOIN t2 USING(c) +LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c; a b if(b = 1,i,if(b = 2,v,'')) 1 1 50 @@ -189,7 +189,7 @@ a b if(b = 1,i,if(b = 2,v,'')) 4 2 453 Boardwalk SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 -LEFT JOIN t2 USING(c) +LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c ORDER BY a; a b if(b = 1,i,if(b = 2,v,'')) @@ -523,10 +523,10 @@ KEY `pseudo` (`pseudo`) ); INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug'); INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug'); -SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug -SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug drop table t1,t2; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 5d0e1d703a6..da5466a6e9d 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -519,56 +519,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -591,47 +591,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -654,28 +654,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index da0421d2caa..237072d7218 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -519,56 +519,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -591,47 +591,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -654,28 +654,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index ff52847a0dc..9b76003900a 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -520,56 +520,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -592,47 +592,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -655,28 +655,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 9af8f6ed6ce..adb300fdcf1 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -562,56 +562,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -634,47 +634,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -697,28 +697,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b @@ -3574,56 +3574,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -3646,47 +3646,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -3709,28 +3709,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index b7d63b97c09..d5a15fb4265 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -519,56 +519,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -591,47 +591,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -654,28 +654,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index c54c09cf6aa..33769f400ae 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -519,56 +519,56 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by t2.a +SELECT * FROM t2 right join t1 using(a) order by a prepare stmt1 from @query9 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by t2.a +SELECT * FROM t2 natural right join t1 order by a prepare stmt1 from @query8 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query7 ; @@ -591,47 +591,47 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by t2.a +SELECT * FROM t2 left join t1 using(a) order by a prepare stmt1 from @query6 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by t2.a +SELECT * FROM t2 natural left join t1 order by a prepare stmt1 from @query5 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b +1 one +2 two +3 three +4 four the join statement is: SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a prepare stmt1 from @query4 ; @@ -654,28 +654,28 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by t2.a +SELECT * FROM t2 join t1 using(a) order by a prepare stmt1 from @query3 ; execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four execute stmt1 ; -a b a b -1 one 1 one -2 two 2 two -3 three 3 three -4 four 4 four +a b b +1 one one +2 two two +3 three three +4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by t2.a +SELECT * FROM t2 natural join t1 order by a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index a0f6bb7084f..d3409bf8d39 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1350,45 +1350,42 @@ fld1 fld1 250504 250505 250505 250505 insert into t2 (fld1, companynr) values (999999,99); -select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; companynr companyname -99 NULL -select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; +select count(*) from t2 left join t4 using (companynr) where companynr is not null; count(*) -1199 -explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +1200 +explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 -1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where; Not exists -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 -1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where; Not exists +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE delete from t2 where fld1=999999; -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where -1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where -1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where -1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t4 ALL NULL NULL NULL NULL 12 -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 @@ -2115,159 +2112,142 @@ insert into t1 values (); insert into t1 values (); insert into t1 values (); select * from (t1 as t2 left join t1 as t3 using (a)), t1; -a a a -1 1 1 -2 2 1 -3 3 1 -1 1 2 -2 2 2 -3 3 2 -1 1 3 -2 2 3 -3 3 3 +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 select * from t1, (t1 as t2 left join t1 as t3 using (a)); -a a a -1 1 1 -2 1 1 -3 1 1 -1 2 2 -2 2 2 -3 2 2 -1 3 3 -2 3 3 -3 3 3 +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 select * from (t1 as t2 left join t1 as t3 using (a)) straight_join t1; -a a a -1 1 1 -2 2 1 -3 3 1 -1 1 2 -2 2 2 -3 3 2 -1 1 3 -2 2 3 -3 3 3 +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 select * from t1 straight_join (t1 as t2 left join t1 as t3 using (a)); -a a a -1 1 1 -2 1 1 -3 1 1 -1 2 2 -2 2 2 -3 2 2 -1 3 3 -2 3 3 -3 3 3 +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; -a a a -1 1 2 -2 2 2 -3 3 2 -1 1 3 -2 2 3 -3 3 3 +a a +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; -a a a -2 1 1 -3 1 1 -2 2 2 -3 2 2 -2 3 3 -3 3 3 +a a +2 1 +3 1 +2 2 +3 2 +2 3 +3 3 select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a ); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a ); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1; -a a a -1 1 2 -1 1 3 -2 2 2 -2 2 3 -3 3 2 -3 3 3 +a a +1 2 +1 3 +2 2 +2 3 +3 2 +3 3 select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; -a a a -1 NULL NULL -2 1 1 -2 2 2 -2 3 3 -3 1 1 -3 2 2 -3 3 3 +a a +1 NULL +2 1 +2 2 +2 3 +3 1 +3 2 +3 3 select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a ); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a ); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a)); -a a a -1 1 1 -2 2 2 -3 3 3 -select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; -a a a -NULL NULL 1 -1 1 2 -2 2 2 -3 3 2 -1 1 3 -2 2 3 -3 3 3 -select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; -a a a -2 1 1 -3 1 1 -2 2 2 -3 2 2 -2 3 3 -3 3 3 +a +1 +2 +3 select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a ); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a ); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1; -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a)); -a a a -1 1 1 -2 2 2 -3 3 3 +a +1 +2 +3 select * from t1 natural join (t1 as t2 left join t1 as t3 using (a)); -a a -1 1 -2 2 -3 3 +a +1 +2 +3 select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1; -a a -1 1 -2 2 -3 3 +a +1 +2 +3 drop table t1; CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) ENGINE=MyISAM; INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 693146c869e..ab44305818c 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1200,7 +1200,7 @@ INSERT INTO t1 VALUES (1); UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i)); UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t); -ERROR 42S02: Unknown table 't' in field list +ERROR 42S22: Unknown column 't.i' in 'field list' select * from t1; i 1 @@ -1638,7 +1638,7 @@ ERROR 42S22: Unknown column 't1.s2' in 'where clause' select * from t1 where (select count(*) from t2 group by t1.s2) = 1; ERROR 42S22: Unknown column 't1.s2' in 'group statement' select count(*) from t2 group by t1.s2; -ERROR 42S02: Unknown table 't1' in group statement +ERROR 42S22: Unknown column 't1.s2' in 'group statement' drop table t1, t2; CREATE TABLE t1(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC VARCHAR(20) DEFAULT NULL,PRIMARY KEY (COLA, COLB)); CREATE TABLE t2(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC CHAR(1) NOT NULL,PRIMARY KEY (COLA)); @@ -1789,11 +1789,11 @@ CREATE TABLE t1 (id INT); CREATE TABLE t2 (id INT); INSERT INTO t1 VALUES (1), (2); INSERT INTO t2 VALUES (1); -SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); id c 1 1 2 0 -SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id; +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id; id c 1 1 2 0 diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index 3da8d76e0f2..39c55206c60 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -307,18 +307,18 @@ create table t1 ( id integer unsigned not null primary key ); create table t2 ( id integer unsigned not null primary key ); insert into t1 values (1), (2); insert into t2 values (1); -select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); id_A id_B 1 1 2 NULL create table t3 (id_A integer unsigned not null, id_B integer unsigned null ); -insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; id_A id_B 1 1 2 NULL drop table t3; -create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; id_A id_B 1 1 diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 1f45d238ea5..eb129e32983 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -430,7 +430,7 @@ drop temporary table t1; create table t1 select a from t1 union select a from t2; ERROR HY000: You can't specify target table 't1' for update in FROM clause select a from t1 union select a from t2 order by t2.a; -ERROR 42S02: Unknown table 't2' in order clause +ERROR 42S22: Unknown column 't2.a' in 'order clause' drop table t1,t2; select length(version()) > 1 as `*` UNION select 2; * diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index c1abe011be4..5e487bd8036 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -400,7 +400,7 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=bdb; insert into t1 (a) values(1),(2),(3); -select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; +select a from t1 natural join t1 as t2 where b >= @a order by a; update t1 set a=5 where a=1; select a from t1; drop table t1; @@ -571,7 +571,7 @@ create temporary table tmp1 select branch_id, target_id, platform_id, product_id from t1, t2, t3, t4 ; create temporary table tmp2 - select tmp1.branch_id, tmp1.target_id, tmp1.platform_id, tmp1.product_id + select branch_id, target_id, platform_id, product_id from tmp1 left join t8 using (branch_id,target_id,platform_id,product_id) where t8.archive_id is null ; diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index 93668ffdd3d..7f41a1621d3 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -14,9 +14,9 @@ update t1 set a=1; create table t1 (a int); --error 1054 select count(test.t1.b) from t1; ---error 1109 +--error 1054 select count(not_existing_database.t1) from t1; ---error 1109 +--error 1054 select count(not_existing_database.t1.a) from t1; --error 1044,1146 select count(not_existing_database.t1.a) from not_existing_database.t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index b0b70d40e5c..3b2fd3fadff 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -128,14 +128,14 @@ WHERE ticket2.id = ttxt.ticket AND t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); # In the following query MySQL didn't use the fulltext index -select t1.id FROM t2 as ttxt,t1 INNER JOIN t1 as ticket2 ON -ticket2.id = ttxt.ticket -WHERE t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); +select ticket2.id FROM t2 as ttxt,t2 INNER JOIN t1 as ticket2 ON +ticket2.id = t2.ticket +WHERE ticket2.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); INSERT INTO t1 VALUES (3,3); -select t1.id FROM t2 as ttxt,t1 -INNER JOIN t1 as ticket2 ON ticket2.id = ttxt.ticket -WHERE t1.id = ticket2.ticket and +select ticket2.id FROM t2 as ttxt,t2 +INNER JOIN t1 as ticket2 ON ticket2.id = t2.ticket +WHERE ticket2.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar'); # Check that we get 'fulltext' index in SHOW CREATE diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index a0bd7954674..98c393fede4 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -80,7 +80,7 @@ CREATE TABLE t3 ( FULLTEXT KEY betreff (betreff) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ; ---error 1109 +--error 1054 select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -100,7 +100,7 @@ group by order by match(b.betreff) against ('+abc' in boolean mode) desc; ---error 1109 +--error 1054 select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 05f47f36e42..910a7b9b4de 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -440,7 +440,7 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb; insert into t1 (a) values(1),(2),(3); -select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; +select a from t1 natural join t1 as t2 where b >= @a order by a; update t1 set a=5 where a=1; select a from t1; drop table t1; @@ -981,7 +981,7 @@ insert into `t3`values ( 1 ) ; delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; --error 1217 update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ---error 1109 +--error 1054 update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; drop table t3,t2,t1; diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 4a463c1d52e..7116a25ff39 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -196,9 +196,9 @@ insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + #Some error cases --error 1052 insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; ---error 1109 +--error 1054 insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; ---error 1109 +--error 1054 insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; drop table t1,t2,t3; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 2715f30b6cf..06e89e6cb9d 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -111,10 +111,12 @@ drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); -select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +# TODO: WL#2486 - the query fails in PS mode with error: +# Cross dependency found in OUTER JOIN; examine your ON conditions +#select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); --replace_result "31 tables" "XX tables" "61 tables" "XX tables" --error 1116 -select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); drop table t1; # @@ -144,7 +146,7 @@ DROP TABLE t1, t2; CREATE TABLE t1 (d DATE NOT NULL); CREATE TABLE t2 (d DATE NOT NULL); INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00'); -SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL; +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL; SELECT * from t1 WHERE t1.d IS NULL; SELECT * FROM t1 WHERE 1/0 IS NULL; DROP TABLE t1,t2; @@ -266,8 +268,8 @@ CREATE TABLE t2 ( FULLTEXT KEY rate_code (rate_code) ) ENGINE=MyISAM; INSERT INTO t2 VALUES ('rivercats','cust',20); -SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; -SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats'; +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith'; drop table t1,t2; # @@ -315,14 +317,14 @@ select * from t3 right join t2 on (t3.i=t2.i); select * from t3 natural right join t2 natural right join t1; select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); -select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; +select * from t1,t2 natural left join t3 order by 1,2; select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; -select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; +select * from t2 natural left join t3,t1 order by t1.i; select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; -select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; +select * from t1,t2 natural right join t3 order by 1,2; select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; -select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; +select * from t2 natural right join t3,t1 order by t1.i; select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; drop table t1,t2,t3; diff --git a/mysql-test/t/join_crash.test b/mysql-test/t/join_crash.test index 68fd9226e41..2ec96dc2c28 100644 --- a/mysql-test/t/join_crash.test +++ b/mysql-test/t/join_crash.test @@ -92,18 +92,11 @@ select distinct t1.comments as comments, sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget from - t1 , t2 as client_period , - t2 as project_period - left join - t3 - on - t3.project_ptr = t1.project_id - and t3.date_received <= '2001-03-22 14:15:09' - left join - t4 - on - t4.client_id = t1.client_ptr + t2 as project_period, + t3 left join t1 on (t3.project_ptr = t1.project_id and + t3.date_received <= '2001-03-22 14:15:09') + left join t4 on t4.client_id = t1.client_ptr where 1 and ( client_period.period_type = 'client_table' diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 992217d0391..20a9db7a196 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -130,15 +130,13 @@ SELECT t8.a,t8.b EXPLAIN EXTENDED SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b - FROM t6, - t7 + FROM (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10; SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b - FROM t6, - t7 + FROM (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10; @@ -150,8 +148,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b FROM t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -162,8 +159,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b FROM t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -186,8 +182,7 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -203,8 +198,7 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -228,8 +222,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -252,8 +245,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -281,8 +273,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -308,8 +299,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -336,8 +326,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -375,8 +364,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -452,7 +440,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b WHERE t1.a <= 2; SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b - FROM t1, t3, t4 + FROM t1, (t3, t4) RIGHT JOIN t2 ON t3.a=1 AND t2.b=t4.b @@ -460,7 +448,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b EXPLAIN EXTENDED SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b - FROM t1, t3, t4 + FROM t1, (t3, t4) RIGHT JOIN t2 ON t3.a=1 AND t2.b=t4.b @@ -470,13 +458,13 @@ CREATE INDEX idx_b ON t2(b); EXPLAIN EXTENDED SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b - FROM t3,t4 + FROM (t3,t4) LEFT JOIN (t1,t2) ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b - FROM t3,t4 + FROM (t3,t4) LEFT JOIN (t1,t2) ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; @@ -494,8 +482,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -534,8 +521,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -573,8 +559,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -613,8 +598,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -649,8 +633,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5 LEFT JOIN ( - t6, - t7 + (t6, t7) LEFT JOIN t8 ON t7.b=t8.b AND t6.b < 10 @@ -695,7 +678,7 @@ SELECT t2.a,t2.b,t3.a1,t3.b FROM t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); -SELECT t2.a,t2.b,t3.a1,t3.b +SELECT * FROM t2 NATURAL LEFT JOIN t3 WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index f48ae985e56..6a3b79f8354 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -19,11 +19,11 @@ select t1.*,t2.* from t1 JOIN t2 where t1.a=t2.a; select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) order by t1.grp,t1.a,t2.c; select t1.*,t2.* from { oj t2 left outer join t1 on (t1.a=t2.a) }; select t1.*,t2.* from t1 as t0,{ oj t2 left outer join t1 on (t1.a=t2.a) } WHERE t0.a=2; -select t1.*,t2.* from t1 left join t2 using (a); -select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a; -select t1.*,t2.* from t1 left join t2 using (a,c); -select t1.*,t2.* from t1 left join t2 using (c); -select t1.*,t2.* from t1 natural left outer join t2; +select * from t1 left join t2 using (a); +select t1.*,t2.* from t1 left join t2 on t1.a=t2.a; +select * from t1 left join t2 using (a,c); +select * from t1 left join t2 using (c); +select * from t1 natural left outer join t2; select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3; select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id is null; @@ -34,19 +34,19 @@ explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1; select t1.*,t2.*,t3.a from t1 left join t2 on (t1.a=t2.a) left join t1 as t3 on (t2.a=t3.a); # The next query should rearange the left joins to get this to work ---error 1120 +--error 1054 explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); ---error 1120 +--error 1054 select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); # The next query should give an error in MySQL ---error 1120 +--error 1054 select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); # Test of inner join -select t1.*,t2.* from t1 inner join t2 using (a); +select * from t1 inner join t2 using (a); select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a); -select t1.*,t2.* from t1 natural join t2; +select * from t1 natural join t2; drop table t1,t2; @@ -292,7 +292,7 @@ insert into t3 values (1); insert into t4 values (1,1); insert into t5 values (1,1); ---error 1120 +--error 1054 explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23; drop table t1,t2,t3,t4,t5; @@ -325,7 +325,7 @@ INSERT INTO t2 VALUES (2,'y'); INSERT INTO t2 VALUES (3,'z'); SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL; -SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; +SELECT id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; drop table t1,t2; @@ -430,8 +430,8 @@ insert into t1 values(1),(2); insert into t2 values(2),(3); insert into t3 values(2),(4); select * from t1 natural left join t2 natural left join t3; -select * from t1 natural left join t2 where (t2.i is not null)=0; -select * from t1 natural left join t2 where (t2.i is not null) is not null; +select * from t1 natural left join t2 where (i is not null)=0; +select * from t1 natural left join t2 where (i is not null) is not null; drop table t1,t2,t3; # @@ -440,7 +440,6 @@ drop table t1,t2,t3; create table t1 (f1 integer,f2 integer,f3 integer); create table t2 (f2 integer,f4 integer); create table t3 (f3 integer,f5 integer); ---error 1054 select * from t1 left outer join t2 using (f2) left outer join t3 using (f3); @@ -657,8 +656,8 @@ create table t1 (a int, b varchar(20)); create table t2 (a int, c varchar(20)); insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); -select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; -select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; drop table t1, t2; set group_concat_max_len=default; diff --git a/mysql-test/t/null_key.test b/mysql-test/t/null_key.test index e15aec01d2a..4ab99fc5d6d 100644 --- a/mysql-test/t/null_key.test +++ b/mysql-test/t/null_key.test @@ -152,12 +152,18 @@ INSERT INTO t1 (order_id, product_id, product_type) VALUES INSERT INTO t2 (order_id, product_id, product_type) VALUES ('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); -select t1.* from t1 -left join t2 using(order_id, product_id, product_type) -where t2.order_id=NULL; -select t1.* from t1 -left join t2 using(order_id, product_id, product_type) +select t1.* from t1 left join t2 + on (t1.order_id = t2.order_id and + t1.product_id = t2.product_id and + t1.product_type = t2.product_type) +where t2.order_id = NULL; + +select t1.* from t1 left join t2 + on (t1.order_id = t2.order_id and + t1.product_id = t2.product_id and + t1.product_type = t2.product_type) where t2.order_id is NULL; + drop table t1,t2; # diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index e3b26a3e47f..615b317eb36 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -153,12 +153,12 @@ INSERT INTO t3 VALUES (2,'453 Boardwalk'); SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 -LEFT JOIN t2 USING(c) +LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c; SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 -LEFT JOIN t2 USING(c) +LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c ORDER BY a; @@ -339,8 +339,8 @@ CREATE TABLE t2 ( INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug'); INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug'); -SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; -SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; drop table t1,t2; # diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index eac76749589..1de0831ad84 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1538,22 +1538,22 @@ select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 25 # insert into t2 (fld1, companynr) values (999999,99); -select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; -select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; -explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; +select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; +select count(*) from t2 left join t4 using (companynr) where companynr is not null; +explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr is null; delete from t2 where fld1=999999; # # Test left join optimization -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0; # Following can't be optimized -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; -explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; # # Joins with forms. @@ -1850,8 +1850,10 @@ select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a ); select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a)); # right join on -select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; -select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +# TODO: WL#2486 - there is a problem in the order of tables in RIGHT JOIN +# check how we set next_name_resolution_table +# select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; +# select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; # right [outer] joing using select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a ); select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a ); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 41cdf9f1c64..cd79ddcf82a 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -696,7 +696,7 @@ CREATE TABLE `t1` ( INSERT INTO t1 VALUES (1); UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i)); UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); --- error 1109 +-- error 1054 UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t); select * from t1; drop table t1; @@ -1005,7 +1005,7 @@ create table t2 (s1 int); select * from t1 where (select count(*) from t2 where t1.s2) = 1; -- error 1054 select * from t1 where (select count(*) from t2 group by t1.s2) = 1; --- error 1109 +-- error 1054 select count(*) from t2 group by t1.s2; drop table t1, t2; @@ -1132,8 +1132,8 @@ CREATE TABLE t1 (id INT); CREATE TABLE t2 (id INT); INSERT INTO t1 VALUES (1), (2); INSERT INTO t2 VALUES (1); -SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); -SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id; +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id; DROP TABLE t1,t2; # diff --git a/mysql-test/t/type_ranges.test b/mysql-test/t/type_ranges.test index c1a5ac382ec..85862821aab 100644 --- a/mysql-test/t/type_ranges.test +++ b/mysql-test/t/type_ranges.test @@ -157,12 +157,12 @@ create table t1 ( id integer unsigned not null primary key ); create table t2 ( id integer unsigned not null primary key ); insert into t1 values (1), (2); insert into t2 values (1); -select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); create table t3 (id_A integer unsigned not null, id_B integer unsigned null ); -insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; drop table t3; -create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; drop table t1,t2,t3; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 227d1cddcfa..d4b0c1746af 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -276,7 +276,7 @@ create temporary table t1 select a from t1 union select a from t2; drop temporary table t1; --error 1093 create table t1 select a from t1 union select a from t2; ---error 1109 +--error 1054 select a from t1 union select a from t2 order by t2.a; drop table t1,t2; diff --git a/sql/item.cc b/sql/item.cc index 25a12bc2d67..f817e0306d6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3067,7 +3067,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) expression to 'reference', i.e. it substitute that expression instead of this Item_field */ - if ((from_field= find_field_in_tables(thd, this, context->table_list, + if ((from_field= find_field_in_tables(thd, this, + context->first_name_resolution_table, + context->last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, !any_privileges && @@ -3076,13 +3078,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference) not_found_field) { /* - If there is an outer contexts (outer selects, but current select is + If there are outer contexts (outer selects, but current select is not derived table or view) try to resolve this reference in the outer contexts. We treat each subselect as a separate namespace, so that different - subselects may contain columns with the same names. The subselects are - searched starting from the innermost. + subselects may contain columns with the same names. The subselects + are searched starting from the innermost. */ Name_resolution_context *last_checked_context= context; Item **ref= (Item **) not_found_item; @@ -3111,7 +3113,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference) (!select->with_sum_func && select->group_list.elements == 0)) && (from_field= find_field_in_tables(thd, this, - outer_context->table_list, + outer_context-> + first_name_resolution_table, + outer_context-> + last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, outer_context-> @@ -3186,7 +3191,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) else { /* Call find_field_in_tables only to report the error */ - find_field_in_tables(thd, this, context->table_list, + find_field_in_tables(thd, this, + context->first_name_resolution_table, + context->last_name_resolution_table, reference, REPORT_ALL_ERRORS, !any_privileges && context->check_privileges, TRUE); @@ -4354,7 +4361,10 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) expression instead of this Item_ref */ from_field= find_field_in_tables(thd, this, - outer_context->table_list, + outer_context-> + first_name_resolution_table, + outer_context-> + last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, outer_context->check_privileges, @@ -4973,9 +4983,8 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table) Try to find field by its name and if it will be found set field_idx properly. */ - (void)find_field_in_real_table(thd, table, field_name, - (uint) strlen(field_name), - 0, 0, &field_idx); + (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name), + 0, 0, &field_idx); thd->set_query_id= save_set_query_id; triggers= table->triggers; } diff --git a/sql/item.h b/sql/item.h index f0ffb160553..a72156c9315 100644 --- a/sql/item.h +++ b/sql/item.h @@ -254,6 +254,19 @@ struct Name_resolution_context name resolution of different parts of the statement. */ TABLE_LIST *table_list; + /* + In most cases the two table references below replace 'table_list' above + for the purpose of name resolution. The first and last name resolution + table references allow us to search only in a sub-tree of the nested + join tree in a FROM clause. This is needed for NATURAL JOIN, JOIN ... USING + and JOIN ... ON. + */ + TABLE_LIST *first_name_resolution_table; + /* + Last table to search in the list of leaf table references that begins + with first_name_resolution_table. + */ + TABLE_LIST *last_name_resolution_table; /* SELECT_LEX item belong to, in case of merged VIEW it can differ from @@ -293,11 +306,13 @@ struct Name_resolution_context { resolve_in_select_list= FALSE; error_processor= &dummy_error_processor; + first_name_resolution_table= NULL; + last_name_resolution_table= NULL; } void resolve_in_table_list_only(TABLE_LIST *tables) { - table_list= tables; + table_list= first_name_resolution_table= tables; resolve_in_select_list= FALSE; } @@ -657,7 +672,8 @@ public: current value and pointer passed via parameter otherwise. */ virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; } - virtual Item *this_const_item() const { return const_cast(this); } /* For SPs mostly. */ + /* For SPs mostly. */ + virtual Item *this_const_item() const { return const_cast(this); } // Row emulation virtual uint cols() { return 1; } @@ -828,6 +844,10 @@ public: void print(String *str); virtual bool change_context_processor(byte *cntx) { context= (Name_resolution_context *)cntx; return FALSE; } + friend bool insert_fields(THD *thd, Name_resolution_context *context, + const char *db_name, + const char *table_name, List_iterator *it, + bool any_privileges); }; class Item_equal; @@ -1129,7 +1149,8 @@ public: void cleanup() {} void print(String *str); Item_num *neg() { value= -value; return this; } - uint decimal_precision() const { return (uint)(max_length - test(value < 0)); } + uint decimal_precision() const + { return (uint)(max_length - test(value < 0)); } bool eq(const Item *, bool binary_cmp) const; }; @@ -1647,7 +1668,9 @@ public: longlong val_int() { int err; - return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err); + return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(), + str_value.length(),10, (char**) 0, + &err); } String *val_str(String*); my_decimal *val_decimal(my_decimal *); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2190c4a1b24..5f63036a06e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -761,23 +761,24 @@ extern Field *view_ref_found; enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE, IGNORE_EXCEPT_NON_UNIQUE}; -Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, - Item **ref, - find_item_error_report_type report_error, - bool check_privileges, - bool register_tree_change); Field * -find_field_in_table(THD *thd, TABLE_LIST *table_list, - const char *name, const char *item_name, - uint length, Item **ref, - bool check_grants_table, bool check_grants_view, - bool allow_rowid, - uint *cached_field_index_ptr, - bool register_tree_change); +find_field_in_tables(THD *thd, Item_ident *item, + TABLE_LIST *first_table, TABLE_LIST *last_table, + Item **ref, find_item_error_report_type report_error, + bool check_privileges, bool register_tree_change); Field * -find_field_in_real_table(THD *thd, TABLE *table, const char *name, - uint length, bool check_grants, bool allow_rowid, - uint *cached_field_index_ptr); +find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, + const char *name, const char *item_name, + const char *table_name, const char *db_name, + uint length, Item **ref, + bool check_grants_table, bool check_grants_view, + bool allow_rowid, + uint *cached_field_index_ptr, + bool register_tree_change, TABLE_LIST **actual_table); +Field * +find_field_in_table(THD *thd, TABLE *table, const char *name, + uint length, bool check_grants, bool allow_rowid, + uint *cached_field_index_ptr); #ifdef HAVE_OPENSSL #include struct st_des_keyblock @@ -884,8 +885,10 @@ create_field * new_create_field(THD *thd, char *field_name, enum_field_types typ uint uint_geom_type); void store_position_for_column(const char *name); bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc); +Name_resolution_context *make_join_on_context(THD *thd, TABLE_LIST *left_op, + TABLE_LIST *right_op); void add_join_on(TABLE_LIST *b,Item *expr); -void add_join_natural(TABLE_LIST *a,TABLE_LIST *b); +void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List *using_fields); bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); @@ -902,8 +905,8 @@ bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges); bool setup_tables(THD *thd, Name_resolution_context *context, - TABLE_LIST *tables, Item **conds, - TABLE_LIST **leaves, bool select_insert); + List *from_clause, TABLE_LIST *tables, + Item **conds, TABLE_LIST **leaves, bool select_insert); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, uint wild_num); bool setup_fields(THD *thd, Item** ref_pointer_array, diff --git a/sql/sp.cc b/sql/sp.cc index dec0eee0095..be45fbc4b42 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -781,6 +781,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) */ thd->lex->select_lex.context.resolve_in_table_list_only(&tables); setup_tables(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, &tables, 0, &leaves, FALSE); for (used_field= &used_fields[0]; used_field->field_name; @@ -790,7 +791,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) "mysql", "proc", used_field->field_name); if (!field || - !(used_field->field= find_field_in_tables(thd, field, &tables, + !(used_field->field= find_field_in_tables(thd, field, &tables, NULL, 0, REPORT_ALL_ERRORS, 1, TRUE))) { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1b3d8cc914a..12eb7a5d84b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2638,10 +2638,11 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, while ((column = column_iter++)) { uint unused_field_idx= NO_CACHED_FIELD_INDEX; - Field *f=find_field_in_table(thd, table_list, column->column.ptr(), - column->column.ptr(), - column->column.length(), 0, 1, 1, 0, - &unused_field_idx, FALSE); + TABLE_LIST *dummy; + Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(), + column->column.ptr(), NULL, NULL, + column->column.length(), 0, 1, 1, 0, + &unused_field_idx, FALSE, &dummy); if (f == (Field*)0) { my_error(ER_BAD_FIELD_ERROR, MYF(0), @@ -3695,6 +3696,24 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) } +/* + Determine the access priviliges for a field. + + SYNOPSIS + get_column_grant() + thd thread handler + grant grants table descriptor + db_name name of database that the field belongs to + table_name name of table that the field belongs to + field_name name of field + + DESCRIPTION + The procedure may also modify: grant->grant_table and grant->version. + + RETURN + The access priviliges for the field db_name.table_name.field_name +*/ + ulong get_column_grant(THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *field_name) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b79748c18e2..924141a6443 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1666,7 +1666,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, { /* Give right error message */ thd->clear_error(); - DBUG_PRINT("error", ("Dicovery of %s/%s failed", db, name)); + DBUG_PRINT("error", ("Discovery of %s/%s failed", db, name)); my_printf_error(ER_UNKNOWN_ERROR, "Failed to open '%-.64s', error while " "unpacking from engine", @@ -2439,152 +2439,255 @@ bool rm_temporary_table(enum db_type base, char *path) /***************************************************************************** -** find field in list or tables. if field is unqualifed and unique, -** return unique field +* The following find_field_in_XXX procedures implement the core of the +* name resolution functionality. The entry point to resolve a column name in a +* list of tables is 'find_field_in_tables'. It calls 'find_field_in_table_ref' +* for each table reference. In turn, depending on the type of table reference, +* 'find_field_in_table_ref' calls one of the 'find_field_in_XXX' procedures +* below specific for the type of table reference. ******************************************************************************/ -/* Special Field pointers for find_field_in_tables returning */ +/* Special Field pointers as return values of find_field_in_XXX functions. */ Field *not_found_field= (Field*) 0x1; Field *view_ref_found= (Field*) 0x2; #define WRONG_GRANT (Field*) -1 - -/* - Find field in table or view - - SYNOPSIS - find_field_in_table() - thd thread handler - table_list table where to find - name name of field - item_name name of item if it will be created (VIEW) - length length of name - ref [in/out] expression substituted in VIEW should be - passed using this reference (return - view_ref_found) - (*ref != NULL) only if *ref contains - the item that we need to replace. - check_grants_table do check columns grants for table? - check_grants_view do check columns grants for view? - allow_rowid do allow finding of "_rowid" field? - cached_field_index_ptr cached position in field list (used to - speedup prepared tables field finding) - register_tree_change TRUE if ref is not stack variable and we - need register changes in item tree - - RETURN - 0 field is not found - view_ref_found found value in VIEW (real result is in *ref) - # pointer to field -*/ - -Field * -find_field_in_table(THD *thd, TABLE_LIST *table_list, - const char *name, const char *item_name, - uint length, Item **ref, - bool check_grants_table, bool check_grants_view, - bool allow_rowid, - uint *cached_field_index_ptr, - bool register_tree_change) +static void update_field_dependencies(THD *thd, Field *field, TABLE *table) { - Field *fld; - DBUG_ENTER("find_field_in_table"); - DBUG_PRINT("enter", ("table: '%s' name: '%s' item name: '%s' ref 0x%lx", - table_list->alias, name, item_name, (ulong) ref)); - if (table_list->field_translation) + if (thd->set_query_id) { - Field_iterator_view field_it; - field_it.set(table_list); - DBUG_ASSERT(table_list->schema_table_reformed || - (ref != 0 && table_list->view != 0)); - for (; !field_it.end_of_fields(); field_it.next()) + if (field->query_id != thd->query_id) { - if (!my_strcasecmp(system_charset_info, field_it.name(), name)) - { - if (table_list->schema_table_reformed) - { - /* - Translation table items are always Item_fields - and fixed already('mysql_schema_table' function). - So we can return ->field. It is used only for - 'show & where' commands. - */ - DBUG_RETURN(((Item_field*) (field_it.item()))->field); - } -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_grants_view && - check_grant_column(thd, &table_list->grant, - table_list->view_db.str, - table_list->view_name.str, - name, length)) - DBUG_RETURN(WRONG_GRANT); -#endif - Item *item= field_it.create_item(thd); - if (!item) - { - DBUG_RETURN(0); - } - /* - *ref != NULL means that *ref contains the item that we need to - replace. If the item was aliased by the user, set the alias to - the replacing item. - */ - if (*ref && !(*ref)->is_autogenerated_name) - item->set_name((*ref)->name, (*ref)->name_length, - system_charset_info); - if (register_tree_change) - thd->change_item_tree(ref, item); - else - *ref= item; - DBUG_RETURN((Field*) view_ref_found); - } + field->query_id= thd->query_id; + table->used_fields++; + table->used_keys.intersect(field->part_of_key); } - DBUG_RETURN(0); + else + thd->dupp_field= field; } - fld= find_field_in_real_table(thd, table_list->table, name, length, - check_grants_table, allow_rowid, - cached_field_index_ptr); -#ifndef NO_EMBEDDED_ACCESS_CHECKS - /* check for views with temporary table algorithm */ - if (check_grants_view && table_list->view && - fld && fld != WRONG_GRANT && - check_grant_column(thd, &table_list->grant, - table_list->view_db.str, - table_list->view_name.str, - name, length)) - { - DBUG_RETURN(WRONG_GRANT); - } -#endif - DBUG_RETURN(fld); } /* - Find field in table + Find a field by name in a view that uses merge algorithm. SYNOPSIS - find_field_in_real_table() + find_field_in_view() thd thread handler - table_list table where to find + table_list view to search for 'name' + name name of field + item_name name of item if it will be created (VIEW) + length length of name + ref expression substituted in VIEW should be passed + using this reference (return view_ref_found) + check_grants do check columns grants for view? + register_tree_change TRUE if ref is not stack variable and we + need register changes in item tree + + RETURN + 0 field is not found + view_ref_found found value in VIEW (real result is in *ref) + # pointer to field - only for schema table fields +*/ + +static Field * +find_field_in_view(THD *thd, TABLE_LIST *table_list, + const char *name, const char *item_name, + uint length, Item **ref, bool check_grants, + bool register_tree_change) +{ + DBUG_ENTER("find_field_in_view"); + DBUG_PRINT("enter", + ("view: '%s', field name: '%s', item name: '%s', ref 0x%lx", + table_list->alias, name, item_name, (ulong) ref)); + Field_iterator_view field_it; + field_it.set(table_list); + DBUG_ASSERT(table_list->schema_table_reformed || + (ref != 0 && table_list->view != 0)); + for (; !field_it.end_of_fields(); field_it.next()) + { + if (!my_strcasecmp(system_charset_info, field_it.name(), name)) + { + if (table_list->schema_table_reformed) + /* + Translation table items are always Item_fields and fixed already + ('mysql_schema_table' function). So we can return ->field. It is + used only for 'show & where' commands. + */ + DBUG_RETURN(((Item_field*) (field_it.item()))->field); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (check_grants && + check_grant_column(thd, &table_list->grant, + table_list->view_db.str, + table_list->view_name.str, + name, length)) + DBUG_RETURN(WRONG_GRANT); +#endif + Item *item= field_it.create_item(thd); + if (!item) + DBUG_RETURN(0); + /* + *ref != NULL means that *ref contains the item that we need to + replace. If the item was aliased by the user, set the alias to + the replacing item. + */ + if (*ref && !(*ref)->is_autogenerated_name) + item->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + if (register_tree_change) + thd->change_item_tree(ref, item); + else + *ref= item; + DBUG_RETURN((Field*) view_ref_found); + } + } + DBUG_RETURN(0); +} + + +/* + Find field by name in a NATURAL/USING join table reference. + + SYNOPSIS + find_field_in_natural_join() + thd [in] thread handler + table_ref [in] table reference to search + name [in] name of field + table_name [in] optional table name that qualifies the field + db_name [in] optional database name that qualifies the field + length [in] length of name + ref [in/out] if 'name' is resolved to a view field, ref is + set to point to the found view field + check_grants [in] do check columns grants? + register_tree_change [in] TRUE if ref is not stack variable and we + need register changes in item tree + actual_table [out] the original table reference where the field + belongs - differs from 'table_list' only for + NATURAL/USING joins + + RETURN + - Pointer to the found Field + - NULL if the field was not found + - WRONG_GRANT if no access rights to the found field +*/ + +static Field * +find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, + const char *table_name, const char *db_name, + uint length, Item **ref, bool check_grants, + bool register_tree_change, TABLE_LIST **actual_table) +{ + DBUG_ENTER("find_field_in_natural_join"); + DBUG_PRINT("enter", ("natural join, field name: '%s', ref 0x%lx", + name, (ulong) ref)); + DBUG_ASSERT(table_ref->is_natural_join && table_ref->join_columns); + List_iterator_fast + field_it(*(table_ref->join_columns)); + Natural_join_column *nj_col= NULL; + Field *found_field= NULL; + + *actual_table= NULL; + + while ((nj_col= field_it++)) + { + if (table_name) + { + /* + Coalesced columns cannot be qualified unless this is the execute phase + of prepared statements. The reason is that they do not belong to any + table, but for PS the prepare phase already resolves and stores + items, so during the execution phase we resolve fully qualified items. + */ + if (!thd->current_arena->is_stmt_execute() && nj_col->is_coalesced) + continue; + if (table_name[0] && + my_strcasecmp(table_alias_charset, nj_col->table_name(), table_name)) + continue; + if (db_name && db_name[0]) + { + const char *cur_db_name= nj_col->db_name(); + if (cur_db_name && cur_db_name && strcmp(db_name, cur_db_name)) + continue; + } + } + + if (!my_strcasecmp(system_charset_info, nj_col->name(), name)) + break; + } + + if (!nj_col) + DBUG_RETURN(NULL); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (check_grants && nj_col->check_grants(thd, name, length)) + DBUG_RETURN(WRONG_GRANT); +#endif + + if (nj_col->view_field) + { + /* + The found field is a view field, we do as in find_field_in_view() + and return a pointer to pointer to the Item of that field. + */ + Item *item= nj_col->create_item(thd); + if (!item) + DBUG_RETURN(NULL); + DBUG_ASSERT(nj_col->table_field == NULL); + if (nj_col->table_ref->schema_table_reformed) + /* + Translation table items are always Item_fields and fixed + already('mysql_schema_table' function). So we can return + ->field. It is used only for 'show & where' commands. + */ + DBUG_RETURN(((Item_field*) (nj_col->view_field->item))->field); + + if (register_tree_change) + thd->change_item_tree(ref, item); + else + *ref= item; + found_field= (Field*) view_ref_found; + } + else + { + /* This is a base table. */ + DBUG_ASSERT(nj_col->view_field == NULL); + found_field= nj_col->table_field; + update_field_dependencies(thd, found_field, nj_col->table_ref->table); + } + + *actual_table= nj_col->table_ref; + + DBUG_RETURN(found_field); +} + + +/* + Find field by name in a base table or a view with temp table algorithm. + + SYNOPSIS + find_field_in_table() + thd thread handler + table table where to search for the field name name of field length length of name check_grants do check columns grants? allow_rowid do allow finding of "_rowid" field? - cached_field_index_ptr cached position in field list (used to - speedup prepared tables field finding) + cached_field_index_ptr cached position in field list (used to speedup + lookup for fields in prepared tables) RETURN 0 field is not found # pointer to field */ -Field *find_field_in_real_table(THD *thd, TABLE *table, - const char *name, uint length, - bool check_grants, bool allow_rowid, - uint *cached_field_index_ptr) +Field * +find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, + bool check_grants, bool allow_rowid, + uint *cached_field_index_ptr) { + DBUG_ENTER("find_field_in_table"); + DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias, name)); Field **field_ptr, *field; uint cached_field_index= *cached_field_index_ptr; @@ -2599,7 +2702,7 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, else { if (!(field_ptr= table->field)) - return (Field *)0; + DBUG_RETURN((Field *)0); for (; *field_ptr; ++field_ptr) if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name)) break; @@ -2615,27 +2718,118 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, if (!allow_rowid || my_strcasecmp(system_charset_info, name, "_rowid") || !(field=table->rowid_field)) - return (Field*) 0; + DBUG_RETURN((Field*) 0); } - if (thd->set_query_id) - { - if (field->query_id != thd->query_id) - { - field->query_id=thd->query_id; - table->used_fields++; - table->used_keys.intersect(field->part_of_key); - } - else - thd->dupp_field=field; - } + update_field_dependencies(thd, field, table); + #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants && check_grant_column(thd, &table->grant, table->s->db, table->s->table_name, name, length)) - return WRONG_GRANT; + DBUG_RETURN(WRONG_GRANT); #endif - return field; + DBUG_RETURN(field); +} + + +/* + Find field in a table reference. + + SYNOPSIS + find_field_in_table_ref() + thd [in] thread handler + table_list [in] table reference to search + name [in] name of field + item_name [in] name of item if it will be created (VIEW) + table_name [in] optional table name that qualifies the field + db_name [in] optional database name that qualifies the + length [in] field length of name + ref [in/out] if 'name' is resolved to a view field, ref + is set to point to the found view field + check_grants_table [in] do check columns grants for table? + check_grants_view [in] do check columns grants for view? + allow_rowid [in] do allow finding of "_rowid" field? + cached_field_index_ptr [in] cached position in field list (used to + speedup lookup for fields in prepared tables) + register_tree_change [in] TRUE if ref is not stack variable and we + need register changes in item tree + actual_table [out] the original table reference where the field + belongs - differs from 'table_list' only for + NATURAL_USING joins. + + RETURN + 0 field is not found + view_ref_found found value in VIEW (real result is in *ref) + # pointer to field +*/ + +Field * +find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, + const char *name, const char *item_name, + const char *table_name, const char *db_name, + uint length, Item **ref, + bool check_grants_table, bool check_grants_view, + bool allow_rowid, uint *cached_field_index_ptr, + bool register_tree_change, TABLE_LIST **actual_table) +{ + Field *fld; + DBUG_ENTER("find_field_in_table_ref"); + DBUG_PRINT("enter", + ("table: '%s' field name: '%s' item name: '%s' ref 0x%lx", + table_list->alias, name, item_name, (ulong) ref)); + + /* + Check that the table and database that qualify the current field name + are the same as the table we are going to search for the field. + This is done differently for NATURAL/USING joins because there we can't + simply compare the qualifying table and database names with the ones of + 'table_list' because each field in such a join may originate from a + different table. + TODO: Ensure that db and tables->db always points to something ! + */ + if (!table_list->is_natural_join && + (table_name && table_name[0] && + my_strcasecmp(table_alias_charset, table_list->alias, table_name) || + (db_name && db_name[0] && table_list->db && table_list->db[0] && + strcmp(db_name, table_list->db)))) + DBUG_RETURN(0); + + if (table_list->field_translation) + { + if ((fld= find_field_in_view(thd, table_list, name, item_name, length, + ref, check_grants_view, register_tree_change))) + *actual_table= table_list; + else + *actual_table= NULL; + } + else if (table_list->is_natural_join) + fld= find_field_in_natural_join(thd, table_list, name, table_name, + db_name, length, ref, + /* TIMOUR_TODO: check this with Sanja */ + check_grants_table || check_grants_view, + register_tree_change, actual_table); + else + { + if ((fld= find_field_in_table(thd, table_list->table, name, length, + check_grants_table, allow_rowid, + cached_field_index_ptr))) + *actual_table= table_list; + else + *actual_table= NULL; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* check for views with temporary table algorithm */ + if (check_grants_view && table_list->view && + fld && fld != WRONG_GRANT && + check_grant_column(thd, &table_list->grant, + table_list->view_db.str, + table_list->view_name.str, + name, length)) + DBUG_RETURN(WRONG_GRANT); +#endif + } + + DBUG_RETURN(fld); } @@ -2644,21 +2838,23 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, SYNOPSIS find_field_in_tables() - thd Pointer to current thread structure - item Field item that should be found - tables Tables to be searched for item - ref If 'item' is resolved to a view field, ref is set to + thd pointer to current thread structure + item field item that should be found + first_table list of tables to be searched for item + last_table end of the list of tables to search for item. If NULL + then search to the end of the list 'first_table'. + ref if 'item' is resolved to a view field, ref is set to point to the found view field - report_error Degree of error reporting: + report_error Degree of error reporting: - IGNORE_ERRORS then do not report any error - IGNORE_EXCEPT_NON_UNIQUE report only non-unique - fields, suppress all other errors + fields, suppress all other errors - REPORT_EXCEPT_NON_UNIQUE report all other errors except when non-unique fields were found - REPORT_ALL_ERRORS check_privileges need to check privileges - register_tree_change TRUE if ref is not stack variable and we - need register changes in item tree + register_tree_change TRUE if ref is not a stack variable and we + to need register changes in item tree RETURN VALUES 0 If error: the found field is not unique, or there are @@ -2672,63 +2868,66 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, */ Field * -find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, +find_field_in_tables(THD *thd, Item_ident *item, + TABLE_LIST *first_table, TABLE_LIST *last_table, Item **ref, find_item_error_report_type report_error, bool check_privileges, bool register_tree_change) { Field *found=0; - const char *db=item->db_name; - const char *table_name=item->table_name; - const char *name=item->field_name; + const char *db= item->db_name; + const char *table_name= item->table_name; + const char *name= item->field_name; uint length=(uint) strlen(name); char name_buff[NAME_LEN+1]; bool allow_rowid; + TABLE_LIST *cur_table= first_table; + TABLE_LIST *actual_table; if (item->cached_table) { /* - This shortcut is used by prepared statements. We assuming that - TABLE_LIST *tables is not changed during query execution (which + This shortcut is used by prepared statements. We assume that + TABLE_LIST *first_table is not changed during query execution (which is true for all queries except RENAME but luckily RENAME doesn't use fields...) so we can rely on reusing pointer to its member. With this optimization we also miss case when addition of one more field makes some prepared query ambiguous and so erroneous, but we accept this trade off. */ - if (item->cached_table->table && !item->cached_table->view) - { - found= find_field_in_real_table(thd, item->cached_table->table, - name, length, - test(item->cached_table-> - table->grant.want_privilege) && - check_privileges, - 1, &(item->cached_field_index)); - - } + TABLE_LIST *table_ref= item->cached_table; + /* + The condition (table_ref->view == NULL) ensures that we will call + find_field_in_table even in the case of information schema tables + when table_ref->field_translation != NULL. + */ + if (table_ref->table && !table_ref->view) + found= find_field_in_table(thd, table_ref->table, name, length, + test(table_ref->table-> + grant.want_privilege) && + check_privileges, + 1, &(item->cached_field_index)); else - { - TABLE_LIST *table= item->cached_table; - found= find_field_in_table(thd, table, name, item->name, length, - ref, - (table->table && - test(table->table->grant. - want_privilege) && - check_privileges), - (test(table->grant.want_privilege) && - check_privileges), - 1, &(item->cached_field_index), - register_tree_change); - } + found= find_field_in_table_ref(thd, table_ref, name, item->name, + NULL, NULL, length, ref, + (table_ref->table && + test(table_ref->table->grant. + want_privilege) && + check_privileges), + (test(table_ref->grant.want_privilege) && + check_privileges), + 1, &(item->cached_field_index), + register_tree_change, + &actual_table); if (found) { if (found == WRONG_GRANT) return (Field*) 0; { SELECT_LEX *current_sel= thd->lex->current_select; - SELECT_LEX *last_select= item->cached_table->select_lex; + SELECT_LEX *last_select= table_ref->select_lex; /* If the field was an outer referencee, mark all selects using this - sub query as dependent of the outer query + sub query as dependent on the outer query */ if (current_sel != last_select) mark_select_range_as_dependent(thd, last_select, current_sel, @@ -2750,46 +2949,52 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, db= name_buff; } + /* The field we search for is qualified with a table name and optional db. */ if (table_name && table_name[0]) - { /* Qualified field */ - bool found_table= 0; - for (; tables; tables= tables->next_local) + { + bool found_table=0; + for ( ; + (cur_table && + (last_table ? + (cur_table != last_table->next_name_resolution_table) : TRUE)); + cur_table= cur_table->next_name_resolution_table) { - /* TODO; Ensure that db and tables->db always points to something ! */ - if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && - (!db || !db[0] || !tables->db || !tables->db[0] || - !strcmp(db,tables->db))) + DBUG_ASSERT(cur_table); + found_table= 1; + Field *cur_field= find_field_in_table_ref(thd, cur_table, name, + item->name, table_name, + db, length, ref, + (cur_table->table && + test(cur_table->table->grant. + want_privilege) && + check_privileges), + (test(cur_table->grant. + want_privilege) + && check_privileges), + 1, &(item->cached_field_index), + register_tree_change, + &actual_table); + if (cur_field) { - found_table=1; - Field *find= find_field_in_table(thd, tables, name, item->name, - length, ref, - (tables->table && - test(tables->table->grant. - want_privilege) && - check_privileges), - (test(tables->grant.want_privilege) && - check_privileges), - 1, &(item->cached_field_index), - register_tree_change); - if (find) - { - item->cached_table= tables; - if (!tables->cacheable_table) - item->cached_table= 0; - if (find == WRONG_GRANT) - return (Field*) 0; - if (db || !thd->where) - return find; - if (found) - { - if (report_error == REPORT_ALL_ERRORS || - report_error == IGNORE_EXCEPT_NON_UNIQUE) - my_error(ER_NON_UNIQ_ERROR, MYF(0), - item->full_name(),thd->where); - return (Field*) 0; - } - found=find; - } + /* + Store the original table of the field, which may be different from + cur_table in the case of NATURAL/USING join. + */ + item->cached_table= (!actual_table->cacheable_table) ? 0 : actual_table; + + if (cur_field == WRONG_GRANT) + return (Field*) 0; + if (db || !thd->where) + return cur_field; + if (found) + { + if (report_error == REPORT_ALL_ERRORS || + report_error == IGNORE_EXCEPT_NON_UNIQUE) + my_error(ER_NON_UNIQ_ERROR, MYF(0), + item->full_name(),thd->where); + return (Field*) 0; + } + found= cur_field; } } if (found) @@ -2813,34 +3018,41 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; return (Field*) 0; } - allow_rowid= tables && !tables->next_local; // Only one table - for (; tables ; tables= tables->next_local) - { - Field *field; - if (!tables->table && !tables->ancestor) - { - if (report_error == REPORT_ALL_ERRORS || - report_error == REPORT_EXCEPT_NON_UNIQUE) - my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where); - return (Field*) not_found_field; - } - field= find_field_in_table(thd, tables, name, item->name, - length, ref, - (tables->table && - test(tables->table->grant. - want_privilege) && - check_privileges), - (test(tables->grant.want_privilege) && - check_privileges), - allow_rowid, - &(item->cached_field_index), - register_tree_change); - if (field) + /* The field we search for is not qualified. */ + allow_rowid= cur_table && !cur_table->next_local; + for ( ; + (cur_table && + (last_table ? + (cur_table != last_table->next_name_resolution_table) : TRUE)); + cur_table= cur_table->next_name_resolution_table) + { + DBUG_ASSERT(cur_table); + Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name, + NULL, NULL, length, ref, + (cur_table->table && + test(cur_table->table->grant. + want_privilege) && + check_privileges), + (test(cur_table->grant. + want_privilege) + && check_privileges), + allow_rowid, + &(item->cached_field_index), + register_tree_change, + &actual_table); + if (cur_field) { - if (field == WRONG_GRANT) + if (cur_field == WRONG_GRANT) return (Field*) 0; - item->cached_table= (!tables->cacheable_table || found) ? 0 : tables; + + /* + Store the original table of the field, which may be different from + cur_table in the case of NATURAL/USING join. + */ + item->cached_table= (!actual_table->cacheable_table || found) ? + 0 : actual_table; + if (found) { if (!thd->where) // Returns first found @@ -2850,7 +3062,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); return (Field*) 0; } - found= field; + found= cur_field; } } if (found) @@ -3064,6 +3276,622 @@ find_item_in_list(Item *find, List &items, uint *counter, return (Item **) not_found_item; } + +/* + Test if a string is a member of a list of strings. + + SYNOPSIS + test_if_string_in_list() + find the string to look for + str_list a list of strings to be searched + + DESCRIPTION + Sequentially search a list of strings for a string, and test whether + the list contains the same string. + + RETURN + TRUE if find is in str_list + FALSE otherwise +*/ + +static bool +test_if_string_in_list(const char *find, List *str_list) +{ + List_iterator str_list_it(*str_list); + String *curr_str; + size_t find_length= strlen(find); + while ((curr_str= str_list_it++)) + { + if (find_length != curr_str->length()) + continue; + if (!strncmp(find, curr_str->ptr(), find_length)) + return TRUE; + } + return FALSE; +} + + +/* + Create a new name resolution context for an item so that it is + being resolved in a specific table reference. + + SYNOPSIS + set_new_item_local_context() + thd pointer to current thread + item item for which new context is created and set + table_ref table ref where an item showld be resolved + + DESCRIPTION + Create a new name resolution context for an item, so that the item + is resolved only the supplied 'table_ref'. + + RETURN + FALSE - if all OK + TRUE - otherwise +*/ + +static bool +set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) +{ + Name_resolution_context *context; + if (!(context= (Name_resolution_context*) + thd->calloc(sizeof(Name_resolution_context)))) + return TRUE; + context->init(); + context->first_name_resolution_table= table_ref; + context->last_name_resolution_table= table_ref; + item->context= context; + return FALSE; +} + + +/* + Find and mark the common columns of two table references. + + SYNOPSIS + mark_common_columns() + thd [in] current thread + table_ref_1 [in] the first (left) join operand + table_ref_2 [in] the second (right) join operand + using_fields [in] if the join is JOIN...USING - the join columns, + if NATURAL join, then NULL + found_using_fields [out] number of fields from the USING clause that were + found among the common fields + + DESCRIPTION + The procedure finds the common columns of two relations (either + tables or intermediate join results), and adds an equi-join condition + to the ON clause of 'table_ref_2' for each pair of matching columns. + If some of table_ref_XXX represents a base table or view, then we + create new 'Natural_join_column' instances for each column + reference and store them in the 'join_columns' of the table + reference. + + IMPLEMENTATION + The procedure assumes that store_natural_using_join_columns() was + called for the previous level of NATURAL/USING joins. + + RETURN + TRUE - if error when some common column is non-unique, or out of memory + FALSE - if OK +*/ + +static bool +mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, + List *using_fields, uint *found_using_fields) +{ + Field_iterator_table_ref it_1, it_2; + Natural_join_column *nj_col_1, *nj_col_2; + const char *field_name_1, *field_name_2; + *found_using_fields= 0; + bool add_columns= TRUE; + Query_arena *arena, backup; + bool result= TRUE; + + DBUG_ENTER("mark_common_columns"); + DBUG_PRINT("info", ("operand_1: %s, operand_2: %s", + table_ref_1->alias, table_ref_2->alias)); + + arena= thd->change_arena_if_needed(&backup); + + /* + TABLE_LIST::join_columns could be allocated by the previous call to + store_natural_using_join_columns() for the lower level of nested tables. + */ + if (!table_ref_1->join_columns) + { + if (!(table_ref_1->join_columns= new List)) + goto err; + table_ref_1->is_join_columns_complete= FALSE; + } + if (!table_ref_2->join_columns) + { + if (!(table_ref_2->join_columns= new List)) + goto err; + table_ref_2->is_join_columns_complete= FALSE; + } + + for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next()) + { + bool is_created_1; + if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created_1))) + goto err; + field_name_1= nj_col_1->name(); + bool found= FALSE; + + /* If nj_col_1 was just created add it to the list of join columns. */ + if (is_created_1) + table_ref_1->join_columns->push_back(nj_col_1); + + /* Find a field with the same name in table_ref_2. */ + nj_col_2= NULL; + field_name_2= NULL; + for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next()) + { + bool is_created_2; + Natural_join_column *cur_nj_col_2; + if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, &is_created_2))) + goto err; + const char *cur_field_name_2= cur_nj_col_2->name(); + + /* If nj_col_1 was just created add it to the list of join columns. */ + if (add_columns && is_created_2) + table_ref_2->join_columns->push_back(cur_nj_col_2); + + /* Compare the two columns and check for duplicate common fields. */ + if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) + { + if (found) + { + my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); + goto err; + } + nj_col_2= cur_nj_col_2; + field_name_2= cur_field_name_2; + found= TRUE; + } + } + table_ref_2->is_join_columns_complete= TRUE; + add_columns= FALSE; + if (!found) + continue; + + /* + field_1 and field_2 have the same names. Check if they are in the USING + clause (if present), mark them as common fields, and add a new + equi-join condition to the ON clause. + */ + if (nj_col_2 && + (!using_fields || + (using_fields && + test_if_string_in_list(field_name_1, using_fields)))) + { + Item *item_1= nj_col_1->create_item(thd); + Item *item_2= nj_col_2->create_item(thd); + Field *field_1= nj_col_1->field(); + Field *field_2= nj_col_2->field(); + Item_ident *item_ident_1, *item_ident_2; + Name_resolution_context *context_1, *context_2; + DBUG_PRINT("info", ("new equi-join condition: %s.%s = %s.%s", + table_ref_1->alias, field_1->field_name, + table_ref_2->alias, field_2->field_name)); + + /* + The first assert guarantees that the two created items are of + type Item_ident. + */ + DBUG_ASSERT(!thd->lex->current_select->no_wrap_view_item); + /* + In the case of no_wrap_view_item == 0, the created items must be + of sub-classes of Item_ident. + */ + DBUG_ASSERT(item_1->type() == Item::FIELD_ITEM || + item_1->type() == Item::REF_ITEM); + DBUG_ASSERT(item_2->type() == Item::FIELD_ITEM || + item_2->type() == Item::REF_ITEM); + + /* + We need to cast item_1,2 to Item_ident, because we need to hook name + resolution contexts specific to each item. + */ + item_ident_1= (Item_ident*) item_1; + item_ident_2= (Item_ident*) item_2; + /* + Create and hook special name resolution contexts to each item in the + new join condition . We need this to both speed-up subsequent name + resolution of these items, and to enable proper name resolution of + the items during the execute phase of PS. + */ + if (set_new_item_local_context(thd, item_ident_1, table_ref_1)) + goto err; + if (set_new_item_local_context(thd, item_ident_2, table_ref_2)) + goto err; + + Item_func_eq *eq_cond= new Item_func_eq(item_ident_1, item_ident_2); + if (!eq_cond) + goto err; /* Out of memory. */ + + /* + Add the new equi-join condition to the ON clause. Notice that + fix_fields() is applied to all ON conditions in setup_conds() + so we don't do it here. + */ + if (table_ref_1->outer_join & JOIN_TYPE_RIGHT) + add_join_on(table_ref_1, eq_cond); + else + add_join_on(table_ref_2, eq_cond); + + nj_col_1->is_common= nj_col_2->is_common= TRUE; + nj_col_1->is_coalesced= nj_col_2->is_coalesced= TRUE; + + if (field_1) + { + /* Mark field_1 used for table cache. */ + field_1->query_id= thd->query_id; + nj_col_1->table_ref->table->used_keys.intersect(field_1->part_of_key); + } + if (field_2) + { + /* Mark field_2 used for table cache. */ + field_2->query_id= thd->query_id; + nj_col_2->table_ref->table->used_keys.intersect(field_2->part_of_key); + } + + if (using_fields != NULL) + ++(*found_using_fields); + } + } + table_ref_1->is_join_columns_complete= TRUE; + + /* + Everything is OK. + Notice that at this point there may be some column names in the USING + clause that are not among the common columns. This is an SQL error and + we check for this error in store_natural_using_join_columns() when + (found_using_fields < length(join_using_fields)). + */ + result= FALSE; + +err: + if (arena) + thd->restore_backup_item_arena(arena, &backup); + DBUG_RETURN(result); +} + + + +/* + Materialize and store the row type of NATURAL/USING join. + + SYNOPSIS + store_natural_using_join_columns() + thd current thread + natural_using_join the table reference of the NATURAL/USING join + table_ref_1 the first (left) operand (of a NATURAL/USING join). + table_ref_2 the second (right) operand (of a NATURAL/USING join). + using_fields if the join is JOIN...USING - the join columns, + if NATURAL join, then NULL + found_using_fields number of fields from the USING clause that were + found among the common fields + + DESCRIPTION + Iterate over the columns of both join operands and sort and store + all columns into the 'join_columns' list of natural_using_join + where the list is formed by three parts: + part1: The coalesced columns of table_ref_1 and table_ref_2, + sorted according to the column order of the first table. + part2: The other columns of the first table, in the order in + which they were defined in CREATE TABLE. + part3: The other columns of the second table, in the order in + which they were defined in CREATE TABLE. + Time complexity - O(N1+N2), where Ni = length(table_ref_i). + + IMPLEMENTATION + The procedure assumes that mark_common_columns() has been called + for the join that is being processed. + + RETURN + TRUE - if error when some common column is ambiguous + FALSE - if OK +*/ + +static bool +store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, + TABLE_LIST *table_ref_1, + TABLE_LIST *table_ref_2, + List *using_fields, + uint found_using_fields) +{ + Field_iterator_table_ref it_1, it_2; + Natural_join_column *nj_col_1, *nj_col_2; + bool is_created; + Query_arena *arena, backup; + bool result= TRUE; + + DBUG_ENTER("store_natural_using_join_columns"); + + arena= thd->change_arena_if_needed(&backup); + + List *non_join_columns; + if (!(non_join_columns= new List)) + goto err; + DBUG_ASSERT(!natural_using_join->join_columns); + if (!(natural_using_join->join_columns= new List)) + goto err; + + /* Append the columns of the first join operand. */ + for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next()) + { + if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created))) + goto err; + DBUG_ASSERT(!is_created); + if (nj_col_1->is_common) + { + natural_using_join->join_columns->push_back(nj_col_1); + /* Reset the common columns for the next call to mark_common_columns. */ + nj_col_1->is_common= FALSE; + } + else + non_join_columns->push_back(nj_col_1); + } + + /* + Check that all columns in the USING clause are among the common + columns. If this is not the case, report the first one that was + not found in an error. + */ + if (using_fields && found_using_fields < using_fields->elements) + { + String *using_field_name; + List_iterator_fast using_fields_it(*using_fields); + while ((using_field_name= using_fields_it++)) + { + const char *using_field_name_ptr= using_field_name->ptr(); + List_iterator_fast + it(*(natural_using_join->join_columns)); + Natural_join_column *common_field; + bool found= FALSE; + while ((common_field= it++)) + { + if (!my_strcasecmp(system_charset_info, + common_field->name(), using_field_name_ptr)) + found= TRUE; + } + if (!found) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr, + current_thd->where); + delete non_join_columns; + goto err; + } + } + } + + /* Append the non-equi-join columns of the second join operand. */ + for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next()) + { + if (!(nj_col_2= it_2.get_or_create_column_ref(thd, &is_created))) + goto err; + DBUG_ASSERT(!is_created); + if (!nj_col_2->is_common) + non_join_columns->push_back(nj_col_2); + else + /* Reset the common columns for the next call to mark_common_columns. */ + nj_col_2->is_common= FALSE; + + } + + if (non_join_columns->elements > 0) + natural_using_join->join_columns->concat(non_join_columns); + else + delete non_join_columns; + natural_using_join->is_join_columns_complete= TRUE; + + + result= FALSE; + +err: + if (arena) + thd->restore_backup_item_arena(arena, &backup); + DBUG_RETURN(result); +} + +/* + Precompute and store the row types of the top-most NATURAL/USING joins. + + SYNOPSIS + store_top_level_join_columns() + thd current thread + table_ref nested join or table in a FROM clause + left_neighbor neighbor table reference to the left of table_ref at the + same level in the join tree + right_neighbor neighbor table reference to the right of table_ref at the + same level in the join tree + + DESCRIPTION + The procedure performs a post-order traversal of a nested join tree + and materializes the row types of NATURAL/USING joins in a + bottom-up manner until it reaches the TABLE_LIST elements that + represent the top-most NATURAL/USING joins. The procedure should be + applied to each element of SELECT_LEX::top_join_list (i.e. to each + top-level element of the FROM clause). + + IMPLEMENTATION + Notice that the table references in the list nested_join->join_list + are in reverse order, thus when we iterate over it, we are moving + from the right to the left in the FROM clause. + + RETURN + TRUE - if error + FALSE - if OK +*/ + +static bool +store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, + TABLE_LIST *left_neighbor, + TABLE_LIST *right_neighbor) +{ + DBUG_ENTER("store_top_level_join_columns"); + /* Call the procedure recursively for each nested table reference. */ + if (table_ref->nested_join) + { + List_iterator_fast nested_it(table_ref->nested_join->join_list); + TABLE_LIST *cur_table_ref; + TABLE_LIST *cur_left_neighbor= nested_it++; + TABLE_LIST *cur_right_neighbor= NULL; + while (cur_left_neighbor) + { + cur_table_ref= cur_left_neighbor; + cur_left_neighbor= nested_it++; + if (cur_table_ref->nested_join && + store_top_level_join_columns(thd, cur_table_ref, + cur_left_neighbor, cur_right_neighbor)) + DBUG_RETURN(TRUE); + cur_right_neighbor= cur_table_ref; + } + } + + /* + If this is a NATURAL/USING join, materialize its result columns and + convert to a JOIN ... ON. + */ + if (table_ref->is_natural_join) + { + DBUG_ASSERT(table_ref->nested_join && + table_ref->nested_join->join_list.elements == 2); + List_iterator_fast operand_it(table_ref->nested_join->join_list); + /* + Notice that the order of join operands depends on whether table_ref + represents a LEFT or a RIGHT join. In a RIGHT join, the operands are + in inverted order. + */ + TABLE_LIST *table_ref_2= operand_it++; /* Second NATURAL join operand.*/ + TABLE_LIST *table_ref_1= operand_it++; /* First NATURAL join operand. */ + TABLE_LIST *last_leaf_on_the_left= NULL; + TABLE_LIST *first_leaf_on_the_right= NULL; + List *using_fields= table_ref->join_using_fields; + uint found_using_fields; + + /* + The two join operands were interchanged in the parser, change the order + back for 'mark_common_columns'. + */ + if (table_ref_2->outer_join & JOIN_TYPE_RIGHT) + swap_variables(TABLE_LIST*, table_ref_1, table_ref_2); + if (mark_common_columns(thd, table_ref_1, table_ref_2, + using_fields, &found_using_fields)) + DBUG_RETURN(TRUE); + + /* + Swap the join operands back, so that we pick the columns of the second + one as the coalesced columns. In this way the coalesced columns are the + same as of an equivalent LEFT JOIN. + */ + if (table_ref_1->outer_join & JOIN_TYPE_RIGHT) + swap_variables(TABLE_LIST*, table_ref_1, table_ref_2); + if (store_natural_using_join_columns(thd, table_ref, table_ref_1, + table_ref_2, using_fields, + found_using_fields)) + DBUG_RETURN(TRUE); + + /* + Change NATURAL JOIN to JOIN ... ON. We do this for both operands + because either one of them or the other is the one with the + natural join flag because RIGHT joins are transformed into LEFT, + and the two tables may be reordered. + */ + table_ref_1->natural_join= table_ref_2->natural_join= NULL; + + /* Change this table reference to become a leaf for name resolution. */ + if (left_neighbor) + { + last_leaf_on_the_left= left_neighbor->last_leaf_for_name_resolution(); + last_leaf_on_the_left->next_name_resolution_table= table_ref; + } + if (right_neighbor) + { + first_leaf_on_the_right= right_neighbor->first_leaf_for_name_resolution(); + table_ref->next_name_resolution_table= first_leaf_on_the_right; + } + else + table_ref->next_name_resolution_table= NULL; + } + DBUG_RETURN(FALSE); +} + + +/* + Compute and store the row types of the top-most NATURAL/USING joins + in a FROM clause. + + SYNOPSIS + setup_natural_join_row_types() + thd current thread + from_clause list of top-level table references in a FROM clause + + DESCRIPTION + Apply the procedure 'store_top_level_join_columns' to each of the + top-level table referencs of the FROM clause. Adjust the list of tables + for name resolution - context->first_name_resolution_table to the + top-most, lef-most NATURAL/USING join. + + IMPLEMENTATION + Notice that the table references in 'from_clause' are in reverse + order, thus when we iterate over it, we are moving from the right + to the left in the FROM clause. + + RETURN + TRUE - if error + FALSE - if OK +*/ +static bool setup_natural_join_row_types(THD *thd, List *from_clause, + Name_resolution_context *context) +{ + thd->where= "from clause"; + if (from_clause->elements == 0) + return FALSE; /* We come here in the case of UNIONs. */ + + /* For stored procedures do not redo work if already done. */ + if (!context->select_lex->first_execution) + return FALSE; + + List_iterator_fast table_ref_it(*from_clause); + TABLE_LIST *table_ref; /* Current table reference. */ + /* Table reference to the left of the current. */ + TABLE_LIST *left_neighbor= table_ref_it++; + /* Table reference to the right of the current. */ + TABLE_LIST *right_neighbor= NULL; + + while (left_neighbor) + { + table_ref= left_neighbor; + left_neighbor= table_ref_it++; + if (store_top_level_join_columns(thd, table_ref, + left_neighbor, right_neighbor)) + return TRUE; + if (left_neighbor) + { + TABLE_LIST *first_leaf_on_the_right; + first_leaf_on_the_right= table_ref->first_leaf_for_name_resolution(); + left_neighbor->next_name_resolution_table= first_leaf_on_the_right; + } + right_neighbor= table_ref; + } + + /* + Store the top-most, left-most NATURAL/USING join, so that we start + the search from that one instead of context->table_list. At this point + right_neigbor points to the left-most top-level table reference in the + FROM clause. + */ + DBUG_ASSERT(right_neighbor); + context->first_name_resolution_table= + right_neighbor->first_leaf_for_name_resolution(); + + return FALSE; +} + + /**************************************************************************** ** Expand all '*' in given fields ****************************************************************************/ @@ -3204,9 +4032,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) for (TABLE_LIST *table= tables; table; table= table->next_local) { if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE) - { list= make_leaves_list(list, table->ancestor); - } else { *list= table; @@ -3223,33 +4049,36 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) setup_tables() thd Thread handler context name resolution contest to setup table list there - tables Table list + from_clause Top-level list of table references in the FROM clause + tables Table list (select_lex->table_list) conds Condition of current SELECT (can be changed by VIEW) - leaves List of join table leaves list + leaves List of join table leaves list (select_lex->leaf_tables) refresh It is onle refresh for subquery select_insert It is SELECT ... INSERT command NOTE Check also that the 'used keys' and 'ignored keys' exists and set up the - table structure accordingly - Create leaf tables list + table structure accordingly. + Create a list of leaf tables. For queries with NATURAL/USING JOINs, + compute the row types of the top most natural/using join table references + and link these into a list of table references for name resolution. This has to be called for all tables that are used by items, as otherwise table->map is not set and all Item_field will be regarded as const items. RETURN - FALSE ok; In this case *map will includes the choosed index + FALSE ok; In this case *map will includes the chosen index TRUE error */ bool setup_tables(THD *thd, Name_resolution_context *context, - TABLE_LIST *tables, Item **conds, - TABLE_LIST **leaves, bool select_insert) + List *from_clause, TABLE_LIST *tables, + Item **conds, TABLE_LIST **leaves, bool select_insert) { uint tablenr= 0; DBUG_ENTER("setup_tables"); - context->table_list= tables; + context->table_list= context->first_name_resolution_table= tables; /* this is used for INSERT ... SELECT. @@ -3321,6 +4150,11 @@ bool setup_tables(THD *thd, Name_resolution_context *context, DBUG_RETURN(1); } } + + /* Precompute and store the row types of NATURAL/USING joins. */ + if (setup_natural_join_row_types(thd, from_clause, context)) + DBUG_RETURN(1); + DBUG_RETURN(0); } @@ -3389,12 +4223,12 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges) { - /* allocate variables on stack to avoid pool alloaction */ - Field_iterator_table table_iter; - Field_iterator_view view_iter; - uint found; + Field_iterator_table_ref field_iterator; + bool found; char name_buff[NAME_LEN+1]; DBUG_ENTER("insert_fields"); + DBUG_PRINT("arena", ("insert_fields: current arena: 0x%lx", + (ulong)thd->current_arena)); if (db_name && lower_case_table_names) { @@ -3408,197 +4242,207 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, db_name= name_buff; } - found= 0; - for (TABLE_LIST *tables= context->table_list; + found= FALSE; + for (TABLE_LIST *tables= context->first_name_resolution_table; tables; - tables= tables->next_local) + tables= tables->next_name_resolution_table) { - Field_iterator *iterator; - TABLE_LIST *natural_join_table; Field *field; - TABLE_LIST *embedded; - TABLE_LIST *last; - TABLE_LIST *embedding; TABLE *table= tables->table; - if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, - tables->alias) && - (!db_name || !strcmp(tables->db,db_name)))) + DBUG_ASSERT(tables->is_leaf_for_name_resolution()); + + /* + If optional table and db names do not match the ones used to qualify + the field being expanded, skip this table reference. However if this is + a NATURAL/USING join, we can't simply skip the whole table reference, + because its columns may come from different tables/views. For NATURAL/ + USING joins we perform this test for each column in the loop below. + */ + if (!tables->is_natural_join) { - bool view; + if (table_name && my_strcasecmp(table_alias_charset, table_name, tables->alias) + || + (db_name && strcmp(tables->db,db_name))) + continue; + } + + bool view; #ifndef NO_EMBEDDED_ACCESS_CHECKS - /* Ensure that we have access right to all columns */ - if (!((table && (table->grant.privilege & SELECT_ACL) || - tables->view && (tables->grant.privilege & SELECT_ACL))) && - !any_privileges) + /* Ensure that we have access rights to all fields to be inserted. */ + if (!((table && (table->grant.privilege & SELECT_ACL) || + tables->view && (tables->grant.privilege & SELECT_ACL))) && + !any_privileges) + { + field_iterator.set(tables); + if (check_grant_all_columns(thd, SELECT_ACL, field_iterator.grant(), + field_iterator.db_name(), field_iterator.table_name(), + &field_iterator)) + DBUG_RETURN(TRUE); + } +#endif + + + /* + Update the tables used in the query based on the referenced fields. For + views and natural joins this update is performed inside the loop below. + */ + if (table) + thd->used_tables|= table->map; + + /* + Initialize a generic field iterator for the current table reference. + Notice that it is guaranteed that this iterator will iterate over the + fields of a single table reference, because 'tables' is a leaf (for + name resolution purposes). + */ + field_iterator.set(tables); + + for (; !field_iterator.end_of_fields(); field_iterator.next()) + { + Item *not_used_item; + uint not_used_field_index= NO_CACHED_FIELD_INDEX; + const char *field_name= field_iterator.name(); + Item *item; + + /* If this is a column of a NATURAL/USING join, and the star was qualified + with a table (and database) name, check if the column is not a coalesced + one, and if not, that is belongs to the same table. + */ + if (tables->is_natural_join && table_name) { - if (tables->view) + if (field_iterator.is_coalesced() + || + my_strcasecmp(table_alias_charset, table_name, field_iterator.table_name()) + || + (db_name && strcmp(db_name, field_iterator.db_name()))) + continue; + } + + if (!(item= field_iterator.create_item(thd))) + DBUG_RETURN(TRUE); + + if (!found) + { + it->replace(item); /* Replace '*' with the first found item. */ + found= TRUE; + } + else + it->after(item); /* Add 'item' to the SELECT list. */ + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* + Set privilege information for the fields of newly created views. + We have that (any_priviliges == TRUE) if and only if we are creating + a view. In the time of view creation we can't use the MERGE algorithm, + therefore if 'tables' is itself a view, it is represented by a temporary + table. Thus in this case we can be sure that 'item' is an Item_field. + */ + if (any_privileges) + { + DBUG_ASSERT(tables->field_translation == NULL && table || + tables->is_natural_join); + DBUG_ASSERT(item->type() == Item::FIELD_ITEM); + Item_field *fld= (Item_field*) item; + const char *table_name= field_iterator.table_name(); + if (!tables->schema_table && + !(fld->have_privileges= + (get_column_grant(thd, field_iterator.grant(), + field_iterator.db_name(), + table_name, fld->field_name) & + VIEW_ANY_ACL))) { - view_iter.set(tables); - if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant, - tables->view_db.str, - tables->view_name.str, - &view_iter)) - goto err; - } - else if (!tables->schema_table) - { - DBUG_ASSERT(table != 0); - table_iter.set(tables); - if (check_grant_all_columns(thd, SELECT_ACL, &table->grant, - table->s->db, - table->s->table_name, - &table_iter)) - goto err; + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", + thd->priv_user, thd->host_or_ip, + fld->field_name, table_name); + DBUG_RETURN(TRUE); } } #endif - natural_join_table= 0; - last= embedded= tables; - while ((embedding= embedded->embedding) && - embedding->join_list->elements != 1) + if ((field= field_iterator.field())) { - TABLE_LIST *next; - List_iterator_fast it(embedding->nested_join->join_list); - last= it++; - while ((next= it++)) - last= next; - if (last != tables) - break; - embedded= embedding; - } + /* + Mark if field used before in this select. + Used by 'insert' to verify if a field name is used twice. + */ + if (field->query_id == thd->query_id) + thd->dupp_field= field; + field->query_id= thd->query_id; - if (tables == last && - !embedded->outer_join && - embedded->natural_join && - !embedded->natural_join->outer_join) - { - embedding= embedded->natural_join; - while (embedding->nested_join) - embedding= embedding->nested_join->join_list.head(); - natural_join_table= embedding; - } - if (tables->field_translation) - { - iterator= &view_iter; - view= 1; + if (table) + table->used_keys.intersect(field->part_of_key); + + if (tables->is_natural_join) + { + bool is_created; + TABLE *field_table; + /* + In this case we are shure that the column ref will not be created + because it was already created and stored with the natural join. + */ + Natural_join_column *nj_col; + if (!(nj_col= field_iterator.get_or_create_column_ref(thd, &is_created))) + DBUG_RETURN(TRUE); + DBUG_ASSERT(nj_col->table_field && !is_created); + field_table= nj_col->table_ref->table; + if (field_table) + { + thd->used_tables|= field_table->map; + field_table->used_keys.intersect(field->part_of_key); + field_table->used_fields++; + } + } } else { - iterator= &table_iter; - view= 0; + thd->used_tables|= item->used_tables(); + item->walk(&Item::reset_query_id_processor, + (byte *)(&thd->query_id)); } - iterator->set(tables); - - /* for view used tables will be collected in following loop */ - if (table) - thd->used_tables|= table->map; - - for (; !iterator->end_of_fields(); iterator->next()) - { - Item *not_used_item; - uint not_used_field_index= NO_CACHED_FIELD_INDEX; - const char *field_name= iterator->name(); - /* Skip duplicate field names if NATURAL JOIN is used */ - if (!natural_join_table || - !find_field_in_table(thd, natural_join_table, field_name, - field_name, - strlen(field_name), ¬_used_item, 0, 0, 0, - ¬_used_field_index, TRUE)) - { - Item *item= iterator->create_item(thd); - if (!item) - goto err; - thd->used_tables|= item->used_tables(); - if (!found++) - (void) it->replace(item); // Replace '*' - else - it->after(item); -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (any_privileges) - { - /* - In time of view creation MEGRGE algorithm for underlying - VIEWs can't be used => it should be Item_field - */ - DBUG_ASSERT(item->type() == Item::FIELD_ITEM); - Item_field *fld= (Item_field*)item; - char *db, *tab; - if (tables->view) - { - db= tables->view_db.str; - tab= tables->view_name.str; - } - else - { - db= tables->db; - tab= tables->table_name; - } - if (!tables->schema_table && - !(fld->have_privileges= (get_column_grant(thd, - &table->grant, - db, - tab, - fld->field_name) & - VIEW_ANY_ACL))) - { - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - "ANY", - thd->priv_user, - thd->host_or_ip, - fld->field_name, - tab); - goto err; - } - } -#endif - } - if ((field= iterator->field())) - { - /* - Mark if field used before in this select. - Used by 'insert' to verify if a field name is used twice - */ - if (field->query_id == thd->query_id) - thd->dupp_field=field; - field->query_id=thd->query_id; - table->used_keys.intersect(field->part_of_key); - } - else - { - Item *item= ((Field_iterator_view *) iterator)->item(); - item->walk(&Item::reset_query_id_processor, - (byte *)(&thd->query_id)); - } - } - /* - All fields are used in case if usual tables (in case of view used - fields marked in setup_tables during fix_fields of view columns - */ - if (table) - table->used_fields= table->s->fields; } + /* + In case of stored tables, all fields are considered as used, + while in the case of views, the fields considered as used are the + ones marked in setup_tables during fix_fields of view columns. + For NATURAL joins, used_tables is updated in the IF above. + */ + if (table) + table->used_fields= table->s->fields; } if (found) - DBUG_RETURN(0); + DBUG_RETURN(FALSE); + /* + TODO: in the case when we skipped all columns because there was a qualified + '*', and all columns were coalesced, we have to give a more meaningful message + than ER_BAD_TABLE_ERROR. + */ if (!table_name) my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0)); else my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name); -err: - DBUG_RETURN(1); + + DBUG_RETURN(TRUE); } /* - Fix all conditions and outer join expressions + Fix all conditions and outer join expressions. SYNOPSIS setup_conds() thd thread handler - leaves list of leaves of join table tree + tables list of tables for name resolving (select_lex->table_list) + leaves list of leaves of join table tree (select_lex->leaf_tables) + conds WHERE clause + + DESCRIPTION + TODO + + RETURN + TRUE if some error occured (e.g. out of memory) + FALSE if all is OK */ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, @@ -3640,11 +4484,14 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, goto err_no_arena; } - /* Check if we are using outer joins */ + /* + Apply fix_fields() to all ON clauses at all levels of nesting, + including the ones inside view definitions. + */ for (table= leaves; table; table= table->next_leaf) { - TABLE_LIST *embedded; - TABLE_LIST *embedding= table; + TABLE_LIST *embedded; /* The table at the current level of nesting. */ + TABLE_LIST *embedding= table; /* The parent nested table reference. */ do { embedded= embedding; @@ -3658,144 +4505,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, goto err_no_arena; select_lex->cond_count++; } - - if (embedded->natural_join) - { - /* Make a join of all fields wich have the same name */ - TABLE_LIST *tab1= embedded; - TABLE_LIST *tab2= embedded->natural_join; - if (!(embedded->outer_join & JOIN_TYPE_RIGHT)) - { - while (tab1->nested_join) - { - TABLE_LIST *next; - List_iterator_fast it(tab1->nested_join->join_list); - tab1= it++; - while ((next= it++)) - tab1= next; - } - } - else - { - while (tab1->nested_join) - tab1= tab1->nested_join->join_list.head(); - } - if (embedded->outer_join & JOIN_TYPE_RIGHT) - { - while (tab2->nested_join) - { - TABLE_LIST *next; - List_iterator_fast it(tab2->nested_join->join_list); - tab2= it++; - while ((next= it++)) - tab2= next; - } - } - else - { - while (tab2->nested_join) - tab2= tab2->nested_join->join_list.head(); - } - - if (arena) - arena= thd->change_arena_if_needed(&backup); - - TABLE *t1=tab1->table; - TABLE *t2=tab2->table; - Field_iterator_table table_iter; - Field_iterator_view view_iter; - Field_iterator *iterator; - Field *t1_field, *t2_field; - Item *item_t2= 0; - Item_cond_and *cond_and= new Item_cond_and(); - - if (!cond_and) // If not out of memory - goto err_no_arena; - cond_and->top_level_item(); - - if (table->field_translation) - { - iterator= &view_iter; - view_iter.set(tab1); - } - else - { - iterator= &table_iter; - table_iter.set(tab1); - } - - for (; !iterator->end_of_fields(); iterator->next()) - { - const char *t1_field_name= iterator->name(); - uint not_used_field_index= NO_CACHED_FIELD_INDEX; - - if ((t2_field= find_field_in_table(thd, tab2, t1_field_name, - t1_field_name, - strlen(t1_field_name), &item_t2, - 0, 0, 0, - ¬_used_field_index, - FALSE))) - { - if (t2_field != view_ref_found) - { - if (!(item_t2= new Item_field(thd, &select_lex->context, - t2_field))) - goto err; - /* Mark field used for table cache */ - t2_field->query_id= thd->query_id; - t2->used_keys.intersect(t2_field->part_of_key); - } - if ((t1_field= iterator->field())) - { - /* Mark field used for table cache */ - t1_field->query_id= thd->query_id; - t1->used_keys.intersect(t1_field->part_of_key); - } - Item_func_eq *tmp= new Item_func_eq(iterator->create_item(thd), - item_t2); - if (!tmp) - goto err; - cond_and->list.push_back(tmp); - } - } - select_lex->cond_count+= cond_and->list.elements; - - // to prevent natural join processing during PS re-execution - embedding->natural_join= 0; - - if (cond_and->list.elements) - { - COND *on_expr= cond_and; - if (!on_expr->fixed) - on_expr->fix_fields(thd, &on_expr); - if (!embedded->outer_join) // Not left join - { - *conds= and_conds(*conds, cond_and); - // fix_fields() should be made with temporary memory pool - if (arena) - thd->restore_backup_item_arena(arena, &backup); - if (*conds && !(*conds)->fixed) - { - if ((*conds)->fix_fields(thd, conds)) - goto err_no_arena; - } - } - else - { - embedded->on_expr= and_conds(embedded->on_expr, cond_and); - // fix_fields() should be made with temporary memory pool - if (arena) - thd->restore_backup_item_arena(arena, &backup); - if (embedded->on_expr && !embedded->on_expr->fixed) - { - if (embedded->on_expr->fix_fields(thd, &embedded->on_expr)) - goto err_no_arena; - } - } - } - else if (arena) - thd->restore_backup_item_arena(arena, &backup); - } embedding= embedded->embedding; } while (embedding && diff --git a/sql/sql_class.h b/sql/sql_class.h index 90112bd650b..3cf11a5e42a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1217,6 +1217,12 @@ public: ulonglong limit_found_rows; ha_rows cuted_fields, sent_row_count, examined_row_count; + /* + The set of those tables whose fields are referenced in all subqueries + of the query. + TODO: possibly this it is incorrect to have used tables in THD because + with more than one subquery, it is not clear what does the field mean. + */ table_map used_tables; USER_CONN *user_connect; CHARSET_INFO *db_charset; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d83937098e2..7972ddf2497 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -301,6 +301,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) DBUG_ENTER("mysql_prepare_delete"); if (setup_tables(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, table_list, conds, &select_lex->leaf_tables, FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || @@ -359,6 +360,7 @@ bool mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ if (setup_tables(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, lex->query_tables, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 6780beec258..0a89c3a29d7 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -75,7 +75,7 @@ enum enum_used_fields RETURN VALUES 0 all ok - 1 one of the fileds didn't finded + 1 one of the fileds was not found */ static bool init_fields(THD *thd, TABLE_LIST *tables, @@ -90,7 +90,7 @@ static bool init_fields(THD *thd, TABLE_LIST *tables, Item_field *field= new Item_field(context, "mysql", find_fields->table_name, find_fields->field_name); - if (!(find_fields->field= find_field_in_tables(thd, field, tables, + if (!(find_fields->field= find_field_in_tables(thd, field, tables, NULL, 0, REPORT_ALL_ERRORS, 1, TRUE))) DBUG_RETURN(1); @@ -631,12 +631,15 @@ bool mysqld_help(THD *thd, const char *mask) tables[0].alias= tables[0].table_name= (char*) "help_topic"; tables[0].lock_type= TL_READ; tables[0].next_global= tables[0].next_local= &tables[1]; + tables[0].next_name_resolution_table= tables[0].next_local; tables[1].alias= tables[1].table_name= (char*) "help_category"; tables[1].lock_type= TL_READ; tables[1].next_global= tables[1].next_local= &tables[2]; + tables[1].next_name_resolution_table= tables[1].next_local; tables[2].alias= tables[2].table_name= (char*) "help_relation"; tables[2].lock_type= TL_READ; tables[2].next_global= tables[2].next_local= &tables[3]; + tables[2].next_name_resolution_table= tables[2].next_local; tables[3].alias= tables[3].table_name= (char*) "help_keyword"; tables[3].lock_type= TL_READ; tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql"; @@ -655,6 +658,7 @@ bool mysqld_help(THD *thd, const char *mask) tables do not contain VIEWs => we can pass 0 as conds */ setup_tables(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, tables, 0, &leaves, FALSE); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 27342287fcd..ed5172e6974 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -106,12 +106,15 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - Name_resolution_context *context= &thd->lex->select_lex.context; - TABLE_LIST *save_next= table_list->next_local, - *save_context= context->table_list; - bool save_resolve_in_select_list= - thd->lex->select_lex.context.resolve_in_select_list; + SELECT_LEX *select_lex= &thd->lex->select_lex; + Name_resolution_context *context= &select_lex->context; + TABLE_LIST *save_next_local; + TABLE_LIST *save_table_list; + TABLE_LIST *save_first_name_resolution_table; + TABLE_LIST *save_next_name_resolution_table; + bool save_resolve_in_select_list; int res; + if (fields.elements != values.elements) { my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L); @@ -119,17 +122,39 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } thd->dupp_field=0; - thd->lex->select_lex.no_wrap_view_item= TRUE; - /* fields only from first table */ + select_lex->no_wrap_view_item= TRUE; + + /* Save the state of the current name resolution context. */ + save_table_list= context->table_list; + save_first_name_resolution_table= context->first_name_resolution_table; + save_next_name_resolution_table= (context->first_name_resolution_table) ? + context->first_name_resolution_table-> + next_name_resolution_table : + NULL; + save_resolve_in_select_list= context->resolve_in_select_list; + save_next_local= table_list->next_local; + + /* + Perform name resolution only in the first table - 'table_list', + which is the table that is inserted into. + */ table_list->next_local= 0; context->resolve_in_table_list_only(table_list); res= setup_fields(thd, 0, fields, 1, 0, 0); - table_list->next_local= save_next; + + /* Restore the current context. */ + table_list->next_local= save_next_local; + context->table_list= save_table_list; + context->first_name_resolution_table= save_first_name_resolution_table; + if (context->first_name_resolution_table) + context->first_name_resolution_table-> + next_name_resolution_table= save_next_name_resolution_table; + context->resolve_in_select_list= save_resolve_in_select_list; thd->lex->select_lex.no_wrap_view_item= FALSE; - context->table_list= save_context; - context->resolve_in_select_list= save_resolve_in_select_list; + if (res) return -1; + if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) { /* it is join view => we need to find table for update */ @@ -254,9 +279,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ulonglong id; COPY_INFO info; TABLE *table= 0; - TABLE_LIST *next_local; + TABLE_LIST *save_table_list; + TABLE_LIST *save_next_local; + TABLE_LIST *save_first_name_resolution_table; + TABLE_LIST *save_next_name_resolution_table; List_iterator_fast its(values_list); List_item *values; + Name_resolution_context *context; #ifndef EMBEDDED_LIBRARY char *query= thd->query; #endif @@ -335,9 +364,23 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert set table_list->table if it was not set */ table= table_list->table; - next_local= table_list->next_local; + context= &thd->lex->select_lex.context; + /* Save the state of the current name resolution context. */ + save_table_list= context->table_list; + save_first_name_resolution_table= context->first_name_resolution_table; + save_next_name_resolution_table= (context->first_name_resolution_table) ? + context->first_name_resolution_table-> + next_name_resolution_table : + NULL; + save_next_local= table_list->next_local; + + /* + Perform name resolution only in the first table - 'table_list', + which is the table that is inserted into. + */ table_list->next_local= 0; - thd->lex->select_lex.context.resolve_in_table_list_only(table_list); + context->resolve_in_table_list_only(table_list); + value_count= values->elements; while ((values= its++)) { @@ -351,7 +394,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, goto abort; } its.rewind (); - table_list->next_local= next_local; + + /* Restore the current context. */ + table_list->next_local= save_next_local; + context->first_name_resolution_table= save_first_name_resolution_table; + if (context->first_name_resolution_table) + context->first_name_resolution_table-> + next_name_resolution_table= save_next_name_resolution_table; + /* Fill in the given fields and dump it to the table file */ @@ -707,6 +757,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, DBUG_ENTER("mysql_prepare_insert_check_table"); if (setup_tables(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, table_list, where, &thd->lex->select_lex.leaf_tables, select_insert)) DBUG_RETURN(TRUE); @@ -761,10 +812,13 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, COND **where, bool select_insert) { SELECT_LEX *select_lex= &thd->lex->select_lex; + Name_resolution_context *context= &select_lex->context; TABLE_LIST *save_table_list; TABLE_LIST *save_next_local; + TABLE_LIST *save_first_name_resolution_table; + TABLE_LIST *save_next_name_resolution_table; + bool save_resolve_in_select_list; bool insert_into_view= (table_list->view != 0); - bool save_resolve_in_select_list; bool res= 0; DBUG_ENTER("mysql_prepare_insert"); DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", @@ -802,35 +856,57 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, select_insert)) DBUG_RETURN(TRUE); - save_table_list= select_lex->context.table_list; - save_resolve_in_select_list= select_lex->context.resolve_in_select_list; - save_next_local= table_list->next_local; + /* Save the state of the current name resolution context. */ + save_table_list= context->table_list; + /* Here first_name_resolution_table points to the first select table. */ + save_first_name_resolution_table= context->first_name_resolution_table; + save_next_name_resolution_table= (context->first_name_resolution_table) ? + context->first_name_resolution_table-> + next_name_resolution_table : + NULL; + save_resolve_in_select_list= context->resolve_in_select_list; + save_next_local= table_list->next_local; + /* + Perform name resolution only in the first table - 'table_list', + which is the table that is inserted into. + */ table_list->next_local= 0; - select_lex->context.resolve_in_table_list_only(table_list); - if ((values && check_insert_fields(thd, table_list, fields, *values, + context->resolve_in_table_list_only(table_list); + + /* Prepare the fields in the statement. */ + if ((values && check_insert_fields(thd, context->table_list, fields, *values, !insert_into_view)) || (values && setup_fields(thd, 0, *values, 0, 0, 0))) res= TRUE; else if (duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; - res= check_update_fields(thd, table_list, update_fields); + res= check_update_fields(thd, context->table_list, update_fields); select_lex->no_wrap_view_item= FALSE; if (select_lex->group_list.elements == 0) { /* When we are not using GROUP BY we can refer to other tables in the - ON DUPLICATE KEY part + ON DUPLICATE KEY part. */ - table_list->next_local= save_next_local; + context->table_list->next_local= save_next_local; + context->first_name_resolution_table-> + next_name_resolution_table= save_next_local; } if (!res) res= setup_fields(thd, 0, update_values, 1, 0, 0); } + + /* Restore the current context. */ table_list->next_local= save_next_local; - select_lex->context.table_list= save_table_list; - select_lex->context.resolve_in_select_list= save_resolve_in_select_list; + context->table_list= save_table_list; + context->first_name_resolution_table= save_first_name_resolution_table; + if (context->first_name_resolution_table) + context->first_name_resolution_table-> + next_name_resolution_table= save_next_name_resolution_table; + context->resolve_in_select_list= save_resolve_in_select_list; + if (res) DBUG_RETURN(res); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ccc0236997f..70b3e9e7427 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -118,8 +118,11 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->buf= lex->ptr= buf; lex->end_of_query= buf+length; + lex->context_stack.empty(); lex->unit.init_query(); lex->unit.init_select(); + /* 'parent_lex' is used in init_query() so it must be before it. */ + lex->select_lex.parent_lex= lex; lex->select_lex.init_query(); lex->value_list.empty(); lex->update_list.empty(); @@ -148,7 +151,6 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->leaf_tables_insert= lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; lex->variables_used= 0; - lex->select_lex.parent_lex= lex; lex->empty_field_list_on_rset= 0; lex->select_lex.select_number= 1; lex->next_state=MY_LEX_START; @@ -1114,6 +1116,11 @@ void st_select_lex::init_query() having_fix_field= 0; context.select_lex= this; context.init(); + /* + Add the name resolution context of the current (sub)query to the + stack of contexts for the whole query. + */ + parent_lex->push_context(&context); cond_count= with_wild= 0; conds_processed_with_permanent_arena= 0; ref_pointer_array= 0; @@ -1130,7 +1137,7 @@ void st_select_lex::init_select() { st_select_lex_node::init_select(); group_list.empty(); - type= db= db1= table1= db2= table2= 0; + type= db= 0; having= 0; use_index_ptr= ignore_index_ptr= 0; table_join_options= 0; @@ -1860,8 +1867,9 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) */ if ((*link_to_local= test(select_lex.table_list.first))) { - select_lex.table_list.first= (byte*) (select_lex.context.table_list= - first->next_local); + select_lex.context.table_list= first->next_local; + select_lex.context.first_name_resolution_table= first->next_local; + select_lex.table_list.first= (byte*) (first->next_local); select_lex.table_list.elements--; //safety first->next_local= 0; /* @@ -1966,8 +1974,8 @@ void st_lex::link_first_table_back(TABLE_LIST *first, if (link_to_local) { first->next_local= (TABLE_LIST*) select_lex.table_list.first; - select_lex.table_list.first= - (byte*) (select_lex.context.table_list= first); + select_lex.context.table_list= first; + select_lex.table_list.first= (byte*) first; select_lex.table_list.elements++; //safety } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4bba0c432c7..51d765889ba 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -471,14 +471,16 @@ class st_select_lex: public st_select_lex_node { public: Name_resolution_context context; - char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ + char *db; Item *where, *having; /* WHERE & HAVING clauses */ Item *prep_where; /* saved WHERE clause for prepared statement processing */ /* point on lex in which it was created, used in view subquery detection */ st_lex *parent_lex; enum olap_type olap; - SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ - List item_list; /* list of fields & expressions */ + /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */ + SQL_LIST table_list; + SQL_LIST group_list; /* GROUP BY clause. */ + List item_list; /* list of fields & expressions */ List interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; /* @@ -491,7 +493,12 @@ public: List top_join_list; /* join list of the top level */ List *join_list; /* list for the currently parsed join */ TABLE_LIST *embedding; /* table embedding to the above list */ - TABLE_LIST *leaf_tables; /* list of leaves in join table tree */ + /* + Beginning of the list of leaves in a FROM clause, where the leaves + inlcude all base tables including view tables. The tables are connected + by TABLE_LIST::next_leaf, so leaf_tables points to the left-most leaf. + */ + TABLE_LIST *leaf_tables; const char *type; /* type of select for EXPLAIN */ SQL_LIST order_list; /* ORDER clause */ @@ -593,7 +600,6 @@ public: bool init_nested_join(THD *thd); TABLE_LIST *end_nested_join(THD *thd); TABLE_LIST *nest_last_join(THD *thd); - void save_names_for_using_list(TABLE_LIST *tab1, TABLE_LIST *tab2); void add_joined_table(TABLE_LIST *table); TABLE_LIST *convert_right_join(); List* get_item_list(); @@ -735,6 +741,21 @@ typedef struct st_lex List var_list; List param_list; List view_list; // view list (list of field names in view) + /* + A stack of name resolution contexts for the query. This stack is used + at parse time to set local name resolution contexts for various parts + of a query. For example, in a JOIN ... ON (some_condition) clause the + Items in 'some_condition' must be resolved only against the operands + of the the join, and not against the whole clause. Similarly, Items in + subqueries should be resolved against the subqueries (and outer queries). + The stack is used in the following way: when the parser detects that + all Items in some clause need a local context, it creates a new context + and pushes it on the stack. All newly created Items always store the + top-most context in the stack. Once the parser leaves the clause that + required a local context, the parser pops the top-most context. + */ + List context_stack; + SQL_LIST proc_list, auxilliary_table_list, save_list; create_field *last_field; udf_func udf; @@ -926,6 +947,21 @@ typedef struct st_lex return ( query_tables_own_last ? *query_tables_own_last : 0); } void cleanup_after_one_table_open(); + + void push_context(Name_resolution_context *context) + { + context_stack.push_front(context); + } + + void pop_context() + { + context_stack.pop(); + } + + Name_resolution_context *current_context() + { + return context_stack.head(); + } } LEX; struct st_lex_local: public st_lex diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1ec209aba85..e1684f9bb11 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -150,6 +150,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); if (setup_tables(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, table_list, &unused_conds, &thd->lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(-1); diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 71e8fe4149f..b457ff5a6d6 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -153,7 +153,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) List all_fields(select_lex->item_list); - if (setup_tables(lex->thd, &select_lex->context, + if (setup_tables(lex->thd, &select_lex->context, &select_lex->top_join_list, (TABLE_LIST *)select_lex->table_list.first &select_lex->where, &select_lex->leaf_tables, FALSE) || setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) || diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f1950d36b23..7ecbc9dbb19 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2141,6 +2141,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, { TABLE_LIST **query_tables_last= lex->query_tables_last; sel= new SELECT_LEX(); + /* 'parent_lex' is used in init_query() so it must be before it. */ + sel->parent_lex= lex; sel->init_query(); if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, (List *) 0, (List *) 0)) @@ -3244,19 +3246,26 @@ end_with_restore_list: if (!(res= open_and_lock_tables(thd, all_tables))) { /* Skip first table, which is the table we are inserting in */ - select_lex->table_list.first= (byte*)first_table->next_local; - + TABLE_LIST *second_table= first_table->next_local; + select_lex->table_list.first= (byte*) second_table; + select_lex->context.table_list= second_table; + select_lex->context.first_name_resolution_table= second_table; res= mysql_insert_select_prepare(thd); - lex->select_lex.context.table_list= first_table->next_local; if (!res && (result= new select_insert(first_table, first_table->table, &lex->field_list, &lex->update_list, &lex->value_list, lex->duplicates, lex->ignore))) { - /* Skip first table, which is the table we are inserting in */ + /* + Skip first table, which is the table we are inserting in. + Below we set context.table_list again because the call above to + mysql_insert_select_prepare() calls resolve_in_table_list_only(), + which in turn resets context.table_list and + context.first_name_resolution_table. + */ select_lex->context.table_list= first_table->next_local; - + select_lex->context.first_name_resolution_table= first_table->next_local; res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); delete result; } @@ -5204,9 +5213,9 @@ mysql_new_select(LEX *lex, bool move_down) if (!(select_lex= new (thd->mem_root) SELECT_LEX())) DBUG_RETURN(1); select_lex->select_number= ++thd->select_number; + select_lex->parent_lex= lex; /* Used in init_query. */ select_lex->init_query(); select_lex->init_select(); - select_lex->parent_lex= lex; /* Don't evaluate this subquery during statement prepare even if it's a constant one. The flag is switched off in the end of @@ -5264,6 +5273,7 @@ mysql_new_select(LEX *lex, bool move_down) fake->include_standalone(unit, (SELECT_LEX_NODE**)&unit->fake_select_lex); fake->select_number= INT_MAX; + fake->parent_lex= lex; /* Used in init_query. */ fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; fake->select_limit= 0; @@ -5272,6 +5282,11 @@ mysql_new_select(LEX *lex, bool move_down) /* allow item list resolving in fake select for ORDER BY */ fake->context.resolve_in_select_list= TRUE; fake->context.select_lex= fake; + /* + Remove the name resolution context of the fake select from the + context stack. + */ + lex->pop_context(); } select_lex->context.outer_context= outer_context; } @@ -5959,6 +5974,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, LEX_STRING *option) { register TABLE_LIST *ptr; + TABLE_LIST *previous_table_ref; /* The table preceding the current one. */ char *alias_str; LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); @@ -6054,8 +6070,29 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } } } - /* Link table in local list (list for current select) */ + /* Store the table reference preceding the current one. */ + if (table_list.elements > 0) + { + previous_table_ref= (TABLE_LIST*) table_list.next; + DBUG_ASSERT(previous_table_ref); + } + /* + Link the current table reference in a local list (list for current select). + Notice that as a side effect here we set the next_local field of the + previous table reference to 'ptr'. Here we also add one element to the + list 'table_list'. + */ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local); + /* + Set next_name_resolution_table of the previous table reference to point to + the current table reference. In effect the list + TABLE_LIST::next_name_resolution_table coincides with + TABLE_LIST::next_local. Later this may be changed in + store_top_level_join_columns() for NATURAL/USING joins. + */ + if (table_list.elements > 1) + previous_table_ref->next_name_resolution_table= ptr; + ptr->next_name_resolution_table= NULL; /* Link table in global list (all used tables) */ lex->add_to_query_tables(ptr); DBUG_RETURN(ptr); @@ -6184,6 +6221,19 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) table->join_list= embedded_list; table->embedding= ptr; embedded_list->push_back(table); + if (table->natural_join) + { + ptr->is_natural_join= TRUE; + /* + If this is a JOIN ... USING, move the list of joined fields to the + table reference that describes the join. + */ + if (table->join_using_fields) + { + ptr->join_using_fields= table->join_using_fields; + table->join_using_fields= NULL; + } + } } join_list->push_front(ptr); nested_join->used_tables= nested_join->not_null_tables= (table_map) 0; @@ -6191,44 +6241,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) } -/* - Save names for a join with using clause - - SYNOPSIS - save_names_for_using_list - tab1 left table in join - tab2 right table in join - - DESCRIPTION - The function saves the full names of the tables in st_select_lex - to be able to build later an on expression to replace the using clause. - - RETURN VALUE - None -*/ - -void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1, - TABLE_LIST *tab2) -{ - while (tab1->nested_join) - { - tab1= tab1->nested_join->join_list.head(); - } - db1= tab1->db; - table1= tab1->alias; - while (tab2->nested_join) - { - TABLE_LIST *next; - List_iterator_fast it(tab2->nested_join->join_list); - tab2= it++; - while ((next= it++)) - tab2= next; - } - db2= tab2->db; - table2= tab2->alias; -} - - /* Add a table to the current join list @@ -6332,16 +6344,71 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) } -void add_join_on(TABLE_LIST *b,Item *expr) +/* + Create a new name resolution context for a JOIN ... ON clause. + + SYNOPSIS + make_join_on_context() + thd pointer to current thread + left_op lefto operand of the JOIN + right_op rigth operand of the JOIN + + DESCRIPTION + Create a new name resolution context for a JOIN ... ON clause, + and set the first and last leaves of the list of table references + to be used for name resolution. + + RETURN + A new context if all is OK + NULL - if a memory allocation error occured +*/ + +Name_resolution_context * +make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op) +{ + Name_resolution_context *on_context; + if (!(on_context= (Name_resolution_context*) + thd->calloc(sizeof(Name_resolution_context)))) + return NULL; + on_context->init(); + on_context->first_name_resolution_table= + left_op->first_leaf_for_name_resolution(); + on_context->last_name_resolution_table= + right_op->last_leaf_for_name_resolution(); + return on_context; +} + + +/* + Add an ON condition to the second operand of a JOIN ... ON. + + SYNOPSIS + add_join_on + b the second operand of a JOIN ... ON + expr the condition to be added to the ON clause + + DESCRIPTION + Add an ON condition to the right operand of a JOIN ... ON clause. + + RETURN + FALSE if there was some error + TRUE if all is OK +*/ + +void add_join_on(TABLE_LIST *b, Item *expr) { if (expr) { if (!b->on_expr) - b->on_expr=expr; + b->on_expr= expr; else { - /* This only happens if you have both a right and left join */ - b->on_expr=new Item_cond_and(b->on_expr,expr); + /* + If called from the parser, this happens if you have both a + right and left join. If called later, it happens if we add more + than one condition to the ON clause. + */ + b->on_expr= new Item_cond_and(b->on_expr,expr); } b->on_expr->top_level_item(); } @@ -6349,28 +6416,49 @@ void add_join_on(TABLE_LIST *b,Item *expr) /* - Mark that we have a NATURAL JOIN between two tables + Mark that there is a NATURAL JOIN or JOIN ... USING between two + tables. SYNOPSIS add_join_natural() - a Table to do normal join with - b Do normal join with this table - + a Left join argument + b Right join argument + using_fields Field names from USING clause + IMPLEMENTATION - This function just marks that table b should be joined with a. - The function setup_cond() will create in b->on_expr a list - of equal condition between all fields of the same name. + This function marks that table b should be joined with a either via + a NATURAL JOIN or via JOIN ... USING. Both join types are special + cases of each other, so we treat them together. The function + setup_conds() creates a list of equal condition between all fields + of the same name for NATURAL JOIN or the fields in 'using_fields' + for JOIN ... USING. The list of equality conditions is stored + either in b->on_expr, or in JOIN::conds, depending on whether there + was an outer join. + EXAMPLE SELECT * FROM t1 NATURAL LEFT JOIN t2 <=> SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... ) + + SELECT * FROM t1 NATURAL JOIN t2 WHERE + <=> + SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and ) + + SELECT * FROM t1 JOIN t2 USING(j) WHERE + <=> + SELECT * FROM t1, t2 WHERE (t1.j=t2.j and ) + + RETURN + None */ -void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) +void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields) { - b->natural_join=a; + b->natural_join= a; + b->join_using_fields= using_fields; } + /* Reload/resets privileges and the different caches. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bf5b0542917..41f61574545 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -338,7 +338,7 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ if ((!(select_options & OPTION_SETUP_TABLES_DONE) && - setup_tables(thd, &select_lex->context, + setup_tables(thd, &select_lex->context, join_list, tables_list, &conds, &select_lex->leaf_tables, FALSE)) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || @@ -11881,13 +11881,14 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) SYNOPSIS find_order_in_list() - thd Pointer to current thread structure - ref_pointer_array All select, group and order by fields - tables List of tables to search in (usually FROM clause) - order Column reference to be resolved - fields List of fields to search in (usually SELECT list) - all_fields All select, group and order by fields - is_group_field True if order is a GROUP field, false if ORDER by field + thd [in] Pointer to current thread structure + ref_pointer_array [in/out] All select, group and order by fields + tables [in] List of tables to search in (usually FROM clause) + order [in] Column reference to be resolved + fields [in] List of fields to search in (usually SELECT list) + all_fields [in/out] All select, group and order by fields + is_group_field [in] True if order is a GROUP field, false if + ORDER by field DESCRIPTION Given a column reference (represented by 'order') from a GROUP BY or ORDER @@ -11963,7 +11964,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, order_item_type == Item::REF_ITEM) { from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables, - &view_ref, IGNORE_ERRORS, TRUE, + NULL, &view_ref, IGNORE_ERRORS, TRUE, FALSE); if (!from_field) from_field= (Field*) not_found_field; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 7ccf475b65e..1a7457386f0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2061,6 +2061,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { int res; TABLE *old_open_tables= thd->open_tables; + /* + Set the parent lex of 'sel' because it is needed by sel.init_query() + which is called inside make_table_list. + */ + sel.parent_lex= lex; if (make_table_list(thd, &sel, base_name, file_name)) goto err; TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8a5b4ad8eae..ce8a3855b11 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -555,7 +555,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.table= table; tables.alias= table_list->alias; - if (setup_tables(thd, &select_lex->context, + if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, table_list, conds, &select_lex->leaf_tables, FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || @@ -642,6 +642,7 @@ bool mysql_multi_update_prepare(THD *thd) */ if (setup_tables(thd, &lex->select_lex.context, + &lex->select_lex.top_join_list, table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); @@ -760,6 +761,7 @@ bool mysql_multi_update_prepare(THD *thd) tbl->cleanup_items(); if (setup_tables(thd, &lex->select_lex.context, + &lex->select_lex.top_join_list, table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE) || setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b680787b9a3..d5d0ac8fff0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -717,7 +717,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); bool_term bool_factor bool_test bool_pri predicate bit_expr bit_term bit_factor value_expr term factor table_wild simple_expr udf_expr - using_list expr_or_default set_expr_or_default interval_expr + expr_or_default set_expr_or_default interval_expr param_marker singlerow_subselect singlerow_subselect_init exists_subselect exists_subselect_init geometry_function signed_literal now_or_signed_literal opt_escape @@ -739,7 +739,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); key_alg opt_btree_or_rtree %type - key_usage_list + key_usage_list using_list %type key_part @@ -4420,10 +4420,10 @@ simple_expr: my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str); YYABORT; } - $$= new Item_default_value(&Select->context, $3); + $$= new Item_default_value(Lex->current_context(), $3); } | VALUES '(' simple_ident ')' - { $$= new Item_insert_value(&Select->context, $3); } + { $$= new Item_insert_value(Lex->current_context(), $3); } | FUNC_ARG0 '(' ')' { if (!$1.symbol->create_func) @@ -4714,9 +4714,9 @@ simple_expr: name->init_qname(YYTHD); sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); if ($5) - $$= new Item_func_sp(&lex->current_select->context, name, *$5); + $$= new Item_func_sp(Lex->current_context(), name, *$5); else - $$= new Item_func_sp(&lex->current_select->context, name); + $$= new Item_func_sp(Lex->current_context(), name); lex->safe_to_cache_query=0; } | IDENT_sys '(' udf_expr_list ')' @@ -4804,9 +4804,9 @@ simple_expr: sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); if ($3) - $$= new Item_func_sp(&lex->current_select->context, name, *$3); + $$= new Item_func_sp(Lex->current_context(), name, *$3); else - $$= new Item_func_sp(&lex->current_select->context, name); + $$= new Item_func_sp(Lex->current_context(), name); lex->safe_to_cache_query=0; } } @@ -5010,7 +5010,7 @@ sum_expr: { SELECT_LEX *sel= Select; sel->in_sum_expr--; - $$=new Item_func_group_concat(&sel->context, $3, $5, + $$=new Item_func_group_concat(Lex->current_context(), $3, $5, sel->gorder_list, $7); $5->empty(); }; @@ -5146,68 +5146,116 @@ join_table: table_ref normal_join table_ref { YYERROR_UNLESS($1 && ($$=$3)); } | table_ref STRAIGHT_JOIN table_factor { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; } - | table_ref normal_join table_ref ON expr - { YYERROR_UNLESS($1 && ($$=$3)); add_join_on($3,$5); } - | table_ref STRAIGHT_JOIN table_factor ON expr - { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; add_join_on($3,$5); } + | table_ref normal_join table_ref + ON + { + YYERROR_UNLESS($1 && ($$=$3)); + /* Change the current name resolution context to a local context. */ + Name_resolution_context *on_context; + if (!(on_context= make_join_on_context(YYTHD,$1,$3))) + YYABORT; + Lex->push_context(on_context); + } + expr + { + add_join_on($3,$6); + Lex->pop_context(); + } + | table_ref STRAIGHT_JOIN table_factor + ON + { + YYERROR_UNLESS($1 && ($$=$3)); + /* Change the current name resolution context to a local context. */ + Name_resolution_context *on_context; + if (!(on_context= make_join_on_context(YYTHD,$1,$3))) + YYABORT; + Lex->push_context(on_context); + } + expr + { + $3->straight=1; + add_join_on($3,$6); + Lex->pop_context(); + } | table_ref normal_join table_ref USING { SELECT_LEX *sel= Select; YYERROR_UNLESS($1 && $3); - sel->save_names_for_using_list($1, $3); } '(' using_list ')' - { add_join_on($3,$7); $$=$3; } - - | table_ref LEFT opt_outer JOIN_SYM table_ref ON expr - { YYERROR_UNLESS($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } + { add_join_natural($1,$3,$7); $$=$3; } + | table_ref LEFT opt_outer JOIN_SYM table_ref + ON + { + /* Change the current name resolution context to a local context. */ + Name_resolution_context *on_context; + if (!(on_context= make_join_on_context(YYTHD,$1,$5))) + YYABORT; + Lex->push_context(on_context); + } + expr + { + YYERROR_UNLESS($1 && $5); + add_join_on($5,$8); + Lex->pop_context(); + $5->outer_join|=JOIN_TYPE_LEFT; + $$=$5; + } | table_ref LEFT opt_outer JOIN_SYM table_factor { SELECT_LEX *sel= Select; YYERROR_UNLESS($1 && $5); - sel->save_names_for_using_list($1, $5); } USING '(' using_list ')' - { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } + { add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor { YYERROR_UNLESS($1 && $6); - add_join_natural($1,$6); + add_join_natural($1,$6,NULL); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } - | table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr + | table_ref RIGHT opt_outer JOIN_SYM table_ref + ON + { + /* Change the current name resolution context to a local context. */ + Name_resolution_context *on_context; + if (!(on_context= make_join_on_context(YYTHD,$1,$5))) + YYABORT; + Lex->push_context(on_context); + } + expr { LEX *lex= Lex; YYERROR_UNLESS($1 && $5); if (!($$= lex->current_select->convert_right_join())) YYABORT; - add_join_on($$, $7); + add_join_on($$, $8); + Lex->pop_context(); } | table_ref RIGHT opt_outer JOIN_SYM table_factor { SELECT_LEX *sel= Select; YYERROR_UNLESS($1 && $5); - sel->save_names_for_using_list($1, $5); } USING '(' using_list ')' { LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; - add_join_on($$, $9); + add_join_natural($$,$5,$9); } | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor { YYERROR_UNLESS($1 && $6); - add_join_natural($6,$1); + add_join_natural($6,$1,NULL); LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; } | table_ref NATURAL JOIN_SYM table_factor - { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4); }; + { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4,NULL); }; normal_join: @@ -5235,8 +5283,23 @@ table_factor: YYABORT; sel->add_joined_table($$); } - | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}' - { YYERROR_UNLESS($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } + | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref + ON + { + /* Change the current name resolution context to a local context. */ + Name_resolution_context *on_context; + if (!(on_context= make_join_on_context(YYTHD,$3,$7))) + YYABORT; + Lex->push_context(on_context); + } + expr '}' + { + YYERROR_UNLESS($3 && $7); + add_join_on($7,$10); + Lex->pop_context(); + $7->outer_join|=JOIN_TYPE_LEFT; + $$=$7; + } | select_derived_init get_select_lex select_derived2 { LEX *lex= Lex; @@ -5290,6 +5353,7 @@ table_factor: YYABORT; sel->add_joined_table($$); + lex->pop_context(); } else if ($4 || $6) @@ -5429,32 +5493,18 @@ key_usage_list2: using_list: ident { - SELECT_LEX *sel= Select; - if (!($$= new Item_func_eq(new Item_field(&sel->context, - sel->db1, sel->table1, - $1.str), - new Item_field(&sel->context, - sel->db2, sel->table2, - $1.str)))) + if (!($$= new List)) YYABORT; + $$->push_back(new (YYTHD->mem_root) + String((const char *) $1.str, $1.length, + system_charset_info)); } | using_list ',' ident { - SELECT_LEX *sel= Select; - if (!($$= - new Item_cond_and(new - Item_func_eq(new - Item_field(&sel->context, - sel->db1, - sel->table1, - $3.str), - new - Item_field(&sel->context, - sel->db2, - sel->table2, - $3.str)), - $1))) - YYABORT; + $1->push_back(new (YYTHD->mem_root) + String((const char *) $3.str, $3.length, + system_charset_info)); + $$= $1; }; interval: @@ -6095,7 +6145,7 @@ values: expr_or_default: expr { $$= $1;} - | DEFAULT {$$= new Item_default_value(&Select->context); } + | DEFAULT {$$= new Item_default_value(Lex->current_context()); } ; opt_insert_update: @@ -7051,13 +7101,13 @@ table_wild: ident '.' '*' { SELECT_LEX *sel= Select; - $$ = new Item_field(&sel->context, NullS, $1.str, "*"); + $$ = new Item_field(Lex->current_context(), NullS, $1.str, "*"); sel->with_wild++; } | ident '.' ident '.' '*' { SELECT_LEX *sel= Select; - $$ = new Item_field(&sel->context, (YYTHD->client_capabilities & + $$ = new Item_field(Lex->current_context(), (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str,"*"); sel->with_wild++; @@ -7085,8 +7135,8 @@ simple_ident: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : - (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); + (Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) : + (Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str); } } | simple_ident_q { $$= $1; } @@ -7098,8 +7148,8 @@ simple_ident_nospvar: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : - (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); + (Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) : + (Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str); } | simple_ident_q { $$= $1; } ; @@ -7136,7 +7186,7 @@ simple_ident_q: YYABORT; } - if (!(trg_fld= new Item_trigger_field(&lex->current_select->context, + if (!(trg_fld= new Item_trigger_field(Lex->current_context(), new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, @@ -7162,8 +7212,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(&sel->context, NullS, $1.str, $3.str) : - (Item*) new Item_ref(&sel->context, NullS, $1.str, $3.str); + (Item*) new Item_field(Lex->current_context(), NullS, $1.str, $3.str) : + (Item*) new Item_ref(Lex->current_context(), NullS, $1.str, $3.str); } } | '.' ident '.' ident @@ -7178,8 +7228,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(&sel->context, NullS, $2.str, $4.str) : - (Item*) new Item_ref(&sel->context, NullS, $2.str, $4.str); + (Item*) new Item_field(Lex->current_context(), NullS, $2.str, $4.str) : + (Item*) new Item_ref(Lex->current_context(), NullS, $2.str, $4.str); } | ident '.' ident '.' ident { @@ -7193,11 +7243,11 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(&sel->context, + (Item*) new Item_field(Lex->current_context(), (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str) : - (Item*) new Item_ref(&sel->context, + (Item*) new Item_ref(Lex->current_context(), (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str); @@ -7761,8 +7811,7 @@ sys_option_value: it= new Item_null(); } - if (!(trg_fld= new Item_trigger_field(&lex->current_select-> - context, + if (!(trg_fld= new Item_trigger_field(Lex->current_context(), Item_trigger_field::NEW_ROW, $2.base_name.str)) || !(i= new sp_instr_set_trigger_field(lex->sphead-> @@ -8618,7 +8667,12 @@ union_list: lex->current_select->master_unit()->union_distinct= lex->current_select; } - select_init {} + select_init + { + /* Remove from the name resolution context stack the context of the + last select in the union. */ + Lex->pop_context(); + } ; union_opt: @@ -8722,6 +8776,7 @@ subselect_end: ')' { LEX *lex=Lex; + lex->pop_context(); lex->current_select = lex->current_select->return_after_parsing(); }; diff --git a/sql/table.cc b/sql/table.cc index 0324e29abf3..83ec2d64935 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2147,8 +2147,296 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) } +/* + Test if this is a leaf with respect to name resolution. + + SYNOPSIS + st_table_list::is_leaf_for_name_resolution() + + DESCRIPTION + A table reference is a leaf with respect to name resolution if + it is either a leaf node in a nested join tree (table, view, + schema table, subquery), or an inner node that represents a + NATURAL/USING join, or a nested join with materialized join + columns. + + RETURN + TRUE if a leaf, FALSE otherwise. +*/ +bool st_table_list::is_leaf_for_name_resolution() +{ + return (view || is_natural_join || is_join_columns_complete || + !nested_join); +} + + +/* + Retrieve the first (left-most) leaf in a nested join tree with + respect to name resolution. + + SYNOPSIS + st_table_list::first_leaf_for_name_resolution() + + DESCRIPTION + Given that 'this' is a nested table reference, recursively walk + down the left-most children of 'this' until we reach a leaf + table reference with respect to name resolution. + + IMPLEMENTATION + The left-most child of a nested table reference is the last element + in the list of children because the children are inserted in + reverse order. + + RETURN + - If 'this' is a nested table reference - the left-most child of + the tree rooted in 'this', + - else - 'this' +*/ + +TABLE_LIST *st_table_list::first_leaf_for_name_resolution() +{ + TABLE_LIST *cur_table_ref= this; + TABLE_LIST *next; + NESTED_JOIN *cur_nested_join= nested_join; + + if (this->is_leaf_for_name_resolution()) + return this; + + while (cur_nested_join) + { + List_iterator_fast it(cur_nested_join->join_list); + cur_table_ref= it++; + /* + If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse + order, thus the first operand is already at the front of the list. + */ + if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT)) + { + while ((next= it++)) + cur_table_ref= next; + } + if (cur_table_ref->is_leaf_for_name_resolution()) + break; + cur_nested_join= cur_table_ref->nested_join; + } + return cur_table_ref; +} + + +/* + Retrieve the last (right-most) leaf in a nested join tree with + respect to name resolution. + + SYNOPSIS + st_table_list::last_leaf_for_name_resolution() + + DESCRIPTION + Given that 'this' is a nested table reference, recursively walk + down the right-most children of 'this' until we reach a leaf + table reference with respect to name resolution. + + IMPLEMENTATION + The right-most child of a nested table reference is the first + element in the list of children because the children are inserted + in reverse order. + + RETURN + - If 'this' is a nested table reference - the right-most child of + the tree rooted in 'this', + - else - 'this' +*/ + +TABLE_LIST *st_table_list::last_leaf_for_name_resolution() +{ + TABLE_LIST *cur_table_ref= this; + TABLE_LIST *next; + NESTED_JOIN *cur_nested_join= nested_join; + + if (this->is_leaf_for_name_resolution()) + return this; + + while (cur_nested_join) + { + /* + If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse + order, thus the last operand is in the end of the list. + */ + if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT)) + { + List_iterator_fast it(cur_nested_join->join_list); + cur_table_ref= it++; + while ((next= it++)) + cur_table_ref= next; + } + else + cur_table_ref= cur_nested_join->join_list.head(); + if (cur_table_ref->is_leaf_for_name_resolution()) + break; + cur_nested_join= cur_table_ref->nested_join; + } + return cur_table_ref; +} + + +Natural_join_column::Natural_join_column(Field_translator *field_param, + TABLE_LIST *tab) +{ + DBUG_ASSERT(tab->field_translation); + view_field= field_param; + table_field= NULL; + table_ref= tab; + is_common= FALSE; + is_coalesced= FALSE; +} + + +Natural_join_column::Natural_join_column(Field *field_param, + TABLE_LIST *tab) +{ + table_field= field_param; + view_field= NULL; + table_ref= tab; + is_common= FALSE; + is_coalesced= FALSE; +} + + +const char *Natural_join_column::name() +{ + if (view_field) + { + DBUG_ASSERT(table_field == NULL); + return view_field->name; + } + else + { + DBUG_ASSERT(view_field == NULL); + return table_field->field_name; + } +} + + +Item *Natural_join_column::create_item(THD *thd) +{ + if (view_field) + { + DBUG_ASSERT(table_field == NULL); + return create_view_field(thd, table_ref, &view_field->item, view_field->name); + } + else + { + DBUG_ASSERT(view_field == NULL); + return new Item_field(thd, &thd->lex->current_select->context, table_field); + } +} + + +Field *Natural_join_column::field() +{ + if (view_field) + { + DBUG_ASSERT(table_field == NULL); + return NULL; + } + else + { + DBUG_ASSERT(view_field == NULL); + return table_field; + } +} + + +const char *Natural_join_column::table_name() +{ + return table_ref->alias; +/* + TODO: I think that it is sufficient to return just + table->alias, which is correctly set to either + the view name, the table name, or the alias to + the table reference (view or stored table). + if (view_field) + return table_ref->view_name.str; + else + { + DBUG_ASSERT(!strcmp(table_ref->table_name, + table_ref->table->s->table_name)); + return table_ref->table_name; + } +*/ +} + + +const char *Natural_join_column::db_name() +{ + if (view_field) + return table_ref->view_db.str; + else + { + DBUG_ASSERT(!strcmp(table_ref->db, + table_ref->table->s->db)); + return table_ref->db; + } +} + + +GRANT_INFO *Natural_join_column::grant() +{ + if (view_field) + return &(table_ref->grant); + else + return &(table_ref->table->grant); +} + + + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + +/* + Check the access rights for the current join column. + columns. + + SYNOPSIS + Natural_join_column::check_grants() + + DESCRIPTION + Check the access rights to a column from a natural join in a generic + way that hides the heterogeneity of the column representation - whether + it is a view or a stored table colum. + + RETURN + FALSE - if the column can be accessed + TRUE - if there are no access rights to all equivalent columns +*/ + +bool +Natural_join_column::check_grants(THD *thd, const char *name, uint length) +{ + GRANT_INFO *grant= NULL; /* If NULL do not check access rights. */ + const char *db_name; + const char *table_name; + if (view_field) + { + DBUG_ASSERT(table_field == NULL); + grant= &(table_ref->grant); + db_name= table_ref->view_db.str; + table_name= table_ref->view_name.str; + } + else + { + DBUG_ASSERT(table_field && view_field == NULL); + grant= &(table_ref->table->grant); + db_name= table_ref->table->s->db; + table_name= table_ref->table->s->table_name; + } + + return check_grant_column(thd, grant, db_name, table_name, name, length); +} +#endif + + void Field_iterator_view::set(TABLE_LIST *table) { + DBUG_ASSERT(table->field_translation); view= table; ptr= table->field_translation; array_end= table->field_translation_end; @@ -2218,6 +2506,191 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, } +void Field_iterator_natural_join::set(TABLE_LIST *table_ref) +{ + DBUG_ASSERT(table_ref->join_columns); + delete column_ref_it; + + /* + TODO: try not to allocate new iterator every time. If we have to, + then check for out of memory condition. + */ + column_ref_it= new List_iterator_fast + (*(table_ref->join_columns)); + cur_column_ref= (*column_ref_it)++; +} + + +void Field_iterator_table_ref::set_field_iterator() +{ + DBUG_ENTER("Field_iterator_table_ref::set_field_iterator"); + /* + If the table reference we are iterating over is a natural join, or it is + an operand of a natural join, and TABLE_LIST::join_columns contains all + the columns of the join operand, then we pick the columns from + TABLE_LIST::join_columns, instead of the orginial container of the + columns of the join operator. + */ + if (table_ref->is_join_columns_complete) + { + /* Necesary, but insufficient conditions. */ + DBUG_ASSERT(table_ref->is_natural_join || + table_ref->nested_join || + table_ref->join_columns && + /* This is a merge view. */ + ((table_ref->field_translation && + table_ref->join_columns->elements == + (ulong)(table_ref->field_translation_end - + table_ref->field_translation)) || + /* This is stored table or a tmptable view. */ + (!table_ref->field_translation && + table_ref->join_columns->elements == + table_ref->table->s->fields))); + natural_join_it.set(table_ref); + field_it= &natural_join_it; + DBUG_PRINT("info",("field_it for '%s' is Field_iterator_natural_join", + table_ref->table_name)); + } + /* This is a merge view, so use field_translation. */ + else if (table_ref->field_translation) + { + DBUG_ASSERT(table_ref->view && + table_ref->effective_algorithm == VIEW_ALGORITHM_MERGE); + view_field_it.set(table_ref); + field_it= &view_field_it; + DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_view", + table_ref->table_name)); + } + /* This is a base table or stored view. */ + else + { + DBUG_ASSERT(table_ref->table || table_ref->view); + table_field_it.set(table_ref); + field_it= &table_field_it; + DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_table", + table_ref->table_name)); + + } + DBUG_VOID_RETURN; +} + + +void Field_iterator_table_ref::set(TABLE_LIST *table) +{ + DBUG_ASSERT(table); + first_leaf= table->first_leaf_for_name_resolution(); + last_leaf= table->last_leaf_for_name_resolution(); + DBUG_ASSERT(first_leaf && last_leaf); + table_ref= first_leaf; + set_field_iterator(); +} + + +void Field_iterator_table_ref::next() +{ + /* Move to the next field in the current table reference. */ + field_it->next(); + /* + If all fields of the current table reference are exhausted, move to + the next leaf table reference. + */ + if (field_it->end_of_fields() && table_ref != last_leaf) + { + table_ref= table_ref->next_name_resolution_table; + DBUG_ASSERT(table_ref); + set_field_iterator(); + } +} + + +const char *Field_iterator_table_ref::table_name() +{ + if (table_ref->view) + return table_ref->view_name.str; + else if (table_ref->is_natural_join) + return natural_join_it.column_ref()->table_name(); + else + { + DBUG_ASSERT(!strcmp(table_ref->table_name, + table_ref->table->s->table_name)); + return table_ref->table_name; + } +} + + +const char *Field_iterator_table_ref::db_name() +{ + if (table_ref->view) + return table_ref->view_db.str; + else if (table_ref->is_natural_join) + return natural_join_it.column_ref()->db_name(); + else + { + DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db)); + return table_ref->db; + } +} + + +GRANT_INFO *Field_iterator_table_ref::grant() +{ + if (table_ref->view) + return &(table_ref->grant); + else if (table_ref->is_natural_join) + return natural_join_it.column_ref()->grant(); + else + return &(table_ref->table->grant); +} + + +bool Field_iterator_table_ref::is_coalesced() +{ + if (table_ref->is_natural_join) + return natural_join_it.column_ref()->is_coalesced; + else + return FALSE; +} + +/* + Create new or return existing column reference to a column of a + natural/using join. + + SYNOPSIS + Field_iterator_table_ref::get_or_create_column_ref() + thd [in] pointer to current thread + is_created [out] set to TRUE if the column was created, + FALSE if we return an already created colum + + DESCRIPTION + TODO + + RETURN + Pointer to a column of a natural join (or its operand) + NULL if there was no memory to allocate the column +*/ + +Natural_join_column * +Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created) +{ + *is_created= TRUE; + if (field_it == &table_field_it) + return new Natural_join_column(table_field_it.field(), table_ref); + else if (field_it == &view_field_it) + return new Natural_join_column(view_field_it.field_translator(), table_ref); + else + { + /* + This is NATURAL join, we already have created a column reference, + so just return it. + */ + *is_created= FALSE; + Natural_join_column *nj_col= natural_join_it.column_ref(); + DBUG_ASSERT(nj_col); + return nj_col; + } +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/table.h b/sql/table.h index 13d44766804..74e676d7596 100644 --- a/sql/table.h +++ b/sql/table.h @@ -92,7 +92,10 @@ class Field_timestamp; class Field_blob; class Table_triggers_list; -/* This structure is shared between different table objects */ +/* + This structure is shared between different table objects. There is one + instance of table share per one table in the database. +*/ typedef struct st_table_share { @@ -350,9 +353,86 @@ struct Field_translator }; +/* + Column reference of a NATURAL/USING join. Since column references in + joins can be both from views and stored tables, may point to either a + Field (for tables), or a Field_translator (for views). +*/ + +class Natural_join_column +{ +public: + Field_translator *view_field; /* Column reference of merge view. */ + Field *table_field; /* Column reference of table or temp view. */ + st_table_list *table_ref; /* Original base table/view reference. */ + /* + True if a common join column of two NATURAL/USING join operands. Notice + that when we have a hierarchy of nested NATURAL/USING joins, a column can + be common at some level of nesting but it may not be common at higher + levels of nesting. Thus this flag may change depending on at which level + we are looking at some column. + */ + bool is_common; + /* + A column is coalesced if it was common in some of several nested NATURAL/ + USING joins. We have to know this, because according to ANSI, coalesced + columns cannot be qualified. + */ + bool is_coalesced; +public: + Natural_join_column(Field_translator *field_param, st_table_list *tab); + Natural_join_column(Field *field_param, st_table_list *tab); + const char *name(); + Item *create_item(THD *thd); + Field *field(); + const char *table_name(); + const char *db_name(); + GRANT_INFO *grant(); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + bool check_grants(THD *thd, const char *name, uint length); +#endif +}; + + +/* + Table reference in the FROM clause. + + These table references can be of several types that correspond to + different SQL elements. Below we list all types of TABLE_LISTs with + the necessary conditions to determine when a TABLE_LIST instance + belongs to a certain type. + + 1) table (TABLE_LIST::view == NULL) + - base table + (TABLE_LIST::derived == NULL) + - subquery - TABLE_LIST::table is a temp table + (TABLE_LIST::derived != NULL) + - information schema table + (TABLE_LIST::schema_table != NULL) + NOTICE: for schema tables TABLE_LIST::field_translation may be != NULL + 2) view (TABLE_LIST::view != NULL) + - merge (TABLE_LIST::effective_algorithm == VIEW_ALGORITHM_MERGE) + also (TABLE_LIST::field_translation != NULL) + - tmptable (TABLE_LIST::effective_algorithm == VIEW_ALGORITHM_TMPTABLE) + also (TABLE_LIST::field_translation == NULL) + 3) nested table reference (TABLE_LIST::nested_join != NULL) + - table sequence - e.g. (t1, t2, t3) + TODO: how to distinguish from a JOIN? + - general JOIN + TODO: how to distinguish from a table sequence? + - NATURAL JOIN + (TABLE_LIST::natural_join != NULL) + - JOIN ... USING + (TABLE_LIST::join_using_fields != NULL) +*/ + typedef struct st_table_list { - /* link in a local table list (used by SQL_LIST) */ + /* + List of tables local to a subquery (used by SQL_LIST). Considers + views as leaves (unlike 'next_leaf' below). Created at parse time + in st_select_lex::add_table_to_list() -> table_list.link_in_list(). + */ struct st_table_list *next_local; /* link in a global list of all queries tables */ struct st_table_list *next_global, **prev_global; @@ -360,7 +440,7 @@ typedef struct st_table_list char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ /* - The scturcture of ON expression presented in the member above + The structure of ON expression presented in the member above can be changed during certain optimizations. This member contains a snapshot of AND-OR structure of the ON expression made after permanent transformations of the parse tree, and is @@ -369,10 +449,40 @@ typedef struct st_table_list */ Item *prep_on_expr; COND_EQUAL *cond_equal; /* Used with outer join */ - struct st_table_list *natural_join; /* natural join on this table*/ - /* ... join ... USE INDEX ... IGNORE INDEX */ - List *use_index, *ignore_index; - TABLE *table; /* opened table */ + /* + During parsing - left operand of NATURAL/USING join where 'this' is + the right operand. After parsing (this->natural_join == this) iff + 'this' represents a NATURAL or USING join operation. Thus after + parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). + */ + struct st_table_list *natural_join; + /* + True if 'this' represents a nested join that is a NATURAL JOIN. + For one of the operands of 'this', the member 'natural_join' points + to the other operand of 'this'. + */ + bool is_natural_join; + /* Field names in a USING clause for JOIN ... USING. */ + List *join_using_fields; + /* + Explicitly store the result columns of either a NATURAL/USING join or + an operand of such a join. + */ + List *join_columns; + /* TRUE if join_columns contains all columns of this table reference. */ + bool is_join_columns_complete; + + /* + List of nodes in a nested join tree, that should be considered as + leaves with respect to name resolution. The leaves are: views, + top-most nodes representing NATURAL/USING joins, subqueries, and + base tables. All of these TABLE_LIST instances contain a + materialized list of columns. The list is local to a subquery. + */ + struct st_table_list *next_name_resolution_table; + /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ + List *use_index, *ignore_index; + TABLE *table; /* opened table */ /* select_result for derived table to pass it from table creation to table filling procedure @@ -389,6 +499,10 @@ 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; + /* + True when the view field translation table is used to convert + schema table fields for backwards compatibility with SHOW command. + */ bool schema_table_reformed; TMP_TABLE_PARAM *schema_table_param; /* link to select_lex where this table was used */ @@ -401,7 +515,11 @@ typedef struct st_table_list st_table_list *ancestor; /* most upper view this table belongs to */ st_table_list *belong_to_view; - /* list of join table tree leaves */ + /* + List of all base tables local to a subquery including all view + tables. Unlike 'next_local', this in this list views are *not* + leaves. Created in setup_tables() -> make_leaves_list(). + */ st_table_list *next_leaf; Item *where; /* VIEW WHERE clause condition */ Item *check_option; /* WITH CHECK OPTION condition */ @@ -471,6 +589,9 @@ typedef struct st_table_list bool set_insert_values(MEM_ROOT *mem_root); void hide_view_error(THD *thd); st_table_list *find_underlying_table(TABLE *table); + st_table_list *first_leaf_for_name_resolution(); + st_table_list *last_leaf_for_name_resolution(); + bool is_leaf_for_name_resolution(); inline bool prepare_check_option(THD *thd) { bool res= FALSE; @@ -492,6 +613,10 @@ private: class Item; +/* + Iterator over the fields of a generic table reference. +*/ + class Field_iterator: public Sql_alloc { public: @@ -505,6 +630,11 @@ public: }; +/* + Iterator over the fields of a base table, view with temporary + table, or subquery. +*/ + class Field_iterator_table: public Field_iterator { Field **ptr; @@ -520,6 +650,8 @@ public: }; +/* Iterator over the fields of a merge view. */ + class Field_iterator_view: public Field_iterator { Field_translator *ptr, *array_end; @@ -533,8 +665,71 @@ public: Item *create_item(THD *thd); Item **item_ptr() {return &ptr->item; } Field *field() { return 0; } - inline Item *item() { return ptr->item; } + Field_translator *field_translator() { return ptr; } +}; + + +/* + Field_iterator interface to the list of materialized fields of a + NATURAL/USING join. +*/ + +class Field_iterator_natural_join: public Field_iterator +{ + List_iterator_fast *column_ref_it; + Natural_join_column *cur_column_ref; +public: + Field_iterator_natural_join() :column_ref_it(NULL), cur_column_ref(NULL) {} + ~Field_iterator_natural_join() { delete column_ref_it; } + void set(TABLE_LIST *table); + void next() { cur_column_ref= (*column_ref_it)++; } + bool end_of_fields() { return !cur_column_ref; } + const char *name() { return cur_column_ref->name(); } + Item *create_item(THD *thd) { return cur_column_ref->create_item(thd); } + Field *field() { return cur_column_ref->field(); } + Natural_join_column *column_ref() { return cur_column_ref; } +}; + + +/* + Generic iterator over the fields of an arbitrary table reference. + + DESCRIPTION + This class unifies the various ways of iterating over the columns + of a table reference depending on the type of SQL entity it + represents. If such an entity represents a nested table reference, + this iterator encapsulates the iteration over the columns of the + members of the table reference. + + IMPLEMENTATION + The implementation assumes that all underlying NATURAL/USING table + references already contain their result columns and are linked into + the list TABLE_LIST::next_name_resolution_table. +*/ + +class Field_iterator_table_ref: public Field_iterator +{ + TABLE_LIST *table_ref, *first_leaf, *last_leaf; + Field_iterator_table table_field_it; + Field_iterator_view view_field_it; + Field_iterator_natural_join natural_join_it; + Field_iterator *field_it; + void set_field_iterator(); +public: + Field_iterator_table_ref() :field_it(NULL) {} + void set(TABLE_LIST *table); + void next(); + bool end_of_fields() + { return (table_ref == last_leaf && field_it->end_of_fields()); } + const char *name() { return field_it->name(); } + const char *table_name(); + const char *db_name(); + GRANT_INFO *grant(); + bool is_coalesced(); + Item *create_item(THD *thd) { return field_it->create_item(thd); } + Field *field() { return field_it->field(); } + Natural_join_column *get_or_create_column_ref(THD *thd, bool *is_created); }; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 53708a7a741..aa323ebb76b 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11801,8 +11801,8 @@ static void test_bug6046() stmt= mysql_stmt_init(mysql); - stmt_text= "SELECT t1.a FROM t1 NATURAL JOIN t1 as X1 " - "WHERE t1.b > ? ORDER BY t1.a"; + stmt_text= "SELECT a FROM t1 NATURAL JOIN t1 as X1 " + "WHERE b > ? ORDER BY a"; rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); From 8f115aafd71a38ebcdff9725ee07002cedcefbb6 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Fri, 12 Aug 2005 20:10:24 +0300 Subject: [PATCH 098/230] WL#2486 Disabled one test case because it is still a problem due to the fix for WL#2486. Pushed to enable code review. --- mysql-test/r/join.result | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 5ea863b4bdb..b7a2f0ce4f4 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -121,10 +121,6 @@ id catid stateid countyid drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); -select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); -a -1 -2 select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); ERROR HY000: Too many tables; MySQL can only use XX tables in a join drop table t1; From 0f9b9829707b8c83dd022b4faaddf7790cb4279c Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Fri, 12 Aug 2005 22:42:50 +0400 Subject: [PATCH 099/230] Fix bug #12298 Typo in timestampdiff() function name results in erroneous view being created. Item_func_timestamp_diff::func_name() were returning function name as "timestamp_diff" thus when view was executed function parameters wasn't properly recognized and error was raised. --- mysql-test/r/func_time.result | 2 +- mysql-test/r/view.result | 5 +++++ mysql-test/t/view.test | 7 ++++++- sql/item_timefunc.h | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 63da5589c57..28eb48790e0 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -687,7 +687,7 @@ timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select timestamp_diff(WEEK,_latin1'2001-02-01',_latin1'2001-05-01') AS `a1`,timestamp_diff(SECOND_FRAC,_latin1'2001-02-01 12:59:59.120000',_latin1'2001-05-01 12:58:58.119999') AS `a2` +Note 1003 select timestampdiff(WEEK,_latin1'2001-02-01',_latin1'2001-05-01') AS `a1`,timestampdiff(SECOND_FRAC,_latin1'2001-02-01 12:59:59.120000',_latin1'2001-05-01 12:58:58.119999') AS `a2` select last_day('2005-00-00'); last_day('2005-00-00') NULL diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 87e80a03c08..2af2f06ad52 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2092,3 +2092,8 @@ SELECT a FROM v1; a DROP VIEW v1; DROP TABLE t1,t2,t3,t4,t5; +create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00:00:00') as f1; +select * from v1; +f1 +1 +drop view v1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 961b8ec13d6..ceff7af401c 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1936,4 +1936,9 @@ SELECT a FROM v1; DROP VIEW v1; DROP TABLE t1,t2,t3,t4,t5; - +# +# Bug #12298 Typo in function name results in erroneous view being created. +# +create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00:00:00') as f1; +select * from v1; +drop view v1; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index e79bc25030b..d9300451fe7 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -860,7 +860,7 @@ class Item_func_timestamp_diff :public Item_int_func public: Item_func_timestamp_diff(Item *a,Item *b,interval_type type_arg) :Item_int_func(a,b), int_type(type_arg) {} - const char *func_name() const { return "timestamp_diff"; } + const char *func_name() const { return "timestampdiff"; } longlong val_int(); void fix_length_and_dec() { From f693d22bb1a57904e531799416245e49b9659f1a Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Fri, 12 Aug 2005 11:44:25 -0700 Subject: [PATCH 100/230] Make sure to clean up temporary files in myisampack even when the -T option is used. (Bug #12235) --- myisam/myisampack.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 88f38be3c54..405c69544e7 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -609,14 +609,22 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) else error=my_rename(new_name,org_name,MYF(MY_WME)); if (!error) + { VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME))); + if (tmp_dir[0]) + VOID(my_delete(new_name,MYF(MY_WME))); + } } } else { if (tmp_dir[0]) + { error=my_copy(new_name,org_name, MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_COPYTIME)); + if (!error) + VOID(my_delete(new_name,MYF(MY_WME))); + } else error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME)); } From f5ff607c142f6bef2cbf7f3a9ddab22df06127f9 Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Fri, 12 Aug 2005 21:15:01 +0200 Subject: [PATCH 101/230] BUG#12162 - one can start two transactions with the same XID. Now we keep all active XID's in a hash --- mysql-test/r/xa.result | 4 +- mysql-test/t/xa.test | 4 ++ sql/ha_innodb.cc | 2 +- sql/handler.cc | 63 +++++++++++------------------- sql/handler.h | 9 ++++- sql/mysqld.cc | 6 +++ sql/share/errmsg.txt | 2 + sql/sql_base.cc | 2 +- sql/sql_class.cc | 89 +++++++++++++++++++++++++++++++++++++++++- sql/sql_class.h | 43 +++++++++++++------- sql/sql_parse.cc | 80 +++++++++++++++++++++++-------------- 11 files changed, 211 insertions(+), 93 deletions(-) diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result index 1dde495d6ae..f3d7e151628 100644 --- a/mysql-test/r/xa.result +++ b/mysql-test/r/xa.result @@ -22,6 +22,8 @@ a xa start 'testa','testb'; insert t1 values (30); xa end 'testa','testb'; +xa start 'testa','testb'; +ERROR XAE08: XAER_DUPID: The XID already exists xa start 0x7465737462, 0x2030405060, 0xb; insert t1 values (40); xa end 'testb',' 0@P`',11; @@ -35,11 +37,11 @@ formatID gtrid_length bqual_length data 11 5 5 testb 0@P` 1 5 5 testatestb xa commit 'testb',0x2030405060,11; +ERROR XAE04: XAER_NOTA: Unknown XID xa rollback 'testa','testb'; xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 select * from t1; a 20 -40 drop table t1; diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test index 321e5008035..aa921516110 100644 --- a/mysql-test/t/xa.test +++ b/mysql-test/t/xa.test @@ -31,6 +31,9 @@ xa end 'testa','testb'; connect (con1,localhost,,,); connection con1; +--error 1438 +xa start 'testa','testb'; + # gtrid [ , bqual [ , formatID ] ] xa start 0x7465737462, 0x2030405060, 0xb; insert t1 values (40); @@ -47,6 +50,7 @@ xa prepare 'testa','testb'; xa recover; +--error 1397 xa commit 'testb',0x2030405060,11; xa rollback 'testa','testb'; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 8dd45c03350..4aeeb954e17 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -7037,7 +7037,7 @@ innobase_xa_prepare( return(0); } - trx->xid=thd->transaction.xid; + trx->xid=thd->transaction.xid_state.xid; /* Release a possible FIFO ticket and search latch. Since we will reserve the kernel mutex, we have to release the search system latch diff --git a/sql/handler.cc b/sql/handler.cc index 5a8762a615e..0b247f83af1 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -547,8 +547,8 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) trans->ht[trans->nht++]=ht_arg; DBUG_ASSERT(*ht == ht_arg); trans->no_2pc|=(ht_arg->prepare==0); - if (thd->transaction.xid.is_null()) - thd->transaction.xid.set(thd->query_id); + if (thd->transaction.xid_state.xid.is_null()) + thd->transaction.xid_state.xid.set(thd->query_id); DBUG_VOID_RETURN; } @@ -595,7 +595,7 @@ int ha_commit_trans(THD *thd, bool all) THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt; bool is_real_trans= all || thd->transaction.all.nht == 0; handlerton **ht= trans->ht; - my_xid xid= thd->transaction.xid.get_my_xid(); + my_xid xid= thd->transaction.xid_state.xid.get_my_xid(); DBUG_ENTER("ha_commit_trans"); if (thd->in_sub_stmt) @@ -695,7 +695,7 @@ int ha_commit_one_phase(THD *thd, bool all) trans->nht=0; trans->no_2pc=0; if (is_real_trans) - thd->transaction.xid.null(); + thd->transaction.xid_state.xid.null(); if (all) { #ifdef HAVE_QUERY_CACHE @@ -751,7 +751,7 @@ int ha_rollback_trans(THD *thd, bool all) trans->nht=0; trans->no_2pc=0; if (is_real_trans) - thd->transaction.xid.null(); + thd->transaction.xid_state.xid.null(); if (all) { thd->variables.tx_isolation=thd->session_tx_isolation; @@ -945,6 +945,7 @@ int ha_recover(HASH *commit_list) char buf[XIDDATASIZE*4+6]; // see xid_to_str sql_print_information("ignore xid %s", xid_to_str(buf, list+i)); #endif + xid_cache_insert(list+i, XA_PREPARED); found_foreign_xids++; continue; } @@ -1008,10 +1009,8 @@ bool mysql_xa_recover(THD *thd) { List field_list; Protocol *protocol= thd->protocol; - handlerton **ht= handlertons, **end_ht=ht+total_ha; - bool error=TRUE; - int len, got; - XID *list=0; + int i=0; + XID_STATE *xs; DBUG_ENTER("mysql_xa_recover"); field_list.push_back(new Item_int("formatID",0,11)); @@ -1021,48 +1020,30 @@ bool mysql_xa_recover(THD *thd) if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); - - for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2) - { - list=(XID *)my_malloc(len*sizeof(XID), MYF(0)); - } - if (!list) - { - my_error(ER_OUTOFMEMORY, MYF(0), len); DBUG_RETURN(1); - } - for ( ; ht < end_ht ; ht++) + pthread_mutex_lock(&LOCK_xid_cache); + while (xs=(XID_STATE*)hash_element(&xid_cache, i++)) { - if (!(*ht)->recover) - continue; - while ((got=(*(*ht)->recover)(list, len)) > 0 ) + if (xs->xa_state==XA_PREPARED) { - XID *xid, *end; - for (xid=list, end=list+got; xid < end; xid++) + protocol->prepare_for_resend(); + protocol->store_longlong((longlong)xs->xid.formatID, FALSE); + protocol->store_longlong((longlong)xs->xid.gtrid_length, FALSE); + protocol->store_longlong((longlong)xs->xid.bqual_length, FALSE); + protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length, + &my_charset_bin); + if (protocol->write()) { - if (xid->get_my_xid()) - continue; // skip "our" xids - protocol->prepare_for_resend(); - protocol->store_longlong((longlong)xid->formatID, FALSE); - protocol->store_longlong((longlong)xid->gtrid_length, FALSE); - protocol->store_longlong((longlong)xid->bqual_length, FALSE); - protocol->store(xid->data, xid->gtrid_length+xid->bqual_length, - &my_charset_bin); - if (protocol->write()) - goto err; + pthread_mutex_unlock(&LOCK_xid_cache); + DBUG_RETURN(1); } - if (got < len) - break; } } - error=FALSE; + pthread_mutex_unlock(&LOCK_xid_cache); send_eof(thd); -err: - my_free((gptr)list, MYF(0)); - DBUG_RETURN(error); + DBUG_RETURN(0); } /* diff --git a/sql/handler.h b/sql/handler.h index 276f50bde63..ef45676207b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -227,11 +227,11 @@ struct xid_t { char data[XIDDATASIZE]; // not \0-terminated ! bool eq(struct xid_t *xid) - { return !memcmp(this, xid, sizeof(long)*3+gtrid_length+bqual_length); } + { return !memcmp(this, xid, length()); } bool eq(long g, long b, const char *d) { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); } void set(struct xid_t *xid) - { memcpy(this, xid, sizeof(long)*3+xid->gtrid_length+xid->bqual_length); } + { memcpy(this, xid, xid->length()); } void set(long f, const char *g, long gl, const char *b, long bl) { formatID= f; @@ -270,6 +270,11 @@ struct xid_t { !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ? quick_get_my_xid() : 0; } + uint length() + { + return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+ + gtrid_length+bqual_length; + } }; typedef struct xid_t XID; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f8bfcb75be2..73080959c44 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1050,6 +1050,7 @@ void clean_up(bool print_message) (void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */ if (tc_log) tc_log->close(); + xid_cache_free(); delete_elements(&key_caches, (void (*)(const char*, gptr)) free_key_cache); multi_keycache_free(); end_thr_alarm(1); /* Free allocated memory */ @@ -2920,6 +2921,11 @@ server."); using_update_log=1; } + if (xid_cache_init()) + { + sql_print_error("Out of memory"); + unireg_abort(1); + } if (ha_init()) { sql_print_error("Can't init databases"); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5dd5cd9c775..a987e0fd82d 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5388,3 +5388,5 @@ ER_STACK_OVERRUN_NEED_MORE eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack." ER_TOO_LONG_BODY 42000 S1009 eng "Routine body for '%-.100s' is too long" +ER_XAER_DUPID XAE08 + eng "XAER_DUPID: The XID already exists" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5ff5e580f81..0836274b704 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -502,7 +502,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived, */ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt)); if (!thd->active_transaction()) - thd->transaction.xid.null(); + thd->transaction.xid_state.xid.null(); /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */ if (!lock_in_use) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 56d3194765b..fd972423bc6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -323,7 +323,8 @@ void THD::init_for_queries() variables.trans_alloc_block_size, variables.trans_prealloc_size); #endif - transaction.xid.null(); + transaction.xid_state.xid.null(); + transaction.xid_state.in_thd=1; } @@ -358,9 +359,15 @@ void THD::cleanup(void) { DBUG_ENTER("THD::cleanup"); #ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE - if (transaction.xa_state != XA_PREPARED) + if (transaction.xid_state.xa_state == XA_PREPARED) + { +#error xid_state in the cache should be replaced by the allocated value + } #endif + { ha_rollback(this); + xid_cache_delete(&transaction.xid_state); + } if (locked_tables) { lock=locked_tables; locked_tables=0; @@ -1841,3 +1848,81 @@ void THD::pop_open_tables_state() set_open_tables_state(state); DBUG_VOID_RETURN; } + +pthread_mutex_t LOCK_xid_cache; +HASH xid_cache; + +static byte *xid_get_hash_key(const byte *ptr,uint *length, + my_bool not_used __attribute__((unused))) +{ + *length=((XID_STATE*)ptr)->xid.length(); + return (byte *)&((XID_STATE*)ptr)->xid; +} + +static void xid_free_hash (void *ptr) +{ + if (!((XID_STATE*)ptr)->in_thd) + my_free((byte *)ptr, MYF(0)); +} + +bool xid_cache_init() +{ + pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST); + hash_init(&xid_cache, &my_charset_bin, 100, 0, 0, + xid_get_hash_key, xid_free_hash, 0) != 0; +} + +void xid_cache_free() +{ + if (hash_inited(&xid_cache)) + { + hash_free(&xid_cache); + pthread_mutex_destroy(&LOCK_xid_cache); + } +} + +XID_STATE *xid_cache_search(XID *xid) +{ + pthread_mutex_lock(&LOCK_xid_cache); + XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, (byte *)xid, xid->length()); + pthread_mutex_unlock(&LOCK_xid_cache); + return res; +} + +bool xid_cache_insert(XID *xid, enum xa_states xa_state) +{ + XID_STATE *xs; + my_bool res; + pthread_mutex_lock(&LOCK_xid_cache); + if (hash_search(&xid_cache, (byte *)xid, xid->length())) + res=0; + else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME)))) + res=1; + else + { + xs->xa_state=xa_state; + xs->xid.set(xid); + xs->in_thd=0; + res=my_hash_insert(&xid_cache, (byte*)xs); + } + pthread_mutex_unlock(&LOCK_xid_cache); + return res; +} + +bool xid_cache_insert(XID_STATE *xid_state) +{ + pthread_mutex_lock(&LOCK_xid_cache); + DBUG_ASSERT(hash_search(&xid_cache, (byte *)&xid_state->xid, + xid_state->xid.length())==0); + my_bool res=my_hash_insert(&xid_cache, (byte*)xid_state); + pthread_mutex_unlock(&LOCK_xid_cache); + return res; +} + +void xid_cache_delete(XID_STATE *xid_state) +{ + pthread_mutex_lock(&LOCK_xid_cache); + hash_delete(&xid_cache, (byte *)xid_state); + pthread_mutex_unlock(&LOCK_xid_cache); +} + diff --git a/sql/sql_class.h b/sql/sql_class.h index ad4f38946a3..c1ac2990331 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -351,8 +351,6 @@ public: inline uint32 get_open_count() { return open_count; } }; -/* character conversion tables */ - typedef struct st_copy_info { ha_rows records; @@ -564,11 +562,11 @@ struct system_variables my_bool ndb_use_transactions; #endif /* HAVE_NDBCLUSTER_DB */ my_bool old_passwords; - + /* Only charset part of these variables is sensible */ - CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_client; CHARSET_INFO *character_set_results; - + /* Both charset and collation parts of these variables are important */ CHARSET_INFO *collation_server; CHARSET_INFO *collation_database; @@ -631,7 +629,7 @@ typedef struct system_status_var ulong filesort_range_count; ulong filesort_rows; ulong filesort_scan_count; - /* Ppepared statements and binary protocol */ + /* Prepared statements and binary protocol */ ulong com_stmt_prepare; ulong com_stmt_execute; ulong com_stmt_send_long_data; @@ -656,8 +654,8 @@ void free_tmp_table(THD *thd, TABLE *entry); /* The following macro is to make init of Query_arena simpler */ #ifndef DBUG_OFF #define INIT_ARENA_DBUG_INFO is_backup_arena= 0 -#else -#define INIT_ARENA_DBUG_INFO +#else +#define INIT_ARENA_DBUG_INFO #endif @@ -925,6 +923,22 @@ struct st_savepoint { enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED}; extern const char *xa_state_names[]; +typedef struct st_xid_state { + /* For now, this is only used to catch duplicated external xids */ + XID xid; // transaction identifier + enum xa_states xa_state; // used by external XA only + bool in_thd; +} XID_STATE; + +extern pthread_mutex_t LOCK_xid_cache; +extern HASH xid_cache; +bool xid_cache_init(void); +void xid_cache_free(void); +XID_STATE *xid_cache_search(XID *xid); +bool xid_cache_insert(XID *xid, enum xa_states xa_state); +bool xid_cache_insert(XID_STATE *xid_state); +void xid_cache_delete(XID_STATE *xid_state); + /* A registry for item tree transformations performed during query optimization. We register only those changes which require @@ -946,7 +960,7 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1, /* - Class that holds information about tables which were open and locked + Class that holds information about tables which were opened and locked by the thread. It is also used to save/restore this information in push_open_tables_state()/pop_open_tables_state(). */ @@ -1062,7 +1076,7 @@ public: // the lock_id of a cursor. pthread_mutex_t LOCK_delete; // Locked before thd is deleted /* all prepared statements and cursors of this connection */ - Statement_map stmt_map; + Statement_map stmt_map; /* A pointer to the stack frame of handle_one_connection(), which is called first in the thread for handling a client @@ -1132,10 +1146,10 @@ public: thr_lock_type update_lock_default; delayed_insert *di; my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ - + /* TRUE if we are inside of trigger or stored function. */ bool in_sub_stmt; - + /* container for handler's private per-connection data */ void *ha_data[MAX_HA]; struct st_transactions { @@ -1143,8 +1157,7 @@ public: THD_TRANS all; // Trans since BEGIN WORK THD_TRANS stmt; // Trans for current statement bool on; // see ha_enable_transaction() - XID xid; // transaction identifier - enum xa_states xa_state; // used by external XA only + XID_STATE xid_state; /* Tables changed in transaction (that must be invalidated in query cache). List contain only transactional tables, that not invalidated in query @@ -1164,7 +1177,7 @@ public: st_transactions() { bzero((char*)this, sizeof(*this)); - xid.null(); + xid_state.xid.null(); init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); } #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 677b3a98174..1d7d1637ff7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2017,7 +2017,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, */ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt)); if (!thd->active_transaction()) - thd->transaction.xid.null(); + thd->transaction.xid_state.xid.null(); /* report error issued during command execution */ if (thd->killed_errno() && !thd->net.report_error) @@ -4502,14 +4502,15 @@ end_with_restore_list: break; } case SQLCOM_XA_START: - if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME) + if (thd->transaction.xid_state.xa_state == XA_IDLE && + thd->lex->xa_opt == XA_RESUME) { - if (! thd->transaction.xid.eq(thd->lex->xid)) + if (! thd->transaction.xid_state.xid.eq(thd->lex->xid)) { my_error(ER_XAER_NOTA, MYF(0)); break; } - thd->transaction.xa_state=XA_ACTIVE; + thd->transaction.xid_state.xa_state=XA_ACTIVE; send_ok(thd); break; } @@ -4518,10 +4519,10 @@ end_with_restore_list: my_error(ER_XAER_INVAL, MYF(0)); break; } - if (thd->transaction.xa_state != XA_NOTR) + if (thd->transaction.xid_state.xa_state != XA_NOTR) { my_error(ER_XAER_RMFAIL, MYF(0), - xa_state_names[thd->transaction.xa_state]); + xa_state_names[thd->transaction.xid_state.xa_state]); break; } if (thd->active_transaction() || thd->locked_tables) @@ -4529,9 +4530,15 @@ end_with_restore_list: my_error(ER_XAER_OUTSIDE, MYF(0)); break; } - DBUG_ASSERT(thd->transaction.xid.is_null()); - thd->transaction.xa_state=XA_ACTIVE; - thd->transaction.xid.set(thd->lex->xid); + if (xid_cache_search(thd->lex->xid)) + { + my_error(ER_XAER_DUPID, MYF(0)); + break; + } + DBUG_ASSERT(thd->transaction.xid_state.xid.is_null()); + thd->transaction.xid_state.xa_state=XA_ACTIVE; + thd->transaction.xid_state.xid.set(thd->lex->xid); + xid_cache_insert(&thd->transaction.xid_state); thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; @@ -4544,28 +4551,28 @@ end_with_restore_list: my_error(ER_XAER_INVAL, MYF(0)); break; } - if (thd->transaction.xa_state != XA_ACTIVE) + if (thd->transaction.xid_state.xa_state != XA_ACTIVE) { my_error(ER_XAER_RMFAIL, MYF(0), - xa_state_names[thd->transaction.xa_state]); + xa_state_names[thd->transaction.xid_state.xa_state]); break; } - if (!thd->transaction.xid.eq(thd->lex->xid)) + if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) { my_error(ER_XAER_NOTA, MYF(0)); break; } - thd->transaction.xa_state=XA_IDLE; + thd->transaction.xid_state.xa_state=XA_IDLE; send_ok(thd); break; case SQLCOM_XA_PREPARE: - if (thd->transaction.xa_state != XA_IDLE) + if (thd->transaction.xid_state.xa_state != XA_IDLE) { my_error(ER_XAER_RMFAIL, MYF(0), - xa_state_names[thd->transaction.xa_state]); + xa_state_names[thd->transaction.xid_state.xa_state]); break; } - if (!thd->transaction.xid.eq(thd->lex->xid)) + if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) { my_error(ER_XAER_NOTA, MYF(0)); break; @@ -4573,22 +4580,28 @@ end_with_restore_list: if (ha_prepare(thd)) { my_error(ER_XA_RBROLLBACK, MYF(0)); - thd->transaction.xa_state=XA_NOTR; + xid_cache_delete(&thd->transaction.xid_state); + thd->transaction.xid_state.xa_state=XA_NOTR; break; } - thd->transaction.xa_state=XA_PREPARED; + thd->transaction.xid_state.xa_state=XA_PREPARED; send_ok(thd); break; case SQLCOM_XA_COMMIT: - if (!thd->transaction.xid.eq(thd->lex->xid)) + if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) { - if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 1))) + XID_STATE *xs=xid_cache_search(thd->lex->xid); + if (!xs || xs->in_thd) my_error(ER_XAER_NOTA, MYF(0)); else + { + ha_commit_or_rollback_by_xid(thd->lex->xid, 1); + xid_cache_delete(xs); send_ok(thd); + } break; } - if (thd->transaction.xa_state == XA_IDLE && + if (thd->transaction.xid_state.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { int r; @@ -4597,7 +4610,7 @@ end_with_restore_list: else send_ok(thd); } - else if (thd->transaction.xa_state == XA_PREPARED && + else if (thd->transaction.xid_state.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) { if (wait_if_global_read_lock(thd, 0, 0)) @@ -4617,27 +4630,33 @@ end_with_restore_list: else { my_error(ER_XAER_RMFAIL, MYF(0), - xa_state_names[thd->transaction.xa_state]); + xa_state_names[thd->transaction.xid_state.xa_state]); break; } thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; - thd->transaction.xa_state=XA_NOTR; + xid_cache_delete(&thd->transaction.xid_state); + thd->transaction.xid_state.xa_state=XA_NOTR; break; case SQLCOM_XA_ROLLBACK: - if (!thd->transaction.xid.eq(thd->lex->xid)) + if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) { - if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 0))) + XID_STATE *xs=xid_cache_search(thd->lex->xid); + if (!xs || xs->in_thd) my_error(ER_XAER_NOTA, MYF(0)); else + { + ha_commit_or_rollback_by_xid(thd->lex->xid, 0); + xid_cache_delete(xs); send_ok(thd); + } break; } - if (thd->transaction.xa_state != XA_IDLE && - thd->transaction.xa_state != XA_PREPARED) + if (thd->transaction.xid_state.xa_state != XA_IDLE && + thd->transaction.xid_state.xa_state != XA_PREPARED) { my_error(ER_XAER_RMFAIL, MYF(0), - xa_state_names[thd->transaction.xa_state]); + xa_state_names[thd->transaction.xid_state.xa_state]); break; } if (ha_rollback(thd)) @@ -4646,7 +4665,8 @@ end_with_restore_list: send_ok(thd); thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; - thd->transaction.xa_state=XA_NOTR; + xid_cache_delete(&thd->transaction.xid_state); + thd->transaction.xid_state.xa_state=XA_NOTR; break; case SQLCOM_XA_RECOVER: res= mysql_xa_recover(thd); From 9097bd2f08abb21b302d56d3d954ad45c247bf2a Mon Sep 17 00:00:00 2001 From: "tsmith@.mysql.com" <> Date: Sat, 13 Aug 2005 05:08:29 +0200 Subject: [PATCH 102/230] sql_parse.cc: Don't skip SET command even if --replicate-wild* says to. E.g., SET ONE_SHOT TIME_ZONE = 'XYZ' should be executed (BUG #12542) --- sql/sql_parse.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cd87b097038..9129cf584f9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1975,11 +1975,16 @@ mysql_execute_command(THD *thd) /* Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated. - Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it - (otherwise we have stale files on slave caused by exclusion of one tmp - table). + + Exceptions are: + + - SET: we always execute it (e.g., SET ONE_SHOT TIME_ZONE = 'XYZ') + + - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we + have stale files on slave caused by exclusion of one tmp table). */ - if (!(lex->sql_command == SQLCOM_DROP_TABLE && + if (lex->sql_command != SQLCOM_SET_OPTION && + !(lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary && lex->drop_if_exists) && all_tables_not_ok(thd,tables)) { From 1e248ceaf1e65521e424e389c6a85ccb5f85e0d7 Mon Sep 17 00:00:00 2001 From: "bell@50.0.168.192.in-addr.arpa" <> Date: Sat, 13 Aug 2005 07:45:14 +0300 Subject: [PATCH 103/230] fixed convertion and handling IN subqueries with rows (BUG#11867) --- mysql-test/r/subselect.result | 60 ++++++++++- mysql-test/t/subselect.test | 13 ++- sql/item.h | 9 ++ sql/item_cmpfunc.h | 5 + sql/item_subselect.cc | 183 ++++++++++++++++++++++++++-------- sql/sql_select.cc | 3 +- 6 files changed, 226 insertions(+), 47 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f0b4a8cc06b..8a2ae8e171a 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2742,13 +2742,26 @@ one two flag 5 6 N 7 8 N insert into t2 values (null,null,'N'); +insert into t2 values (null,3,'0'); +insert into t2 values (null,5,'0'); +insert into t2 values (10,null,'0'); +insert into t1 values (10,3,'0'); +insert into t1 values (10,5,'0'); +insert into t1 values (10,10,'0'); SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; one two test -1 2 0 -2 3 0 -3 4 0 +1 2 NULL +2 3 NULL +3 4 NULL 5 6 1 7 8 1 +10 3 NULL +10 5 NULL +10 10 NULL +SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +one two +5 6 +7 8 SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; one two test 1 2 NULL @@ -2756,6 +2769,47 @@ one two test 3 4 NULL 5 6 1 7 8 1 +10 3 NULL +10 5 NULL +10 10 NULL +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +one two test +1 2 0 +2 3 NULL +3 4 0 +5 6 0 +7 8 0 +10 3 NULL +10 5 NULL +10 10 NULL +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +one two test +1 2 0 +2 3 NULL +3 4 0 +5 6 0 +7 8 0 +10 3 NULL +10 5 NULL +10 10 NULL +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where +Warnings: +Note 1003 select test.t1.one AS `one`,test.t1.two AS `two`,((test.t1.one,test.t1.two),(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where ((test.t2.flag = _latin1'0') and (((test.t1.one) = test.t2.one) or isnull(test.t2.one)) and (((test.t1.two) = test.t2.two) or isnull(test.t2.two))) having ((test.t2.one) and (test.t2.two)))) AS `test` from test.t1 +explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where +Warnings: +Note 1003 select test.t1.one AS `one`,test.t1.two AS `two` from test.t1 where ((test.t1.one,test.t1.two),(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where ((test.t2.flag = _latin1'N') and ((test.t1.one) = test.t2.one) and ((test.t1.two) = test.t2.two)))) +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where; Using temporary; Using filesort +Warnings: +Note 1003 select test.t1.one AS `one`,test.t1.two AS `two`,((test.t1.one,test.t1.two),(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where (test.t2.flag = _latin1'0') group by test.t2.one,test.t2.two having ((((test.t1.one) = test.t2.one) or isnull(test.t2.one)) and (((test.t1.two) = test.t2.two) or isnull(test.t2.two)) and (test.t2.one) and (test.t2.two)))) AS `test` from test.t1 DROP TABLE t1,t2; CREATE TABLE t1 (a char(5), b char(5)); INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1b7e01627cd..4bb917ab58c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1769,9 +1769,20 @@ SELECT * FROM t1 WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); insert into t2 values (null,null,'N'); +insert into t2 values (null,3,'0'); +insert into t2 values (null,5,'0'); +insert into t2 values (10,null,'0'); +insert into t1 values (10,3,'0'); +insert into t1 values (10,5,'0'); +insert into t1 values (10,10,'0'); SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; - +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; DROP TABLE t1,t2; # diff --git a/sql/item.h b/sql/item.h index 825b37fe64c..c71769b5129 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1023,6 +1023,15 @@ public: String* val_str(String* s); bool get_date(TIME *ltime, uint fuzzydate); void print(String *str); + /* + we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE + */ + table_map used_tables() const + { + return (depended_from ? + OUTER_REF_TABLE_BIT : + (*ref)->used_tables() | RAND_TABLE_BIT); + } }; class Item_null_helper :public Item_ref_null_helper diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 525f269e528..47884f6064e 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -832,6 +832,11 @@ public: longlong val_int(); const char *func_name() const { return ""; } void update_used_tables(); + /* + we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE + */ + table_map used_tables() const + { return used_tables_cache | RAND_TABLE_BIT; } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6ec8b11d863..c8405a9f8f4 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -859,6 +859,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + select_lex->where->top_level_item(); if (join->conds->fix_fields(thd, join->tables_list, 0)) DBUG_RETURN(RES_ERROR); } @@ -912,10 +913,13 @@ Item_in_subselect::single_value_transformer(JOIN *join, Item_subselect::trans_res Item_in_subselect::row_value_transformer(JOIN *join) { - DBUG_ENTER("Item_in_subselect::row_value_transformer"); - - Item *item= 0; SELECT_LEX *select_lex= join->select_lex; + Item *having_item= 0; + uint cols_num= left_expr->cols(); + bool is_having_used= (join->having || select_lex->with_sum_func || + select_lex->group_list.first || + !select_lex->table_list.elements); + DBUG_ENTER("Item_in_subselect::row_value_transformer"); if (select_lex->item_list.elements != left_expr->cols()) { @@ -946,61 +950,156 @@ Item_in_subselect::row_value_transformer(JOIN *join) } select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; + if (is_having_used) { - uint n= left_expr->cols(); - List_iterator_fast li(select_lex->item_list); - for (uint i= 0; i < n; i++) + /* + (l1, l2, l3) IN (SELECT v1, v2, v3 ... HAVING having) => + EXISTS (SELECT ... HAVING having and + (l1 = v1 or is null v1) and + (l2 = v2 or is null v2) and + (l3 = v3 or is null v3) and + is_not_null_test(v1) and + is_not_null_test(v2) and + is_not_null_test(v3)) + where is_not_null_test used to register nulls in case if we have + not found matching to return correct NULL value + */ + Item *item_having_part2= 0; + for (uint i= 0; i < cols_num; i++) { - Item *func; DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->el(i)->cols())) DBUG_RETURN(RES_ERROR); - if (join->having || select_lex->with_sum_func || - select_lex->group_list.elements) - func= new Item_ref_null_helper(this, - select_lex->ref_pointer_array+i, - (char *) "", - (char *) ""); - else - func= li++; - func= - eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> - addr(i), - (char *)"", - (char *)in_left_expr_name), - func); - item= and_items(item, func); + Item *item_eq= + new Item_func_eq(new + Item_direct_ref((*optimizer->get_cache())-> + addr(i), + (char *)"", + (char *)in_left_expr_name), + new + Item_direct_ref(select_lex->ref_pointer_array + i, + (char *)"", + (char *)"") + ); + Item *item_isnull= + new Item_func_isnull(new + Item_direct_ref( select_lex-> + ref_pointer_array+i, + (char *)"", + (char *)"") + ); + having_item= + and_items(having_item, + new Item_cond_or(item_eq, item_isnull)); + item_having_part2= + and_items(item_having_part2, + new + Item_is_not_null_test(this, + new + Item_direct_ref(select_lex-> + ref_pointer_array + i, + (char *)"", + (char *)"") + ) + ); + item_having_part2->top_level_item(); } - } - if (join->having || select_lex->with_sum_func || - select_lex->group_list.first || - !select_lex->table_list.elements) - { - /* - AND can't be changed during fix_fields() - we can assign select_lex->having here, and pass 0 as last - argument (reference) to fix_fields() - */ - select_lex->having= join->having= and_items(join->having, item); - select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, 0)) - { - select_lex->having_fix_field= 0; - DBUG_RETURN(RES_ERROR); - } - select_lex->having_fix_field= 0; + having_item= and_items(having_item, item_having_part2); + having_item->top_level_item(); } else { + /* + (l1, l2, l3) IN (SELECT v1, v2, v3 ... WHERE where) => + EXISTS (SELECT ... WHERE where and + (l1 = v1 or is null v1) and + (l2 = v2 or is null v2) and + (l3 = v3 or is null v3) + HAVING is_not_null_test(v1) and + is_not_null_test(v2) and + is_not_null_test(v3)) + where is_not_null_test register NULLs values but reject rows + + in case when we do not need correct NULL, we have simplier construction: + EXISTS (SELECT ... WHERE where and + (l1 = v1) and + (l2 = v2) and + (l3 = v3) + */ + Item *where_item= 0; + for (uint i= 0; i < cols_num; i++) + { + Item *item, *item_isnull; + DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + if (select_lex->ref_pointer_array[i]-> + check_cols(left_expr->el(i)->cols())) + DBUG_RETURN(RES_ERROR); + item= + new Item_func_eq(new + Item_direct_ref((*optimizer->get_cache())-> + addr(i), + (char *)"", + (char *)in_left_expr_name), + new + Item_direct_ref( select_lex-> + ref_pointer_array+i, + (char *)"", + (char *)"") + ); + if (!abort_on_null) + { + having_item= + and_items(having_item, + new + Item_is_not_null_test(this, + new + Item_direct_ref(select_lex-> + ref_pointer_array + i, + (char *)"", + (char *)"") + ) + ); + item_isnull= new + Item_func_isnull(new + Item_direct_ref( select_lex-> + ref_pointer_array+i, + (char *)"", + (char *)"") + ); + + item= new Item_cond_or(item, item_isnull); + } + + where_item= and_items(where_item, item); + } + /* + AND can't be changed during fix_fields() + we can assign select_lex->where here, and pass 0 as last + argument (reference) to fix_fields() + */ + select_lex->where= join->conds= and_items(join->conds, where_item); + select_lex->where->top_level_item(); + if (join->conds->fix_fields(thd, join->tables_list, 0)) + DBUG_RETURN(RES_ERROR); + } + if (having_item) + { + bool res; + select_lex->having= join->having= and_items(join->having, having_item); + select_lex->having->top_level_item(); /* AND can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() */ - select_lex->where= join->conds= and_items(join->conds, item); - if (join->conds->fix_fields(thd, join->tables_list, 0)) + select_lex->having_fix_field= 1; + res= join->having->fix_fields(thd, join->tables_list, 0); + select_lex->having_fix_field= 0; + if (res) + { DBUG_RETURN(RES_ERROR); + } } DBUG_RETURN(RES_OK); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 353ccf79ab8..a7984b525d1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1439,7 +1439,8 @@ JOIN::exec() curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having, ~ (table_map) 0, ~used_tables); - DBUG_EXECUTE("where",print_where(conds,"having after sort");); + DBUG_EXECUTE("where",print_where(curr_join->tmp_having, + "having after sort");); } } { From 135103bac171833a6725a13a5ef498338cfc7a6a Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Sat, 13 Aug 2005 08:42:35 +0200 Subject: [PATCH 104/230] after merge --- mysql-test/t/xa.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test index aa921516110..1347fd05415 100644 --- a/mysql-test/t/xa.test +++ b/mysql-test/t/xa.test @@ -31,7 +31,7 @@ xa end 'testa','testb'; connect (con1,localhost,,,); connection con1; ---error 1438 +--error 1440 xa start 'testa','testb'; # gtrid [ , bqual [ , formatID ] ] From 2e2b897ff39239855e83cddbe1e5599800d61187 Mon Sep 17 00:00:00 2001 From: "sanja@hasky.mysql.fi" <> Date: Sat, 13 Aug 2005 11:15:17 +0300 Subject: [PATCH 105/230] item_subselect.cc: postmerge fix subselect.result: new 5.0 result (postmerge) --- mysql-test/r/subselect.result | 6 ++--- sql/item_subselect.cc | 42 +++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8a01b4080c3..6c05ce10592 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2809,19 +2809,19 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where Warnings: -Note 1003 select test.t1.one AS `one`,test.t1.two AS `two`,((test.t1.one,test.t1.two),(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where ((test.t2.flag = _latin1'0') and (((test.t1.one) = test.t2.one) or isnull(test.t2.one)) and (((test.t1.two) = test.t2.two) or isnull(test.t2.two))) having ((test.t2.one) and (test.t2.two)))) AS `test` from test.t1 +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = _latin1'0') and (((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`)) and (((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) having ((`test`.`t2`.`one`) and (`test`.`t2`.`two`)))) AS `test` from `test`.`t1` explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where Warnings: -Note 1003 select test.t1.one AS `one`,test.t1.two AS `two` from test.t1 where ((test.t1.one,test.t1.two),(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where ((test.t2.flag = _latin1'N') and ((test.t1.one) = test.t2.one) and ((test.t1.two) = test.t2.two)))) +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` where ((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = _latin1'N') and ((`test`.`t1`.`one`) = `test`.`t2`.`one`) and ((`test`.`t1`.`two`) = `test`.`t2`.`two`)))) explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 8 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where; Using temporary; Using filesort Warnings: -Note 1003 select test.t1.one AS `one`,test.t1.two AS `two`,((test.t1.one,test.t1.two),(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where (test.t2.flag = _latin1'0') group by test.t2.one,test.t2.two having ((((test.t1.one) = test.t2.one) or isnull(test.t2.one)) and (((test.t1.two) = test.t2.two) or isnull(test.t2.two)) and (test.t2.one) and (test.t2.two)))) AS `test` from test.t1 +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,((`test`.`t1`.`one`,`test`.`t1`.`two`),(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where (`test`.`t2`.`flag` = _latin1'0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having ((((`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`)) and (((`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)) and (`test`.`t2`.`one`) and (`test`.`t2`.`two`)))) AS `test` from `test`.`t1` DROP TABLE t1,t2; CREATE TABLE t1 (a char(5), b char(5)); INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1eddb36b34c..a5985a6c4a9 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1093,21 +1093,24 @@ Item_in_subselect::row_value_transformer(JOIN *join) DBUG_RETURN(RES_ERROR); Item *item_eq= new Item_func_eq(new - Item_direct_ref((*optimizer->get_cache())-> + Item_direct_ref(&select_lex->context, + (*optimizer->get_cache())-> addr(i), (char *)"", (char *)in_left_expr_name), new - Item_direct_ref(select_lex->ref_pointer_array + i, + Item_direct_ref(&select_lex->context, + select_lex->ref_pointer_array + i, (char *)"", (char *)"") ); Item *item_isnull= new Item_func_isnull(new - Item_direct_ref( select_lex-> - ref_pointer_array+i, - (char *)"", - (char *)"") + Item_direct_ref(&select_lex->context, + select_lex-> + ref_pointer_array+i, + (char *)"", + (char *)"") ); having_item= and_items(having_item, @@ -1117,7 +1120,8 @@ Item_in_subselect::row_value_transformer(JOIN *join) new Item_is_not_null_test(this, new - Item_direct_ref(select_lex-> + Item_direct_ref(&select_lex->context, + select_lex-> ref_pointer_array + i, (char *)"", (char *)"") @@ -1157,15 +1161,17 @@ Item_in_subselect::row_value_transformer(JOIN *join) DBUG_RETURN(RES_ERROR); item= new Item_func_eq(new - Item_direct_ref((*optimizer->get_cache())-> + Item_direct_ref(&select_lex->context, + (*optimizer->get_cache())-> addr(i), (char *)"", (char *)in_left_expr_name), new - Item_direct_ref( select_lex-> - ref_pointer_array+i, - (char *)"", - (char *)"") + Item_direct_ref(&select_lex->context, + select_lex-> + ref_pointer_array+i, + (char *)"", + (char *)"") ); if (!abort_on_null) { @@ -1174,7 +1180,8 @@ Item_in_subselect::row_value_transformer(JOIN *join) new Item_is_not_null_test(this, new - Item_direct_ref(select_lex-> + Item_direct_ref(&select_lex->context, + select_lex-> ref_pointer_array + i, (char *)"", (char *)"") @@ -1182,10 +1189,11 @@ Item_in_subselect::row_value_transformer(JOIN *join) ); item_isnull= new Item_func_isnull(new - Item_direct_ref( select_lex-> - ref_pointer_array+i, - (char *)"", - (char *)"") + Item_direct_ref(&select_lex->context, + select_lex-> + ref_pointer_array+i, + (char *)"", + (char *)"") ); item= new Item_cond_or(item, item_isnull); From 562786bc3649737bf43b14f5b278faa12000e7ee Mon Sep 17 00:00:00 2001 From: "sanja@hasky.mysql.fi" <> Date: Sat, 13 Aug 2005 17:06:30 +0300 Subject: [PATCH 106/230] table.cc: remove unneeded multitable_view assignment sql_view.cc: fix potential memorry overrun in ref_array asssign multitable_view in time of view creation (BUG#12569) --- sql/sql_view.cc | 7 +++++++ sql/table.cc | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index a910cdb2fbc..c958185b622 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -844,6 +844,9 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) view_tables); lex->select_lex.context.outer_context= 0; lex->select_lex.context.select_lex= table->select_lex; + lex->select_lex.select_n_having_items+= + table->select_lex->select_n_having_items; + /* do not check privileges & hide errors for view underlyings */ for (SELECT_LEX *sl= lex->all_selects_list; sl; @@ -864,7 +867,11 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) { if (view_tables->next_local) + { table->multitable_view= TRUE; + if (table->belong_to_view) + table->belong_to_view->multitable_view= TRUE; + } /* make nested join structure for view tables */ NESTED_JOIN *nested_join; if (!(nested_join= table->nested_join= diff --git a/sql/table.cc b/sql/table.cc index 83ec2d64935..0b557b097cf 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1720,8 +1720,6 @@ void st_table_list::set_ancestor() */ tbl->ancestor->set_ancestor(); } - if (tbl->multitable_view) - multitable_view= TRUE; } while ((tbl= tbl->next_local)); if (!multitable_view) From 2870638ef2935fa4d938d46ed9d4373db11a4bec Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Sun, 14 Aug 2005 14:06:47 +0200 Subject: [PATCH 107/230] client/mysql.cc mysql default port cleanup (it's set in libmysql.c, NOT in my_getopt) configure.in autoconf 2.52 is enough to build mysql-5.0 --- client/mysql.cc | 2 +- configure.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index bee5376e036..04b634a47af 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -624,7 +624,7 @@ static struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, - (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, + (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.", (gptr*) ¤t_prompt, (gptr*) ¤t_prompt, 0, GET_STR_ALLOC, diff --git a/configure.in b/configure.in index aeb057509bf..e06f32f5e97 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.57)dnl Minimum Autoconf version required. +AC_PREREQ(2.52)dnl Minimum Autoconf version required. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM From d689d415b3b12ecaae1d95a4174418c8004e02db Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Sun, 14 Aug 2005 23:20:06 +0200 Subject: [PATCH 108/230] forgotten 'return' --- .bzrignore | 2 ++ sql/sql_class.cc | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.bzrignore b/.bzrignore index 2c20c4daf22..24ac6e22c45 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1121,3 +1121,5 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +support-files/MacOSX/postflight +support-files/MacOSX/preflight diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 23e4ccd0172..792d3c62169 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1863,8 +1863,8 @@ static void xid_free_hash (void *ptr) bool xid_cache_init() { pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST); - hash_init(&xid_cache, &my_charset_bin, 100, 0, 0, - xid_get_hash_key, xid_free_hash, 0) != 0; + return hash_init(&xid_cache, &my_charset_bin, 100, 0, 0, + xid_get_hash_key, xid_free_hash, 0) != 0; } void xid_cache_free() From 7fcb9cd599450a3efba3e8218bb81a5916e1e964 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Mon, 15 Aug 2005 13:02:29 +0400 Subject: [PATCH 109/230] Fix bug #10802 Index is not used if table using BDB engine on HP-UX HP-UX compiler was generating code which makes wrong conversion from double to ulonglong which results in not using index in some cases. Changed type cast operators odrer with which generated code makes proper conversion. --- mysql-test/include/varchar.inc | 1 + sql/ha_berkeley.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/include/varchar.inc b/mysql-test/include/varchar.inc index 13b4315f2b8..70b563e871c 100644 --- a/mysql-test/include/varchar.inc +++ b/mysql-test/include/varchar.inc @@ -229,6 +229,7 @@ drop table t1; # # Bug #9489: problem with hash indexes +# Bug #10802: Index is not used if table using BDB engine on HP-UX # create table t1(a int, b varchar(12), key ba(b, a)); diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 793029ab4c7..4a7585d800e 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -2150,7 +2150,7 @@ ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key, end_pos=end_range.less+end_range.equal; rows=(end_pos-start_pos)*records; DBUG_PRINT("exit",("rows: %g",rows)); - DBUG_RETURN(rows <= 1.0 ? (ha_rows) 1 : (ha_rows) rows); + DBUG_RETURN((ha_rows)(rows <= 1.0 ? 1 : rows)); } From 4880d22b79fc3ab486a4ec0b4f267bfbe06b367c Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Mon, 15 Aug 2005 15:44:56 +0200 Subject: [PATCH 110/230] - Removed a non-fatal error when running the Mac OS X 10.4 PackageMaker: CFBundleShortVersionString in Info.plist may not include a version suffix like "-beta" (BUG#12584) - Minor cleanup: removed two unused keys from Info.plist: IFMajorVersion and IFMinorVersion --- support-files/MacOSX/Info.plist.sh | 6 +----- support-files/MacOSX/Makefile.am | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/support-files/MacOSX/Info.plist.sh b/support-files/MacOSX/Info.plist.sh index f14902ff379..fdfb0c7a17c 100644 --- a/support-files/MacOSX/Info.plist.sh +++ b/support-files/MacOSX/Info.plist.sh @@ -9,11 +9,7 @@ CFBundleName MySQL CFBundleShortVersionString - @VERSION@ - IFMajorVersion - 4 - IFMinorVersion - 0 + @MYSQL_NO_DASH_VERSION@ IFPkgFlagAllowBackRev IFPkgFlagAuthorizationAction diff --git a/support-files/MacOSX/Makefile.am b/support-files/MacOSX/Makefile.am index d751ed7ca5b..ea99c46389d 100644 --- a/support-files/MacOSX/Makefile.am +++ b/support-files/MacOSX/Makefile.am @@ -47,6 +47,7 @@ SUFFIXES = .sh @SED@ \ -e 's!@''prefix''@!$(prefix)!g' \ -e 's!@''VERSION''@!@VERSION@!' \ + -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \ -e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \ $< > $@-t From df32f7d621becb146b759ab12751596e4d199e5c Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Mon, 15 Aug 2005 18:15:12 +0300 Subject: [PATCH 111/230] Save and clear run context before executing a stored function or trigger and restore it afterwards. This allows us to use statement replication with functions and triggers The following things are fixed with this patch: - NOW() and automatic timestamps takes the value from the main event for functions and triggers (which allows these to replicate with statement level logging) - No side effects for triggers or functions with auto-increment values(), last_insert_id(), rand() or found_rows() - Triggers can't return result sets Fixes bugs: #12480: NOW() is not constant in a trigger #12481: Using NOW() in a stored function breaks statement based replication #12482: Triggers has side effects with auto_increment values #11587: trigger causes lost connection error --- mysql-test/r/rpl_trigger.result | 108 +++++++++++++++++++++++++++++ mysql-test/r/trigger.result | 33 +++++++++ mysql-test/t/rpl_trigger.test | 117 ++++++++++++++++++++++++++++++++ mysql-test/t/sp-error.test | 6 +- mysql-test/t/trigger.test | 44 ++++++++++++ sql/item_func.cc | 52 ++++---------- sql/share/errmsg.txt | 4 +- sql/sp_head.cc | 7 +- sql/sql_class.cc | 84 ++++++++++++++++++++++- sql/sql_class.h | 34 ++++++++-- sql/sql_parse.cc | 29 ++++++-- sql/sql_trigger.cc | 36 ++++++++++ sql/sql_trigger.h | 51 +------------- sql/sql_yacc.yy | 9 ++- tests/fork_big2.pl | 2 +- 15 files changed, 505 insertions(+), 111 deletions(-) create mode 100644 mysql-test/r/rpl_trigger.result create mode 100644 mysql-test/t/rpl_trigger.test diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result new file mode 100644 index 00000000000..db824c9c423 --- /dev/null +++ b/mysql-test/r/rpl_trigger.result @@ -0,0 +1,108 @@ +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 auto_increment, primary key (a), b int, rand_value double not null); +create table t2 (a int auto_increment, primary key (a), b int); +create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null); +create trigger t1 before insert on t1 for each row +begin +insert into t3 values (NULL, "t1", new.a, new.b, rand()); +end| +create trigger t2 after insert on t2 for each row +begin +insert into t3 values (NULL, "t2", new.a, new.b, rand()); +end| +insert into t3 values(100,"log",0,0,0); +SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; +insert into t1 values(1,1,rand()),(NULL,2,rand()); +insert into t2 (b) values(last_insert_id()); +insert into t2 values(3,0),(NULL,0); +insert into t2 values(NULL,0),(500,0); +select a,b, truncate(rand_value,4) from t1; +a b truncate(rand_value,4) +1 1 0.4320 +2 2 0.3055 +select * from t2; +a b +1 2 +3 0 +4 0 +5 0 +500 0 +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +a name old_a old_b truncate(rand_value,4) +100 log 0 0 0.0000 +101 t1 1 1 0.3203 +102 t1 0 2 0.5666 +103 t2 1 2 0.9164 +104 t2 3 0 0.8826 +105 t2 4 0 0.6635 +106 t2 5 0 0.6699 +107 t2 500 0 0.3593 + +--- On slave -- +select a,b, truncate(rand_value,4) from t1; +a b truncate(rand_value,4) +1 1 0.4320 +2 2 0.3055 +select * from t2; +a b +1 2 +3 0 +4 0 +5 0 +500 0 +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +a name old_a old_b truncate(rand_value,4) +100 log 0 0 0.0000 +101 t1 1 1 0.3203 +102 t1 0 2 0.5666 +103 t2 1 2 0.9164 +104 t2 3 0 0.8826 +105 t2 4 0 0.6635 +106 t2 5 0 0.6699 +107 t2 500 0 0.3593 +drop table t1,t2,t3; +select get_lock("bug12480",2); +get_lock("bug12480",2) +1 +create table t1 (a datetime,b datetime, c datetime); +drop function if exists bug12480; +Warnings: +Note 1305 FUNCTION bug12480 does not exist +create function bug12480() returns datetime +begin +set @a=get_lock("bug12480",2); +return now(); +end| +create trigger t1_first before insert on t1 +for each row begin +set @a=get_lock("bug12480",2); +set new.b= now(); +set new.c= bug12480(); +end +| +insert into t1 set a = now(); +select a=b && a=c from t1; +a=b && a=c +1 + +--- On slave -- +select a=b && a=c from t1; +a=b && a=c +1 +test +1 +truncate table t1; +drop trigger t1_first; +insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now()); +select a=b && a=c from t1; +a=b && a=c +1 +1 +1 +drop function bug12480; +drop table t1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ee0a6f6b744..6a5063f54c9 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -664,3 +664,36 @@ end| update t1 set data = 1; update t1 set data = 2; drop table t1; +create table t1 (c1 int, c2 datetime); +create trigger tr1 before insert on t1 for each row +begin +set new.c2= '2004-04-01'; +select 'hello'; +end| +ERROR 0A000: Not allowed to return a result set from a trigger +insert into t1 (c1) values (1),(2),(3); +select * from t1; +c1 c2 +1 NULL +2 NULL +3 NULL +drop procedure if exists bug11587; +create procedure bug11587(x char(16)) +begin +select "hello"; +select "hello again"; +end| +create trigger tr1 before insert on t1 for each row +begin +call bug11587(); +set new.c2= '2004-04-02'; +end| +insert into t1 (c1) values (4),(5),(6); +ERROR 0A000: PROCEDURE test.bug11587 can't return a result set in the given context +select * from t1; +c1 c2 +1 NULL +2 NULL +3 NULL +drop procedure bug11587; +drop table t1; diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test new file mode 100644 index 00000000000..c73e8b2d19e --- /dev/null +++ b/mysql-test/t/rpl_trigger.test @@ -0,0 +1,117 @@ +# +# Test of triggers with replication +# + +source include/master-slave.inc; + +# +# #12482: Triggers has side effects with auto_increment values +# + +create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null); +create table t2 (a int auto_increment, primary key (a), b int); +create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null); + +delimiter |; +create trigger t1 before insert on t1 for each row +begin + insert into t3 values (NULL, "t1", new.a, new.b, rand()); +end| + +create trigger t2 after insert on t2 for each row +begin + insert into t3 values (NULL, "t2", new.a, new.b, rand()); +end| +delimiter ;| + +insert into t3 values(100,"log",0,0,0); + +# Ensure we always have same random numbers +SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; + +# Emulate that we have rows 2-9 deleted on the slave +insert into t1 values(1,1,rand()),(NULL,2,rand()); +insert into t2 (b) values(last_insert_id()); +insert into t2 values(3,0),(NULL,0); +insert into t2 values(NULL,0),(500,0); + +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +save_master_pos; +connection slave; +sync_with_master; +--disable_query_log +select "--- On slave --" as ""; +--enable_query_log +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +connection master; +drop table t1,t2,t3; + +# +# #12480: NOW() is not constant in a trigger +# #12481: Using NOW() in a stored function breaks statement based replication +# + +# Start by getting a lock on 'bug12480' to be able to use get_lock() as sleep() +connect (con2,localhost,root,,); +connection con2; +select get_lock("bug12480",2); +connection default; + +create table t1 (a datetime,b datetime, c datetime); +--ignore_warnings +drop function if exists bug12480; +--enable_warnings + +delimiter |; + +create function bug12480() returns datetime +begin + set @a=get_lock("bug12480",2); + return now(); +end| + +create trigger t1_first before insert on t1 +for each row begin + set @a=get_lock("bug12480",2); + set new.b= now(); + set new.c= bug12480(); +end +| + +delimiter ;| +insert into t1 set a = now(); +select a=b && a=c from t1; +let $time=`select a from t1`; + +connection slave; +sync_with_master; +--disable_query_log +select "--- On slave --" as ""; +--enable_query_log +select a=b && a=c from t1; +--disable_query_log +eval select a='$time' as 'test' from t1; +--enable_query_log + +connection master; +disconnect con2; + +truncate table t1; +drop trigger t1_first; + +insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now()); +select a=b && a=c from t1; + +drop function bug12480; +drop table t1; + +# +# End of test +# +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 349bd148814..85b81f72f40 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -811,19 +811,19 @@ end| # # Some things are caught when parsing ---error ER_SP_NO_RETSET_IN_FUNC +--error ER_SP_NO_RETSET create function bug8408() returns int begin select * from t1; return 0; end| ---error ER_SP_NO_RETSET_IN_FUNC +--error ER_SP_NO_RETSET create function bug8408() returns int begin show warnings; return 0; end| ---error ER_SP_NO_RETSET_IN_FUNC +--error ER_SP_NO_RETSET create function bug8408(a int) returns int begin declare b int; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 49ec42568ad..a8ea9c59ebb 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -665,6 +665,7 @@ drop table t1; # Test for bug #11973 "SELECT .. INTO var_name; in trigger cause # crash on update" + create table t1 (id int, data int, username varchar(16)); insert into t1 (id, data) values (1, 0); delimiter |; @@ -684,4 +685,47 @@ connection addconroot; update t1 set data = 2; connection default; +disconnect addconroot; +drop table t1; + +# +# #11587 Trigger causes lost connection error +# + +create table t1 (c1 int, c2 datetime); +delimiter |; +--error ER_SP_NO_RETSET +create trigger tr1 before insert on t1 for each row +begin + set new.c2= '2004-04-01'; + select 'hello'; +end| +delimiter ;| + +insert into t1 (c1) values (1),(2),(3); +select * from t1; + +--disable_warnings +drop procedure if exists bug11587; +--enable_warnings + +delimiter |; +create procedure bug11587(x char(16)) +begin + select "hello"; + select "hello again"; +end| + +create trigger tr1 before insert on t1 for each row +begin + call bug11587(); + set new.c2= '2004-04-02'; +end| +delimiter ;| + +--error 726 +insert into t1 (c1) values (4),(5),(6); +select * from t1; + +drop procedure bug11587; drop table t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index ef1c85f6120..61467595424 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1873,6 +1873,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) Allocate rand structure once: we must use thd->current_arena to create rand in proper mem_root if it's a prepared statement or stored procedure. + + No need to send a Rand log event if seed was given eg: RAND(seed), + as it will be replicated in the query as such. */ if (!rand && !(rand= (struct rand_struct*) thd->current_arena->alloc(sizeof(*rand)))) @@ -1895,16 +1898,16 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) else { /* - No need to send a Rand log event if seed was given eg: RAND(seed), - as it will be replicated in the query as such. - Save the seed only the first time RAND() is used in the query Once events are forwarded rather than recreated, the following can be skipped if inside the slave thread */ - thd->rand_used=1; - thd->rand_saved_seed1=thd->rand.seed1; - thd->rand_saved_seed2=thd->rand.seed2; + if (!thd->rand_used) + { + thd->rand_used= 1; + thd->rand_saved_seed1= thd->rand.seed1; + thd->rand_saved_seed2= thd->rand.seed2; + } rand= &thd->rand; } return FALSE; @@ -4665,10 +4668,9 @@ Item_func_sp::execute(Item **itp) { DBUG_ENTER("Item_func_sp::execute"); THD *thd= current_thd; - ulong old_client_capabilites; int res= -1; - bool save_in_sub_stmt= thd->in_sub_stmt; - my_bool save_no_send_ok; + Sub_statement_state statement_state; + #ifndef NO_EMBEDDED_ACCESS_CHECKS st_sp_security_context save_ctx; #endif @@ -4679,38 +4681,21 @@ Item_func_sp::execute(Item **itp) goto error; } - old_client_capabilites= thd->client_capabilities; - thd->client_capabilities &= ~CLIENT_MULTI_RESULTS; - -#ifndef EMBEDDED_LIBRARY - save_no_send_ok= thd->net.no_send_ok; - thd->net.no_send_ok= TRUE; -#endif - #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - goto error_check; + goto error; sp_change_security_context(thd, m_sp, &save_ctx); if (save_ctx.changed && check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) goto error_check_ctx; #endif - /* - Like for SPs, we don't binlog the substatements. If the statement which - called this function is an update statement, it will be binlogged; but if - it's not (e.g. SELECT myfunc()) it won't be binlogged (documented known - problem). - */ - - tmp_disable_binlog(thd); /* don't binlog the substatements */ - thd->in_sub_stmt= TRUE; + thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION); res= m_sp->execute_function(thd, args, arg_count, itp); + thd->restore_sub_statement_state(&statement_state); - thd->in_sub_stmt= save_in_sub_stmt; - reenable_binlog(thd); if (res && mysql_bin_log.is_open() && (m_sp->m_chistics->daccess == SP_CONTAINS_SQL || m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA)) @@ -4723,15 +4708,6 @@ error_check_ctx: sp_restore_security_context(thd, m_sp, &save_ctx); #endif - thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; - -error_check: -#ifndef EMBEDDED_LIBRARY - thd->net.no_send_ok= save_no_send_ok; -#endif - - thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; - error: DBUG_RETURN(res); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7ad8e7c3030..d188ee9fd0e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5342,8 +5342,8 @@ ER_SP_DUP_HANDLER 42000 eng "Duplicate handler declared in the same block" ER_SP_NOT_VAR_ARG 42000 eng "OUT or INOUT argument %d for routine %s is not a variable" -ER_SP_NO_RETSET_IN_FUNC 0A000 - eng "Not allowed to return a result set from a function" +ER_SP_NO_RETSET 0A000 + eng "Not allowed to return a result set from a %s" ER_CANT_CREATE_GEOMETRY_OBJECT 22003 eng "Cannot get geometry object from data you send to the GEOMETRY field" ER_FAILED_ROUTINE_BREAK_BINLOG diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d0cd968f4fb..50bb3a84ee7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -659,7 +659,9 @@ sp_head::execute(THD *thd) if (i == NULL) break; DBUG_PRINT("execute", ("Instruction %u", ip)); - thd->set_time(); // Make current_time() et al work + /* Don't change NOW() in FUNCTION or TRIGGER */ + if (!thd->in_sub_stmt) + thd->set_time(); // Make current_time() et al work /* We have to set thd->current_arena before executing the instruction to store in the instruction free_list all new items, created @@ -690,8 +692,7 @@ sp_head::execute(THD *thd) { uint hf; - switch (ctx->found_handler(&hip, &hf)) - { + switch (ctx->found_handler(&hip, &hf)) { case SP_HANDLER_NONE: break; case SP_HANDLER_CONTINUE: diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 21df4640f3f..566d4e9d2a2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -174,7 +174,7 @@ THD::THD() :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), Open_tables_state(refresh_version), lock_id(&main_lock_id), - user_time(0), in_sub_stmt(FALSE), global_read_lock(0), is_fatal_error(0), + user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE), @@ -1836,3 +1836,85 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) set_open_tables_state(backup); DBUG_VOID_RETURN; } + + +/**************************************************************************** + Handling of statement states in functions and triggers. + + This is used to ensure that the function/trigger gets a clean state + to work with and does not cause any side effects of the calling statement. + + It also allows most stored functions and triggers to replicate even + if they are used items that would normally be stored in the binary + replication (like last_insert_id() etc...) + + The following things is done + - Disable binary logging for the duration of the statement + - Disable multi-result-sets for the duration of the statement + - Value of last_insert_id() is reset and restored + - Value set by 'SET INSERT_ID=#' is reset and restored + - Value for found_rows() is reset and restored + - examined_row_count is added to the total + - cuted_fields is added to the total + + NOTES: + Seed for random() is saved for the first! usage of RAND() + We reset examined_row_count and cuted_fields and add these to the + result to ensure that if we have a bug that would reset these within + a function, we are not loosing any rows from the main statement. +****************************************************************************/ + +void THD::reset_sub_statement_state(Sub_statement_state *backup, + uint new_state) +{ + backup->options= options; + backup->in_sub_stmt= in_sub_stmt; + backup->no_send_ok= net.no_send_ok; + backup->enable_slow_log= enable_slow_log; + backup->last_insert_id= last_insert_id; + backup->next_insert_id= next_insert_id; + backup->insert_id_used= insert_id_used; + backup->limit_found_rows= limit_found_rows; + backup->examined_row_count= examined_row_count; + backup->sent_row_count= sent_row_count; + backup->cuted_fields= cuted_fields; + backup->client_capabilities= client_capabilities; + + options&= ~OPTION_BIN_LOG; + /* Disable result sets */ + client_capabilities &= ~CLIENT_MULTI_RESULTS; + in_sub_stmt|= new_state; + last_insert_id= 0; + next_insert_id= 0; + insert_id_used= 0; + examined_row_count= 0; + sent_row_count= 0; + cuted_fields= 0; + +#ifndef EMBEDDED_LIBRARY + /* Surpress OK packets in case if we will execute statements */ + net.no_send_ok= TRUE; +#endif +} + + +void THD::restore_sub_statement_state(Sub_statement_state *backup) +{ + options= backup->options; + in_sub_stmt= backup->in_sub_stmt; + net.no_send_ok= backup->no_send_ok; + enable_slow_log= backup->enable_slow_log; + last_insert_id= backup->last_insert_id; + next_insert_id= backup->next_insert_id; + insert_id_used= backup->insert_id_used; + limit_found_rows= backup->limit_found_rows; + sent_row_count= backup->sent_row_count; + client_capabilities= backup->client_capabilities; + + /* + The following is added to the old values as we are interested in the + total complexity of the query + */ + examined_row_count+= backup->examined_row_count; + cuted_fields+= backup->cuted_fields; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 0b8205dfdb3..77408ba3035 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1031,6 +1031,27 @@ public: }; +/* class to save context when executing a function or trigger */ + +/* Defines used for Sub_statement_state::in_sub_stmt */ + +#define SUB_STMT_TRIGGER 1 +#define SUB_STMT_FUNCTION 2 + +class Sub_statement_state +{ +public: + ulonglong options; + ulonglong last_insert_id, next_insert_id; + ulonglong limit_found_rows; + ha_rows cuted_fields, sent_row_count, examined_row_count; + ulong client_capabilities; + uint in_sub_stmt; + bool enable_slow_log, insert_id_used; + my_bool no_send_ok; +}; + + /* For each client connection we create a separate thread with THD serving as a thread/connection descriptor @@ -1137,10 +1158,9 @@ public: time_t connect_time,thr_create_time; // track down slow pthread_create thr_lock_type update_lock_default; delayed_insert *di; - my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ - /* TRUE if we are inside of trigger or stored function. */ - bool in_sub_stmt; + /* <> 0 if we are inside of trigger or stored function. */ + uint in_sub_stmt; /* container for handler's private per-connection data */ void *ha_data[MAX_HA]; @@ -1223,6 +1243,8 @@ public: */ ulonglong current_insert_id; ulonglong limit_found_rows; + ulonglong options; /* Bitmap of states */ + longlong row_count_func; /* For the ROW_COUNT() function */ ha_rows cuted_fields, sent_row_count, examined_row_count; table_map used_tables; @@ -1246,7 +1268,6 @@ public: update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id, warn_id; - ulonglong options; ulong thread_id, col_access; /* Statement id is thread-wide. This counter is used to generate ids */ @@ -1287,7 +1308,8 @@ public: bool no_warnings_for_error; /* no warnings on call to my_error() */ /* set during loop of derived table processing */ bool derived_tables_processing; - longlong row_count_func; /* For the ROW_COUNT() function */ + my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ + sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; sp_cache *sp_func_cache; @@ -1495,6 +1517,8 @@ public: { return current_arena->is_stmt_prepare() || lex->view_prepare_mode; } void reset_n_backup_open_tables_state(Open_tables_state *backup); void restore_backup_open_tables_state(Open_tables_state *backup); + void reset_sub_statement_state(Sub_statement_state *backup, uint new_state); + void restore_sub_statement_state(Sub_statement_state *backup); }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bbd1f81b7f3..a0a99e5fe09 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1101,11 +1101,11 @@ pthread_handler_decl(handle_one_connection,arg) execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); if (thd->query_error) thd->killed= THD::KILL_CONNECTION; + thd->proc_info=0; + thd->set_time(); + thd->init_for_queries(); } - thd->proc_info=0; - thd->set_time(); - thd->init_for_queries(); while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION)) { @@ -1464,6 +1464,7 @@ bool do_command(THD *thd) /* Perform one connection-level (COM_XXXX) command. + SYNOPSIS dispatch_command() thd connection handle @@ -2044,7 +2045,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd, void log_slow_statement(THD *thd) { - time_t start_of_query=thd->start_time; + time_t start_of_query; + + /* + The following should never be true with our current code base, + but better to keep this here so we don't accidently try to log a + statement in a trigger or stored function + */ + if (unlikely(thd->in_sub_stmt)) + return; // Don't set time for sub stmt + + start_of_query= thd->start_time; thd->end_time(); // Set start time /* @@ -5157,10 +5168,8 @@ void mysql_reset_thd_for_next_command(THD *thd) DBUG_ENTER("mysql_reset_thd_for_next_command"); thd->free_list= 0; thd->select_number= 1; - thd->total_warn_count=0; // Warnings for this query thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; - thd->sent_row_count= thd->examined_row_count= 0; - thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0; + thd->is_fatal_error= thd->time_zone_used= 0; thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); @@ -5168,6 +5177,12 @@ void mysql_reset_thd_for_next_command(THD *thd) if (opt_bin_log) reset_dynamic(&thd->user_var_events); thd->clear_error(); + if (!thd->in_sub_stmt) + { + thd->total_warn_count=0; // Warnings for this query + thd->rand_used= 0; + thd->sent_row_count= thd->examined_row_count= 0; + } DBUG_VOID_RETURN; } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 09eeff02de6..053dfdfc990 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -869,3 +869,39 @@ end: free_root(&table.mem_root, MYF(0)); DBUG_RETURN(result); } + + + +bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, + trg_action_time_type time_type, + bool old_row_is_record1) +{ + int res= 0; + + if (bodies[event][time_type]) + { + Sub_statement_state statement_state; + + if (old_row_is_record1) + { + old_field= record1_field; + new_field= table->field; + } + else + { + new_field= record1_field; + old_field= table->field; + } + + /* + FIXME: We should juggle with security context here (because trigger + should be invoked with creator rights). + */ + + thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); + res= bodies[event][time_type]->execute_function(thd, 0, 0, 0); + thd->restore_sub_statement_state(&statement_state); + } + + return res; +} diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index e2ed4bcc0f4..d9b39cc3034 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -20,6 +20,7 @@ QQ: Will it be merged into TABLE in future ? */ + class Table_triggers_list: public Sql_alloc { /* Triggers as SPs grouped by event, action_time */ @@ -76,55 +77,7 @@ public: bool drop_trigger(THD *thd, TABLE_LIST *table); bool process_triggers(THD *thd, trg_event_type event, trg_action_time_type time_type, - bool old_row_is_record1) - { - int res= 0; - - if (bodies[event][time_type]) - { - bool save_in_sub_stmt= thd->in_sub_stmt; -#ifndef EMBEDDED_LIBRARY - /* Surpress OK packets in case if we will execute statements */ - my_bool nsok= thd->net.no_send_ok; - thd->net.no_send_ok= TRUE; -#endif - - if (old_row_is_record1) - { - old_field= record1_field; - new_field= table->field; - } - else - { - new_field= record1_field; - old_field= table->field; - } - - /* - FIXME: We should juggle with security context here (because trigger - should be invoked with creator rights). - */ - /* - We disable binlogging, as in SP/functions, even though currently - triggers can't do updates. When triggers can do updates, someone - should add such a trigger to rpl_sp.test to verify that the update - does NOT go into binlog. - */ - tmp_disable_binlog(thd); - thd->in_sub_stmt= TRUE; - - res= bodies[event][time_type]->execute_function(thd, 0, 0, 0); - - thd->in_sub_stmt= save_in_sub_stmt; - reenable_binlog(thd); - -#ifndef EMBEDDED_LIBRARY - thd->net.no_send_ok= nsok; -#endif - } - - return res; - } + bool old_row_is_record1); bool get_trigger_info(THD *thd, trg_event_type event, trg_action_time_type time_type, LEX_STRING *trigger_name, LEX_STRING *trigger_stmt, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1d9413d2cf7..f933c00a1c4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1311,6 +1311,12 @@ create: YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); + if (sp->m_multi_results) + { + my_error(ER_SP_NO_RETSET, MYF(0), "trigger"); + YYABORT; + } + /* We have to do it after parsing trigger body, because some of sp_proc_stmt alternatives are not saving/restoring LEX, so @@ -1463,8 +1469,7 @@ create_function_tail: if (sp->m_multi_results) { - my_message(ER_SP_NO_RETSET_IN_FUNC, ER(ER_SP_NO_RETSET_IN_FUNC), - MYF(0)); + my_error(ER_SP_NO_RETSET, MYF(0), "function"); YYABORT; } if (sp->check_backpatch(YYTHD)) diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl index a1c55ac4c11..567cfafa176 100644 --- a/tests/fork_big2.pl +++ b/tests/fork_big2.pl @@ -300,7 +300,7 @@ sub test_select # # Do big select count(distinct..) over the table -# +# sub test_select_count { From d0c66bbaa3446f44a1cdd38ffde7527c0a058e2d Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Mon, 15 Aug 2005 18:29:51 +0300 Subject: [PATCH 112/230] Fixed typo in error numbers --- mysql-test/t/trigger.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index a8ea9c59ebb..cbc9da2bf51 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -723,7 +723,7 @@ begin end| delimiter ;| ---error 726 +--error 1312 insert into t1 (c1) values (4),(5),(6); select * from t1; From b6a65715d6f9e74568e7cbd117d17f5dd00c89a3 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Mon, 15 Aug 2005 17:53:38 +0200 Subject: [PATCH 113/230] BUG#12542: Prevous patch was incorrect. This removed the patch. --- sql/sql_parse.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9129cf584f9..cd87b097038 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1975,16 +1975,11 @@ mysql_execute_command(THD *thd) /* Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated. - - Exceptions are: - - - SET: we always execute it (e.g., SET ONE_SHOT TIME_ZONE = 'XYZ') - - - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we - have stale files on slave caused by exclusion of one tmp table). + Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it + (otherwise we have stale files on slave caused by exclusion of one tmp + table). */ - if (lex->sql_command != SQLCOM_SET_OPTION && - !(lex->sql_command == SQLCOM_DROP_TABLE && + if (!(lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary && lex->drop_if_exists) && all_tables_not_ok(thd,tables)) { From c414bb15209939df14ca019b458f900704ebd80d Mon Sep 17 00:00:00 2001 From: "acurtis@xiphis.org" <> Date: Mon, 15 Aug 2005 17:14:55 +0100 Subject: [PATCH 114/230] Bug#12518 "COLUMN_DEFAULT has wrong value if NOT NULL is set" Show NULL instead of empty string when no default value is set --- mysql-test/r/information_schema.result | 9 +++++++++ mysql-test/t/information_schema.test | 10 ++++++++++ sql/sql_show.cc | 1 + 3 files changed, 20 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index e0fb15a83c5..0a7f1af45f3 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -958,3 +958,12 @@ trigger_schema trigger_name test tr1 use test; drop table t1; +create table t1 (a int not null, b int); +use information_schema; +select column_name, column_default from columns +where table_schema='test' and table_name='t1'; +column_name column_default +a NULL +b NULL +use test; +drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 93b200b8a7c..d6d9f34302b 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -639,3 +639,13 @@ select trigger_schema, trigger_name from triggers where trigger_name='tr1'; use test; drop table t1; + +# +# Bug#12518 COLUMN_DEFAULT has wrong value if NOT NULL is set +# +create table t1 (a int not null, b int); +use information_schema; +select column_name, column_default from columns + where table_schema='test' and table_name='t1'; +use test; +drop table t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 760f5f7c456..c7a48c69cba 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2462,6 +2462,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[5]->set_notnull(); } else if (field->unireg_check == Field::NEXT_NUMBER || + lex->orig_sql_command != SQLCOM_SHOW_FIELDS || field->maybe_null()) table->field[5]->set_null(); // Null as default else From c10f05552ff3a3566412a7f7ea42a4053abfed60 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Mon, 15 Aug 2005 20:08:58 +0300 Subject: [PATCH 115/230] Don't clear warnings for functions or triggers Fixed failing test --- mysql-test/t/rpl_trigger.test | 1 + sql/sql_parse.cc | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test index c73e8b2d19e..715222f0314 100644 --- a/mysql-test/t/rpl_trigger.test +++ b/mysql-test/t/rpl_trigger.test @@ -87,6 +87,7 @@ insert into t1 set a = now(); select a=b && a=c from t1; let $time=`select a from t1`; +save_master_pos; connection slave; sync_with_master; --disable_query_log diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 926ae797f4c..eb54c44fa47 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5208,11 +5208,11 @@ void mysql_reset_thd_for_next_command(THD *thd) SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); thd->tmp_table_used= 0; - if (opt_bin_log) - reset_dynamic(&thd->user_var_events); - thd->clear_error(); if (!thd->in_sub_stmt) { + if (opt_bin_log) + reset_dynamic(&thd->user_var_events); + thd->clear_error(); thd->total_warn_count=0; // Warnings for this query thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; From 69319f17e7c2ffcde7b86a6679adc7acefc582ec Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Mon, 15 Aug 2005 23:05:05 +0400 Subject: [PATCH 116/230] Fix bug #10624 Views with multiple UNION and UNION ALL produce incorrect results. st_select_lex_unit::print() was losing UNION ALL if in statement were present UNION DISTINCT. --- mysql-test/r/view.result | 12 ++++++++++++ mysql-test/t/view.test | 12 ++++++++++++ sql/sql_lex.cc | 5 ++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 2af2f06ad52..a1566fa30c2 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2097,3 +2097,15 @@ select * from v1; f1 1 drop view v1; +create table t1 (f1 int); +create table t2 (f1 int); +insert into t1 values (1); +insert into t2 values (2); +create view v1 as select * from t1 union select * from t2 union all select * from t2; +select * from v1; +f1 +1 +2 +2 +drop view v1; +drop table t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ceff7af401c..f2fe5f460e2 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1942,3 +1942,15 @@ DROP TABLE t1,t2,t3,t4,t5; create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00:00:00') as f1; select * from v1; drop view v1; + +# +# Bug #10624 Views with multiple UNION and UNION ALL produce incorrect results +# +create table t1 (f1 int); +create table t2 (f1 int); +insert into t1 values (1); +insert into t2 values (2); +create view v1 as select * from t1 union select * from t2 union all select * from t2; +select * from v1; +drop view v1; +drop table t1,t2; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 86e677cc8dc..bbff64e516f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1511,13 +1511,16 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) void st_select_lex_unit::print(String *str) { + bool union_all= !union_distinct; for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { if (sl != first_select()) { str->append(" union ", 7); - if (!union_distinct) + if (union_all) str->append("all ", 4); + else if (union_distinct == sl) + union_all= true; } if (sl->braces) str->append('('); From 68d5420d7c0aa9c964b115fab5f7d88c8d2bf84f Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Mon, 15 Aug 2005 14:19:56 -0700 Subject: [PATCH 117/230] Clean up merge from 4.1 --- mysql-test/r/func_date_add.result | 4 ++-- mysql-test/r/func_time.result | 14 ++++++++++++++ server-tools/instance-manager/protocol.cc | 2 +- sql/sp_head.cc | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index 15ec80426ea..841d13a6ea6 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -56,10 +56,10 @@ insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); set sql_mode=''; insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); Warnings: -Warning 1437 Datetime function: datetime field overflow +Warning 1441 Datetime function: datetime field overflow insert into t1 (d) select date_add('2000-01-01',interval 8000 year); Warnings: -Warning 1437 Datetime function: datetime field overflow +Warning 1441 Datetime function: datetime field overflow insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); select * from t1; diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 28eb48790e0..e51dc113f97 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -247,9 +247,13 @@ date_add("1997-12-31 23:59:59",INTERVAL -100000 DAY) select date_add("1997-12-31 23:59:59",INTERVAL 100000 MONTH); date_add("1997-12-31 23:59:59",INTERVAL 100000 MONTH) NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow select date_add("1997-12-31 23:59:59",INTERVAL -100000 YEAR); date_add("1997-12-31 23:59:59",INTERVAL -100000 YEAR) NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow select date_add("1997-12-31 23:59:59",INTERVAL "10000:1" MINUTE_SECOND); date_add("1997-12-31 23:59:59",INTERVAL "10000:1" MINUTE_SECOND) 1998-01-07 22:40:00 @@ -301,6 +305,8 @@ NULL select date_add("9999-12-31 23:59:59",INTERVAL 1 SECOND); date_add("9999-12-31 23:59:59",INTERVAL 1 SECOND) NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow select date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND); date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND) NULL @@ -375,15 +381,23 @@ SELECT "1900-01-01 00:00:00" + INTERVAL 1<<20 HOUR; SELECT "1900-01-01 00:00:00" + INTERVAL 1<<38 SECOND; "1900-01-01 00:00:00" + INTERVAL 1<<38 SECOND NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow SELECT "1900-01-01 00:00:00" + INTERVAL 1<<33 MINUTE; "1900-01-01 00:00:00" + INTERVAL 1<<33 MINUTE NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow SELECT "1900-01-01 00:00:00" + INTERVAL 1<<30 HOUR; "1900-01-01 00:00:00" + INTERVAL 1<<30 HOUR NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow SELECT "1900-01-01 00:00:00" + INTERVAL "1000000000:214748364700" MINUTE_SECOND; "1900-01-01 00:00:00" + INTERVAL "1000000000:214748364700" MINUTE_SECOND NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow create table t1 (ctime varchar(20)); insert into t1 values ('2001-01-12 12:23:40'); select ctime, hour(ctime) from t1; diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc index 4b46d091c3f..cd1be805b6b 100644 --- a/server-tools/instance-manager/protocol.cc +++ b/server-tools/instance-manager/protocol.cc @@ -203,7 +203,7 @@ int send_fields(struct st_net *net, LIST *fields) position+= 12; if (my_net_write(net, send_buff.buffer, (uint) position+1)) goto err; - tmp= rest(tmp); + tmp= list_rest(tmp); } if (my_net_write(net, eof_buff, 1)) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 50bb3a84ee7..11677848cb8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -737,7 +737,7 @@ sp_head::execute(THD *thd) if (dbchanged) { if (! thd->killed) - ret= sp_change_db(thd, olddb, 0); + ret= mysql_change_db(thd, olddb, 0); } m_is_invoked= FALSE; DBUG_RETURN(ret); From 9693dc6a6be58d9cc1a12006927b492174301f8f Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 15 Aug 2005 21:33:58 -0700 Subject: [PATCH 118/230] sql_select.cc: Fixed bug #11479. The JOIN::reinit method cannot call setup_tables after the optimization phase since this function removes some optimization settings for joined tables. E.g. it resets values of the null_row flag to 0. subselect.result, subselect.test: Added a test case for bug #11479. --- mysql-test/r/subselect.result | 16 ++++++++++++++++ mysql-test/t/subselect.test | 16 ++++++++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8a2ae8e171a..673466245ee 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2817,3 +2817,19 @@ SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); a b aaa aaa DROP TABLE t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int); +CREATE TABLE t3 (b int NOT NULL); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1,10), (3,30); +SELECT * FROM t2 LEFT JOIN t3 ON t2.b=t3.b +WHERE t3.b IS NOT NULL OR t2.a > 10; +a b b +SELECT * FROM t1 +WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b +WHERE t3.b IS NOT NULL OR t2.a > 10); +a +1 +2 +3 +4 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 4bb917ab58c..7e3aa31217b 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1796,4 +1796,20 @@ SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); DROP TABLE t1; +# +# Bug #11479: subquery over left join with an empty inner table +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int); +CREATE TABLE t3 (b int NOT NULL); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1,10), (3,30); + +SELECT * FROM t2 LEFT JOIN t3 ON t2.b=t3.b + WHERE t3.b IS NOT NULL OR t2.a > 10; +SELECT * FROM t1 + WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b + WHERE t3.b IS NOT NULL OR t2.a > 10); + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7984b525d1..9984cb4138f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -984,7 +984,7 @@ JOIN::reinit() if (unit->select_limit_cnt == HA_POS_ERROR) select_lex->options&= ~OPTION_FOUND_ROWS; - if (setup_tables(tables_list)) + if (!optimized && setup_tables(tables_list)) DBUG_RETURN(1); /* Reset of sum functions */ From d553e1651830a9db78261888218c4dc2007afff1 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 15 Aug 2005 21:43:46 -0700 Subject: [PATCH 119/230] subselect.result: Added missing drop statement subselect.test: Added missing drop statement. --- mysql-test/r/subselect.result | 1 + mysql-test/t/subselect.test | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 673466245ee..8652ed89a65 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2833,3 +2833,4 @@ a 2 3 4 +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 7e3aa31217b..3d21456ee45 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1812,4 +1812,6 @@ SELECT * FROM t1 WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t3.b IS NOT NULL OR t2.a > 10); +DROP TABLE t1,t2,t3; + # End of 4.1 tests From c896ca1a10dd83804208546c594f1d7c21d4573b Mon Sep 17 00:00:00 2001 From: "andrey@lmy004.wdf.sap.corp" <> Date: Tue, 16 Aug 2005 11:18:35 +0200 Subject: [PATCH 120/230] fix for bug #12183 "SHOW OPEN TABLES behavior doesn't match grammar" (after review commit) --- mysql-test/r/show_check.result | 43 ++++++++++++++++++++++++++++++++++ mysql-test/t/show_check.test | 18 ++++++++++++++ sql/mysql_priv.h | 2 +- sql/sql_base.cc | 9 +++---- sql/sql_show.cc | 3 ++- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index f1c536ed1da..94d1ac7ac11 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -512,3 +512,46 @@ t1 CREATE TABLE `t1` ( KEY `c2` USING BTREE (`c2`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; +CREATE TABLE txt1(a int); +CREATE TABLE tyt2(a int); +CREATE TABLE urkunde(a int); +FLUSH TABLES; +SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone_name, txt1, tyt2, urkunde LIMIT 0; +1 +SHOW OPEN TABLES; +Database Table In_use Name_locked +mysql db 0 0 +test urkunde 0 0 +mysql time_zone 0 0 +mysql user 0 0 +test txt1 0 0 +mysql proc 0 0 +test tyt2 0 0 +mysql time_zone_name 0 0 +SHOW OPEN TABLES FROM mysql; +Database Table In_use Name_locked +mysql db 0 0 +mysql time_zone 0 0 +mysql user 0 0 +mysql proc 0 0 +mysql time_zone_name 0 0 +SHOW OPEN TABLES FROM mysql LIKE 'u%'; +Database Table In_use Name_locked +mysql user 0 0 +SHOW OPEN TABLES LIKE 't%'; +Database Table In_use Name_locked +mysql time_zone 0 0 +test txt1 0 0 +test tyt2 0 0 +mysql time_zone_name 0 0 +SHOW OPEN TABLES LIKE '%o%'; +Database Table In_use Name_locked +mysql time_zone 0 0 +mysql proc 0 0 +mysql time_zone_name 0 0 +FLUSH TABLES; +SHOW OPEN TABLES; +Database Table In_use Name_locked +DROP TABLE txt1; +DROP TABLE tyt2; +DROP TABLE urkunde; diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index efe3504ad7d..41b8a9e401c 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -387,3 +387,21 @@ SHOW CREATE TABLE t1; DROP TABLE t1; # End of 4.1 tests +# +# BUG 12183 - SHOW OPEN TABLES behavior doesn't match grammar +# First we close all open tables with FLUSH tables and then we open some. +CREATE TABLE txt1(a int); +CREATE TABLE tyt2(a int); +CREATE TABLE urkunde(a int); +FLUSH TABLES; +SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone_name, txt1, tyt2, urkunde LIMIT 0; +SHOW OPEN TABLES; +SHOW OPEN TABLES FROM mysql; +SHOW OPEN TABLES FROM mysql LIKE 'u%'; +SHOW OPEN TABLES LIKE 't%'; +SHOW OPEN TABLES LIKE '%o%'; +FLUSH TABLES; +SHOW OPEN TABLES; +DROP TABLE txt1; +DROP TABLE tyt2; +DROP TABLE urkunde; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0370251f119..085bb0166cc 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -981,7 +981,7 @@ bool fill_record_n_invoke_before_triggers(THD *thd, Field **field, bool ignore_errors, Table_triggers_list *triggers, enum trg_event_type event); -OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); +OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild); inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table, const char *db_name, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5627b97c734..3b716422663 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -129,12 +129,11 @@ static void check_unused(void) # Pointer to list of names of open tables. */ -OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) +OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) { int result = 0; OPEN_TABLE_LIST **start_list, *open_list; TABLE_LIST table_list; - char name[NAME_LEN*2]; DBUG_ENTER("list_open_tables"); VOID(pthread_mutex_lock(&LOCK_open)); @@ -151,10 +150,12 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) DBUG_ASSERT(share->table_name != 0); if ((!share->table_name)) // To be removed continue; // Shouldn't happen + if (db && my_strcasecmp(system_charset_info, db, share->table_cache_key)) + continue; + if (wild) { - strxmov(name,share->table_cache_key,".",share->table_name,NullS); - if (wild_compare(name,wild,0)) + if (wild_compare(share->table_name,wild,0)) continue; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0a76e9fb753..e1d5f80ebc2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3189,7 +3189,8 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; CHARSET_INFO *cs= system_charset_info; OPEN_TABLE_LIST *open_list; - if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error) + if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild)) + && thd->is_fatal_error) DBUG_RETURN(1); for (; open_list ; open_list=open_list->next) From c7bdc5bb12f8f9d9a17d155ff38ff803e57cb8d4 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Tue, 16 Aug 2005 15:32:41 +0300 Subject: [PATCH 121/230] Fixed indentations in error and warning messages. --- sql/ha_innodb.cc | 161 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 39 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index bf781e9a5c2..98a3922beec 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -975,7 +975,9 @@ innobase_query_caching_of_table_permitted( trx = check_trx_exists(thd); if (trx->has_search_latch) { ut_print_timestamp(stderr); - sql_print_error("The calling thread is holding the adaptive search, latch though calling innobase_query_caching_of_table_permitted."); + sql_print_error("The calling thread is holding the adaptive " + "search, latch though calling " + "innobase_query_caching_of_table_permitted."); } innobase_release_stat_resources(trx); @@ -1291,7 +1293,8 @@ innobase_init(void) &srv_log_group_home_dirs); if (ret == FALSE || innobase_mirrored_log_groups != 1) { - sql_print_error("syntax error in innodb_log_group_home_dir, or a wrong number of mirrored log groups"); + sql_print_error("syntax error in innodb_log_group_home_dir, or a " + "wrong number of mirrored log groups"); my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); @@ -1593,7 +1596,8 @@ innobase_commit( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != " + "TRX_NOT_STARTED"); } if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { @@ -1870,7 +1874,23 @@ try_again: if (ret != 0) { ut_print_timestamp(stderr); - sql_print_error("MySQL synchronous replication was not able to send the binlog to the slave within the timeout %lu. We assume that the slave has become inaccessible, and switch off synchronous replication until the communication to the slave works again. MySQL synchronous replication has sent binlog to the slave up to file %s, position %lu. This transaction needs it to be sent up to file %s, position %lu.", thd->variables.sync_replication_timeout, innobase_repl_file_name, (ulong)innobase_repl_pos, trx->repl_wait_binlog_name, (ulong)trx->repl_wait_binlog_pos); + sql_print_error("MySQL synchronous replication was " + "not able to send the binlog to the " + "slave within the timeout %lu. We " + "assume that the slave has become " + "inaccessible, and switch off " + "synchronous replication until the " + "communication to the slave works " + "again. MySQL synchronous replication " + "has sent binlog to the slave up to " + "file %s, position %lu. This " + "transaction needs it to be sent up " + "to file %s, position %lu.", + thd->variables.sync_replication_timeout, + innobase_repl_file_name, + (ulong) innobase_repl_pos, + trx->repl_wait_binlog_name, + (ulong) trx->repl_wait_binlog_pos); innobase_repl_state = 0; @@ -1921,7 +1941,9 @@ innobase_repl_report_sent_binlog( if (innobase_repl_state == 0) { ut_print_timestamp(stderr); - sql_print_warning("Switching MySQL synchronous replication on again at binlog file %s, position %lu", log_file_name, (ulong) end_offset); + sql_print_warning("Switching MySQL synchronous replication on " + "again at binlog file %s, position %lu", + log_file_name, (ulong) end_offset); innobase_repl_state = 1; } @@ -1938,7 +1960,14 @@ innobase_repl_report_sent_binlog( || (cmp == 0 && end_offset < innobase_repl_pos)) { ut_print_timestamp(stderr); - sql_print_error("MySQL synchronous replication has sent binlog to the slave up to file %s, position %lu, but now MySQL reports that it sent the binlog only up to file %s, position %lu", innobase_repl_file_name, (ulong)innobase_repl_pos, log_file_name, (ulong) end_offset); + sql_print_error("MySQL synchronous replication has " + "sent binlog to the slave up to file " + "%s, position %lu, but now MySQL " + "reports that it sent the binlog only " + "up to file %s, position %lu", + innobase_repl_file_name, + (ulong) innobase_repl_pos, + log_file_name, (ulong) end_offset); } } @@ -2183,7 +2212,8 @@ innobase_close_connection( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != " + "TRX_NOT_STARTED"); } @@ -2344,15 +2374,17 @@ ha_innobase::open( norm_name, NULL); if (NULL == ib_table) { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB error:\n" -"Cannot find table %s from the internal data dictionary\n" -"of InnoDB though the .frm file for the table exists. Maybe you\n" -"have deleted and recreated InnoDB data files but have forgotten\n" -"to delete the corresponding .frm files of InnoDB tables, or you\n" -"have moved .frm files to another database?\n" -"Look from section 15.1 of http://www.innodb.com/ibman.html\n" -"how you can resolve the problem.\n", - norm_name); + sql_print_error("Cannot find table %s from the internal data " + "dictionary\nof InnoDB though the .frm file " + "for the table exists. Maybe you\nhave " + "deleted and recreated InnoDB data files but " + "have forgotten\nto delete the corresponding " + ".frm files of InnoDB tables, or you\n" + "have moved .frm files to another database?\n" + "Look from section 15.1 of " + "http://www.innodb.com/ibman.html\n" + "how you can resolve the problem.\n", + norm_name); free_share(share); my_free((char*) upd_buff, MYF(0)); my_errno = ENOENT; @@ -2362,14 +2394,15 @@ ha_innobase::open( if (ib_table->ibd_file_missing && !thd->tablespace_op) { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB error:\n" -"MySQL is trying to open a table handle but the .ibd file for\n" -"table %s does not exist.\n" -"Have you deleted the .ibd file from the database directory under\n" -"the MySQL datadir, or have you used DISCARD TABLESPACE?\n" -"Look from section 15.1 of http://www.innodb.com/ibman.html\n" -"how you can resolve the problem.\n", - norm_name); + sql_print_error("MySQL is trying to open a table handle but " + "the .ibd file for\ntable %s does not exist.\n" + "Have you deleted the .ibd file from the " + "database directory under\nthe MySQL datadir, " + "or have you used DISCARD TABLESPACE?\n" + "Look from section 15.1 of " + "http://www.innodb.com/ibman.html\n" + "how you can resolve the problem.\n", + norm_name); free_share(share); my_free((char*) upd_buff, MYF(0)); my_errno = ENOENT; @@ -2395,7 +2428,8 @@ ha_innobase::open( if (!row_table_got_default_clust_index(ib_table)) { if (primary_key >= MAX_KEY) { - sql_print_error("Table %s has a primary key in InnoDB data dictionary, but not in MySQL!", name); + sql_print_error("Table %s has a primary key in InnoDB data " + "dictionary, but not in MySQL!", name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -2409,7 +2443,15 @@ ha_innobase::open( ref_length = table->key_info[primary_key].key_length; } else { if (primary_key != MAX_KEY) { - sql_print_error("Table %s has no primary key in InnoDB data dictionary, but has one in MySQL! If you created the table with a MySQL version < 3.23.54 and did not define a primary key, but defined a unique key with all non-NULL columns, then MySQL internally treats that key as the primary key. You can fix this error by dump + DROP + CREATE + reimport of the table.", name); + sql_print_error("Table %s has no primary key in InnoDB data " + "dictionary, but has one in MySQL! If you " + "created the table with a MySQL version < " + "3.23.54 and did not define a primary key, " + "but defined a unique key with all non-NULL " + "columns, then MySQL internally treats that " + "key as the primary key. You can fix this " + "error by dump + DROP + CREATE + reimport " + "of the table.", name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -2426,7 +2468,9 @@ ha_innobase::open( and it will never be updated anyway. */ if (key_used_on_scan != MAX_KEY) { - sql_print_warning("Table %s key_used_on_scan is %lu even though there is no primary key inside InnoDB.", name, (ulong) key_used_on_scan); + sql_print_warning("Table %s key_used_on_scan is %lu even " + "though there is no primary key inside " + "InnoDB.", name, (ulong) key_used_on_scan); } } @@ -2581,7 +2625,10 @@ innobase_mysql_cmp( charset = get_charset(charset_number, MYF(MY_WME)); if (charset == NULL) { - sql_print_error("InnoDB needs charset %lu for doing a comparison, but MySQL cannot find that charset.", (ulong) charset_number); + sql_print_error("InnoDB needs charset %lu for doing " + "a comparison, but MySQL cannot " + "find that charset.", + (ulong) charset_number); ut_a(0); } } @@ -3147,7 +3194,10 @@ ha_innobase::write_row( if (prebuilt->trx != (trx_t*) current_thd->ha_data[innobase_hton.slot]) { - sql_print_error("The transaction object for the table handle is at %p, but for the current thread it is at %p", prebuilt->trx, (trx_t*) current_thd->ha_data[innobase_hton.slot]); + sql_print_error("The transaction object for the table handle is at " + "%p, but for the current thread it is at %p", + prebuilt->trx, + (trx_t*) current_thd->ha_data[innobase_hton.slot]); fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr); ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200); @@ -3635,7 +3685,9 @@ ha_innobase::unlock_row(void) if (last_query_id != user_thd->query_id) { ut_print_timestamp(stderr); - sql_print_error("last_query_id is %lu != user_thd_query_id is %lu", (ulong) last_query_id, (ulong) user_thd->query_id); + sql_print_error("last_query_id is %lu != user_thd_query_id is " + "%lu", (ulong) last_query_id, + (ulong) user_thd->query_id); mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } @@ -3927,9 +3979,10 @@ ha_innobase::change_active_index( } if (!prebuilt->index) { - sql_print_error( -"Innodb could not find key n:o %u with name %s from dict cache for table %s", - keynr, key ? key->name : "NULL", prebuilt->table->name); + sql_print_error("Innodb could not find key n:o %u with name %s " + "from dict cache for table %s", + keynr, key ? key->name : "NULL", + prebuilt->table->name); DBUG_RETURN(1); } @@ -4501,7 +4554,12 @@ create_index( || col_type == DATA_FLOAT || col_type == DATA_DOUBLE || col_type == DATA_DECIMAL) { - sql_print_error("MySQL is trying to create a column prefix index field, on an inappropriate data type. Table name %s, column name %s.", table_name, key_part->field->field_name); + sql_print_error("MySQL is trying to create a column " + "prefix index field, on an " + "inappropriate data type. Table " + "name %s, column name %s.", + table_name, + key_part->field->field_name); prefix_len = 0; } @@ -5385,7 +5443,14 @@ ha_innobase::info( for (i = 0; i < table->s->keys; i++) { if (index == NULL) { ut_print_timestamp(stderr); - sql_print_error("Table %s contains less indexes inside InnoDB than are defined in the MySQL .frm file. Have you mixed up .frm files from different installations? See section 15.1 at http://www.innodb.com/ibman.html", ib_table->name); + sql_print_error("Table %s contains less " + "indexes inside InnoDB than " + "are defined in the MySQL " + ".frm file. Have you mixed up " + ".frm files from different " + "installations? See section " + "15.1 at http://www.innodb.com/ibman.html", + ib_table->name); break; } @@ -5393,7 +5458,21 @@ ha_innobase::info( if (j + 1 > index->n_uniq) { ut_print_timestamp(stderr); - sql_print_error("Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking statistics for %lu columns. Have you mixed up .frm files from different installations? See section 15.1 at http://www.innodb.com/ibman.html", index->name, ib_table->name, (unsigned long) index->n_uniq, j + 1); + sql_print_error("Index %s of %s has " + "%lu columns unique " + "inside InnoDB, but " + "MySQL is asking " + "statistics for %lu " + "columns. Have you " + "mixed up .frm files " + "from different " + "installations? See " + "section 15.1 at " + "http://www.innodb.com/ibman.html", + index->name, + ib_table->name, + (unsigned long) + index->n_uniq, j + 1); break; } @@ -5941,7 +6020,9 @@ ha_innobase::start_stmt( if (prebuilt->stored_select_lock_type != LOCK_S && prebuilt->stored_select_lock_type != LOCK_X) { - sql_print_error("stored_select_lock_type is %lu inside ::start_stmt()!", prebuilt->stored_select_lock_type); + sql_print_error("stored_select_lock_type is %lu inside " + "::start_stmt()!", + prebuilt->stored_select_lock_type); /* Set the value to LOCK_X: this is just fault tolerance, we do not know what the correct value @@ -6717,7 +6798,8 @@ ha_innobase::innobase_read_and_init_auto_inc( error = 0; } else { /* This should not happen in a consistent read */ - sql_print_error("Consistent read of auto-inc column returned %lu", (ulong) error); + sql_print_error("Consistent read of auto-inc column " + "returned %lu", (ulong) error); auto_inc = -1; goto func_exit; @@ -7042,7 +7124,8 @@ innobase_xa_prepare( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != " + "TRX_NOT_STARTED"); } if (all From a7a762e27d4e66dc70cc7a27e8ec1e6a0e148959 Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Tue, 16 Aug 2005 15:39:40 +0200 Subject: [PATCH 122/230] fix for bug #12595 (Escape character has to be exactly one) --- mysql-test/r/select.result | 11 +++++++++++ mysql-test/t/select.test | 11 +++++++++++ sql/item_cmpfunc.cc | 8 +++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d3409bf8d39..580ccc44a7c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2739,3 +2739,14 @@ DROP TABLE t1,t2; select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0 16 16 2 2 +CREATE TABLE BUG_12595(a varchar(100)); +INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; +a +ha%an +DROP TABLE BUG_12595; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 1de0831ad84..e0c4d66633b 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2350,3 +2350,14 @@ DROP TABLE t1,t2; # select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; + +# +# BUG #12595 +# +CREATE TABLE BUG_12595(a varchar(100)); +INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; +DROP TABLE BUG_12595; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 261f719e502..0a448f463e4 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2792,8 +2792,14 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&tmp_value1); + /* ESCAPE must be 1 char in length.*/ + if (escape_str && escape_str->numchars() != 1) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE"); + return TRUE; + } escape= escape_str ? *(escape_str->ptr()) : '\\'; - + /* We could also do boyer-more for non-const items, but as we would have to recompute the tables for each row it's not worth it. From 9457373c5f89ef16946da1cd9c443ee18202145d Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Tue, 16 Aug 2005 19:49:43 +0200 Subject: [PATCH 123/230] mtr_process.pl: Bug#12094: Let sleep_until_file_created() return the pid as intended --- mysql-test/lib/mtr_process.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 1eb4f6b7c58..e4cdaff1e77 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -752,6 +752,7 @@ sub mtr_ping_mysqld_server () { # ############################################################################## +# FIXME check that the pidfile contains the expected pid! sub sleep_until_file_created ($$$) { my $pidfile= shift; @@ -762,7 +763,7 @@ sub sleep_until_file_created ($$$) { { if ( -r $pidfile ) { - return 1; + return $pid; } # Check if it died after the fork() was successful From eb6135a7653dfc843081ada7461157497aac9e75 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 16 Aug 2005 22:13:43 +0400 Subject: [PATCH 124/230] Fix bug #11398 Bug in field_conv() results in wrong result of join with index When copying varchar fields with field_conv() it's not taken into account that length_bytes of source and destination fields may be different. This results in saving wrong data in field and making wrong key later. Added check so if fields are varchar and have different length_bytes they are not copied by memcpy(). --- mysql-test/r/select.result | 9 +++++++++ mysql-test/t/select.test | 10 ++++++++++ sql/field_conv.cc | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d3409bf8d39..4cbe652552f 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2739,3 +2739,12 @@ DROP TABLE t1,t2; select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0 16 16 2 2 +create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null); +create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4)); +insert into t1 values (" 2", 2); +insert into t2 values (" 2", " one "),(" 2", " two "); +select * from t1 left join t2 on f1 = f3; +f1 f2 f3 f4 + 2 2 2 one + 2 2 2 two +drop table t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 1de0831ad84..b7b09c36543 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2350,3 +2350,13 @@ DROP TABLE t1,t2; # select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; + +# +# Bug #11398 Bug in field_conv() results in wrong result of join with index +# +create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null); +create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4)); +insert into t1 values (" 2", 2); +insert into t2 values (" 2", " one "),(" 2", " two "); +select * from t1 left join t2 on f1 = f3; +drop table t1,t2; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index fc7347ef9af..40f3ff85c58 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -640,7 +640,10 @@ void field_conv(Field *to,Field *from) (!(to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) || to->type() != FIELD_TYPE_DATE && - to->type() != FIELD_TYPE_DATETIME)) + to->type() != FIELD_TYPE_DATETIME) && + (from->real_type() != MYSQL_TYPE_VARCHAR || + ((Field_varstring*)from)->length_bytes == + ((Field_varstring*)to)->length_bytes)) { // Identical fields #ifdef HAVE_purify /* This may happen if one does 'UPDATE ... SET x=x' */ From 7269045b821419246659f51f23790d939ba7c1bc Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Tue, 16 Aug 2005 20:54:53 +0200 Subject: [PATCH 125/230] after review fix for bug #12595 --- sql/item_cmpfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 0a448f463e4..c305196615a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2799,7 +2799,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) return TRUE; } escape= escape_str ? *(escape_str->ptr()) : '\\'; - + /* We could also do boyer-more for non-const items, but as we would have to recompute the tables for each row it's not worth it. From ed6cd805dc21c07d4c4157773877fc78f74e03e0 Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Tue, 16 Aug 2005 23:11:04 +0400 Subject: [PATCH 126/230] information_schema.test: Added a comment line for a test case used for bug #12301. information_schema.result: Fixed some test cases results (bug #12301). sql_show.cc: Fixed bug #12301. The bug was due to a missing value setting for the NUMERIC_SCALE column in the get_schema_column_record() function (sql_show.cc). --- mysql-test/r/information_schema.result | 14 +++++++------- mysql-test/t/information_schema.test | 1 + sql/sql_show.cc | 2 ++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 0a7f1af45f3..64e2434521e 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -165,7 +165,7 @@ c varchar(64) utf8_general_ci NO select,insert,update,references select * from information_schema.COLUMNS where table_name="t1" and column_name= "a"; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT -NULL mysqltest t1 a 1 NULL YES int NULL NULL 10 NULL NULL NULL int(11) select,insert,update,references +NULL mysqltest t1 a 1 NULL YES int NULL NULL 10 0 NULL NULL int(11) select,insert,update,references show columns from mysqltest.t1 where field like "%a%"; Field Type Null Key Default Extra a int(11) YES NULL @@ -535,7 +535,7 @@ c float(5,2) NULL NULL 5 2 d decimal(6,4) NULL NULL 6 4 e float NULL NULL 12 NULL f decimal(6,3) NULL NULL 6 3 -g int(11) NULL NULL 10 NULL +g int(11) NULL NULL 10 0 h double(10,3) NULL NULL 10 3 i double NULL NULL 22 NULL drop table t1; @@ -941,11 +941,11 @@ select column_name, NUMERIC_PRECISION, NUMERIC_SCALE from information_schema.columns where table_name='t1'; column_name NUMERIC_PRECISION NUMERIC_SCALE -f1 3 NULL -f2 5 NULL -f3 7 NULL -f4 10 NULL -f5 19 NULL +f1 3 0 +f2 5 0 +f3 7 0 +f4 10 0 +f5 19 0 f6 1 NULL f7 64 NULL drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index d6d9f34302b..03810447299 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -615,6 +615,7 @@ show create database information_schema; # # Bug #11057 information_schema: columns table has some questionable contents +# Bug #12301 information_schema: NUMERIC_SCALE must be 0 for integer columns # create table t1(f1 LONGBLOB, f2 LONGTEXT); select column_name,data_type,CHARACTER_OCTET_LENGTH, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e1d5f80ebc2..b06f1d683dd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2513,6 +2513,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, { table->field[10]->store((longlong) field->max_length() - 1); table->field[10]->set_notnull(); + table->field[11]->store((longlong) 0); + table->field[11]->set_notnull(); break; } case FIELD_TYPE_BIT: From eaf3af22b7d7621344a921c98095690e70d87123 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Wed, 17 Aug 2005 08:40:11 +1000 Subject: [PATCH 127/230] BUG#10950 make previous patch portable by abstracting to Ndb_check_socket_hup. Is in portlib rather than mysys due to the socket parameter being NDB_SOCKET_TYPE --- ndb/include/portlib/NdbTCP.h | 2 ++ ndb/src/common/portlib/NdbTCP.cpp | 15 +++++++++++++ ndb/src/common/portlib/win32/NdbTCP.c | 32 +++++++++++++++++++++++++++ ndb/src/mgmapi/mgmapi.cpp | 9 +------- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/ndb/include/portlib/NdbTCP.h b/ndb/include/portlib/NdbTCP.h index 308a3833ffd..9ed5b5e7f96 100644 --- a/ndb/include/portlib/NdbTCP.h +++ b/ndb/include/portlib/NdbTCP.h @@ -95,6 +95,8 @@ int Ndb_getInAddr(struct in_addr * dst, const char *address); int NDB_CLOSE_SOCKET(int fd); #endif +int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock); + #ifdef __cplusplus } #endif diff --git a/ndb/src/common/portlib/NdbTCP.cpp b/ndb/src/common/portlib/NdbTCP.cpp index c7b9d33c5f6..768292ac7c0 100644 --- a/ndb/src/common/portlib/NdbTCP.cpp +++ b/ndb/src/common/portlib/NdbTCP.cpp @@ -83,3 +83,18 @@ Ndb_getInAddr(struct in_addr * dst, const char *address) { return -1; } #endif + +int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock) +{ + struct pollfd pfd[1]; + int r; + + pfd[0].fd= sock; + pfd[0].events= POLLHUP | POLLIN | POLLOUT | POLLNVAL; + pfd[0].revents= 0; + r= poll(pfd,1,0); + if(pfd[0].revents & (POLLHUP|POLLERR)) + return 1; + + return 0; +} diff --git a/ndb/src/common/portlib/win32/NdbTCP.c b/ndb/src/common/portlib/win32/NdbTCP.c index b936cd2db6c..a14cd4409eb 100644 --- a/ndb/src/common/portlib/win32/NdbTCP.c +++ b/ndb/src/common/portlib/win32/NdbTCP.c @@ -37,3 +37,35 @@ Ndb_getInAddr(struct in_addr * dst, const char *address) return -1; } +int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock) +{ + fd_set readfds, writefds, errorfds; + struct timeval tv= {0,0}; + int s_err; + int s_err_size= sizeof(s_err); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&errorfds); + + FD_SET(sock, &readfds); + FD_SET(sock, &writefds); + FD_SET(sock, &errorfds); + + if(select(1, &readfds, &writefds, &errorfds, &t)==SOCKET_ERROR) + return 1; + + if(FD_ISSET(sock,&errorfds)) + return 1; + + s_err=0; + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) + return(1); + + if (s_err) + { /* getsockopt could succeed */ + return(1); /* but return an error... */ + } + + return 0; +} diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 26885a148a6..9f393d10528 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -360,19 +360,12 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, extern "C" int ndb_mgm_is_connected(NdbMgmHandle handle) { - struct pollfd pfd[1]; - int r; - if(!handle) return 0; if(handle->connected) { - pfd[0].fd= handle->socket; - pfd[0].events= POLLHUP | POLLIN | POLLOUT | POLLNVAL; - pfd[0].revents= 0; - r= poll(pfd,1,0); - if(pfd[0].revents & POLLHUP) + if(Ndb_check_socket_hup(handle->socket)) { handle->connected= 0; NDB_CLOSE_SOCKET(handle->socket); From c3104d1af1a75da3955d0e695e239a728f182175 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 17 Aug 2005 01:18:13 +0200 Subject: [PATCH 128/230] mtr_process.pl: Bug#11792: Check all of status code, to catch a crash as a failure mtr_cases.pl: Code cleanup for skipped/disabled handling mtr_process.pl: In debug mode, report if mysqladmin did not at least make the server stop listening to the port. Increased the time waiting for terminating to 20 seconds, to wait for really slow slave shutdown. Added call to start_reap_all(), to avoid zombies. mtr_report.pl: Removed prototype for unused function mtr_report_test_disabled() --- mysql-test/lib/mtr_cases.pl | 27 ++++++++++++------------- mysql-test/lib/mtr_process.pl | 37 ++++++++++++++++++++++++----------- mysql-test/lib/mtr_report.pl | 1 - 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 12714ddc1ad..158fd602ef8 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -53,21 +53,20 @@ sub collect_test_cases ($) { else { # ---------------------------------------------------------------------- - # Skip some tests listed in disabled.def + # Disable some tests listed in disabled.def # ---------------------------------------------------------------------- - my %skiplist; - my $skipfile= "$testdir/disabled.def"; - if ( open(SKIPFILE, $skipfile) ) + my %disabled; + if ( open(DISABLED, "$testdir/disabled.def" ) ) { - while ( ) + while ( ) { chomp; if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) { - $skiplist{$1}= $2; + $disabled{$1}= $2; } } - close SKIPFILE; + close DISABLED; } foreach my $elem ( sort readdir(TESTDIR) ) { @@ -75,7 +74,7 @@ sub collect_test_cases ($) { next if ! defined $tname; next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); - collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%skiplist); + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled); } closedir TESTDIR; } @@ -119,7 +118,7 @@ sub collect_one_test_case($$$$$$) { my $tname= shift; my $elem= shift; my $cases= shift; - my $skiplist=shift; + my $disabled=shift; my $path= "$testdir/$elem"; @@ -188,7 +187,7 @@ sub collect_one_test_case($$$$$$) { my $slave_mi_file= "$testdir/$tname.slave-mi"; my $master_sh= "$testdir/$tname-master.sh"; my $slave_sh= "$testdir/$tname-slave.sh"; - my $disabled= "$testdir/$tname.disabled"; + my $disabled_file= "$testdir/$tname.disabled"; $tinfo->{'master_opt'}= $::glob_win32 ? ["--default-time-zone=+3:00"] : []; $tinfo->{'slave_opt'}= $::glob_win32 ? ["--default-time-zone=+3:00"] : []; @@ -292,18 +291,18 @@ sub collect_one_test_case($$$$$$) { } # FIXME why this late? - if ( $skiplist->{$tname} ) + if ( $disabled->{$tname} ) { $tinfo->{'skip'}= 1; $tinfo->{'disable'}= 1; # Sub type of 'skip' - $tinfo->{'comment'}= $skiplist->{$tname} if $skiplist->{$tname}; + $tinfo->{'comment'}= $disabled->{$tname} if $disabled->{$tname}; } - if ( -f $disabled ) + if ( -f $disabled_file ) { $tinfo->{'skip'}= 1; $tinfo->{'disable'}= 1; # Sub type of 'skip' - $tinfo->{'comment'}= mtr_fromfile($disabled); + $tinfo->{'comment'}= mtr_fromfile($disabled_file); } # We can't restart a running server that may be in use diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index e4cdaff1e77..1f18968031c 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -186,8 +186,8 @@ sub spawn_parent_impl { if ( $mode eq 'run' or $mode eq 'test' ) { my $exit_value= -1; - my $signal_num= 0; - my $dumped_core= 0; +# my $signal_num= 0; +# my $dumped_core= 0; if ( $mode eq 'run' ) { @@ -199,9 +199,10 @@ sub spawn_parent_impl { mtr_error("$path ($pid) got lost somehow"); } - $exit_value= $? >> 8; - $signal_num= $? & 127; - $dumped_core= $? & 128; + $exit_value= $?; +# $exit_value= $? >> 8; +# $signal_num= $? & 127; +# $dumped_core= $? & 128; return $exit_value; } @@ -229,9 +230,10 @@ sub spawn_parent_impl { if ( $ret_pid == $pid ) { # We got termination of mysqltest, we are done - $exit_value= $? >> 8; - $signal_num= $? & 127; - $dumped_core= $? & 128; + $exit_value= $?; +# $exit_value= $? >> 8; +# $signal_num= $? & 127; +# $dumped_core= $? & 128; last; } @@ -473,6 +475,7 @@ sub mtr_stop_mysqld_servers ($) { } else { + # Server is dead, we remove the pidfile if any # Race, could have been removed between I tested with -f # and the unlink() below, so I better check again with -f @@ -502,10 +505,12 @@ sub mtr_stop_mysqld_servers ($) { # that for true Win32 processes, kill(0,$pid) will not return 1. # ---------------------------------------------------------------------- + start_reap_all(); # Avoid zombies + SIGNAL: foreach my $sig (15,9) { - my $retries= 10; # 10 seconds + my $retries= 20; # FIXME 20 seconds, this is silly! kill($sig, keys %mysqld_pids); while ( $retries-- and kill(0, keys %mysqld_pids) ) { @@ -514,6 +519,8 @@ sub mtr_stop_mysqld_servers ($) { } } + stop_reap_all(); # Get into control again + # ---------------------------------------------------------------------- # Now, we check if all we can find using kill(0,$pid) are dead, # and just assume the rest are. We cleanup socket and PID files. @@ -632,7 +639,8 @@ sub mtr_mysqladmin_shutdown () { $mysql_admin_pids{$pid}= 1; } - # We wait blocking, we wait for the last one anyway + # As mysqladmin is such a simple program, we trust it to terminate. + # I.e. we wait blocking, and wait wait for them all before we go on. while (keys %mysql_admin_pids) { foreach my $pid (keys %mysql_admin_pids) @@ -651,7 +659,8 @@ sub mtr_mysqladmin_shutdown () { my $timeout= 20; # 20 seconds max my $res= 1; # If we just fall through, we are done - + # in the sense that the servers don't + # listen to their ports any longer TIME: while ( $timeout-- ) { @@ -669,6 +678,8 @@ sub mtr_mysqladmin_shutdown () { last; # If we got here, we are done } + $timeout or mtr_debug("At least one server is still listening to its port"); + sleep(5) if $::glob_win32; # FIXME next startup fails if no sleep return $res; @@ -794,8 +805,12 @@ sub sleep_until_file_created ($$$) { # ############################################################################## +# FIXME something is wrong, we sometimes terminate with "Hangup" written +# to tty, and no STDERR output telling us why. + sub mtr_exit ($) { my $code= shift; +# cluck("Called mtr_exit()"); local $SIG{HUP} = 'IGNORE'; kill('HUP', -$$); exit($code); diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 0af34d11a3f..b9dab6b8d32 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -10,7 +10,6 @@ sub mtr_report_test_name($); sub mtr_report_test_passed($); sub mtr_report_test_failed($); sub mtr_report_test_skipped($); -sub mtr_report_test_disabled($); sub mtr_show_failed_diff ($); sub mtr_report_stats ($); From 054e78943e6a85cff68daaa7630b907da1e8f10f Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Tue, 16 Aug 2005 16:31:16 -0700 Subject: [PATCH 129/230] Fix SLEEP() to be interruptable. (Bug #12582) --- include/my_global.h | 7 +++++++ sql/item_func.cc | 30 ++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index 95763f64e55..2627ea8e821 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -939,6 +939,13 @@ typedef char bool; /* Ordinary boolean values 0 1 */ #endif /* HAVE_TIMESPEC_TS_SEC */ #endif /* set_timespec */ +#define set_timespec_nsec(ABSTIME,NSEC) \ +{\ + ulonglong now= my_getsystime(); \ + (ABSTIME).tv_sec= (now / ULL(10000000)) + (NSEC / ULL(1000000000)); \ + (ABSTIME).tv_nsec= (now % ULL(10000000)) * 100 + (NSEC % ULL(1000000000)); \ +} + /* Define-funktions for reading and storing in machine independent format (low byte first) diff --git a/sql/item_func.cc b/sql/item_func.cc index 61467595424..460d442de89 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3266,10 +3266,36 @@ void Item_func_benchmark::print(String *str) longlong Item_func_sleep::val_int() { + THD *thd= current_thd; + struct timespec abstime; + pthread_cond_t cond; + int error= 0; + DBUG_ASSERT(fixed == 1); + double time= args[0]->val_real(); - my_sleep((ulong)time*1000000L); - return 0; + set_timespec_nsec(abstime, (ulonglong)(time * ULL(1000000000))); + + pthread_cond_init(&cond, NULL); + pthread_mutex_lock(&LOCK_user_locks); + + thd->mysys_var->current_mutex= &LOCK_user_locks; + thd->mysys_var->current_cond= &cond; + + while (!thd->killed && + (error= pthread_cond_timedwait(&cond, &LOCK_user_locks, + &abstime) != ETIMEDOUT) && + error != EINVAL) ; + + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + pthread_mutex_unlock(&thd->mysys_var->mutex); + + pthread_mutex_unlock(&LOCK_user_locks); + pthread_cond_destroy(&cond); + + return (error == ETIMEDOUT) ? 0 : 1; } From 16359fc02fed06ca455498265574d269e827d8a0 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 17 Aug 2005 03:35:50 +0200 Subject: [PATCH 130/230] mysql-test-run.pl: Bug#11884: Corrected --start-and-exit, start the server as if the default/specified test case would have been run --- mysql-test/mysql-test-run.pl | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 523f31f5a5f..e976242e726 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -341,7 +341,6 @@ sub main () { if ( ! $glob_use_running_server ) { - if ( $opt_start_dirty ) { kill_running_server(); @@ -356,7 +355,7 @@ sub main () { } } - if ( $opt_start_and_exit or $opt_start_dirty ) + if ( $opt_start_dirty ) { if ( ndbcluster_start() ) { @@ -371,16 +370,13 @@ sub main () { mtr_error("Can't start the mysqld server"); } } + elsif ( $opt_bench ) + { + run_benchmarks(shift); # Shift what? Extra arguments?! + } else { - if ( $opt_bench ) - { - run_benchmarks(shift); # Shift what? Extra arguments?! - } - else - { - run_tests(); - } + run_tests(); } mtr_exit(0); @@ -1490,6 +1486,16 @@ sub run_testcase ($) { } } + # ---------------------------------------------------------------------- + # If --start-and-exit given, stop here to let user manually run tests + # ---------------------------------------------------------------------- + + if ( $opt_start_and_exit ) + { + mtr_report("\nServers started, exiting"); + exit(0); + } + # ---------------------------------------------------------------------- # Run the test case # ---------------------------------------------------------------------- @@ -2248,7 +2254,8 @@ Misc options script-debug Debug this script itself compress Use the compressed protocol between client and server timer Show test case execution time - start-and-exit Only initiate and start the "mysqld" servers + start-and-exit Only initiate and start the "mysqld" servers, use the startup + settings for the specified test case if any start-dirty Only start the "mysqld" servers without initiation fast Don't try to cleanup from earlier runs reorder Reorder tests to get less server restarts From 197782605f836ccb038c93b98548297e0cc20655 Mon Sep 17 00:00:00 2001 From: "elliot@mysql.com" <> Date: Wed, 17 Aug 2005 04:26:32 -0400 Subject: [PATCH 131/230] BUG#11338 (logging of prepared statement w/ blob type) In cp932, '\' character can be the second byte in a multi-byte character stream. This makes it difficult to use mysql_escape_string. Added flag to indicate which languages allow '\' as second byte of multibyte sequence so that when putting a prepared statement into the binlog we can decide at runtime whether hex encoding is really needed. --- include/m_ctype.h | 1 + include/my_sys.h | 1 + mysys/charset.c | 18 ++++++++++++++++++ sql/item.cc | 18 +++++++++++++----- sql/item.h | 2 +- sql/sql_prepare.cc | 4 ++-- strings/ctype-big5.c | 2 ++ strings/ctype-bin.c | 1 + strings/ctype-cp932.c | 2 ++ strings/ctype-czech.c | 1 + strings/ctype-euc_kr.c | 2 ++ strings/ctype-extra.c | 1 + strings/ctype-gb2312.c | 2 ++ strings/ctype-gbk.c | 2 ++ strings/ctype-latin1.c | 3 +++ strings/ctype-sjis.c | 2 ++ strings/ctype-tis620.c | 2 ++ strings/ctype-uca.c | 34 ++++++++++++++++++++++++++++++++++ strings/ctype-ucs2.c | 2 ++ strings/ctype-ujis.c | 2 ++ strings/ctype-utf8.c | 3 +++ strings/ctype-win1250ch.c | 1 + 22 files changed, 98 insertions(+), 8 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index ab63a1e0db1..a5dc7cc00c6 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -220,6 +220,7 @@ typedef struct charset_info_st uint mbmaxlen; uint16 min_sort_char; uint16 max_sort_char; /* For LIKE optimization */ + my_bool escape_with_backslash_is_dangerous; MY_CHARSET_HANDLER *cset; MY_COLLATION_HANDLER *coll; diff --git a/include/my_sys.h b/include/my_sys.h index 8752aa30772..eafa41a05c8 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -788,6 +788,7 @@ extern my_bool init_compiled_charsets(myf flags); extern void add_compiled_collation(CHARSET_INFO *cs); extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); +extern char *bare_str_to_hex(char *to, const char *from, uint len); #ifdef __WIN__ #define BACKSLASH_MBTAIL /* File system character set */ diff --git a/mysys/charset.c b/mysys/charset.c index 3a39fce9437..df3f1cfa279 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -663,3 +663,21 @@ CHARSET_INFO *fs_character_set() return fs_cset_cache; } #endif + +/* + Transforms a string into hex form. + */ +char *bare_str_to_hex(char *to, const char *from, uint len) +{ + char *p= to; + uint i; + for (i= 0; i < len; i++, p+= 2) + { + /* val[i] is char. Casting to uchar helps greatly if val[i] < 0 */ + uint tmp= (uint) (uchar) from[i]; + p[0]= _dig_vec_upper[tmp >> 4]; + p[1]= _dig_vec_upper[tmp & 15]; + } + *p= 0; + return p; // pointer to end 0 of 'to' +} diff --git a/sql/item.cc b/sql/item.cc index b3d2932acf6..79579eeeb67 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1443,7 +1443,7 @@ String *Item_param::val_str(String* str) and avoid one more memcpy/alloc between str and log string. */ -const String *Item_param::query_val_str(String* str) const +const String *Item_param::query_val_str(String* str, THD *thd) const { switch (state) { case INT_VALUE: @@ -1482,10 +1482,18 @@ const String *Item_param::query_val_str(String* str) const buf= str->c_ptr_quick(); ptr= buf; - *ptr++= '\''; - ptr+= escape_string_for_mysql(str_value.charset(), ptr, - str_value.ptr(), str_value.length()); - *ptr++= '\''; + if (thd->charset()->escape_with_backslash_is_dangerous) + { + ptr= strmov(ptr, "x\'"); + ptr= bare_str_to_hex(ptr, str_value.ptr(), str_value.length()); + } + else + { + *ptr++= '\''; + ptr+= escape_string_for_mysql(str_value.charset(), ptr, + str_value.ptr(), str_value.length()); + } + *ptr++='\''; str->length(ptr - buf); break; } diff --git a/sql/item.h b/sql/item.h index 825b37fe64c..ee86fb80167 100644 --- a/sql/item.h +++ b/sql/item.h @@ -591,7 +591,7 @@ public: */ void (*set_param_func)(Item_param *param, uchar **pos, ulong len); - const String *query_val_str(String *str) const; + const String *query_val_str(String *str, THD *thd) const; bool convert_str_value(THD *thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6507de37a71..d0c06a3eaf7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -601,7 +601,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, param->set_param_func(param, &read_pos, data_end - read_pos); } } - res= param->query_val_str(&str); + res= param->query_val_str(&str, thd); if (param->convert_str_value(thd)) DBUG_RETURN(1); /* out of memory */ @@ -749,7 +749,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) client_param->buffer_length); } } - res= param->query_val_str(&str); + res= param->query_val_str(&str, thd); if (param->convert_str_value(thd)) DBUG_RETURN(1); /* out of memory */ diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 73e3efd09a7..76a4e197405 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6378,6 +6378,7 @@ CHARSET_INFO my_charset_big5_chinese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, &my_collation_big5_chinese_ci_handler }; @@ -6406,6 +6407,7 @@ CHARSET_INFO my_charset_big5_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 425985e6bc1..1ac79ac9ca0 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -514,6 +514,7 @@ CHARSET_INFO my_charset_bin = 1, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_binary_handler }; diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index be3526519cb..e476130b706 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -5520,6 +5520,7 @@ CHARSET_INFO my_charset_cp932_japanese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -5547,6 +5548,7 @@ CHARSET_INFO my_charset_cp932_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index 5725e81b15e..4bd2fbddbc4 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -612,6 +612,7 @@ CHARSET_INFO my_charset_latin2_czech_ci = 1, /* mbmaxlen */ 0, /* min_sort_char */ 0, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_8bit_handler, &my_collation_latin2_czech_ci_handler }; diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index ee792d9c3e4..f15e97de5be 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8701,6 +8701,7 @@ CHARSET_INFO my_charset_euckr_korean_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -8729,6 +8730,7 @@ CHARSET_INFO my_charset_euckr_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-extra.c b/strings/ctype-extra.c index 3672dcd0b33..1c786c16ec5 100644 --- a/strings/ctype-extra.c +++ b/strings/ctype-extra.c @@ -40,6 +40,7 @@ CHARSET_INFO compiled_charsets[] = { 0, /* mbmaxlen */ 0, /* min_sort_ord */ 0, /* max_sort_ord */ + 0, /* escape_with_backslash_is_dangerous */ NULL, /* cset handler */ NULL /* coll handler */ } diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index f17cc94723f..0cbad2d1c55 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5752,6 +5752,7 @@ CHARSET_INFO my_charset_gb2312_chinese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -5779,6 +5780,7 @@ CHARSET_INFO my_charset_gb2312_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 7196d004ad5..82c76b8ee96 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -10028,6 +10028,7 @@ CHARSET_INFO my_charset_gbk_chinese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -10055,6 +10056,7 @@ CHARSET_INFO my_charset_gbk_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index 9b429fea95c..b6e3e300c34 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -438,6 +438,7 @@ CHARSET_INFO my_charset_latin1= 1, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_8bit_simple_ci_handler }; @@ -722,6 +723,7 @@ CHARSET_INFO my_charset_latin1_german2_ci= 1, /* mbmaxlen */ 0, /* min_sort_char */ 247, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_german2_ci_handler }; @@ -750,6 +752,7 @@ CHARSET_INFO my_charset_latin1_bin= 1, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_8bit_bin_handler }; diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 900acefd4ea..4342fc670df 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4676,6 +4676,7 @@ CHARSET_INFO my_charset_sjis_japanese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -4703,6 +4704,7 @@ CHARSET_INFO my_charset_sjis_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 6a6c55d214e..208168bb946 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -975,6 +975,7 @@ CHARSET_INFO my_charset_tis620_thai_ci= 1, /* mbmaxlen */ 0, /* min_sort_char */ 0, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -1002,6 +1003,7 @@ CHARSET_INFO my_charset_tis620_bin= 1, /* mbmaxlen */ 0, /* min_sort_char */ 0, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_8bit_bin_handler }; diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 53c4fabaf08..010250521c7 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -8044,6 +8044,7 @@ CHARSET_INFO my_charset_ucs2_general_uca= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8071,6 +8072,7 @@ CHARSET_INFO my_charset_ucs2_icelandic_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8098,6 +8100,7 @@ CHARSET_INFO my_charset_ucs2_latvian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8125,6 +8128,7 @@ CHARSET_INFO my_charset_ucs2_romanian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8152,6 +8156,7 @@ CHARSET_INFO my_charset_ucs2_slovenian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8179,6 +8184,7 @@ CHARSET_INFO my_charset_ucs2_polish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8206,6 +8212,7 @@ CHARSET_INFO my_charset_ucs2_estonian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8233,6 +8240,7 @@ CHARSET_INFO my_charset_ucs2_spanish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8260,6 +8268,7 @@ CHARSET_INFO my_charset_ucs2_swedish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8287,6 +8296,7 @@ CHARSET_INFO my_charset_ucs2_turkish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8314,6 +8324,7 @@ CHARSET_INFO my_charset_ucs2_czech_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8342,6 +8353,7 @@ CHARSET_INFO my_charset_ucs2_danish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8369,6 +8381,7 @@ CHARSET_INFO my_charset_ucs2_lithuanian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8396,6 +8409,7 @@ CHARSET_INFO my_charset_ucs2_slovak_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8423,6 +8437,7 @@ CHARSET_INFO my_charset_ucs2_spanish2_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8451,6 +8466,7 @@ CHARSET_INFO my_charset_ucs2_roman_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8479,6 +8495,7 @@ CHARSET_INFO my_charset_ucs2_persian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler }; @@ -8552,6 +8569,7 @@ CHARSET_INFO my_charset_utf8_general_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8580,6 +8598,7 @@ CHARSET_INFO my_charset_utf8_icelandic_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8607,6 +8626,7 @@ CHARSET_INFO my_charset_utf8_latvian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8634,6 +8654,7 @@ CHARSET_INFO my_charset_utf8_romanian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8661,6 +8682,7 @@ CHARSET_INFO my_charset_utf8_slovenian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8688,6 +8710,7 @@ CHARSET_INFO my_charset_utf8_polish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8715,6 +8738,7 @@ CHARSET_INFO my_charset_utf8_estonian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8742,6 +8766,7 @@ CHARSET_INFO my_charset_utf8_spanish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8769,6 +8794,7 @@ CHARSET_INFO my_charset_utf8_swedish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8796,6 +8822,7 @@ CHARSET_INFO my_charset_utf8_turkish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8823,6 +8850,7 @@ CHARSET_INFO my_charset_utf8_czech_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8851,6 +8879,7 @@ CHARSET_INFO my_charset_utf8_danish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8878,6 +8907,7 @@ CHARSET_INFO my_charset_utf8_lithuanian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8905,6 +8935,7 @@ CHARSET_INFO my_charset_utf8_slovak_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8932,6 +8963,7 @@ CHARSET_INFO my_charset_utf8_spanish2_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8959,6 +8991,7 @@ CHARSET_INFO my_charset_utf8_roman_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; @@ -8986,6 +9019,7 @@ CHARSET_INFO my_charset_utf8_persian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler }; diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 025fdd5a7f6..2761e781724 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1583,6 +1583,7 @@ CHARSET_INFO my_charset_ucs2_general_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_general_ci_handler }; @@ -1610,6 +1611,7 @@ CHARSET_INFO my_charset_ucs2_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_bin_handler }; diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index f20e2756810..b3bba85968e 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8571,6 +8571,7 @@ CHARSET_INFO my_charset_ujis_japanese_ci= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -8599,6 +8600,7 @@ CHARSET_INFO my_charset_ujis_bin= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 0bf57967630..b3e78ce27e9 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2345,6 +2345,7 @@ CHARSET_INFO my_charset_utf8_general_ci= 3, /* mbmaxlen */ 0, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_ci_handler }; @@ -2373,6 +2374,7 @@ CHARSET_INFO my_charset_utf8_bin= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_mb_bin_handler }; @@ -2538,6 +2540,7 @@ CHARSET_INFO my_charset_utf8_general_cs= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_cs_handler }; diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index 2a899dfd147..351af3de23e 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -647,6 +647,7 @@ CHARSET_INFO my_charset_cp1250_czech_ci = 1, /* mbmaxlen */ 0, /* min_sort_char */ 0, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_8bit_handler, &my_collation_czech_ci_handler }; From c8e55a35b3ce7da0082073ad1f5968b7db5f5250 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Wed, 17 Aug 2005 13:46:36 +0300 Subject: [PATCH 132/230] WL#2486 - Process NATURAL and USING joins according to SQL:2003 - Applied Monty's patch after his review of sql_base.cc --- sql/sql_base.cc | 301 +++++++++++++++++++++++++----------------------- 1 file changed, 158 insertions(+), 143 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4c1b8347466..57bd6985579 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2600,30 +2600,35 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, NATURAL/USING joins RETURN - - Pointer to the found Field - - NULL if the field was not found - - WRONG_GRANT if no access rights to the found field + NULL if the field was not found + WRONG_GRANT if no access rights to the found field + # Pointer to the found Field */ static Field * find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, const char *table_name, const char *db_name, uint length, Item **ref, bool check_grants, - bool register_tree_change, TABLE_LIST **actual_table) + bool register_tree_change, + TABLE_LIST **actual_table) { - DBUG_ENTER("find_field_in_natural_join"); - DBUG_PRINT("enter", ("natural join, field name: '%s', ref 0x%lx", - name, (ulong) ref)); - DBUG_ASSERT(table_ref->is_natural_join && table_ref->join_columns); List_iterator_fast field_it(*(table_ref->join_columns)); - Natural_join_column *nj_col= NULL; - Field *found_field= NULL; + Natural_join_column *nj_col; + Field *found_field; + DBUG_ENTER("find_field_in_natural_join"); + DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx", + name, (ulong) ref)); + DBUG_ASSERT(table_ref->is_natural_join && table_ref->join_columns); + DBUG_ASSERT(*actual_table == NULL); - *actual_table= NULL; + LINT_INIT(found_field); - while ((nj_col= field_it++)) + for (;;) { + if (!(nj_col= field_it++)) + DBUG_RETURN(NULL); + if (table_name) { /* @@ -2640,7 +2645,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, if (db_name && db_name[0]) { const char *cur_db_name= nj_col->db_name(); - if (cur_db_name && cur_db_name && strcmp(db_name, cur_db_name)) + if (cur_db_name && strcmp(db_name, cur_db_name)) continue; } } @@ -2649,9 +2654,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, break; } - if (!nj_col) - DBUG_RETURN(NULL); - #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants && nj_col->check_grants(thd, name, length)) DBUG_RETURN(WRONG_GRANT); @@ -2668,13 +2670,14 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, DBUG_RETURN(NULL); DBUG_ASSERT(nj_col->table_field == NULL); if (nj_col->table_ref->schema_table_reformed) + { /* Translation table items are always Item_fields and fixed already('mysql_schema_table' function). So we can return ->field. It is used only for 'show & where' commands. */ DBUG_RETURN(((Item_field*) (nj_col->view_field->item))->field); - + } if (register_tree_change) thd->change_item_tree(ref, item); else @@ -2710,8 +2713,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, lookup for fields in prepared tables) RETURN - 0 field is not found - # pointer to field + 0 field is not found + # pointer to field */ Field * @@ -2719,10 +2722,10 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, bool check_grants, bool allow_rowid, uint *cached_field_index_ptr) { - DBUG_ENTER("find_field_in_table"); - DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias, name)); Field **field_ptr, *field; uint cached_field_index= *cached_field_index_ptr; + DBUG_ENTER("find_field_in_table"); + DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias, name)); /* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */ if (cached_field_index < table->s->fields && @@ -2760,7 +2763,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, if (check_grants && check_grant_column(thd, &table->grant, table->s->db, table->s->table_name, name, length)) - DBUG_RETURN(WRONG_GRANT); + field= WRONG_GRANT; #endif DBUG_RETURN(field); } @@ -2819,22 +2822,23 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, simply compare the qualifying table and database names with the ones of 'table_list' because each field in such a join may originate from a different table. - TODO: Ensure that db and tables->db always points to something ! + TODO: Ensure that table_name, db_name and tables->db always points to + something ! */ if (!table_list->is_natural_join && - (table_name && table_name[0] && - my_strcasecmp(table_alias_charset, table_list->alias, table_name) || + table_name && table_name[0] && + (my_strcasecmp(table_alias_charset, table_list->alias, table_name) || (db_name && db_name[0] && table_list->db && table_list->db[0] && strcmp(db_name, table_list->db)))) DBUG_RETURN(0); + *actual_table= NULL; if (table_list->field_translation) { if ((fld= find_field_in_view(thd, table_list, name, item_name, length, - ref, check_grants_view, register_tree_change))) + ref, check_grants_view, + register_tree_change))) *actual_table= table_list; - else - *actual_table= NULL; } else if (table_list->is_natural_join) fld= find_field_in_natural_join(thd, table_list, name, table_name, @@ -2848,8 +2852,6 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, check_grants_table, allow_rowid, cached_field_index_ptr))) *actual_table= table_list; - else - *actual_table= NULL; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* check for views with temporary table algorithm */ if (check_grants_view && table_list->view && @@ -2858,7 +2860,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str, name, length)) - DBUG_RETURN(WRONG_GRANT); + fld= WRONG_GRANT; #endif } @@ -2982,18 +2984,15 @@ find_field_in_tables(THD *thd, Item_ident *item, db= name_buff; } + if (last_table) + last_table= last_table->next_name_resolution_table; + /* The field we search for is qualified with a table name and optional db. */ if (table_name && table_name[0]) { - bool found_table=0; - for ( ; - (cur_table && - (last_table ? - (cur_table != last_table->next_name_resolution_table) : TRUE)); + for (; cur_table != last_table ; cur_table= cur_table->next_name_resolution_table) { - DBUG_ASSERT(cur_table); - found_table= 1; Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name, table_name, db, length, ref, @@ -3002,8 +3001,8 @@ find_field_in_tables(THD *thd, Item_ident *item, want_privilege) && check_privileges), (test(cur_table->grant. - want_privilege) - && check_privileges), + want_privilege) && + check_privileges), 1, &(item->cached_field_index), register_tree_change, &actual_table); @@ -3032,8 +3031,12 @@ find_field_in_tables(THD *thd, Item_ident *item, } if (found) return found; - if (!found_table && (report_error == REPORT_ALL_ERRORS || - report_error == REPORT_EXCEPT_NON_UNIQUE)) + /* + If there were no tables to search, we wouldn't go through the loop and + cur_table wouldn't be updated by the loop increment part. + */ + if (cur_table == first_table && (report_error == REPORT_ALL_ERRORS || + report_error == REPORT_EXCEPT_NON_UNIQUE)) { char buff[NAME_LEN*2+1]; if (db && db[0]) @@ -3054,13 +3057,9 @@ find_field_in_tables(THD *thd, Item_ident *item, /* The field we search for is not qualified. */ allow_rowid= cur_table && !cur_table->next_local; - for ( ; - (cur_table && - (last_table ? - (cur_table != last_table->next_name_resolution_table) : TRUE)); - cur_table= cur_table->next_name_resolution_table) + for (; cur_table != last_table ; + cur_table= cur_table->next_name_resolution_table) { - DBUG_ASSERT(cur_table); Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name, NULL, NULL, length, ref, (cur_table->table && @@ -3359,20 +3358,21 @@ test_if_string_in_list(const char *find, List *str_list) is resolved only the supplied 'table_ref'. RETURN - FALSE - if all OK - TRUE - otherwise + FALSE if all OK + TRUE otherwise */ static bool set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) { Name_resolution_context *context; + if (!(context= (Name_resolution_context*) thd->calloc(sizeof(Name_resolution_context)))) return TRUE; context->init(); - context->first_name_resolution_table= table_ref; - context->last_name_resolution_table= table_ref; + context->first_name_resolution_table= + context->last_name_resolution_table= table_ref; item->context= context; return FALSE; } @@ -3405,8 +3405,8 @@ set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) called for the previous level of NATURAL/USING joins. RETURN - TRUE - if error when some common column is non-unique, or out of memory - FALSE - if OK + TRUE error when some common column is non-unique, or out of memory + FALSE OK */ static bool @@ -3415,16 +3415,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { Field_iterator_table_ref it_1, it_2; Natural_join_column *nj_col_1, *nj_col_2; - const char *field_name_1, *field_name_2; - *found_using_fields= 0; - bool add_columns= TRUE; + const char *field_name_1; Query_arena *arena, backup; + bool add_columns= TRUE; bool result= TRUE; DBUG_ENTER("mark_common_columns"); - DBUG_PRINT("info", ("operand_1: %s, operand_2: %s", + DBUG_PRINT("info", ("operand_1: %s operand_2: %s", table_ref_1->alias, table_ref_2->alias)); + *found_using_fields= 0; arena= thd->change_arena_if_needed(&backup); /* @@ -3447,25 +3447,31 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next()) { bool is_created_1; + bool found= FALSE; if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created_1))) goto err; field_name_1= nj_col_1->name(); - bool found= FALSE; /* If nj_col_1 was just created add it to the list of join columns. */ if (is_created_1) table_ref_1->join_columns->push_back(nj_col_1); - /* Find a field with the same name in table_ref_2. */ + /* + Find a field with the same name in table_ref_2. + + Note that for the second loop, it_2.set() will iterate over + table_ref_2->join_columns and not generate any new elements or + lists. + */ nj_col_2= NULL; - field_name_2= NULL; for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next()) { bool is_created_2; Natural_join_column *cur_nj_col_2; + const char *cur_field_name_2; if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, &is_created_2))) goto err; - const char *cur_field_name_2= cur_nj_col_2->name(); + cur_field_name_2= cur_nj_col_2->name(); /* If nj_col_1 was just created add it to the list of join columns. */ if (add_columns && is_created_2) @@ -3480,14 +3486,14 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, goto err; } nj_col_2= cur_nj_col_2; - field_name_2= cur_field_name_2; found= TRUE; } } + /* Force it_2.set() to use table_ref_2->join_columns. */ table_ref_2->is_join_columns_complete= TRUE; add_columns= FALSE; if (!found) - continue; + continue; // No matching field /* field_1 and field_2 have the same names. Check if they are in the USING @@ -3496,8 +3502,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, */ if (nj_col_2 && (!using_fields || - (using_fields && - test_if_string_in_list(field_name_1, using_fields)))) + test_if_string_in_list(field_name_1, using_fields))) { Item *item_1= nj_col_1->create_item(thd); Item *item_2= nj_col_2->create_item(thd); @@ -3505,12 +3510,17 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, Field *field_2= nj_col_2->field(); Item_ident *item_ident_1, *item_ident_2; Name_resolution_context *context_1, *context_2; + Item_func_eq *eq_cond; + DBUG_PRINT("info", ("new equi-join condition: %s.%s = %s.%s", table_ref_1->alias, field_1->field_name, table_ref_2->alias, field_2->field_name)); + if (!item_1 || !item_2) + goto err; // out of memory + /* - The first assert guarantees that the two created items are of + The following assert checks that the two created items are of type Item_ident. */ DBUG_ASSERT(!thd->lex->current_select->no_wrap_view_item); @@ -3535,24 +3545,21 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, resolution of these items, and to enable proper name resolution of the items during the execute phase of PS. */ - if (set_new_item_local_context(thd, item_ident_1, table_ref_1)) - goto err; - if (set_new_item_local_context(thd, item_ident_2, table_ref_2)) + if (set_new_item_local_context(thd, item_ident_1, table_ref_1) || + set_new_item_local_context(thd, item_ident_2, table_ref_2)) goto err; - Item_func_eq *eq_cond= new Item_func_eq(item_ident_1, item_ident_2); - if (!eq_cond) - goto err; /* Out of memory. */ + if (!(eq_cond= new Item_func_eq(item_ident_1, item_ident_2))) + goto err; /* Out of memory. */ /* Add the new equi-join condition to the ON clause. Notice that fix_fields() is applied to all ON conditions in setup_conds() so we don't do it here. */ - if (table_ref_1->outer_join & JOIN_TYPE_RIGHT) - add_join_on(table_ref_1, eq_cond); - else - add_join_on(table_ref_2, eq_cond); + add_join_on((table_ref_1->outer_join & JOIN_TYPE_RIGHT ? + table_ref_1 : table_ref_2), + eq_cond); nj_col_1->is_common= nj_col_2->is_common= TRUE; nj_col_1->is_coalesced= nj_col_2->is_coalesced= TRUE; @@ -3624,8 +3631,8 @@ err: for the join that is being processed. RETURN - TRUE - if error when some common column is ambiguous - FALSE - if OK + TRUE error: Some common column is ambiguous + FALSE OK */ static bool @@ -3640,16 +3647,15 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, bool is_created; Query_arena *arena, backup; bool result= TRUE; - + List *non_join_columns; DBUG_ENTER("store_natural_using_join_columns"); + DBUG_ASSERT(!natural_using_join->join_columns); + arena= thd->change_arena_if_needed(&backup); - List *non_join_columns; - if (!(non_join_columns= new List)) - goto err; - DBUG_ASSERT(!natural_using_join->join_columns); - if (!(natural_using_join->join_columns= new List)) + if (!(non_join_columns= new List) || + !(natural_using_join->join_columns= new List)) goto err; /* Append the columns of the first join operand. */ @@ -3657,6 +3663,10 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, { if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created))) goto err; + /* + The following assert checks that mark_common_columns() was run and + we created the list table_ref_1->join_columns. + */ DBUG_ASSERT(!is_created); if (nj_col_1->is_common) { @@ -3679,23 +3689,23 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, List_iterator_fast using_fields_it(*using_fields); while ((using_field_name= using_fields_it++)) { - const char *using_field_name_ptr= using_field_name->ptr(); + const char *using_field_name_ptr= using_field_name->c_ptr(); List_iterator_fast it(*(natural_using_join->join_columns)); Natural_join_column *common_field; - bool found= FALSE; - while ((common_field= it++)) + + for (;;) { + /* If reached the end of fields, and none was found, report error. */ + if (!(common_field= it++)) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr, + current_thd->where); + goto err; + } if (!my_strcasecmp(system_charset_info, common_field->name(), using_field_name_ptr)) - found= TRUE; - } - if (!found) - { - my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr, - current_thd->where); - delete non_join_columns; - goto err; + break; // Found match } } } @@ -3705,22 +3715,24 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, { if (!(nj_col_2= it_2.get_or_create_column_ref(thd, &is_created))) goto err; + /* + The following assert checks that mark_common_columns() was run and + we created the list table_ref_2->join_columns. + */ DBUG_ASSERT(!is_created); if (!nj_col_2->is_common) non_join_columns->push_back(nj_col_2); else + { /* Reset the common columns for the next call to mark_common_columns. */ nj_col_2->is_common= FALSE; - + } } if (non_join_columns->elements > 0) natural_using_join->join_columns->concat(non_join_columns); - else - delete non_join_columns; natural_using_join->is_join_columns_complete= TRUE; - result= FALSE; err: @@ -3729,6 +3741,7 @@ err: DBUG_RETURN(result); } + /* Precompute and store the row types of the top-most NATURAL/USING joins. @@ -3755,8 +3768,8 @@ err: from the right to the left in the FROM clause. RETURN - TRUE - if error - FALSE - if OK + TRUE Error + FALSE OK */ static bool @@ -3765,22 +3778,22 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, TABLE_LIST *right_neighbor) { DBUG_ENTER("store_top_level_join_columns"); + /* Call the procedure recursively for each nested table reference. */ if (table_ref->nested_join) { List_iterator_fast nested_it(table_ref->nested_join->join_list); - TABLE_LIST *cur_table_ref; TABLE_LIST *cur_left_neighbor= nested_it++; TABLE_LIST *cur_right_neighbor= NULL; + while (cur_left_neighbor) { - cur_table_ref= cur_left_neighbor; + TABLE_LIST *cur_table_ref= cur_left_neighbor; cur_left_neighbor= nested_it++; - if (cur_table_ref->nested_join && - store_top_level_join_columns(thd, cur_table_ref, - cur_left_neighbor, cur_right_neighbor)) - DBUG_RETURN(TRUE); - cur_right_neighbor= cur_table_ref; + if (cur_table_ref->nested_join && + store_top_level_join_columns(thd, cur_table_ref, + cur_left_neighbor, cur_right_neighbor)) + DBUG_RETURN(TRUE); cur_right_neighbor= cur_table_ref; } } @@ -3800,8 +3813,6 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, */ TABLE_LIST *table_ref_2= operand_it++; /* Second NATURAL join operand.*/ TABLE_LIST *table_ref_1= operand_it++; /* First NATURAL join operand. */ - TABLE_LIST *last_leaf_on_the_left= NULL; - TABLE_LIST *first_leaf_on_the_right= NULL; List *using_fields= table_ref->join_using_fields; uint found_using_fields; @@ -3838,11 +3849,13 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, /* Change this table reference to become a leaf for name resolution. */ if (left_neighbor) { + TABLE_LIST *last_leaf_on_the_left; last_leaf_on_the_left= left_neighbor->last_leaf_for_name_resolution(); last_leaf_on_the_left->next_name_resolution_table= table_ref; } if (right_neighbor) { + TABLE_LIST *first_leaf_on_the_right; first_leaf_on_the_right= right_neighbor->first_leaf_for_name_resolution(); table_ref->next_name_resolution_table= first_leaf_on_the_right; } @@ -3874,10 +3887,11 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, to the left in the FROM clause. RETURN - TRUE - if error - FALSE - if OK + TRUE Error + FALSE OK */ -static bool setup_natural_join_row_types(THD *thd, List *from_clause, +static bool setup_natural_join_row_types(THD *thd, + List *from_clause, Name_resolution_context *context) { thd->where= "from clause"; @@ -3891,11 +3905,12 @@ static bool setup_natural_join_row_types(THD *thd, List *from_clause List_iterator_fast table_ref_it(*from_clause); TABLE_LIST *table_ref; /* Current table reference. */ /* Table reference to the left of the current. */ - TABLE_LIST *left_neighbor= table_ref_it++; + TABLE_LIST *left_neighbor; /* Table reference to the right of the current. */ TABLE_LIST *right_neighbor= NULL; - while (left_neighbor) + /* Note that tables in the list are in reversed order */ + for (left_neighbor= table_ref_it++; left_neighbor ; ) { table_ref= left_neighbor; left_neighbor= table_ref_it++; @@ -3914,7 +3929,7 @@ static bool setup_natural_join_row_types(THD *thd, List *from_clause /* Store the top-most, left-most NATURAL/USING join, so that we start the search from that one instead of context->table_list. At this point - right_neigbor points to the left-most top-level table reference in the + right_neighbor points to the left-most top-level table reference in the FROM clause. */ DBUG_ASSERT(right_neighbor); @@ -4249,8 +4264,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, for all columns 1 If any privilege is ok RETURN - 0 ok - 'it' is updated to point at last inserted + 0 ok 'it' is updated to point at last inserted 1 error. Error message is generated but not sent to client */ @@ -4263,8 +4277,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, bool found; char name_buff[NAME_LEN+1]; DBUG_ENTER("insert_fields"); - DBUG_PRINT("arena", ("insert_fields: current arena: 0x%lx", - (ulong)thd->current_arena)); + DBUG_PRINT("arena", ("current arena: 0x%lx", (ulong)thd->current_arena)); if (db_name && lower_case_table_names) { @@ -4297,8 +4310,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, */ if (!tables->is_natural_join) { - if (table_name && my_strcasecmp(table_alias_charset, table_name, tables->alias) - || + if (table_name && my_strcasecmp(table_alias_charset, table_name, + tables->alias) || (db_name && strcmp(tables->db,db_name))) continue; } @@ -4312,7 +4325,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, { field_iterator.set(tables); if (check_grant_all_columns(thd, SELECT_ACL, field_iterator.grant(), - field_iterator.db_name(), field_iterator.table_name(), + field_iterator.db_name(), + field_iterator.table_name(), &field_iterator)) DBUG_RETURN(TRUE); } @@ -4336,21 +4350,19 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, for (; !field_iterator.end_of_fields(); field_iterator.next()) { - Item *not_used_item; - uint not_used_field_index= NO_CACHED_FIELD_INDEX; - const char *field_name= field_iterator.name(); Item *item; - /* If this is a column of a NATURAL/USING join, and the star was qualified - with a table (and database) name, check if the column is not a coalesced - one, and if not, that is belongs to the same table. + /* + If this is a column of a NATURAL/USING join, and the star was + qualified with a table (and database) name, check if the + column is not a coalesced one, and if not, that is belongs to + the same table. */ if (tables->is_natural_join && table_name) { - if (field_iterator.is_coalesced() - || - my_strcasecmp(table_alias_charset, table_name, field_iterator.table_name()) - || + if (field_iterator.is_coalesced() || + my_strcasecmp(table_alias_charset, table_name, + field_iterator.table_name()) || (db_name && strcmp(db_name, field_iterator.db_name()))) continue; } @@ -4360,8 +4372,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (!found) { - it->replace(item); /* Replace '*' with the first found item. */ found= TRUE; + it->replace(item); /* Replace '*' with the first found item. */ } else it->after(item); /* Add 'item' to the SELECT list. */ @@ -4371,8 +4383,9 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, Set privilege information for the fields of newly created views. We have that (any_priviliges == TRUE) if and only if we are creating a view. In the time of view creation we can't use the MERGE algorithm, - therefore if 'tables' is itself a view, it is represented by a temporary - table. Thus in this case we can be sure that 'item' is an Item_field. + therefore if 'tables' is itself a view, it is represented by a + temporary table. Thus in this case we can be sure that 'item' is an + Item_field. */ if (any_privileges) { @@ -4381,6 +4394,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *fld= (Item_field*) item; const char *table_name= field_iterator.table_name(); + if (!tables->schema_table && !(fld->have_privileges= (get_column_grant(thd, field_iterator.grant(), @@ -4414,11 +4428,12 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, bool is_created; TABLE *field_table; /* - In this case we are shure that the column ref will not be created + In this case we are sure that the column ref will not be created because it was already created and stored with the natural join. - */ + */ Natural_join_column *nj_col; - if (!(nj_col= field_iterator.get_or_create_column_ref(thd, &is_created))) + if (!(nj_col= field_iterator.get_or_create_column_ref(thd, + &is_created))) DBUG_RETURN(TRUE); DBUG_ASSERT(nj_col->table_field && !is_created); field_table= nj_col->table_ref->table; @@ -4450,9 +4465,9 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, DBUG_RETURN(FALSE); /* - TODO: in the case when we skipped all columns because there was a qualified - '*', and all columns were coalesced, we have to give a more meaningful message - than ER_BAD_TABLE_ERROR. + TODO: in the case when we skipped all columns because there was a + qualified '*', and all columns were coalesced, we have to give a more + meaningful message than ER_BAD_TABLE_ERROR. */ if (!table_name) my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0)); From 0671228b05ac5169b591c898f39a8077ae4688b4 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Wed, 17 Aug 2005 14:20:01 +0300 Subject: [PATCH 133/230] Fixed code formatting. --- sql/sql_base.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bb3209d56c5..4d4f9ae48da 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3793,7 +3793,8 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (cur_table_ref->nested_join && store_top_level_join_columns(thd, cur_table_ref, cur_left_neighbor, cur_right_neighbor)) - DBUG_RETURN(TRUE); cur_right_neighbor= cur_table_ref; + DBUG_RETURN(TRUE); + cur_right_neighbor= cur_table_ref; } } From e1351afccace7a5b76d4f041fb61763f67796697 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 17 Aug 2005 14:40:23 +0200 Subject: [PATCH 134/230] mysql-test-run.pl, mtr_misc.pl: Bug#12615: Host name might not resolve, use short host name --- mysql-test/lib/mtr_misc.pl | 9 +++++++++ mysql-test/mysql-test-run.pl | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl index c1aab340a16..9a12d842998 100644 --- a/mysql-test/lib/mtr_misc.pl +++ b/mysql-test/lib/mtr_misc.pl @@ -7,6 +7,7 @@ use strict; sub mtr_full_hostname (); +sub mtr_short_hostname (); sub mtr_init_args ($); sub mtr_add_arg ($$); sub mtr_path_exists(@); @@ -21,6 +22,7 @@ sub mtr_exe_exists(@); # We want the fully qualified host name and hostname() may have returned # only the short name. So we use the resolver to find out. +# Note that this might fail on some platforms sub mtr_full_hostname () { @@ -35,6 +37,13 @@ sub mtr_full_hostname () { return $hostname; } +sub mtr_short_hostname () { + + my $hostname= hostname(); + $hostname =~ s/\..+$//; + return $hostname; +} + # FIXME move to own lib sub mtr_init_args ($) { diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index e976242e726..f3e42ecf755 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -414,7 +414,7 @@ sub initial_setup () { $opt_source_dist= 1; } - $glob_hostname= mtr_full_hostname(); + $glob_hostname= mtr_short_hostname(); # 'basedir' is always parent of "mysql-test" directory $glob_mysql_test_dir= cwd(); From 09a3d58987d51d88f248c0f7b446ba8c461d783f Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Wed, 17 Aug 2005 15:03:29 +0200 Subject: [PATCH 135/230] Increase the version number to 4.1.15 (as 4.1.14 has been cloned off). --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index b270e5b0013..9e370dfa680 100644 --- a/configure.in +++ b/configure.in @@ -5,7 +5,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 4.1.14) +AM_INIT_AUTOMAKE(mysql, 4.1.15) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -16,7 +16,7 @@ SHARED_LIB_VERSION=14:0:0 # ndb version NDB_VERSION_MAJOR=4 NDB_VERSION_MINOR=1 -NDB_VERSION_BUILD=14 +NDB_VERSION_BUILD=15 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From ecf4068fff22203cf82932569bcd7298ac9a53c3 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Wed, 17 Aug 2005 15:11:29 +0200 Subject: [PATCH 136/230] No C++ style comments in C source! --- mysys/charset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/charset.c b/mysys/charset.c index df3f1cfa279..5aaac7a178f 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -679,5 +679,5 @@ char *bare_str_to_hex(char *to, const char *from, uint len) p[1]= _dig_vec_upper[tmp & 15]; } *p= 0; - return p; // pointer to end 0 of 'to' + return p; /* pointer to end 0 of 'to' */ } From a55786ca70db8cea04d661b1185bd4879ab8daf7 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Wed, 17 Aug 2005 17:19:31 +0300 Subject: [PATCH 137/230] WL#2486 - natural and using join according to SQL:2003 - fixed a problem with RIGHT JOIN ON and enabled corresponding tests in select.test - fixed a memory leak --- mysql-test/r/select.result | 17 +++++++++++++++++ mysql-test/t/select.test | 6 ++---- sql/sql_base.cc | 27 +++++++++++++++++++++++---- sql/table.h | 2 +- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 580ccc44a7c..1b35df534a0 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2218,6 +2218,23 @@ a 1 2 3 +select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; +a a +NULL 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +a a +2 1 +3 1 +2 2 +3 2 +2 3 +3 3 select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a ); a 1 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index e0c4d66633b..390c4372f16 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1850,10 +1850,8 @@ select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a ); select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a)); # right join on -# TODO: WL#2486 - there is a problem in the order of tables in RIGHT JOIN -# check how we set next_name_resolution_table -# select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; -# select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; +select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; # right [outer] joing using select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a ); select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a ); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4d4f9ae48da..98ce12eb7de 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3790,10 +3790,29 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, { TABLE_LIST *cur_table_ref= cur_left_neighbor; cur_left_neighbor= nested_it++; - if (cur_table_ref->nested_join && - store_top_level_join_columns(thd, cur_table_ref, - cur_left_neighbor, cur_right_neighbor)) - DBUG_RETURN(TRUE); + /* + The order of RIGHT JOIN operands is reversed in 'join list' to + transform it into a LEFT JOIN. However, in this procedure we need + the join operands in their lexical order, so below we reverse the + join operands. Notice that this happens only in the first loop, and + not in the second one, as in the second loop cur_left_neighbor == NULL. + This is the correct behavior, because the second loop + sets cur_table_ref reference correctly after the join operands are + swapped in the first loop. + */ + if (cur_left_neighbor && + cur_table_ref->outer_join & JOIN_TYPE_RIGHT) + { + DBUG_ASSERT(cur_table_ref); + /* This can happen only for JOIN ... ON. */ + DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2); + swap_variables(TABLE_LIST*, cur_left_neighbor, cur_table_ref); + } + + if (cur_table_ref->nested_join && + store_top_level_join_columns(thd, cur_table_ref, + cur_left_neighbor, cur_right_neighbor)) + DBUG_RETURN(TRUE); cur_right_neighbor= cur_table_ref; } } diff --git a/sql/table.h b/sql/table.h index bb9de5dc86d..3d4f02e389b 100644 --- a/sql/table.h +++ b/sql/table.h @@ -374,7 +374,7 @@ struct Field_translator Field (for tables), or a Field_translator (for views). */ -class Natural_join_column +class Natural_join_column: public Sql_alloc { public: Field_translator *view_field; /* Column reference of merge view. */ From de8058630db5f8abedebe99695c673912eb47390 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 17 Aug 2005 18:15:50 +0300 Subject: [PATCH 138/230] univ.i: Do not use __builtin_expect etc. with the Intel ICC compiler, as the compiler crashed in btr0cur.c; the patch was submitted by Axel Schwenke (Bug #11510) --- innobase/include/univ.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 132ac9e18c5..6849dcd9c51 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -244,7 +244,7 @@ contains the sum of the following flag and the locally stored len. */ #define UNIV_EXTERN_STORAGE_FIELD (UNIV_SQL_NULL - UNIV_PAGE_SIZE) /* Some macros to improve branch prediction and reduce cache misses */ -#if defined(__GNUC__) && (__GNUC__ > 2) +#if defined(__GNUC__) && (__GNUC__ > 2) && ! defined(__INTEL_COMPILER) /* Tell the compiler that 'expr' probably evaluates to 'constant'. */ # define UNIV_EXPECT(expr,constant) __builtin_expect(expr, constant) /* Tell the compiler that a pointer is likely to be NULL */ From 4ff51a57435520fe932b9498ecc68cb9b5382650 Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Wed, 17 Aug 2005 17:51:10 +0200 Subject: [PATCH 139/230] fix for bug #12591 (SHOW TABLES FROM dbname produces wrong error message) --- mysql-test/r/show_check.result | 2 ++ mysql-test/t/show_check.test | 5 +++++ sql/sql_show.cc | 8 +++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 94d1ac7ac11..c143c7f0f29 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -555,3 +555,5 @@ Database Table In_use Name_locked DROP TABLE txt1; DROP TABLE tyt2; DROP TABLE urkunde; +SHOW TABLES FROM non_existing_database; +ERROR 42000: Unknown database 'non_existing_database' diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 41b8a9e401c..b9fc991dc80 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -405,3 +405,8 @@ SHOW OPEN TABLES; DROP TABLE txt1; DROP TABLE tyt2; DROP TABLE urkunde; +# +# BUG #12591 (SHOW TABLES FROM dbname produces wrong error message) +# +--error 1049 +SHOW TABLES FROM non_existing_database; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e1d5f80ebc2..1c6d86793e6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -264,8 +264,14 @@ mysql_find_files(THD *thd,List *files, const char *db,const char *path, bzero((char*) &table_list,sizeof(table_list)); - if (!(dirp = my_dir(path,MYF(MY_WME | (dir ? MY_WANT_STAT : 0))))) + if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0)))) + { + if (my_errno == ENOENT) + my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db); + else + my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno); DBUG_RETURN(-1); + } for (i=0 ; i < (uint) dirp->number_off_files ; i++) { From 6d8bd17c3a8d11ad5404c4d80723fc0cb8a8496b Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 17 Aug 2005 23:53:12 +0400 Subject: [PATCH 140/230] Fix bug #11718 query with function, join and order by returns wrong type. create_tmp_field_from_item() was creating tmp field without regard to original field type of Item. This results in wrong type being reported to client. To create_tmp_field_from_item() added special handling for Items with DATE/TIME field types to preserve their type. --- sql/sql_select.cc | 10 +++++++++- tests/mysql_client_test.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9984cb4138f..73cfe153b9b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4899,7 +4899,15 @@ static Field* create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, item->name, table, item->unsigned_flag); break; case STRING_RESULT: - if (item->max_length > 255) + enum enum_field_types type; + /* + DATE/TIME fields have STRING_RESULT result type. To preserve + type they needed to be handled separately. + */ + if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || + type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) + new_field= item->tmp_table_field_from_field_type(table); + else if (item->max_length > 255) { if (convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 37d6d951f96..64c5e7edaf9 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11796,6 +11796,40 @@ static void test_bug12001() DIE_UNLESS(res==1); } +/* + Bug#11718: query with function, join and order by returns wrong type +*/ + +static void test_bug11718() +{ + MYSQL_RES *res; + int rc; + const char *query= "select str_to_date(concat(f3),'%Y%m%d') from t1,t2 " + "where f1=f2 order by f1"; + + myheader("test_bug11718"); + + rc= mysql_query(mysql, "drop table if exists t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (f1 int)"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (f2 int, f3 numeric(8))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1,20050101), (2,20050202)"); + myquery(rc); + rc= mysql_query(mysql, query); + myquery(rc); + res = mysql_store_result(mysql); + + if (!opt_silent) + printf("return type: %s", (res->fields[0].type == MYSQL_TYPE_DATE)?"DATE": + "not DATE"); + DIE_UNLESS(res->fields[0].type == MYSQL_TYPE_DATE); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} /* Read and parse arguments and MySQL options from my.cnf */ @@ -12013,6 +12047,7 @@ static struct my_tests_st my_tests[]= { { "test_bug9735", test_bug9735 }, { "test_bug11183", test_bug11183 }, { "test_bug12001", test_bug12001 }, + { "test_bug11718", test_bug11718 }, { 0, 0 } }; From 1dddccb8e9f38a498d5ed586aab49d5cba952f16 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 17 Aug 2005 23:47:03 +0200 Subject: [PATCH 141/230] mtr_process.pl: Longer shutdown timeout, slave may be in reconnect HUP seem to disturb exit(), added sleep to make sure output is flushed --- mysql-test/lib/mtr_process.pl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 1f18968031c..fb37296971e 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -331,7 +331,7 @@ sub mtr_kill_leftovers () { }); } - mtr_mysqladmin_shutdown(\@args); + mtr_mysqladmin_shutdown(\@args, 20); # We now have tried to terminate nice. We have waited for the listen # port to be free, but can't really tell if the mysqld process died @@ -441,7 +441,8 @@ sub mtr_stop_mysqld_servers ($) { # First try nice normal shutdown using 'mysqladmin' # ---------------------------------------------------------------------- - mtr_mysqladmin_shutdown($spec); + # Shutdown time must be high as slave may be in reconnect + mtr_mysqladmin_shutdown($spec, 70); # ---------------------------------------------------------------------- # We loop with waitpid() nonblocking to see how many of the ones we @@ -591,8 +592,9 @@ sub mtr_stop_mysqld_servers ($) { # ############################################################################## -sub mtr_mysqladmin_shutdown () { +sub mtr_mysqladmin_shutdown { my $spec= shift; + my $adm_shutdown_tmo= shift; my %mysql_admin_pids; my @to_kill_specs; @@ -631,7 +633,7 @@ sub mtr_mysqladmin_shutdown () { mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket } mtr_add_arg($args, "--connect_timeout=5"); - mtr_add_arg($args, "--shutdown_timeout=20"); + mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo"); mtr_add_arg($args, "shutdown"); # We don't wait for termination of mysqladmin my $pid= mtr_spawn($::exe_mysqladmin, $args, @@ -808,11 +810,15 @@ sub sleep_until_file_created ($$$) { # FIXME something is wrong, we sometimes terminate with "Hangup" written # to tty, and no STDERR output telling us why. +# FIXME for some readon, setting HUP to 'IGNORE' will cause exit() to +# write out "Hangup", and maybe loose some output. We insert a sleep... + sub mtr_exit ($) { my $code= shift; # cluck("Called mtr_exit()"); local $SIG{HUP} = 'IGNORE'; kill('HUP', -$$); + sleep 2; exit($code); } From adb94df2962a05d0b04dc5a2919244e89b4195f8 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Thu, 18 Aug 2005 00:07:17 +0200 Subject: [PATCH 142/230] mtr_process.pl: Bug#11792: Create a shell like 'mysqltest' exit status --- mysql-test/lib/mtr_process.pl | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index fb37296971e..ec12bc3907c 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -185,10 +185,6 @@ sub spawn_parent_impl { if ( $mode eq 'run' or $mode eq 'test' ) { - my $exit_value= -1; -# my $signal_num= 0; -# my $dumped_core= 0; - if ( $mode eq 'run' ) { # Simple run of command, we wait for it to return @@ -199,12 +195,7 @@ sub spawn_parent_impl { mtr_error("$path ($pid) got lost somehow"); } - $exit_value= $?; -# $exit_value= $? >> 8; -# $signal_num= $? & 127; -# $dumped_core= $? & 128; - - return $exit_value; + return mtr_process_exit_status($?); } else { @@ -218,6 +209,7 @@ sub spawn_parent_impl { # FIXME is this as it should be? Can't mysqld terminate # normally from running a test case? + my $exit_value= -1; my $ret_pid; # What waitpid() returns while ( ($ret_pid= waitpid(-1,0)) != -1 ) @@ -230,10 +222,7 @@ sub spawn_parent_impl { if ( $ret_pid == $pid ) { # We got termination of mysqltest, we are done - $exit_value= $?; -# $exit_value= $? >> 8; -# $signal_num= $? & 127; -# $dumped_core= $? & 128; + $exit_value= mtr_process_exit_status($?); last; } @@ -292,6 +281,23 @@ sub spawn_parent_impl { } +# ---------------------------------------------------------------------- +# We try to emulate how an Unix shell calculates the exit code +# ---------------------------------------------------------------------- + +sub mtr_process_exit_status { + my $raw_status= shift; + + if ( $raw_status & 127 ) + { + return ($raw_status & 127) + 128; # Signal num + 128 + } + else + { + return $raw_status >> 8; # Exit code + } +} + ############################################################################## # From 1476a524332334e5634a1af4aaabc67a4231aecf Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Thu, 18 Aug 2005 00:16:44 +0200 Subject: [PATCH 143/230] mtr_timer.pl, mysql-test-run.pl, mtr_report.pl, mtr_process.pl: Added suite and test case timeout mtr_timer.pl: new file --- mysql-test/lib/mtr_process.pl | 21 +++++- mysql-test/lib/mtr_report.pl | 9 ++- mysql-test/lib/mtr_timer.pl | 127 ++++++++++++++++++++++++++++++++++ mysql-test/mysql-test-run.pl | 28 +++++++- 4 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 mysql-test/lib/mtr_timer.pl diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index ec12bc3907c..c9ae92305c2 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -210,6 +210,7 @@ sub spawn_parent_impl { # normally from running a test case? my $exit_value= -1; + my $saved_exit_value; my $ret_pid; # What waitpid() returns while ( ($ret_pid= waitpid(-1,0)) != -1 ) @@ -219,6 +220,24 @@ sub spawn_parent_impl { # but not $exit_value, this is flagged from # + my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid); + if ( $timer_name ) + { + if ( $timer_name eq "suite" ) + { + # We give up here + # FIXME we should only give up the suite, not all of the run? + print STDERR "\n"; + mtr_error("Test suite timeout"); + } + elsif ( $timer_name eq "testcase" ) + { + $saved_exit_value= 63; # Mark as timeout + kill(9, $pid); # Kill mysqltest + next; # Go on and catch the termination + } + } + if ( $ret_pid == $pid ) { # We got termination of mysqltest, we are done @@ -270,7 +289,7 @@ sub spawn_parent_impl { } } - return $exit_value; + return $saved_exit_value || $exit_value; } } else diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index b9dab6b8d32..5e1a8308505 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -109,7 +109,14 @@ sub mtr_report_test_failed ($) { my $tinfo= shift; $tinfo->{'result'}= 'MTR_RES_FAILED'; - print "[ fail ]\n"; + if ( $tinfo->{'timeout'} ) + { + print "[ fail ] timeout\n"; + } + else + { + print "[ fail ]\n"; + } # FIXME Instead of this test, and meaningless error message in 'else' # we should write out into $::path_timefile when the error occurs. diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl new file mode 100644 index 00000000000..aab57d1bc52 --- /dev/null +++ b/mysql-test/lib/mtr_timer.pl @@ -0,0 +1,127 @@ +# -*- cperl -*- + +# This is a library file used by the Perl version of mysql-test-run, +# and is part of the translation of the Bourne shell script with the +# same name. + +use Carp qw(cluck); +use Socket; +use Errno; +use strict; + +#use POSIX ":sys_wait_h"; +use POSIX 'WNOHANG'; + +sub mtr_init_timers (); +sub mtr_timer_start($$$); +sub mtr_timer_stop($$); +sub mtr_timer_waitpid($$$); + +############################################################################## +# +# Initiate a structure shared by all timers +# +############################################################################## + +sub mtr_init_timers () { + my $timers = { timers => {}, pids => {}}; + return $timers; +} + + +############################################################################## +# +# Start, stop and poll a timer +# +# As alarm() isn't portable to Windows, we use separate processes to +# implement timers. That is why there is a mtr_timer_waitpid(), as this +# is where we catch a timeout. +# +############################################################################## + +sub mtr_timer_start($$$) { + my ($timers,$name,$duration)= @_; + + if ( exists $timers->{'timers'}->{$name} ) + { + # We have an old running timer, kill it + mtr_timer_stop($timers,$name); + } + + FORK: + { + my $tpid= fork(); + + if ( ! defined $tpid ) + { + if ( $! == $!{EAGAIN} ) # See "perldoc Errno" + { + mtr_debug("Got EAGAIN from fork(), sleep 1 second and redo"); + sleep(1); + redo FORK; + } + else + { + mtr_error("can't fork"); + } + } + + if ( $tpid ) + { + # Parent, record the information + $timers->{'timers'}->{$name}->{'pid'}= $tpid; + $timers->{'timers'}->{$name}->{'duration'}= $duration; + $timers->{'pids'}->{$tpid}= $name; + } + else + { + # Child, redirect output and exec + # FIXME do we need to redirect streams? + $0= "mtr_timer(timers,$name,$duration)"; + sleep($duration); + exit(0); + } + } +} + + +sub mtr_timer_stop ($$) { + my ($timers,$name)= @_; + + if ( exists $timers->{'timers'}->{$name} ) + { + my $tpid= $timers->{'timers'}->{$name}->{'pid'}; + + # FIXME as Cygwin reuses pids fast, maybe check that is + # the expected process somehow?! + kill(9, $tpid); + + # As the timers are so simple programs, we trust them to terminate, + # and use blocking wait for it. We wait just to avoid a zombie. + waitpid($tpid,0); + + delete $timers->{'timers'}->{$name}; # Remove the timer information + delete $timers->{'pids'}->{$tpid}; # and PID reference + + return 1; + } + else + { + mtr_debug("Asked to stop timer \"$name\" not started"); + return 0; + } +} + + +sub mtr_timer_timeout ($$) { + my ($timers,$pid)= @_; + + return "" unless exists $timers->{'pids'}->{$pid}; + + # We got a timeout + my $name= $timers->{'pids'}->{$pid}; + mtr_timer_stop($timers, $timers->{'timers'}->{$name}); + return $name; +} + +1; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f3e42ecf755..456f481ce86 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -90,6 +90,7 @@ use strict; require "lib/mtr_cases.pl"; require "lib/mtr_process.pl"; +require "lib/mtr_timer.pl"; require "lib/mtr_io.pl"; require "lib/mtr_gcov.pl"; require "lib/mtr_gprof.pl"; @@ -137,6 +138,7 @@ our $glob_mysql_test_dir= undef; our $glob_mysql_bench_dir= undef; our $glob_hostname= undef; our $glob_scriptname= undef; +our $glob_timers= undef; our $glob_use_running_server= 0; our $glob_use_running_ndbcluster= 0; our $glob_use_embedded_server= 0; @@ -232,8 +234,10 @@ our $opt_skip_test; our $opt_sleep; our $opt_ps_protocol; -our $opt_sleep_time_after_restart= 1; +our $opt_sleep_time_after_restart= 1; our $opt_sleep_time_for_delete= 10; +our $opt_testcase_timeout= 5; # 5 min max +our $opt_suite_timeout= 120; # 2 hours max our $opt_socket; @@ -435,6 +439,8 @@ sub initial_setup () { $path_my_basedir= $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; + + $glob_timers= mtr_init_timers(); } @@ -530,6 +536,8 @@ sub command_line_setup () { 'vardir=s' => \$opt_vardir, 'verbose' => \$opt_verbose, 'wait-timeout=i' => \$opt_wait_timeout, + 'testcase-timeout=i' => \$opt_testcase_timeout, + 'suite-timeout=i' => \$opt_suite_timeout, 'warnings|log-warnings' => \$opt_warnings, 'with-openssl' => \$opt_with_openssl, @@ -1197,6 +1205,8 @@ sub run_suite () { mtr_report("Finding Tests in the '$suite' suite"); + mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout); + my $tests= collect_test_cases($suite); mtr_report("Starting Tests in the '$suite' suite"); @@ -1205,7 +1215,9 @@ sub run_suite () { foreach my $tinfo ( @$tests ) { + mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout); run_testcase($tinfo); + mtr_timer_stop($glob_timers,"testcase"); } mtr_print_line(); @@ -1226,6 +1238,8 @@ sub run_suite () { } mtr_report_stats($tests); + + mtr_timer_stop($glob_timers,"suite"); } @@ -1523,6 +1537,11 @@ sub run_testcase ($) { # Testcase itself tell us to skip this one mtr_report_test_skipped($tinfo); } + elsif ( $res == 63 ) + { + $tinfo->{'timeout'}= 1; # Mark as timeout + report_failure_and_restart($tinfo); + } else { # Test case failed, if in control mysqltest returns 1 @@ -1657,8 +1676,6 @@ sub mysqld_arguments ($$$$$) { my $extra_opt= shift; my $slave_master_info= shift; -# print STDERR Dumper($extra_opt); - my $sidx= ""; # Index as string, 0 is empty string if ( $idx > 0 ) { @@ -2262,6 +2279,10 @@ Misc options help Get this help text unified-diff | udiff When presenting differences, use unified diff + testcase-timeout=MINUTES Max test case run time (default 5) + suite-timeout=MINUTES Max test suite run time (default 120) + + Options not yet described, or that I want to look into more big-test @@ -2281,4 +2302,5 @@ Options not yet described, or that I want to look into more HERE mtr_exit(1); + } From 3eaa9535297fb3f88037c9d27459dea0f96a55f5 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Thu, 18 Aug 2005 03:12:42 +0300 Subject: [PATCH 144/230] Cleanups and optimization during review of new code --- mysql-test/t/kill.test | 2 +- sql/sql_help.cc | 40 +++++------ sql/sql_insert.cc | 6 +- sql/sql_lex.cc | 4 +- sql/sql_parse.cc | 61 +++++++++------- sql/sql_view.cc | 52 +++++++------- sql/sql_yacc.yy | 6 +- sql/table.cc | 160 +++++++++++++++++++---------------------- 8 files changed, 165 insertions(+), 166 deletions(-) diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 09ad3f59c10..3503d5fde1d 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -15,6 +15,7 @@ connection con1; drop table if exists t1; --enable_warnings +--disable_reconnect create table t1 (kill_id int); insert into t1 values(connection_id()); @@ -25,7 +26,6 @@ kill @id; connection con1; ---disable_reconnect # this statement should fail --error 2006,2013 select 1; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 0a89c3a29d7..799758f7d1e 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -623,38 +623,37 @@ bool mysqld_help(THD *thd, const char *mask) Protocol *protocol= thd->protocol; SQL_SELECT *select; st_find_field used_fields[array_elements(init_used_fields)]; - DBUG_ENTER("mysqld_help"); - TABLE_LIST *leaves= 0; TABLE_LIST tables[4]; - bzero((gptr)tables,sizeof(tables)); - tables[0].alias= tables[0].table_name= (char*) "help_topic"; - tables[0].lock_type= TL_READ; - tables[0].next_global= tables[0].next_local= &tables[1]; - tables[0].next_name_resolution_table= tables[0].next_local; - tables[1].alias= tables[1].table_name= (char*) "help_category"; - tables[1].lock_type= TL_READ; - tables[1].next_global= tables[1].next_local= &tables[2]; - tables[1].next_name_resolution_table= tables[1].next_local; - tables[2].alias= tables[2].table_name= (char*) "help_relation"; - tables[2].lock_type= TL_READ; - tables[2].next_global= tables[2].next_local= &tables[3]; - tables[2].next_name_resolution_table= tables[2].next_local; - tables[3].alias= tables[3].table_name= (char*) "help_keyword"; - tables[3].lock_type= TL_READ; - tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql"; - List topics_list, categories_list, subcategories_list; String name, description, example; int count_topics, count_categories, error; uint mlen= strlen(mask); + size_t i; MEM_ROOT *mem_root= thd->mem_root; + DBUG_ENTER("mysqld_help"); + + bzero((gptr)tables,sizeof(tables)); + tables[0].alias= tables[0].table_name= (char*) "help_topic"; + tables[0].lock_type= TL_READ; + tables[0].next_global= tables[0].next_local= + tables[0].next_name_resolution_table= &tables[1]; + tables[1].alias= tables[1].table_name= (char*) "help_category"; + tables[1].lock_type= TL_READ; + tables[1].next_global= tables[1].next_local= + tables[1].next_name_resolution_table= &tables[2]; + tables[2].alias= tables[2].table_name= (char*) "help_relation"; + tables[2].lock_type= TL_READ; + tables[2].next_global= tables[2].next_local= + tables[2].next_name_resolution_table= &tables[3]; + tables[3].alias= tables[3].table_name= (char*) "help_keyword"; + tables[3].lock_type= TL_READ; + tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql"; if (open_and_lock_tables(thd, tables)) goto error; /* Init tables and fields to be usable from items - tables do not contain VIEWs => we can pass 0 as conds */ setup_tables(thd, &thd->lex->select_lex.context, @@ -663,7 +662,6 @@ bool mysqld_help(THD *thd, const char *mask) memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) goto error; - size_t i; for (i=0; ifile->init_table_handle_for_HANDLER(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 62b96d567c3..93c9991418d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -891,8 +891,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (select_lex->group_list.elements == 0) { context->table_list->next_local= save_next_local; + /* first_name_resolution_table was set by resolve_in_table_list_only() */ context->first_name_resolution_table-> - next_name_resolution_table= save_next_local; + next_name_resolution_table= save_next_local; } if (!res) res= setup_fields(thd, 0, update_values, 1, 0, 0); @@ -2199,8 +2200,9 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) if (lex->select_lex.group_list.elements == 0) { context->table_list->next_local= save_next_local; + /* first_name_resolution_table was set by resolve_in_table_list_only() */ context->first_name_resolution_table-> - next_name_resolution_table= save_next_local; + next_name_resolution_table= save_next_local; } res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 86e677cc8dc..7fcc16c681e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1867,8 +1867,8 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) */ if ((*link_to_local= test(select_lex.table_list.first))) { - select_lex.context.table_list= first->next_local; - select_lex.context.first_name_resolution_table= first->next_local; + select_lex.context.table_list= + select_lex.context.first_name_resolution_table= first->next_local; select_lex.table_list.first= (byte*) (first->next_local); select_lex.table_list.elements--; //safety first->next_local= 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index eb54c44fa47..ed20d98c3a8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3258,8 +3258,8 @@ end_with_restore_list: /* Skip first table, which is the table we are inserting in */ TABLE_LIST *second_table= first_table->next_local; select_lex->table_list.first= (byte*) second_table; - select_lex->context.table_list= second_table; - select_lex->context.first_name_resolution_table= second_table; + select_lex->context.table_list= + select_lex->context.first_name_resolution_table= second_table; res= mysql_insert_select_prepare(thd); if (!res && (result= new select_insert(first_table, first_table->table, &lex->field_list, @@ -3274,8 +3274,8 @@ end_with_restore_list: which in turn resets context.table_list and context.first_name_resolution_table. */ - select_lex->context.table_list= first_table->next_local; - select_lex->context.first_name_resolution_table= first_table->next_local; + select_lex->context.table_list= + select_lex->context.first_name_resolution_table= second_table; res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); delete result; } @@ -6016,6 +6016,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, char *alias_str; LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); + LINT_INIT(previous_table_ref); if (!table) DBUG_RETURN(0); // End of memory @@ -6111,9 +6112,23 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, /* Store the table reference preceding the current one. */ if (table_list.elements > 0) { - previous_table_ref= (TABLE_LIST*) table_list.next; + /* + table_list.next points to the last inserted TABLE_LIST->next_local' + element + */ + previous_table_ref= (TABLE_LIST*) (table_list.next - + offsetof(TABLE_LIST, next_local)); DBUG_ASSERT(previous_table_ref); + /* + Set next_name_resolution_table of the previous table reference to point + to the current table reference. In effect the list + TABLE_LIST::next_name_resolution_table coincides with + TABLE_LIST::next_local. Later this may be changed in + store_top_level_join_columns() for NATURAL/USING joins. + */ + previous_table_ref->next_name_resolution_table= ptr; } + /* Link the current table reference in a local list (list for current select). Notice that as a side effect here we set the next_local field of the @@ -6121,15 +6136,6 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, list 'table_list'. */ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local); - /* - Set next_name_resolution_table of the previous table reference to point to - the current table reference. In effect the list - TABLE_LIST::next_name_resolution_table coincides with - TABLE_LIST::next_local. Later this may be changed in - store_top_level_join_columns() for NATURAL/USING joins. - */ - if (table_list.elements > 1) - previous_table_ref->next_name_resolution_table= ptr; ptr->next_name_resolution_table= NULL; /* Link table in global list (all used tables) */ lex->add_to_query_tables(ptr); @@ -6164,10 +6170,12 @@ bool st_select_lex::init_nested_join(THD *thd) NESTED_JOIN *nested_join; DBUG_ENTER("init_nested_join"); - if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) || - !(nested_join= ptr->nested_join= - (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN)))) + if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ + sizeof(NESTED_JOIN)))) DBUG_RETURN(1); + nested_join= ptr->nested_join= + ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); + join_list->push_front(ptr); ptr->embedding= embedding; ptr->join_list= join_list; @@ -6235,25 +6243,30 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd) The function nest last join operation as if it was enclosed in braces. RETURN VALUE - Pointer to TABLE_LIST element created for the new nested join, if success - 0, otherwise + 0 Error + # Pointer to TABLE_LIST element created for the new nested join + */ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) { TABLE_LIST *ptr; NESTED_JOIN *nested_join; + List *embedded_list; DBUG_ENTER("nest_last_join"); - if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) || - !(nested_join= ptr->nested_join= - (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN)))) + if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ + sizeof(NESTED_JOIN)))) DBUG_RETURN(0); + nested_join= ptr->nested_join= + ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); + ptr->embedding= embedding; ptr->join_list= join_list; - List *embedded_list= &nested_join->join_list; + embedded_list= &nested_join->join_list; embedded_list->empty(); - for (int i=0; i < 2; i++) + + for (uint i=0; i < 2; i++) { TABLE_LIST *table= join_list->pop(); table->join_list= embedded_list; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c3222f951bb..577d1d32fcc 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -120,42 +120,38 @@ static void make_unique_view_field_name(Item *target, bool check_duplicate_names(List &item_list, bool gen_unique_view_name) { + Item *item; + List_iterator_fast it(item_list); + List_iterator_fast itc(item_list); DBUG_ENTER("check_duplicate_names"); - /* Test absence of duplicates names */ + + while ((item= it++)) { - Item *item; - List_iterator_fast it(item_list); - List_iterator_fast itc(item_list); - while ((item= it++)) + Item *check; + /* treat underlying fields like set by user names */ + if (item->real_item()->type() == Item::FIELD_ITEM) + item->is_autogenerated_name= FALSE; + itc.rewind(); + while ((check= itc++) && check != item) { - Item *check; - /* treat underlying fields like set by user names */ - if (item->real_item()->type() == Item::FIELD_ITEM) - item->is_autogenerated_name= FALSE; - itc.rewind(); - while ((check= itc++) && check != item) + if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) { - if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) - { - if (!gen_unique_view_name) - { - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); - DBUG_RETURN(TRUE); - } - else if (item->is_autogenerated_name) - make_unique_view_field_name(item, item_list, item); - else if (check->is_autogenerated_name) - make_unique_view_field_name(check, item_list, item); - else - { - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); - DBUG_RETURN(TRUE); - } - } + if (!gen_unique_view_name) + goto err; + if (item->is_autogenerated_name) + make_unique_view_field_name(item, item_list, item); + else if (check->is_autogenerated_name) + make_unique_view_field_name(check, item_list, item); + else + goto err; } } } DBUG_RETURN(FALSE); + +err: + my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + DBUG_RETURN(TRUE); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5085ac6698e..7c040ff1def 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8681,8 +8681,10 @@ union_list: } select_init { - /* Remove from the name resolution context stack the context of the - last select in the union. */ + /* + Remove from the name resolution context stack the context of the + last select in the union. + */ Lex->pop_context(); } ; diff --git a/sql/table.cc b/sql/table.cc index 0b557b097cf..516116a56c3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2186,21 +2186,24 @@ bool st_table_list::is_leaf_for_name_resolution() reverse order. RETURN - - If 'this' is a nested table reference - the left-most child of + If 'this' is a nested table reference - the left-most child of the tree rooted in 'this', - - else - 'this' + else return 'this' */ TABLE_LIST *st_table_list::first_leaf_for_name_resolution() { - TABLE_LIST *cur_table_ref= this; - TABLE_LIST *next; - NESTED_JOIN *cur_nested_join= nested_join; + TABLE_LIST *cur_table_ref; + NESTED_JOIN *cur_nested_join; + LINT_INIT(cur_table_ref); - if (this->is_leaf_for_name_resolution()) + if (is_leaf_for_name_resolution()) return this; + DBUG_ASSERT(nested_join); - while (cur_nested_join) + for (cur_nested_join= nested_join; + cur_nested_join; + cur_nested_join= cur_table_ref->nested_join) { List_iterator_fast it(cur_nested_join->join_list); cur_table_ref= it++; @@ -2210,12 +2213,12 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution() */ if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT)) { + TABLE_LIST *next; while ((next= it++)) cur_table_ref= next; } if (cur_table_ref->is_leaf_for_name_resolution()) break; - cur_nested_join= cur_table_ref->nested_join; } return cur_table_ref; } @@ -2247,13 +2250,16 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution() TABLE_LIST *st_table_list::last_leaf_for_name_resolution() { TABLE_LIST *cur_table_ref= this; - TABLE_LIST *next; - NESTED_JOIN *cur_nested_join= nested_join; + NESTED_JOIN *cur_nested_join; + LINT_INIT(cur_table_ref); - if (this->is_leaf_for_name_resolution()) + if (is_leaf_for_name_resolution()) return this; + DBUG_ASSERT(nested_join); - while (cur_nested_join) + for (cur_nested_join= nested_join; + cur_nested_join; + cur_nested_join= cur_table_ref->nested_join) { /* If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse @@ -2262,6 +2268,7 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution() if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT)) { List_iterator_fast it(cur_nested_join->join_list); + TABLE_LIST *next; cur_table_ref= it++; while ((next= it++)) cur_table_ref= next; @@ -2270,7 +2277,6 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution() cur_table_ref= cur_nested_join->join_list.head(); if (cur_table_ref->is_leaf_for_name_resolution()) break; - cur_nested_join= cur_table_ref->nested_join; } return cur_table_ref; } @@ -2306,11 +2312,8 @@ const char *Natural_join_column::name() DBUG_ASSERT(table_field == NULL); return view_field->name; } - else - { - DBUG_ASSERT(view_field == NULL); - return table_field->field_name; - } + + return table_field->field_name; } @@ -2319,13 +2322,10 @@ Item *Natural_join_column::create_item(THD *thd) if (view_field) { DBUG_ASSERT(table_field == NULL); - return create_view_field(thd, table_ref, &view_field->item, view_field->name); - } - else - { - DBUG_ASSERT(view_field == NULL); - return new Item_field(thd, &thd->lex->current_select->context, table_field); + return create_view_field(thd, table_ref, &view_field->item, + view_field->name); } + return new Item_field(thd, &thd->lex->current_select->context, table_field); } @@ -2336,31 +2336,29 @@ Field *Natural_join_column::field() DBUG_ASSERT(table_field == NULL); return NULL; } - else - { - DBUG_ASSERT(view_field == NULL); - return table_field; - } + return table_field; } const char *Natural_join_column::table_name() { return table_ref->alias; -/* - TODO: I think that it is sufficient to return just - table->alias, which is correctly set to either - the view name, the table name, or the alias to - the table reference (view or stored table). + /* + TODO: + I think that it is sufficient to return just + table->alias, which is correctly set to either + the view name, the table name, or the alias to + the table reference (view or stored table). + */ +#ifdef NOT_YET if (view_field) return table_ref->view_name.str; - else - { - DBUG_ASSERT(!strcmp(table_ref->table_name, - table_ref->table->s->table_name)); - return table_ref->table_name; - } -*/ + + DBUG_ASSERT(!strcmp(table_ref->table_name, + table_ref->table->s->table_name)); + return table_ref->table_name; +} +#endif } @@ -2368,12 +2366,10 @@ const char *Natural_join_column::db_name() { if (view_field) return table_ref->view_db.str; - else - { - DBUG_ASSERT(!strcmp(table_ref->db, - table_ref->table->s->db)); - return table_ref->db; - } + + DBUG_ASSERT(!strcmp(table_ref->db, + table_ref->table->s->db)); + return table_ref->db; } @@ -2381,8 +2377,7 @@ GRANT_INFO *Natural_join_column::grant() { if (view_field) return &(table_ref->grant); - else - return &(table_ref->table->grant); + return &(table_ref->table->grant); } @@ -2402,16 +2397,17 @@ GRANT_INFO *Natural_join_column::grant() it is a view or a stored table colum. RETURN - FALSE - if the column can be accessed - TRUE - if there are no access rights to all equivalent columns + FALSE The column can be accessed + TRUE There are no access rights to all equivalent columns */ bool Natural_join_column::check_grants(THD *thd, const char *name, uint length) { - GRANT_INFO *grant= NULL; /* If NULL do not check access rights. */ + GRANT_INFO *grant; const char *db_name; const char *table_name; + if (view_field) { DBUG_ASSERT(table_field == NULL); @@ -2544,7 +2540,6 @@ void Field_iterator_table_ref::set_field_iterator() (!table_ref->field_translation && table_ref->join_columns->elements == table_ref->table->s->fields))); - natural_join_it.set(table_ref); field_it= &natural_join_it; DBUG_PRINT("info",("field_it for '%s' is Field_iterator_natural_join", table_ref->table_name)); @@ -2554,7 +2549,6 @@ void Field_iterator_table_ref::set_field_iterator() { DBUG_ASSERT(table_ref->view && table_ref->effective_algorithm == VIEW_ALGORITHM_MERGE); - view_field_it.set(table_ref); field_it= &view_field_it; DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_view", table_ref->table_name)); @@ -2563,12 +2557,11 @@ void Field_iterator_table_ref::set_field_iterator() else { DBUG_ASSERT(table_ref->table || table_ref->view); - table_field_it.set(table_ref); field_it= &table_field_it; DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_table", table_ref->table_name)); - } + field_it->set(table_ref); DBUG_VOID_RETURN; } @@ -2607,12 +2600,10 @@ const char *Field_iterator_table_ref::table_name() return table_ref->view_name.str; else if (table_ref->is_natural_join) return natural_join_it.column_ref()->table_name(); - else - { - DBUG_ASSERT(!strcmp(table_ref->table_name, - table_ref->table->s->table_name)); - return table_ref->table_name; - } + + DBUG_ASSERT(!strcmp(table_ref->table_name, + table_ref->table->s->table_name)); + return table_ref->table_name; } @@ -2622,11 +2613,9 @@ const char *Field_iterator_table_ref::db_name() return table_ref->view_db.str; else if (table_ref->is_natural_join) return natural_join_it.column_ref()->db_name(); - else - { - DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db)); - return table_ref->db; - } + + DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db)); + return table_ref->db; } @@ -2636,8 +2625,7 @@ GRANT_INFO *Field_iterator_table_ref::grant() return &(table_ref->grant); else if (table_ref->is_natural_join) return natural_join_it.column_ref()->grant(); - else - return &(table_ref->table->grant); + return &(table_ref->table->grant); } @@ -2645,8 +2633,7 @@ bool Field_iterator_table_ref::is_coalesced() { if (table_ref->is_natural_join) return natural_join_it.column_ref()->is_coalesced; - else - return FALSE; + return FALSE; } /* @@ -2663,29 +2650,30 @@ bool Field_iterator_table_ref::is_coalesced() TODO RETURN - Pointer to a column of a natural join (or its operand) - NULL if there was no memory to allocate the column + # Pointer to a column of a natural join (or its operand) + NULL No memory to allocate the column */ Natural_join_column * Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created) { + Natural_join_column *nj_col; + *is_created= TRUE; if (field_it == &table_field_it) return new Natural_join_column(table_field_it.field(), table_ref); - else if (field_it == &view_field_it) - return new Natural_join_column(view_field_it.field_translator(), table_ref); - else - { - /* - This is NATURAL join, we already have created a column reference, - so just return it. - */ - *is_created= FALSE; - Natural_join_column *nj_col= natural_join_it.column_ref(); - DBUG_ASSERT(nj_col); - return nj_col; - } + if (field_it == &view_field_it) + return new Natural_join_column(view_field_it.field_translator(), + table_ref); + + /* + This is NATURAL join, we already have created a column reference, + so just return it. + */ + *is_created= FALSE; + nj_col= natural_join_it.column_ref(); + DBUG_ASSERT(nj_col); + return nj_col; } From a3ae4e0fc7a2a1b556e4e2ac6ae4231c1d0a505e Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 17 Aug 2005 18:08:30 -0700 Subject: [PATCH 145/230] Fix up definition of new set_timespec_nsec() macro. (Related to bug #12582) --- include/my_global.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index 2627ea8e821..2546dde754d 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -927,7 +927,17 @@ typedef char bool; /* Ordinary boolean values 0 1 */ #ifndef set_timespec #ifdef HAVE_TIMESPEC_TS_SEC -#define set_timespec(ABSTIME,SEC) { (ABSTIME).ts_sec=time(0) + (time_t) (SEC); (ABSTIME).ts_nsec=0; } +#define set_timespec(ABSTIME,SEC) \ +{ \ + (ABSTIME).ts_sec=time(0) + (time_t) (SEC); \ + (ABSTIME).ts_nsec=0; \ +} +#define set_timespec_nsec(ABSTIME,NSEC) \ +{\ + ulonglong now= my_getsystime(); \ + (ABSTIME).ts_sec= (now / ULL(10000000)) + (NSEC / ULL(1000000000)); \ + (ABSTIME).ts_nsec= (now % ULL(10000000)) * 100 + (NSEC % ULL(1000000000)); \ +} #else #define set_timespec(ABSTIME,SEC) \ {\ @@ -936,15 +946,14 @@ typedef char bool; /* Ordinary boolean values 0 1 */ (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\ (ABSTIME).tv_nsec=tv.tv_usec*1000;\ } -#endif /* HAVE_TIMESPEC_TS_SEC */ -#endif /* set_timespec */ - #define set_timespec_nsec(ABSTIME,NSEC) \ {\ ulonglong now= my_getsystime(); \ (ABSTIME).tv_sec= (now / ULL(10000000)) + (NSEC / ULL(1000000000)); \ (ABSTIME).tv_nsec= (now % ULL(10000000)) * 100 + (NSEC % ULL(1000000000)); \ } +#endif /* HAVE_TIMESPEC_TS_SEC */ +#endif /* set_timespec */ /* Define-funktions for reading and storing in machine independent format From 19ed563cd594b7ec82bda553730ce6a221f8e861 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 17 Aug 2005 18:42:07 -0700 Subject: [PATCH 146/230] Fix bad merge of sql/item_strfunc.cc by aivanov --- sql/item_strfunc.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1e1cc123e60..094a0c56319 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2176,9 +2176,6 @@ void Item_func_lpad::fix_length_and_dec() { ulonglong length= ((ulonglong) args[1]->val_int() * collation.collation->mbmaxlen); - /*a comment before (merged) */ - length= max((ulonglong)args[0]->max_length, length); - /*a comment after */ if (length >= MAX_BLOB_WIDTH) { length= MAX_BLOB_WIDTH; From 15f97778ff5eb63f14ab09eab0f24542f8482a49 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 17 Aug 2005 19:56:14 -0700 Subject: [PATCH 147/230] Revert patch for Bug #12595, it causes the sql_mode test to fail. --- mysql-test/r/select.result | 11 ----------- mysql-test/t/select.test | 11 ----------- sql/item_cmpfunc.cc | 6 ------ 3 files changed, 28 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 1b35df534a0..b20949d4a62 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2756,14 +2756,3 @@ DROP TABLE t1,t2; select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0 16 16 2 2 -CREATE TABLE BUG_12595(a varchar(100)); -INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); -SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; -a -hakan% -SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; -ERROR HY000: Incorrect arguments to ESCAPE -SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; -a -ha%an -DROP TABLE BUG_12595; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 390c4372f16..8e74167852b 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2348,14 +2348,3 @@ DROP TABLE t1,t2; # select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; - -# -# BUG #12595 -# -CREATE TABLE BUG_12595(a varchar(100)); -INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); -SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; --- error 1210 -SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; -SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; -DROP TABLE BUG_12595; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c305196615a..b513fb26bdb 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2792,12 +2792,6 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&tmp_value1); - /* ESCAPE must be 1 char in length.*/ - if (escape_str && escape_str->numchars() != 1) - { - my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE"); - return TRUE; - } escape= escape_str ? *(escape_str->ptr()) : '\\'; /* From 1eb0f45d1729b200e4bdfceb3e7ca0fc729aa02c Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 17 Aug 2005 19:57:07 -0700 Subject: [PATCH 148/230] Fix minor typo in handling of error conditions and return of SLEEP(). --- sql/item_func.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index 460d442de89..d3b53db2d54 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3269,7 +3269,7 @@ longlong Item_func_sleep::val_int() THD *thd= current_thd; struct timespec abstime; pthread_cond_t cond; - int error= 0; + int error; DBUG_ASSERT(fixed == 1); @@ -3284,7 +3284,7 @@ longlong Item_func_sleep::val_int() while (!thd->killed && (error= pthread_cond_timedwait(&cond, &LOCK_user_locks, - &abstime) != ETIMEDOUT) && + &abstime)) != ETIMEDOUT && error != EINVAL) ; pthread_mutex_lock(&thd->mysys_var->mutex); From cc05d6dca1e36725a0def473f2ffb05c1eb3356b Mon Sep 17 00:00:00 2001 From: "jan@hundin.mysql.fi" <> Date: Thu, 18 Aug 2005 06:38:01 +0300 Subject: [PATCH 149/230] Allow consistent cursor view see changes made by creating transaction. This is quick fix and needs to be fixed when semi-consistent high-granularity read view is implemented (Bug #12456). --- innobase/read/read0read.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/innobase/read/read0read.c b/innobase/read/read0read.c index dc1ae2f1a16..06349c1fd39 100644 --- a/innobase/read/read0read.c +++ b/innobase/read/read0read.c @@ -310,11 +310,13 @@ read_cursor_view_create_for_mysql( n = 0; trx = UT_LIST_GET_FIRST(trx_sys->trx_list); - /* No active transaction should be visible, not even cr_trx !*/ + /* No active transaction should be visible, except cr_trx. + This is quick fix for a bug 12456 and needs to be fixed when + semi-consistent high-granularity read view is implemented. */ while (trx) { - if (trx->conc_state == TRX_ACTIVE || - trx->conc_state == TRX_PREPARED) { + if (trx != cr_trx && (trx->conc_state == TRX_ACTIVE || + trx->conc_state == TRX_PREPARED)) { read_view_set_nth_trx_id(view, n, trx->id); From 5ac7d86793cdc0a503b6c46698ec9a3345fd2a77 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Wed, 17 Aug 2005 22:19:12 -0700 Subject: [PATCH 150/230] view.test: Added a test case for bug #10970. view.result: Added a test case for bug #10970. Modified the error messages for error ER_VIEW_SELECT_TMPTABLE. sql_view.cc: Fixed bug #10970. In the function mysql_create_view if a view does not refer any tables directly the variable table must be updated after the call of open_and_lock_tables. errmsg.txt: Modified the error messages for error ER_VIEW_SELECT_TMPTABLE (when fixing bug #10970). --- mysql-test/r/view.result | 8 +++++++- mysql-test/t/view.test | 13 +++++++++++++ sql/share/errmsg.txt | 2 +- sql/sql_view.cc | 8 +++++--- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 2af2f06ad52..f6c15669e9e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -6,7 +6,7 @@ create view v1 (c,d) as select a,b from t1; ERROR 42S02: Table 'test.t1' doesn't exist create temporary table t1 (a int, b int); create view v1 (c) as select b+1 from t1; -ERROR HY000: View's SELECT contains a temporary table 't1' +ERROR HY000: View's SELECT refers to a temporary table 't1' drop table t1; create table t1 (a int, b int); insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10); @@ -2097,3 +2097,9 @@ select * from v1; f1 1 drop view v1; +CREATE TEMPORARY TABLE t1 (a int); +CREATE FUNCTION f1 () RETURNS int RETURN (SELECT COUNT(*) FROM t1); +CREATE VIEW v1 AS SELECT f1(); +ERROR HY000: View's SELECT refers to a temporary table 't1' +DROP FUNCTION f1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ceff7af401c..5635358120a 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1942,3 +1942,16 @@ DROP TABLE t1,t2,t3,t4,t5; create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00:00:00') as f1; select * from v1; drop view v1; + +# +# Test for bug #10970: view referring a temporary table indirectly +# + +CREATE TEMPORARY TABLE t1 (a int); +CREATE FUNCTION f1 () RETURNS int RETURN (SELECT COUNT(*) FROM t1); +-- error 1352 +CREATE VIEW v1 AS SELECT f1(); + +DROP FUNCTION f1; +DROP TABLE t1; + diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 2c28eef1ea1..65afefef35a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5194,7 +5194,7 @@ ER_VIEW_SELECT_VARIABLE rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÅÒÅÍÅÎÎÕÀ ÉÌÉ ÐÁÒÁÍÅÔÒ" ukr "View SELECT ÍÁ¤ ÚÍÉÎÎÕ ÁÂÏ ÐÁÒÁÍÅÔÅÒ" ER_VIEW_SELECT_TMPTABLE - eng "View's SELECT contains a temporary table '%-.64s'" + eng "View's SELECT refers to a temporary table '%-.64s'" rus "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'" ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'" ER_VIEW_WRONG_LIST diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c3222f951bb..ddc47d26a69 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -310,9 +310,11 @@ bool mysql_create_view(THD *thd, /* check that tables are not temporary and this VIEW do not used in query - (it is possible with ALTERing VIEW) - */ - for (tbl= tables; tbl; tbl= tbl->next_global) + (it is possible with ALTERing VIEW). + open_and_lock_tables can change the value of tables, + e.g. it may happen if before the function call tables was equal to 0. + */ + for (tbl= tables= lex->query_tables; tbl; tbl= tbl->next_global) { /* is this table temporary and is not view? */ if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view && From 9bd662624c8713b25f25fa7a843ca1cb1a326737 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Thu, 18 Aug 2005 16:47:41 +1000 Subject: [PATCH 151/230] Fix merge of BUG#11538 fix. --- config/ac-macros/ha_ndbcluster.m4 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/config/ac-macros/ha_ndbcluster.m4 b/config/ac-macros/ha_ndbcluster.m4 index dc5e0e73558..509cd868909 100644 --- a/config/ac-macros/ha_ndbcluster.m4 +++ b/config/ac-macros/ha_ndbcluster.m4 @@ -62,10 +62,19 @@ AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [ [ndb_debug="$withval"], [ndb_debug="default"]) AC_ARG_WITH([ndb-ccflags], - [ - --with-ndb-ccflags Extra CC options for ndb compile], - [ndb_cxxflags_fix="$ndb_cxxflags_fix $withval"], - [ndb_cxxflags_fix=$ndb_cxxflags_fix]) + AC_HELP_STRING([--with-ndb-ccflags=CFLAGS], + [Extra CFLAGS for ndb compile]), + [ndb_ccflags=${withval}], + [ndb_ccflags=""]) + + case "$ndb_ccflags" in + "yes") + AC_MSG_RESULT([The --ndb-ccflags option requires a parameter (passed to CC for ndb compilation)]) + ;; + *) + ndb_cxxflags_fix="$ndb_cxxflags_fix $ndb_ccflags" + ;; + esac AC_MSG_CHECKING([for NDB Cluster options]) AC_MSG_RESULT([]) From 8d975efc7246076694e7b6872dc75142bab41277 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Thu, 18 Aug 2005 11:24:59 +0300 Subject: [PATCH 152/230] WL#2486 - natural and using join according to SQL:2003 - Fixed minor error after Monty's review. --- sql/table.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/table.cc b/sql/table.cc index 516116a56c3..b1dea25b8e0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2251,7 +2251,6 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution() { TABLE_LIST *cur_table_ref= this; NESTED_JOIN *cur_nested_join; - LINT_INIT(cur_table_ref); if (is_leaf_for_name_resolution()) return this; From f31f5eabc77b699460ee797d16bf807de6098ade Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Thu, 18 Aug 2005 11:28:50 +0300 Subject: [PATCH 153/230] WL#2486 - natural and using join Fixed debug printout. --- sql/table.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index 0b557b097cf..5fd37b9ae07 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2547,7 +2547,7 @@ void Field_iterator_table_ref::set_field_iterator() natural_join_it.set(table_ref); field_it= &natural_join_it; DBUG_PRINT("info",("field_it for '%s' is Field_iterator_natural_join", - table_ref->table_name)); + table_ref->alias)); } /* This is a merge view, so use field_translation. */ else if (table_ref->field_translation) @@ -2557,7 +2557,7 @@ void Field_iterator_table_ref::set_field_iterator() view_field_it.set(table_ref); field_it= &view_field_it; DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_view", - table_ref->table_name)); + table_ref->alias)); } /* This is a base table or stored view. */ else @@ -2566,7 +2566,7 @@ void Field_iterator_table_ref::set_field_iterator() table_field_it.set(table_ref); field_it= &table_field_it; DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_table", - table_ref->table_name)); + table_ref->alias)); } DBUG_VOID_RETURN; From fc070c2bcb40460300609428d6bd6d5da0f55b22 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Thu, 18 Aug 2005 12:07:14 +0300 Subject: [PATCH 154/230] stop on NULL comparison only if it is allowed (BUG#12509) --- mysql-test/r/row.result | 8 +++++++- mysql-test/t/row.test | 6 ++++++ sql/item_cmpfunc.cc | 26 ++++++++++++++++++++++---- sql/item_cmpfunc.h | 4 +++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index f7f7e3e8429..1762587415d 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -58,7 +58,7 @@ SELECT (1,2,3)=(1,NULL,3); NULL SELECT (1,2,3)=(1,NULL,0); (1,2,3)=(1,NULL,0) -NULL +0 SELECT ROW(1,2,3)=ROW(1,2,3); ROW(1,2,3)=ROW(1,2,3) 1 @@ -175,3 +175,9 @@ ROW(2,10) <=> ROW(3,4) SELECT ROW(NULL,10) <=> ROW(3,NULL); ROW(NULL,10) <=> ROW(3,NULL) 0 +SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NULL,1) = ROW(2,2,1) as `0`, ROW(1,NULL,1) = ROW(1,2,2) as `0`, ROW(1,NULL,1) = ROW(1,2,1) as `null` ; +1 0 0 0 null +1 0 0 0 NULL +select row(NULL,1)=(2,0); +row(NULL,1)=(2,0) +0 diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index 4becef1c2b7..6301cc0f584 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -86,3 +86,9 @@ SELECT ROW(2,10) <=> ROW(3,4); SELECT ROW(NULL,10) <=> ROW(3,NULL); # End of 4.1 tests + +# +# Correct NULL handling in row comporison (BUG#12509) +# +SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NULL,1) = ROW(2,2,1) as `0`, ROW(1,NULL,1) = ROW(1,2,2) as `0`, ROW(1,NULL,1) = ROW(1,2,1) as `null` ; +select row(NULL,1)=(2,0); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c305196615a..67d0ef83e92 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -614,17 +614,35 @@ int Arg_comparator::compare_e_int_diff_signedness() int Arg_comparator::compare_row() { int res= 0; + bool was_null= 0; (*a)->bring_value(); (*b)->bring_value(); uint n= (*a)->cols(); for (uint i= 0; inull_value) - return -1; + { + // NULL was compared + if (owner->abort_on_null) + return -1; // We do not need correct NULL returning + was_null= 1; + owner->null_value= 0; + res= 0; // continue comparison (maybe we will meet explicit difference) + } + if (res) + return res; } - return res; + if (was_null) + { + /* + There was NULL(s) in comparison in some parts, but there was not + explicit difference in other parts, so we have to return NULL + */ + owner->null_value= 1; + return -1; + } + return 0; } int Arg_comparator::compare_e_row() diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a4165407159..6b0cf3e80c2 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -193,10 +193,11 @@ class Item_bool_func2 :public Item_int_func protected: Arg_comparator cmp; String tmp_value1,tmp_value2; + bool abort_on_null; public: Item_bool_func2(Item *a,Item *b) - :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} + :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), abort_on_null(FALSE) {} void fix_length_and_dec(); void set_cmp_func() { @@ -210,6 +211,7 @@ public: bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; } uint decimal_precision() const { return 1; } + void top_level_item() { abort_on_null=1; } friend class Arg_comparator; }; From 4fb6f4dddf85d40f98086091b13c5fec39600b90 Mon Sep 17 00:00:00 2001 From: "petr@mysql.com" <> Date: Thu, 18 Aug 2005 11:23:54 +0200 Subject: [PATCH 155/230] Fix for Bug#11247 Stored procedures: Function calls in long loops leak memory and Bug#12297 SP crashes the server if data inserted inside a lon loop Third commit attempt. With fixes to the issues, showed up after full rebuild and tests on other hosts. --- mysql-test/r/rpl_sp.result | 2 + mysql-test/r/sp.result | 15 ++ mysql-test/t/sp.test | 59 +++++++ sql/sp_head.cc | 353 +++++++++++++++++++++++-------------- sql/sp_rcontext.cc | 10 +- sql/sp_rcontext.h | 8 +- 6 files changed, 304 insertions(+), 143 deletions(-) diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 15180abe8fd..b31951e93c5 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -109,6 +109,7 @@ call foo4(); Got one of the listed errors show warnings; Level Code Message +Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1' Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes call foo3(); show warnings; @@ -117,6 +118,7 @@ call foo4(); Got one of the listed errors show warnings; Level Code Message +Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1' Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes alter procedure foo4 sql security invoker; call foo4(); diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 2aea7be6c12..78bf22d0b27 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3085,4 +3085,19 @@ column_name bug10055(t.column_name) id id data data drop function bug10055| +drop function if exists f_bug11247| +drop procedure if exists p_bug11247| +create function f_bug11247(param int) +returns int +return param + 1| +create procedure p_bug11247(lim int) +begin +declare v int default 0; +while v < lim do +set v= f_bug11247(v); +end while; +end| +call p_bug11247(10)| +drop function f_bug11247| +drop procedure p_bug11247| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f4f527fd222..cde5d3922ab 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3870,6 +3870,65 @@ from information_schema.columns as t where t.table_schema = 'test' and t.table_name = 't1'| drop function bug10055| +# +# Bug #12297 "SP crashes the server if data inserted inside a lon loop" +# The test for memleak bug, so actually there is no way to test it +# from the suite. The test below could be used to check SP memory +# consumption by passing large input parameter. +# + +# +# Note: the test is currenly disabled because of the +# Bug #12637: SP crashes the server if it has update query with user var +# & binlog is enabled. +# + +--disable_warnings +#drop procedure if exists bug12297| +--enable_warnings + +#create procedure bug12297(lim int) +#begin +# set @x = 0; +# repeat +# insert into t1(id,data) +# values('aa', @x); +# set @x = @x + 1; +# until @x >= lim +# end repeat; +#end| + +#call bug12297(10)| +#drop procedure bug12297| + +# +# Bug #11247 "Stored procedures: Function calls in long loops leak memory" +# One more memleak bug test. One could use this test to check that the memory +# isn't leaking by increasing the input value for p_bug11247. +# + +--disable_warnings +drop function if exists f_bug11247| +drop procedure if exists p_bug11247| +--enable_warnings + +create function f_bug11247(param int) + returns int +return param + 1| + +create procedure p_bug11247(lim int) +begin + declare v int default 0; + + while v < lim do + set v= f_bug11247(v); + end while; +end| + +call p_bug11247(10)| +drop function f_bug11247| +drop procedure p_bug11247| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 11677848cb8..26d76804fca 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -126,16 +126,47 @@ sp_prepare_func_item(THD* thd, Item **it_addr) } -/* Evaluate a (presumed) func item. Always returns an item, the parameter -** if nothing else. +/* Macro to switch arena in sp_eval_func_item */ +#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) do\ + {\ + if (condition) \ + thd->set_n_backup_item_arena(thd->spcont->callers_arena,\ + backup_arena);\ + new_command;\ + if (condition)\ + thd->restore_backup_item_arena(thd->spcont->callers_arena,\ + &backup_current_arena);\ + } while(0) + +/* + Evaluate an item and store it in the returned item + + SYNOPSIS + sp_eval_func_item() + name - current thread object + it_addr - pointer to the item to evaluate + type - type of the item we evaluating + reuse - used if we would like to reuse existing item + instead of allocation of the new one + use_callers_arena - TRUE if we want to use caller's arena + rather then current one. + DESCRIPTION + We use this function to evaluate result for stored functions + and stored procedure parameters. It is also used to evaluate and + (re) allocate variables. + + RETURN VALUES + Evaluated item is returned */ + Item * sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, - Item *reuse) + Item *reuse, bool use_callers_arena) { DBUG_ENTER("sp_eval_func_item"); Item *it= sp_prepare_func_item(thd, it_addr); uint rsize; + Query_arena backup_current_arena; DBUG_PRINT("info", ("type: %d", type)); if (!it) @@ -145,90 +176,99 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, /* QQ How do we do this? Is there some better way? */ if (type == MYSQL_TYPE_NULL) - it= new(reuse, &rsize) Item_null(); - else - { - switch (sp_map_result_type(type)) { - case INT_RESULT: - { - longlong i= it->val_int(); + goto return_null_item; - if (it->null_value) - { - DBUG_PRINT("info", ("INT_RESULT: null")); - it= new(reuse, &rsize) Item_null(); - } - else - { - DBUG_PRINT("info", ("INT_RESULT: %d", i)); - it= new(reuse, &rsize) Item_int(i); - } - break; - } - case REAL_RESULT: - { - double d= it->val_real(); + switch (sp_map_result_type(type)) { + case INT_RESULT: + { + longlong i= it->val_int(); - if (it->null_value) - { - DBUG_PRINT("info", ("REAL_RESULT: null")); - it= new(reuse, &rsize) Item_null(); - } - else - { - /* There's some difference between Item::new_item() and the - * constructor; the former crashes, the latter works... weird. */ - uint8 decimals= it->decimals; - uint32 max_length= it->max_length; - DBUG_PRINT("info", ("REAL_RESULT: %g", d)); - it= new(reuse, &rsize) Item_float(d); - it->decimals= decimals; - it->max_length= max_length; - } - break; - } - case DECIMAL_RESULT: + if (it->null_value) { - my_decimal value, *val= it->val_decimal(&value); - if (it->null_value) - it= new(reuse, &rsize) Item_null(); - else - it= new(reuse, &rsize) Item_decimal(val); -#ifndef DBUG_OFF - char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; - DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val))); -#endif - break; + DBUG_PRINT("info", ("INT_RESULT: null")); + goto return_null_item; } - case STRING_RESULT: + else { - char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer, sizeof(buffer), it->collation.collation); - String *s= it->val_str(&tmp); - - if (it->null_value) - { - DBUG_PRINT("info", ("default result: null")); - it= new(reuse, &rsize) Item_null(); - } - else - { - DBUG_PRINT("info",("default result: %*s", - s->length(), s->c_ptr_quick())); - it= new(reuse, &rsize) Item_string(thd->strmake(s->ptr(), - s->length()), - s->length(), - it->collation.collation); - } - break; + DBUG_PRINT("info", ("INT_RESULT: %d", i)); + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i), + use_callers_arena, &backup_current_arena); } - case ROW_RESULT: - default: - DBUG_ASSERT(0); + break; } + case REAL_RESULT: + { + double d= it->val_real(); + + if (it->null_value) + { + DBUG_PRINT("info", ("REAL_RESULT: null")); + goto return_null_item; + } + else + { + /* There's some difference between Item::new_item() and the + * constructor; the former crashes, the latter works... weird. */ + uint8 decimals= it->decimals; + uint32 max_length= it->max_length; + DBUG_PRINT("info", ("REAL_RESULT: %g", d)); + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d), + use_callers_arena, &backup_current_arena); + it->decimals= decimals; + it->max_length= max_length; + } + break; + } + case DECIMAL_RESULT: + { + my_decimal value, *val= it->val_decimal(&value); + if (it->null_value) + goto return_null_item; + else + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val), + use_callers_arena, &backup_current_arena); +#ifndef DBUG_OFF + char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; + DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val))); +#endif + break; + } + case STRING_RESULT: + { + char buffer[MAX_FIELD_WIDTH]; + String tmp(buffer, sizeof(buffer), it->collation.collation); + String *s= it->val_str(&tmp); + + if (it->null_value) + { + DBUG_PRINT("info", ("default result: null")); + goto return_null_item; + } + else + { + DBUG_PRINT("info",("default result: %*s", + s->length(), s->c_ptr_quick())); + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) + Item_string(thd->strmake(s->ptr(), + s->length()), s->length(), + it->collation.collation), + use_callers_arena, &backup_current_arena); + } + break; + } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } it->rsize= rsize; + DBUG_RETURN(it); + +return_null_item: + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(), + use_callers_arena, &backup_current_arena); + it->rsize= rsize; + DBUG_RETURN(it); } @@ -545,23 +585,14 @@ Field * sp_head::make_field(uint max_length, const char *name, TABLE *dummy) { Field *field; - MEM_ROOT *tmp_mem_root; - THD *thd; DBUG_ENTER("sp_head::make_field"); - thd= current_thd; - tmp_mem_root= thd->mem_root; - if (thd->spcont && thd->spcont->callers_mem_root) - thd->mem_root= thd->spcont->callers_mem_root; - else - thd->mem_root= &thd->main_mem_root; field= ::make_field((char *)0, !m_returns_len ? max_length : m_returns_len, (uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs, (enum Field::geometry_type)0, Field::NONE, m_returns_typelib, name ? name : (const char *)m_name.str, dummy); - thd->mem_root= tmp_mem_root; DBUG_RETURN(field); } @@ -576,12 +607,20 @@ sp_head::execute(THD *thd) uint ip= 0; ulong save_sql_mode; Query_arena *old_arena; + /* per-instruction arena */ + MEM_ROOT execute_mem_root; + Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP), + execute_backup_arena; query_id_t old_query_id; TABLE *old_derived_tables; LEX *old_lex; Item_change_list old_change_list; String old_packet; + /* init per-instruction memroot */ + init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + + /* Use some extra margin for possible SP recursion and functions */ if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb)) { @@ -650,6 +689,18 @@ sp_head::execute(THD *thd) */ old_packet.swap(thd->packet); + /* + Switch to per-instruction arena here. We can do it since we cleanup + arena after every instruction. + */ + thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena); + + /* + Save callers arena in order to store instruction results and out + parameters in it later during sp_eval_func_item() + */ + thd->spcont->callers_arena= &execute_backup_arena; + do { sp_instr *i; @@ -670,6 +721,7 @@ sp_head::execute(THD *thd) */ thd->current_arena= i; ret= i->execute(thd, &ip); + /* If this SP instruction have sent eof, it has caused no_send_error to be set. Clear it back to allow the next instruction to send error. (multi- @@ -680,6 +732,10 @@ sp_head::execute(THD *thd) cleanup_items(i->free_list); i->state= Query_arena::EXECUTED; + /* we should cleanup free_list and memroot, used by instruction */ + thd->free_items(); + free_root(&execute_mem_root, MYF(0)); + /* Check if an exception has occurred and a handler has been found Note: We havo to check even if ret==0, since warnings (and some @@ -696,8 +752,10 @@ sp_head::execute(THD *thd) case SP_HANDLER_NONE: break; case SP_HANDLER_CONTINUE: - ctx->save_variables(hf); - ctx->push_hstack(ip); + thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena); + ctx->save_variables(hf); + thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena); + ctx->push_hstack(ip); // Fall through default: ip= hip; @@ -711,6 +769,9 @@ sp_head::execute(THD *thd) } } while (ret == 0 && !thd->killed); + thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena); + + /* Restore all saved */ old_packet.swap(thd->packet); DBUG_ASSERT(thd->change_list.is_empty()); @@ -757,8 +818,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) sp_rcontext *nctx = NULL; uint i; int ret; - MEM_ROOT call_mem_root; - Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena; if (argcount != params) { @@ -771,16 +830,13 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) DBUG_RETURN(-1); } - init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - // QQ Should have some error checking here? (types, etc...) nctx= new sp_rcontext(csize, hmax, cmax); - nctx->callers_mem_root= thd->mem_root; for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); - Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL); + Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE); if (it) nctx->push_item(it); @@ -804,26 +860,16 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } } thd->spcont= nctx; - thd->set_n_backup_item_arena(&call_arena, &backup_arena); - /* mem_root was moved to backup_arena */ - DBUG_ASSERT(nctx->callers_mem_root == backup_arena.mem_root); ret= execute(thd); - /* - Partially restore context now. - We still need the call mem root and free list for processing - of the result. - */ - thd->restore_backup_item_arena(&call_arena, &backup_arena); - if (m_type == TYPE_ENUM_FUNCTION && ret == 0) { /* We need result only in function but not in trigger */ Item *it= nctx->get_result(); if (it) - *resp= sp_eval_func_item(thd, &it, m_returns, NULL); + *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE); else { my_error(ER_SP_NORETURNEND, MYF(0), m_name.str); @@ -832,12 +878,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } nctx->pop_all_cursors(); // To avoid memory leaks after an error + delete nctx; thd->spcont= octx; - // Now get rid of the rest of the callee context - call_arena.free_items(); - free_root(&call_mem_root, MYF(0)); - DBUG_RETURN(ret); } @@ -866,9 +909,7 @@ sp_head::execute_procedure(THD *thd, List *args) uint cmax = m_pcont->max_cursors(); sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; - my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx - MEM_ROOT call_mem_root; - Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena; + my_bool is_tmp_octx = FALSE; // True if we have allocated a temporary octx if (args->elements != params) { @@ -877,7 +918,17 @@ sp_head::execute_procedure(THD *thd, List *args) DBUG_RETURN(-1); } - init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + if (! octx) + { // Create a temporary old context + octx= new sp_rcontext(csize, hmax, cmax); + is_tmp_octx= TRUE; + thd->spcont= octx; + + /* set callers_arena to thd, for upper-level function to work */ + thd->spcont->callers_arena= thd; + } + + nctx= new sp_rcontext(csize, hmax, cmax); if (csize > 0 || hmax > 0 || cmax > 0) { @@ -886,12 +937,6 @@ sp_head::execute_procedure(THD *thd, List *args) List_iterator li(*args); Item *it; - nctx= new sp_rcontext(csize, hmax, cmax); - if (! octx) - { // Create a temporary old context - octx= new sp_rcontext(csize, hmax, cmax); - tmp_octx= TRUE; - } /* Evaluate SP arguments (i.e. get the values passed as parameters) */ // QQ: Should do type checking? @@ -919,7 +964,7 @@ sp_head::execute_procedure(THD *thd, List *args) } else { - Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL); + Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE); if (it2) nctx->push_item(it2); // IN or INOUT @@ -952,15 +997,20 @@ sp_head::execute_procedure(THD *thd, List *args) nit= new Item_null(); nctx->push_item(nit); } - thd->spcont= nctx; } + thd->spcont= nctx; + if (! ret) - { - thd->set_n_backup_item_arena(&call_arena, &backup_arena); ret= execute(thd); - thd->restore_backup_item_arena(&call_arena, &backup_arena); - } + + /* + In the case when we weren't able to employ reuse mechanism for + OUT/INOUT paranmeters, we should reallocate memory. This + allocation should be done on the arena which will live through + all execution of calling routine. + */ + thd->spcont->callers_arena= octx->callers_arena; if (!ret && csize > 0) { @@ -985,12 +1035,20 @@ sp_head::execute_procedure(THD *thd, List *args) Item *val= nctx->get_item(i); Item *orig= octx->get_item(offset); Item *o_item_next; - Item *o_free_list= thd->free_list; + /* we'll use callers_arena in sp_eval_func_item */ + Item *o_free_list= thd->spcont->callers_arena->free_list; + LINT_INIT(o_item_next); if (orig) o_item_next= orig->next; - copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy + + /* + We might need to allocate new item if we weren't able to + employ reuse mechanism. Then we should do it on the callers arena. + */ + copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy + if (!copy) { ret= -1; @@ -1004,7 +1062,7 @@ sp_head::execute_procedure(THD *thd, List *args) A reused item slot, where the constructor put it in the free_list, so we have to restore the list. */ - thd->free_list= o_free_list; + thd->spcont->callers_arena->free_list= o_free_list; copy->next= o_item_next; } } @@ -1032,16 +1090,15 @@ sp_head::execute_procedure(THD *thd, List *args) } } - if (tmp_octx) + if (is_tmp_octx) + { + delete octx; /* call destructor */ octx= NULL; - if (nctx) - nctx->pop_all_cursors(); // To avoid memory leaks after an error - thd->spcont= octx; + } - // Now get rid of the rest of the callee context - call_arena.free_items(); - thd->lex->unit.cleanup(); - free_root(&call_mem_root, MYF(0)); + nctx->pop_all_cursors(); // To avoid memory leaks after an error + delete nctx; + thd->spcont= octx; DBUG_RETURN(ret); } @@ -1894,7 +1951,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_eval_func_item(thd, &m_value, m_type, NULL); + it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE); if (! it) res= -1; else @@ -2044,9 +2101,23 @@ sp_instr_hreturn::opt_mark(sp_head *sp) int sp_instr_cpush::execute(THD *thd, uint *nextp) { + Query_arena backup_current_arena; DBUG_ENTER("sp_instr_cpush::execute"); + + /* + We should create cursors in the callers arena, as + it could be (and usually is) used in several instructions. + */ + thd->set_n_backup_item_arena(thd->spcont->callers_arena, + &backup_current_arena); + thd->spcont->push_cursor(&m_lex_keeper, this); + + thd->restore_backup_item_arena(thd->spcont->callers_arena, + &backup_current_arena); + *nextp= m_ip+1; + DBUG_RETURN(0); } @@ -2197,12 +2268,20 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) { sp_cursor *c= thd->spcont->get_cursor(m_cursor); int res; + Query_arena backup_current_arena; DBUG_ENTER("sp_instr_cfetch::execute"); if (! c) res= -1; else + { + thd->set_n_backup_item_arena(thd->spcont->callers_arena, + &backup_current_arena); res= c->fetch(thd, &m_varlist); + thd->restore_backup_item_arena(thd->spcont->callers_arena, + &backup_current_arena); + } + *nextp= m_ip+1; DBUG_RETURN(res); } diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index d0817e43790..748c09f56c7 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -32,7 +32,6 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0), m_hfound(-1), m_ccount(0) { - callers_mem_root= NULL; in_handler= FALSE; m_frame= (Item **)sql_alloc(fsize * sizeof(Item*)); m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t)); @@ -47,17 +46,18 @@ sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr, enum_field_types type) { extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type, - Item *reuse); + Item *reuse, bool use_callers_arena); Item *it; Item *reuse_it; Item *old_item_next; - Item *old_free_list= thd->free_list; + /* sp_eval_func_item will use callers_arena */ + Item *old_free_list= thd->spcont->callers_arena->free_list; int res; LINT_INIT(old_item_next); if ((reuse_it= get_item(idx))) old_item_next= reuse_it->next; - it= sp_eval_func_item(thd, item_addr, type, reuse_it); + it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE); if (! it) res= -1; else @@ -67,7 +67,7 @@ sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr, { // A reused item slot, where the constructor put it in the free_list, // so we have to restore the list. - thd->free_list= old_free_list; + thd->spcont->callers_arena->free_list= old_free_list; it->next= old_item_next; } set_item(idx, it); diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 856beb13f6d..dedbc7bdef1 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -48,8 +48,14 @@ class sp_rcontext : public Sql_alloc public: - MEM_ROOT *callers_mem_root; // Used to store result fields bool in_handler; + /* + Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT + SP parameters when they don't fit into prealloced items. This + is common situation with String items. It is used mainly in + sp_eval_func_item(). + */ + Query_arena *callers_arena; sp_rcontext(uint fsize, uint hmax, uint cmax); From 3b68047235d6a7bd8816672fdc7bad9a4de1bb18 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Thu, 18 Aug 2005 14:02:25 +0200 Subject: [PATCH 156/230] bug#12118 - ndb alter table data loss Split table version into 2 (major, minor) Impl. signaling to API when table has been altered Allow running transactions to use any minor number for transactions --- mysql-test/r/ndb_alter_table.result | 18 +++- mysql-test/t/ndb_alter_table.test | 26 +++++- ndb/include/kernel/BlockNumbers.h | 4 +- ndb/include/kernel/GlobalSignalNumbers.h | 4 +- ndb/include/kernel/kernel_types.h | 7 ++ ndb/include/kernel/signaldata/AlterTable.hpp | 25 +++++- .../kernel/signaldata/ApiBroadcast.hpp | 31 +++++++ ndb/include/ndbapi/NdbDictionary.hpp | 5 +- ndb/src/common/debugger/BlockNames.cpp | 1 - ndb/src/common/util/version.c | 4 +- ndb/src/kernel/SimBlockList.cpp | 6 +- ndb/src/kernel/blocks/Makefile.am | 1 - ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp | 1 - ndb/src/kernel/blocks/dbdict/Dbdict.cpp | 89 +++++++++++++++++-- ndb/src/kernel/blocks/dbdict/Dbdict.hpp | 1 + .../kernel/blocks/dbdict/printSchemaFile.cpp | 3 +- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 2 - ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 7 +- ndb/src/kernel/blocks/dbtc/Dbtc.hpp | 3 +- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 4 +- ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp | 7 +- ndb/src/kernel/blocks/qmgr/Qmgr.hpp | 1 + ndb/src/kernel/blocks/qmgr/QmgrInit.cpp | 3 +- ndb/src/kernel/blocks/qmgr/QmgrMain.cpp | 38 +++++--- ndb/src/kernel/blocks/suma/Suma.cpp | 20 +---- ndb/src/mgmsrv/MgmtSrvr.cpp | 39 +------- ndb/src/ndbapi/DictCache.cpp | 72 ++++++++++++++- ndb/src/ndbapi/DictCache.hpp | 3 + ndb/src/ndbapi/NdbDictionaryImpl.cpp | 21 ++--- ndb/src/ndbapi/TransporterFacade.cpp | 12 +++ sql/ha_ndbcluster.cc | 5 +- 31 files changed, 339 insertions(+), 124 deletions(-) create mode 100644 ndb/include/kernel/signaldata/ApiBroadcast.hpp diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index 52ae0b58d56..63afc07718f 100644 --- a/mysql-test/r/ndb_alter_table.result +++ b/mysql-test/r/ndb_alter_table.result @@ -179,8 +179,24 @@ a b c 2 two two alter table t1 drop index c; select * from t1 where b = 'two'; -ERROR HY000: Table definition has changed, please retry transaction +a b c +2 two two select * from t1 where b = 'two'; a b c 2 two two drop table t1; +create table t3 (a int primary key) engine=ndbcluster; +begin; +insert into t3 values (1); +alter table t3 rename t4; +delete from t3; +insert into t3 values (1); +commit; +select * from t3; +ERROR HY000: Can't lock file (errno: 155) +select * from t4; +a +1 +drop table t4; +show tables; +Tables_in_test diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 9cc1426554f..e59183fcda1 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -144,7 +144,6 @@ select * from t1 where b = 'two'; connection server1; alter table t1 drop index c; connection server2; ---error 1105 select * from t1 where b = 'two'; select * from t1 where b = 'two'; connection server1; @@ -172,3 +171,28 @@ drop table t1; #truncate table t2; #select count(*) from t2; #drop table t2; + +connection server1; +create table t3 (a int primary key) engine=ndbcluster; + +connection server2; +begin; +insert into t3 values (1); + +connection server1; +alter table t3 rename t4; + +connection server2; +# This should work as transaction is ongoing... +delete from t3; +insert into t3 values (1); +commit; + +# This should fail as its a new transaction +--error 1015 +select * from t3; +select * from t4; +drop table t4; +show tables; +connection server1; + diff --git a/ndb/include/kernel/BlockNumbers.h b/ndb/include/kernel/BlockNumbers.h index cb3cc697eee..49b5842ac4e 100644 --- a/ndb/include/kernel/BlockNumbers.h +++ b/ndb/include/kernel/BlockNumbers.h @@ -44,8 +44,7 @@ #define TRIX 0xFF #define DBUTIL 0x100 #define SUMA 0x101 -#define GREP 0x102 -#define DBTUX 0x103 +#define DBTUX 0x102 const BlockReference BACKUP_REF = numberToRef(BACKUP, 0); const BlockReference DBTC_REF = numberToRef(DBTC, 0); @@ -61,7 +60,6 @@ const BlockReference CMVMI_REF = numberToRef(CMVMI, 0); const BlockReference TRIX_REF = numberToRef(TRIX, 0); const BlockReference DBUTIL_REF = numberToRef(DBUTIL, 0); const BlockReference SUMA_REF = numberToRef(SUMA, 0); -const BlockReference GREP_REF = numberToRef(GREP, 0); const BlockReference DBTUX_REF = numberToRef(DBTUX, 0); const BlockNumber MIN_BLOCK_NO = BACKUP; diff --git a/ndb/include/kernel/GlobalSignalNumbers.h b/ndb/include/kernel/GlobalSignalNumbers.h index 9413f4ef56a..ff3690d60a5 100644 --- a/ndb/include/kernel/GlobalSignalNumbers.h +++ b/ndb/include/kernel/GlobalSignalNumbers.h @@ -777,8 +777,8 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; /** * Grep signals */ -#define GSN_GREP_SUB_CREATE_REQ 606 -#define GSN_GREP_SUB_CREATE_REF 607 +#define GSN_ALTER_TABLE_REP 606 +#define GSN_API_BROADCAST_REP 607 #define GSN_GREP_SUB_CREATE_CONF 608 #define GSN_GREP_CREATE_REQ 609 #define GSN_GREP_CREATE_REF 610 diff --git a/ndb/include/kernel/kernel_types.h b/ndb/include/kernel/kernel_types.h index b176d20798c..e16e61471e7 100644 --- a/ndb/include/kernel/kernel_types.h +++ b/ndb/include/kernel/kernel_types.h @@ -36,6 +36,13 @@ enum Operation_t { #endif }; +inline +Uint32 +table_version_major(Uint32 ver) +{ + return ver & 0x00FFFFFF; +} + #endif diff --git a/ndb/include/kernel/signaldata/AlterTable.hpp b/ndb/include/kernel/signaldata/AlterTable.hpp index 173a9acf9ed..16c9eb204c9 100644 --- a/ndb/include/kernel/signaldata/AlterTable.hpp +++ b/ndb/include/kernel/signaldata/AlterTable.hpp @@ -129,7 +129,8 @@ public: InvalidPrimaryKeySize = 739, NullablePrimaryKey = 740, UnsupportedChange = 741, - BackupInProgress = 762 + BackupInProgress = 762, + IncompatibleVersions = 763 }; private: @@ -177,4 +178,26 @@ private: Uint32 tableVersion; }; +/** + * Inform API about change of table definition + */ +struct AlterTableRep +{ + friend bool printALTER_TABLE_REP(FILE*, const Uint32*, Uint32, Uint16); + + STATIC_CONST( SignalLength = 3 ); + + enum Change_type + { + CT_ALTERED = 0x1, + CT_DROPPED = 0x2 + }; + + Uint32 tableId; + Uint32 tableVersion; + Uint32 changeType; + + SECTION( TABLE_NAME = 0 ); +}; + #endif diff --git a/ndb/include/kernel/signaldata/ApiBroadcast.hpp b/ndb/include/kernel/signaldata/ApiBroadcast.hpp new file mode 100644 index 00000000000..8050326ce78 --- /dev/null +++ b/ndb/include/kernel/signaldata/ApiBroadcast.hpp @@ -0,0 +1,31 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef API_BROADCAST_HPP +#define API_BROADCAST_HPP + +#include "SignalData.hpp" + +struct ApiBroadcastRep +{ + STATIC_CONST( SignalLength = 2 ); + + Uint32 gsn; + Uint32 minVersion; + Uint32 theData[1]; +}; + +#endif diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 85615f3aa66..a541cd5190e 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -77,9 +77,10 @@ public: ///< changes to take effect Retrieved, ///< The object exist and has been read ///< into main memory from NDB Kernel - Invalid ///< The object has been invalidated + Invalid, ///< The object has been invalidated ///< and should not be used - + Altered ///< Table has been altered in NDB kernel + ///< but is still valid for usage }; /** diff --git a/ndb/src/common/debugger/BlockNames.cpp b/ndb/src/common/debugger/BlockNames.cpp index 44650b84c5c..0c61b6327ef 100644 --- a/ndb/src/common/debugger/BlockNames.cpp +++ b/ndb/src/common/debugger/BlockNames.cpp @@ -32,7 +32,6 @@ const BlockName BlockNames[] = { { "BACKUP", BACKUP }, { "DBUTIL", DBUTIL }, { "SUMA", SUMA }, - { "GREP", GREP }, { "DBTUX", DBTUX } }; diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c index 7221dc48fa4..05ce6d88d11 100644 --- a/ndb/src/common/util/version.c +++ b/ndb/src/common/util/version.c @@ -90,7 +90,8 @@ void ndbSetOwnVersion() {} #ifndef TEST_VERSION struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { - { MAKE_VERSION(4,1,NDB_VERSION_BUILD), MAKE_VERSION(4,1,10), UG_Range }, + { MAKE_VERSION(4,1,NDB_VERSION_BUILD), MAKE_VERSION(4,1,15), UG_Range }, + { MAKE_VERSION(4,1,14), MAKE_VERSION(4,1,10), UG_Range }, { MAKE_VERSION(4,1,10), MAKE_VERSION(4,1,9), UG_Exact }, { MAKE_VERSION(4,1,9), MAKE_VERSION(4,1,8), UG_Exact }, { MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact }, @@ -98,6 +99,7 @@ struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { }; struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = { + { MAKE_VERSION(4,1,15), MAKE_VERSION(4,1,14), UG_Exact }, { MAKE_VERSION(3,5,4), MAKE_VERSION(3,5,3), UG_Exact }, { 0, 0, UG_Null } }; diff --git a/ndb/src/kernel/SimBlockList.cpp b/ndb/src/kernel/SimBlockList.cpp index bf3958cf137..6029fc7e225 100644 --- a/ndb/src/kernel/SimBlockList.cpp +++ b/ndb/src/kernel/SimBlockList.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -97,13 +96,14 @@ SimBlockList::load(const Configuration & conf){ theList[11] = NEW_BLOCK(Backup)(conf); theList[12] = NEW_BLOCK(DbUtil)(conf); theList[13] = NEW_BLOCK(Suma)(conf); - theList[14] = NEW_BLOCK(Grep)(conf); + theList[14] = 0; //NEW_BLOCK(Grep)(conf); theList[15] = NEW_BLOCK(Dbtux)(conf); // Metadata common part shared by block instances ptrMetaDataCommon = new MetaData::Common(*dbdict, *dbdih); for (int i = 0; i < noOfBlocks; i++) - theList[i]->setMetaDataCommon(ptrMetaDataCommon); + if(theList[i]) + theList[i]->setMetaDataCommon(ptrMetaDataCommon); } void diff --git a/ndb/src/kernel/blocks/Makefile.am b/ndb/src/kernel/blocks/Makefile.am index 7ee90e6239f..8addf257003 100644 --- a/ndb/src/kernel/blocks/Makefile.am +++ b/ndb/src/kernel/blocks/Makefile.am @@ -13,7 +13,6 @@ SUBDIRS = \ backup \ dbutil \ suma \ - grep \ dbtux windoze-dsp: diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp index 0274ef4af3e..7659ee1145d 100644 --- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp +++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp @@ -987,7 +987,6 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal) sendSignal(BACKUP_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB); sendSignal(DBUTIL_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB); sendSignal(SUMA_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB); - sendSignal(GREP_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB); sendSignal(TRIX_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB); sendSignal(DBTUX_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index a3ea195786e..f60720a1345 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #define ZNOT_FOUND 626 #define ZALREADYEXIST 630 @@ -91,6 +92,27 @@ #define DIV(x,y) (((x)+(y)-1)/(y)) #include +static +Uint32 +alter_table_inc_schema_version(Uint32 old) +{ + return (old & 0x00FFFFFF) + ((old + 0x1000000) & 0xFF000000); +} + +static +Uint32 +alter_table_dec_schema_version(Uint32 old) +{ + return (old & 0x00FFFFFF) + ((old - 0x1000000) & 0xFF000000); +} + +static +Uint32 +create_table_inc_schema_version(Uint32 old) +{ + return (old + 0x00000001) & 0x00FFFFFF; +} + /* **************************************************************** */ /* ---------------------------------------------------------------- */ /* MODULE: GENERAL MODULE -------------------------------- */ @@ -584,7 +606,7 @@ void Dbdict::openTableFile(Signal* signal, jam(); fsOpenReq->fileFlags = FsOpenReq::OM_READONLY; }//if - ndbrequire(tablePtr.p->tableVersion < ZNIL); + fsOpenReq->fileNumber[3] = 0; // Initialise before byte changes FsOpenReq::setVersion(fsOpenReq->fileNumber, 1); FsOpenReq::setSuffix(fsOpenReq->fileNumber, FsOpenReq::S_TABLELIST); @@ -776,7 +798,7 @@ Dbdict::updateSchemaState(Signal* signal, Uint32 tableId, case SchemaFile::ADD_STARTED: jam(); ok = true; - ndbrequire((oldVersion + 1) == newVersion); + ndbrequire(create_table_inc_schema_version(oldVersion) == newVersion); ndbrequire(oldState == SchemaFile::INIT || oldState == SchemaFile::DROP_TABLE_COMMITTED); break; @@ -789,7 +811,7 @@ Dbdict::updateSchemaState(Signal* signal, Uint32 tableId, case SchemaFile::ALTER_TABLE_COMMITTED: jam(); ok = true; - ndbrequire((oldVersion + 1) == newVersion); + ndbrequire(alter_table_inc_schema_version(oldVersion) == newVersion); ndbrequire(oldState == SchemaFile::TABLE_ADD_COMMITTED || oldState == SchemaFile::ALTER_TABLE_COMMITTED); break; @@ -2806,6 +2828,21 @@ Dbdict::execBACKUP_FRAGMENT_REQ(Signal* signal) } } +bool +Dbdict::check_ndb_versions() const +{ + Uint32 node = 0; + Uint32 version = getNodeInfo(getOwnNodeId()).m_version; + while((node = c_aliveNodes.find(node + 1)) != BitmaskImpl::NotFound) + { + if(getNodeInfo(node).m_version != version) + { + return false; + } + } + return true; +} + void Dbdict::execALTER_TABLE_REQ(Signal* signal) { @@ -2842,6 +2879,13 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) alterTableRef(signal, req, AlterTableRef::Busy); return; } + + if (!check_ndb_versions()) + { + jam(); + alterTableRef(signal, req, AlterTableRef::IncompatibleVersions); + return; + } const TableRecord::TabState tabState = tablePtr.p->tabState; bool ok = false; @@ -2992,7 +3036,7 @@ Dbdict::alterTable_backup_mutex_locked(Signal* signal, lreq->clientData = alterTabPtr.p->m_senderData; lreq->changeMask = alterTabPtr.p->m_changeMask; lreq->tableId = tablePtr.p->tableId; - lreq->tableVersion = tablePtr.p->tableVersion + 1; + lreq->tableVersion = alter_table_inc_schema_version(tablePtr.p->tableVersion); lreq->gci = tablePtr.p->gciTableCreated; lreq->requestType = AlterTabReq::AlterTablePrepare; @@ -3072,6 +3116,14 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) alterTabRef(signal, req, AlterTableRef::Busy); return; } + + if (!check_ndb_versions()) + { + jam(); + alterTabRef(signal, req, AlterTableRef::IncompatibleVersions); + return; + } + alterTabPtr.p->m_alterTableId = tableId; alterTabPtr.p->m_coordinatorRef = senderRef; @@ -3114,7 +3166,7 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) } ndbrequire(ok); - if(tablePtr.p->tableVersion + 1 != tableVersion){ + if(alter_table_inc_schema_version(tablePtr.p->tableVersion) != tableVersion){ jam(); alterTabRef(signal, req, AlterTableRef::InvalidTableVersion); return; @@ -3599,7 +3651,7 @@ void Dbdict::revertAlterTable(Signal * signal, // Restore name strcpy(tablePtr.p->tableName, alterTabPtrP->previousTableName); // Revert schema version - tablePtr.p->tableVersion = tablePtr.p->tableVersion - 1; + tablePtr.p->tableVersion = alter_table_dec_schema_version(tablePtr.p->tableVersion); // Put it back #ifdef VM_TRACE ndbrequire(!c_tableRecordHash.find(tmp, * tablePtr.p)); @@ -3659,6 +3711,27 @@ Dbdict::alterTab_writeTableConf(Signal* signal, conf->requestType = AlterTabReq::AlterTableCommit; sendSignal(coordinatorRef, GSN_ALTER_TAB_CONF, signal, AlterTabConf::SignalLength, JBB); + + + { + ApiBroadcastRep* api= (ApiBroadcastRep*)signal->getDataPtrSend(); + api->gsn = GSN_ALTER_TABLE_REP; + api->minVersion = MAKE_VERSION(4,1,15); + + AlterTableRep* rep = (AlterTableRep*)api->theData; + rep->tableId = tabPtr.p->tableId; + rep->tableVersion = alter_table_dec_schema_version(tabPtr.p->tableVersion); + rep->changeType = AlterTableRep::CT_ALTERED; + + LinearSectionPtr ptr[3]; + ptr[0].p = (Uint32*)alterTabPtr.p->previousTableName; + ptr[0].sz = (sizeof(alterTabPtr.p->previousTableName) + 3) >> 2; + + sendSignal(QMGR_REF, GSN_API_BROADCAST_REP, signal, + ApiBroadcastRep::SignalLength + AlterTableRep::SignalLength, + JBB, ptr,1); + } + if(coordinatorRef != reference()) { jam(); // Release resources @@ -3711,7 +3784,7 @@ Dbdict::execCREATE_FRAGMENTATION_CONF(Signal* signal){ c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); SchemaFile::TableEntry * tabEntry = getTableEntry(pagePtr.p, tabPtr.i); - tabPtr.p->tableVersion = tabEntry->m_tableVersion + 1; + tabPtr.p->tableVersion = create_table_inc_schema_version(tabEntry->m_tableVersion); /** * Pack @@ -3740,7 +3813,7 @@ Dbdict::execCREATE_FRAGMENTATION_CONF(Signal* signal){ req->gci = 0; req->tableId = tabPtr.i; - req->tableVersion = tabEntry->m_tableVersion + 1; + req->tableVersion = create_table_inc_schema_version(tabEntry->m_tableVersion); sendFragmentedSignal(rg, GSN_CREATE_TAB_REQ, signal, CreateTabReq::SignalLength, JBB); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index 48dc2d2c2d5..77a44d0ad24 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -578,6 +578,7 @@ private: void execALTER_TAB_REQ(Signal* signal); void execALTER_TAB_REF(Signal* signal); void execALTER_TAB_CONF(Signal* signal); + bool check_ndb_versions() const; /* * 2.4 COMMON STORED VARIABLES diff --git a/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp b/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp index 0ba52878b7c..3e944485e1c 100644 --- a/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp +++ b/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp @@ -58,7 +58,8 @@ print(const char * filename, const SchemaFile * file){ SchemaFile::TableEntry te = file->TableEntries[i]; if(te.m_tableState != SchemaFile::INIT){ ndbout << "Table " << i << ": State = " << te.m_tableState - << " version = " << te.m_tableVersion + << " version = " << table_version_major(te.m_tableVersion) << + << "(" << table_version_minor(te.m_tableVersion) << ")" << " type = " << te.m_tableType << " noOfPages = " << te.m_noOfPages << " gcp: " << te.m_gcp << endl; diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 82678827927..94426c8be3f 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -1886,8 +1886,6 @@ void Dbdih::execINCL_NODECONF(Signal* signal) // Suma will not send response to this for now, later... sendSignal(SUMA_REF, GSN_INCL_NODEREQ, signal, 2, JBB); - // Grep will not send response to this for now, later... - sendSignal(GREP_REF, GSN_INCL_NODEREQ, signal, 2, JBB); return; }//if if (TstartNode_or_blockref == numberToRef(BACKUP, getOwnNodeId())){ diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 5d689274f26..05d76f5fb25 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -3512,7 +3512,8 @@ void Dblqh::execLQHKEYREQ(Signal* signal) LQHKEY_abort(signal, 4); return; } - if(tabptr.p->schemaVersion != schemaVersion){ + if(table_version_major(tabptr.p->schemaVersion) != + table_version_major(schemaVersion)){ LQHKEY_abort(signal, 5); return; } @@ -4451,7 +4452,7 @@ void Dblqh::packLqhkeyreqLab(Signal* signal) lqhKeyReq->requestInfo = Treqinfo; lqhKeyReq->tcBlockref = sig4; - sig0 = regTcPtr->tableref + (regTcPtr->schemaVersion << 16); + sig0 = regTcPtr->tableref + ((regTcPtr->schemaVersion << 16) & 0xFFFF0000); sig1 = regTcPtr->fragmentid + (regTcPtr->nodeAfterNext[0] << 16); sig2 = regTcPtr->transid[0]; sig3 = regTcPtr->transid[1]; @@ -15840,7 +15841,7 @@ Uint32 Dblqh::checkIfExecLog(Signal* signal) tabptr.i = tcConnectptr.p->tableref; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); if (getFragmentrec(signal, tcConnectptr.p->fragmentid) && - (tabptr.p->schemaVersion == tcConnectptr.p->schemaVersion)) { + (table_version_major(tabptr.p->schemaVersion) == table_version_major(tcConnectptr.p->schemaVersion))) { if (fragptr.p->execSrStatus != Fragrecord::IDLE) { if (fragptr.p->execSrNoReplicas > logPartPtr.p->execSrExecuteIndex) { ndbrequire((fragptr.p->execSrNoReplicas - 1) < 4); diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index fbd181cae24..61afef30b43 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -958,7 +958,8 @@ public: Uint8 storedTable; bool checkTable(Uint32 schemaVersion) const { - return enabled && !dropping && (schemaVersion == currentSchemaVersion); + return enabled && !dropping && + (table_version_major(schemaVersion) == table_version_major(currentSchemaVersion)); } Uint32 getErrorCode(Uint32 schemaVersion) const; diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 736a660f396..93b122b9a99 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -3196,7 +3196,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal, lqhKeyReq->tcBlockref = sig4; lqhKeyReq->savePointId = sig5; - sig0 = regCachePtr->tableref + (regCachePtr->schemaVersion << 16); + sig0 = regCachePtr->tableref + ((regCachePtr->schemaVersion << 16) & 0xFFFF0000); sig1 = regCachePtr->fragmentid + (regTcPtr->tcNodedata[1] << 16); sig2 = regApiPtr->transid[0]; sig3 = regApiPtr->transid[1]; @@ -12877,7 +12877,7 @@ Dbtc::TableRecord::getErrorCode(Uint32 schemaVersion) const { return ZNO_SUCH_TABLE; if(dropping) return ZDROP_TABLE_IN_PROGRESS; - if(schemaVersion != currentSchemaVersion) + if(table_version_major(schemaVersion) != table_version_major(currentSchemaVersion)) return ZWRONG_SCHEMA_VERSION_ERROR; ErrorReporter::handleAssert("Dbtc::TableRecord::getErrorCode", __FILE__, __LINE__); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 9eaa203b098..c80891548cf 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -76,7 +76,6 @@ static BlockInfo ALL_BLOCKS[] = { { BACKUP_REF, 1 , 10000, 10999 }, { DBUTIL_REF, 1 , 11000, 11999 }, { SUMA_REF, 1 , 13000, 13999 }, - { GREP_REF, 1 , 0, 0 }, { DBTUX_REF, 1 , 12000, 12999 } }; @@ -1453,9 +1452,6 @@ void Ndbcntr::execNODE_FAILREP(Signal* signal) sendSignal(SUMA_REF, GSN_NODE_FAILREP, signal, NodeFailRep::SignalLength, JBB); - sendSignal(GREP_REF, GSN_NODE_FAILREP, signal, - NodeFailRep::SignalLength, JBB); - Uint32 nodeId = 0; while(!allFailed.isclear()){ nodeId = allFailed.find(nodeId + 1); @@ -2381,7 +2377,6 @@ void Ndbcntr::execREAD_CONFIG_CONF(Signal* signal){ void Ndbcntr::execSTART_ORD(Signal* signal){ jamEntry(); - ndbrequire(NO_OF_BLOCKS == ALL_BLOCKS_SZ); c_missra.execSTART_ORD(signal); } @@ -2456,7 +2451,7 @@ void Ndbcntr::Missra::sendNextREAD_CONFIG_REQ(Signal* signal){ * Finished... */ currentStartPhase = 0; - for(Uint32 i = 0; i #include #include +#include #include @@ -1702,16 +1703,6 @@ void Qmgr::sendApiFailReq(Signal* signal, Uint16 failedNodeNo) sendSignal(DBDICT_REF, GSN_API_FAILREQ, signal, 2, JBA); sendSignal(SUMA_REF, GSN_API_FAILREQ, signal, 2, JBA); - /** - * GREP also need the information that an API node - * (actually a REP node) has failed. - * - * GREP does however NOT send a CONF on this signal, i.e. - * the API_FAILREQ signal to GREP is like a REP signal - * (i.e. without any confirmation). - */ - sendSignal(GREP_REF, GSN_API_FAILREQ, signal, 2, JBA); - /**------------------------------------------------------------------------- * THE OTHER NODE WAS AN API NODE. THE COMMUNICATION LINK IS ALREADY * BROKEN AND THUS NO ACTION IS NEEDED TO BREAK THE CONNECTION. @@ -3926,3 +3917,30 @@ void Qmgr::execSET_VAR_REQ(Signal* signal) }// switch #endif }//execSET_VAR_REQ() + +void +Qmgr::execAPI_BROADCAST_REP(Signal* signal) +{ + jamEntry(); + ApiBroadcastRep api= *(const ApiBroadcastRep*)signal->getDataPtr(); + + Uint32 len = signal->getLength() - ApiBroadcastRep::SignalLength; + memmove(signal->theData, signal->theData+ApiBroadcastRep::SignalLength, + 4*len); + + NodeBitmask mask; + NodeRecPtr nodePtr; + for (nodePtr.i = 1; nodePtr.i < MAX_NODES; nodePtr.i++) + { + jam(); + ptrAss(nodePtr, nodeRec); + if (nodePtr.p->phase == ZAPI_ACTIVE && + getNodeInfo(nodePtr.i).m_version >= api.minVersion) + { + mask.set(nodePtr.i); + } + } + + NodeReceiverGroup rg(API_CLUSTERMGR, mask); + sendSignal(rg, api.gsn, signal, len, JBB); // forward sections +} diff --git a/ndb/src/kernel/blocks/suma/Suma.cpp b/ndb/src/kernel/blocks/suma/Suma.cpp index 44ac054dd67..84a59f440d9 100644 --- a/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/ndb/src/kernel/blocks/suma/Suma.cpp @@ -2143,7 +2143,8 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){ case SubCreateReq::DatabaseSnapshot: case SubCreateReq::SelectiveTableSnapshot: jam(); - subbPtr.p->m_subscriberRef = GREP_REF; + ndbrequire(false); + //subbPtr.p->m_subscriberRef = GREP_REF; subbPtr.p->m_subscriberData = subPtr.p->m_subscriberData; break; case SubCreateReq::SingleTableScan: @@ -2971,16 +2972,6 @@ SumaParticipant::execSUB_GCP_COMPLETE_REP(Signal* signal){ Uint32 gci = rep->gci; c_lastCompleteGCI = gci; - /** - * always send SUB_GCP_COMPLETE_REP to Grep (so - * Lars can do funky stuff calculating intervals, - * even before the subscription is started - */ - rep->senderRef = reference(); - rep->senderData = 0; //ignored in grep - EXECUTE_DIRECT(refToBlock(GREP_REF), GSN_SUB_GCP_COMPLETE_REP, signal, - SubGcpCompleteRep::SignalLength); - /** * Signal to subscriber(s) */ @@ -3005,13 +2996,6 @@ SumaParticipant::execSUB_GCP_COMPLETE_REP(Signal* signal){ ndbout_c("GSN_SUB_GCP_COMPLETE_REP to %s:", getBlockName(refToBlock(ref))); #else - /** - * Ignore sending to GREP (since we sent earlier) - */ - if (ref == GREP_REF) { - jam(); - continue; - } CRASH_INSERTION(13018); diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index ceaedc9955b..292e13a234b 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -2541,44 +2541,7 @@ MgmtSrvr::backupCallback(BackupEvent & event) int MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted) { - bool next; - NodeId nodeId = 0; - - while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && - theFacade->get_node_alive(nodeId) == false); - - if(!next){ - return NO_CONTACT_WITH_DB_NODES; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - GrepReq* req = CAST_PTR(GrepReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, GREP, GSN_GREP_REQ, GrepReq::SignalLength); - req->senderRef = _ownReference; - req->request = request; - - int result; - if (waitCompleted) - result = sendRecSignal(nodeId, NO_WAIT, signal, true); - else - result = sendRecSignal(nodeId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - /** - * @todo - * Maybe add that we should receive a confirmation that the - * request was received ok. - * Then we should give the user the correct repReqId. - */ - - *repReqId = 4711; - + abort(); return 0; } diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index ccc45a04824..ca361e900b1 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -21,6 +21,9 @@ #include #include +static NdbTableImpl f_invalid_table; +static NdbTableImpl f_altered_table; + Ndb_local_table_info * Ndb_local_table_info::create(NdbTableImpl *table_impl, Uint32 sz) { @@ -164,21 +167,41 @@ GlobalDictCache::put(const char * name, NdbTableImpl * tab) TableVersion & ver = vers->back(); if(ver.m_status != RETREIVING || - ver.m_impl != 0 || + !(ver.m_impl == 0 || + ver.m_impl == &f_invalid_table || ver.m_impl == &f_altered_table) || ver.m_version != 0 || ver.m_refCount == 0){ abort(); } - if(tab == 0){ + if(tab == 0) + { // No table found in db vers->erase(sz - 1); - } else { + } + else if (ver.m_impl == 0) { ver.m_impl = tab; ver.m_version = tab->m_version; ver.m_status = OK; + } + else if (ver.m_impl == &f_invalid_table) + { + ver.m_impl = tab; + ver.m_version = tab->m_version; + ver.m_status = DROPPED; + ver.m_impl->m_status = NdbDictionary::Object::Invalid; + } + else if(ver.m_impl == &f_altered_table) + { + ver.m_impl = tab; + ver.m_version = tab->m_version; + ver.m_status = DROPPED; + ver.m_impl->m_status = NdbDictionary::Object::Altered; + } + else + { + abort(); } - NdbCondition_Broadcast(m_waitForTableCondition); return tab; } @@ -275,4 +298,45 @@ GlobalDictCache::release(NdbTableImpl * tab){ abort(); } +void +GlobalDictCache::alter_table_rep(const char * name, + Uint32 tableId, + Uint32 tableVersion, + bool altered) +{ + const Uint32 len = strlen(name); + Vector * vers = + m_tableHash.getData(name, len); + + if(vers == 0) + { + return; + } + + const Uint32 sz = vers->size(); + if(sz == 0) + { + return; + } + + for(Uint32 i = 0; i < sz; i++) + { + TableVersion & ver = (* vers)[i]; + if(ver.m_version == tableVersion && ver.m_impl && + ver.m_impl->m_tableId == tableId) + { + ver.m_status = DROPPED; + ver.m_impl->m_status = altered ? + NdbDictionary::Object::Altered : NdbDictionary::Object::Invalid; + return; + } + + if(i == sz - 1 && ver.m_status == RETREIVING) + { + ver.m_impl = altered ? &f_altered_table : &f_invalid_table; + return; + } + } +} + template class Vector; diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp index ca31c345396..7f2ee457476 100644 --- a/ndb/src/ndbapi/DictCache.hpp +++ b/ndb/src/ndbapi/DictCache.hpp @@ -68,6 +68,9 @@ public: NdbTableImpl* put(const char * name, NdbTableImpl *); void drop(NdbTableImpl *); void release(NdbTableImpl *); + + void alter_table_rep(const char * name, + Uint32 tableId, Uint32 tableVersion, bool altered); public: enum Status { OK = 0, diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 27fd70cd0f4..8b1847502d9 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1439,25 +1439,22 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl) const char * originalExternalName = externalName.c_str(); DBUG_ENTER("NdbDictionaryImpl::alterTable"); - if(!get_local_table_info(originalInternalName, false)){ + Ndb_local_table_info * local = 0; + if((local= get_local_table_info(originalInternalName, false)) == 0) + { m_error.code = 709; DBUG_RETURN(-1); } + // Alter the table int ret = m_receiver.alterTable(m_ndb, impl); if(ret == 0){ // Remove cached information and let it be refreshed at next access - if (m_localHash.get(originalInternalName) != NULL) { - m_localHash.drop(originalInternalName); - m_globalHash->lock(); - NdbTableImpl * cachedImpl = m_globalHash->get(originalInternalName); - // If in local cache it must be in global - if (!cachedImpl) - abort(); - cachedImpl->m_status = NdbDictionary::Object::Invalid; - m_globalHash->drop(cachedImpl); - m_globalHash->unlock(); - } + m_globalHash->lock(); + local->m_table_impl->m_status = NdbDictionary::Object::Invalid; + m_globalHash->drop(local->m_table_impl); + m_globalHash->unlock(); + m_localHash.drop(originalInternalName); } DBUG_RETURN(ret); } diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp index 93cec59ada6..a89b6287872 100644 --- a/ndb/src/ndbapi/TransporterFacade.cpp +++ b/ndb/src/ndbapi/TransporterFacade.cpp @@ -35,6 +35,7 @@ #include #include #include +#include //#define REPORT_TRANSPORTER //#define API_TRACE; @@ -305,6 +306,17 @@ execute(void * callbackObj, SignalHeader * const header, theFacade->theArbitMgr->doStop(theData); break; + case GSN_ALTER_TABLE_REP: + { + const AlterTableRep* rep = (const AlterTableRep*)theData; + theFacade->m_globalDictCache.lock(); + theFacade->m_globalDictCache. + alter_table_rep((const char*)ptr[0].p, + rep->tableId, + rep->tableVersion, + rep->changeType == AlterTableRep::CT_ALTERED); + theFacade->m_globalDictCache.unlock(); + } default: break; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 65c5fcb7de4..533895ce378 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3266,7 +3266,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); // Check if thread has stale local cache - if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) + // New transaction must not use old tables... (trans != 0) + // Running might... + if ((trans && tab->getObjectStatus() != NdbDictionary::Object::Retrieved) + || tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); if (!(tab= dict->getTable(m_tabname, &tab_info))) From c085c9a3b7d9938da6287860f809b37ed22af325 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Thu, 18 Aug 2005 18:26:30 +0400 Subject: [PATCH 157/230] Undo the test cset that shouldn't have been pushed (ChangeSet@1.1988, 2005-08-16 00:03:50+04:00, aivanov@mysql.com ) --- sql/item_strfunc.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1e1cc123e60..094a0c56319 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2176,9 +2176,6 @@ void Item_func_lpad::fix_length_and_dec() { ulonglong length= ((ulonglong) args[1]->val_int() * collation.collation->mbmaxlen); - /*a comment before (merged) */ - length= max((ulonglong)args[0]->max_length, length); - /*a comment after */ if (length >= MAX_BLOB_WIDTH) { length= MAX_BLOB_WIDTH; From 78bd379b29fc70cae3e7cfc3164aa01da9fb43cf Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Fri, 19 Aug 2005 00:48:03 +1000 Subject: [PATCH 158/230] Fix merge of BUG10950 and jonas' message improvements. --- ndb/src/mgmapi/mgmapi.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 6551ca24ee2..c10eb073855 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -343,11 +343,9 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, /** * Print some info about why the parser returns NULL */ - ndbout << "Error in mgm protocol parser. " - << "cmd: '" << cmd - << "' status=" << (Uint32)ctx.m_status - << ", curr=" << ctx.m_currentToken - << endl; + fprintf(handle->errstream, + "Error in mgm protocol parser. cmd: >%s< status: %d curr: %d\n", + cmd, (Uint32)ctx.m_status, ctx.m_currentToken); DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s", ctx.m_status, ctx.m_currentToken)); } From 6c39364f85b6707caee8d7eaefe8fa62af298054 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Thu, 18 Aug 2005 19:07:23 +0400 Subject: [PATCH 159/230] Fix for bug #11896 "Partial locking in case of recursive trigger definitions". If we are in stored function or trigger we should ensure that we won't change table that is already used by calling statement (this can damage table or easily cause infinite loops). Particularly this means that recursive triggers should be disallowed. --- mysql-test/r/sp-error.result | 30 +++++++++++++++ mysql-test/r/trigger.result | 41 ++++++++++++++++++++ mysql-test/t/sp-error.test | 29 ++++++++++++++ mysql-test/t/trigger.test | 36 ++++++++++++++++++ sql/share/errmsg.txt | 2 + sql/sql_base.cc | 74 ++++++++++++++++++++++++------------ 6 files changed, 188 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index bd383379abc..4ac29a07757 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -299,6 +299,36 @@ lock tables t1 read, mysql.proc read| unlock tables| lock tables mysql.proc write| unlock tables| +drop function if exists f1| +create function f1(i int) returns int +begin +insert into t1 (val) values (i); +return 0; +end| +select val, f1(val) from t1| +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +select val, f1(val) from t1 as tab| +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +select * from t1| +val x +42 3.1 +19 1.2 +update t1 set val= f1(val)| +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +select * from t1| +val x +42 3.1 +19 1.2 +select f1(17)| +f1(17) +0 +select * from t1| +val x +42 3.1 +19 1.2 +17 NULL +delete from t1 where val= 17| +drop function f1| create procedure bug1965() begin declare c cursor for select val from t1 order by valname; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ee0a6f6b744..7e359d3703e 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -664,3 +664,44 @@ end| update t1 set data = 1; update t1 set data = 2; drop table t1; +create table t1 (f1 integer); +create table t2 (f2 integer); +create trigger t1_ai after insert on t1 +for each row insert into t2 values (new.f1+1); +create trigger t2_ai after insert on t2 +for each row insert into t1 values (new.f2+1); +insert into t1 values (1); +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +select * from t1; +f1 +1 +select * from t2; +f2 +2 +drop trigger t1_ai; +drop trigger t2_ai; +create trigger t1_bu before update on t1 +for each row insert into t1 values (2); +update t1 set f1= 10; +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +select * from t1; +f1 +1 +drop trigger t1_bu; +create trigger t1_bu before update on t1 +for each row delete from t1 where f1=new.f1; +update t1 set f1= 10; +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +select * from t1; +f1 +1 +drop trigger t1_bu; +create trigger t1_bi before insert on t1 +for each row set new.f1=(select sum(f1) from t1); +insert into t1 values (3); +select * from t1; +f1 +1 +1 +drop trigger t1_bi; +drop tables t1, t2; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 349bd148814..b9abdb1b74a 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -409,6 +409,35 @@ lock tables mysql.proc write| unlock tables| +# +# Check that in functions we don't allow to update tables which +# are used by statements which invoke these functions. +# +--disable_warnings +drop function if exists f1| +--enable_warnings +create function f1(i int) returns int +begin + insert into t1 (val) values (i); + return 0; +end| +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +select val, f1(val) from t1| +# Table alias should not matter +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +select val, f1(val) from t1 as tab| +select * from t1| +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +update t1 set val= f1(val)| +select * from t1| +# But this should be OK +select f1(17)| +select * from t1| +# Cleanup +delete from t1 where val= 17| +drop function f1| + + # # BUG#1965 # diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 49ec42568ad..62f14941579 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -685,3 +685,39 @@ update t1 set data = 2; connection default; drop table t1; + +# Test for bug #11896 "Partial locking in case of recursive trigger +# definitions". Recursion in triggers should not be allowed. +# We also should not allow to change tables which are used in +# statements invoking this trigger. +create table t1 (f1 integer); +create table t2 (f2 integer); +create trigger t1_ai after insert on t1 + for each row insert into t2 values (new.f1+1); +create trigger t2_ai after insert on t2 + for each row insert into t1 values (new.f2+1); +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +insert into t1 values (1); +select * from t1; +select * from t2; +drop trigger t1_ai; +drop trigger t2_ai; +create trigger t1_bu before update on t1 + for each row insert into t1 values (2); +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +update t1 set f1= 10; +select * from t1; +drop trigger t1_bu; +create trigger t1_bu before update on t1 + for each row delete from t1 where f1=new.f1; +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +update t1 set f1= 10; +select * from t1; +drop trigger t1_bu; +# This should work tough +create trigger t1_bi before insert on t1 + for each row set new.f1=(select sum(f1) from t1); +insert into t1 values (3); +select * from t1; +drop trigger t1_bi; +drop tables t1, t2; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a035426db57..28bb4d4dec5 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5395,3 +5395,5 @@ ER_TOO_BIG_DISPLAYWIDTH 42000 S1009 eng "Display width out of range for column '%-.64s' (max = %d)" ER_XAER_DUPID XAE08 eng "XAER_DUPID: The XID already exists" +ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG + eng "Can't update table '%-.64s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger." diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4c1b8347466..a1f76536f1f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1046,35 +1046,61 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { // Using table locks TABLE *best_table= 0; int best_distance= INT_MIN; + bool check_if_used= thd->prelocked_mode && + ((int) table_list->lock_type >= + (int) TL_WRITE_ALLOW_WRITE); for (table=thd->open_tables; table ; table=table->next) { if (table->s->key_length == key_length && - !memcmp(table->s->table_cache_key, key, key_length) && - !my_strcasecmp(system_charset_info, table->alias, alias) && - table->query_id != thd->query_id && /* skip tables already used */ - !(thd->prelocked_mode && table->query_id)) + !memcmp(table->s->table_cache_key, key, key_length)) { - int distance= ((int) table->reginfo.lock_type - - (int) table_list->lock_type); - /* - Find a table that either has the exact lock type requested, - or has the best suitable lock. In case there is no locked - table that has an equal or higher lock than requested, - we us the closest matching lock to be able to produce an error - message about wrong lock mode on the table. The best_table is changed - if bd < 0 <= d or bd < d < 0 or 0 <= d < bd. - - distance < 0 - No suitable lock found - distance > 0 - we have lock mode higher then we require - distance == 0 - we have lock mode exactly which we need - */ - if (best_distance < 0 && distance > best_distance || - distance >= 0 && distance < best_distance) + if (check_if_used && table->query_id && + table->query_id != thd->query_id) { - best_distance= distance; - best_table= table; - if (best_distance == 0) // Found perfect lock - break; + /* + If we are in stored function or trigger we should ensure that + we won't change table that is already used by calling statement. + So if we are opening table for writing, we should check that it + is not already open by some calling stamement. + */ + my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0), + table->s->table_name); + DBUG_RETURN(0); + } + if (!my_strcasecmp(system_charset_info, table->alias, alias) && + table->query_id != thd->query_id && /* skip tables already used */ + !(thd->prelocked_mode && table->query_id)) + { + int distance= ((int) table->reginfo.lock_type - + (int) table_list->lock_type); + /* + Find a table that either has the exact lock type requested, + or has the best suitable lock. In case there is no locked + table that has an equal or higher lock than requested, + we us the closest matching lock to be able to produce an error + message about wrong lock mode on the table. The best_table + is changed if bd < 0 <= d or bd < d < 0 or 0 <= d < bd. + + distance < 0 - No suitable lock found + distance > 0 - we have lock mode higher then we require + distance == 0 - we have lock mode exactly which we need + */ + if (best_distance < 0 && distance > best_distance || + distance >= 0 && distance < best_distance) + { + best_distance= distance; + best_table= table; + if (best_distance == 0 && !check_if_used) + { + /* + If we have found perfect match and we don't need to check that + table is not used by one of calling statements (assuming that + we are inside of function or trigger) we can finish iterating + through open tables list. + */ + break; + } + } } } } From 79339063254e2166bc1ed6470e0851fe5c3011a8 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Thu, 18 Aug 2005 17:29:24 +0200 Subject: [PATCH 160/230] mysqld.dsp: Added archive and example storage engine to Windows build ha_example.cc, ha_archive.cc: Windows fix, use relative include path to "mysql_priv.h" ha_archive.h: Windows VC6 compile needed (char*) cast of byte var mysqltest.dsp, mysql_test_run_new.dsp: Added /FD flag, to avoid include file warnings --- VC++Files/client/mysqltest.dsp | 12 +++++------ VC++Files/mysql-test/mysql_test_run_new.dsp | 8 ++++---- VC++Files/sql/mysqld.dsp | 22 ++++++++++++++------- sql/examples/ha_archive.cc | 2 +- sql/examples/ha_archive.h | 2 +- sql/examples/ha_example.cc | 2 +- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/VC++Files/client/mysqltest.dsp b/VC++Files/client/mysqltest.dsp index e705b17b0f0..1c636c4d078 100644 --- a/VC++Files/client/mysqltest.dsp +++ b/VC++Files/client/mysqltest.dsp @@ -42,8 +42,8 @@ RSC=rc.exe # PROP Output_Dir ".\debug" # PROP Intermediate_Dir ".\debug" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /c /GX -# ADD CPP /nologo /MTd /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /c /GX +# ADD BASE CPP /nologo /MTd /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /FD /c /GX +# ADD CPP /nologo /MTd /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /FD /c /GX # ADD BASE MTL /nologo /tlb".\debug\mysqltest.tlb" /win32 # ADD MTL /nologo /tlb".\debug\mysqltest.tlb" /win32 # ADD BASE RSC /l 1033 /d "_DEBUG" @@ -67,8 +67,8 @@ LINK32=link.exe # PROP Output_Dir ".\classic" # PROP Intermediate_Dir ".\classic" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /c /GX -# ADD CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /c /GX +# ADD BASE CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /FD /c /GX +# ADD CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /FD /c /GX # ADD BASE MTL /nologo /tlb".\classic\mysqltest.tlb" /win32 # ADD MTL /nologo /tlb".\classic\mysqltest.tlb" /win32 # ADD BASE RSC /l 1033 /d "NDEBUG" @@ -92,8 +92,8 @@ LINK32=link.exe # PROP Output_Dir ".\release" # PROP Intermediate_Dir ".\release" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /c /GX -# ADD CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /c /GX +# ADD BASE CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /FD /c /GX +# ADD CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /FD /c /GX # ADD BASE MTL /nologo /tlb".\release\mysqltest.tlb" /win32 # ADD MTL /nologo /tlb".\release\mysqltest.tlb" /win32 # ADD BASE RSC /l 1033 /d "NDEBUG" diff --git a/VC++Files/mysql-test/mysql_test_run_new.dsp b/VC++Files/mysql-test/mysql_test_run_new.dsp index 467ff939502..5ff07f0994d 100644 --- a/VC++Files/mysql-test/mysql_test_run_new.dsp +++ b/VC++Files/mysql-test/mysql_test_run_new.dsp @@ -41,8 +41,8 @@ RSC=rc.exe # PROP Output_Dir ".\Debug" # PROP Intermediate_Dir ".\Debug" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /I "../include" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /Fp".\Debug/mysql_test_run_new.pch" /Fo".\Debug/" /Fd".\Debug/" /GZ /c /GX -# ADD CPP /nologo /MTd /I "../include" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /Fp".\Debug/mysql_test_run_new.pch" /Fo".\Debug/" /Fd".\Debug/" /GZ /c /GX +# ADD BASE CPP /nologo /MTd /I "../include" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /Fp".\Debug/mysql_test_run_new.pch" /Fo".\Debug/" /Fd".\Debug/" /GZ /FD /c /GX +# ADD CPP /nologo /MTd /I "../include" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /Fp".\Debug/mysql_test_run_new.pch" /Fo".\Debug/" /Fd".\Debug/" /GZ /FD /c /GX # ADD BASE MTL /nologo /tlb".\Debug\mysql_test_run_new.tlb" /win32 # ADD MTL /nologo /tlb".\Debug\mysql_test_run_new.tlb" /win32 # ADD BASE RSC /l 1033 @@ -66,8 +66,8 @@ LINK32=link.exe # PROP Output_Dir ".\Release" # PROP Intermediate_Dir ".\Release" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /I "../include" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /GF /Gy /Fp".\Release/mysql_test_run_new.pch" /Fo".\Release/" /Fd".\Release/" /c /GX -# ADD CPP /nologo /MTd /I "../include" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /GF /Gy /Fp".\Release/mysql_test_run_new.pch" /Fo".\Release/" /Fd".\Release/" /c /GX +# ADD BASE CPP /nologo /MTd /I "../include" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /GF /Gy /Fp".\Release/mysql_test_run_new.pch" /Fo".\Release/" /Fd".\Release/" /FD /c /GX +# ADD CPP /nologo /MTd /I "../include" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /GF /Gy /Fp".\Release/mysql_test_run_new.pch" /Fo".\Release/" /Fd".\Release/" /FD /c /GX # ADD BASE MTL /nologo /tlb".\Release\mysql_test_run_new.tlb" /win32 # ADD MTL /nologo /tlb".\Release\mysql_test_run_new.tlb" /win32 # ADD BASE RSC /l 1033 diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index 6a33889da53..4034ac9f5d0 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -49,7 +49,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../zlib" /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../zlib" /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x410 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -75,7 +75,7 @@ LINK32=xilink6.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../zlib" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_BLACKHOLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c +# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../zlib" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_EXAMPLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c # SUBTRACT CPP /Fr /YX # ADD BASE RSC /l 0x410 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -102,7 +102,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G5 /MT /W3 /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /D "DBUG_OFF" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x410 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -130,7 +130,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../zlib" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_BLACKHOLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt-max /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../zlib" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_EXAMPLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt-max /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -159,7 +159,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../zlib" /D "NDEBUG" /D "DBUG_OFF" /D "USE_SYMDIR" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_BLACKHOLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-max /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../zlib" /D "NDEBUG" /D "DBUG_OFF" /D "USE_SYMDIR" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_EXAMPLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-max /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -215,7 +215,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "USE_SYMDIR" /D "HAVE_DLOPEN" /D "NDEBUG" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_MBCS" /D "HAVE_DLOPEN" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "NDEBUG" /D "_WINDOWS" /D "_CONSOLE" /D MYSQL_SERVER_SUFFIX=-pro /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_MBCS" /D "HAVE_DLOPEN" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "DBUG_OFF" /D "NDEBUG" /D "_WINDOWS" /D "_CONSOLE" /D MYSQL_SERVER_SUFFIX=-pro /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -272,7 +272,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "USE_SYMDIR" /D "HAVE_DLOPEN" /D "NDEBUG" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D LICENSE=Commercial /D "NDEBUG" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-pro-nt /FD +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D LICENSE=Commercial /D "NDEBUG" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-pro-nt /FD # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -451,6 +451,14 @@ SOURCE=.\gstream.cpp # End Source File # Begin Source File +SOURCE=.\examples\ha_archive.cpp +# End Source File +# Begin Source File + +SOURCE=.\examples\ha_example.cpp +# End Source File +# Begin Source File + SOURCE=.\ha_blackhole.cpp # End Source File # Begin Source File diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index 10712c2e3be..b125f435cfa 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -18,7 +18,7 @@ #pragma implementation // gcc: Class implementation #endif -#include +#include "../mysql_priv.h" #ifdef HAVE_ARCHIVE_DB #include "ha_archive.h" diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 7ab463b6661..52300fda8a2 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -58,7 +58,7 @@ public: ha_archive(TABLE *table): handler(table) { /* Set our original buffer from pre-allocated memory */ - buffer.set(byte_buffer, IO_SIZE, system_charset_info); + buffer.set((char*)byte_buffer, IO_SIZE, system_charset_info); /* The size of the offset value we will use for position() */ ref_length = sizeof(z_off_t); diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index 31e4e97c5c7..b3edce5ba4a 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -67,7 +67,7 @@ #pragma implementation // gcc: Class implementation #endif -#include +#include "../mysql_priv.h" #ifdef HAVE_EXAMPLE_DB #include "ha_example.h" From 3bfa514655295ce15b12c7182f1f06ed0ddb961d Mon Sep 17 00:00:00 2001 From: "jani@a193-229-222-105.elisa-laajakaista.fi" <> Date: Thu, 18 Aug 2005 21:22:35 +0300 Subject: [PATCH 161/230] Changes for Netware. This is needed when building against newer Libc than we've used before. --- include/config-netware.h | 12 ++++++++++++ sql/mysqld.cc | 1 + 2 files changed, 13 insertions(+) diff --git a/include/config-netware.h b/include/config-netware.h index c8eba43b86f..1b24655ee89 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -51,6 +51,18 @@ extern "C" { #define HAVE_PTHREAD_YIELD_ZERO_ARG 1 #define HAVE_BROKEN_REALPATH 1 +/* changes made to make use of LibC-June-2004 for building purpose */ +#undef HAVE_POSIX_SIGNALS +#undef HAVE_PTHREAD_ATTR_SETSCOPE +#undef HAVE_ALLOC_A +#undef HAVE_FINITE +#undef HAVE_GETPWNAM +#undef HAVE_GETPWUID +#undef HAVE_PTHREAD_SETSCHEDPARAM +#undef HAVE_READLINK +#undef HAVE_STPCPY +/* changes end */ + /* no libc crypt() function */ #ifdef HAVE_OPENSSL #define HAVE_CRYPT 1 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b5a292fec28..55995a71980 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -152,6 +152,7 @@ int deny_severity = LOG_WARNING; #define zVOLSTATE_MAINTENANCE 3 #ifdef __NETWARE__ +#include #include #include #include From c6ee26ab4532aae678d76b125f667653473d6fb7 Mon Sep 17 00:00:00 2001 From: "jani@a193-229-222-105.elisa-laajakaista.fi" <> Date: Thu, 18 Aug 2005 21:26:25 +0300 Subject: [PATCH 162/230] Some minor fixes for Netware. These were required after we started building against a later version of libc. --- include/config-netware.h | 12 ++++++++++++ netware/BUILD/nwbootstrap | 8 +------- sql/mysqld.cc | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/config-netware.h b/include/config-netware.h index 3e145f566a1..578975a1cea 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -50,6 +50,18 @@ extern "C" { #define HAVE_PTHREAD_YIELD_ZERO_ARG 1 #define HAVE_BROKEN_REALPATH 1 +/*required adjustments with LibC-June-2004 */ +#undef HAVE_POSIX_SIGNALS +#undef HAVE_PTHREAD_ATTR_SETSCOPE +#undef HAVE_ALLOCA_H +#undef HAVE_FINITE +#undef HAVE_GETPWNAM +#undef HAVE_GETPWUID +#undef HAVE_PTHREAD_SETSCHEDPARAM +#undef HAVE_READLINK +#undef HAVE_STPCPY +/*required adjustments with LibC-June-2004 */ + /* no libc crypt() function */ #ifdef HAVE_OPENSSL #define HAVE_CRYPT 1 diff --git a/netware/BUILD/nwbootstrap b/netware/BUILD/nwbootstrap index 2ba90e32fa7..a420aa8b64c 100755 --- a/netware/BUILD/nwbootstrap +++ b/netware/BUILD/nwbootstrap @@ -171,15 +171,9 @@ do rm $file.org done -# create the libmysql.imp file in netware folder from libmysql/libmysql.def -# file -echo "generating llibmysql.imp file..." -awk 'BEGIN{x=0;} x==1 {print $1;next} /EXPORTS/{x=1}' libmysql/libmysql.def > netware/libmysql.imp - # create the libmysql.imp file in netware folder from libmysql/libmysql.def file echo "generating llibmysql.imp file..." -awk 'BEGIN{x=0;} x==1 {print $1;next} /EXPORTS/{x=1}' libmysql/libmysql.def > netware/libmysql.imp - +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/sql/mysqld.cc b/sql/mysqld.cc index 82335e7d706..ac66874888b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -114,6 +114,7 @@ int deny_severity = LOG_WARNING; #endif #ifdef __NETWARE__ +#include #include #include #include From 86e5ddeb520f1963cc390425873f1fec61bf83a4 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Thu, 18 Aug 2005 22:27:12 +0200 Subject: [PATCH 163/230] ps_conv.inc: Adjustment of float results for Windows mysql-test-run.pl: Added --port to make MYSQL_DUMP and MYSQL_SHOW work on windows have_lowercase0.inc: new file --- mysql-test/include/have_lowercase0.inc | 4 ++++ mysql-test/include/ps_conv.inc | 16 ++++++++++++++++ mysql-test/mysql-test-run.pl | 2 ++ 3 files changed, 22 insertions(+) create mode 100644 mysql-test/include/have_lowercase0.inc diff --git a/mysql-test/include/have_lowercase0.inc b/mysql-test/include/have_lowercase0.inc new file mode 100644 index 00000000000..f967c18928b --- /dev/null +++ b/mysql-test/include/have_lowercase0.inc @@ -0,0 +1,4 @@ +--require r/lowercase0.require +--disable_query_log; +show variables like "lower_case_%"; +--enable_query_log; diff --git a/mysql-test/include/ps_conv.inc b/mysql-test/include/ps_conv.inc index 0a5bec26fe7..348526202ec 100644 --- a/mysql-test/include/ps_conv.inc +++ b/mysql-test/include/ps_conv.inc @@ -576,15 +576,19 @@ set @arg00= 9223372036854775807 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; # Use the minimum BIGINT from the manual # @@ -592,15 +596,19 @@ set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; set @arg00= '-9223372036854775808' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; # Numeric overflow of columns(c1, c2, c3, c4, c5, c12) with type not in @@ -610,8 +618,10 @@ set @arg00= 1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; # Attention: The columns(c1,c2,c3,c4,c5,c6) do not get the overflow, # because the string is treated as written integer and @@ -620,15 +630,19 @@ set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; # Attention: The columns(c1,c2,c3,c4,c5,c6) do not get the overflow, # because the string is treated as written integer and @@ -637,8 +651,10 @@ set @arg00= '-1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00 ; --vertical_results +--replace_result e+0 e+ execute my_select ; --horizontal_results +--replace_result e+0 e+ execute my_delete ; ########################## test of string types ########################## diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 456f481ce86..e72d8f5f683 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2043,6 +2043,7 @@ sub run_mysqltest ($) { my $tinfo= shift; my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . + "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'} --password="; if ( $opt_debug ) { @@ -2051,6 +2052,7 @@ sub run_mysqltest ($) { } my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " . + "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'} --password="; if ( $opt_debug ) { From 6fae8f6c8d263ce95a93951510643688b64fb59d Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Thu, 18 Aug 2005 15:18:26 -0700 Subject: [PATCH 164/230] Manual merge --- mysql-test/t/view.test | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 5635358120a..a5b72a16972 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1943,6 +1943,17 @@ create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00: select * from v1; drop view v1; +# +# Bug #10624 Views with multiple UNION and UNION ALL produce incorrect results +# +create table t1 (f1 int); +create table t2 (f1 int); +insert into t1 values (1); +insert into t2 values (2); +create view v1 as select * from t1 union select * from t2 union all select * from t2; +select * from v1; +drop view v1; +drop table t1,t2; # # Test for bug #10970: view referring a temporary table indirectly # From c594ab792179ced153d4b3073382b3ed1967c658 Mon Sep 17 00:00:00 2001 From: "sasha@asksasha.com" <> Date: Thu, 18 Aug 2005 21:40:14 -0600 Subject: [PATCH 165/230] updated patch for BUG#4680 (incomplete DROP DATABASE breaking replication). We binlog the DROP TABLE for each table that was actually dropped. Per Sergei's suggestion a fixed buffer for the DROP TABLE query is pre-allocated from THD pool, and logging now is done in batches - new batch is started if the buffer becomes full. Reduced memory usage by reusing the table list instead of accumulating a list of dropped table names. Also fixed the problem if the table was not actually dropped, eg due to permissions. Extended the test case to make sure batched query logging does work. --- .bzrignore | 2 + mysql-test/r/rpl_drop_db.result | 1005 +++++++++++++++++++++++++++++++ mysql-test/t/rpl_drop_db.test | 13 + sql/mysql_priv.h | 2 +- sql/sql_db.cc | 85 ++- sql/sql_table.cc | 23 +- sql/table.h | 3 + 7 files changed, 1085 insertions(+), 48 deletions(-) diff --git a/.bzrignore b/.bzrignore index 7a10ce9db69..f9f9c146692 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1054,3 +1054,5 @@ vio/test-sslclient vio/test-sslserver vio/viotest-ssl ndb/tools/ndb_config +support-files/MacOSX/postflight +support-files/MacOSX/preflight diff --git a/mysql-test/r/rpl_drop_db.result b/mysql-test/r/rpl_drop_db.result index bafbfe3a1ed..01a2af5341b 100644 --- a/mysql-test/r/rpl_drop_db.result +++ b/mysql-test/r/rpl_drop_db.result @@ -16,6 +16,1011 @@ ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17) use d1; show tables; Tables_in_d1 +create table d1.t1000(n int); +create table d1.t999(n int); +create table d1.t998(n int); +create table d1.t997(n int); +create table d1.t996(n int); +create table d1.t995(n int); +create table d1.t994(n int); +create table d1.t993(n int); +create table d1.t992(n int); +create table d1.t991(n int); +create table d1.t990(n int); +create table d1.t989(n int); +create table d1.t988(n int); +create table d1.t987(n int); +create table d1.t986(n int); +create table d1.t985(n int); +create table d1.t984(n int); +create table d1.t983(n int); +create table d1.t982(n int); +create table d1.t981(n int); +create table d1.t980(n int); +create table d1.t979(n int); +create table d1.t978(n int); +create table d1.t977(n int); +create table d1.t976(n int); +create table d1.t975(n int); +create table d1.t974(n int); +create table d1.t973(n int); +create table d1.t972(n int); +create table d1.t971(n int); +create table d1.t970(n int); +create table d1.t969(n int); +create table d1.t968(n int); +create table d1.t967(n int); +create table d1.t966(n int); +create table d1.t965(n int); +create table d1.t964(n int); +create table d1.t963(n int); +create table d1.t962(n int); +create table d1.t961(n int); +create table d1.t960(n int); +create table d1.t959(n int); +create table d1.t958(n int); +create table d1.t957(n int); +create table d1.t956(n int); +create table d1.t955(n int); +create table d1.t954(n int); +create table d1.t953(n int); +create table d1.t952(n int); +create table d1.t951(n int); +create table d1.t950(n int); +create table d1.t949(n int); +create table d1.t948(n int); +create table d1.t947(n int); +create table d1.t946(n int); +create table d1.t945(n int); +create table d1.t944(n int); +create table d1.t943(n int); +create table d1.t942(n int); +create table d1.t941(n int); +create table d1.t940(n int); +create table d1.t939(n int); +create table d1.t938(n int); +create table d1.t937(n int); +create table d1.t936(n int); +create table d1.t935(n int); +create table d1.t934(n int); +create table d1.t933(n int); +create table d1.t932(n int); +create table d1.t931(n int); +create table d1.t930(n int); +create table d1.t929(n int); +create table d1.t928(n int); +create table d1.t927(n int); +create table d1.t926(n int); +create table d1.t925(n int); +create table d1.t924(n int); +create table d1.t923(n int); +create table d1.t922(n int); +create table d1.t921(n int); +create table d1.t920(n int); +create table d1.t919(n int); +create table d1.t918(n int); +create table d1.t917(n int); +create table d1.t916(n int); +create table d1.t915(n int); +create table d1.t914(n int); +create table d1.t913(n int); +create table d1.t912(n int); +create table d1.t911(n int); +create table d1.t910(n int); +create table d1.t909(n int); +create table d1.t908(n int); +create table d1.t907(n int); +create table d1.t906(n int); +create table d1.t905(n int); +create table d1.t904(n int); +create table d1.t903(n int); +create table d1.t902(n int); +create table d1.t901(n int); +create table d1.t900(n int); +create table d1.t899(n int); +create table d1.t898(n int); +create table d1.t897(n int); +create table d1.t896(n int); +create table d1.t895(n int); +create table d1.t894(n int); +create table d1.t893(n int); +create table d1.t892(n int); +create table d1.t891(n int); +create table d1.t890(n int); +create table d1.t889(n int); +create table d1.t888(n int); +create table d1.t887(n int); +create table d1.t886(n int); +create table d1.t885(n int); +create table d1.t884(n int); +create table d1.t883(n int); +create table d1.t882(n int); +create table d1.t881(n int); +create table d1.t880(n int); +create table d1.t879(n int); +create table d1.t878(n int); +create table d1.t877(n int); +create table d1.t876(n int); +create table d1.t875(n int); +create table d1.t874(n int); +create table d1.t873(n int); +create table d1.t872(n int); +create table d1.t871(n int); +create table d1.t870(n int); +create table d1.t869(n int); +create table d1.t868(n int); +create table d1.t867(n int); +create table d1.t866(n int); +create table d1.t865(n int); +create table d1.t864(n int); +create table d1.t863(n int); +create table d1.t862(n int); +create table d1.t861(n int); +create table d1.t860(n int); +create table d1.t859(n int); +create table d1.t858(n int); +create table d1.t857(n int); +create table d1.t856(n int); +create table d1.t855(n int); +create table d1.t854(n int); +create table d1.t853(n int); +create table d1.t852(n int); +create table d1.t851(n int); +create table d1.t850(n int); +create table d1.t849(n int); +create table d1.t848(n int); +create table d1.t847(n int); +create table d1.t846(n int); +create table d1.t845(n int); +create table d1.t844(n int); +create table d1.t843(n int); +create table d1.t842(n int); +create table d1.t841(n int); +create table d1.t840(n int); +create table d1.t839(n int); +create table d1.t838(n int); +create table d1.t837(n int); +create table d1.t836(n int); +create table d1.t835(n int); +create table d1.t834(n int); +create table d1.t833(n int); +create table d1.t832(n int); +create table d1.t831(n int); +create table d1.t830(n int); +create table d1.t829(n int); +create table d1.t828(n int); +create table d1.t827(n int); +create table d1.t826(n int); +create table d1.t825(n int); +create table d1.t824(n int); +create table d1.t823(n int); +create table d1.t822(n int); +create table d1.t821(n int); +create table d1.t820(n int); +create table d1.t819(n int); +create table d1.t818(n int); +create table d1.t817(n int); +create table d1.t816(n int); +create table d1.t815(n int); +create table d1.t814(n int); +create table d1.t813(n int); +create table d1.t812(n int); +create table d1.t811(n int); +create table d1.t810(n int); +create table d1.t809(n int); +create table d1.t808(n int); +create table d1.t807(n int); +create table d1.t806(n int); +create table d1.t805(n int); +create table d1.t804(n int); +create table d1.t803(n int); +create table d1.t802(n int); +create table d1.t801(n int); +create table d1.t800(n int); +create table d1.t799(n int); +create table d1.t798(n int); +create table d1.t797(n int); +create table d1.t796(n int); +create table d1.t795(n int); +create table d1.t794(n int); +create table d1.t793(n int); +create table d1.t792(n int); +create table d1.t791(n int); +create table d1.t790(n int); +create table d1.t789(n int); +create table d1.t788(n int); +create table d1.t787(n int); +create table d1.t786(n int); +create table d1.t785(n int); +create table d1.t784(n int); +create table d1.t783(n int); +create table d1.t782(n int); +create table d1.t781(n int); +create table d1.t780(n int); +create table d1.t779(n int); +create table d1.t778(n int); +create table d1.t777(n int); +create table d1.t776(n int); +create table d1.t775(n int); +create table d1.t774(n int); +create table d1.t773(n int); +create table d1.t772(n int); +create table d1.t771(n int); +create table d1.t770(n int); +create table d1.t769(n int); +create table d1.t768(n int); +create table d1.t767(n int); +create table d1.t766(n int); +create table d1.t765(n int); +create table d1.t764(n int); +create table d1.t763(n int); +create table d1.t762(n int); +create table d1.t761(n int); +create table d1.t760(n int); +create table d1.t759(n int); +create table d1.t758(n int); +create table d1.t757(n int); +create table d1.t756(n int); +create table d1.t755(n int); +create table d1.t754(n int); +create table d1.t753(n int); +create table d1.t752(n int); +create table d1.t751(n int); +create table d1.t750(n int); +create table d1.t749(n int); +create table d1.t748(n int); +create table d1.t747(n int); +create table d1.t746(n int); +create table d1.t745(n int); +create table d1.t744(n int); +create table d1.t743(n int); +create table d1.t742(n int); +create table d1.t741(n int); +create table d1.t740(n int); +create table d1.t739(n int); +create table d1.t738(n int); +create table d1.t737(n int); +create table d1.t736(n int); +create table d1.t735(n int); +create table d1.t734(n int); +create table d1.t733(n int); +create table d1.t732(n int); +create table d1.t731(n int); +create table d1.t730(n int); +create table d1.t729(n int); +create table d1.t728(n int); +create table d1.t727(n int); +create table d1.t726(n int); +create table d1.t725(n int); +create table d1.t724(n int); +create table d1.t723(n int); +create table d1.t722(n int); +create table d1.t721(n int); +create table d1.t720(n int); +create table d1.t719(n int); +create table d1.t718(n int); +create table d1.t717(n int); +create table d1.t716(n int); +create table d1.t715(n int); +create table d1.t714(n int); +create table d1.t713(n int); +create table d1.t712(n int); +create table d1.t711(n int); +create table d1.t710(n int); +create table d1.t709(n int); +create table d1.t708(n int); +create table d1.t707(n int); +create table d1.t706(n int); +create table d1.t705(n int); +create table d1.t704(n int); +create table d1.t703(n int); +create table d1.t702(n int); +create table d1.t701(n int); +create table d1.t700(n int); +create table d1.t699(n int); +create table d1.t698(n int); +create table d1.t697(n int); +create table d1.t696(n int); +create table d1.t695(n int); +create table d1.t694(n int); +create table d1.t693(n int); +create table d1.t692(n int); +create table d1.t691(n int); +create table d1.t690(n int); +create table d1.t689(n int); +create table d1.t688(n int); +create table d1.t687(n int); +create table d1.t686(n int); +create table d1.t685(n int); +create table d1.t684(n int); +create table d1.t683(n int); +create table d1.t682(n int); +create table d1.t681(n int); +create table d1.t680(n int); +create table d1.t679(n int); +create table d1.t678(n int); +create table d1.t677(n int); +create table d1.t676(n int); +create table d1.t675(n int); +create table d1.t674(n int); +create table d1.t673(n int); +create table d1.t672(n int); +create table d1.t671(n int); +create table d1.t670(n int); +create table d1.t669(n int); +create table d1.t668(n int); +create table d1.t667(n int); +create table d1.t666(n int); +create table d1.t665(n int); +create table d1.t664(n int); +create table d1.t663(n int); +create table d1.t662(n int); +create table d1.t661(n int); +create table d1.t660(n int); +create table d1.t659(n int); +create table d1.t658(n int); +create table d1.t657(n int); +create table d1.t656(n int); +create table d1.t655(n int); +create table d1.t654(n int); +create table d1.t653(n int); +create table d1.t652(n int); +create table d1.t651(n int); +create table d1.t650(n int); +create table d1.t649(n int); +create table d1.t648(n int); +create table d1.t647(n int); +create table d1.t646(n int); +create table d1.t645(n int); +create table d1.t644(n int); +create table d1.t643(n int); +create table d1.t642(n int); +create table d1.t641(n int); +create table d1.t640(n int); +create table d1.t639(n int); +create table d1.t638(n int); +create table d1.t637(n int); +create table d1.t636(n int); +create table d1.t635(n int); +create table d1.t634(n int); +create table d1.t633(n int); +create table d1.t632(n int); +create table d1.t631(n int); +create table d1.t630(n int); +create table d1.t629(n int); +create table d1.t628(n int); +create table d1.t627(n int); +create table d1.t626(n int); +create table d1.t625(n int); +create table d1.t624(n int); +create table d1.t623(n int); +create table d1.t622(n int); +create table d1.t621(n int); +create table d1.t620(n int); +create table d1.t619(n int); +create table d1.t618(n int); +create table d1.t617(n int); +create table d1.t616(n int); +create table d1.t615(n int); +create table d1.t614(n int); +create table d1.t613(n int); +create table d1.t612(n int); +create table d1.t611(n int); +create table d1.t610(n int); +create table d1.t609(n int); +create table d1.t608(n int); +create table d1.t607(n int); +create table d1.t606(n int); +create table d1.t605(n int); +create table d1.t604(n int); +create table d1.t603(n int); +create table d1.t602(n int); +create table d1.t601(n int); +create table d1.t600(n int); +create table d1.t599(n int); +create table d1.t598(n int); +create table d1.t597(n int); +create table d1.t596(n int); +create table d1.t595(n int); +create table d1.t594(n int); +create table d1.t593(n int); +create table d1.t592(n int); +create table d1.t591(n int); +create table d1.t590(n int); +create table d1.t589(n int); +create table d1.t588(n int); +create table d1.t587(n int); +create table d1.t586(n int); +create table d1.t585(n int); +create table d1.t584(n int); +create table d1.t583(n int); +create table d1.t582(n int); +create table d1.t581(n int); +create table d1.t580(n int); +create table d1.t579(n int); +create table d1.t578(n int); +create table d1.t577(n int); +create table d1.t576(n int); +create table d1.t575(n int); +create table d1.t574(n int); +create table d1.t573(n int); +create table d1.t572(n int); +create table d1.t571(n int); +create table d1.t570(n int); +create table d1.t569(n int); +create table d1.t568(n int); +create table d1.t567(n int); +create table d1.t566(n int); +create table d1.t565(n int); +create table d1.t564(n int); +create table d1.t563(n int); +create table d1.t562(n int); +create table d1.t561(n int); +create table d1.t560(n int); +create table d1.t559(n int); +create table d1.t558(n int); +create table d1.t557(n int); +create table d1.t556(n int); +create table d1.t555(n int); +create table d1.t554(n int); +create table d1.t553(n int); +create table d1.t552(n int); +create table d1.t551(n int); +create table d1.t550(n int); +create table d1.t549(n int); +create table d1.t548(n int); +create table d1.t547(n int); +create table d1.t546(n int); +create table d1.t545(n int); +create table d1.t544(n int); +create table d1.t543(n int); +create table d1.t542(n int); +create table d1.t541(n int); +create table d1.t540(n int); +create table d1.t539(n int); +create table d1.t538(n int); +create table d1.t537(n int); +create table d1.t536(n int); +create table d1.t535(n int); +create table d1.t534(n int); +create table d1.t533(n int); +create table d1.t532(n int); +create table d1.t531(n int); +create table d1.t530(n int); +create table d1.t529(n int); +create table d1.t528(n int); +create table d1.t527(n int); +create table d1.t526(n int); +create table d1.t525(n int); +create table d1.t524(n int); +create table d1.t523(n int); +create table d1.t522(n int); +create table d1.t521(n int); +create table d1.t520(n int); +create table d1.t519(n int); +create table d1.t518(n int); +create table d1.t517(n int); +create table d1.t516(n int); +create table d1.t515(n int); +create table d1.t514(n int); +create table d1.t513(n int); +create table d1.t512(n int); +create table d1.t511(n int); +create table d1.t510(n int); +create table d1.t509(n int); +create table d1.t508(n int); +create table d1.t507(n int); +create table d1.t506(n int); +create table d1.t505(n int); +create table d1.t504(n int); +create table d1.t503(n int); +create table d1.t502(n int); +create table d1.t501(n int); +create table d1.t500(n int); +create table d1.t499(n int); +create table d1.t498(n int); +create table d1.t497(n int); +create table d1.t496(n int); +create table d1.t495(n int); +create table d1.t494(n int); +create table d1.t493(n int); +create table d1.t492(n int); +create table d1.t491(n int); +create table d1.t490(n int); +create table d1.t489(n int); +create table d1.t488(n int); +create table d1.t487(n int); +create table d1.t486(n int); +create table d1.t485(n int); +create table d1.t484(n int); +create table d1.t483(n int); +create table d1.t482(n int); +create table d1.t481(n int); +create table d1.t480(n int); +create table d1.t479(n int); +create table d1.t478(n int); +create table d1.t477(n int); +create table d1.t476(n int); +create table d1.t475(n int); +create table d1.t474(n int); +create table d1.t473(n int); +create table d1.t472(n int); +create table d1.t471(n int); +create table d1.t470(n int); +create table d1.t469(n int); +create table d1.t468(n int); +create table d1.t467(n int); +create table d1.t466(n int); +create table d1.t465(n int); +create table d1.t464(n int); +create table d1.t463(n int); +create table d1.t462(n int); +create table d1.t461(n int); +create table d1.t460(n int); +create table d1.t459(n int); +create table d1.t458(n int); +create table d1.t457(n int); +create table d1.t456(n int); +create table d1.t455(n int); +create table d1.t454(n int); +create table d1.t453(n int); +create table d1.t452(n int); +create table d1.t451(n int); +create table d1.t450(n int); +create table d1.t449(n int); +create table d1.t448(n int); +create table d1.t447(n int); +create table d1.t446(n int); +create table d1.t445(n int); +create table d1.t444(n int); +create table d1.t443(n int); +create table d1.t442(n int); +create table d1.t441(n int); +create table d1.t440(n int); +create table d1.t439(n int); +create table d1.t438(n int); +create table d1.t437(n int); +create table d1.t436(n int); +create table d1.t435(n int); +create table d1.t434(n int); +create table d1.t433(n int); +create table d1.t432(n int); +create table d1.t431(n int); +create table d1.t430(n int); +create table d1.t429(n int); +create table d1.t428(n int); +create table d1.t427(n int); +create table d1.t426(n int); +create table d1.t425(n int); +create table d1.t424(n int); +create table d1.t423(n int); +create table d1.t422(n int); +create table d1.t421(n int); +create table d1.t420(n int); +create table d1.t419(n int); +create table d1.t418(n int); +create table d1.t417(n int); +create table d1.t416(n int); +create table d1.t415(n int); +create table d1.t414(n int); +create table d1.t413(n int); +create table d1.t412(n int); +create table d1.t411(n int); +create table d1.t410(n int); +create table d1.t409(n int); +create table d1.t408(n int); +create table d1.t407(n int); +create table d1.t406(n int); +create table d1.t405(n int); +create table d1.t404(n int); +create table d1.t403(n int); +create table d1.t402(n int); +create table d1.t401(n int); +create table d1.t400(n int); +create table d1.t399(n int); +create table d1.t398(n int); +create table d1.t397(n int); +create table d1.t396(n int); +create table d1.t395(n int); +create table d1.t394(n int); +create table d1.t393(n int); +create table d1.t392(n int); +create table d1.t391(n int); +create table d1.t390(n int); +create table d1.t389(n int); +create table d1.t388(n int); +create table d1.t387(n int); +create table d1.t386(n int); +create table d1.t385(n int); +create table d1.t384(n int); +create table d1.t383(n int); +create table d1.t382(n int); +create table d1.t381(n int); +create table d1.t380(n int); +create table d1.t379(n int); +create table d1.t378(n int); +create table d1.t377(n int); +create table d1.t376(n int); +create table d1.t375(n int); +create table d1.t374(n int); +create table d1.t373(n int); +create table d1.t372(n int); +create table d1.t371(n int); +create table d1.t370(n int); +create table d1.t369(n int); +create table d1.t368(n int); +create table d1.t367(n int); +create table d1.t366(n int); +create table d1.t365(n int); +create table d1.t364(n int); +create table d1.t363(n int); +create table d1.t362(n int); +create table d1.t361(n int); +create table d1.t360(n int); +create table d1.t359(n int); +create table d1.t358(n int); +create table d1.t357(n int); +create table d1.t356(n int); +create table d1.t355(n int); +create table d1.t354(n int); +create table d1.t353(n int); +create table d1.t352(n int); +create table d1.t351(n int); +create table d1.t350(n int); +create table d1.t349(n int); +create table d1.t348(n int); +create table d1.t347(n int); +create table d1.t346(n int); +create table d1.t345(n int); +create table d1.t344(n int); +create table d1.t343(n int); +create table d1.t342(n int); +create table d1.t341(n int); +create table d1.t340(n int); +create table d1.t339(n int); +create table d1.t338(n int); +create table d1.t337(n int); +create table d1.t336(n int); +create table d1.t335(n int); +create table d1.t334(n int); +create table d1.t333(n int); +create table d1.t332(n int); +create table d1.t331(n int); +create table d1.t330(n int); +create table d1.t329(n int); +create table d1.t328(n int); +create table d1.t327(n int); +create table d1.t326(n int); +create table d1.t325(n int); +create table d1.t324(n int); +create table d1.t323(n int); +create table d1.t322(n int); +create table d1.t321(n int); +create table d1.t320(n int); +create table d1.t319(n int); +create table d1.t318(n int); +create table d1.t317(n int); +create table d1.t316(n int); +create table d1.t315(n int); +create table d1.t314(n int); +create table d1.t313(n int); +create table d1.t312(n int); +create table d1.t311(n int); +create table d1.t310(n int); +create table d1.t309(n int); +create table d1.t308(n int); +create table d1.t307(n int); +create table d1.t306(n int); +create table d1.t305(n int); +create table d1.t304(n int); +create table d1.t303(n int); +create table d1.t302(n int); +create table d1.t301(n int); +create table d1.t300(n int); +create table d1.t299(n int); +create table d1.t298(n int); +create table d1.t297(n int); +create table d1.t296(n int); +create table d1.t295(n int); +create table d1.t294(n int); +create table d1.t293(n int); +create table d1.t292(n int); +create table d1.t291(n int); +create table d1.t290(n int); +create table d1.t289(n int); +create table d1.t288(n int); +create table d1.t287(n int); +create table d1.t286(n int); +create table d1.t285(n int); +create table d1.t284(n int); +create table d1.t283(n int); +create table d1.t282(n int); +create table d1.t281(n int); +create table d1.t280(n int); +create table d1.t279(n int); +create table d1.t278(n int); +create table d1.t277(n int); +create table d1.t276(n int); +create table d1.t275(n int); +create table d1.t274(n int); +create table d1.t273(n int); +create table d1.t272(n int); +create table d1.t271(n int); +create table d1.t270(n int); +create table d1.t269(n int); +create table d1.t268(n int); +create table d1.t267(n int); +create table d1.t266(n int); +create table d1.t265(n int); +create table d1.t264(n int); +create table d1.t263(n int); +create table d1.t262(n int); +create table d1.t261(n int); +create table d1.t260(n int); +create table d1.t259(n int); +create table d1.t258(n int); +create table d1.t257(n int); +create table d1.t256(n int); +create table d1.t255(n int); +create table d1.t254(n int); +create table d1.t253(n int); +create table d1.t252(n int); +create table d1.t251(n int); +create table d1.t250(n int); +create table d1.t249(n int); +create table d1.t248(n int); +create table d1.t247(n int); +create table d1.t246(n int); +create table d1.t245(n int); +create table d1.t244(n int); +create table d1.t243(n int); +create table d1.t242(n int); +create table d1.t241(n int); +create table d1.t240(n int); +create table d1.t239(n int); +create table d1.t238(n int); +create table d1.t237(n int); +create table d1.t236(n int); +create table d1.t235(n int); +create table d1.t234(n int); +create table d1.t233(n int); +create table d1.t232(n int); +create table d1.t231(n int); +create table d1.t230(n int); +create table d1.t229(n int); +create table d1.t228(n int); +create table d1.t227(n int); +create table d1.t226(n int); +create table d1.t225(n int); +create table d1.t224(n int); +create table d1.t223(n int); +create table d1.t222(n int); +create table d1.t221(n int); +create table d1.t220(n int); +create table d1.t219(n int); +create table d1.t218(n int); +create table d1.t217(n int); +create table d1.t216(n int); +create table d1.t215(n int); +create table d1.t214(n int); +create table d1.t213(n int); +create table d1.t212(n int); +create table d1.t211(n int); +create table d1.t210(n int); +create table d1.t209(n int); +create table d1.t208(n int); +create table d1.t207(n int); +create table d1.t206(n int); +create table d1.t205(n int); +create table d1.t204(n int); +create table d1.t203(n int); +create table d1.t202(n int); +create table d1.t201(n int); +create table d1.t200(n int); +create table d1.t199(n int); +create table d1.t198(n int); +create table d1.t197(n int); +create table d1.t196(n int); +create table d1.t195(n int); +create table d1.t194(n int); +create table d1.t193(n int); +create table d1.t192(n int); +create table d1.t191(n int); +create table d1.t190(n int); +create table d1.t189(n int); +create table d1.t188(n int); +create table d1.t187(n int); +create table d1.t186(n int); +create table d1.t185(n int); +create table d1.t184(n int); +create table d1.t183(n int); +create table d1.t182(n int); +create table d1.t181(n int); +create table d1.t180(n int); +create table d1.t179(n int); +create table d1.t178(n int); +create table d1.t177(n int); +create table d1.t176(n int); +create table d1.t175(n int); +create table d1.t174(n int); +create table d1.t173(n int); +create table d1.t172(n int); +create table d1.t171(n int); +create table d1.t170(n int); +create table d1.t169(n int); +create table d1.t168(n int); +create table d1.t167(n int); +create table d1.t166(n int); +create table d1.t165(n int); +create table d1.t164(n int); +create table d1.t163(n int); +create table d1.t162(n int); +create table d1.t161(n int); +create table d1.t160(n int); +create table d1.t159(n int); +create table d1.t158(n int); +create table d1.t157(n int); +create table d1.t156(n int); +create table d1.t155(n int); +create table d1.t154(n int); +create table d1.t153(n int); +create table d1.t152(n int); +create table d1.t151(n int); +create table d1.t150(n int); +create table d1.t149(n int); +create table d1.t148(n int); +create table d1.t147(n int); +create table d1.t146(n int); +create table d1.t145(n int); +create table d1.t144(n int); +create table d1.t143(n int); +create table d1.t142(n int); +create table d1.t141(n int); +create table d1.t140(n int); +create table d1.t139(n int); +create table d1.t138(n int); +create table d1.t137(n int); +create table d1.t136(n int); +create table d1.t135(n int); +create table d1.t134(n int); +create table d1.t133(n int); +create table d1.t132(n int); +create table d1.t131(n int); +create table d1.t130(n int); +create table d1.t129(n int); +create table d1.t128(n int); +create table d1.t127(n int); +create table d1.t126(n int); +create table d1.t125(n int); +create table d1.t124(n int); +create table d1.t123(n int); +create table d1.t122(n int); +create table d1.t121(n int); +create table d1.t120(n int); +create table d1.t119(n int); +create table d1.t118(n int); +create table d1.t117(n int); +create table d1.t116(n int); +create table d1.t115(n int); +create table d1.t114(n int); +create table d1.t113(n int); +create table d1.t112(n int); +create table d1.t111(n int); +create table d1.t110(n int); +create table d1.t109(n int); +create table d1.t108(n int); +create table d1.t107(n int); +create table d1.t106(n int); +create table d1.t105(n int); +create table d1.t104(n int); +create table d1.t103(n int); +create table d1.t102(n int); +create table d1.t101(n int); +create table d1.t100(n int); +create table d1.t99(n int); +create table d1.t98(n int); +create table d1.t97(n int); +create table d1.t96(n int); +create table d1.t95(n int); +create table d1.t94(n int); +create table d1.t93(n int); +create table d1.t92(n int); +create table d1.t91(n int); +create table d1.t90(n int); +create table d1.t89(n int); +create table d1.t88(n int); +create table d1.t87(n int); +create table d1.t86(n int); +create table d1.t85(n int); +create table d1.t84(n int); +create table d1.t83(n int); +create table d1.t82(n int); +create table d1.t81(n int); +create table d1.t80(n int); +create table d1.t79(n int); +create table d1.t78(n int); +create table d1.t77(n int); +create table d1.t76(n int); +create table d1.t75(n int); +create table d1.t74(n int); +create table d1.t73(n int); +create table d1.t72(n int); +create table d1.t71(n int); +create table d1.t70(n int); +create table d1.t69(n int); +create table d1.t68(n int); +create table d1.t67(n int); +create table d1.t66(n int); +create table d1.t65(n int); +create table d1.t64(n int); +create table d1.t63(n int); +create table d1.t62(n int); +create table d1.t61(n int); +create table d1.t60(n int); +create table d1.t59(n int); +create table d1.t58(n int); +create table d1.t57(n int); +create table d1.t56(n int); +create table d1.t55(n int); +create table d1.t54(n int); +create table d1.t53(n int); +create table d1.t52(n int); +create table d1.t51(n int); +create table d1.t50(n int); +create table d1.t49(n int); +create table d1.t48(n int); +create table d1.t47(n int); +create table d1.t46(n int); +create table d1.t45(n int); +create table d1.t44(n int); +create table d1.t43(n int); +create table d1.t42(n int); +create table d1.t41(n int); +create table d1.t40(n int); +create table d1.t39(n int); +create table d1.t38(n int); +create table d1.t37(n int); +create table d1.t36(n int); +create table d1.t35(n int); +create table d1.t34(n int); +create table d1.t33(n int); +create table d1.t32(n int); +create table d1.t31(n int); +create table d1.t30(n int); +create table d1.t29(n int); +create table d1.t28(n int); +create table d1.t27(n int); +create table d1.t26(n int); +create table d1.t25(n int); +create table d1.t24(n int); +create table d1.t23(n int); +create table d1.t22(n int); +create table d1.t21(n int); +create table d1.t20(n int); +create table d1.t19(n int); +create table d1.t18(n int); +create table d1.t17(n int); +create table d1.t16(n int); +create table d1.t15(n int); +create table d1.t14(n int); +create table d1.t13(n int); +create table d1.t12(n int); +create table d1.t11(n int); +create table d1.t10(n int); +create table d1.t9(n int); +create table d1.t8(n int); +create table d1.t7(n int); +create table d1.t6(n int); +create table d1.t5(n int); +create table d1.t4(n int); +create table d1.t3(n int); +create table d1.t2(n int); +create table d1.t1(n int); +drop database d1; +ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17) +use d1; +show tables; +Tables_in_d1 use test; create table t1 (n int); insert into t1 values (1234); diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test index ef0ab4be6fd..71dc22f705f 100644 --- a/mysql-test/t/rpl_drop_db.test +++ b/mysql-test/t/rpl_drop_db.test @@ -17,6 +17,19 @@ create table d1.t3 (n int); drop database d1; use d1; show tables; + +# test the branch of the code that deals with the query buffer overflow + +let $1=1000; +while ($1) +{ + eval create table d1.t$1(n int); + dec $1; +} +--error 1010 +drop database d1; +use d1; +show tables; use test; create table t1 (n int); insert into t1 values (1234); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 946bb117e9e..0af3ea3af63 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -447,7 +447,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool log_query); int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, - bool log_query, List *dropped_tables); + bool log_query); int quick_rm_table(enum db_type base,const char *db, const char *table_name); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 0155fca0466..6dcc7be0904 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -25,14 +25,20 @@ #include #endif +#define MAX_DROP_TABLE_Q_LEN 1024 + const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; static TYPELIB deletable_extentions= {array_elements(del_exts)-1,"del_exts", del_exts, NULL}; static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, - const char *db, const char *path, - uint level, List *dropped_tables); + const char *db, const char *path, uint level, + TABLE_LIST** dropped_tables); + +static inline void write_to_binlog(THD* thd, char* query, uint q_len, + char* db, uint db_len); + /* Database options hash */ static HASH dboptions; static my_bool dboptions_init= 0; @@ -57,6 +63,19 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, return (byte*) opt->name; } +/* + Helper function to write a query to binlog used by mysql_rm_db() + */ +static inline void write_to_binlog(THD* thd, char* query, uint q_len, + char* db, uint db_len) +{ + Query_log_event qinfo(thd, query, q_len, 0, 0); + qinfo.error_code= 0; + qinfo.db= db; + qinfo.db_len= db_len; + mysql_bin_log.write(&qinfo); +} + /* Function to free dboptions hash element @@ -584,8 +603,8 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) int error= 0; char path[FN_REFLEN+16], tmp_db[NAME_LEN+1]; MY_DIR *dirp; - List dropped_tables; uint length; + TABLE_LIST* dropped_tables= 0; DBUG_ENTER("mysql_rm_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -625,7 +644,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) error= -1; if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0, - &dropped_tables)) >= 0) + &dropped_tables)) >= 0) { ha_drop_database(path); query_cache_invalidate1(db); @@ -675,36 +694,44 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) send_ok(thd, (ulong) deleted); thd->server_status&= ~SERVER_STATUS_DB_DROPPED; } - else if (!dropped_tables.is_empty() && mysql_bin_log.is_open()) + else if (mysql_bin_log.is_open()) { - List_iterator it(dropped_tables); - String* dropped_table; - int q_len= 11; /* drop table */ - int db_len= strlen(db); + char* query= thd->alloc(MAX_DROP_TABLE_Q_LEN); - for (;(dropped_table= it++);) - { - q_len += dropped_table->length() + 2 + db_len; - } - q_len--; /* no last comma */ - - char* query= thd->alloc(q_len); if (!query) goto exit; /* not much else we can do */ char* p= strmov(query,"drop table "); - it.rewind(); + char* p_end= query + MAX_DROP_TABLE_Q_LEN; + TABLE_LIST* tbl; + bool last_query_needs_write= 0; + uint db_len= strlen(db); - for (;(dropped_table= it++);) + for (tbl= dropped_tables;tbl;tbl= tbl->next) { - p= strmov(p,db); - *p++ = '.'; - p= strnmov(p,dropped_table->ptr(),dropped_table->length()); + if (!tbl->was_dropped) + continue; + + /* 3 for the quotes and the comma*/ + uint tbl_name_len= strlen(tbl->real_name) + 3; + if (p + tbl_name_len + 1 >= p_end) + { + *--p= 0; /* kill , */ + write_to_binlog(thd, query, p - query, db, db_len); + p= query + 11; /* reuse the initial "drop table" */ + } + + *p++ = '`'; + p= strmov(p,tbl->real_name); + *p++ = '`'; *p++ = ','; + last_query_needs_write= 1; } - *--p= 0; - Query_log_event qinfo(thd, query, q_len, 0, 0); - qinfo.error_code= 0; - mysql_bin_log.write(&qinfo); + + if (last_query_needs_write) + { + *--p= 0; + write_to_binlog(thd, query, p - query, db, db_len); + } } exit: @@ -750,7 +777,7 @@ exit2: */ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, - const char *org_path, uint level, List *dropped_tables) + const char *org_path, uint level, TABLE_LIST** dropped_tables) { long deleted=0; ulong found_other_files=0; @@ -839,8 +866,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } } if (thd->killed || - (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, - 1,dropped_tables))) + (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) goto err; /* Remove RAID directories */ @@ -853,6 +879,9 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } my_dirend(dirp); + if (dropped_tables) + *dropped_tables= tot_list; + /* If the directory is a symbolic link, remove the link first, then remove the directory the symbolic link pointed at diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e948a65f301..80ac9e007b9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -156,8 +156,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, - bool drop_temporary, bool dont_log_query, - List* dropped_tables) + bool drop_temporary, bool dont_log_query) { int error; thd->mysys_var->current_mutex= &LOCK_open; @@ -166,23 +165,6 @@ int mysql_rm_table_part2_with_lock(THD *thd, error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, dont_log_query); - /* - For now we assume that if we got success all the tables in the list - were actually dropped, otherwise, assume none were dropped. - TODO: fix it to work with a partial drop - extremely rare case, but - can happen. - */ - if (!error && dropped_tables) - { - TABLE_LIST* tbl; - - for (tbl= tables; tbl; tbl= tbl->next) - { - String *dropped_table= new (thd->mem_root) - String(tbl->real_name,&my_charset_latin1); - dropped_tables->push_back(dropped_table); - } - } pthread_mutex_unlock(&LOCK_open); @@ -238,6 +220,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, for (table=tables ; table ; table=table->next) { char *db=table->db; + table->was_dropped= 0; mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); if (!close_temporary_table(thd, db, table->real_name)) { @@ -298,6 +281,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, wrong_tables.append(','); wrong_tables.append(String(table->real_name,system_charset_info)); } + else + table->was_dropped= 1; } thd->tmp_table_used= tmp_table_deleted; error= 0; diff --git a/sql/table.h b/sql/table.h index 77153e5d8cd..fb742acf804 100644 --- a/sql/table.h +++ b/sql/table.h @@ -235,6 +235,9 @@ typedef struct st_table_list bool cacheable_table; /* stop PS caching */ /* used in multi-upd privelege check */ bool table_in_update_from_clause; + + /* used for proper partially successful DROP DATABASE binlogging */ + bool was_dropped; } TABLE_LIST; typedef struct st_changed_table_list From 523039c832c72d78c6c455bda7b583cbb580dc48 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 19 Aug 2005 07:48:59 +0200 Subject: [PATCH 166/230] ndb rename config.cpp -> ndb_config.cpp for case insesitive filesystems why wasn't this done in 4.1 directly --- mysql-test/t/ndb_config.test | 1 - ndb/tools/Makefile.am | 2 +- ndb/tools/{config.cpp => ndb_config.cpp} | 0 3 files changed, 1 insertion(+), 2 deletions(-) rename ndb/tools/{config.cpp => ndb_config.cpp} (100%) diff --git a/mysql-test/t/ndb_config.test b/mysql-test/t/ndb_config.test index a79973515b2..ea78a32b1ba 100644 --- a/mysql-test/t/ndb_config.test +++ b/mysql-test/t/ndb_config.test @@ -1,5 +1,4 @@ -- source include/have_ndb.inc --- source include/ndb_default_cluster.inc -- source include/not_embedded.inc --exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=type,nodeid,host 2> /dev/null diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 1f11122fb70..89830129576 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -32,7 +32,7 @@ ndb_restore_SOURCES = restore/restore_main.cpp \ restore/consumer_printer.cpp \ restore/Restore.cpp -ndb_config_SOURCES = config.cpp \ +ndb_config_SOURCES = ndb_config.cpp \ ../src/mgmsrv/Config.cpp \ ../src/mgmsrv/ConfigInfo.cpp \ ../src/mgmsrv/InitConfigFileParser.cpp diff --git a/ndb/tools/config.cpp b/ndb/tools/ndb_config.cpp similarity index 100% rename from ndb/tools/config.cpp rename to ndb/tools/ndb_config.cpp From d0767dfad3b9c12f50b0564e29f6d8dd284e5007 Mon Sep 17 00:00:00 2001 From: "patg@radha.local" <> Date: Fri, 19 Aug 2005 07:51:22 +0200 Subject: [PATCH 167/230] BUG #12498 Fixed mispelling --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9177703599c..c919614fc88 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4323,7 +4323,7 @@ Disable with --skip-bdb (will save memory).", (gptr*) &default_collation_name, (gptr*) &default_collation_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"default-storage-engine", OPT_STORAGE_ENGINE, - "Set the default storage engine (table tyoe) for tables.", 0, 0, + "Set the default storage engine (table type) for tables.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-table-type", OPT_STORAGE_ENGINE, "(deprecated) Use --default-storage-engine.", 0, 0, From 69476be2d13b71fa30db98a4855f9cc3f8102943 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Fri, 19 Aug 2005 09:46:59 +0300 Subject: [PATCH 168/230] changes in row operation --- mysql-test/r/subselect.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index bbfdeb970a6..d3ab359702e 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -923,7 +923,7 @@ select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a') (select c from t1 where a=t2.a) 1 1 a 2 0 b -NULL NULL NULL +NULL 0 NULL select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2; a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b') (select c from t1 where a=t2.a) 1 0 a @@ -933,7 +933,7 @@ select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c') (select c from t1 where a=t2.a) 1 0 a 2 0 b -NULL NULL NULL +NULL 0 NULL drop table t1,t2; create table t1 (a int, b real, c varchar(10)); insert into t1 values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); From 24be1c152400c1f1a8297d6f17202e45c542bb38 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 19 Aug 2005 09:04:30 +0200 Subject: [PATCH 169/230] jonas - Fix checkout properties --- BitKeeper/etc/config | 1 + 1 file changed, 1 insertion(+) diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index 6ddd492ebc4..0f0666d5050 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -70,5 +70,6 @@ hours: [serg:]checkout:get [arjen:]checkout:get [nick:]checkout:get +[jonas:]checkout:get checkout:edit eoln:unix From 7f9e97f70cd9023e7318ab45290e3b75ee582e83 Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Fri, 19 Aug 2005 09:08:41 +0200 Subject: [PATCH 170/230] test fix for fix of 12591 --- mysql-test/r/innodb.result | 2 +- mysql-test/t/innodb.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 69620d5d527..91d72045169 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -904,7 +904,7 @@ insert into mysqltest.t3 values(1); commit; drop database mysqltest; show tables from mysqltest; -Got one of the listed errors +ERROR 42000: Unknown database 'mysqltest' set autocommit=0; create table t1 (a int not null) engine= innodb; insert into t1 values(1),(2); diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 8d51af4f22f..3eaf408af0f 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -586,7 +586,7 @@ insert into mysqltest.t3 values(1); commit; drop database mysqltest; # Don't check error message ---error 12,12 +--error 1049 show tables from mysqltest; # From bf835c89c25e6ca43fabb5be0b59086e1278bf3f Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 19 Aug 2005 10:12:44 +0200 Subject: [PATCH 171/230] ndb - remove grep from Makefile --- ndb/src/kernel/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/ndb/src/kernel/Makefile.am b/ndb/src/kernel/Makefile.am index 55d3c5a578f..389cb85c1d8 100644 --- a/ndb/src/kernel/Makefile.am +++ b/ndb/src/kernel/Makefile.am @@ -23,7 +23,6 @@ INCLUDES += \ -Iblocks/backup \ -Iblocks/dbutil \ -Iblocks/suma \ - -Iblocks/grep \ -Iblocks/dbtux LDADD += \ @@ -41,7 +40,6 @@ LDADD += \ blocks/backup/libbackup.a \ blocks/dbutil/libdbutil.a \ blocks/suma/libsuma.a \ - blocks/grep/libgrep.a \ blocks/dbtux/libdbtux.a \ vm/libkernel.a \ error/liberror.a \ From e449bfed9df742f19fec2194a6144c6cd42e7385 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 19 Aug 2005 10:24:37 +0200 Subject: [PATCH 172/230] jonas: fix bk checkout properties --- BitKeeper/etc/config | 1 + 1 file changed, 1 insertion(+) diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index 56ae08e5ffa..d9c45d3d36a 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -71,5 +71,6 @@ hours: [arjen:]checkout:get [kostja:]checkout:get [nick:]checkout:get +[jonas:]checkout:get checkout:edit eoln:unix From 6b32f5a1e933bbe7685843255b01786a87452897 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Fri, 19 Aug 2005 11:33:11 +0300 Subject: [PATCH 173/230] row0sel.c: Temporarily remove error print if MySQL tries to do a SELECT even though trx->n_mysql_tables_in_use is 0. We must return the error print when the lock count of cursors is properly implemented (Bug #12456) --- innobase/row/row0sel.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 7328db1c65d..a77010d939b 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -3124,12 +3124,17 @@ row_search_for_mysql( be zero; in that case select_lock_type is set to LOCK_X in ::start_stmt. */ +/* August 19, 2005 by Heikki: temporarily disable this error print until the +cursor lock count is done correctly. See bugs #12263 and #12456! + fputs( "InnoDB: Error: MySQL is trying to perform a SELECT\n" "InnoDB: but it has not locked any tables in ::external_lock()!\n", stderr); trx_print(stderr, trx, 600); fputc('\n', stderr); +*/ + } /* fprintf(stderr, "Match mode %lu\n search tuple ", (ulong) match_mode); From 20a052880f4f28021653a6cd71dcc08d58d314fe Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Fri, 19 Aug 2005 11:38:14 +0300 Subject: [PATCH 174/230] fixed test after merge --- mysql-test/r/rpl_delete_all.result | 2 +- mysql-test/t/rpl_delete_all.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/rpl_delete_all.result b/mysql-test/r/rpl_delete_all.result index 5ed221823e8..1aa556270c9 100644 --- a/mysql-test/r/rpl_delete_all.result +++ b/mysql-test/r/rpl_delete_all.result @@ -9,7 +9,7 @@ drop database if exists mysqltest; Warnings: Note 1008 Can't drop database 'mysqltest'; database doesn't exist show tables from mysqltest; -ERROR HY000: Can't read dir of './mysqltest/' (Errcode: X) +ERROR 42000: Unknown database 'mysqltest' create table t1 (a int); drop table if exists t1; Warnings: diff --git a/mysql-test/t/rpl_delete_all.test b/mysql-test/t/rpl_delete_all.test index db33ee3bb86..e0c0757bbc2 100644 --- a/mysql-test/t/rpl_delete_all.test +++ b/mysql-test/t/rpl_delete_all.test @@ -7,7 +7,7 @@ drop database if exists mysqltest; sync_slave_with_master; # can't read dir --replace_result "Errcode: 1" "Errcode: X" "Errcode: 2" "Errcode: X" \\ / ---error 12 +--error 1049 show tables from mysqltest; connection slave; From 2d32b77693de4ec6fdd4df9a8b7736000920d88e Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Fri, 19 Aug 2005 01:57:22 -0700 Subject: [PATCH 175/230] distinct.test, distinct.result: Added test cases for bug #12625. sql_select.cc: Fixed bug #12625. Fixed invalid removal of constant items from the DISTINCT list in the function create_distinct_group. --- mysql-test/r/distinct.result | 40 ++++++++++++++++++++++++++++++++++++ mysql-test/t/distinct.test | 17 +++++++++++++++ sql/sql_select.cc | 4 +--- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index f4bc4263c4d..8932285b5d0 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -464,3 +464,43 @@ SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; html prod 1 0.00 drop table t1; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SELECT DISTINCT a, 1 FROM t1; +a 1 +1 1 +2 1 +3 1 +4 1 +5 1 +SELECT DISTINCT 1, a FROM t1; +1 a +1 1 +1 2 +1 3 +1 4 +1 5 +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES (1,1),(2,2),(2,3),(2,4),(3,5); +SELECT DISTINCT a, b, 2 FROM t2; +a b 2 +1 1 2 +2 2 2 +2 3 2 +2 4 2 +3 5 2 +SELECT DISTINCT 2, a, b FROM t2; +2 a b +2 1 1 +2 2 2 +2 2 3 +2 2 4 +2 3 5 +SELECT DISTINCT a, 2, b FROM t2; +a 2 b +1 2 1 +2 2 2 +2 2 3 +2 2 4 +3 2 5 +DROP TABLE t1,t2; diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index f05dd4b75a0..f2fe1ec6372 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -333,4 +333,21 @@ INSERT INTO t1 VALUES ('1',1,0); SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; drop table t1; +# +# Test cases for #12625: DISTINCT for a list with constants +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SELECT DISTINCT a, 1 FROM t1; +SELECT DISTINCT 1, a FROM t1; + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES (1,1),(2,2),(2,3),(2,4),(3,5); +SELECT DISTINCT a, b, 2 FROM t2; +SELECT DISTINCT 2, a, b FROM t2; +SELECT DISTINCT a, 2, b FROM t2; + +DROP TABLE t1,t2; + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9984cb4138f..3b67af8eea7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8517,9 +8517,7 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, li.rewind(); while ((item=li++)) { - if (item->const_item() || item->with_sum_func) - continue; - if (!item->marker) + if (!item->const_item() && !item->with_sum_func && !item->marker) { ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) From d9bbf7bc53b6618f77cfcb5802a5459c1aac844e Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Fri, 19 Aug 2005 12:54:13 +0300 Subject: [PATCH 176/230] btr0sea.c: Add diagnostic code to track a crash in adaptive hash indexes; the crash may happen if block->index == NULL --- innobase/btr/btr0sea.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index f705fee4275..7a4e92a672a 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -964,6 +964,13 @@ btr_search_drop_page_hash_index( heap = NULL; offsets = NULL; + if (block->index == NULL) { + + mem_analyze_corruption((byte*)block); + + ut_a(block->index != NULL); + } + while (!page_rec_is_supremum(rec)) { /* FIXME: in a mixed tree, not all records may have enough ordering fields: */ From 6371e9a23f53c266b5eeb5c8a8fcfe5d0a1998f3 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 19 Aug 2005 13:20:36 +0200 Subject: [PATCH 177/230] ndb remove grep stuff --- ndb/src/kernel/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/ndb/src/kernel/Makefile.am b/ndb/src/kernel/Makefile.am index 55d3c5a578f..389cb85c1d8 100644 --- a/ndb/src/kernel/Makefile.am +++ b/ndb/src/kernel/Makefile.am @@ -23,7 +23,6 @@ INCLUDES += \ -Iblocks/backup \ -Iblocks/dbutil \ -Iblocks/suma \ - -Iblocks/grep \ -Iblocks/dbtux LDADD += \ @@ -41,7 +40,6 @@ LDADD += \ blocks/backup/libbackup.a \ blocks/dbutil/libdbutil.a \ blocks/suma/libsuma.a \ - blocks/grep/libgrep.a \ blocks/dbtux/libdbtux.a \ vm/libkernel.a \ error/liberror.a \ From f5fc1543aa49a7ef47a20d4b591825763c75d06a Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Fri, 19 Aug 2005 15:22:30 +0300 Subject: [PATCH 178/230] WL#2486 - natural and using join according to SQL:2003 - Corrected problem with N-way nested natural joins in PS mode. - Code cleanup - More asserts to check consistency of name resolution contexts - Fixed potential memory leak of name resolution contexts --- mysql-test/r/join.result | 4 ++++ mysql-test/t/join.test | 4 +--- sql/item.h | 2 +- sql/sql_base.cc | 11 ++++----- sql/sql_parse.cc | 3 +-- sql/table.cc | 50 ++++++++++++++++++++++++++++++---------- sql/table.h | 2 +- 7 files changed, 50 insertions(+), 26 deletions(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index b7a2f0ce4f4..5ea863b4bdb 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -121,6 +121,10 @@ id catid stateid countyid drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +a +1 +2 select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); ERROR HY000: Too many tables; MySQL can only use XX tables in a join drop table t1; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 06e89e6cb9d..2e82bad8abb 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -111,9 +111,7 @@ drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); -# TODO: WL#2486 - the query fails in PS mode with error: -# Cross dependency found in OUTER JOIN; examine your ON conditions -#select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); --replace_result "31 tables" "XX tables" "61 tables" "XX tables" --error 1116 select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); diff --git a/sql/item.h b/sql/item.h index ae5fbe5a44b..4dfd99e0dbd 100644 --- a/sql/item.h +++ b/sql/item.h @@ -237,7 +237,7 @@ void view_error_processor(THD *thd, void *data); structure before and after INSERT/CREATE and its SELECT to make correct field name resolution. */ -struct Name_resolution_context +struct Name_resolution_context: Sql_alloc { /* The name resolution context to search in when an Item cannot be diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 98ce12eb7de..b8748b89fbd 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2688,6 +2688,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { /* This is a base table. */ DBUG_ASSERT(nj_col->view_field == NULL); + DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->table); found_field= nj_col->table_field; update_field_dependencies(thd, found_field, nj_col->table_ref->table); } @@ -3366,9 +3367,7 @@ static bool set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) { Name_resolution_context *context; - - if (!(context= (Name_resolution_context*) - thd->calloc(sizeof(Name_resolution_context)))) + if (!(context= new Name_resolution_context)) return TRUE; context->init(); context->first_name_resolution_table= @@ -3509,7 +3508,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, Field *field_1= nj_col_1->field(); Field *field_2= nj_col_2->field(); Item_ident *item_ident_1, *item_ident_2; - Name_resolution_context *context_1, *context_2; Item_func_eq *eq_cond; DBUG_PRINT("info", ("new equi-join condition: %s.%s = %s.%s", @@ -3545,8 +3543,8 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, resolution of these items, and to enable proper name resolution of the items during the execute phase of PS. */ - if (set_new_item_local_context(thd, item_ident_1, table_ref_1) || - set_new_item_local_context(thd, item_ident_2, table_ref_2)) + if (set_new_item_local_context(thd, item_ident_1, nj_col_1->table_ref) || + set_new_item_local_context(thd, item_ident_2, nj_col_2->table_ref)) goto err; if (!(eq_cond= new Item_func_eq(item_ident_1, item_ident_2))) @@ -4336,7 +4334,6 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, continue; } - bool view; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Ensure that we have access rights to all fields to be inserted. */ if (!((table && (table->grant.privilege & SELECT_ACL) || diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2ba82954319..f23963727ce 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6415,8 +6415,7 @@ Name_resolution_context * make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op) { Name_resolution_context *on_context; - if (!(on_context= (Name_resolution_context*) - thd->calloc(sizeof(Name_resolution_context)))) + if (!(on_context= new Name_resolution_context)) return NULL; on_context->init(); on_context->first_name_resolution_table= diff --git a/sql/table.cc b/sql/table.cc index baf44680807..beecd6442e8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2296,6 +2296,7 @@ Natural_join_column::Natural_join_column(Field_translator *field_param, Natural_join_column::Natural_join_column(Field *field_param, TABLE_LIST *tab) { + DBUG_ASSERT(tab->table == field_param->table); table_field= field_param; view_field= NULL; table_ref= tab; @@ -2514,6 +2515,18 @@ void Field_iterator_natural_join::set(TABLE_LIST *table_ref) } +void Field_iterator_natural_join::next() +{ + cur_column_ref= (*column_ref_it)++; + DBUG_ASSERT(cur_column_ref ? + (cur_column_ref->table_field ? + cur_column_ref->table_ref->table == + cur_column_ref->table_field->table : + TRUE) : + TRUE); +} + + void Field_iterator_table_ref::set_field_iterator() { DBUG_ENTER("Field_iterator_table_ref::set_field_iterator"); @@ -2660,18 +2673,31 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created) *is_created= TRUE; if (field_it == &table_field_it) - return new Natural_join_column(table_field_it.field(), table_ref); - if (field_it == &view_field_it) - return new Natural_join_column(view_field_it.field_translator(), - table_ref); - - /* - This is NATURAL join, we already have created a column reference, - so just return it. - */ - *is_created= FALSE; - nj_col= natural_join_it.column_ref(); - DBUG_ASSERT(nj_col); + { + /* The field belongs to a stored table. */ + Field *field= table_field_it.field(); + nj_col= new Natural_join_column(field, table_ref); + } + else if (field_it == &view_field_it) + { + /* The field belongs to a merge view or information schema table. */ + Field_translator *translated_field= view_field_it.field_translator(); + nj_col= new Natural_join_column(translated_field, table_ref); + } + else + { + /* + The field belongs to a NATURAL join, therefore the column reference was + already created via one of the two constructor calls above. In this case + we just return the already created column reference. + */ + *is_created= FALSE; + nj_col= natural_join_it.column_ref(); + DBUG_ASSERT(nj_col); + } + DBUG_ASSERT(nj_col->table_field ? + nj_col->table_ref->table == nj_col->table_field->table : + TRUE); return nj_col; } diff --git a/sql/table.h b/sql/table.h index 3d4f02e389b..c0e4ad4c150 100644 --- a/sql/table.h +++ b/sql/table.h @@ -698,7 +698,7 @@ public: Field_iterator_natural_join() :column_ref_it(NULL), cur_column_ref(NULL) {} ~Field_iterator_natural_join() { delete column_ref_it; } void set(TABLE_LIST *table); - void next() { cur_column_ref= (*column_ref_it)++; } + void next(); bool end_of_fields() { return !cur_column_ref; } const char *name() { return cur_column_ref->name(); } Item *create_item(THD *thd) { return cur_column_ref->create_item(thd); } From 887fba473686cfb8d3c4bc214e3810df28283f2d Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Fri, 19 Aug 2005 17:03:21 +0400 Subject: [PATCH 179/230] A fix and a test case for "Bug #12168 'DECLARE CONTINUE HANDLER FOR NOT FOUND ...' in conditional handled incorrectly". Whenever we remove an instruction during optimization, we need to adjust instruction numbers (ip - instruction pointer) stored in all instructions. In addition to that, sp_instr_hpush_jump, which corresponds to DECLARE CONTINUE HANDLER needs adjustment for m_handler, which holds the number of instruction with the continue handler. In the bug report, a wrong ip stored in m_handler was pointing at FETCH, which resulted in an error message and abnormal SP termination. The fix is to just remove m_handler member from sp_instr_hpush_jump, as it's always points to the instruction next to the DECLARE statement itself (m_ip+1). --- mysql-test/r/sp.result | 66 ++++++++++++++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 66 ++++++++++++++++++++++++++++++++++++++++++ sql/sp_head.cc | 4 +-- sql/sp_head.h | 2 -- 4 files changed, 134 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 78bf22d0b27..d1d41035475 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3100,4 +3100,70 @@ end| call p_bug11247(10)| drop function f_bug11247| drop procedure p_bug11247| +drop procedure if exists bug12168| +drop table if exists t1, t2| +create table t1 (a int)| +insert into t1 values (1),(2),(3),(4)| +create table t2 (a int)| +create procedure bug12168(arg1 char(1)) +begin +declare b, c integer; +if arg1 = 'a' then +begin +declare c1 cursor for select a from t1 where a % 2; +declare continue handler for not found set b = 1; +set b = 0; +open c1; +c1_repeat: repeat +fetch c1 into c; +if (b = 1) then +leave c1_repeat; +end if; +insert into t2 values (c); +until b = 1 +end repeat; +end; +end if; +if arg1 = 'b' then +begin +declare c2 cursor for select a from t1 where not a % 2; +declare continue handler for not found set b = 1; +set b = 0; +open c2; +c2_repeat: repeat +fetch c2 into c; +if (b = 1) then +leave c2_repeat; +end if; +insert into t2 values (c); +until b = 1 +end repeat; +end; +end if; +end| +call bug12168('a')| +select * from t2| +a +1 +3 +truncate t2| +call bug12168('b')| +select * from t2| +a +2 +4 +truncate t2| +call bug12168('a')| +select * from t2| +a +1 +3 +truncate t2| +call bug12168('b')| +select * from t2| +a +2 +4 +truncate t2| +drop procedure if exists bug12168| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index cde5d3922ab..f3e7c3e07a0 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3928,6 +3928,72 @@ end| call p_bug11247(10)| drop function f_bug11247| drop procedure p_bug11247| +# +# BUG#12168: "'DECLARE CONTINUE HANDLER FOR NOT FOUND ...' in conditional +# handled incorrectly" +# +--disable_warnings +drop procedure if exists bug12168| +drop table if exists t1, t2| +--enable_warnings + +create table t1 (a int)| +insert into t1 values (1),(2),(3),(4)| + +create table t2 (a int)| + +create procedure bug12168(arg1 char(1)) +begin + declare b, c integer; + if arg1 = 'a' then + begin + declare c1 cursor for select a from t1 where a % 2; + declare continue handler for not found set b = 1; + set b = 0; + open c1; + c1_repeat: repeat + fetch c1 into c; + if (b = 1) then + leave c1_repeat; + end if; + + insert into t2 values (c); + until b = 1 + end repeat; + end; + end if; + if arg1 = 'b' then + begin + declare c2 cursor for select a from t1 where not a % 2; + declare continue handler for not found set b = 1; + set b = 0; + open c2; + c2_repeat: repeat + fetch c2 into c; + if (b = 1) then + leave c2_repeat; + end if; + + insert into t2 values (c); + until b = 1 + end repeat; + end; + end if; +end| + +call bug12168('a')| +select * from t2| +truncate t2| +call bug12168('b')| +select * from t2| +truncate t2| +call bug12168('a')| +select * from t2| +truncate t2| +call bug12168('b')| +select * from t2| +truncate t2| +drop procedure if exists bug12168| # # BUG#NNNN: New bug synopsis diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 26d76804fca..f119ef1ec22 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1986,7 +1986,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) sp_cond_type_t *p; while ((p= li++)) - thd->spcont->push_handler(p, m_handler, m_type, m_frame); + thd->spcont->push_handler(p, m_ip+1, m_type, m_frame); *nextp= m_dest; DBUG_RETURN(0); @@ -2003,7 +2003,7 @@ sp_instr_hpush_jump::print(String *str) str->append(" f="); str->qs_append(m_frame); str->append(" h="); - str->qs_append(m_handler); + str->qs_append(m_ip+1); } uint diff --git a/sql/sp_head.h b/sql/sp_head.h index e15b68be158..8ae7834eb2a 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -714,7 +714,6 @@ public: sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp) : sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp) { - m_handler= ip+1; m_cond.empty(); } @@ -743,7 +742,6 @@ private: int m_type; // Handler type uint m_frame; - uint m_handler; // Location of handler List m_cond; }; // class sp_instr_hpush_jump : public sp_instr_jump From 5605117d4dbe0c6c853189abd2e01a2dc28bc298 Mon Sep 17 00:00:00 2001 From: "petr@mysql.com" <> Date: Fri, 19 Aug 2005 17:19:12 +0400 Subject: [PATCH 180/230] Fix for BUG#10957 "stop instance, issued after flush instances causes IM to crash" Recommited with post-review fixes --- server-tools/instance-manager/instance.cc | 344 ++++++++++++------ server-tools/instance-manager/instance.h | 4 +- .../instance-manager/instance_options.cc | 2 + 3 files changed, 245 insertions(+), 105 deletions(-) diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index dee3c2d4e38..0a373429d01 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -36,6 +36,16 @@ #include #include + +static void start_and_monitor_instance(Instance_options *old_instance_options, + Instance_map *instance_map); + +#ifndef _WIN_ +typedef pid_t My_process_info; +#else +typedef PROCESS_INFORMATION My_process_info; +#endif + C_MODE_START /* @@ -48,13 +58,224 @@ C_MODE_START pthread_handler_decl(proxy, arg) { Instance *instance= (Instance *) arg; - instance->fork_and_monitor(); + start_and_monitor_instance(&instance->options, + instance->get_map()); return 0; } C_MODE_END +/* + Wait for an instance + + SYNOPSYS + wait_process() + pi Pointer to the process information structure + (platform-dependent). + + RETURN + 0 - Success + 1 - Error +*/ + +#ifndef __WIN__ +static int wait_process(My_process_info *pi) +{ + /* + Here we wait for the child created. This process differs for systems + running LinuxThreads and POSIX Threads compliant systems. This is because + according to POSIX we could wait() for a child in any thread of the + process. While LinuxThreads require that wait() is called by the thread, + which created the child. + On the other hand we could not expect mysqld to return the pid, we + got in from fork(), to wait4() fucntion when running on LinuxThreads. + This is because MySQL shutdown thread is not the one, which was created + by our fork() call. + So basically we have two options: whether the wait() call returns only in + the creator thread, but we cannot use waitpid() since we have no idea + which pid we should wait for (in fact it should be the pid of shutdown + thread, but we don't know this one). Or we could use waitpid(), but + couldn't use wait(), because it could return in any wait() in the program. + */ + if (linuxthreads) + wait(NULL); /* LinuxThreads were detected */ + else + waitpid(*pi, NULL, 0); + + return 0; +} +#else +static int wait_process(My_process_info *pi) +{ + /* Wait until child process exits. */ + WaitForSingleObject(pi->hProcess, INFINITE); + + DWORD exitcode; + ::GetExitCodeProcess(pi->hProcess, &exitcode); + + /* Close process and thread handles. */ + CloseHandle(pi->hProcess); + CloseHandle(pi->hThread); + + /* + GetExitCodeProces returns zero on failure. We should revert this value + to report an error. + */ + return (!exitcode); +} +#endif + + +/* + Launch an instance + + SYNOPSYS + start_process() + instance_options Pointer to the options of the instance to be + launched. + pi Pointer to the process information structure + (platform-dependent). + + RETURN + 0 - Success + 1 - Cannot create an instance +*/ + +#ifndef __WIN__ +static int start_process(Instance_options *instance_options, + My_process_info *pi) +{ + *pi= fork(); + + switch (*pi) { + case 0: + execv(instance_options->mysqld_path, instance_options->argv); + /* exec never returns */ + exit(1); + case 1: + log_info("cannot fork() to start instance %s", + instance_options->instance_name); + return 1; + } + return 0; +} +#else +static int start_process(Instance_options *instance_options, + My_process_info *pi) +{ + STARTUPINFO si; + + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb= sizeof(STARTUPINFO); + ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); + + int cmdlen= 0; + for (int i= 1; instance_options->argv[i] != 0; i++) + cmdlen+= strlen(instance_options->argv[i]) + 1; + cmdlen++; /* we have to add a single space for CreateProcess (see docs) */ + + char *cmdline= NULL; + if (cmdlen > 0) + { + cmdline= new char[cmdlen]; + cmdline[0]= 0; + for (int i= 1; instance_options->argv[i] != 0; i++) + { + strcat(cmdline, " "); + strcat(cmdline, instance_options->argv[i]); + } + } + + /* Start the child process */ + BOOL result= + CreateProcess(instance_options->mysqld_path, /* File to execute */ + cmdline, /* Command line */ + NULL, /* Process handle not inheritable */ + NULL, /* Thread handle not inheritable */ + FALSE, /* Set handle inheritance to FALSE */ + 0, /* No creation flags */ + NULL, /* Use parent's environment block */ + NULL, /* Use parent's starting directory */ + &si, /* Pointer to STARTUPINFO structure */ + pi); /* Pointer to PROCESS_INFORMATION structure */ + delete cmdline; + + return (!result); +} +#endif + +/* + Fork child, exec an instance and monitor it. + + SYNOPSYS + start_and_monitor_instance() + old_instance_options Pointer to the options of the instance to be + launched. This info is likely to become obsolete + when function returns from wait_process() + instance_map Pointer to the instance_map. We use it to protect + the instance from deletion, while we are working + with it. + + DESCRIPTION + Fork a child, then exec and monitor it. When the child is dead, + find appropriate instance (for this purpose we save its name), + set appropriate flags and wake all threads waiting for instance + to stop. + + RETURN + Function returns no value +*/ + +static void start_and_monitor_instance(Instance_options *old_instance_options, + Instance_map *instance_map) +{ + enum { MAX_INSTANCE_NAME_LEN= 512 }; + char instance_name_buff[MAX_INSTANCE_NAME_LEN]; + uint instance_name_len; + Instance *current_instance; + My_process_info process_info; + + /* + Lock instance map to guarantee that no instances are deleted during + strmake() and execv() calls. + */ + instance_map->lock(); + + /* + Save the instance name in the case if Instance object we + are using is destroyed. (E.g. by "FLUSH INSTANCES") + */ + strmake(instance_name_buff, old_instance_options->instance_name, + MAX_INSTANCE_NAME_LEN - 1); + instance_name_len= old_instance_options->instance_name_len; + + log_info("starting instance %s", instance_name_buff); + + if (start_process(old_instance_options, &process_info)) + return; /* error is logged */ + + /* allow users to delete instances */ + instance_map->unlock(); + + /* don't check for return value */ + wait_process(&process_info); + + current_instance= instance_map->find(instance_name_buff, instance_name_len); + + if (current_instance) + current_instance->set_crash_flag_n_wake_all(); + + return; +} + + +Instance_map *Instance::get_map() +{ + return instance_map; +} + + void Instance::remove_pid() { int pid; @@ -65,6 +286,7 @@ void Instance::remove_pid() options.instance_name); } + /* The method starts an instance. @@ -116,107 +338,24 @@ int Instance::start() return ER_INSTANCE_ALREADY_STARTED; } -#ifndef __WIN__ -int Instance::launch_and_wait() +/* + The method sets the crash flag and wakes all waiters on + COND_instance_stopped and COND_guardian + + SYNOPSYS + set_crash_flag_n_wake_all() + + DESCRIPTION + The method is called when an instance is crashed or terminated. + In the former case it might indicate that guardian probably should + restart it. + + RETURN + Function returns no value +*/ + +void Instance::set_crash_flag_n_wake_all() { - pid_t pid= fork(); - - switch (pid) { - case 0: - execv(options.mysqld_path, options.argv); - /* exec never returns */ - exit(1); - case -1: - log_info("cannot fork() to start instance %s", options.instance_name); - return -1; - default: - /* - Here we wait for the child created. This process differs for systems - running LinuxThreads and POSIX Threads compliant systems. This is because - according to POSIX we could wait() for a child in any thread of the - process. While LinuxThreads require that wait() is called by the thread, - which created the child. - On the other hand we could not expect mysqld to return the pid, we - got in from fork(), to wait4() fucntion when running on LinuxThreads. - This is because MySQL shutdown thread is not the one, which was created - by our fork() call. - So basically we have two options: whether the wait() call returns only in - the creator thread, but we cannot use waitpid() since we have no idea - which pid we should wait for (in fact it should be the pid of shutdown - thread, but we don't know this one). Or we could use waitpid(), but - couldn't use wait(), because it could return in any wait() in the program. - */ - if (linuxthreads) - wait(NULL); /* LinuxThreads were detected */ - else - waitpid(pid, NULL, 0); - } - return 0; -} -#else -int Instance::launch_and_wait() -{ - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb= sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - int cmdlen= 0; - for (int i= 1; options.argv[i] != 0; i++) - cmdlen+= strlen(options.argv[i]) + 1; - cmdlen++; // we have to add a single space for CreateProcess (read the docs) - - char *cmdline= NULL; - if (cmdlen > 0) - { - cmdline= new char[cmdlen]; - cmdline[0]= 0; - for (int i= 1; options.argv[i] != 0; i++) - { - strcat(cmdline, " "); - strcat(cmdline, options.argv[i]); - } - } - - // Start the child process. - BOOL result= CreateProcess(options.mysqld_path, // file to execute - cmdline, // Command line. - NULL, // Process handle not inheritable. - NULL, // Thread handle not inheritable. - FALSE, // Set handle inheritance to FALSE. - 0, // No creation flags. - NULL, // Use parent's environment block. - NULL, // Use parent's starting directory. - &si, // Pointer to STARTUPINFO structure. - &pi ); // Pointer to PROCESS_INFORMATION structure. - delete cmdline; - if (! result) - return -1; - - // Wait until child process exits. - WaitForSingleObject(pi.hProcess, INFINITE); - - DWORD exitcode; - ::GetExitCodeProcess(pi.hProcess, &exitcode); - - // Close process and thread handles. - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return exitcode; -} -#endif - - -void Instance::fork_and_monitor() -{ - log_info("starting instance %s", options.instance_name); - - if (launch_and_wait()) - return; /* error is logged */ - /* set instance state to crashed */ pthread_mutex_lock(&LOCK_instance); crashed= 1; @@ -230,11 +369,10 @@ void Instance::fork_and_monitor() pthread_cond_signal(&COND_instance_stopped); /* wake guardian */ pthread_cond_signal(&instance_map->guardian->COND_guardian); - /* thread exits */ - return; } + Instance::Instance(): crashed(0) { pthread_mutex_init(&LOCK_instance, 0); diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h index 0ff5ecc179e..ee37690d40a 100644 --- a/server-tools/instance-manager/instance.h +++ b/server-tools/instance-manager/instance.h @@ -41,7 +41,8 @@ public: /* send a signal to the instance */ void kill_instance(int signo); int is_crashed(); - void fork_and_monitor(); + void set_crash_flag_n_wake_all(); + Instance_map *Instance::get_map(); public: enum { DEFAULT_SHUTDOWN_DELAY= 35 }; @@ -63,7 +64,6 @@ private: Instance_map *instance_map; void remove_pid(); - int launch_and_wait(); }; #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */ diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index 0ae364e5b2d..998bf470c8d 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -130,6 +130,8 @@ int Instance_options::fill_instance_version() version_option, sizeof(version_option))) goto err; + bzero(result, MAX_VERSION_STRING_LENGTH); + rc= parse_output_and_get_value(cmd.buffer, mysqld_path, result, MAX_VERSION_STRING_LENGTH, GET_LINE); From c234386a40492827cd8c24590f7f0ec2ac7d0053 Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Fri, 19 Aug 2005 18:00:16 +0400 Subject: [PATCH 181/230] the syntax is XA END xid [SUSPEND [FOR MIGRATE]] --- sql/sql_yacc.yy | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3fa015ad623..08989c96903 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8833,7 +8833,7 @@ xa: XA_SYM begin_or_start xid opt_join_or_resume { Lex->sql_command = SQLCOM_XA_START; } - | XA_SYM END xid opt_suspend_or_migrate + | XA_SYM END xid opt_suspend { Lex->sql_command = SQLCOM_XA_END; } @@ -8893,9 +8893,14 @@ opt_one_phase: | ONE_SYM PHASE_SYM { Lex->xa_opt=XA_ONE_PHASE; } ; -opt_suspend_or_migrate: +opt_suspend: /* nothing */ { Lex->xa_opt=XA_NONE; } | SUSPEND_SYM { Lex->xa_opt=XA_SUSPEND; } + opt_migrate + ; + +opt_migrate: + /* nothing */ { } | FOR_SYM MIGRATE_SYM { Lex->xa_opt=XA_FOR_MIGRATE; } ; From c79ba8e3469a3a37074248be9f80e274cff65e99 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Fri, 19 Aug 2005 16:25:55 +0200 Subject: [PATCH 182/230] BUG#12532: Added more memory in malloc for slave query cache --- sql/log_event.cc | 8 +++++++- sql/sql_cache.cc | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index bdf17ba20e3..5b9287f03ac 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1330,7 +1330,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + time_zone_len + 1 + - data_len + 1, MYF(MY_WME)))) + data_len + 1 + +#ifndef MYSQL_CLIENT +#ifdef HAVE_QUERY_CACHE + QUERY_CACHE_FLAGS_SIZE + +#endif +#endif + db_len + 1, MYF(MY_WME)))) DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 0f4fdd52583..81eed413a8e 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -923,6 +923,10 @@ end: 0 The query was cached and user was sent the result. -1 The query was cached but we didn't have rights to use it. No error is sent to the client yet. + + NOTE + This method requires that sql points to allocated memory of size: + tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE; */ int From d9efe655ed8f0377725ace8912f0123175d4099d Mon Sep 17 00:00:00 2001 From: "elliot@mysql.com" <> Date: Fri, 19 Aug 2005 14:49:34 -0400 Subject: [PATCH 183/230] Bug#11338 Fixes from review (identical functionality). --- include/my_sys.h | 1 - mysql-test/r/ctype_cp932.result | 14 ++++++++++++++ mysql-test/t/ctype_cp932.test | 20 ++++++++++++++++++++ mysys/charset.c | 18 ------------------ sql/item.cc | 15 +++++++-------- sql/item.h | 3 ++- sql/log_event.cc | 2 +- sql/log_event.h | 2 +- sql/sql_prepare.cc | 9 ++++++--- 9 files changed, 51 insertions(+), 33 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index eafa41a05c8..8752aa30772 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -788,7 +788,6 @@ extern my_bool init_compiled_charsets(myf flags); extern void add_compiled_collation(CHARSET_INFO *cs); extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); -extern char *bare_str_to_hex(char *to, const char *from, uint len); #ifdef __WIN__ #define BACKSLASH_MBTAIL /* File system character set */ diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result index 0e28edc6df3..85e317481d1 100644 --- a/mysql-test/r/ctype_cp932.result +++ b/mysql-test/r/ctype_cp932.result @@ -8576,6 +8576,20 @@ FC4B DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS FROM 27642; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.000001 27642 Query 1 27642 use `test`; CREATE TABLE t1(f1 blob) +master-bin.000001 27701 Query 1 27701 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=95,COLLATION_CONNECTION=95,COLLATION_DATABASE=95,COLLATION_SERVER=8 +master-bin.000001 27837 User var 1 27837 @`var1`=_binary 0x8300 COLLATE binary +master-bin.000001 27876 Query 1 27876 use `test`; INSERT INTO t1 VALUES(@'var1') +SELECT HEX(f1) FROM t1; +HEX(f1) +8300 +DROP table t1; SET collation_connection='cp932_japanese_ci'; create table t1 select repeat('a',4000) a; delete from t1; diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index 7060d917ab0..34bf7965248 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -401,6 +401,26 @@ DROP TABLE t2; DROP TABLE t3; #DROP TABLE t4; +# Test prepared statement with 0x8300 sequence in parameter while +# running with cp932 client character set. +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +# TODO: Note that this doesn't actually test the code which was added for +# bug#11338 because this syntax for prepared statements causes the PS to +# be replicated differently than if we executed the PS from C or Java. +# Using this syntax, variable names are inserted into the binlog instead +# of values. The real goal of this test is to check the code that was +# added to Item_param::query_val_str() in order to do hex encoding of +# PS parameters when the client character set is cp932; +# Bug#11338 has an example java program which can be used to verify this +# code (and I have used it to test the fix) until there is some way to +# exercise this code from mysql-test-run. +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS FROM 27642; +SELECT HEX(f1) FROM t1; +DROP table t1; +# end test for bug#11338 SET collation_connection='cp932_japanese_ci'; -- source include/ctype_filesort.inc diff --git a/mysys/charset.c b/mysys/charset.c index df3f1cfa279..3a39fce9437 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -663,21 +663,3 @@ CHARSET_INFO *fs_character_set() return fs_cset_cache; } #endif - -/* - Transforms a string into hex form. - */ -char *bare_str_to_hex(char *to, const char *from, uint len) -{ - char *p= to; - uint i; - for (i= 0; i < len; i++, p+= 2) - { - /* val[i] is char. Casting to uchar helps greatly if val[i] < 0 */ - uint tmp= (uint) (uchar) from[i]; - p[0]= _dig_vec_upper[tmp >> 4]; - p[1]= _dig_vec_upper[tmp & 15]; - } - *p= 0; - return p; // pointer to end 0 of 'to' -} diff --git a/sql/item.cc b/sql/item.cc index 79579eeeb67..2ae56d17b07 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1230,7 +1230,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) CHARSET_INFO *tocs= thd->variables.collation_connection; uint32 dummy_offset; - value.cs_info.character_set_client= fromcs; + value.cs_info.character_set_of_placeholder= fromcs; /* Setup source and destination character sets so that they are different only if conversion is necessary: this will @@ -1443,7 +1443,7 @@ String *Item_param::val_str(String* str) and avoid one more memcpy/alloc between str and log string. */ -const String *Item_param::query_val_str(String* str, THD *thd) const +const String *Item_param::query_val_str(String* str) const { switch (state) { case INT_VALUE: @@ -1482,18 +1482,17 @@ const String *Item_param::query_val_str(String* str, THD *thd) const buf= str->c_ptr_quick(); ptr= buf; - if (thd->charset()->escape_with_backslash_is_dangerous) + if (value.cs_info.character_set_client->escape_with_backslash_is_dangerous) { - ptr= strmov(ptr, "x\'"); - ptr= bare_str_to_hex(ptr, str_value.ptr(), str_value.length()); + ptr= str_to_hex(ptr, str_value.ptr(), str_value.length()); } else { *ptr++= '\''; ptr+= escape_string_for_mysql(str_value.charset(), ptr, str_value.ptr(), str_value.length()); + *ptr++='\''; } - *ptr++='\''; str->length(ptr - buf); break; } @@ -1523,10 +1522,10 @@ bool Item_param::convert_str_value(THD *thd) here only if conversion is really necessary. */ if (value.cs_info.final_character_set_of_str_value != - value.cs_info.character_set_client) + value.cs_info.character_set_of_placeholder) { rc= thd->convert_string(&str_value, - value.cs_info.character_set_client, + value.cs_info.character_set_of_placeholder, value.cs_info.final_character_set_of_str_value); } else diff --git a/sql/item.h b/sql/item.h index ff34dfad025..080b804c730 100644 --- a/sql/item.h +++ b/sql/item.h @@ -532,6 +532,7 @@ public: struct CONVERSION_INFO { CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_of_placeholder; /* This points at character set of connection if conversion to it is required (i. e. if placeholder typecode is not BLOB). @@ -591,7 +592,7 @@ public: */ void (*set_param_func)(Item_param *param, uchar **pos, ulong len); - const String *query_val_str(String *str, THD *thd) const; + const String *query_val_str(String *str) const; bool convert_str_value(THD *thd); diff --git a/sql/log_event.cc b/sql/log_event.cc index 4d260763491..66c732e8cb0 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -207,7 +207,7 @@ static inline int read_str(char * &buf, char *buf_end, char * &str, /* Transforms a string into "" or its expression in 0x... form. */ -static char *str_to_hex(char *to, char *from, uint len) +char *str_to_hex(char *to, const char *from, uint len) { char *p= to; if (len) diff --git a/sql/log_event.h b/sql/log_event.h index 7ae4e863fc2..5c81d0c92f0 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1069,5 +1069,5 @@ public: bool is_valid() { return 1; } }; #endif - +char *str_to_hex(char *to, const char *from, uint len); #endif /* _log_event_h */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d0c06a3eaf7..8a50d0bd50e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -528,7 +528,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: param->set_param_func= set_param_str; - param->value.cs_info.character_set_client= &my_charset_bin; + param->value.cs_info.character_set_of_placeholder= &my_charset_bin; + param->value.cs_info.character_set_client= + thd->variables.character_set_client; param->value.cs_info.final_character_set_of_str_value= &my_charset_bin; param->item_type= Item::STRING_ITEM; param->item_result_type= STRING_RESULT; @@ -544,6 +546,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, CHARSET_INFO *tocs= thd->variables.collation_connection; uint32 dummy_offset; + param->value.cs_info.character_set_of_placeholder= fromcs; param->value.cs_info.character_set_client= fromcs; /* @@ -601,7 +604,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, param->set_param_func(param, &read_pos, data_end - read_pos); } } - res= param->query_val_str(&str, thd); + res= param->query_val_str(&str); if (param->convert_str_value(thd)) DBUG_RETURN(1); /* out of memory */ @@ -749,7 +752,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) client_param->buffer_length); } } - res= param->query_val_str(&str, thd); + res= param->query_val_str(&str); if (param->convert_str_value(thd)) DBUG_RETURN(1); /* out of memory */ From bbbb56df8f29ba3f9601e0c45cbc8564d5b2d5e0 Mon Sep 17 00:00:00 2001 From: "elliot@mysql.com" <> Date: Fri, 19 Aug 2005 17:55:28 -0400 Subject: [PATCH 184/230] Fix ctype_cp932 test to be deterministic on different machines. --- mysql-test/r/ctype_cp932.result | 13 ++++++++----- mysql-test/t/ctype_cp932.test | 4 +++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result index 85e317481d1..0711f251a07 100644 --- a/mysql-test/r/ctype_cp932.result +++ b/mysql-test/r/ctype_cp932.result @@ -8576,16 +8576,19 @@ FC4B DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; +RESET MASTER; CREATE TABLE t1(f1 blob); PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; SET @var1= x'8300'; EXECUTE stmt1 USING @var1; -SHOW BINLOG EVENTS FROM 27642; +SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 27642 Query 1 27642 use `test`; CREATE TABLE t1(f1 blob) -master-bin.000001 27701 Query 1 27701 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=95,COLLATION_CONNECTION=95,COLLATION_DATABASE=95,COLLATION_SERVER=8 -master-bin.000001 27837 User var 1 27837 @`var1`=_binary 0x8300 COLLATE binary -master-bin.000001 27876 Query 1 27876 use `test`; INSERT INTO t1 VALUES(@'var1') +master-bin.000001 # Start 1 # Server ver: 4.1.15-debug-log, Binlog ver: 3 +master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=95,COLLATION_CONNECTION=95,COLLATION_DATABASE=95,COLLATION_SERVER=8 +master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1(f1 blob) +master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=95,COLLATION_CONNECTION=95,COLLATION_DATABASE=95,COLLATION_SERVER=8 +master-bin.000001 # User var 1 # @`var1`=_binary 0x8300 COLLATE binary +master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES(@'var1') SELECT HEX(f1) FROM t1; HEX(f1) 8300 diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index 34bf7965248..8f471ebb979 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -403,6 +403,7 @@ DROP TABLE t3; # Test prepared statement with 0x8300 sequence in parameter while # running with cp932 client character set. +RESET MASTER; CREATE TABLE t1(f1 blob); PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; SET @var1= x'8300'; @@ -417,7 +418,8 @@ SET @var1= x'8300'; # code (and I have used it to test the fix) until there is some way to # exercise this code from mysql-test-run. EXECUTE stmt1 USING @var1; -SHOW BINLOG EVENTS FROM 27642; +--replace_column 2 # 5 # +SHOW BINLOG EVENTS; SELECT HEX(f1) FROM t1; DROP table t1; # end test for bug#11338 From 24f81a781e5c0a5ef340889680c47e35c3d576c6 Mon Sep 17 00:00:00 2001 From: "elliot@mysql.com" <> Date: Fri, 19 Aug 2005 18:17:54 -0400 Subject: [PATCH 185/230] Fix wrong auto-merge. --- strings/ctype-cp932.c | 2 ++ strings/ctype-eucjpms.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index f62cf2db599..b5f36c030bd 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -5522,6 +5522,7 @@ CHARSET_INFO my_charset_cp932_japanese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -5552,6 +5553,7 @@ CHARSET_INFO my_charset_cp932_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c index 2ab103d65ac..ccdca2ba595 100644 --- a/strings/ctype-eucjpms.c +++ b/strings/ctype-eucjpms.c @@ -8708,6 +8708,7 @@ CHARSET_INFO my_charset_eucjpms_japanese_ci= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -8739,6 +8740,7 @@ CHARSET_INFO my_charset_eucjpms_bin= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; From a3c893e0b8cc630cef295b70b6779f133b9b9eb3 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Fri, 19 Aug 2005 15:51:40 -0700 Subject: [PATCH 186/230] Fix cases where SLEEP() calls would get optimized away or cached. (Bug #12689) --- mysql-test/r/func_misc.result | 24 ++++++++++++++++++++++++ mysql-test/t/func_misc.test | 23 +++++++++++++++++++++++ sql/item_create.cc | 1 + sql/item_func.h | 6 ++++++ 4 files changed, 54 insertions(+) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 670b8754e30..36666fc827d 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -70,3 +70,27 @@ select timediff(b, a) >= '00:00:03' from t1; timediff(b, a) >= '00:00:03' 1 drop table t1; +set global query_cache_size=1355776; +create table t1 (a int); +insert into t1 values (1),(1),(1); +create table t2 (a datetime default null, b datetime default null); +insert into t2 set a = now(); +select a from t1 where sleep(1); +a +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(a); +a +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(1); +a +update t2 set b = now() where b is null; +select timediff(b, a) >= '00:00:03' from t2; +timediff(b, a) >= '00:00:03' +1 +1 +1 +drop table t2; +drop table t1; +set global query_cache_size=default; diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index f4cbacb93bb..4a618a56483 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -55,3 +55,26 @@ select sleep(3); update t1 set b = now(); select timediff(b, a) >= '00:00:03' from t1; drop table t1; + +# +# Bug #12689: SLEEP() gets incorrectly cached/optimized-away +# +set global query_cache_size=1355776; +create table t1 (a int); +insert into t1 values (1),(1),(1); +create table t2 (a datetime default null, b datetime default null); +insert into t2 set a = now(); +select a from t1 where sleep(1); +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(a); +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(1); +update t2 set b = now() where b is null; +select timediff(b, a) >= '00:00:03' from t2; +drop table t2; +drop table t1; +set global query_cache_size=default; + +# End of 5.0 tests diff --git a/sql/item_create.cc b/sql/item_create.cc index 8798bf889fc..77476e41d0b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -356,6 +356,7 @@ Item *create_func_sha(Item* a) Item *create_func_sleep(Item* a) { + current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new Item_func_sleep(a); } diff --git a/sql/item_func.h b/sql/item_func.h index 1f25b762b70..384cb486f7c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -893,7 +893,13 @@ class Item_func_sleep :public Item_int_func { public: Item_func_sleep(Item *a) :Item_int_func(a) {} + bool const_item() const { return 0; } const char *func_name() const { return "sleep"; } + void update_used_tables() + { + Item_int_func::update_used_tables(); + used_tables_cache|= RAND_TABLE_BIT; + } longlong val_int(); }; From 00fd26baeb7b707d75be4fc762a62f709b8f29a4 Mon Sep 17 00:00:00 2001 From: "elliot@mysql.com" <> Date: Fri, 19 Aug 2005 19:08:47 -0400 Subject: [PATCH 187/230] Add test that got dropped in automerge --- mysql-test/r/ctype_cp932.result | 15 +++++++++++++++ mysql-test/t/ctype_cp932.test | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result index 2661ff5e3c9..f677af7db76 100755 --- a/mysql-test/r/ctype_cp932.result +++ b/mysql-test/r/ctype_cp932.result @@ -11315,6 +11315,21 @@ DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; +RESET MASTER; +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server ver: 5.0.12-beta-debug-log, Binlog ver: 4 +master-bin.000001 98 Query 1 185 use `test`; CREATE TABLE t1(f1 blob) +master-bin.000001 185 User var 1 224 @`var1`=_binary 0x8300 COLLATE binary +master-bin.000001 224 Query 1 317 use `test`; INSERT INTO t1 VALUES(@'var1') +SELECT HEX(f1) FROM t1; +HEX(f1) +8300 +DROP table t1; SET collation_connection='cp932_japanese_ci'; create table t1 select repeat('a',4000) a; delete from t1; diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index fed87af3adc..c41ee489a37 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -398,6 +398,27 @@ DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; +# Test prepared statement with 0x8300 sequence in parameter while +# running with cp932 client character set. +RESET MASTER; +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +# TODO: Note that this doesn't actually test the code which was added for +# bug#11338 because this syntax for prepared statements causes the PS to +# be replicated differently than if we executed the PS from C or Java. +# Using this syntax, variable names are inserted into the binlog instead +# of values. The real goal of this test is to check the code that was +# added to Item_param::query_val_str() in order to do hex encoding of +# PS parameters when the client character set is cp932; +# Bug#11338 has an example java program which can be used to verify this +# code (and I have used it to test the fix) until there is some way to +# exercise this code from mysql-test-run. +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS; +SELECT HEX(f1) FROM t1; +DROP table t1; +# end test for bug#11338 SET collation_connection='cp932_japanese_ci'; -- source include/ctype_filesort.inc From 1c1f26d5e2dbd35bf26ddc7f4830ceacd86eb3f9 Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Sat, 20 Aug 2005 11:00:00 +0300 Subject: [PATCH 188/230] Fixes during review of new pushed code Fixed new bug when running a SP without a default database --- mysql-test/r/information_schema.result | 4 + mysql-test/r/sp-security.result | 2 + mysql-test/t/information_schema.test | 1 + mysql-test/t/sp-security.test | 6 + sql/item_strfunc.cc | 3 - sql/mysqld.cc | 3 +- sql/sql_base.cc | 13 +- sql/sql_db.cc | 22 +- sql/sql_parse.cc | 7 +- sql/sql_show.cc | 379 +++++++++++++------------ 10 files changed, 233 insertions(+), 207 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 64e2434521e..7ec2fcdd453 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -966,4 +966,8 @@ column_name column_default a NULL b NULL use test; +show columns from t1; +Field Type Null Key Default Extra +a int(11) NO +b int(11) YES NULL drop table t1; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index d78f5fc36ea..eb2e2ce334e 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -245,6 +245,8 @@ end// grant usage on *.* to mysqltest_1@localhost; call mysqltest_1.p1(); ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1' +call mysqltest_1.p1(); +ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1' drop procedure mysqltest_1.p1; drop database mysqltest_1; revoke usage on *.* from mysqltest_1@localhost; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 03810447299..04d53828035 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -649,4 +649,5 @@ use information_schema; select column_name, column_default from columns where table_schema='test' and table_name='t1'; use test; +show columns from t1; drop table t1; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index c7c7ef20a5b..6f1332f80d5 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -397,6 +397,12 @@ connection n1; --error 1370 call mysqltest_1.p1(); disconnect n1; +# Test also without a current database +connect (n2,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK); +connection n2; +--error 1370 +call mysqltest_1.p1(); +disconnect n2; connection default; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1e1cc123e60..094a0c56319 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2176,9 +2176,6 @@ void Item_func_lpad::fix_length_and_dec() { ulonglong length= ((ulonglong) args[1]->val_int() * collation.collation->mbmaxlen); - /*a comment before (merged) */ - length= max((ulonglong)args[0]->max_length, length); - /*a comment after */ if (length >= MAX_BLOB_WIDTH) { length= MAX_BLOB_WIDTH; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e58fa669130..5288fc04294 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -730,7 +730,8 @@ static void close_connections(void) DBUG_PRINT("quit",("Informing thread %ld that it's time to die", tmp->thread_id)); /* We skip slave threads on this first loop through. */ - if (tmp->slave_thread) continue; + if (tmp->slave_thread) + continue; tmp->killed= THD::KILL_CONNECTION; if (tmp->mysys_var) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 98ce12eb7de..f9193d38c98 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -150,14 +150,10 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) DBUG_ASSERT(share->table_name != 0); if ((!share->table_name)) // To be removed continue; // Shouldn't happen - if (db && my_strcasecmp(system_charset_info, db, share->table_cache_key)) + if (db && my_strcasecmp(system_charset_info, db, share->db)) + continue; + if (wild && wild_compare(share->table_name,wild,0)) continue; - - if (wild) - { - if (wild_compare(share->table_name,wild,0)) - continue; - } /* Check if user has SELECT privilege for any column in the table */ table_list.db= (char*) share->db; @@ -3803,7 +3799,6 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (cur_left_neighbor && cur_table_ref->outer_join & JOIN_TYPE_RIGHT) { - DBUG_ASSERT(cur_table_ref); /* This can happen only for JOIN ... ON. */ DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2); swap_variables(TABLE_LIST*, cur_left_neighbor, cur_table_ref); @@ -3813,7 +3808,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, store_top_level_join_columns(thd, cur_table_ref, cur_left_neighbor, cur_right_neighbor)) DBUG_RETURN(TRUE); - cur_right_neighbor= cur_table_ref; + cur_right_neighbor= cur_table_ref; } } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 67fc1053774..874dfd5f975 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -998,7 +998,7 @@ err: mysql_change_db() thd Thread handler name Databasename - no_access_check True= don't do access check + no_access_check True don't do access check. In this case name may be "" DESCRIPTION Becasue the database name may have been given directly from the @@ -1025,14 +1025,22 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) char *dbname=my_strdup((char*) name,MYF(MY_WME)); char path[FN_REFLEN]; HA_CREATE_INFO create; - bool schema_db= 0; + bool system_db= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; #endif DBUG_ENTER("mysql_change_db"); + DBUG_PRINT("enter",("name: '%s'",name)); + /* dbname can only be NULL if malloc failed */ if (!dbname || !(db_length= strlen(dbname))) { + if (no_access_check && dbname) + { + /* Called from SP when orignal database was not set */ + system_db= 1; + goto end; + } x_free(dbname); /* purecov: inspected */ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */ @@ -1047,7 +1055,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) DBUG_PRINT("info",("Use database: %s", dbname)); if (!my_strcasecmp(system_charset_info, dbname, information_schema_name.str)) { - schema_db= 1; + system_db= 1; #ifndef NO_EMBEDDED_ACCESS_CHECKS db_access= SELECT_ACL; #endif @@ -1055,13 +1063,15 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!no_access_check) { + if (!no_access_check) + { if (test_all_bits(thd->master_access,DB_ACLS)) db_access=DB_ACLS; else db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | thd->master_access); - if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) + if (!(db_access & DB_ACLS) && (!grant_option || + check_grant_db(thd,dbname))) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), thd->priv_user, @@ -1094,7 +1104,7 @@ end: if (!no_access_check) thd->db_access=db_access; #endif - if (schema_db) + if (system_db) { thd->db_charset= system_charset_info; thd->variables.collation_database= system_charset_info; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2ba82954319..4fc01d99d22 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -238,7 +238,8 @@ end: /* - Check if user exist and password supplied is correct. + Check if user exist and password supplied is correct. + SYNOPSIS check_user() thd thread handle, thd->{host,user,ip} are used @@ -273,6 +274,10 @@ int check_user(THD *thd, enum enum_server_command command, /* Change database if necessary */ if (db && db[0]) { + /* + thd->db is saved in caller and needs to be freed by caller if this + function returns 0 + */ thd->db= 0; thd->db_length= 0; if (mysql_change_db(thd, db, FALSE)) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b06f1d683dd..767981702db 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -620,7 +620,7 @@ static const char *require_quotes(const char *name, uint name_length) uint length; const char *end= name + name_length; - for ( ; name < end ; name++) + for (; name < end ; name++) { uchar chr= (uchar) *name; length= my_mbcharlen(system_charset_info, chr); @@ -1908,7 +1908,7 @@ int make_db_list(THD *thd, List *files, int schema_tables_add(THD *thd, List *files, const char *wild) { ST_SCHEMA_TABLE *tmp_schema_table= schema_tables; - for ( ; tmp_schema_table->table_name; tmp_schema_table++) + for (; tmp_schema_table->table_name; tmp_schema_table++) { if (tmp_schema_table->hidden) continue; @@ -2365,7 +2365,13 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, LEX *lex= thd->lex; const char *wild= lex->wild ? lex->wild->ptr() : NullS; CHARSET_INFO *cs= system_charset_info; + TABLE *show_table; + handler *file; + Field **ptr,*field; + int count; + uint base_name_length, file_name_length; DBUG_ENTER("get_schema_column_record"); + if (res) { if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS) @@ -2382,189 +2388,187 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, DBUG_RETURN(res); } - TABLE *show_table= tables->table; - handler *file= show_table->file; + show_table= tables->table; + file= show_table->file; + count= 0; file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); restore_record(show_table, s->default_values); - Field **ptr,*field; - int count= 0; + base_name_length= strlen(base_name); + file_name_length= strlen(file_name); + for (ptr=show_table->field; (field= *ptr) ; ptr++) { - if (!wild || !wild[0] || - !wild_case_compare(system_charset_info, field->field_name,wild)) - { - const char *tmp_buff; - byte *pos; - bool is_blob; - uint flags=field->flags; - char tmp[MAX_FIELD_WIDTH]; - char tmp1[MAX_FIELD_WIDTH]; - String type(tmp,sizeof(tmp), system_charset_info); - char *end= tmp; - count++; - restore_record(table, s->default_values); + const char *tmp_buff; + byte *pos; + bool is_blob; + uint flags=field->flags; + char tmp[MAX_FIELD_WIDTH]; + char tmp1[MAX_FIELD_WIDTH]; + String type(tmp,sizeof(tmp), system_charset_info); + char *end; + int decimals, field_length; + + if (wild && wild[0] && + wild_case_compare(system_charset_info, field->field_name,wild)) + continue; + + flags= field->flags; + count++; + /* Get default row, with all NULL fields set to NULL */ + restore_record(table, s->default_values); #ifndef NO_EMBEDDED_ACCESS_CHECKS - uint col_access; - check_access(thd,SELECT_ACL | EXTRA_ACL, base_name, - &tables->grant.privilege, 0, 0); - col_access= get_column_grant(thd, &tables->grant, - base_name, file_name, - field->field_name) & COL_ACLS; - if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS && - !tables->schema_table && !col_access) - continue; - for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) + uint col_access; + check_access(thd,SELECT_ACL | EXTRA_ACL, base_name, + &tables->grant.privilege, 0, 0); + col_access= get_column_grant(thd, &tables->grant, + base_name, file_name, + field->field_name) & COL_ACLS; + if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS && + !tables->schema_table && !col_access) + continue; + end= tmp; + for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) + { + if (col_access & 1) { - if (col_access & 1) - { - *end++=','; - end=strmov(end,grant_types.type_names[bitnr]); - } + *end++=','; + end=strmov(end,grant_types.type_names[bitnr]); } - if (tables->schema_table) // any user has 'select' privilege on all - // I_S table columns - table->field[17]->store(grant_types.type_names[0], - strlen(grant_types.type_names[0]), cs); - else - table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs); - -#else - *end= 0; -#endif - table->field[1]->store(base_name, strlen(base_name), cs); - table->field[2]->store(file_name, strlen(file_name), cs); - table->field[3]->store(field->field_name, strlen(field->field_name), - cs); - table->field[4]->store((longlong) count); - field->sql_type(type); - table->field[14]->store(type.ptr(), type.length(), cs); - tmp_buff= strchr(type.ptr(), '('); - table->field[7]->store(type.ptr(), - (tmp_buff ? tmp_buff - type.ptr() : - type.length()), cs); - if (show_table->timestamp_field == field && - field->unireg_check != Field::TIMESTAMP_UN_FIELD) - { - table->field[5]->store("CURRENT_TIMESTAMP", 17, cs); - table->field[5]->set_notnull(); - } - else if (field->unireg_check != Field::NEXT_NUMBER && - !field->is_null() && - !(field->flags & NO_DEFAULT_VALUE_FLAG)) - { - String def(tmp1,sizeof(tmp1), cs); - type.set(tmp, sizeof(tmp), field->charset()); - field->val_str(&type); - uint dummy_errors; - def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors); - table->field[5]->store(def.ptr(), def.length(), def.charset()); - table->field[5]->set_notnull(); - } - else if (field->unireg_check == Field::NEXT_NUMBER || - lex->orig_sql_command != SQLCOM_SHOW_FIELDS || - field->maybe_null()) - table->field[5]->set_null(); // Null as default - else - { - table->field[5]->store("",0, cs); - table->field[5]->set_notnull(); - } - pos=(byte*) ((flags & NOT_NULL_FLAG) && - field->type() != FIELD_TYPE_TIMESTAMP ? - "NO" : "YES"); - table->field[6]->store((const char*) pos, - strlen((const char*) pos), cs); - is_blob= (field->type() == FIELD_TYPE_BLOB); - if (field->has_charset() || is_blob) - { - longlong c_octet_len= is_blob ? (longlong) field->max_length() : - (longlong) field->max_length()/field->charset()->mbmaxlen; - table->field[8]->store(c_octet_len); - table->field[8]->set_notnull(); - table->field[9]->store((longlong) field->max_length()); - table->field[9]->set_notnull(); - } - - { - uint dec =field->decimals(); - switch (field->type()) { - case FIELD_TYPE_NEWDECIMAL: - table->field[10]->store((longlong) - ((Field_new_decimal*)field)->precision); - table->field[10]->set_notnull(); - table->field[11]->store((longlong) field->decimals()); - table->field[11]->set_notnull(); - break; - case FIELD_TYPE_DECIMAL: - { - uint int_part=field->field_length - (dec ? dec + 1 : 0); - table->field[10]->store((longlong) (int_part + dec - 1)); - table->field[10]->set_notnull(); - table->field[11]->store((longlong) field->decimals()); - table->field[11]->set_notnull(); - break; - } - case FIELD_TYPE_TINY: - case FIELD_TYPE_SHORT: - case FIELD_TYPE_LONG: - case FIELD_TYPE_LONGLONG: - case FIELD_TYPE_INT24: - { - table->field[10]->store((longlong) field->max_length() - 1); - table->field[10]->set_notnull(); - table->field[11]->store((longlong) 0); - table->field[11]->set_notnull(); - break; - } - case FIELD_TYPE_BIT: - { - table->field[10]->store((longlong) field->max_length()); - table->field[10]->set_notnull(); - break; - } - case FIELD_TYPE_FLOAT: - case FIELD_TYPE_DOUBLE: - { - table->field[10]->store((longlong) field->field_length); - table->field[10]->set_notnull(); - if (dec != NOT_FIXED_DEC) - { - table->field[11]->store((longlong) dec); - table->field[11]->set_notnull(); - } - break; - } - default: - break; - } - } - if (field->has_charset()) - { - pos=(byte*) field->charset()->csname; - table->field[12]->store((const char*) pos, - strlen((const char*) pos), cs); - table->field[12]->set_notnull(); - pos=(byte*) field->charset()->name; - table->field[13]->store((const char*) pos, - strlen((const char*) pos), cs); - table->field[13]->set_notnull(); - } - pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : - (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : - (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); - table->field[15]->store((const char*) pos, - strlen((const char*) pos), cs); - end= tmp; - if (field->unireg_check == Field::NEXT_NUMBER) - end=strmov(tmp,"auto_increment"); - table->field[16]->store(tmp, (uint) (end-tmp), cs); - - end=tmp; - table->field[18]->store(field->comment.str, field->comment.length, cs); - if (schema_table_store_record(thd, table)) - DBUG_RETURN(1); } + if (tables->schema_table) // any user has 'select' privilege on all + // I_S table columns + table->field[17]->store(grant_types.type_names[0], + strlen(grant_types.type_names[0]), cs); + else + table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs); + +#endif + table->field[1]->store(base_name, base_name_length, cs); + table->field[2]->store(file_name, file_name_length, cs); + table->field[3]->store(field->field_name, strlen(field->field_name), + cs); + table->field[4]->store((longlong) count); + field->sql_type(type); + table->field[14]->store(type.ptr(), type.length(), cs); + tmp_buff= strchr(type.ptr(), '('); + table->field[7]->store(type.ptr(), + (tmp_buff ? tmp_buff - type.ptr() : + type.length()), cs); + if (show_table->timestamp_field == field && + field->unireg_check != Field::TIMESTAMP_UN_FIELD) + { + table->field[5]->store("CURRENT_TIMESTAMP", 17, cs); + table->field[5]->set_notnull(); + } + else if (field->unireg_check != Field::NEXT_NUMBER && + !field->is_null() && + !(field->flags & NO_DEFAULT_VALUE_FLAG)) + { + String def(tmp1,sizeof(tmp1), cs); + type.set(tmp, sizeof(tmp), field->charset()); + field->val_str(&type); + uint dummy_errors; + def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors); + table->field[5]->store(def.ptr(), def.length(), def.charset()); + table->field[5]->set_notnull(); + } + else if (field->unireg_check == Field::NEXT_NUMBER || + lex->orig_sql_command != SQLCOM_SHOW_FIELDS || + field->maybe_null()) + table->field[5]->set_null(); // Null as default + else + { + table->field[5]->store("",0, cs); + table->field[5]->set_notnull(); + } + pos=(byte*) ((flags & NOT_NULL_FLAG) && + field->type() != FIELD_TYPE_TIMESTAMP ? + "NO" : "YES"); + table->field[6]->store((const char*) pos, + strlen((const char*) pos), cs); + is_blob= (field->type() == FIELD_TYPE_BLOB); + if (field->has_charset() || is_blob) + { + longlong c_octet_len= is_blob ? (longlong) field->max_length() : + (longlong) field->max_length()/field->charset()->mbmaxlen; + table->field[8]->store(c_octet_len); + table->field[8]->set_notnull(); + table->field[9]->store((longlong) field->max_length()); + table->field[9]->set_notnull(); + } + + /* + Calculate field_length and decimals. + They are set to -1 if they should not be set (we should return NULL) + */ + + decimals= field->decimals(); + switch (field->type()) { + case FIELD_TYPE_NEWDECIMAL: + field_length= ((Field_new_decimal*) field)->precision; + break; + case FIELD_TYPE_DECIMAL: + field_length= field->field_length - (decimals ? 2 : 1); + break; + case FIELD_TYPE_TINY: + case FIELD_TYPE_SHORT: + case FIELD_TYPE_LONG: + case FIELD_TYPE_LONGLONG: + case FIELD_TYPE_INT24: + field_length= field->max_length() - 1; + break; + case FIELD_TYPE_BIT: + field_length= field->max_length(); + decimals= -1; // return NULL + break; + case FIELD_TYPE_FLOAT: + case FIELD_TYPE_DOUBLE: + field_length= field->field_length; + if (decimals == NOT_FIXED_DEC) + decimals= -1; // return NULL + break; + default: + field_length= decimals= -1; + break; + } + + if (field_length >= 0) + { + table->field[10]->store((longlong) field_length); + table->field[10]->set_notnull(); + } + if (decimals >= 0) + { + table->field[11]->store((longlong) decimals); + table->field[11]->set_notnull(); + } + + if (field->has_charset()) + { + pos=(byte*) field->charset()->csname; + table->field[12]->store((const char*) pos, + strlen((const char*) pos), cs); + table->field[12]->set_notnull(); + pos=(byte*) field->charset()->name; + table->field[13]->store((const char*) pos, + strlen((const char*) pos), cs); + table->field[13]->set_notnull(); + } + pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : + (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : + (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); + table->field[15]->store((const char*) pos, + strlen((const char*) pos), cs); + + end= tmp; + if (field->unireg_check == Field::NEXT_NUMBER) + end=strmov(tmp,"auto_increment"); + table->field[16]->store(tmp, (uint) (end-tmp), cs); + + table->field[18]->store(field->comment.str, field->comment.length, cs); + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); } DBUG_RETURN(0); } @@ -2577,7 +2581,8 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; TABLE *table= tables->table; CHARSET_INFO *scs= system_charset_info; - for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ ) + + for (cs= all_charsets ; cs < all_charsets+255 ; cs++) { CHARSET_INFO *tmp_cs= cs[0]; if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && @@ -2585,12 +2590,12 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) !(wild && wild[0] && wild_case_compare(scs, tmp_cs->csname,wild))) { + const char *comment; restore_record(table, s->default_values); table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs); table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs); - table->field[2]->store(tmp_cs->comment ? tmp_cs->comment : "", - strlen(tmp_cs->comment ? tmp_cs->comment : ""), - scs); + comment= tmp_cs->comment ? tmp_cs->comment : ""; + table->field[2]->store(comment, strlen(comment), scs); table->field[3]->store((longlong) tmp_cs->mbmaxlen); if (schema_table_store_record(thd, table)) return 1; @@ -2606,14 +2611,14 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; TABLE *table= tables->table; CHARSET_INFO *scs= system_charset_info; - for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ ) + for (cs= all_charsets ; cs < all_charsets+255 ; cs++ ) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; - for ( cl= all_charsets; cl < all_charsets+255 ;cl ++) + for (cl= all_charsets; cl < all_charsets+255 ;cl ++) { CHARSET_INFO *tmp_cl= cl[0]; if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || @@ -2646,14 +2651,14 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond) CHARSET_INFO **cs; TABLE *table= tables->table; CHARSET_INFO *scs= system_charset_info; - for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ ) + for (cs= all_charsets ; cs < all_charsets+255 ; cs++ ) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; - for ( cl= all_charsets; cl < all_charsets+255 ;cl ++) + for (cl= all_charsets; cl < all_charsets+255 ;cl ++) { CHARSET_INFO *tmp_cl= cl[0]; if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || @@ -3258,7 +3263,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name) { ST_SCHEMA_TABLE *schema_table= schema_tables; - for ( ; schema_table->table_name; schema_table++) + for (; schema_table->table_name; schema_table++) { if (!my_strcasecmp(system_charset_info, schema_table->table_name, @@ -3299,7 +3304,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("create_schema_table"); - for ( ; fields_info->field_name; fields_info++) + for (; fields_info->field_name; fields_info++) { switch (fields_info->field_type) { case MYSQL_TYPE_LONG: @@ -3368,7 +3373,7 @@ int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { ST_FIELD_INFO *field_info= schema_table->fields_info; Name_resolution_context *context= &thd->lex->select_lex.context; - for ( ; field_info->field_name; field_info++) + for (; field_info->field_name; field_info++) { if (field_info->old_name) { From 5340e046618ca893450fb519dc06c87c4b9a068c Mon Sep 17 00:00:00 2001 From: "pappa@c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se" <> Date: Sat, 20 Aug 2005 10:07:46 -0400 Subject: [PATCH 189/230] Bug #12460 Table Full On 64 bit platforms the changed statement doesn't work so making sure that the larger value is first and using subtraction is a quick and backwards-compatible fix of this line. --- heap/hp_delete.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heap/hp_delete.c b/heap/hp_delete.c index 9cf8b8936b6..90e537081d3 100644 --- a/heap/hp_delete.c +++ b/heap/hp_delete.c @@ -80,7 +80,7 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, custom_arg.search_flag= SEARCH_SAME; old_allocated= keyinfo->rb_tree.allocated; res= tree_delete(&keyinfo->rb_tree, info->recbuf, &custom_arg); - info->s->index_length+= (keyinfo->rb_tree.allocated-old_allocated); + info->s->index_length-= (old_allocated - keyinfo->rb_tree.allocated); return res; } From d62295e44e0c0a6d0730e7429023486d0ef3204d Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Mon, 22 Aug 2005 01:13:37 +0300 Subject: [PATCH 190/230] Cleanup during review of new pushed code --- include/my_global.h | 14 +-- sql/item_cmpfunc.cc | 3 +- sql/sp_head.cc | 262 ++++++++++++++++++++++---------------------- sql/sql_base.cc | 2 +- sql/sql_lex.cc | 2 +- sql/sql_parse.cc | 2 +- sql/sql_view.cc | 2 +- sql/table.cc | 14 +-- 8 files changed, 152 insertions(+), 149 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index 2546dde754d..95d0b983b72 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -933,10 +933,10 @@ typedef char bool; /* Ordinary boolean values 0 1 */ (ABSTIME).ts_nsec=0; \ } #define set_timespec_nsec(ABSTIME,NSEC) \ -{\ - ulonglong now= my_getsystime(); \ - (ABSTIME).ts_sec= (now / ULL(10000000)) + (NSEC / ULL(1000000000)); \ - (ABSTIME).ts_nsec= (now % ULL(10000000)) * 100 + (NSEC % ULL(1000000000)); \ +{ \ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).ts_sec= (now / ULL(10000000)); \ + (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ } #else #define set_timespec(ABSTIME,SEC) \ @@ -948,9 +948,9 @@ typedef char bool; /* Ordinary boolean values 0 1 */ } #define set_timespec_nsec(ABSTIME,NSEC) \ {\ - ulonglong now= my_getsystime(); \ - (ABSTIME).tv_sec= (now / ULL(10000000)) + (NSEC / ULL(1000000000)); \ - (ABSTIME).tv_nsec= (now % ULL(10000000)) * 100 + (NSEC % ULL(1000000000)); \ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).tv_sec= (now / ULL(10000000)); \ + (ABSTIME).tv_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ } #endif /* HAVE_TIMESPEC_TS_SEC */ #endif /* set_timespec */ diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1bae5f1c9af..9443a2949d8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -630,7 +630,7 @@ int Arg_comparator::compare_row() owner->null_value= 0; res= 0; // continue comparison (maybe we will meet explicit difference) } - if (res) + else if (res) return res; } if (was_null) @@ -645,6 +645,7 @@ int Arg_comparator::compare_row() return 0; } + int Arg_comparator::compare_e_row() { (*a)->bring_value(); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f119ef1ec22..ebcbfb67fc8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -127,16 +127,17 @@ sp_prepare_func_item(THD* thd, Item **it_addr) /* Macro to switch arena in sp_eval_func_item */ -#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) do\ - {\ - if (condition) \ - thd->set_n_backup_item_arena(thd->spcont->callers_arena,\ - backup_arena);\ - new_command;\ - if (condition)\ - thd->restore_backup_item_arena(thd->spcont->callers_arena,\ - &backup_current_arena);\ - } while(0) +#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) \ + do \ + { \ + if (condition) \ + thd->set_n_backup_item_arena(thd->spcont->callers_arena, \ + backup_arena); \ + new_command; \ + if (condition) \ + thd->restore_backup_item_arena(thd->spcont->callers_arena, \ + &backup_current_arena); \ + } while(0) /* Evaluate an item and store it in the returned item @@ -174,88 +175,82 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, DBUG_RETURN(NULL); } - /* QQ How do we do this? Is there some better way? */ - if (type == MYSQL_TYPE_NULL) - goto return_null_item; - switch (sp_map_result_type(type)) { case INT_RESULT: - { - longlong i= it->val_int(); + { + longlong i= it->val_int(); - if (it->null_value) - { - DBUG_PRINT("info", ("INT_RESULT: null")); - goto return_null_item; - } - else - { - DBUG_PRINT("info", ("INT_RESULT: %d", i)); - CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i), - use_callers_arena, &backup_current_arena); - } - break; + if (it->null_value) + { + DBUG_PRINT("info", ("INT_RESULT: null")); + goto return_null_item; } + DBUG_PRINT("info", ("INT_RESULT: %d", i)); + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i), + use_callers_arena, &backup_current_arena); + break; + } case REAL_RESULT: - { - double d= it->val_real(); + { + double d= it->val_real(); + uint8 decimals; + uint32 max_length; - if (it->null_value) - { - DBUG_PRINT("info", ("REAL_RESULT: null")); - goto return_null_item; - } - else - { - /* There's some difference between Item::new_item() and the - * constructor; the former crashes, the latter works... weird. */ - uint8 decimals= it->decimals; - uint32 max_length= it->max_length; - DBUG_PRINT("info", ("REAL_RESULT: %g", d)); - CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d), - use_callers_arena, &backup_current_arena); - it->decimals= decimals; - it->max_length= max_length; - } - break; + if (it->null_value) + { + DBUG_PRINT("info", ("REAL_RESULT: null")); + goto return_null_item; } + + /* + There's some difference between Item::new_item() and the + constructor; the former crashes, the latter works... weird. + */ + decimals= it->decimals; + max_length= it->max_length; + DBUG_PRINT("info", ("REAL_RESULT: %g", d)); + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d), + use_callers_arena, &backup_current_arena); + it->decimals= decimals; + it->max_length= max_length; + break; + } case DECIMAL_RESULT: - { - my_decimal value, *val= it->val_decimal(&value); - if (it->null_value) - goto return_null_item; - else - CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val), - use_callers_arena, &backup_current_arena); + { + my_decimal value, *val= it->val_decimal(&value); + if (it->null_value) + goto return_null_item; + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val), + use_callers_arena, &backup_current_arena); #ifndef DBUG_OFF - char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; - DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val))); -#endif - break; - } - case STRING_RESULT: { - char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer, sizeof(buffer), it->collation.collation); - String *s= it->val_str(&tmp); - - if (it->null_value) - { - DBUG_PRINT("info", ("default result: null")); - goto return_null_item; - } - else - { - DBUG_PRINT("info",("default result: %*s", - s->length(), s->c_ptr_quick())); - CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) - Item_string(thd->strmake(s->ptr(), - s->length()), s->length(), - it->collation.collation), - use_callers_arena, &backup_current_arena); - } - break; + char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; + DBUG_PRINT("info", ("DECIMAL_RESULT: %s", + dbug_decimal_as_string(dbug_buff, val))); +#endif } + break; + } + case STRING_RESULT: + { + char buffer[MAX_FIELD_WIDTH]; + String tmp(buffer, sizeof(buffer), it->collation.collation); + String *s= it->val_str(&tmp); + + if (type == MYSQL_TYPE_NULL || it->null_value) + { + DBUG_PRINT("info", ("STRING_RESULT: null")); + goto return_null_item; + } + DBUG_PRINT("info",("STRING_RESULT: %*s", + s->length(), s->c_ptr_quick())); + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) + Item_string(thd->strmake(s->ptr(), + s->length()), s->length(), + it->collation.collation), + use_callers_arena, &backup_current_arena); + break; + } case ROW_RESULT: default: DBUG_ASSERT(0); @@ -574,13 +569,10 @@ sp_head::destroy() /* - * This is only used for result fields from functions (both during - * fix_length_and_dec() and evaluation). - * - * Since the current mem_root during a will be freed and the result - * field will be used by the caller, we have to put it in the caller's - * or main mem_root. - */ + This is only used for result fields from functions (both during + fix_length_and_dec() and evaluation). +*/ + Field * sp_head::make_field(uint max_length, const char *name, TABLE *dummy) { @@ -817,47 +809,49 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; uint i; - int ret; + Item_null *nit; + int ret= -1; // Assume error if (argcount != params) { /* - Need to use my_printf_error here, or it will not terminate the + Need to use my_error here, or it will not terminate the invoking query properly. */ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "FUNCTION", m_qname.str, params, argcount); - DBUG_RETURN(-1); + goto end; } // QQ Should have some error checking here? (types, etc...) - nctx= new sp_rcontext(csize, hmax, cmax); + if (!(nctx= new sp_rcontext(csize, hmax, cmax))) + goto end; for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE); - if (it) - nctx->push_item(it); - else - { - DBUG_RETURN(-1); - } + if (!it) + goto end; // EOM error + nctx->push_item(it); } + /* The rest of the frame are local variables which are all IN. Default all variables to null (those with default clauses will be set by an set instruction). */ + + nit= NULL; // Re-use this, and only create if needed + for (; i < csize ; i++) { - Item_null *nit= NULL; // Re-use this, and only create if needed - for (; i < csize ; i++) + if (! nit) { - if (! nit) - nit= new Item_null(); - nctx->push_item(nit); + if (!(nit= new Item_null())) + DBUG_RETURN(-1); } + nctx->push_item(nit); } thd->spcont= nctx; @@ -878,14 +872,15 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } nctx->pop_all_cursors(); // To avoid memory leaks after an error - delete nctx; + delete nctx; // Doesn't do anything thd->spcont= octx; +end: DBUG_RETURN(ret); } -static Item_func_get_user_var * -item_is_user_var(Item *it) + +static Item_func_get_user_var *item_is_user_var(Item *it) { if (it->type() == Item::FUNC_ITEM) { @@ -897,19 +892,18 @@ item_is_user_var(Item *it) return NULL; } -int -sp_head::execute_procedure(THD *thd, List *args) + +int sp_head::execute_procedure(THD *thd, List *args) { - DBUG_ENTER("sp_head::execute_procedure"); - DBUG_PRINT("info", ("procedure %s", m_name.str)); int ret= 0; uint csize = m_pcont->max_pvars(); uint params = m_pcont->current_pvars(); uint hmax = m_pcont->max_handlers(); uint cmax = m_pcont->max_cursors(); - sp_rcontext *octx = thd->spcont; + sp_rcontext *save_spcont, *octx; sp_rcontext *nctx = NULL; - my_bool is_tmp_octx = FALSE; // True if we have allocated a temporary octx + DBUG_ENTER("sp_head::execute_procedure"); + DBUG_PRINT("info", ("procedure %s", m_name.str)); if (args->elements != params) { @@ -918,17 +912,22 @@ sp_head::execute_procedure(THD *thd, List *args) DBUG_RETURN(-1); } + save_spcont= octx= thd->spcont; if (! octx) { // Create a temporary old context - octx= new sp_rcontext(csize, hmax, cmax); - is_tmp_octx= TRUE; + if (!(octx= new sp_rcontext(csize, hmax, cmax))) + DBUG_RETURN(-1); thd->spcont= octx; /* set callers_arena to thd, for upper-level function to work */ thd->spcont->callers_arena= thd; } - nctx= new sp_rcontext(csize, hmax, cmax); + if (!(nctx= new sp_rcontext(csize, hmax, cmax))) + { + thd->spcont= save_spcont; + DBUG_RETURN(-1); + } if (csize > 0 || hmax > 0 || cmax > 0) { @@ -937,7 +936,6 @@ sp_head::execute_procedure(THD *thd, List *args) List_iterator li(*args); Item *it; - /* Evaluate SP arguments (i.e. get the values passed as parameters) */ // QQ: Should do type checking? DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str)); @@ -959,20 +957,25 @@ sp_head::execute_procedure(THD *thd, List *args) if (pvar->mode == sp_param_out) { if (! nit) - nit= new Item_null(); + { + if (!(nit= new Item_null())) + { + ret= -1; + break; + } + } nctx->push_item(nit); // OUT } else { Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE); - if (it2) - nctx->push_item(it2); // IN or INOUT - else + if (!it2) { ret= -1; // Eval failed break; } + nctx->push_item(it2); // IN or INOUT } } } @@ -994,7 +997,13 @@ sp_head::execute_procedure(THD *thd, List *args) for (; i < csize ; i++) { if (! nit) - nit= new Item_null(); + { + if (!(nit= new Item_null())) + { + ret= -1; + break; + } + } nctx->push_item(nit); } } @@ -1090,15 +1099,12 @@ sp_head::execute_procedure(THD *thd, List *args) } } - if (is_tmp_octx) - { - delete octx; /* call destructor */ - octx= NULL; - } + if (!save_spcont) + delete octx; // Does nothing nctx->pop_all_cursors(); // To avoid memory leaks after an error - delete nctx; - thd->spcont= octx; + delete nctx; // Does nothing + thd->spcont= save_spcont; DBUG_RETURN(ret); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 23b8dae24fb..186d5984dcd 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3363,7 +3363,7 @@ static bool set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) { Name_resolution_context *context; - if (!(context= new Name_resolution_context)) + if (!(context= new (thd->mem_root) Name_resolution_context)) return TRUE; context->init(); context->first_name_resolution_table= diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6ede870a7fb..031d133a40c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1520,7 +1520,7 @@ void st_select_lex_unit::print(String *str) if (union_all) str->append("all ", 4); else if (union_distinct == sl) - union_all= true; + union_all= TRUE; } if (sl->braces) str->append('('); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 619a84e185e..31d0f3eb675 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6420,7 +6420,7 @@ Name_resolution_context * make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op) { Name_resolution_context *on_context; - if (!(on_context= new Name_resolution_context)) + if (!(on_context= new (thd->mem_root) Name_resolution_context)) return NULL; on_context->init(); on_context->first_name_resolution_table= diff --git a/sql/sql_view.cc b/sql/sql_view.cc index af21b43e5c9..dcada0c0780 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -310,7 +310,7 @@ bool mysql_create_view(THD *thd, open_and_lock_tables can change the value of tables, e.g. it may happen if before the function call tables was equal to 0. */ - for (tbl= tables= lex->query_tables; tbl; tbl= tbl->next_global) + for (tbl= lex->query_tables; tbl; tbl= tbl->next_global) { /* is this table temporary and is not view? */ if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view && diff --git a/sql/table.cc b/sql/table.cc index beecd6442e8..e84f8adc32f 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2518,12 +2518,9 @@ void Field_iterator_natural_join::set(TABLE_LIST *table_ref) void Field_iterator_natural_join::next() { cur_column_ref= (*column_ref_it)++; - DBUG_ASSERT(cur_column_ref ? - (cur_column_ref->table_field ? - cur_column_ref->table_ref->table == - cur_column_ref->table_field->table : - TRUE) : - TRUE); + DBUG_ASSERT(!cur_column_ref || ! cur_column_ref->table_field || + cur_column_ref->table_ref->table == + cur_column_ref->table_field->table); } @@ -2695,9 +2692,8 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created) nj_col= natural_join_it.column_ref(); DBUG_ASSERT(nj_col); } - DBUG_ASSERT(nj_col->table_field ? - nj_col->table_ref->table == nj_col->table_field->table : - TRUE); + DBUG_ASSERT(!nj_col->table_field || + nj_col->table_ref->table == nj_col->table_field->table); return nj_col; } From 90256d31d12fc1a69ca0fbadb00a6783860c3e95 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Mon, 22 Aug 2005 10:59:25 +0200 Subject: [PATCH 191/230] bug#12220 - ndb - node recovery with charsets LQH computes incorrect hash values during NR (as it doesn't concider charsets) Solution: make LQH compute correct hash :-) 1) move xfrm_key into SimulatedBlock so that there's _one_ impl. 2) make TC, ACC, LQH use same impl. --- ndb/include/kernel/AttributeDescriptor.hpp | 3 +- ndb/src/kernel/blocks/dbacc/Dbacc.hpp | 8 -- ndb/src/kernel/blocks/dbacc/DbaccInit.cpp | 1 - ndb/src/kernel/blocks/dbacc/DbaccMain.cpp | 129 ++---------------- ndb/src/kernel/blocks/dbdict/Dbdict.cpp | 68 ++++++---- ndb/src/kernel/blocks/dblqh/Dblqh.hpp | 2 +- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 59 +++------ ndb/src/kernel/blocks/dbtc/Dbtc.hpp | 5 - ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 145 +++------------------ ndb/src/kernel/vm/SimulatedBlock.cpp | 115 ++++++++++++++++ ndb/src/kernel/vm/SimulatedBlock.hpp | 20 +++ 11 files changed, 237 insertions(+), 318 deletions(-) diff --git a/ndb/include/kernel/AttributeDescriptor.hpp b/ndb/include/kernel/AttributeDescriptor.hpp index af28e777213..2fe7c9f0973 100644 --- a/ndb/include/kernel/AttributeDescriptor.hpp +++ b/ndb/include/kernel/AttributeDescriptor.hpp @@ -23,7 +23,8 @@ class AttributeDescriptor { friend class Dbacc; friend class Dbtup; friend class Dbtux; - + friend class SimulatedBlock; + private: static void setType(Uint32 &, Uint32 type); static void setSize(Uint32 &, Uint32 size); diff --git a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp index a2d6fe4d64a..8800388e96c 100644 --- a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp +++ b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp @@ -851,13 +851,6 @@ struct Tabrec { Uint32 fragptrholder[MAX_FRAG_PER_NODE]; Uint32 tabUserPtr; BlockReference tabUserRef; - - Uint8 noOfKeyAttr; - Uint8 hasCharAttr; - struct KeyAttr { - Uint32 attributeDescriptor; - CHARSET_INFO* charsetInfo; - } keyAttr[MAX_ATTRIBUTES_IN_INDEX]; }; typedef Ptr TabrecPtr; @@ -903,7 +896,6 @@ private: void execACCKEYREQ(Signal* signal); void execACCSEIZEREQ(Signal* signal); void execACCFRAGREQ(Signal* signal); - void execTC_SCHVERREQ(Signal* signal); void execACC_SRREQ(Signal* signal); void execNEXT_SCANREQ(Signal* signal); void execACC_ABORTREQ(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp index 90839163a72..d4ff20e4c43 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp @@ -179,7 +179,6 @@ Dbacc::Dbacc(const class Configuration & conf): addRecSignal(GSN_ACCKEYREQ, &Dbacc::execACCKEYREQ); addRecSignal(GSN_ACCSEIZEREQ, &Dbacc::execACCSEIZEREQ); addRecSignal(GSN_ACCFRAGREQ, &Dbacc::execACCFRAGREQ); - addRecSignal(GSN_TC_SCHVERREQ, &Dbacc::execTC_SCHVERREQ); addRecSignal(GSN_ACC_SRREQ, &Dbacc::execACC_SRREQ); addRecSignal(GSN_NEXT_SCANREQ, &Dbacc::execNEXT_SCANREQ); addRecSignal(GSN_ACC_ABORTREQ, &Dbacc::execACC_ABORTREQ); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index aefd2612151..37b6825cbd2 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -28,7 +28,8 @@ #include #include #include -#include +#include + // TO_DO_RONM is a label for comments on what needs to be improved in future versions // when more time is given. @@ -1037,12 +1038,6 @@ void Dbacc::initialiseTableRec(Signal* signal) tabptr.p->fragholder[i] = RNIL; tabptr.p->fragptrholder[i] = RNIL; }//for - tabptr.p->noOfKeyAttr = 0; - tabptr.p->hasCharAttr = 0; - for (Uint32 k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) { - tabptr.p->keyAttr[k].attributeDescriptor = 0; - tabptr.p->keyAttr[k].charsetInfo = 0; - } }//for }//Dbacc::initialiseTableRec() @@ -1172,8 +1167,8 @@ void Dbacc::execACCFRAGREQ(Signal* signal) Uint32 userPtr = req->userPtr; BlockReference retRef = req->userRef; rootfragrecptr.p->rootState = ACTIVEROOT; - AccFragConf * const conf = (AccFragConf*)&signal->theData[0]; + AccFragConf * const conf = (AccFragConf*)&signal->theData[0]; conf->userPtr = userPtr; conf->rootFragPtr = rootfragrecptr.i; conf->fragId[0] = rootfragrecptr.p->fragmentid[0]; @@ -1197,65 +1192,6 @@ void Dbacc::addFragRefuse(Signal* signal, Uint32 errorCode) return; }//Dbacc::addFragRefuseEarly() -void -Dbacc::execTC_SCHVERREQ(Signal* signal) -{ - jamEntry(); - if (! assembleFragments(signal)) { - jam(); - return; - } - tabptr.i = signal->theData[0]; - ptrCheckGuard(tabptr, ctablesize, tabrec); - Uint32 noOfKeyAttr = signal->theData[6]; - ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX); - Uint32 hasCharAttr = 0; - - SegmentedSectionPtr s0Ptr; - signal->getSection(s0Ptr, 0); - SectionReader r0(s0Ptr, getSectionSegmentPool()); - Uint32 i = 0; - while (i < noOfKeyAttr) { - jam(); - Uint32 attributeDescriptor = ~0; - Uint32 csNumber = ~0; - if (! r0.getWord(&attributeDescriptor) || - ! r0.getWord(&csNumber)) { - jam(); - break; - } - CHARSET_INFO* cs = 0; - if (csNumber != 0) { - cs = all_charsets[csNumber]; - ndbrequire(cs != 0); - hasCharAttr = 1; - } - tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor; - tabptr.p->keyAttr[i].charsetInfo = cs; - i++; - } - ndbrequire(i == noOfKeyAttr); - releaseSections(signal); - - tabptr.p->noOfKeyAttr = noOfKeyAttr; - tabptr.p->hasCharAttr = hasCharAttr; - - // copy char attr flag to each fragment - for (Uint32 i1 = 0; i1 < MAX_FRAG_PER_NODE; i1++) { - jam(); - if (tabptr.p->fragptrholder[i1] != RNIL) { - rootfragrecptr.i = tabptr.p->fragptrholder[i1]; - ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec); - for (Uint32 i2 = 0; i2 < 2; i2++) { - fragrecptr.i = rootfragrecptr.p->fragmentptr[i2]; - ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec); - fragrecptr.p->hasCharAttr = hasCharAttr; - } - } - } - - // no reply to DICT -} void Dbacc::execDROP_TAB_REQ(Signal* signal){ @@ -1841,55 +1777,14 @@ void Dbacc::execACCKEYREQ(Signal* signal) void Dbacc::xfrmKeyData(Signal* signal) { - tabptr.i = fragrecptr.p->myTableId; - ptrCheckGuard(tabptr, ctablesize, tabrec); - - Uint32 dst[1024 * MAX_XFRM_MULTIPLY]; - Uint32 dstSize = (sizeof(dst) >> 2); + Uint32 table = fragrecptr.p->myTableId; + Uint32 dst[MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY]; + Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]; Uint32* src = &signal->theData[7]; - const Uint32 noOfKeyAttr = tabptr.p->noOfKeyAttr; - Uint32 dstPos = 0; - Uint32 srcPos = 0; - Uint32 i = 0; - - while (i < noOfKeyAttr) { - const Tabrec::KeyAttr& keyAttr = tabptr.p->keyAttr[i]; - - Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor); - Uint32 srcWords = (srcBytes + 3) / 4; - Uint32 dstWords = ~0; - uchar* dstPtr = (uchar*)&dst[dstPos]; - const uchar* srcPtr = (const uchar*)&src[srcPos]; - CHARSET_INFO* cs = keyAttr.charsetInfo; - - if (cs == 0) { - jam(); - memcpy(dstPtr, srcPtr, srcWords << 2); - dstWords = srcWords; - } else { - jam(); - Uint32 typeId = AttributeDescriptor::getType(keyAttr.attributeDescriptor); - Uint32 lb, len; - bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); - ndbrequire(ok); - Uint32 xmul = cs->strxfrm_multiply; - if (xmul == 0) - xmul = 1; - // see comment in DbtcMain.cpp - Uint32 dstLen = xmul * (srcBytes - lb); - ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); - int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); - ndbrequire(n != -1); - while ((n & 3) != 0) - dstPtr[n++] = 0; - dstWords = (n >> 2); - } - dstPos += dstWords; - srcPos += srcWords; - i++; - } - memcpy(src, dst, dstPos << 2); - operationRecPtr.p->xfrmtupkeylen = dstPos; + Uint32 len = xfrm_key(table, src, dst, sizeof(dst) >> 2, keyPartLen); + ndbrequire(len); // 0 means error + memcpy(src, dst, len << 2); + operationRecPtr.p->xfrmtupkeylen = len; } void Dbacc::accIsLockedLab(Signal* signal) @@ -8024,6 +7919,10 @@ void Dbacc::initFragAdd(Signal* signal, Uint32 Tmp2 = regFragPtr.p->maxloadfactor - regFragPtr.p->minloadfactor; Tmp2 = Tmp1 * Tmp2; regFragPtr.p->slackCheck = Tmp2; + + Uint32 hasCharAttr = g_key_descriptor_pool.getPtr(req->tableId)->hasCharAttr; + regFragPtr.p->hasCharAttr = hasCharAttr; + }//Dbacc::initFragAdd() void Dbacc::initFragGeneral(FragmentrecPtr regFragPtr) diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 7d036b0e988..2725e7d14fe 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1750,6 +1751,7 @@ void Dbdict::execREAD_CONFIG_REQ(Signal* signal) c_schemaPageRecordArray.setSize(2 * NDB_SF_MAX_PAGES); c_tableRecordPool.setSize(tablerecSize); c_tableRecordHash.setSize(tablerecSize); + g_key_descriptor_pool.setSize(tablerecSize); c_triggerRecordPool.setSize(c_maxNoOfTriggers); c_triggerRecordHash.setSize(c_maxNoOfTriggers); c_opRecordPool.setSize(256); // XXX need config params @@ -4450,6 +4452,44 @@ Dbdict::execADD_FRAGREQ(Signal* signal) { sendSignal(DBLQH_REF, GSN_LQHFRAGREQ, signal, LqhFragReq::SignalLength, JBB); } + + /** + * Create KeyDescriptor + */ + KeyDescriptor* desc= g_key_descriptor_pool.getPtr(tabPtr.i); + new (desc) KeyDescriptor(); + + Uint32 key = 0; + Uint32 tAttr = tabPtr.p->firstAttribute; + while (tAttr != RNIL) + { + jam(); + AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); + if (aRec->tupleKey) + { + desc->noOfKeyAttr ++; + desc->keyAttr[key].attributeDescriptor = aRec->attributeDescriptor; + + Uint32 csNumber = (aRec->extPrecision >> 16); + if(csNumber) + { + desc->keyAttr[key].charsetInfo = all_charsets[csNumber]; + ndbrequire(all_charsets[csNumber]); + desc->hasCharAttr = 1; + } + else + { + desc->keyAttr[key].charsetInfo = 0; + } + if(AttributeDescriptor::getDKey(aRec->attributeDescriptor)) + { + desc->noOfDistrKeys ++; + } + key++; + } + tAttr = aRec->nextAttrInTable; + } + ndbrequire(key == tabPtr.p->noOfPrimkey); } void @@ -4644,31 +4684,11 @@ Dbdict::execTAB_COMMITCONF(Signal* signal){ signal->theData[4] = (Uint32)tabPtr.p->tableType; signal->theData[5] = createTabPtr.p->key; signal->theData[6] = (Uint32)tabPtr.p->noOfPrimkey; - - Uint32 buf[2 * MAX_ATTRIBUTES_IN_INDEX]; - Uint32 sz = 0; - Uint32 tAttr = tabPtr.p->firstAttribute; - while (tAttr != RNIL) { - jam(); - AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); - if (aRec->tupleKey) { - buf[sz++] = aRec->attributeDescriptor; - buf[sz++] = (aRec->extPrecision >> 16); // charset number - } - tAttr = aRec->nextAttrInTable; - } - ndbrequire((int)sz == 2 * tabPtr.p->noOfPrimkey); - - LinearSectionPtr lsPtr[3]; - lsPtr[0].p = buf; - lsPtr[0].sz = sz; - // note: ACC does not reply - if (tabPtr.p->isTable() || tabPtr.p->isHashIndex()) - sendSignal(DBACC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1); - sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1); + + sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB); return; } - + ndbrequire(false); } @@ -12342,3 +12362,5 @@ Dbdict::getMetaAttribute(MetaData::Attribute& attr, const MetaData::Table& table new (&attr) MetaData::Attribute(*attrPtr.p); return 0; } + +CArray g_key_descriptor_pool; diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index fa7e8667e27..ce84834e808 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -2233,7 +2233,7 @@ private: void LQHKEY_abort(Signal* signal, int errortype); void LQHKEY_error(Signal* signal, int errortype); void nextRecordCopy(Signal* signal); - void calculateHash(Signal* signal); + Uint32 calculateHash(Uint32 tableId, const Uint32* src); void continueAfterCheckLcpStopBlocked(Signal* signal); void checkLcpStopBlockedLab(Signal* signal); void sendCommittedTc(Signal* signal, BlockReference atcBlockref); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 5a35b5eefc0..71b5aaf4163 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -55,6 +55,7 @@ #include #include +#include // Use DEBUG to print messages that should be // seen only when we debug the product @@ -9013,44 +9014,17 @@ void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted) /* FRAGMENT TO A NEW REPLICA OF THE FRAGMENT. IT DOES ALSO SHUT DOWN ALL */ /* CONNECTIONS TO THE FAILED NODE. */ /*---------------------------------------------------------------------------*/ -void Dblqh::calculateHash(Signal* signal) +Uint32 +Dblqh::calculateHash(Uint32 tableId, const Uint32* src) { - DatabufPtr locDatabufptr; - UintR Ti; - UintR Tdata0; - UintR Tdata1; - UintR Tdata2; - UintR Tdata3; - UintR* Tdata32; - Uint64 Tdata[512]; - - Tdata32 = (UintR*)&Tdata[0]; - - Tdata0 = tcConnectptr.p->tupkeyData[0]; - Tdata1 = tcConnectptr.p->tupkeyData[1]; - Tdata2 = tcConnectptr.p->tupkeyData[2]; - Tdata3 = tcConnectptr.p->tupkeyData[3]; - Tdata32[0] = Tdata0; - Tdata32[1] = Tdata1; - Tdata32[2] = Tdata2; - Tdata32[3] = Tdata3; - locDatabufptr.i = tcConnectptr.p->firstTupkeybuf; - Ti = 4; - while (locDatabufptr.i != RNIL) { - ptrCheckGuard(locDatabufptr, cdatabufFileSize, databuf); - Tdata0 = locDatabufptr.p->data[0]; - Tdata1 = locDatabufptr.p->data[1]; - Tdata2 = locDatabufptr.p->data[2]; - Tdata3 = locDatabufptr.p->data[3]; - Tdata32[Ti ] = Tdata0; - Tdata32[Ti + 1] = Tdata1; - Tdata32[Ti + 2] = Tdata2; - Tdata32[Ti + 3] = Tdata3; - locDatabufptr.i = locDatabufptr.p->nextDatabuf; - Ti += 4; - }//while - tcConnectptr.p->hashValue = - md5_hash((Uint64*)&Tdata32[0], (UintR)tcConnectptr.p->primKeyLen); + jam(); + Uint64 Tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1]; + Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]; + Uint32 keyLen = xfrm_key(tableId, src, (Uint32*)Tmp, sizeof(Tmp) >> 2, + keyPartLen); + ndbrequire(keyLen); + + return md5_hash(Tmp, keyLen); }//Dblqh::calculateHash() /* *************************************** */ @@ -9384,7 +9358,7 @@ void Dblqh::copyTupkeyConfLab(Signal* signal) const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr(); UintR readLength = tupKeyConf->readLength; - + Uint32 tableId = tcConnectptr.p->tableref; scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); ScanRecord* scanP = scanptr.p; @@ -9411,7 +9385,14 @@ void Dblqh::copyTupkeyConfLab(Signal* signal) Uint32 len= tcConnectptr.p->primKeyLen = readPrimaryKeys(scanP, tcConP, tmp); // Calculate hash (no need to linearies key) - tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len); + if (g_key_descriptor_pool.getPtr(tableId)->hasCharAttr) + { + tcConnectptr.p->hashValue = calculateHash(tableId, tmp); + } + else + { + tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len); + } // Move into databuffer to make packLqhkeyreqLab happy memcpy(tcConP->tupkeyData, tmp, 4*4); diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index cd5eedd89ad..bf9f421a0e3 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -962,11 +962,6 @@ public: Uint8 hasCharAttr; Uint8 noOfDistrKeys; - struct KeyAttr { - Uint32 attributeDescriptor; - CHARSET_INFO* charsetInfo; - } keyAttr[MAX_ATTRIBUTES_IN_INDEX]; - bool checkTable(Uint32 schemaVersion) const { return enabled && !dropping && (table_version_major(schemaVersion) == table_version_major(currentSchemaVersion)); diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 12f3a278f0e..0ff6d8477b9 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -329,42 +330,16 @@ void Dbtc::execTC_SCHVERREQ(Signal* signal) BlockReference retPtr = signal->theData[5]; Uint32 noOfKeyAttr = signal->theData[6]; ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX); - Uint32 hasCharAttr = 0; - Uint32 noOfDistrKeys = 0; - SegmentedSectionPtr s0Ptr; - signal->getSection(s0Ptr, 0); - SectionReader r0(s0Ptr, getSectionSegmentPool()); - Uint32 i = 0; - while (i < noOfKeyAttr) { - jam(); - Uint32 attributeDescriptor = ~0; - Uint32 csNumber = ~0; - if (! r0.getWord(&attributeDescriptor) || - ! r0.getWord(&csNumber)) { - jam(); - break; - } - CHARSET_INFO* cs = 0; - if (csNumber != 0) { - cs = all_charsets[csNumber]; - ndbrequire(cs != 0); - hasCharAttr = 1; - } - - noOfDistrKeys += AttributeDescriptor::getDKey(attributeDescriptor); - tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor; - tabptr.p->keyAttr[i].charsetInfo = cs; - i++; - } - ndbrequire(i == noOfKeyAttr); - releaseSections(signal); + + const KeyDescriptor* desc = g_key_descriptor_pool.getPtr(tabptr.i); + ndbrequire(noOfKeyAttr == desc->noOfKeyAttr); ndbrequire(tabptr.p->enabled == false); tabptr.p->enabled = true; tabptr.p->dropping = false; - tabptr.p->noOfKeyAttr = noOfKeyAttr; - tabptr.p->hasCharAttr = hasCharAttr; - tabptr.p->noOfDistrKeys = noOfDistrKeys; + tabptr.p->noOfKeyAttr = desc->noOfKeyAttr; + tabptr.p->hasCharAttr = desc->hasCharAttr; + tabptr.p->noOfDistrKeys = desc->noOfDistrKeys; signal->theData[0] = tabptr.i; signal->theData[1] = retPtr; @@ -2323,113 +2298,37 @@ Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen, Uint32 tabPtrI, bool distr) { - Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS * 4 * MAX_XFRM_MULTIPLY]; - const Uint32 dstSize = sizeof(Tmp) / 4; + Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY]; const TableRecord* tabPtrP = &tableRecord[tabPtrI]; - const Uint32 noOfKeyAttr = tabPtrP->noOfKeyAttr; - Uint32 noOfDistrKeys = tabPtrP->noOfDistrKeys; const bool hasCharAttr = tabPtrP->hasCharAttr; + const bool hasDistKeys = tabPtrP->noOfDistrKeys > 0; Uint32 *dst = (Uint32*)Tmp; Uint32 dstPos = 0; - Uint32 srcPos = 0; Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]; - if(hasCharAttr){ - Uint32 i = 0; - while (i < noOfKeyAttr) { - const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i]; - - Uint32 srcBytes = - AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor); - Uint32 srcWords = (srcBytes + 3) / 4; - Uint32 dstWords = ~0; - uchar* dstPtr = (uchar*)&dst[dstPos]; - const uchar* srcPtr = (const uchar*)&src[srcPos]; - CHARSET_INFO* cs = keyAttr.charsetInfo; - - if (cs == NULL) { - jam(); - memcpy(dstPtr, srcPtr, srcWords << 2); - dstWords = srcWords; - } else { - jam(); - Uint32 typeId = - AttributeDescriptor::getType(keyAttr.attributeDescriptor); - Uint32 lb, len; - bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); - ndbrequire(ok); - Uint32 xmul = cs->strxfrm_multiply; - if (xmul == 0) - xmul = 1; - /* - * Varchar is really Char. End spaces do not matter. To get - * same hash we blank-pad to maximum length via strnxfrm. - * TODO use MySQL charset-aware hash function instead - */ - Uint32 dstLen = xmul * (srcBytes - lb); - ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); - int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); - ndbrequire(n != -1); - while ((n & 3) != 0) { - dstPtr[n++] = 0; - } - dstWords = (n >> 2); - } - dstPos += dstWords; - srcPos += srcWords; - keyPartLen[i++] = dstWords; - } + Uint32 * keyPartLenPtr; + if(hasCharAttr) + { + keyPartLenPtr = keyPartLen; + dstPos = xfrm_key(tabPtrI, src, dst, sizeof(Tmp) >> 2, keyPartLenPtr); + ndbrequire(dstPos); } else { dst = src; dstPos = srcLen; + keyPartLenPtr = 0; } md5_hash(dstHash, (Uint64*)dst, dstPos); - if(distr && noOfDistrKeys) + if(distr && hasDistKeys) { jam(); - src = dst; - dstPos = 0; - Uint32 i = 0; - if(hasCharAttr) - { - while (i < noOfKeyAttr && noOfDistrKeys) - { - const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i]; - Uint32 len = keyPartLen[i]; - if(AttributeDescriptor::getDKey(keyAttr.attributeDescriptor)) - { - noOfDistrKeys--; - memmove(dst+dstPos, src, len << 2); - dstPos += len; - } - src += len; - i++; - } - } - else - { - while (i < noOfKeyAttr && noOfDistrKeys) - { - const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i]; - Uint32 len = - AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor); - len = (len + 3) / 4; - if(AttributeDescriptor::getDKey(keyAttr.attributeDescriptor)) - { - noOfDistrKeys--; - memmove(dst+dstPos, src, len << 2); - dstPos += len; - } - src += len; - i++; - } - } + Uint32 tmp[4]; - md5_hash(tmp, (Uint64*)dst, dstPos); + Uint32 len = create_distr_key(tabPtrI, dst, keyPartLenPtr); + md5_hash(tmp, (Uint64*)dst, len); dstHash[1] = tmp[1]; } return true; // success @@ -10204,10 +10103,6 @@ void Dbtc::initTable(Signal* signal) tabptr.p->noOfKeyAttr = 0; tabptr.p->hasCharAttr = 0; tabptr.p->noOfDistrKeys = 0; - for (unsigned k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) { - tabptr.p->keyAttr[k].attributeDescriptor = 0; - tabptr.p->keyAttr[k].charsetInfo = 0; - } }//for }//Dbtc::initTable() diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp index 35c0781a24d..ef9f2c3c716 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.cpp +++ b/ndb/src/kernel/vm/SimulatedBlock.cpp @@ -1802,3 +1802,118 @@ SimulatedBlock::init_globals_list(void ** tmp, size_t cnt){ } #endif + +#include "KeyDescriptor.hpp" + +Uint32 +SimulatedBlock::xfrm_key(Uint32 tab, const Uint32* src, + Uint32 *dst, Uint32 dstSize, + Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const +{ + const KeyDescriptor * desc = g_key_descriptor_pool.getPtr(tab); + const Uint32 noOfKeyAttr = desc->noOfKeyAttr; + + Uint32 i = 0; + Uint32 srcPos = 0; + Uint32 dstPos = 0; + while (i < noOfKeyAttr) + { + const KeyDescriptor::KeyAttr& keyAttr = desc->keyAttr[i]; + + Uint32 srcBytes = + AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor); + Uint32 srcWords = (srcBytes + 3) / 4; + Uint32 dstWords = ~0; + uchar* dstPtr = (uchar*)&dst[dstPos]; + const uchar* srcPtr = (const uchar*)&src[srcPos]; + CHARSET_INFO* cs = keyAttr.charsetInfo; + + if (cs == NULL) + { + jam(); + memcpy(dstPtr, srcPtr, srcWords << 2); + dstWords = srcWords; + } + else + { + jam(); + Uint32 typeId = + AttributeDescriptor::getType(keyAttr.attributeDescriptor); + Uint32 lb, len; + bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); + ndbrequire(ok); + Uint32 xmul = cs->strxfrm_multiply; + if (xmul == 0) + xmul = 1; + /* + * Varchar is really Char. End spaces do not matter. To get + * same hash we blank-pad to maximum length via strnxfrm. + * TODO use MySQL charset-aware hash function instead + */ + Uint32 dstLen = xmul * (srcBytes - lb); + ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); + int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); + ndbrequire(n != -1); + while ((n & 3) != 0) + { + dstPtr[n++] = 0; + } + dstWords = (n >> 2); + } + dstPos += dstWords; + srcPos += srcWords; + keyPartLen[i++] = dstWords; + } + + return dstPos; +} + +Uint32 +SimulatedBlock::create_distr_key(Uint32 tableId, + Uint32 *data, + const Uint32 + keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const +{ + const KeyDescriptor* desc = g_key_descriptor_pool.getPtr(tableId); + const Uint32 noOfKeyAttr = desc->noOfKeyAttr; + Uint32 noOfDistrKeys = desc->noOfDistrKeys; + + Uint32 *src = data; + Uint32 *dst = data; + Uint32 i = 0; + Uint32 dstPos = 0; + + if(keyPartLen) + { + while (i < noOfKeyAttr && noOfDistrKeys) + { + Uint32 attr = desc->keyAttr[i].attributeDescriptor; + Uint32 len = keyPartLen[i]; + if(AttributeDescriptor::getDKey(attr)) + { + noOfDistrKeys--; + memmove(dst+dstPos, src, len << 2); + dstPos += len; + } + src += len; + i++; + } + } + else + { + while (i < noOfKeyAttr && noOfDistrKeys) + { + Uint32 attr = desc->keyAttr[i].attributeDescriptor; + Uint32 len = AttributeDescriptor::getSizeInWords(attr); + if(AttributeDescriptor::getDKey(attr)) + { + noOfDistrKeys--; + memmove(dst+dstPos, src, len << 2); + dstPos += len; + } + src += len; + i++; + } + } + return dstPos; +} diff --git a/ndb/src/kernel/vm/SimulatedBlock.hpp b/ndb/src/kernel/vm/SimulatedBlock.hpp index 787d14ca5cb..50c85a0b274 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -20,11 +20,13 @@ #include #include #include +#include #include "VMSignal.hpp" #include #include #include + #include "pc.hpp" #include #include @@ -385,6 +387,24 @@ protected: */ const NodeInfo & getNodeInfo(NodeId nodeId) const; NodeInfo & setNodeInfo(NodeId); + + /********************** + * Xfrm stuff + */ + + /** + * @return length + */ + Uint32 xfrm_key(Uint32 tab, const Uint32* src, + Uint32 *dst, Uint32 dstLen, + Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const; + + /** + * + */ + Uint32 create_distr_key(Uint32 tableId, + Uint32 *data, + const Uint32 keyPaLen[MAX_ATTRIBUTES_IN_INDEX])const; private: NewVARIABLE* NewVarRef; /* New Base Address Table for block */ From d7349750e51f69b320d79a5767f2e89c45fb6564 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Mon, 22 Aug 2005 11:25:03 +0200 Subject: [PATCH 192/230] ndb - bug#12220 forgott to add KeyDescriptor.hpp --- ndb/src/kernel/vm/KeyDescriptor.hpp | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ndb/src/kernel/vm/KeyDescriptor.hpp diff --git a/ndb/src/kernel/vm/KeyDescriptor.hpp b/ndb/src/kernel/vm/KeyDescriptor.hpp new file mode 100644 index 00000000000..456d64ce1d8 --- /dev/null +++ b/ndb/src/kernel/vm/KeyDescriptor.hpp @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef KEY_DESCRIPTOR_HPP +#define KEY_DESCRIPTOR_HPP + +#include +#include +#include "CArray.hpp" + +struct KeyDescriptor +{ + KeyDescriptor () { noOfKeyAttr = hasCharAttr = noOfDistrKeys = 0; } + + Uint8 noOfKeyAttr; + Uint8 hasCharAttr; + Uint8 noOfDistrKeys; + Uint8 unused; + struct KeyAttr + { + Uint32 attributeDescriptor; + CHARSET_INFO* charsetInfo; + } keyAttr[MAX_ATTRIBUTES_IN_INDEX]; +}; + +extern CArray g_key_descriptor_pool; + +#endif From f4f63f0351ef3bed150293e112974fb80d1122c4 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Mon, 22 Aug 2005 11:34:33 +0200 Subject: [PATCH 193/230] ndb - Fix merge error --- mysql-test/t/ndb_config.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/ndb_config.test b/mysql-test/t/ndb_config.test index 66287bf6d29..ab3063af672 100644 --- a/mysql-test/t/ndb_config.test +++ b/mysql-test/t/ndb_config.test @@ -1,4 +1,5 @@ -- source include/have_ndb.inc +-- source include/ndb_default_cluster.inc -- source include/not_embedded.inc --exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=type,nodeid,host 2> /dev/null From ddcbf609c48ce867cc15d772a8d9d88c509a9643 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Mon, 22 Aug 2005 12:48:01 +0200 Subject: [PATCH 194/230] Ensure that a failing test does not stop testing or the whole RPM build process. --- support-files/mysql.spec.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index b563972e08a..af9abd2fce1 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -308,7 +308,7 @@ BuildMySQL "--enable-shared \ --with-comment=\"MySQL Community Edition - Max (GPL)\" \ --with-server-suffix='-Max'" -make test +make test-force || true # Save mysqld-max mv sql/mysqld sql/mysqld-max @@ -359,7 +359,7 @@ BuildMySQL "--disable-shared \ --without-openssl" nm --numeric-sort sql/mysqld > sql/mysqld.sym -make test +make test-force || true %install RBR=$RPM_BUILD_ROOT From c04138ec945bdc9ba55db934c05f53c94244f38c Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Mon, 22 Aug 2005 17:04:55 +0300 Subject: [PATCH 195/230] Test case for BUG#6558 - Views: create fails with JOIN ... USING The bug is non-view specific, and it resulted from incorrect name resolution of natural join result columns. The bug is fixed by WL#2486. --- mysql-test/r/select.result | 10 ++++++++++ mysql-test/t/select.test | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index ed075c8a6ad..63ed0d187f0 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2765,3 +2765,13 @@ f1 f2 f3 f4 2 2 2 one 2 2 2 two drop table t1,t2; +create table t1 (empnum smallint, grp int); +create table t2 (empnum int, name char(5)); +insert into t1 values(1,1); +insert into t2 values(1,'bob'); +create view v1 as select * from t2 inner join t1 using (empnum); +select * from v1; +empnum name grp +1 bob 1 +drop table t1,t2; +drop view v1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index b8975749fd6..fc0df8fb8b5 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2358,3 +2358,16 @@ insert into t1 values (" 2", 2); insert into t2 values (" 2", " one "),(" 2", " two "); select * from t1 left join t2 on f1 = f3; drop table t1,t2; + +# +# Bug #6558 Views: CREATE VIEW fails with JOIN ... USING +# + +create table t1 (empnum smallint, grp int); +create table t2 (empnum int, name char(5)); +insert into t1 values(1,1); +insert into t2 values(1,'bob'); +create view v1 as select * from t2 inner join t1 using (empnum); +select * from v1; +drop table t1,t2; +drop view v1; From 310afc80dd7b59e3990a2eb7416ded47aacd7264 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Mon, 22 Aug 2005 17:34:08 +0300 Subject: [PATCH 196/230] Test case for BUG#10646 The bug itself is fixed by WL #2486. --- mysql-test/r/select.result | 5 +++++ mysql-test/t/select.test | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 63ed0d187f0..64946b88a41 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2775,3 +2775,8 @@ empnum name grp 1 bob 1 drop table t1,t2; drop view v1; +create table t1 (pk int primary key, b int); +create table t2 (pk int primary key, c int); +select pk from t1 inner join t2 using (pk); +pk +drop table t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index fc0df8fb8b5..373aa73eec0 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2371,3 +2371,13 @@ create view v1 as select * from t2 inner join t1 using (empnum); select * from v1; drop table t1,t2; drop view v1; + +# +# Bug #10646 Columns included in the join between two tables are ambigious +# in the select +# + +create table t1 (pk int primary key, b int); +create table t2 (pk int primary key, c int); +select pk from t1 inner join t2 using (pk); +drop table t1,t2; From c75cfc358e9d43d8d52c144eebdb1322f2253b84 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Mon, 22 Aug 2005 18:59:47 +0400 Subject: [PATCH 197/230] Fix a -ansi -pedantic compile failure. --- server-tools/instance-manager/instance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h index ee37690d40a..cbcfee0c7ef 100644 --- a/server-tools/instance-manager/instance.h +++ b/server-tools/instance-manager/instance.h @@ -42,7 +42,7 @@ public: void kill_instance(int signo); int is_crashed(); void set_crash_flag_n_wake_all(); - Instance_map *Instance::get_map(); + Instance_map *get_map(); public: enum { DEFAULT_SHUTDOWN_DELAY= 35 }; From fb7be5270f78bf48cea488fb8ac80ba079651b3a Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Mon, 22 Aug 2005 19:23:01 +0400 Subject: [PATCH 198/230] Add a comment about I_List<> copy constructor. --- sql/sql_list.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sql/sql_list.h b/sql/sql_list.h index 09c01931c38..e4a34cc0aa1 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -426,9 +426,14 @@ struct ilink template class I_List_iterator; +/* + WARNING: copy constructor of this class does not create a usable + copy, as its members may point at each other. +*/ + class base_ilist { - public: +public: struct ilink *first,last; inline void empty() { first= &last; last.prev= &first; } base_ilist() { empty(); } From 7767828b81457efe9645d4172e9a4e0a204705c8 Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Mon, 22 Aug 2005 19:56:36 +0300 Subject: [PATCH 199/230] Don't write first even that contains server version --- mysql-test/r/ctype_cp932.result | 3 +-- mysql-test/t/ctype_cp932.test | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result index f677af7db76..08206a91b7b 100755 --- a/mysql-test/r/ctype_cp932.result +++ b/mysql-test/r/ctype_cp932.result @@ -11320,9 +11320,8 @@ CREATE TABLE t1(f1 blob); PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; SET @var1= x'8300'; EXECUTE stmt1 USING @var1; -SHOW BINLOG EVENTS; +SHOW BINLOG EVENTS FROM 98; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 98 Server ver: 5.0.12-beta-debug-log, Binlog ver: 4 master-bin.000001 98 Query 1 185 use `test`; CREATE TABLE t1(f1 blob) master-bin.000001 185 User var 1 224 @`var1`=_binary 0x8300 COLLATE binary master-bin.000001 224 Query 1 317 use `test`; INSERT INTO t1 VALUES(@'var1') diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index c41ee489a37..3d630311b3a 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -415,7 +415,7 @@ SET @var1= x'8300'; # code (and I have used it to test the fix) until there is some way to # exercise this code from mysql-test-run. EXECUTE stmt1 USING @var1; -SHOW BINLOG EVENTS; +SHOW BINLOG EVENTS FROM 98; SELECT HEX(f1) FROM t1; DROP table t1; # end test for bug#11338 From 8859ab64d18fb542d74efad09926091e05397bcd Mon Sep 17 00:00:00 2001 From: "hartmut@mysql.com" <> Date: Mon, 22 Aug 2005 22:13:56 +0200 Subject: [PATCH 200/230] added file missing from release to EXTRA_DIST list (bug# 12733) --- BUILD/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am index 27a42cdca16..45c1aaa1a76 100644 --- a/BUILD/Makefile.am +++ b/BUILD/Makefile.am @@ -19,6 +19,7 @@ EXTRA_DIST = FINISH.sh \ SETUP.sh \ + autorun.sh \ check-cpu \ compile-alpha \ compile-alpha-ccc \ From f70beef6c7cb0f57211776854fba8d030f8389c8 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Mon, 22 Aug 2005 15:48:50 -0700 Subject: [PATCH 201/230] Use the hostname with which the user authenticated when determining which user to update with 'SET PASSWORD = ...'. (Bug #12302) --- mysql-test/r/grant2.result | 26 ++++++++++++++++++++++++++ mysql-test/t/grant2.test | 38 ++++++++++++++++++++++++++++++++++++++ sql/set_var.cc | 13 ++++++++++++- sql/sql_acl.cc | 19 +++++++++++-------- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index ada205f6f23..8bd39b0225e 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -94,5 +94,31 @@ i 2 3 REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0'; +delete from mysql.user where user like 'mysqltest\_1'; +flush privileges; drop table mysqltest_1.t1; +grant all on mysqltest_1.* to mysqltest_1@'127.0.0.1'; +select current_user(); +current_user() +mysqltest_1@127.0.0.1 +set password = password('changed'); +select host, length(password) from mysql.user where user like 'mysqltest\_1'; +host length(password) +127.0.0.1 41 +revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.1'; +delete from mysql.user where user like 'mysqltest\_1'; +flush privileges; +grant all on mysqltest_1.* to mysqltest_1@'127.0.0.0/255.0.0.0'; +select current_user(); +current_user() +mysqltest_1@127.0.0.0/255.0.0.0 +set password = password('changed'); +select host, length(password) from mysql.user where user like 'mysqltest\_1'; +host length(password) +127.0.0.0/255.0.0.0 41 +revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.0/255.0.0.0'; +delete from mysql.user where user like 'mysqltest\_1'; +flush privileges; drop database mysqltest_1; +set password = password("changed"); +ERROR 42000: Access denied for user ''@'localhost' to database 'mysql' diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index f347869d9ec..e3e733a50c3 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -122,7 +122,45 @@ select * from t1; disconnect n1; connection default; REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0'; +delete from mysql.user where user like 'mysqltest\_1'; +flush privileges; drop table mysqltest_1.t1; + +# +# Bug #12302: 'SET PASSWORD = ...' didn't work if connecting hostname != +# hostname the current user is authenticated as. Note that a test for this +# was also added to the test above. +# +grant all on mysqltest_1.* to mysqltest_1@'127.0.0.1'; +connect (b12302,127.0.0.1,mysqltest_1,,mysqltest_1,$MASTER_MYPORT,); +connection b12302; +select current_user(); +set password = password('changed'); +disconnect b12302; +connection default; +select host, length(password) from mysql.user where user like 'mysqltest\_1'; +revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.1'; +delete from mysql.user where user like 'mysqltest\_1'; +flush privileges; +grant all on mysqltest_1.* to mysqltest_1@'127.0.0.0/255.0.0.0'; +connect (b12302_2,127.0.0.1,mysqltest_1,,mysqltest_1,$MASTER_MYPORT,); +connection b12302_2; +select current_user(); +set password = password('changed'); +disconnect b12302_2; +connection default; +select host, length(password) from mysql.user where user like 'mysqltest\_1'; +revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.0/255.0.0.0'; +delete from mysql.user where user like 'mysqltest\_1'; +flush privileges; drop database mysqltest_1; +# But anonymous users can't change their password +connect (n5,localhost,test,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connection n5; +--error 1044 +set password = password("changed"); +disconnect n5; +connection default; + # End of 4.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index f7700d18607..1b66b68b349 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2944,7 +2944,18 @@ int set_var_password::check(THD *thd) { #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!user->host.str) - user->host.str= (char*) thd->host_or_ip; + { + if (thd->priv_host != 0) + { + user->host.str= (char *) thd->priv_host; + user->host.length= strlen(thd->priv_host); + } + else + { + user->host.str= (char *)"%"; + user->host.length= 1; + } + } /* Returns 1 as the function sends error to client */ return check_change_password(thd, user->host.str, user->user.str, password, strlen(password)) ? 1 : 0; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d191da32189..813754ad937 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -67,7 +67,8 @@ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); -static ACL_USER *find_acl_user(const char *host, const char *user); +static ACL_USER *find_acl_user(const char *host, const char *user, + my_bool exact); static bool update_user_table(THD *thd, const char *host, const char *user, const char *new_password, uint new_password_len); static void update_hostname(acl_host_and_ip *host, const char *hostname); @@ -1188,7 +1189,7 @@ bool check_change_password(THD *thd, const char *host, const char *user, } if (!thd->slave_thread && (strcmp(thd->user,user) || - my_strcasecmp(&my_charset_latin1, host, thd->host_or_ip))) + my_strcasecmp(&my_charset_latin1, host, thd->priv_host))) { if (check_access(thd, UPDATE_ACL, "mysql",0,1,0)) return(1); @@ -1240,7 +1241,7 @@ bool change_password(THD *thd, const char *host, const char *user, VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; - if (!(acl_user= find_acl_user(host, user))) + if (!(acl_user= find_acl_user(host, user, TRUE))) { VOID(pthread_mutex_unlock(&acl_cache->lock)); send_error(thd, ER_PASSWORD_NO_MATCH); @@ -1282,7 +1283,7 @@ bool change_password(THD *thd, const char *host, const char *user, */ static ACL_USER * -find_acl_user(const char *host, const char *user) +find_acl_user(const char *host, const char *user, my_bool exact) { DBUG_ENTER("find_acl_user"); DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user)); @@ -1298,7 +1299,9 @@ find_acl_user(const char *host, const char *user) if (!acl_user->user && !user[0] || acl_user->user && !strcmp(user,acl_user->user)) { - if (compare_hostname(&acl_user->host,host,host)) + if (exact ? !my_strcasecmp(&my_charset_latin1, host, + acl_user->host.hostname) : + compare_hostname(&acl_user->host,host,host)) { DBUG_RETURN(acl_user); } @@ -1689,7 +1692,7 @@ static int replace_db_table(TABLE *table, const char *db, } /* Check if there is such a user in user table in memory? */ - if (!find_acl_user(combo.host.str,combo.user.str)) + if (!find_acl_user(combo.host.str,combo.user.str, FALSE)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); DBUG_RETURN(-1); @@ -2151,7 +2154,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, The following should always succeed as new users are created before this function is called! */ - if (!find_acl_user(combo.host.str,combo.user.str)) + if (!find_acl_user(combo.host.str,combo.user.str, FALSE)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */ DBUG_RETURN(-1); /* purecov: deadcode */ @@ -3448,7 +3451,7 @@ void get_privilege_desc(char *to, uint max_length, ulong access) void get_mqh(const char *user, const char *host, USER_CONN *uc) { ACL_USER *acl_user; - if (initialized && (acl_user= find_acl_user(host,user))) + if (initialized && (acl_user= find_acl_user(host,user, FALSE))) uc->user_resources= acl_user->user_resource; else bzero((char*) &uc->user_resources, sizeof(uc->user_resources)); From 94166de5f3d88bd491d96e5773d4b3080f126c89 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 22 Aug 2005 17:32:02 -0700 Subject: [PATCH 202/230] sql_show.cc: Database name was set incorrectly for any show command that used sunqueries in its where condition. information_schema.test, information_schema.result: Added a test case for bug #12636. --- mysql-test/r/information_schema.result | 8 ++++++++ mysql-test/t/information_schema.test | 15 +++++++++++++++ sql/sql_show.cc | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 3f1e94c9e5f..b1c5f8de7dc 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -967,3 +967,11 @@ a NULL b NULL use test; drop table t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +SHOW TABLE STATUS FROM test +WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 03810447299..5410885a404 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -650,3 +650,18 @@ select column_name, column_default from columns where table_schema='test' and table_name='t1'; use test; drop table t1; + +# +# Bug #12636: SHOW TABLE STATUS with where condition containing a subquery +# over information schema +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); + +--replace_column 8 # 12 # 13 # +SHOW TABLE STATUS FROM test + WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); + +DROP TABLE t1,t2 diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 958971d65f1..f140e20ca83 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1705,7 +1705,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values) case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TRIGGERS: - index_field_values->db_value= lex->current_select->db; + index_field_values->db_value= lex->select_lex.db; index_field_values->table_value= wild; break; default: From 28e3fe8759fe36c5db7eeb0765ea921eb252dfce Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Tue, 23 Aug 2005 11:50:24 +0200 Subject: [PATCH 203/230] enabled make of ndb_redo_log_reader --- ndb/src/kernel/blocks/dblqh/Makefile.am | 8 ++++++-- .../blocks/dblqh/redoLogReader/redoLogFileReader.cpp | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/Makefile.am b/ndb/src/kernel/blocks/dblqh/Makefile.am index 854860b269c..bb8efe8c5b8 100644 --- a/ndb/src/kernel/blocks/dblqh/Makefile.am +++ b/ndb/src/kernel/blocks/dblqh/Makefile.am @@ -1,12 +1,16 @@ -#SUBDIRS = redoLogReader - noinst_LIBRARIES = libdblqh.a +EXTRA_PROGRAMS = ndbd_redo_log_reader libdblqh_a_SOURCES = DblqhInit.cpp DblqhMain.cpp +ndbd_redo_log_reader_SOURCES = redoLogReader/records.cpp redoLogReader/redoLogFileReader.cpp include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_kernel.mk.am +LDADD += \ + $(top_builddir)/ndb/src/common/util/libgeneral.la \ + $(top_builddir)/ndb/src/common/portlib/libportlib.la + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp index 540df7b507e..67e59c48ea6 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp @@ -40,7 +40,7 @@ Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords); void readArguments(int argc, const char** argv); void doExit(); -FILE * f; +FILE * f= 0; char fileName[256]; bool thePrintFlag = true; bool theCheckFlag = true; @@ -458,7 +458,7 @@ void readArguments(int argc, const char** argv) void doExit() { ndbout << "Error in redoLogReader(). Exiting!" << endl; - fclose(f); + if (f) fclose(f); delete [] redoLogPage; exit(RETURN_ERROR); } From 653e99dea2099a1d47c82ad8142c0ac3cf4c74cd Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Tue, 23 Aug 2005 12:16:16 +0200 Subject: [PATCH 204/230] removed ndb grep from configure .in --- configure.in | 1 - .../blocks/dblqh/redoLogReader/Makefile | 9 - ndb/src/kernel/blocks/grep/Grep.cpp | 2010 ----------------- ndb/src/kernel/blocks/grep/Grep.hpp | 535 ----- ndb/src/kernel/blocks/grep/GrepInit.cpp | 164 -- ndb/src/kernel/blocks/grep/Makefile.am | 23 - .../kernel/blocks/grep/systab_test/Makefile | 12 - .../grep/systab_test/grep_systab_test.cpp | 138 -- ndb/test/ndbapi/testGrep.cpp | 540 ----- 9 files changed, 3432 deletions(-) delete mode 100644 ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile delete mode 100644 ndb/src/kernel/blocks/grep/Grep.cpp delete mode 100644 ndb/src/kernel/blocks/grep/Grep.hpp delete mode 100644 ndb/src/kernel/blocks/grep/GrepInit.cpp delete mode 100644 ndb/src/kernel/blocks/grep/Makefile.am delete mode 100644 ndb/src/kernel/blocks/grep/systab_test/Makefile delete mode 100644 ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp delete mode 100644 ndb/test/ndbapi/testGrep.cpp diff --git a/configure.in b/configure.in index 9e370dfa680..b9ad38fb59d 100644 --- a/configure.in +++ b/configure.in @@ -3281,7 +3281,6 @@ AC_CONFIG_FILES(ndb/Makefile ndb/include/Makefile dnl ndb/src/kernel/blocks/backup/Makefile dnl ndb/src/kernel/blocks/dbutil/Makefile dnl ndb/src/kernel/blocks/suma/Makefile dnl - ndb/src/kernel/blocks/grep/Makefile dnl ndb/src/kernel/blocks/dbtux/Makefile dnl ndb/src/kernel/vm/Makefile dnl ndb/src/mgmapi/Makefile dnl diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile b/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile deleted file mode 100644 index a89b648de77..00000000000 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include .defs.mk - -BIN_TARGET := redoLogFileReader - -SOURCES := records.cpp redoLogFileReader.cpp - -TYPE := util - -include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/kernel/blocks/grep/Grep.cpp b/ndb/src/kernel/blocks/grep/Grep.cpp deleted file mode 100644 index e89361dab06..00000000000 --- a/ndb/src/kernel/blocks/grep/Grep.cpp +++ /dev/null @@ -1,2010 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "Grep.hpp" -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CONTINUEB_DELAY 500 -#define SSREPBLOCKNO 2 -#define PSREPBLOCKNO 2 - -//#define DEBUG_GREP -//#define DEBUG_GREP_SUBSCRIPTION -//#define DEBUG_GREP_TRANSFER -//#define DEBUG_GREP_APPLY -//#define DEBUG_GREP_DELETE - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: STARTUP of GREP Block, etc - * ------------------------------------------------------------------------ - **************************************************************************/ -static Uint32 g_TypeOfStart = NodeState::ST_ILLEGAL_TYPE; -void -Grep::getNodeGroupMembers(Signal* signal) { - jam(); - /** - * Ask DIH for nodeGroupMembers - */ - CheckNodeGroups * sd = (CheckNodeGroups*)signal->getDataPtrSend(); - sd->blockRef = reference(); - sd->requestType = - CheckNodeGroups::Direct | - CheckNodeGroups::GetNodeGroupMembers; - sd->nodeId = getOwnNodeId(); - EXECUTE_DIRECT(DBDIH, GSN_CHECKNODEGROUPSREQ, signal, - CheckNodeGroups::SignalLength); - jamEntry(); - - c_nodeGroup = sd->output; - c_noNodesInGroup = 0; - for (int i = 0; i < MAX_NDB_NODES; i++) { - if (sd->mask.get(i)) { - if (i == getOwnNodeId()) c_idInNodeGroup = c_noNodesInGroup; - c_nodesInGroup[c_noNodesInGroup] = i; - c_noNodesInGroup++; - } - } - ndbrequire(c_noNodesInGroup > 0); // at least 1 node in the nodegroup - -#ifdef NODEFAIL_DEBUG - for (Uint32 i = 0; i < c_noNodesInGroup; i++) { - ndbout_c ("Grep: NodeGroup %u, me %u, me in group %u, member[%u] %u", - c_nodeGroup, getOwnNodeId(), c_idInNodeGroup, - i, c_nodesInGroup[i]); - } -#endif -} - - -void -Grep::execSTTOR(Signal* signal) -{ - jamEntry(); - const Uint32 startphase = signal->theData[1]; - const Uint32 typeOfStart = signal->theData[7]; - if (startphase == 3) - { - jam(); - signal->theData[0] = reference(); - g_TypeOfStart = typeOfStart; - sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB); - return; - } - if(startphase == 5) { - jam(); - /** - * we don't want any log/meta records comming to use - * until we are done with the recovery. - */ - if (g_TypeOfStart == NodeState::ST_NODE_RESTART) { - jam(); - pspart.m_recoveryMode = true; - getNodeGroupMembers(signal); - for (Uint32 i = 0; i < c_noNodesInGroup; i++) { - Uint32 ref =numberToRef(GREP, c_nodesInGroup[i]); - if (ref != reference()) - sendSignal(ref, GSN_GREP_START_ME, signal, - 1 /*SumaStartMe::SignalLength*/, JBB); - } - } else pspart.m_recoveryMode = false; - - } - - if(startphase == 7) { - jam(); - if (g_TypeOfStart == NodeState::ST_NODE_RESTART) { - pspart.m_recoveryMode = false; - } - } - - sendSTTORRY(signal); -} - - -void -Grep::PSPart::execSTART_ME(Signal* signal) -{ - jamEntry(); - GrepStartMe * me =(GrepStartMe*)signal->getDataPtr(); - BlockReference ref = me->senderRef; - GrepAddSubReq* const addReq = (GrepAddSubReq *)signal->getDataPtr(); - - - SubscriptionPtr subPtr; - c_subscriptions.first(c_subPtr); - for(; !c_subPtr.isNull(); c_subscriptions.next(c_subPtr)) { - jam(); - subPtr.i = c_subPtr.curr.i; - subPtr.p = c_subscriptions.getPtr(subPtr.i); - addReq->subscriptionId = subPtr.p->m_subscriptionId; - addReq->subscriptionKey = subPtr.p->m_subscriptionKey; - addReq->subscriberData = subPtr.p->m_subscriberData; - addReq->subscriptionType = subPtr.p->m_subscriptionType; - addReq->senderRef = subPtr.p->m_coordinatorRef; - addReq->subscriberRef =subPtr.p->m_subscriberRef; - - sendSignal(ref, - GSN_GREP_ADD_SUB_REQ, - signal, - GrepAddSubReq::SignalLength, - JBB); - } - - addReq->subscriptionId = 0; - addReq->subscriptionKey = 0; - addReq->subscriberData = 0; - addReq->subscriptionType = 0; - addReq->senderRef = 0; - addReq->subscriberRef = 0; - - sendSignal(ref, - GSN_GREP_ADD_SUB_REQ, - signal, - GrepAddSubReq::SignalLength, - JBB); -} - -void -Grep::PSPart::execGREP_ADD_SUB_REQ(Signal* signal) -{ - jamEntry(); - GrepAddSubReq * const grepReq = (GrepAddSubReq *)signal->getDataPtr(); - const Uint32 subId = grepReq->subscriptionId; - const Uint32 subKey = grepReq->subscriptionKey; - const Uint32 subData = grepReq->subscriberData; - const Uint32 subType = grepReq->subscriptionType; - const Uint32 coordinatorRef = grepReq->senderRef; - - /** - * this is ref to the REP node for this subscription. - */ - const Uint32 subRef = grepReq->subscriberRef; - - if(subId!=0 && subKey!=0) { - jam(); - SubscriptionPtr subPtr; - ndbrequire( c_subscriptionPool.seize(subPtr)); - subPtr.p->m_coordinatorRef = coordinatorRef; - subPtr.p->m_subscriptionId = subId; - subPtr.p->m_subscriptionKey = subKey; - subPtr.p->m_subscriberRef = subRef; - subPtr.p->m_subscriberData = subData; - subPtr.p->m_subscriptionType = subType; - - c_subscriptions.add(subPtr); - } - else { - jam(); - GrepAddSubConf * conf = (GrepAddSubConf *)grepReq; - conf->noOfSub = - c_subscriptionPool.getSize()-c_subscriptionPool.getNoOfFree(); - sendSignal(signal->getSendersBlockRef(), - GSN_GREP_ADD_SUB_CONF, - signal, - GrepAddSubConf::SignalLength, - JBB); - } -} - -void -Grep::PSPart::execGREP_ADD_SUB_REF(Signal* signal) -{ - /** - * @todo fix error stuff - */ -} - -void -Grep::PSPart::execGREP_ADD_SUB_CONF(Signal* signal) -{ - jamEntry(); - GrepAddSubConf* const conf = (GrepAddSubConf *)signal->getDataPtr(); - Uint32 noOfSubscriptions = conf->noOfSub; - Uint32 noOfRestoredSubscriptions = - c_subscriptionPool.getSize()-c_subscriptionPool.getNoOfFree(); - if(noOfSubscriptions!=noOfRestoredSubscriptions) { - jam(); - /** - *@todo send ref signal - */ - ndbrequire(false); - } -} - -void -Grep::execREAD_NODESCONF(Signal* signal) -{ - jamEntry(); - ReadNodesConf * conf = (ReadNodesConf *)signal->getDataPtr(); - -#if 0 - ndbout_c("Grep: Recd READ_NODESCONF"); -#endif - - /****************************** - * Check which REP nodes exist - ******************************/ - Uint32 i; - for (i = 1; i < MAX_NODES; i++) - { - jam(); -#if 0 - ndbout_c("Grep: Found node %d of type %d", i, getNodeInfo(i).getType()); -#endif - if (getNodeInfo(i).getType() == NodeInfo::REP) - { - jam(); - /** - * @todo This should work for more than ONE rep node! - */ - pscoord.m_repRef = numberToRef(PSREPBLOCKNO, i); - pspart.m_repRef = numberToRef(PSREPBLOCKNO, i); -#if 0 - ndbout_c("Grep: REP node %d detected", i); -#endif - } - } - - /***************************** - * Check which DB nodes exist - *****************************/ - m_aliveNodes.clear(); - - Uint32 count = 0; - for(i = 0; iallNodes, i)) - { - jam(); - count++; - - NodePtr node; - ndbrequire(m_nodes.seize(node)); - - node.p->nodeId = i; - if (NodeBitmask::get(conf->inactiveNodes, i)) - { - node.p->alive = 0; - } - else - { - node.p->alive = 1; - m_aliveNodes.set(i); - } - } - } - m_masterNodeId = conf->masterNodeId; - ndbrequire(count == conf->noOfNodes); - sendSTTORRY(signal); -} - -void -Grep::sendSTTORRY(Signal* signal) -{ - signal->theData[0] = 0; - signal->theData[3] = 1; - signal->theData[4] = 3; - signal->theData[5] = 5; - signal->theData[6] = 7; - signal->theData[7] = 255; // No more start phases from missra - sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 8, JBB); -} - -void -Grep::execNDB_STTOR(Signal* signal) -{ - jamEntry(); -} - -void -Grep::execDUMP_STATE_ORD(Signal* signal) -{ - jamEntry(); - //Uint32 tCase = signal->theData[0]; - -#if 0 - if(sscoord.m_repRef == 0) - { - ndbout << "Grep: Recd DUMP signal but has no connection with REP node" - << endl; - return; - } -#endif - - /* - switch (tCase) - { - case 8100: sscoord.grepReq(signal, GrepReq::START_SUBSCR); break; - case 8102: sscoord.grepReq(signal, GrepReq::START_METALOG); break; - case 8104: sscoord.grepReq(signal, GrepReq::START_METASCAN); break; - case 8106: sscoord.grepReq(signal, GrepReq::START_DATALOG); break; - case 8108: sscoord.grepReq(signal, GrepReq::START_DATASCAN); break; - case 8110: sscoord.grepReq(signal, GrepReq::STOP_SUBSCR); break; - case 8500: sscoord.grepReq(signal, GrepReq::REMOVE_BUFFERS); break; - case 8300: sscoord.grepReq(signal, GrepReq::SLOWSTOP); break; - case 8400: sscoord.grepReq(signal, GrepReq::FASTSTOP); break; - case 8600: sscoord.grepReq(signal, GrepReq::CREATE_SUBSCR); break; - case 8700: sscoord.dropTable(signal,(Uint32)signal->theData[1]);break; - default: break; - } - */ -} - -/** - * Signal received when REP node has failed - */ -void -Grep::execAPI_FAILREQ(Signal* signal) -{ - jamEntry(); - //Uint32 failedApiNode = signal->theData[0]; - //BlockReference retRef = signal->theData[1]; - - /** - * @todo We should probably do something smart if the - * PS REP node fails???? /Lars - */ - -#if 0 - ndbout_c("Grep: API_FAILREQ received for API node %d.", failedApiNode); -#endif - - /** - * @note This signal received is NOT allowed to send any CONF - * signal, since this would screw up TC/DICT to API - * "connections". - */ -} - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: GREP Control - * ------------------------------------------------------------------------ - **************************************************************************/ -void -Grep::execGREP_REQ(Signal* signal) -{ - jamEntry(); - - //GrepReq * req = (GrepReq *)signal->getDataPtr(); - - /** - * @todo Fix so that request is redirected to REP Server - * Obsolete? - * Was: sscoord.grepReq(signal, req->request); - */ - ndbout_c("Warning! REP commands can only be executed at REP SERVER prompt!"); -} - - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: NODE STATE HANDLING - * ------------------------------------------------------------------------ - **************************************************************************/ -void -Grep::execNODE_FAILREP(Signal* signal) -{ - jamEntry(); - NodeFailRep * rep = (NodeFailRep*)signal->getDataPtr(); - bool changed = false; - - NodePtr nodePtr; - for(m_nodes.first(nodePtr); nodePtr.i != RNIL; m_nodes.next(nodePtr)) - { - jam(); - if (NodeBitmask::get(rep->theNodes, nodePtr.p->nodeId)) - { - jam(); - - if (nodePtr.p->alive) - { - jam(); - ndbassert(m_aliveNodes.get(nodePtr.p->nodeId)); - changed = true; - } - else - { - ndbassert(!m_aliveNodes.get(nodePtr.p->nodeId)); - } - - nodePtr.p->alive = 0; - m_aliveNodes.clear(nodePtr.p->nodeId); - } - } - - - /** - * Problem: Fix a node failure running a protocol - * - * 1. Coordinator node of a protocol dies - * - Elect a new coordinator - * - send ref to user - * - * 2. Non-coordinator dies. - * - make coordinator aware of this - * so that coordinator does not wait for - * conf from faulty node - * - node recovery will restore the non-coordinator. - * - */ -} - -void -Grep::execINCL_NODEREQ(Signal* signal) -{ - jamEntry(); - - //const Uint32 senderRef = signal->theData[0]; - const Uint32 inclNode = signal->theData[1]; - - NodePtr node; - for(m_nodes.first(node); node.i != RNIL; m_nodes.next(node)) - { - jam(); - const Uint32 nodeId = node.p->nodeId; - if (inclNode == nodeId) { - jam(); - - ndbrequire(node.p->alive == 0); - ndbassert(!m_aliveNodes.get(nodeId)); - - node.p->alive = 1; - m_aliveNodes.set(nodeId); - - break; - } - } - - /** - * @todo: if we include this DIH's got to be prepared, later if needed... - */ -#if 0 - signal->theData[0] = reference(); - - sendSignal(senderRef, GSN_INCL_NODECONF, signal, 1, JBB); -#endif -} - - -/** - * Helper methods - */ -void -Grep::PSCoord::prepareOperationRec(SubCoordinatorPtr subPtr, - BlockReference subscriber, - Uint32 subId, - Uint32 subKey, - Uint32 request) -{ - subPtr.p->m_coordinatorRef = reference(); - subPtr.p->m_subscriberRef = subscriber; - subPtr.p->m_subscriberData = subPtr.i; - subPtr.p->m_subscriptionId = subId; - subPtr.p->m_subscriptionKey = subKey; - subPtr.p->m_outstandingRequest = request; -} - - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: CREATE SUBSCRIPTION ID - * ------------------------------------------------------------------------ - * - * Requests SUMA to create a unique subscription id - **************************************************************************/ - -void -Grep::PSCoord::execGREP_CREATE_SUBID_REQ(Signal* signal) -{ - jamEntry(); - - CreateSubscriptionIdReq * req = - (CreateSubscriptionIdReq*)signal->getDataPtr(); - BlockReference ref = signal->getSendersBlockRef(); - - SubCoordinatorPtr subPtr; - if( !c_subCoordinatorPool.seize(subPtr)) { - jam(); - SubCoordinator sub; - sub.m_subscriberRef = ref; - sub.m_subscriptionId = 0; - sub.m_subscriptionKey = 0; - sendRefToSS(signal, sub, GrepError::SUBSCRIPTION_ID_NOMEM ); - return; - } - prepareOperationRec(subPtr, - ref, - 0,0, - GSN_CREATE_SUBID_REQ); - - - ndbout_c("SUBID_REQ Ref %d",ref); - req->senderData=subPtr.p->m_subscriberData; - - sendSignal(SUMA_REF, GSN_CREATE_SUBID_REQ, signal, - SubCreateReq::SignalLength, JBB); - -#if 1 //def DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSCoord: Sent CREATE_SUBID_REQ to SUMA"); -#endif -} - -void -Grep::PSCoord::execCREATE_SUBID_CONF(Signal* signal) -{ - jamEntry(); - CreateSubscriptionIdConf const * conf = - (CreateSubscriptionIdConf *)signal->getDataPtr(); - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 subData = conf->subscriberData; - -#if 1 //def DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSCoord: Recd GREP_SUBID_CONF (subId:%d, subKey:%d)", - subId, subKey); -#endif - - SubCoordinatorPtr subPtr; - c_subCoordinatorPool.getPtr(subPtr, subData); - BlockReference repRef = subPtr.p->m_subscriberRef; - - { // Check that id/key is unique - SubCoordinator key; - SubCoordinatorPtr tmp; - key.m_subscriptionId = subId; - key.m_subscriptionKey = subKey; - if(c_runningSubscriptions.find(tmp, key)){ - jam(); - SubCoordinator sub; - sub.m_subscriberRef=repRef; - sub.m_subscriptionId = subId; - sub.m_subscriptionKey = subKey; - sendRefToSS(signal,sub, GrepError::SUBSCRIPTION_ID_NOT_UNIQUE ); - return; - } - } - - sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_CREATE_SUBID_CONF, signal, - CreateSubscriptionIdConf::SignalLength, JBB); - c_subCoordinatorPool.release(subData); - - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionInfo, - GrepEvent::GrepPS_CreateSubIdConf, - subId, - subKey, - (Uint32)GrepError::GE_NO_ERROR); -} - -void -Grep::PSCoord::execCREATE_SUBID_REF(Signal* signal) { - jamEntry(); - CreateSubscriptionIdRef const * ref = - (CreateSubscriptionIdRef *)signal->getDataPtr(); - Uint32 subData = ref->subscriberData; - GrepError::GE_Code err; - - Uint32 sendersBlockRef = signal->getSendersBlockRef(); - if(sendersBlockRef == SUMA_REF) - { - jam(); - err = GrepError::SUBSCRIPTION_ID_SUMA_FAILED_CREATE; - } else { - jam(); - ndbrequire(false); /* Added since errorcode err unhandled - * TODO: fix correct errorcode - */ - err= GrepError::GE_NO_ERROR; // remove compiler warning - } - - SubCoordinatorPtr subPtr; - c_runningSubscriptions.getPtr(subPtr, subData); - BlockReference repref = subPtr.p->m_subscriberRef; - - SubCoordinator sub; - sub.m_subscriberRef = repref; - sub.m_subscriptionId = 0; - sub.m_subscriptionKey = 0; - sendRefToSS(signal,sub, err); - -} - - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: CREATE SUBSCRIPTION - * ------------------------------------------------------------------------ - * - * Creates a subscription for every GREP to its local SUMA. - * GREP node that executes createSubscription becomes the GREP Coord. - **************************************************************************/ - -/** - * Request to create a subscription (sent from SS) - */ -void -Grep::PSCoord::execGREP_SUB_CREATE_REQ(Signal* signal) -{ - jamEntry(); - GrepSubCreateReq const * grepReq = (GrepSubCreateReq *)signal->getDataPtr(); - Uint32 subId = grepReq->subscriptionId; - Uint32 subKey = grepReq->subscriptionKey; - Uint32 subType = grepReq->subscriptionType; - BlockReference rep = signal->getSendersBlockRef(); - - GrepCreateReq * req =(GrepCreateReq*)grepReq; - - SubCoordinatorPtr subPtr; - - if( !c_subCoordinatorPool.seize(subPtr)) { - jam(); - SubCoordinator sub; - sub.m_subscriberRef = rep; - sub.m_subscriptionId = 0; - sub.m_subscriptionKey = 0; - sub.m_outstandingRequest = GSN_GREP_CREATE_REQ; - sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL); - return; - } - prepareOperationRec(subPtr, - numberToRef(PSREPBLOCKNO, refToNode(rep)), subId, subKey, - GSN_GREP_CREATE_REQ); - - /* Get the payload of the signal. - */ - SegmentedSectionPtr selectedTablesPtr; - if(subType == SubCreateReq::SelectiveTableSnapshot) { - jam(); - ndbrequire(signal->getNoOfSections()==1); - signal->getSection(selectedTablesPtr,0); - signal->header.m_noOfSections = 0; - } - /** - * Prepare the signal to be sent to Grep participatns - */ - subPtr.p->m_subscriptionType = subType; - req->senderRef = reference(); - req->subscriberRef = numberToRef(PSREPBLOCKNO, refToNode(rep)); - req->subscriberData = subPtr.p->m_subscriberData; - req->subscriptionId = subId; - req->subscriptionKey = subKey; - req->subscriptionType = subType; - - /*add payload if it is a selectivetablesnap*/ - if(subType == SubCreateReq::SelectiveTableSnapshot) { - jam(); - signal->setSection(selectedTablesPtr, 0); - } - - /****************************** - * Send to all PS participants - ******************************/ - NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes); - subPtr.p->m_outstandingParticipants = rg; - sendSignal(rg, - GSN_GREP_CREATE_REQ, signal, - GrepCreateReq::SignalLength, JBB); - - -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSCoord: Sent GREP_CREATE_REQ " - "(subId:%d, subKey:%d, subData:%d, subType:%d) to parts", - subId, subKey, subPtr.p->m_subscriberData, subType); -#endif -} - -void -Grep::PSPart::execGREP_CREATE_REQ(Signal* signal) -{ - jamEntry(); - GrepCreateReq * const grepReq = (GrepCreateReq *)signal->getDataPtr(); - const Uint32 subId = grepReq->subscriptionId; - const Uint32 subKey = grepReq->subscriptionKey; - const Uint32 subData = grepReq->subscriberData; - const Uint32 subType = grepReq->subscriptionType; - const Uint32 coordinatorRef = grepReq->senderRef; - const Uint32 subRef = grepReq->subscriberRef; //this is ref to the - //REP node for this - //subscription. - - SubscriptionPtr subPtr; - ndbrequire( c_subscriptionPool.seize(subPtr)); - subPtr.p->m_coordinatorRef = coordinatorRef; - subPtr.p->m_subscriptionId = subId; - subPtr.p->m_subscriptionKey = subKey; - subPtr.p->m_subscriberRef = subRef; - subPtr.p->m_subscriberData = subPtr.i; - subPtr.p->m_subscriptionType = subType; - subPtr.p->m_outstandingRequest = GSN_GREP_CREATE_REQ; - subPtr.p->m_operationPtrI = subData; - - c_subscriptions.add(subPtr); - - SegmentedSectionPtr selectedTablesPtr; - if(subType == SubCreateReq::SelectiveTableSnapshot) { - jam(); - ndbrequire(signal->getNoOfSections()==1); - signal->getSection(selectedTablesPtr,0);// SubCreateReq::TABLE_LIST); - signal->header.m_noOfSections = 0; - } - - /** - * Prepare signal to be sent to SUMA - */ - SubCreateReq * sumaReq = (SubCreateReq *)grepReq; - sumaReq->subscriberRef = GREP_REF; - sumaReq->subscriberData = subPtr.p->m_subscriberData; - sumaReq->subscriptionId = subPtr.p->m_subscriptionId; - sumaReq->subscriptionKey = subPtr.p->m_subscriptionKey; - sumaReq->subscriptionType = subPtr.p->m_subscriptionType; - /*add payload if it is a selectivetablesnap*/ - if(subType == SubCreateReq::SelectiveTableSnapshot) { - jam(); - signal->setSection(selectedTablesPtr, 0); - } - sendSignal(SUMA_REF, - GSN_SUB_CREATE_REQ, - signal, - SubCreateReq::SignalLength, - JBB); -} - -void -Grep::PSPart::execSUB_CREATE_CONF(Signal* signal) -{ - jamEntry(); - - SubCreateConf * const conf = (SubCreateConf *)signal->getDataPtr(); - Uint32 subData = conf->subscriberData; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - /** - @todo check why this can fuck up -johan - - ndbrequire(subPtr.p->m_subscriptionId == conf->subscriptionId); - ndbrequire(subPtr.p->m_subscriptionKey == conf->subscriptionKey); - */ -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSPart: Recd SUB_CREATE_CONF " - "(subId:%d, subKey:%d) from SUMA", - conf->subscriptionId, conf->subscriptionKey); -#endif - - /********************* - * Send conf to coord - *********************/ - GrepCreateConf * grepConf = (GrepCreateConf*)conf; - grepConf->senderNodeId = getOwnNodeId(); - grepConf->senderData = subPtr.p->m_operationPtrI; - sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_CREATE_CONF, signal, - GrepCreateConf::SignalLength, JBB); - subPtr.p->m_outstandingRequest = 0; -} - -/** - * Handle errors that either occured in: - * 1) PSPart - * or - * 2) propagated from local SUMA - */ -void -Grep::PSPart::execSUB_CREATE_REF(Signal* signal) -{ - jamEntry(); - SubCreateRef * const ref = (SubCreateRef *)signal->getDataPtr(); - Uint32 subData = ref->subscriberData; - GrepError::GE_Code err = (GrepError::GE_Code)ref->err; - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - sendRefToPSCoord(signal, *subPtr.p, err /*error*/); - subPtr.p->m_outstandingRequest = 0; -} - -void -Grep::PSCoord::execGREP_CREATE_CONF(Signal* signal) -{ - jamEntry(); - GrepCreateConf const * conf = (GrepCreateConf *)signal->getDataPtr(); - Uint32 subData = conf->senderData; - Uint32 nodeId = conf->senderNodeId; - - SubCoordinatorPtr subPtr; - c_subCoordinatorPool.getPtr(subPtr, subData); - - ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_CREATE_REQ); - - subPtr.p->m_outstandingParticipants.clearWaitingFor(nodeId); - - if(!subPtr.p->m_outstandingParticipants.done()) return; - /******************************** - * All participants have CONF:ed - ********************************/ - Uint32 subId = subPtr.p->m_subscriptionId; - Uint32 subKey = subPtr.p->m_subscriptionKey; - - GrepSubCreateConf * grepConf = (GrepSubCreateConf *)signal->getDataPtr(); - grepConf->subscriptionId = subId; - grepConf->subscriptionKey = subKey; - sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_CREATE_CONF, signal, - GrepSubCreateConf::SignalLength, JBB); - - /** - * Send event report - */ - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionInfo, - GrepEvent::GrepPS_SubCreateConf, - subId, - subKey, - (Uint32)GrepError::GE_NO_ERROR); - - c_subCoordinatorPool.release(subPtr); - -} - -/** - * Handle errors that either occured in: - * 1) PSCoord - * or - * 2) propagated from PSPart - */ -void -Grep::PSCoord::execGREP_CREATE_REF(Signal* signal) -{ - jamEntry(); - GrepCreateRef * const ref = (GrepCreateRef *)signal->getDataPtr(); - Uint32 subData = ref->senderData; - Uint32 err = ref->err; - SubCoordinatorPtr subPtr; - c_runningSubscriptions.getPtr(subPtr, subData); - - sendRefToSS(signal, *subPtr.p, (GrepError::GE_Code)err /*error*/); -} - - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: START SUBSCRIPTION - * ------------------------------------------------------------------------ - * - * Starts a subscription at SUMA. - * Each participant starts its own subscription. - **************************************************************************/ - -/** - * Request to start subscription (Sent from SS) - */ -void -Grep::PSCoord::execGREP_SUB_START_REQ(Signal* signal) -{ - jamEntry(); - GrepSubStartReq * const subReq = (GrepSubStartReq *)signal->getDataPtr(); - SubscriptionData::Part part = (SubscriptionData::Part) subReq->part; - Uint32 subId = subReq->subscriptionId; - Uint32 subKey = subReq->subscriptionKey; - BlockReference rep = signal->getSendersBlockRef(); - - SubCoordinatorPtr subPtr; - - if(!c_subCoordinatorPool.seize(subPtr)) { - jam(); - SubCoordinator sub; - sub.m_subscriberRef = rep; - sub.m_subscriptionId = 0; - sub.m_subscriptionKey = 0; - sub.m_outstandingRequest = GSN_GREP_START_REQ; - sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL); - return; - } - - prepareOperationRec(subPtr, - numberToRef(PSREPBLOCKNO, refToNode(rep)), - subId, subKey, - GSN_GREP_START_REQ); - - GrepStartReq * const req = (GrepStartReq *) subReq; - req->part = (Uint32) part; - req->subscriptionId = subPtr.p->m_subscriptionId; - req->subscriptionKey = subPtr.p->m_subscriptionKey; - req->senderData = subPtr.p->m_subscriberData; - - /*************************** - * Send to all participants - ***************************/ - NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes); - subPtr.p->m_outstandingParticipants = rg; - sendSignal(rg, - GSN_GREP_START_REQ, - signal, - GrepStartReq::SignalLength, JBB); - -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSCoord: Sent GREP_START_REQ " - "(subId:%d, subKey:%d, senderData:%d, part:%d) to all participants", - req->subscriptionId, req->subscriptionKey, req->senderData, part); -#endif -} - - -void -Grep::PSPart::execGREP_START_REQ(Signal* signal) -{ - jamEntry(); - GrepStartReq * const grepReq = (GrepStartReq *) signal->getDataPtr(); - SubscriptionData::Part part = (SubscriptionData::Part)grepReq->part; - Uint32 subId = grepReq->subscriptionId; - Uint32 subKey = grepReq->subscriptionKey; - Uint32 operationPtrI = grepReq->senderData; - - Subscription key; - key.m_subscriptionId = subId; - key.m_subscriptionKey = subKey; - SubscriptionPtr subPtr; - ndbrequire(c_subscriptions.find(subPtr, key));; - subPtr.p->m_outstandingRequest = GSN_GREP_START_REQ; - subPtr.p->m_operationPtrI = operationPtrI; - /** - * send SUB_START_REQ to local SUMA - */ - SubStartReq * sumaReq = (SubStartReq *) grepReq; - sumaReq->subscriptionId = subId; - sumaReq->subscriptionKey = subKey; - sumaReq->subscriberData = subPtr.i; - sumaReq->part = (Uint32) part; - - sendSignal(SUMA_REF, GSN_SUB_START_REQ, signal, - SubStartReq::SignalLength, JBB); -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSPart: Sent SUB_START_REQ (subId:%d, subKey:%d, part:%d)", - subId, subKey, (Uint32)part); -#endif -} - - -void -Grep::PSPart::execSUB_START_CONF(Signal* signal) -{ - jamEntry(); - - SubStartConf * const conf = (SubStartConf *) signal->getDataPtr(); - SubscriptionData::Part part = (SubscriptionData::Part)conf->part; - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 subData = conf->subscriberData; - Uint32 firstGCI = conf->firstGCI; -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSPart: Recd SUB_START_CONF " - "(subId:%d, subKey:%d, subData:%d)", - subId, subKey, subData); -#endif - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - ndbrequire(subPtr.p->m_subscriptionId == subId); - ndbrequire(subPtr.p->m_subscriptionKey == subKey); - - GrepStartConf * grepConf = (GrepStartConf *)conf; - grepConf->senderData = subPtr.p->m_operationPtrI; - grepConf->part = (Uint32) part; - grepConf->subscriptionKey = subKey; - grepConf->subscriptionId = subId; - grepConf->firstGCI = firstGCI; - grepConf->senderNodeId = getOwnNodeId(); - sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_START_CONF, signal, - GrepStartConf::SignalLength, JBB); - subPtr.p->m_outstandingRequest = 0; - -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSPart: Sent GREP_START_CONF " - "(subId:%d, subKey:%d, subData:%d, part:%d)", - subId, subKey, subData, part); -#endif -} - - -/** - * Handle errors that either occured in: - * 1) PSPart - * or - * 2) propagated from local SUMA - * - * Propagates REF signal to PSCoord - */ -void -Grep::PSPart::execSUB_START_REF(Signal* signal) -{ - SubStartRef * const ref = (SubStartRef *)signal->getDataPtr(); - Uint32 subData = ref->subscriberData; - GrepError::GE_Code err = (GrepError::GE_Code)ref->err; - SubscriptionData::Part part = (SubscriptionData::Part)ref->part; - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - sendRefToPSCoord(signal, *subPtr.p, err /*error*/, part); - subPtr.p->m_outstandingRequest = 0; -} - - -/** - * Logging has started... (says PS Participant) - */ -void -Grep::PSCoord::execGREP_START_CONF(Signal* signal) -{ - jamEntry(); - - GrepStartConf * const conf = (GrepStartConf *) signal->getDataPtr(); - Uint32 subData = conf->senderData; - SubscriptionData::Part part = (SubscriptionData::Part)conf->part; - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 firstGCI = conf->firstGCI; - - SubCoordinatorPtr subPtr; - c_subCoordinatorPool.getPtr(subPtr, subData); - ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_START_REQ); - - subPtr.p->m_outstandingParticipants.clearWaitingFor(conf->senderNodeId); - - if(!subPtr.p->m_outstandingParticipants.done()) return; - jam(); - - /************************* - * All participants ready - *************************/ - GrepSubStartConf * grepConf = (GrepSubStartConf *) conf; - grepConf->part = part; - grepConf->subscriptionId = subId; - grepConf->subscriptionKey = subKey; - grepConf->firstGCI = firstGCI; - - bool ok = false; - switch(part) { - case SubscriptionData::MetaData: - ok = true; - sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_START_CONF, signal, - GrepSubStartConf::SignalLength, JBB); - - /** - * Send event report - */ - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionInfo, - GrepEvent::GrepPS_SubStartMetaConf, - subId, subKey, - (Uint32)GrepError::GE_NO_ERROR); - - c_subCoordinatorPool.release(subPtr); - break; - case SubscriptionData::TableData: - ok = true; - sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_START_CONF, signal, - GrepSubStartConf::SignalLength, JBB); - - /** - * Send event report - */ - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionInfo, - GrepEvent::GrepPS_SubStartDataConf, - subId, subKey, - (Uint32)GrepError::GE_NO_ERROR); - - - c_subCoordinatorPool.release(subPtr); - break; - } - ndbrequire(ok); - -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSCoord: Recd SUB_START_CONF (subId:%d, subKey:%d, part:%d) " - "from all slaves", - subId, subKey, (Uint32)part); -#endif -} - -/** - * Handle errors that either occured in: - * 1) PSCoord - * or - * 2) propagated from PSPart - */ -void -Grep::PSCoord::execGREP_START_REF(Signal* signal) -{ - jamEntry(); - GrepStartRef * const ref = (GrepStartRef *)signal->getDataPtr(); - Uint32 subData = ref->senderData; - GrepError::GE_Code err = (GrepError::GE_Code)ref->err; - SubscriptionData::Part part = (SubscriptionData::Part)ref->part; - - SubCoordinatorPtr subPtr; - c_runningSubscriptions.getPtr(subPtr, subData); - sendRefToSS(signal, *subPtr.p, err /*error*/, part); -} - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: REMOVE SUBSCRIPTION - * ------------------------------------------------------------------------ - * - * Remove a subscription at SUMA. - * Each participant removes its own subscription. - * We start by deleting the subscription inside the requestor - * since, we don't know if nodes (REP nodes or DB nodes) - * have disconnected after we sent out this and - * if we dont delete the sub in the requestor now, - * we won't be able to create a new subscription - **************************************************************************/ - -/** - * Request to abort subscription (Sent from SS) - */ -void -Grep::PSCoord::execGREP_SUB_REMOVE_REQ(Signal* signal) -{ - jamEntry(); - GrepSubRemoveReq * const subReq = (GrepSubRemoveReq *)signal->getDataPtr(); - Uint32 subId = subReq->subscriptionId; - Uint32 subKey = subReq->subscriptionKey; - BlockReference rep = signal->getSendersBlockRef(); - - SubCoordinatorPtr subPtr; - if( !c_subCoordinatorPool.seize(subPtr)) { - jam(); - SubCoordinator sub; - sub.m_subscriberRef = rep; - sub.m_subscriptionId = 0; - sub.m_subscriptionKey = 0; - sub.m_outstandingRequest = GSN_GREP_REMOVE_REQ; - sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL); - return; - } - - - prepareOperationRec(subPtr, - numberToRef(PSREPBLOCKNO, refToNode(rep)), - subId, subKey, - GSN_GREP_REMOVE_REQ); - - c_runningSubscriptions.add(subPtr); - - GrepRemoveReq * req = (GrepRemoveReq *) subReq; - req->subscriptionId = subPtr.p->m_subscriptionId; - req->subscriptionKey = subPtr.p->m_subscriptionKey; - req->senderData = subPtr.p->m_subscriberData; - req->senderRef = subPtr.p->m_coordinatorRef; - - /*************************** - * Send to all participants - ***************************/ - NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes); - subPtr.p->m_outstandingParticipants = rg; - sendSignal(rg, - GSN_GREP_REMOVE_REQ, signal, - GrepRemoveReq::SignalLength, JBB); -} - - -void -Grep::PSPart::execGREP_REMOVE_REQ(Signal* signal) -{ - jamEntry(); - GrepRemoveReq * const grepReq = (GrepRemoveReq *) signal->getDataPtr(); - Uint32 subId = grepReq->subscriptionId; - Uint32 subKey = grepReq->subscriptionKey; - Uint32 subData = grepReq->senderData; - Uint32 coordinator = grepReq->senderRef; - - Subscription key; - key.m_subscriptionId = subId; - key.m_subscriptionKey = subKey; - SubscriptionPtr subPtr; - - if(!c_subscriptions.find(subPtr, key)) - { - /** - * The subscription was not found, so it must be deleted. - * Send CONF back, since it does not exist (thus, it is removed) - */ - GrepRemoveConf * grepConf = (GrepRemoveConf *)grepReq; - grepConf->subscriptionKey = subKey; - grepConf->subscriptionId = subId; - grepConf->senderData = subData; - grepConf->senderNodeId = getOwnNodeId(); - sendSignal(coordinator, GSN_GREP_REMOVE_CONF, signal, - GrepRemoveConf::SignalLength, JBB); - return; - } - - subPtr.p->m_operationPtrI = subData; - subPtr.p->m_coordinatorRef = coordinator; - subPtr.p->m_outstandingRequest = GSN_GREP_REMOVE_REQ; - - /** - * send SUB_REMOVE_REQ to local SUMA - */ - SubRemoveReq * sumaReq = (SubRemoveReq *) grepReq; - sumaReq->subscriptionId = subId; - sumaReq->subscriptionKey = subKey; - sumaReq->senderData = subPtr.i; - sendSignal(SUMA_REF, GSN_SUB_REMOVE_REQ, signal, - SubStartReq::SignalLength, JBB); -} - - -/** - * SUB_REMOVE_CONF (from local SUMA) - */ -void -Grep::PSPart::execSUB_REMOVE_CONF(Signal* signal) -{ - jamEntry(); - SubRemoveConf * const conf = (SubRemoveConf *) signal->getDataPtr(); - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 subData = conf->subscriberData; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - ndbrequire(subPtr.p->m_subscriptionId == subId); - ndbrequire(subPtr.p->m_subscriptionKey == subKey); - subPtr.p->m_outstandingRequest = 0; - GrepRemoveConf * grepConf = (GrepRemoveConf *)conf; - grepConf->subscriptionKey = subKey; - grepConf->subscriptionId = subId; - grepConf->senderData = subPtr.p->m_operationPtrI; - grepConf->senderNodeId = getOwnNodeId(); - sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_REMOVE_CONF, signal, - GrepRemoveConf::SignalLength, JBB); - c_subscriptions.release(subPtr); - -} - - -/** - * SUB_REMOVE_CONF (from local SUMA) - */ -void -Grep::PSPart::execSUB_REMOVE_REF(Signal* signal) -{ - jamEntry(); - SubRemoveRef * const ref = (SubRemoveRef *)signal->getDataPtr(); - Uint32 subData = ref->subscriberData; - /* GrepError::GE_Code err = (GrepError::GE_Code)ref->err;*/ - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - - //sendSubRemoveRef_PSCoord(signal, *subPtr.p, err /*error*/); -} - - -/** - * Aborting has been carried out (says Participants) - */ -void -Grep::PSCoord::execGREP_REMOVE_CONF(Signal* signal) -{ - jamEntry(); - GrepRemoveConf * const conf = (GrepRemoveConf *) signal->getDataPtr(); - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 senderNodeId = conf->senderNodeId; - Uint32 subData = conf->senderData; - SubCoordinatorPtr subPtr; - c_subCoordinatorPool.getPtr(subPtr, subData); - - ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_REMOVE_REQ); - - subPtr.p->m_outstandingParticipants.clearWaitingFor(senderNodeId); - - if(!subPtr.p->m_outstandingParticipants.done()) { - jam(); - return; - } - jam(); - - /************************* - * All participants ready - *************************/ - - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionInfo, - GrepEvent::GrepPS_SubRemoveConf, - subId, subKey, - GrepError::GE_NO_ERROR); - - GrepSubRemoveConf * grepConf = (GrepSubRemoveConf *) conf; - grepConf->subscriptionId = subId; - grepConf->subscriptionKey = subKey; - sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_REMOVE_CONF, signal, - GrepSubRemoveConf::SignalLength, JBB); - - c_subCoordinatorPool.release(subPtr); -} - - - -void -Grep::PSCoord::execGREP_REMOVE_REF(Signal* signal) -{ - jamEntry(); - GrepRemoveRef * const ref = (GrepRemoveRef *)signal->getDataPtr(); - Uint32 subData = ref->senderData; - Uint32 err = ref->err; - SubCoordinatorPtr subPtr; - - /** - * Get the operationrecord matching subdata and remove it. Subsequent - * execGREP_REMOVE_REF will simply be ignored at this stage. - */ - for( c_runningSubscriptions.first(c_subPtr); - !c_subPtr.isNull(); c_runningSubscriptions.next(c_subPtr)) { - jam(); - subPtr.i = c_subPtr.curr.i; - subPtr.p = c_runningSubscriptions.getPtr(subPtr.i); - if(subData == subPtr.i) - { - sendRefToSS(signal, *subPtr.p, (GrepError::GE_Code)err /*error*/); - c_runningSubscriptions.release(subPtr); - return; - } - } - return; -} - - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: LOG RECORDS (COMING IN FROM LOCAL SUMA) - * ------------------------------------------------------------------------ - * - * After the subscription is started, we get log records from SUMA. - * Both table data and meta data log records are received. - * - * TODO: - * @todo Changes in meta data is currently not - * allowed during global replication - **************************************************************************/ - -void -Grep::PSPart::execSUB_META_DATA(Signal* signal) -{ - jamEntry(); - if(m_recoveryMode) { - jam(); - return; - } - /** - * METASCAN and METALOG - */ - SubMetaData * data = (SubMetaData *) signal->getDataPtrSend(); - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, data->subscriberData); - - /*************************** - * Forward data to REP node - ***************************/ - sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_META_DATA, signal, - SubMetaData::SignalLength, JBB); -#ifdef DEBUG_GREP_SUBSCRIPTION - ndbout_c("Grep::PSPart: Sent SUB_META_DATA to REP " - "(TableId: %d, SenderData: %d, GCI: %d)", - data->tableId, data->senderData, data->gci); -#endif -} - -/** - * Receive table data from SUMA and dispatches it to REP node. - */ -void -Grep::PSPart::execSUB_TABLE_DATA(Signal* signal) -{ - jamEntry(); - if(m_recoveryMode) { - jam(); - return; - } - ndbrequire(m_repRef!=0); - - if(!assembleFragments(signal)) { jam(); return; } - - /** - * Check if it is SCAN or LOG data that has arrived - */ - if(signal->getNoOfSections() == 2) - { - jam(); - /** - * DATASCAN - Not marked with GCI, so mark with latest seen GCI - */ - if(m_firstScanGCI == 1 && m_lastScanGCI == 0) { - m_firstScanGCI = m_latestSeenGCI; - m_lastScanGCI = m_latestSeenGCI; - } - SubTableData * data = (SubTableData*)signal->getDataPtrSend(); - Uint32 subData = data->senderData; - data->gci = m_latestSeenGCI; - data->logType = SubTableData::SCAN; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_TABLE_DATA, signal, - SubTableData::SignalLength, JBB); -#ifdef DEBUG_GREP - ndbout_c("Grep::PSPart: Sent SUB_TABLE_DATA (Scan, GCI: %d)", - data->gci); -#endif - } - else - { - jam(); - /** - * DATALOG (TRIGGER) - Already marked with GCI - */ - SubTableData * data = (SubTableData*)signal->getDataPtrSend(); - data->logType = SubTableData::LOG; - Uint32 subData = data->senderData; - if (data->gci > m_latestSeenGCI) m_latestSeenGCI = data->gci; - - // Reformat to sections and send to replication node. - LinearSectionPtr ptr[3]; - ptr[0].p = signal->theData + 25; - ptr[0].sz = data->noOfAttributes; - ptr[1].p = signal->theData + 25 + MAX_ATTRIBUTES_IN_TABLE; - ptr[1].sz = data->dataSize; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_TABLE_DATA, - signal, SubTableData::SignalLength, JBB, ptr, 2); -#ifdef DEBUG_GREP - ndbout_c("Grep::PSPart: Sent SUB_TABLE_DATA (Log, GCI: %d)", - data->gci); -#endif - } -} - - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: START SYNCHRONIZATION - * ------------------------------------------------------------------------ - * - * - **************************************************************************/ - -/** - * Request to start sync (from Rep SS) - */ -void -Grep::PSCoord::execGREP_SUB_SYNC_REQ(Signal* signal) -{ - jamEntry(); - GrepSubSyncReq * const subReq = (GrepSubSyncReq*)signal->getDataPtr(); - SubscriptionData::Part part = (SubscriptionData::Part) subReq->part; - Uint32 subId = subReq->subscriptionId; - Uint32 subKey = subReq->subscriptionKey; - BlockReference rep = signal->getSendersBlockRef(); - - SubCoordinatorPtr subPtr; - if( !c_subCoordinatorPool.seize(subPtr)) { - jam(); - SubCoordinator sub; - sub.m_subscriberRef = rep; - sub.m_subscriptionId = 0; - sub.m_subscriptionKey = 0; - sub.m_outstandingRequest = GSN_GREP_SYNC_REQ; - sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL); - return; - } - - prepareOperationRec(subPtr, - numberToRef(PSREPBLOCKNO, refToNode(rep)), - subId, subKey, - GSN_GREP_SYNC_REQ); - - GrepSyncReq * req = (GrepSyncReq *)subReq; - req->subscriptionId = subPtr.p->m_subscriptionId; - req->subscriptionKey = subPtr.p->m_subscriptionKey; - req->senderData = subPtr.p->m_subscriberData; - req->part = (Uint32)part; - - /*************************** - * Send to all participants - ***************************/ - NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes); - subPtr.p->m_outstandingParticipants = rg; - sendSignal(rg, - GSN_GREP_SYNC_REQ, signal, GrepSyncReq::SignalLength, JBB); -} - - -/** - * Sync req from Grep::PSCoord to PS particpant - */ -void -Grep::PSPart::execGREP_SYNC_REQ(Signal* signal) -{ - jamEntry(); - - GrepSyncReq * const grepReq = (GrepSyncReq *) signal->getDataPtr(); - Uint32 part = grepReq->part; - Uint32 subId = grepReq->subscriptionId; - Uint32 subKey = grepReq->subscriptionKey; - Uint32 subData = grepReq->senderData; - - Subscription key; - key.m_subscriptionId = subId; - key.m_subscriptionKey = subKey; - SubscriptionPtr subPtr; - ndbrequire(c_subscriptions.find(subPtr, key)); - subPtr.p->m_operationPtrI = subData; - subPtr.p->m_outstandingRequest = GSN_GREP_SYNC_REQ; - /********************************** - * Send SUB_SYNC_REQ to local SUMA - **********************************/ - SubSyncReq * sumaReq = (SubSyncReq *)grepReq; - sumaReq->subscriptionId = subId; - sumaReq->subscriptionKey = subKey; - sumaReq->subscriberData = subPtr.i; - sumaReq->part = part; - sendSignal(SUMA_REF, GSN_SUB_SYNC_REQ, signal, - SubSyncReq::SignalLength, JBB); -} - - -/** - * SYNC conf from SUMA - */ -void -Grep::PSPart::execSUB_SYNC_CONF(Signal* signal) -{ - jamEntry(); - - SubSyncConf * const conf = (SubSyncConf *) signal->getDataPtr(); - Uint32 part = conf->part; - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 subData = conf->subscriberData; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - - ndbrequire(subPtr.p->m_subscriptionId == subId); - ndbrequire(subPtr.p->m_subscriptionKey == subKey); - - GrepSyncConf * grepConf = (GrepSyncConf *)conf; - grepConf->senderNodeId = getOwnNodeId(); - grepConf->part = part; - grepConf->firstGCI = m_firstScanGCI; - grepConf->lastGCI = m_lastScanGCI; - grepConf->subscriptionId = subId; - grepConf->subscriptionKey = subKey; - grepConf->senderData = subPtr.p->m_operationPtrI; - sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_SYNC_CONF, signal, - GrepSyncConf::SignalLength, JBB); - - m_firstScanGCI = 1; - m_lastScanGCI = 0; - subPtr.p->m_outstandingRequest = 0; -} - -/** - * Handle errors that either occured in: - * 1) PSPart - * or - * 2) propagated from local SUMA - * - * Propagates REF signal to PSCoord - */ -void -Grep::PSPart::execSUB_SYNC_REF(Signal* signal) { - jamEntry(); - SubSyncRef * const ref = (SubSyncRef *)signal->getDataPtr(); - Uint32 subData = ref->subscriberData; - GrepError::GE_Code err = (GrepError::GE_Code)ref->err; - SubscriptionData::Part part = (SubscriptionData::Part)ref->part; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr, subData); - sendRefToPSCoord(signal, *subPtr.p, err /*error*/ ,part); - subPtr.p->m_outstandingRequest = 0; -} - -/** - * Syncing has started... (says PS Participant) - */ -void -Grep::PSCoord::execGREP_SYNC_CONF(Signal* signal) -{ - jamEntry(); - - GrepSyncConf const * conf = (GrepSyncConf *)signal->getDataPtr(); - Uint32 part = conf->part; - Uint32 firstGCI = conf->firstGCI; - Uint32 lastGCI = conf->lastGCI; - Uint32 subId = conf->subscriptionId; - Uint32 subKey = conf->subscriptionKey; - Uint32 subData = conf->senderData; - - SubCoordinatorPtr subPtr; - c_subCoordinatorPool.getPtr(subPtr, subData); - ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_SYNC_REQ); - - subPtr.p->m_outstandingParticipants.clearWaitingFor(conf->senderNodeId); - if(!subPtr.p->m_outstandingParticipants.done()) return; - - /** - * Send event - */ - GrepEvent::Subscription event; - if(part == SubscriptionData::MetaData) - event = GrepEvent::GrepPS_SubSyncMetaConf; - else - event = GrepEvent::GrepPS_SubSyncDataConf; - - /* @todo Johan: Add firstGCI here. /Lars */ - m_grep->sendEventRep(signal, EventReport::GrepSubscriptionInfo, - event, subId, subKey, - (Uint32)GrepError::GE_NO_ERROR, - lastGCI); - - /************************* - * All participants ready - *************************/ - GrepSubSyncConf * grepConf = (GrepSubSyncConf *)conf; - grepConf->part = part; - grepConf->firstGCI = firstGCI; - grepConf->lastGCI = lastGCI; - grepConf->subscriptionId = subId; - grepConf->subscriptionKey = subKey; - - sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_SYNC_CONF, signal, - GrepSubSyncConf::SignalLength, JBB); - c_subCoordinatorPool.release(subPtr); -} - -/** - * Handle errors that either occured in: - * 1) PSCoord - * or - * 2) propagated from PSPart - */ -void -Grep::PSCoord::execGREP_SYNC_REF(Signal* signal) { - jamEntry(); - GrepSyncRef * const ref = (GrepSyncRef *)signal->getDataPtr(); - Uint32 subData = ref->senderData; - SubscriptionData::Part part = (SubscriptionData::Part)ref->part; - GrepError::GE_Code err = (GrepError::GE_Code)ref->err; - SubCoordinatorPtr subPtr; - c_runningSubscriptions.getPtr(subPtr, subData); - sendRefToSS(signal, *subPtr.p, err /*error*/, part); -} - - - -void -Grep::PSCoord::sendRefToSS(Signal * signal, - SubCoordinator sub, - GrepError::GE_Code err, - SubscriptionData::Part part) { - /** - - GrepCreateRef * ref = (GrepCreateRef*)signal->getDataPtrSend(); - ref->senderData = sub.m_subscriberData; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->err = err; - sendSignal(sub.m_coordinatorRef, GSN_GREP_CREATE_REF, signal, - GrepCreateRef::SignalLength, JBB); -*/ - - jam(); - GrepEvent::Subscription event; - switch(sub.m_outstandingRequest) { - case GSN_GREP_CREATE_SUBID_REQ: - { - jam(); - CreateSubscriptionIdRef * ref = - (CreateSubscriptionIdRef*)signal->getDataPtrSend(); - ref->err = (Uint32)err; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - sendSignal(sub.m_subscriberRef, - GSN_GREP_CREATE_SUBID_REF, - signal, - CreateSubscriptionIdRef::SignalLength, - JBB); - event = GrepEvent::GrepPS_CreateSubIdRef; - } - break; - case GSN_GREP_CREATE_REQ: - { - jam(); - GrepSubCreateRef * ref = (GrepSubCreateRef*)signal->getDataPtrSend(); - ref->err = (Uint32)err; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - sendSignal(sub.m_subscriberRef, GSN_GREP_SUB_CREATE_REF, signal, - GrepSubCreateRef::SignalLength, JBB); - event = GrepEvent::GrepPS_SubCreateRef; - } - break; - case GSN_GREP_SYNC_REQ: - { - jam(); - GrepSubSyncRef * ref = (GrepSubSyncRef*)signal->getDataPtrSend(); - ref->err = (Uint32)err; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->part = (SubscriptionData::Part) part; - sendSignal(sub.m_subscriberRef, - GSN_GREP_SUB_SYNC_REF, - signal, - GrepSubSyncRef::SignalLength, - JBB); - if(part == SubscriptionData::MetaData) - event = GrepEvent::GrepPS_SubSyncMetaRef; - else - event = GrepEvent::GrepPS_SubSyncDataRef; - } - break; - case GSN_GREP_START_REQ: - { - jam(); - GrepSubStartRef * ref = (GrepSubStartRef*)signal->getDataPtrSend(); - ref->err = (Uint32)err; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - - sendSignal(sub.m_subscriberRef, GSN_GREP_SUB_START_REF, - signal, GrepSubStartRef::SignalLength, JBB); - if(part == SubscriptionData::MetaData) - event = GrepEvent::GrepPS_SubStartMetaRef; - else - event = GrepEvent::GrepPS_SubStartDataRef; - /** - * Send event report - */ - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionAlert, - event, - sub.m_subscriptionId, - sub.m_subscriptionKey, - (Uint32)err); - } - break; - case GSN_GREP_REMOVE_REQ: - { - jam(); - GrepSubRemoveRef * ref = (GrepSubRemoveRef*)signal->getDataPtrSend(); - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->err = (Uint32)err; - - sendSignal(sub.m_subscriberRef, - GSN_GREP_SUB_REMOVE_REF, - signal, - GrepSubRemoveRef::SignalLength, - JBB); - - event = GrepEvent::GrepPS_SubRemoveRef; - } - break; - default: - ndbrequire(false); - event= GrepEvent::Rep_Disconnect; // remove compiler warning - } - /** - * Finally, send an event. - */ - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionAlert, - event, - sub.m_subscriptionId, - sub.m_subscriptionKey, - err); - -} - - -void -Grep::PSPart::sendRefToPSCoord(Signal * signal, - Subscription sub, - GrepError::GE_Code err, - SubscriptionData::Part part) { - - jam(); - GrepEvent::Subscription event; - switch(sub.m_outstandingRequest) { - - case GSN_GREP_CREATE_REQ: - { - GrepCreateRef * ref = (GrepCreateRef*)signal->getDataPtrSend(); - ref->senderData = sub.m_subscriberData; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->err = err; - sendSignal(sub.m_coordinatorRef, GSN_GREP_CREATE_REF, signal, - GrepCreateRef::SignalLength, JBB); - - event = GrepEvent::GrepPS_SubCreateRef; - } - break; - case GSN_GREP_SYNC_REQ: - { - GrepSyncRef * ref = (GrepSyncRef*)signal->getDataPtrSend(); - ref->senderData = sub.m_subscriberData; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->part = part; - ref->err = err; - sendSignal(sub.m_coordinatorRef, - GSN_GREP_SYNC_REF, signal, - GrepSyncRef::SignalLength, JBB); - if(part == SubscriptionData::MetaData) - event = GrepEvent::GrepPS_SubSyncMetaRef; - else - event = GrepEvent::GrepPS_SubSyncDataRef; - } - break; - case GSN_GREP_START_REQ: - { - jam(); - GrepStartRef * ref = (GrepStartRef*)signal->getDataPtrSend(); - ref->senderData = sub.m_subscriberData; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->part = (Uint32) part; - ref->err = err; - sendSignal(sub.m_coordinatorRef, GSN_GREP_START_REF, signal, - GrepStartRef::SignalLength, JBB); - if(part == SubscriptionData::MetaData) - event = GrepEvent::GrepPS_SubStartMetaRef; - else - event = GrepEvent::GrepPS_SubStartDataRef; - } - break; - - case GSN_GREP_REMOVE_REQ: - { - jamEntry(); - GrepRemoveRef * ref = (GrepRemoveRef*)signal->getDataPtrSend(); - ref->senderData = sub.m_operationPtrI; - ref->subscriptionId = sub.m_subscriptionId; - ref->subscriptionKey = sub.m_subscriptionKey; - ref->err = err; - sendSignal(sub.m_coordinatorRef, GSN_GREP_REMOVE_REF, signal, - GrepCreateRef::SignalLength, JBB); - - } - break; - default: - ndbrequire(false); - event= GrepEvent::Rep_Disconnect; // remove compiler warning - } - - /** - * Finally, send an event. - */ - m_grep->sendEventRep(signal, - EventReport::GrepSubscriptionAlert, - event, - sub.m_subscriptionId, - sub.m_subscriptionKey, - err); - -} - -/************************************************************************** - * ------------------------------------------------------------------------ - * MODULE: GREP PS Coordinator GCP - * ------------------------------------------------------------------------ - * - * - **************************************************************************/ - -void -Grep::PSPart::execSUB_GCP_COMPLETE_REP(Signal* signal) -{ - jamEntry(); - if(m_recoveryMode) { - jam(); - return; - } - SubGcpCompleteRep * rep = (SubGcpCompleteRep *)signal->getDataPtrSend(); - rep->senderRef = reference(); - - if (rep->gci > m_latestSeenGCI) m_latestSeenGCI = rep->gci; - SubscriptionPtr subPtr; - c_subscriptions.first(c_subPtr); - for(; !c_subPtr.isNull(); c_subscriptions.next(c_subPtr)) { - - subPtr.i = c_subPtr.curr.i; - subPtr.p = c_subscriptions.getPtr(subPtr.i); - sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_GCP_COMPLETE_REP, signal, - SubGcpCompleteRep::SignalLength, JBB); - } - -#ifdef DEBUG_GREP - ndbout_c("Grep::PSPart: Recd SUB_GCP_COMPLETE_REP " - "(GCI: %d, nodeId: %d) from SUMA", - rep->gci, refToNode(rep->senderRef)); -#endif -} - - -void -Grep::PSPart::execSUB_SYNC_CONTINUE_REQ(Signal* signal) -{ - jamEntry(); - SubSyncContinueReq * const req = (SubSyncContinueReq*)signal->getDataPtr(); - Uint32 subData = req->subscriberData; - - SubscriptionPtr subPtr; - c_subscriptions.getPtr(subPtr,subData); - - /** - * @todo Figure out how to control how much data we can receive? - */ - SubSyncContinueConf * conf = (SubSyncContinueConf*)req; - conf->subscriptionId = subPtr.p->m_subscriptionId; - conf->subscriptionKey = subPtr.p->m_subscriptionKey; - sendSignal(SUMA_REF, GSN_SUB_SYNC_CONTINUE_CONF, signal, - SubSyncContinueConf::SignalLength, JBB); -} - -void -Grep::sendEventRep(Signal * signal, - EventReport::EventType type, - GrepEvent::Subscription event, - Uint32 subId, - Uint32 subKey, - Uint32 err, - Uint32 other) { - jam(); - signal->theData[0] = type; - signal->theData[1] = event; - signal->theData[2] = subId; - signal->theData[3] = subKey; - signal->theData[4] = err; - - if(other==0) - sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 5 ,JBB); - else { - signal->theData[5] = other; - sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 6 ,JBB); - } -} diff --git a/ndb/src/kernel/blocks/grep/Grep.hpp b/ndb/src/kernel/blocks/grep/Grep.hpp deleted file mode 100644 index 7d3dd916ecc..00000000000 --- a/ndb/src/kernel/blocks/grep/Grep.hpp +++ /dev/null @@ -1,535 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef GREP_HPP -#define GREP_HPP - -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include -#include - - -/** - * Module in block (Should be placed elsewhere) - */ -class BlockComponent { -public: - BlockComponent(SimulatedBlock *); - BlockReference reference() { return m_sb->reference(); }; - BlockNumber number() { return m_sb->number(); }; - - void sendSignal(NodeReceiverGroup rg, - GlobalSignalNumber gsn, - Signal* signal, - Uint32 length, - JobBufferLevel jbuf ) const { - m_sb->sendSignal(rg, gsn, signal, length, jbuf); - } - - void sendSignal(BlockReference ref, - GlobalSignalNumber gsn, - Signal* signal, - Uint32 length, - JobBufferLevel jbuf ) const { - m_sb->sendSignal(ref, gsn, signal, length, jbuf); - } - - void sendSignal(BlockReference ref, - GlobalSignalNumber gsn, - Signal* signal, - Uint32 length, - JobBufferLevel jbuf, - LinearSectionPtr ptr[3], - Uint32 noOfSections) const { - m_sb->sendSignal(ref, gsn, signal, length, jbuf, ptr, noOfSections); - } - - void sendSignalWithDelay(BlockReference ref, - GlobalSignalNumber gsn, - Signal* signal, - Uint32 delayInMilliSeconds, - Uint32 length) const { - - m_sb->sendSignalWithDelay(ref, gsn, signal, delayInMilliSeconds, length); - } - - NodeId getOwnNodeId() const { - return m_sb->getOwnNodeId(); - } - - bool assembleFragments(Signal * signal) { - return m_sb->assembleFragments(signal); - } - - void progError(int line, int err_code, const char* extra) { - m_sb->progError(line, err_code, extra); - } - -private: - SimulatedBlock * m_sb; -}; - - - -/** - * Participant of GREP Protocols (not necessarily a protocol coordinator) - * - * This object is only used on primary system - */ -#if 0 -class GrepParticipant : public SimulatedBlock -{ -protected: - GrepParticipant(const Configuration & conf); - virtual ~GrepParticipant(); - BLOCK_DEFINES(GrepParticipant); - -protected: - /*************************************************************************** - * SUMA Signal Interface - ***************************************************************************/ - void execSUB_CREATE_CONF(Signal*); - void execSUB_STARTCONF(Signal*); - void execSUB_REMOVE_CONF(Signal*); - - void execSUB_META_DATA(Signal*); - void execSUB_TABLE_DATA(Signal*); - - void execSUB_SYNC_CONF(Signal*); - - void execSUB_GCP_COMPLETE_REP(Signal*); - void execSUB_SYNC_CONTINUE_REQ(Signal*); - - /*************************************************************************** - * GREP Coordinator Signal Interface - ***************************************************************************/ - void execGREP_CREATE_REQ(Signal*); - void execGREP_START_REQ(Signal*); - void execGREP_SYNC_REQ(Signal*); - void execGREP_REMOVE_REQ(Signal*); - - -protected: - BlockReference m_repRef; ///< Replication node (only one rep node per grep) - -private: - BlockReference m_coordinator; - Uint32 m_latestSeenGCI; -}; -#endif - - -/** - * GREP Coordinator - */ -class Grep : public SimulatedBlock //GrepParticipant -{ - BLOCK_DEFINES(Grep); - -public: - Grep(const Configuration & conf); - virtual ~Grep(); - -private: - /*************************************************************************** - * General Signal Recivers - ***************************************************************************/ - void execSTTOR(Signal*); - void sendSTTORRY(Signal*); - void execNDB_STTOR(Signal*); - void execDUMP_STATE_ORD(Signal*); - void execREAD_NODESCONF(Signal*); - void execNODE_FAILREP(Signal*); - void execINCL_NODEREQ(Signal*); - void execGREP_REQ(Signal*); - void execAPI_FAILREQ(Signal*); - /** - * Forwarded to PSCoord - */ - //CONF - void fwdGREP_CREATE_CONF(Signal* s) { - pscoord.execGREP_CREATE_CONF(s); }; - void fwdGREP_START_CONF(Signal* s) { - pscoord.execGREP_START_CONF(s); }; - void fwdGREP_SYNC_CONF(Signal* s) { - pscoord.execGREP_SYNC_CONF(s); }; - void fwdGREP_REMOVE_CONF(Signal* s) { - pscoord.execGREP_REMOVE_CONF(s); }; - void fwdCREATE_SUBID_CONF(Signal* s) { - pscoord.execCREATE_SUBID_CONF(s); }; - - //REF - - void fwdGREP_CREATE_REF(Signal* s) { - pscoord.execGREP_CREATE_REF(s); }; - void fwdGREP_START_REF(Signal* s) { - pscoord.execGREP_START_REF(s); }; - void fwdGREP_SYNC_REF(Signal* s) { - pscoord.execGREP_SYNC_REF(s); }; - - void fwdGREP_REMOVE_REF(Signal* s) { - pscoord.execGREP_REMOVE_REF(s); }; - - void fwdCREATE_SUBID_REF(Signal* s) { - pscoord.execCREATE_SUBID_REF(s); }; - - //REQ - void fwdGREP_SUB_CREATE_REQ(Signal* s) { - pscoord.execGREP_SUB_CREATE_REQ(s); }; - void fwdGREP_SUB_START_REQ(Signal* s) { - pscoord.execGREP_SUB_START_REQ(s); }; - void fwdGREP_SUB_SYNC_REQ(Signal* s) { - pscoord.execGREP_SUB_SYNC_REQ(s); }; - void fwdGREP_SUB_REMOVE_REQ(Signal* s) { - pscoord.execGREP_SUB_REMOVE_REQ(s); }; - void fwdGREP_CREATE_SUBID_REQ(Signal* s) { - pscoord.execGREP_CREATE_SUBID_REQ(s); }; - - /** - * Forwarded to PSPart - */ - - void fwdSTART_ME(Signal* s){ - pspart.execSTART_ME(s); - }; - void fwdGREP_ADD_SUB_REQ(Signal* s){ - pspart.execGREP_ADD_SUB_REQ(s); - }; - void fwdGREP_ADD_SUB_REF(Signal* s){ - pspart.execGREP_ADD_SUB_REF(s); - }; - void fwdGREP_ADD_SUB_CONF(Signal* s){ - pspart.execGREP_ADD_SUB_CONF(s); - }; - - //CONF - void fwdSUB_CREATE_CONF(Signal* s) { - pspart.execSUB_CREATE_CONF(s); }; - void fwdSUB_START_CONF(Signal* s) { - pspart.execSUB_START_CONF(s); }; - void fwdSUB_REMOVE_CONF(Signal* s) { - pspart.execSUB_REMOVE_CONF(s); }; - void fwdSUB_SYNC_CONF(Signal* s) { - pspart.execSUB_SYNC_CONF(s); }; - - //REF - - void fwdSUB_CREATE_REF(Signal* s) { - pspart.execSUB_CREATE_REF(s); }; - void fwdSUB_START_REF(Signal* s) { - pspart.execSUB_START_REF(s); }; - void fwdSUB_REMOVE_REF(Signal* s) { - pspart.execSUB_REMOVE_REF(s); }; - void fwdSUB_SYNC_REF(Signal* s) { - pspart.execSUB_SYNC_REF(s); }; - - //REQ - void fwdSUB_SYNC_CONTINUE_REQ(Signal* s) { - pspart.execSUB_SYNC_CONTINUE_REQ(s); }; - void fwdGREP_CREATE_REQ(Signal* s) { - pspart.execGREP_CREATE_REQ(s); }; - void fwdGREP_START_REQ(Signal* s) { - pspart.execGREP_START_REQ(s); }; - void fwdGREP_SYNC_REQ(Signal* s) { - pspart.execGREP_SYNC_REQ(s); }; - void fwdGREP_REMOVE_REQ(Signal* s) { - pspart.execGREP_REMOVE_REQ(s); }; - - void fwdSUB_META_DATA(Signal* s) { - pspart.execSUB_META_DATA(s); }; - void fwdSUB_TABLE_DATA(Signal* s) { - pspart.execSUB_TABLE_DATA(s); }; - - void fwdSUB_GCP_COMPLETE_REP(Signal* s) { - pspart.execSUB_GCP_COMPLETE_REP(s); }; - - void sendEventRep(Signal * signal, - EventReport::EventType type, - GrepEvent::Subscription event, - Uint32 subId, - Uint32 subKey, - Uint32 err, - Uint32 gci=0); - - void getNodeGroupMembers(Signal* signal); - - - /*************************************************************************** - * Block Data - ***************************************************************************/ - struct Node { - Uint32 nodeId; - Uint32 alive; - Uint32 nextList; - union { Uint32 prevList; Uint32 nextPool; }; - }; - typedef Ptr NodePtr; - - NodeId m_masterNodeId; - SLList m_nodes; - NdbNodeBitmask m_aliveNodes; - ArrayPool m_nodePool; - - /** - * for all Suma's to keep track of other Suma's in Node group - */ - Uint32 c_nodeGroup; - Uint32 c_noNodesInGroup; - Uint32 c_idInNodeGroup; - NodeId c_nodesInGroup[4]; - - -public: - /*************************************************************************** - * GREP PS Coordinator - ***************************************************************************/ - class PSCoord : public BlockComponent { - - private: - - struct SubCoordinator { - Uint32 m_subscriberRef; - Uint32 m_subscriberData; - Uint32 m_coordinatorRef; - Uint32 m_subscriptionId; - Uint32 m_subscriptionKey; - Uint32 m_subscriptionType; - NdbNodeBitmask m_participants; - Uint32 m_outstandingRequest; - SignalCounter m_outstandingParticipants; - - Uint32 nextHash; - union { Uint32 prevHash; Uint32 nextPool; }; - - Uint32 hashValue() const { - return m_subscriptionId + m_subscriptionKey; - } - - bool equal(const SubCoordinator & s) const { - return - m_subscriptionId == s.m_subscriptionId && - m_subscriptionKey == s.m_subscriptionKey; - } - - }; - - typedef Ptr SubCoordinatorPtr; - ArrayPool c_subCoordinatorPool; - DLHashTable::Iterator c_subPtr; - DLHashTable c_runningSubscriptions; - - void prepareOperationRec(SubCoordinatorPtr ptr, - BlockReference subscriber, - Uint32 subId, - Uint32 subKey, - Uint32 request); - - public: - PSCoord(class Grep *); - - void execGREP_CREATE_CONF(Signal*); - void execGREP_START_CONF(Signal*); - void execGREP_SYNC_CONF(Signal*); - void execGREP_REMOVE_CONF(Signal*); - - void execGREP_CREATE_REF(Signal*); - void execGREP_START_REF(Signal*); - void execGREP_SYNC_REF(Signal*); - void execGREP_REMOVE_REF(Signal*); - - - void execCREATE_SUBID_CONF(Signal*); //comes from SUMA - void execGREP_CREATE_SUBID_REQ(Signal*); - - void execGREP_SUB_CREATE_REQ(Signal*); - void execGREP_SUB_START_REQ(Signal*); - void execGREP_SUB_SYNC_REQ(Signal*); - void execGREP_SUB_REMOVE_REQ(Signal*); - - - - void execCREATE_SUBID_REF(Signal*); - - - - void sendCreateSubIdRef_SS(Signal * signal, - Uint32 subId, - Uint32 subKey, - BlockReference to, - GrepError::GE_Code err); - - - void sendSubRemoveRef_SS(Signal * signal, - SubCoordinator sub, - GrepError::GE_Code err); - - void sendRefToSS(Signal * signal, - SubCoordinator sub, - GrepError::GE_Code err, - SubscriptionData::Part part = (SubscriptionData::Part)0); - - void setRepRef(BlockReference rr) { m_repRef = rr; }; - //void setAliveNodes(NdbNodeBitmask an) { m_aliveNodes = an; }; - - BlockReference m_repRef; ///< Rep node (only one rep node per grep) - // NdbNodeBitmask m_aliveNodes; - - Uint32 m_outstandingRequest; - SignalCounter m_outstandingParticipants; - - Grep * m_grep; - } pscoord; - friend class PSCoord; - - /*************************************************************************** - * GREP PS Participant - *************************************************************************** - * Participant of GREP Protocols (not necessarily a protocol coordinator) - * - * This object is only used on primary system - ***************************************************************************/ - class PSPart: public BlockComponent - { - //protected: - //GrepParticipant(const Configuration & conf); - //virtual ~GrepParticipant(); - //BLOCK_DEFINES(GrepParticipant); - - struct Subscription { - Uint32 m_subscriberRef; - Uint32 m_subscriberData; - Uint32 m_subscriptionId; - Uint32 m_subscriptionKey; - Uint32 m_subscriptionType; - Uint32 m_coordinatorRef; - Uint32 m_outstandingRequest; - Uint32 m_operationPtrI; - Uint32 nextHash; - union { Uint32 prevHash; Uint32 nextPool; }; - - Uint32 hashValue() const { - return m_subscriptionId + m_subscriptionKey; - } - - bool equal(const Subscription & s) const { - return - m_subscriptionId == s.m_subscriptionId && - m_subscriptionKey == s.m_subscriptionKey; - } - - }; - typedef Ptr SubscriptionPtr; - - DLHashTable c_subscriptions; - DLHashTable::Iterator c_subPtr; - ArrayPool c_subscriptionPool; - - public: - PSPart(class Grep *); - - - //protected: - /************************************************************************* - * SUMA Signal Interface - *************************************************************************/ - void execSUB_CREATE_CONF(Signal*); - void execSUB_START_CONF(Signal*); - void execSUB_SYNC_CONF(Signal*); - void execSUB_REMOVE_CONF(Signal*); - - void execSUB_CREATE_REF(Signal*); - void execSUB_START_REF(Signal*); - void execSUB_SYNC_REF(Signal*); - void execSUB_REMOVE_REF(Signal*); - - - void execSUB_META_DATA(Signal*); - void execSUB_TABLE_DATA(Signal*); - - - void execSUB_GCP_COMPLETE_REP(Signal*); - void execSUB_SYNC_CONTINUE_REQ(Signal*); - - /************************************************************************* - * GREP Coordinator Signal Interface - *************************************************************************/ - void execGREP_CREATE_REQ(Signal*); - void execGREP_START_REQ(Signal*); - void execGREP_SYNC_REQ(Signal*); - void execGREP_REMOVE_REQ(Signal*); - - /** - * NR/NF signals - */ - void execSTART_ME(Signal *); - void execGREP_ADD_SUB_REQ(Signal *); - void execGREP_ADD_SUB_REF(Signal *); - void execGREP_ADD_SUB_CONF(Signal *); - - /************************************************************************* - * GREP Coordinator error handling interface - *************************************************************************/ - - void sendRefToPSCoord(Signal * signal, - Subscription sub, - GrepError::GE_Code err, - SubscriptionData::Part part = (SubscriptionData::Part)0); - - //protected: - BlockReference m_repRef; ///< Replication node - ///< (only one rep node per grep) - bool m_recoveryMode; - - private: - BlockReference m_coordinator; - Uint32 m_firstScanGCI; - Uint32 m_lastScanGCI; - Uint32 m_latestSeenGCI; - Grep * m_grep; - } pspart; - friend class PSPart; - - /*************************************************************************** - * AddRecSignal Stuff (should maybe be gerneralized) - ***************************************************************************/ - typedef void (Grep::* ExecSignalLocal1) (Signal* signal); - typedef void (Grep::PSCoord::* ExecSignalLocal2) (Signal* signal); - typedef void (Grep::PSPart::* ExecSignalLocal4) (Signal* signal); -}; - - -/************************************************************************* - * Requestor - * - * The following methods are callbacks (registered functions) - * for the Requestor. The Requestor calls these when it needs - * something to be done. - *************************************************************************/ -void startSubscription(void * cbObj, Signal*, int type); -void scanSubscription(void * cbObj, Signal*, int type); - -#endif diff --git a/ndb/src/kernel/blocks/grep/GrepInit.cpp b/ndb/src/kernel/blocks/grep/GrepInit.cpp deleted file mode 100644 index d764fb1f473..00000000000 --- a/ndb/src/kernel/blocks/grep/GrepInit.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "Grep.hpp" -#include -#include - -/***************************************************************************** - * Grep Participant - *****************************************************************************/ -#if 0 -GrepParticipant::GrepParticipant(const Configuration & conf) : - SimulatedBlock(GREP, conf) -{ - BLOCK_CONSTRUCTOR(Grep); - //m_repRef = 0; - m_latestSeenGCI = 0; -} - -GrepParticipant::~GrepParticipant() -{ -} - -BLOCK_FUNCTIONS(GrepParticipant); -#endif - -/***************************************************************************** - * Grep Coordinator - *****************************************************************************/ -Grep::Grep(const Configuration & conf) : - // GrepParticipant(conf), - SimulatedBlock(GREP, conf), - m_nodes(m_nodePool), - pscoord(this), - pspart(this) -{ - m_nodePool.setSize(MAX_NDB_NODES); - m_masterNodeId = getOwnNodeId(); - - /*************************************************************************** - * General Signals - ***************************************************************************/ - addRecSignal(GSN_STTOR, &Grep::execSTTOR); - addRecSignal(GSN_NDB_STTOR, &Grep::execNDB_STTOR); - addRecSignal(GSN_DUMP_STATE_ORD, &Grep::execDUMP_STATE_ORD); - addRecSignal(GSN_READ_NODESCONF, &Grep::execREAD_NODESCONF); - addRecSignal(GSN_NODE_FAILREP, &Grep::execNODE_FAILREP); - addRecSignal(GSN_INCL_NODEREQ, &Grep::execINCL_NODEREQ); - - addRecSignal(GSN_GREP_REQ, &Grep::execGREP_REQ); - addRecSignal(GSN_API_FAILREQ, &Grep::execAPI_FAILREQ); - - - /*************************************************************************** - * Grep::PSCoord Signal Interface - ***************************************************************************/ - /** - * From Grep::PSPart - */ - addRecSignal(GSN_GREP_CREATE_CONF, &Grep::fwdGREP_CREATE_CONF); - addRecSignal(GSN_GREP_START_CONF, &Grep::fwdGREP_START_CONF); - addRecSignal(GSN_GREP_SYNC_CONF, &Grep::fwdGREP_SYNC_CONF); - addRecSignal(GSN_GREP_REMOVE_CONF, &Grep::fwdGREP_REMOVE_CONF); - - addRecSignal(GSN_GREP_CREATE_REF, &Grep::fwdGREP_CREATE_REF); - addRecSignal(GSN_GREP_START_REF, &Grep::fwdGREP_START_REF); - addRecSignal(GSN_GREP_REMOVE_REF, &Grep::fwdGREP_REMOVE_REF); - - /** - * From Grep::SSCoord to Grep::PSCoord - */ - addRecSignal(GSN_GREP_SUB_START_REQ, &Grep::fwdGREP_SUB_START_REQ); - addRecSignal(GSN_GREP_SUB_CREATE_REQ, &Grep::fwdGREP_SUB_CREATE_REQ); - addRecSignal(GSN_GREP_SUB_SYNC_REQ, &Grep::fwdGREP_SUB_SYNC_REQ); - addRecSignal(GSN_GREP_SUB_REMOVE_REQ, &Grep::fwdGREP_SUB_REMOVE_REQ); - addRecSignal(GSN_GREP_CREATE_SUBID_REQ, &Grep::fwdGREP_CREATE_SUBID_REQ); - - /**************************************************************************** - * PSPart - ***************************************************************************/ - /** - * From SUMA to GREP PS Participant. If suma is not a coodinator - */ - addRecSignal(GSN_SUB_START_CONF, &Grep::fwdSUB_START_CONF); - addRecSignal(GSN_SUB_CREATE_CONF, &Grep::fwdSUB_CREATE_CONF); - addRecSignal(GSN_SUB_SYNC_CONF, &Grep::fwdSUB_SYNC_CONF); - addRecSignal(GSN_SUB_REMOVE_CONF, &Grep::fwdSUB_REMOVE_CONF); - addRecSignal(GSN_SUB_CREATE_REF, &Grep::fwdSUB_CREATE_REF); - addRecSignal(GSN_SUB_START_REF, &Grep::fwdSUB_START_REF); - addRecSignal(GSN_SUB_SYNC_REF, &Grep::fwdSUB_SYNC_REF); - addRecSignal(GSN_SUB_REMOVE_REF, &Grep::fwdSUB_REMOVE_REF); - - addRecSignal(GSN_SUB_SYNC_CONTINUE_REQ, - &Grep::fwdSUB_SYNC_CONTINUE_REQ); - - /** - * From Suma to Grep::PSPart. Data signals. - */ - addRecSignal(GSN_SUB_META_DATA, &Grep::fwdSUB_META_DATA); - addRecSignal(GSN_SUB_TABLE_DATA, &Grep::fwdSUB_TABLE_DATA); - addRecSignal(GSN_SUB_GCP_COMPLETE_REP, &Grep::fwdSUB_GCP_COMPLETE_REP); - - /** - * From Grep::PSCoord to Grep::PSPart - */ - addRecSignal(GSN_GREP_CREATE_REQ, &Grep::fwdGREP_CREATE_REQ); - addRecSignal(GSN_GREP_START_REQ, &Grep::fwdGREP_START_REQ); - addRecSignal(GSN_GREP_REMOVE_REQ, &Grep::fwdGREP_REMOVE_REQ); - addRecSignal(GSN_GREP_SYNC_REQ, &Grep::fwdGREP_SYNC_REQ); - addRecSignal(GSN_CREATE_SUBID_CONF, &Grep::fwdCREATE_SUBID_CONF); - addRecSignal(GSN_GREP_START_ME, &Grep::fwdSTART_ME); - addRecSignal(GSN_GREP_ADD_SUB_REQ, &Grep::fwdGREP_ADD_SUB_REQ); - addRecSignal(GSN_GREP_ADD_SUB_REF, &Grep::fwdGREP_ADD_SUB_REF); - addRecSignal(GSN_GREP_ADD_SUB_CONF, &Grep::fwdGREP_ADD_SUB_CONF); -} - -Grep::~Grep() -{ -} - -BLOCK_FUNCTIONS(Grep) - -Grep::PSPart::PSPart(Grep * sb) : - BlockComponent(sb), - c_subscriptions(c_subscriptionPool) -{ - m_grep = sb; - - m_firstScanGCI = 1; // Empty interval = [1,0] - m_lastScanGCI = 0; - - m_latestSeenGCI = 0; - - c_subscriptions.setSize(10); - c_subscriptionPool.setSize(10); -} - -Grep::PSCoord::PSCoord(Grep * sb) : - BlockComponent(sb), - c_runningSubscriptions(c_subCoordinatorPool) -{ - m_grep = sb; - c_runningSubscriptions.setSize(10); - c_subCoordinatorPool.setSize(2); -} - -//BLOCK_FUNCTIONS(Grep::PSCoord); - -BlockComponent::BlockComponent(SimulatedBlock * sb) { - m_sb = sb; -} diff --git a/ndb/src/kernel/blocks/grep/Makefile.am b/ndb/src/kernel/blocks/grep/Makefile.am deleted file mode 100644 index 6d2b422784b..00000000000 --- a/ndb/src/kernel/blocks/grep/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -noinst_LIBRARIES = libgrep.a - -libgrep_a_SOURCES = Grep.cpp GrepInit.cpp - -include $(top_srcdir)/ndb/config/common.mk.am -include $(top_srcdir)/ndb/config/type_kernel.mk.am - -# Don't update the files from bitkeeper -%::SCCS/s.% - -windoze-dsp: libgrep.dsp - -libgrep.dsp: Makefile \ - $(top_srcdir)/ndb/config/win-lib.am \ - $(top_srcdir)/ndb/config/win-name \ - $(top_srcdir)/ndb/config/win-includes \ - $(top_srcdir)/ndb/config/win-sources \ - $(top_srcdir)/ndb/config/win-libraries - cat $(top_srcdir)/ndb/config/win-lib.am > $@ - @$(top_srcdir)/ndb/config/win-name $@ $(noinst_LIBRARIES) - @$(top_srcdir)/ndb/config/win-includes $@ $(INCLUDES) - @$(top_srcdir)/ndb/config/win-sources $@ $(libgrep_a_SOURCES) - @$(top_srcdir)/ndb/config/win-libraries $@ LIB $(LDADD) diff --git a/ndb/src/kernel/blocks/grep/systab_test/Makefile b/ndb/src/kernel/blocks/grep/systab_test/Makefile deleted file mode 100644 index bd69e0f3799..00000000000 --- a/ndb/src/kernel/blocks/grep/systab_test/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include .defs.mk - -TYPE := kernel - -BIN_TARGET := grep_systab_test -BIN_TARGET_ARCHIVES := portlib general - -CCFLAGS_LOC += -I.. - -SOURCES = ../GrepSystemTable.cpp grep_systab_test.cpp - -include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp b/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp deleted file mode 100644 index e3a77af4e4e..00000000000 --- a/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/** - * Unit Test for GrepSystemTable - */ - -#include "../GrepSystemTable.hpp" -#include - -#define EXEC(X) ( ndbout << endl, ndbout_c(#X), X ) - -int -main () { - GrepSystemTable st; - - Uint32 f, l; - - ndbout_c("*************************************"); - ndbout_c("* GrepSystemTable Unit Test Program *"); - ndbout_c("*************************************"); - - ndbout_c("--------------------------------------------------------"); - ndbout_c("Test 1: Clear"); - ndbout_c("--------------------------------------------------------"); - - EXEC(st.set(GrepSystemTable::PS, 22, 26)); - st.print(); - st.require(GrepSystemTable::PS, 22, 26); - - EXEC(st.clear(GrepSystemTable::PS, 20, 24)); - st.print(); - st.require(GrepSystemTable::PS, 25, 26); - - EXEC(st.clear(GrepSystemTable::PS, 0, 100)); - st.print(); - st.require(GrepSystemTable::PS, 1, 0); - - EXEC(st.set(GrepSystemTable::PS, 22, 26)); - st.print(); - st.require(GrepSystemTable::PS, 22, 26); - - EXEC(st.clear(GrepSystemTable::PS, 24, 28)); - st.print(); - st.require(GrepSystemTable::PS, 22, 23); - - EXEC(st.clear(GrepSystemTable::PS, 0, 100)); - st.print(); - st.require(GrepSystemTable::PS, 1, 0); - - EXEC(st.set(GrepSystemTable::PS, 22, 26)); - st.print(); - st.require(GrepSystemTable::PS, 22, 26); - - EXEC(st.clear(GrepSystemTable::PS, 24, 26)); - st.print(); - st.require(GrepSystemTable::PS, 22, 23); - - EXEC(st.clear(GrepSystemTable::PS, 0, 100)); - st.print(); - st.require(GrepSystemTable::PS, 1, 0); - - EXEC(st.set(GrepSystemTable::PS, 22, 26)); - st.print(); - st.require(GrepSystemTable::PS, 22, 26); - - EXEC(st.clear(GrepSystemTable::PS, 22, 24)); - st.print(); - st.require(GrepSystemTable::PS, 25, 26); - - ndbout_c("--------------------------------------------------------"); - ndbout_c("Test 2: PS --> SSreq"); - ndbout_c("--------------------------------------------------------"); - - EXEC(st.set(GrepSystemTable::PS, 22, 26)); - st.print(); - st.require(GrepSystemTable::PS, 22, 26); - st.require(GrepSystemTable::SSReq, 1, 0); - - if (!EXEC(st.copy(GrepSystemTable::PS, GrepSystemTable::SSReq, 3, &f, &l))) - ndbout_c("%s:%d: Illegal copy!", __FILE__, __FILE__); - ndbout_c("f=%d, l=%d", f, l); - st.print(); - st.require(GrepSystemTable::PS, 22, 26); - st.require(GrepSystemTable::SSReq, 22, 24); - - EXEC(st.clear(GrepSystemTable::PS, 22, 22)); - st.print(); - st.require(GrepSystemTable::PS, 23, 26); - st.require(GrepSystemTable::SSReq, 22, 24); - - if (!EXEC(st.copy(GrepSystemTable::PS, GrepSystemTable::SSReq, 2, &f, &l))) - ndbout_c("%s:%d: Illegal copy!", __FILE__, __LINE__); - ndbout_c("f=%d, l=%d", f, l); - st.print(); - st.require(GrepSystemTable::PS, 23, 26); - st.require(GrepSystemTable::SSReq, 22, 26); - - st.set(GrepSystemTable::SS, 7, 9); - st.set(GrepSystemTable::InsReq, 7, 9); - if (EXEC(st.movable(GrepSystemTable::SS, GrepSystemTable::InsReq))) - ndbout_c("%s:%d: Illegal move!", __FILE__, __LINE__); - st.print(); - st.require(GrepSystemTable::SS, 7, 9); - st.require(GrepSystemTable::InsReq, 7, 9); - - EXEC(st.intervalMinus(7, 9, 7, 7, &f, &l)); - ndbout_c("f=%d, l=%d", f, l); - - st.clear(GrepSystemTable::InsReq, 8, 9); - st.require(GrepSystemTable::SS, 7, 9); - st.require(GrepSystemTable::InsReq, 7, 7); - if (EXEC(st.movable(GrepSystemTable::SS, GrepSystemTable::InsReq)) != 2) - ndbout_c("%s:%d: Illegal move!", __FILE__, __LINE__); - st.print(); - - EXEC(st.copy(GrepSystemTable::SS, GrepSystemTable::InsReq, &f)); - st.print(); - st.require(GrepSystemTable::SS, 7, 9); - st.require(GrepSystemTable::InsReq, 7, 8); - - ndbout_c("--------------------------------------------------------"); - ndbout_c("Test completed"); - ndbout_c("--------------------------------------------------------"); -} diff --git a/ndb/test/ndbapi/testGrep.cpp b/ndb/test/ndbapi/testGrep.cpp deleted file mode 100644 index 713aefbeafa..00000000000 --- a/ndb/test/ndbapi/testGrep.cpp +++ /dev/null @@ -1,540 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include -#include -#include - - -#define CHECK(b) if (!(b)) { \ - g_err << "ERR: "<< step->getName() \ - << " failed on line " << __LINE__ << endl; \ - result = NDBT_FAILED; \ - continue; } - - -int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ - - int records = ctx->getNumRecords(); - HugoTransactions hugoTrans(*ctx->getTab()); - if (hugoTrans.loadTable(GETNDB(step), records) != 0){ - return NDBT_FAILED; - } - return NDBT_OK; -} - -int runPkUpdate(NDBT_Context* ctx, NDBT_Step* step){ - int loops = ctx->getNumLoops(); - int records = ctx->getNumRecords(); - int batchSize = ctx->getProperty("BatchSize", 1); - int i = 0; - HugoTransactions hugoTrans(*ctx->getTab()); - while (igetTab(); - pNdb->getDictionary()->dropTable(tab->getName()); - - if (restarter.restartAll(true) != 0) - return NDBT_FAILED; - - return NDBT_OK; -} - -int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ - int result = NDBT_OK; - int loops = ctx->getNumLoops(); - NdbRestarter restarter; - int i = 0; - int lastId = 0; - - if (restarter.getNumDbNodes() < 2){ - ctx->stopTest(); - return NDBT_OK; - } - - if(restarter.waitClusterStarted(60) != 0){ - g_err << "Cluster failed to start" << endl; - return NDBT_FAILED; - } - - loops *= restarter.getNumDbNodes(); - while(iisTestStopped()){ - - int id = lastId % restarter.getNumDbNodes(); - int nodeId = restarter.getDbNodeId(id); - ndbout << "Restart node " << nodeId << endl; - if(restarter.restartOneDbNode(nodeId) != 0){ - g_err << "Failed to restartNextDbNode" << endl; - result = NDBT_FAILED; - break; - } - - if(restarter.waitClusterStarted(60) != 0){ - g_err << "Cluster failed to start" << endl; - result = NDBT_FAILED; - break; - } - - NdbSleep_SecSleep(1); - - lastId++; - i++; - } - - ctx->stopTest(); - - return result; -} - -int runCheckAllNodesStarted(NDBT_Context* ctx, NDBT_Step* step){ - NdbRestarter restarter; - - if(restarter.waitClusterStarted(1) != 0){ - g_err << "All nodes was not started " << endl; - return NDBT_FAILED; - } - - return NDBT_OK; -} - - -bool testMaster = true; -bool testSlave = false; - -int setMaster(NDBT_Context* ctx, NDBT_Step* step){ - testMaster = true; - testSlave = false; - return NDBT_OK; -} -int setMasterAsSlave(NDBT_Context* ctx, NDBT_Step* step){ - testMaster = true; - testSlave = true; - return NDBT_OK; -} -int setSlave(NDBT_Context* ctx, NDBT_Step* step){ - testMaster = false; - testSlave = true; - return NDBT_OK; -} - -int runAbort(NDBT_Context* ctx, NDBT_Step* step){ - - - NdbGrep grep(GETNDB(step)->getNodeId()+1); - NdbRestarter restarter; - - if (restarter.getNumDbNodes() < 2){ - ctx->stopTest(); - return NDBT_OK; - } - - if(restarter.waitClusterStarted(60) != 0){ - g_err << "Cluster failed to start" << endl; - return NDBT_FAILED; - } - - if (testMaster) { - if (testSlave) { - if (grep.NFMasterAsSlave(restarter) == -1){ - return NDBT_FAILED; - } - } else { - if (grep.NFMaster(restarter) == -1){ - return NDBT_FAILED; - } - } - } else { - if (grep.NFSlave(restarter) == -1){ - return NDBT_FAILED; - } - } - - return NDBT_OK; -} - -int runFail(NDBT_Context* ctx, NDBT_Step* step){ - NdbGrep grep(GETNDB(step)->getNodeId()+1); - - NdbRestarter restarter; - - if (restarter.getNumDbNodes() < 2){ - ctx->stopTest(); - return NDBT_OK; - } - - if(restarter.waitClusterStarted(60) != 0){ - g_err << "Cluster failed to start" << endl; - return NDBT_FAILED; - } - - if (testMaster) { - if (testSlave) { - if (grep.FailMasterAsSlave(restarter) == -1){ - return NDBT_FAILED; - } - } else { - if (grep.FailMaster(restarter) == -1){ - return NDBT_FAILED; - } - } - } else { - if (grep.FailSlave(restarter) == -1){ - return NDBT_FAILED; - } - } - - return NDBT_OK; -} - -int runGrepBasic(NDBT_Context* ctx, NDBT_Step* step){ - NdbGrep grep(GETNDB(step)->getNodeId()+1); - unsigned grepId = 0; - - if (grep.start() == -1){ - return NDBT_FAILED; - } - ndbout << "Started grep " << grepId << endl; - ctx->setProperty("GrepId", grepId); - - return NDBT_OK; -} - - - - -int runVerifyBasic(NDBT_Context* ctx, NDBT_Step* step){ - NdbGrep grep(GETNDB(step)->getNodeId()+1, ctx->getRemoteMgm()); - ndbout_c("no of nodes %d" ,grep.getNumDbNodes()); - int result; - if ((result = grep.verify(ctx)) == -1){ - return NDBT_FAILED; - } - return result; -} - - - -int runClearTable(NDBT_Context* ctx, NDBT_Step* step){ - int records = ctx->getNumRecords(); - - UtilTransactions utilTrans(*ctx->getTab()); - if (utilTrans.clearTable2(GETNDB(step), records) != 0){ - return NDBT_FAILED; - } - return NDBT_OK; -} - -#include "bank/Bank.hpp" - -int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){ - Bank bank; - int overWriteExisting = true; - if (bank.createAndLoadBank(overWriteExisting) != NDBT_OK) - return NDBT_FAILED; - return NDBT_OK; -} - -int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){ - Bank bank; - int wait = 30; // Max seconds between each "day" - int yield = 1; // Loops before bank returns - - while (ctx->isTestStopped() == false) { - bank.performIncreaseTime(wait, yield); - } - return NDBT_OK; -} - -int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){ - Bank bank; - int wait = 10; // Max ms between each transaction - int yield = 100; // Loops before bank returns - - while (ctx->isTestStopped() == false) { - bank.performTransactions(wait, yield); - } - return NDBT_OK; -} - -int runBankGL(NDBT_Context* ctx, NDBT_Step* step){ - Bank bank; - int yield = 20; // Loops before bank returns - int result = NDBT_OK; - - while (ctx->isTestStopped() == false) { - if (bank.performMakeGLs(yield) != NDBT_OK){ - ndbout << "bank.performMakeGLs FAILED" << endl; - result = NDBT_FAILED; - } - } - return NDBT_OK; -} - -int runBankSum(NDBT_Context* ctx, NDBT_Step* step){ - Bank bank; - int wait = 2000; // Max ms between each sum of accounts - int yield = 1; // Loops before bank returns - int result = NDBT_OK; - - while (ctx->isTestStopped() == false) { - if (bank.performSumAccounts(wait, yield) != NDBT_OK){ - ndbout << "bank.performSumAccounts FAILED" << endl; - result = NDBT_FAILED; - } - } - return result ; -} - -int runDropBank(NDBT_Context* ctx, NDBT_Step* step){ - Bank bank; - if (bank.dropBank() != NDBT_OK) - return NDBT_FAILED; - return NDBT_OK; -} - -int runGrepBank(NDBT_Context* ctx, NDBT_Step* step){ - int loops = ctx->getNumLoops(); - int l = 0; - int maxSleep = 30; // Max seconds between each grep - Ndb* pNdb = GETNDB(step); - NdbGrep grep(GETNDB(step)->getNodeId()+1); - unsigned minGrepId = ~0; - unsigned maxGrepId = 0; - unsigned grepId = 0; - int result = NDBT_OK; - - while (l < loops && result != NDBT_FAILED){ - - if (pNdb->waitUntilReady() != 0){ - result = NDBT_FAILED; - continue; - } - - // Sleep for a while - NdbSleep_SecSleep(maxSleep); - - // Perform grep - if (grep.start() != 0){ - ndbout << "grep.start failed" << endl; - result = NDBT_FAILED; - continue; - } - ndbout << "Started grep " << grepId << endl; - - // Remember min and max grepid - if (grepId < minGrepId) - minGrepId = grepId; - - if (grepId > maxGrepId) - maxGrepId = grepId; - - ndbout << " maxGrepId = " << maxGrepId - << ", minGrepId = " << minGrepId << endl; - ctx->setProperty("MinGrepId", minGrepId); - ctx->setProperty("MaxGrepId", maxGrepId); - - l++; - } - - ctx->stopTest(); - - return result; -} -/* -int runRestoreBankAndVerify(NDBT_Context* ctx, NDBT_Step* step){ - NdbRestarter restarter; - NdbGrep grep(GETNDB(step)->getNodeId()+1); - unsigned minGrepId = ctx->getProperty("MinGrepId"); - unsigned maxGrepId = ctx->getProperty("MaxGrepId"); - unsigned grepId = minGrepId; - int result = NDBT_OK; - int errSumAccounts = 0; - int errValidateGL = 0; - - ndbout << " maxGrepId = " << maxGrepId << endl; - ndbout << " minGrepId = " << minGrepId << endl; - - while (grepId <= maxGrepId){ - - // TEMPORARY FIX - // To erase all tables from cache(s) - // To be removed, maybe replaced by ndb.invalidate(); - { - Bank bank; - - if (bank.dropBank() != NDBT_OK){ - result = NDBT_FAILED; - break; - } - } - // END TEMPORARY FIX - - ndbout << "Performing initial restart" << endl; - if (restarter.restartAll(true) != 0) - return NDBT_FAILED; - - if (restarter.waitClusterStarted() != 0) - return NDBT_FAILED; - - ndbout << "Restoring grep " << grepId << endl; - if (grep.restore(grepId) == -1){ - return NDBT_FAILED; - } - ndbout << "Grep " << grepId << " restored" << endl; - - // Let bank verify - Bank bank; - - int wait = 0; - int yield = 1; - if (bank.performSumAccounts(wait, yield) != 0){ - ndbout << "bank.performSumAccounts FAILED" << endl; - ndbout << " grepId = " << grepId << endl << endl; - result = NDBT_FAILED; - errSumAccounts++; - } - - if (bank.performValidateAllGLs() != 0){ - ndbout << "bank.performValidateAllGLs FAILED" << endl; - ndbout << " grepId = " << grepId << endl << endl; - result = NDBT_FAILED; - errValidateGL++; - } - - grepId++; - } - - if (result != NDBT_OK){ - ndbout << "Verification of grep failed" << endl - << " errValidateGL="< Date: Tue, 23 Aug 2005 13:01:46 +0200 Subject: [PATCH 205/230] configure.in: fixed build bug with ndb grep block --- configure.in | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.in b/configure.in index ffd6fc3f483..4aef78e5b18 100644 --- a/configure.in +++ b/configure.in @@ -2755,7 +2755,6 @@ AC_CONFIG_FILES(ndb/Makefile ndb/include/Makefile dnl ndb/src/kernel/blocks/backup/Makefile dnl ndb/src/kernel/blocks/dbutil/Makefile dnl ndb/src/kernel/blocks/suma/Makefile dnl - ndb/src/kernel/blocks/grep/Makefile dnl ndb/src/kernel/blocks/dbtux/Makefile dnl ndb/src/kernel/vm/Makefile dnl ndb/src/mgmapi/Makefile dnl From 398392cdcc9f4ec801651ee2f371266edafe1e10 Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Tue, 23 Aug 2005 13:57:12 +0200 Subject: [PATCH 206/230] tests fixes --- mysql-test/lib/init_db.sql | 2 +- mysql-test/r/rpl_delete_all.result | 2 +- mysql-test/t/rpl_delete_all.test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index a71de229ee9..37353e5974f 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -518,7 +518,7 @@ CREATE TABLE proc ( security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob DEFAULT '' NOT NULL, returns char(64) DEFAULT '' NOT NULL, - body blob DEFAULT '' NOT NULL, + body longblob DEFAULT '' NOT NULL, definer char(77) collate utf8_bin DEFAULT '' NOT NULL, created timestamp, modified timestamp, diff --git a/mysql-test/r/rpl_delete_all.result b/mysql-test/r/rpl_delete_all.result index 5ed221823e8..1aa556270c9 100644 --- a/mysql-test/r/rpl_delete_all.result +++ b/mysql-test/r/rpl_delete_all.result @@ -9,7 +9,7 @@ drop database if exists mysqltest; Warnings: Note 1008 Can't drop database 'mysqltest'; database doesn't exist show tables from mysqltest; -ERROR HY000: Can't read dir of './mysqltest/' (Errcode: X) +ERROR 42000: Unknown database 'mysqltest' create table t1 (a int); drop table if exists t1; Warnings: diff --git a/mysql-test/t/rpl_delete_all.test b/mysql-test/t/rpl_delete_all.test index db33ee3bb86..e0c0757bbc2 100644 --- a/mysql-test/t/rpl_delete_all.test +++ b/mysql-test/t/rpl_delete_all.test @@ -7,7 +7,7 @@ drop database if exists mysqltest; sync_slave_with_master; # can't read dir --replace_result "Errcode: 1" "Errcode: X" "Errcode: 2" "Errcode: X" \\ / ---error 12 +--error 1049 show tables from mysqltest; connection slave; From e0403003933fcc5fdecac5d6f8c1bce995d4ca54 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Tue, 23 Aug 2005 18:08:04 +0300 Subject: [PATCH 207/230] WL#2486 - natural and using join according to SQL:2003 * Provide backwards compatibility extension to name resolution of coalesced columns. The patch allows such columns to be qualified with a table (and db) name, as it is in 4.1. Based on a patch from Monty. * Adjusted tests accordingly to test both backwards compatible name resolution of qualified columns, and ANSI-style resolution of non-qualified columns. For this, each affected test has two versions - one with qualified columns, and one without. --- mysql-test/include/ps_query.inc | 12 +- mysql-test/r/bdb.result | 7 +- mysql-test/r/innodb.result | 5 + mysql-test/r/join.result | 48 ++++--- mysql-test/r/join_nested.result | 10 +- mysql-test/r/join_outer.result | 112 ++++++++------- mysql-test/r/null_key.result | 14 +- mysql-test/r/order_by.result | 25 ++++ mysql-test/r/ps_2myisam.result | 24 ++-- mysql-test/r/ps_3innodb.result | 24 ++-- mysql-test/r/ps_4heap.result | 24 ++-- mysql-test/r/ps_5merge.result | 48 +++---- mysql-test/r/ps_6bdb.result | 24 ++-- mysql-test/r/ps_7ndb.result | 24 ++-- mysql-test/r/select.result | 38 +++++ mysql-test/r/subselect.result | 8 ++ mysql-test/r/type_ranges.result | 16 +++ mysql-test/t/bdb.test | 3 +- mysql-test/t/innodb.test | 1 + mysql-test/t/join.test | 15 +- mysql-test/t/join_nested.test | 2 +- mysql-test/t/join_outer.test | 20 +-- mysql-test/t/null_key.test | 16 +-- mysql-test/t/order_by.test | 13 ++ mysql-test/t/select.test | 13 ++ mysql-test/t/subselect.test | 2 + mysql-test/t/type_ranges.test | 7 + sql/sql_base.cc | 240 +++++++++++++------------------- sql/table.cc | 9 -- sql/table.h | 7 - tests/mysql_client_test.c | 4 +- 31 files changed, 458 insertions(+), 357 deletions(-) diff --git a/mysql-test/include/ps_query.inc b/mysql-test/include/ps_query.inc index 97653c0b9f8..27a86f88231 100644 --- a/mysql-test/include/ps_query.inc +++ b/mysql-test/include/ps_query.inc @@ -349,14 +349,14 @@ drop table if exists t2 ; --enable_warnings create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; let $1= 9 ; while ($1) { diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index a0b68bfbc13..d525b019c64 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -732,6 +732,11 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=bdb; insert into t1 (a) values(1),(2),(3); +select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; +a +1 +2 +3 select a from t1 natural join t1 as t2 where b >= @a order by a; a 1 @@ -906,7 +911,7 @@ create temporary table tmp1 select branch_id, target_id, platform_id, product_id from t1, t2, t3, t4 ; create temporary table tmp2 -select branch_id, target_id, platform_id, product_id +select tmp1.branch_id, tmp1.target_id, tmp1.platform_id, tmp1.product_id from tmp1 left join t8 using (branch_id,target_id,platform_id,product_id) where t8.archive_id is null ; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 91d72045169..4b62e63c49b 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -750,6 +750,11 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb; insert into t1 (a) values(1),(2),(3); +select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; +a +1 +2 +3 select a from t1 natural join t1 as t2 where b >= @a order by a; a 1 diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 5ea863b4bdb..c887dc9d6a7 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -121,6 +121,12 @@ id catid stateid countyid drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +a +1 +2 +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +ERROR HY000: Too many tables; MySQL can only use XX tables in a join select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); a 1 @@ -145,6 +151,10 @@ DROP TABLE t1, t2; CREATE TABLE t1 (d DATE NOT NULL); CREATE TABLE t2 (d DATE NOT NULL); INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00'); +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL; +d +2001-08-01 +0000-00-00 SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL; d 0000-00-00 @@ -264,6 +274,12 @@ PRIMARY KEY (siteid,rate_code), FULLTEXT KEY rate_code (rate_code) ) ENGINE=MyISAM; INSERT INTO t2 VALUES ('rivercats','cust',20); +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; +rate_code base_rate +cust 20 +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; +rate_code base_rate +cust 20 SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats'; rate_code base_rate cust 20 @@ -326,7 +342,7 @@ select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); i i i NULL NULL 1 2 2 2 -select * from t1,t2 natural left join t3 order by 1,2; +select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; i i 1 2 1 3 @@ -338,36 +354,36 @@ i i i 1 3 NULL 2 2 2 2 3 NULL -select * from t2 natural left join t3,t1 order by t1.i; -i i -2 1 -3 1 -2 2 -3 2 +select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; i i i 1 2 2 1 3 NULL 2 2 2 2 3 NULL -select * from t1,t2 natural right join t3 order by 1,2; +select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; i i -1 2 1 4 -2 2 +1 2 2 4 +2 2 select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; i i i 1 NULL 4 1 2 2 2 NULL 4 2 2 2 -select * from t2 natural right join t3,t1 order by t1.i; -i i -2 1 -4 1 -2 2 -4 2 +select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; i i i 1 NULL 4 diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 8779c61b686..f9a25898a6f 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1153,13 +1153,13 @@ a b a1 b 4 2 1 2 4 2 2 2 5 3 NULL NULL -SELECT * +SELECT t2.a,t2.b,t3.a1,t3.b FROM t2 NATURAL LEFT JOIN t3 WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); -b a c a1 c1 -2 4 0 1 0 -2 4 0 2 0 -3 5 0 NULL NULL +a b a1 b +4 2 1 2 +4 2 2 2 +5 3 NULL NULL DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; CREATE TABLE t1 (a int); CREATE TABLE t2 (a int); diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 9bc85dfa987..d4a20209162 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -36,16 +36,7 @@ grp a c id a c d 3 5 C 3 5 B 5 3 6 D 3 6 C 6 NULL NULL NULL 4 7 D 7 -select * from t1 left join t2 using (a); -a grp c id c d -1 1 a 1 a 1 -2 2 b NULL NULL NULL -3 2 c NULL NULL NULL -4 3 E 3 A 4 -5 3 C 3 B 5 -6 3 D 3 C 6 -NULL NULL NULL NULL NULL -select t1.*,t2.* from t1 left join t2 on t1.a=t2.a; +select t1.*,t2.* from t1 left join t2 using (a); grp a c id a c d 1 1 a 1 1 a 1 2 2 b NULL NULL NULL NULL @@ -54,34 +45,40 @@ grp a c id a c d 3 5 C 3 5 B 5 3 6 D 3 6 C 6 NULL NULL NULL NULL NULL NULL -select * from t1 left join t2 using (a,c); -a c grp id d -1 a 1 1 1 -2 b 2 NULL NULL -3 c 2 NULL NULL -4 E 3 NULL NULL -5 C 3 NULL NULL -6 D 3 NULL NULL -NULL NULL NULL NULL -select * from t1 left join t2 using (c); -c grp a id a d -a 1 1 1 1 1 -a 1 1 3 4 4 -b 2 2 3 5 5 -c 2 3 3 6 6 -E 3 4 NULL NULL NULL -C 3 5 3 6 6 -D 3 6 4 7 7 - NULL NULL NULL NULL NULL -select * from t1 natural left outer join t2; -a c grp id d -1 a 1 1 1 -2 b 2 NULL NULL -3 c 2 NULL NULL -4 E 3 NULL NULL -5 C 3 NULL NULL -6 D 3 NULL NULL -NULL NULL NULL NULL +select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a; +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from t1 left join t2 using (a,c); +grp a c id a c d +1 1 a 1 1 a 1 +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +3 4 E NULL NULL NULL NULL +3 5 C NULL NULL NULL NULL +3 6 D NULL NULL NULL NULL +NULL NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 left join t2 using (c); +grp a c id a c d +1 1 a 1 1 a 1 +1 1 a 3 4 A 4 +2 2 b 3 5 B 5 +2 3 c 3 6 C 6 +3 4 E NULL NULL NULL NULL +3 5 C 3 6 C 6 +3 6 D 4 7 D 7 +NULL NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 natural left outer join t2; +grp a c id a c d +1 1 a 1 1 a 1 +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +3 4 E NULL NULL NULL NULL +3 5 C NULL NULL NULL NULL +3 6 D NULL NULL NULL NULL +NULL NULL NULL NULL NULL NULL select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3; grp a c id a c d 3 4 E 3 4 A 4 @@ -114,21 +111,21 @@ select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on ERROR 42S22: Unknown column 't3.a' in 'on clause' select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); ERROR 42S22: Unknown column 't3.a' in 'on clause' -select * from t1 inner join t2 using (a); -a grp c id c d -1 1 a 1 a 1 -4 3 E 3 A 4 -5 3 C 3 B 5 -6 3 D 3 C 6 +select t1.*,t2.* from t1 inner join t2 using (a); +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a); grp a c id a c d 1 1 a 1 1 a 1 3 4 E 3 4 A 4 3 5 C 3 5 B 5 3 6 D 3 6 C 6 -select * from t1 natural join t2; -a c grp id d -1 a 1 1 1 +select t1.*,t2.* from t1 natural join t2; +grp a c id a c d +1 1 a 1 1 a 1 drop table t1,t2; CREATE TABLE t1 ( usr_id INT unsigned NOT NULL, @@ -435,7 +432,7 @@ INSERT INTO t2 VALUES (3,'z'); SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL; id2 3 -SELECT id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; +SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; id2 3 drop table t1,t2; @@ -653,6 +650,13 @@ select * from t1 natural left join t2 natural left join t3; i 1 2 +select * from t1 natural left join t2 where (t2.i is not null)=0; +i +1 +select * from t1 natural left join t2 where (t2.i is not null) is not null; +i +1 +2 select * from t1 natural left join t2 where (i is not null)=0; i select * from t1 natural left join t2 where (i is not null) is not null; @@ -931,6 +935,18 @@ create table t1 (a int, b varchar(20)); create table t2 (a int, c varchar(20)); insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; +group_concat(t1.b,t2.c) +aaaaa +bbbbb +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; +group_concat(t1.b,t2.c) +aaaaa +bbbbb +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; group_concat(t1.b,t2.c) aaaaa diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 5c2141befa6..7f746a3dbd8 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -313,16 +313,12 @@ INSERT INTO t1 (order_id, product_id, product_type) VALUES ('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); INSERT INTO t2 (order_id, product_id, product_type) VALUES ('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); -select t1.* from t1 left join t2 -on (t1.order_id = t2.order_id and -t1.product_id = t2.product_id and -t1.product_type = t2.product_type) -where t2.order_id = NULL; +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) +where t2.order_id=NULL; order_id product_id product_type -select t1.* from t1 left join t2 -on (t1.order_id = t2.order_id and -t1.product_id = t2.product_id and -t1.product_type = t2.product_type) +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) where t2.order_id is NULL; order_id product_id product_type 3d7ce39b5d4b3e3d22aaafe9b633de51 1206029 3 diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index b766f146254..6864c35dbfc 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -180,6 +180,15 @@ INSERT INTO t3 VALUES (1,'123 Park Place'); INSERT INTO t3 VALUES (2,'453 Boardwalk'); SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c; +a b if(b = 1,i,if(b = 2,v,'')) +1 1 50 +2 1 25 +3 2 123 Park Place +4 2 453 Boardwalk +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c; a b if(b = 1,i,if(b = 2,v,'')) @@ -189,6 +198,16 @@ a b if(b = 1,i,if(b = 2,v,'')) 4 2 453 Boardwalk SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c +ORDER BY a; +a b if(b = 1,i,if(b = 2,v,'')) +1 1 50 +2 1 25 +3 2 123 Park Place +4 2 453 Boardwalk +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c ORDER BY a; @@ -523,9 +542,15 @@ KEY `pseudo` (`pseudo`) ); INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug'); INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug'); +SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest +test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug +SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest +test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index da5466a6e9d..16ead200933 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -519,16 +519,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -549,7 +549,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -591,7 +591,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -612,7 +612,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -654,7 +654,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -675,7 +675,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 237072d7218..9ab5a79f755 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -519,16 +519,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -549,7 +549,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -591,7 +591,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -612,7 +612,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -654,7 +654,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -675,7 +675,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index 9b76003900a..8336a5bf99b 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -520,16 +520,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -550,7 +550,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -592,7 +592,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -613,7 +613,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -655,7 +655,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -676,7 +676,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index adb300fdcf1..f341247a417 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -562,16 +562,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -592,7 +592,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -634,7 +634,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -655,7 +655,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -697,7 +697,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -718,7 +718,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b @@ -3574,16 +3574,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -3604,7 +3604,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -3646,7 +3646,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -3667,7 +3667,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -3709,7 +3709,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -3730,7 +3730,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index d5a15fb4265..fe4536827e6 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -519,16 +519,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -549,7 +549,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -591,7 +591,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -612,7 +612,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -654,7 +654,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -675,7 +675,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 33769f400ae..c4cb92bdc02 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -519,16 +519,16 @@ a ? a drop table if exists t2 ; create table t2 as select * from t1 ; set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ; -set @query2= 'SELECT * FROM t2 natural join t1 order by a ' ; -set @query3= 'SELECT * FROM t2 join t1 using(a) order by a ' ; +set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ; +set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ; set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query5= 'SELECT * FROM t2 natural left join t1 order by a ' ; -set @query6= 'SELECT * FROM t2 left join t1 using(a) order by a ' ; +set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ; +set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ; set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ; -set @query8= 'SELECT * FROM t2 natural right join t1 order by a ' ; -set @query9= 'SELECT * FROM t2 right join t1 using(a) order by a ' ; +set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ; +set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ; the join statement is: -SELECT * FROM t2 right join t1 using(a) order by a +SELECT * FROM t2 right join t1 using(a) order by t2.a prepare stmt1 from @query9 ; execute stmt1 ; a b b @@ -549,7 +549,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural right join t1 order by a +SELECT * FROM t2 natural right join t1 order by t2.a prepare stmt1 from @query8 ; execute stmt1 ; a b @@ -591,7 +591,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 left join t1 using(a) order by a +SELECT * FROM t2 left join t1 using(a) order by t2.a prepare stmt1 from @query6 ; execute stmt1 ; a b b @@ -612,7 +612,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural left join t1 order by a +SELECT * FROM t2 natural left join t1 order by t2.a prepare stmt1 from @query5 ; execute stmt1 ; a b @@ -654,7 +654,7 @@ a b a b 3 three 3 three 4 four 4 four the join statement is: -SELECT * FROM t2 join t1 using(a) order by a +SELECT * FROM t2 join t1 using(a) order by t2.a prepare stmt1 from @query3 ; execute stmt1 ; a b b @@ -675,7 +675,7 @@ a b b 3 three three 4 four four the join statement is: -SELECT * FROM t2 natural join t1 order by a +SELECT * FROM t2 natural join t1 order by t2.a prepare stmt1 from @query2 ; execute stmt1 ; a b diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index b20949d4a62..6e28ecb5ec3 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1350,6 +1350,20 @@ fld1 fld1 250504 250505 250505 250505 insert into t2 (fld1, companynr) values (999999,99); +select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +companynr companyname +99 NULL +select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; +count(*) +1199 +explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where; Not exists +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where; Not exists select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; companynr companyname select count(*) from t2 left join t4 using (companynr) where companynr is not null; @@ -1362,6 +1376,18 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE delete from t2 where fld1=999999; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where @@ -1374,6 +1400,18 @@ explain select companynr,companyname from t4 left join t2 using (companynr) wher id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index d3ab359702e..14806279362 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1789,10 +1789,18 @@ CREATE TABLE t1 (id INT); CREATE TABLE t2 (id INT); INSERT INTO t1 VALUES (1), (2); INSERT INTO t2 VALUES (1); +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +id c +1 1 +2 0 SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); id c 1 1 2 0 +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id; +id c +1 1 +2 0 SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id; id c 1 1 diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index 39c55206c60..1342603f755 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -307,17 +307,33 @@ create table t1 ( id integer unsigned not null primary key ); create table t2 ( id integer unsigned not null primary key ); insert into t1 values (1), (2); insert into t2 values (1); +select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +id_A id_B +1 1 +2 NULL select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); id_A id_B 1 1 2 NULL create table t3 (id_A integer unsigned not null, id_B integer unsigned null ); +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +id_A id_B +1 1 +2 NULL +delete from t3; insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; id_A id_B 1 1 2 NULL drop table t3; +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +id_A id_B +1 1 +2 NULL +drop table t3; create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; id_A id_B diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index 5e487bd8036..3167682f816 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -400,6 +400,7 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=bdb; insert into t1 (a) values(1),(2),(3); +select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; select a from t1 natural join t1 as t2 where b >= @a order by a; update t1 set a=5 where a=1; select a from t1; @@ -571,7 +572,7 @@ create temporary table tmp1 select branch_id, target_id, platform_id, product_id from t1, t2, t3, t4 ; create temporary table tmp2 - select branch_id, target_id, platform_id, product_id + select tmp1.branch_id, tmp1.target_id, tmp1.platform_id, tmp1.product_id from tmp1 left join t8 using (branch_id,target_id,platform_id,product_id) where t8.archive_id is null ; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 3eaf408af0f..bf094dd0e5d 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -440,6 +440,7 @@ drop table t1; set @a:=now(); CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb; insert into t1 (a) values(1),(2),(3); +select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; select a from t1 natural join t1 as t2 where b >= @a order by a; update t1 set a=5 where a=1; select a from t1; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 2e82bad8abb..bb82a93c6c4 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -111,6 +111,10 @@ drop table t1, t2; create table t1 (a int primary key); insert into t1 values(1),(2); +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +--replace_result "31 tables" "XX tables" "61 tables" "XX tables" +--error 1116 +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); --replace_result "31 tables" "XX tables" "61 tables" "XX tables" --error 1116 @@ -144,6 +148,7 @@ DROP TABLE t1, t2; CREATE TABLE t1 (d DATE NOT NULL); CREATE TABLE t2 (d DATE NOT NULL); INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00'); +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL; SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL; SELECT * from t1 WHERE t1.d IS NULL; SELECT * FROM t1 WHERE 1/0 IS NULL; @@ -266,6 +271,8 @@ CREATE TABLE t2 ( FULLTEXT KEY rate_code (rate_code) ) ENGINE=MyISAM; INSERT INTO t2 VALUES ('rivercats','cust',20); +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats'; SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith'; drop table t1,t2; @@ -315,14 +322,14 @@ select * from t3 right join t2 on (t3.i=t2.i); select * from t3 natural right join t2 natural right join t1; select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); -select * from t1,t2 natural left join t3 order by 1,2; +select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; -select * from t2 natural left join t3,t1 order by t1.i; +select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; -select * from t1,t2 natural right join t3 order by 1,2; +select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; -select * from t2 natural right join t3,t1 order by t1.i; +select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; drop table t1,t2,t3; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index f6b74237123..482c7f9f8b9 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -678,7 +678,7 @@ SELECT t2.a,t2.b,t3.a1,t3.b FROM t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); -SELECT * +SELECT t2.a,t2.b,t3.a1,t3.b FROM t2 NATURAL LEFT JOIN t3 WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 6a3b79f8354..aabc32c009a 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -19,11 +19,11 @@ select t1.*,t2.* from t1 JOIN t2 where t1.a=t2.a; select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) order by t1.grp,t1.a,t2.c; select t1.*,t2.* from { oj t2 left outer join t1 on (t1.a=t2.a) }; select t1.*,t2.* from t1 as t0,{ oj t2 left outer join t1 on (t1.a=t2.a) } WHERE t0.a=2; -select * from t1 left join t2 using (a); -select t1.*,t2.* from t1 left join t2 on t1.a=t2.a; -select * from t1 left join t2 using (a,c); -select * from t1 left join t2 using (c); -select * from t1 natural left outer join t2; +select t1.*,t2.* from t1 left join t2 using (a); +select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a; +select t1.*,t2.* from t1 left join t2 using (a,c); +select t1.*,t2.* from t1 left join t2 using (c); +select t1.*,t2.* from t1 natural left outer join t2; select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3; select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id is null; @@ -44,9 +44,9 @@ select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); # Test of inner join -select * from t1 inner join t2 using (a); +select t1.*,t2.* from t1 inner join t2 using (a); select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a); -select * from t1 natural join t2; +select t1.*,t2.* from t1 natural join t2; drop table t1,t2; @@ -325,7 +325,7 @@ INSERT INTO t2 VALUES (2,'y'); INSERT INTO t2 VALUES (3,'z'); SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL; -SELECT id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; +SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; drop table t1,t2; @@ -430,6 +430,8 @@ insert into t1 values(1),(2); insert into t2 values(2),(3); insert into t3 values(2),(4); select * from t1 natural left join t2 natural left join t3; +select * from t1 natural left join t2 where (t2.i is not null)=0; +select * from t1 natural left join t2 where (t2.i is not null) is not null; select * from t1 natural left join t2 where (i is not null)=0; select * from t1 natural left join t2 where (i is not null) is not null; drop table t1,t2,t3; @@ -656,6 +658,8 @@ create table t1 (a int, b varchar(20)); create table t2 (a int, c varchar(20)); insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; drop table t1, t2; diff --git a/mysql-test/t/null_key.test b/mysql-test/t/null_key.test index 4ab99fc5d6d..e15aec01d2a 100644 --- a/mysql-test/t/null_key.test +++ b/mysql-test/t/null_key.test @@ -152,18 +152,12 @@ INSERT INTO t1 (order_id, product_id, product_type) VALUES INSERT INTO t2 (order_id, product_id, product_type) VALUES ('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); -select t1.* from t1 left join t2 - on (t1.order_id = t2.order_id and - t1.product_id = t2.product_id and - t1.product_type = t2.product_type) -where t2.order_id = NULL; - -select t1.* from t1 left join t2 - on (t1.order_id = t2.order_id and - t1.product_id = t2.product_id and - t1.product_type = t2.product_type) +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) +where t2.order_id=NULL; +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) where t2.order_id is NULL; - drop table t1,t2; # diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 615b317eb36..b1807579b20 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -151,11 +151,22 @@ INSERT INTO t2 VALUES (2,25); INSERT INTO t3 VALUES (1,'123 Park Place'); INSERT INTO t3 VALUES (2,'453 Boardwalk'); +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c; + SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 LEFT JOIN t2 ON t1.c = t2.c LEFT JOIN t3 ON t3.c = t1.c; +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c +ORDER BY a; + SELECT a,b,if(b = 1,i,if(b = 2,v,'')) FROM t1 LEFT JOIN t2 ON t1.c = t2.c @@ -339,7 +350,9 @@ CREATE TABLE t2 ( INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug'); INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug'); +SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; drop table t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 8e74167852b..f580d3d1223 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1538,6 +1538,11 @@ select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 25 # insert into t2 (fld1, companynr) values (999999,99); +select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; +explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; + select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; select count(*) from t2 left join t4 using (companynr) where companynr is not null; explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; @@ -1547,10 +1552,18 @@ delete from t2 where fld1=999999; # # Test left join optimization +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; + explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0; # Following can't be optimized +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; + explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 22c5471dee2..5020902009d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1132,7 +1132,9 @@ CREATE TABLE t1 (id INT); CREATE TABLE t2 (id INT); INSERT INTO t1 VALUES (1), (2); INSERT INTO t2 VALUES (1); +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id; SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id; DROP TABLE t1,t2; diff --git a/mysql-test/t/type_ranges.test b/mysql-test/t/type_ranges.test index 85862821aab..03ee91f14d8 100644 --- a/mysql-test/t/type_ranges.test +++ b/mysql-test/t/type_ranges.test @@ -157,11 +157,18 @@ create table t1 ( id integer unsigned not null primary key ); create table t2 ( id integer unsigned not null primary key ); insert into t1 values (1), (2); insert into t2 values (1); +select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); create table t3 (id_A integer unsigned not null, id_B integer unsigned null ); +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +delete from t3; insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; drop table t3; +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +drop table t3; create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); select * from t3; drop table t1,t2,t3; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b8748b89fbd..8017a82f1ed 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2587,8 +2587,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, thd [in] thread handler table_ref [in] table reference to search name [in] name of field - table_name [in] optional table name that qualifies the field - db_name [in] optional database name that qualifies the field length [in] length of name ref [in/out] if 'name' is resolved to a view field, ref is set to point to the found view field @@ -2599,6 +2597,12 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, belongs - differs from 'table_list' only for NATURAL/USING joins + DESCRIPTION + Search for a field among the result fields of a NATURAL/USING join. + Notice that this procedure is called only for non-qualified field + names. In the case of qualified fields, we search directly the base + tables of a natural join. + RETURN NULL if the field was not found WRONG_GRANT if no access rights to the found field @@ -2607,7 +2611,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, static Field * find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, - const char *table_name, const char *db_name, uint length, Item **ref, bool check_grants, bool register_tree_change, TABLE_LIST **actual_table) @@ -2629,27 +2632,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, if (!(nj_col= field_it++)) DBUG_RETURN(NULL); - if (table_name) - { - /* - Coalesced columns cannot be qualified unless this is the execute phase - of prepared statements. The reason is that they do not belong to any - table, but for PS the prepare phase already resolves and stores - items, so during the execution phase we resolve fully qualified items. - */ - if (!thd->current_arena->is_stmt_execute() && nj_col->is_coalesced) - continue; - if (table_name[0] && - my_strcasecmp(table_alias_charset, nj_col->table_name(), table_name)) - continue; - if (db_name && db_name[0]) - { - const char *cur_db_name= nj_col->db_name(); - if (cur_db_name && strcmp(db_name, cur_db_name)) - continue; - } - } - if (!my_strcasecmp(system_charset_info, nj_col->name(), name)) break; } @@ -2842,11 +2824,35 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, *actual_table= table_list; } else if (table_list->is_natural_join) - fld= find_field_in_natural_join(thd, table_list, name, table_name, - db_name, length, ref, + { + if (table_name && table_name[0]) + { + /* + Qualified field; Search for it in the tables used by the natural join. + */ + List_iterator it(table_list->nested_join->join_list); + TABLE_LIST *table; + while ((table= it++)) + { + if ((fld= find_field_in_table_ref(thd, table, name, item_name, + table_name, db_name, length, ref, + check_grants_table, + check_grants_view, + allow_rowid, cached_field_index_ptr, + register_tree_change, actual_table))) + DBUG_RETURN(fld); + } + DBUG_RETURN(0); + } + /* + Non-qualified field, search directly in the result columns of the + natural join. + */ + fld= find_field_in_natural_join(thd, table_list, name, length, ref, /* TIMOUR_TODO: check this with Sanja */ check_grants_table || check_grants_view, register_tree_change, actual_table); + } else { if ((fld= find_field_in_table(thd, table_list->table, name, length, @@ -2915,9 +2921,11 @@ find_field_in_tables(THD *thd, Item_ident *item, const char *name= item->field_name; uint length=(uint) strlen(name); char name_buff[NAME_LEN+1]; - bool allow_rowid; TABLE_LIST *cur_table= first_table; TABLE_LIST *actual_table; + bool is_qualified= table_name && table_name[0]; + bool allow_rowid= is_qualified ? + TRUE : (cur_table && !cur_table->next_local); if (item->cached_table) { @@ -2988,81 +2996,13 @@ find_field_in_tables(THD *thd, Item_ident *item, if (last_table) last_table= last_table->next_name_resolution_table; - /* The field we search for is qualified with a table name and optional db. */ - if (table_name && table_name[0]) - { - for (; cur_table != last_table ; - cur_table= cur_table->next_name_resolution_table) - { - Field *cur_field= find_field_in_table_ref(thd, cur_table, name, - item->name, table_name, - db, length, ref, - (cur_table->table && - test(cur_table->table->grant. - want_privilege) && - check_privileges), - (test(cur_table->grant. - want_privilege) && - check_privileges), - 1, &(item->cached_field_index), - register_tree_change, - &actual_table); - if (cur_field) - { - /* - Store the original table of the field, which may be different from - cur_table in the case of NATURAL/USING join. - */ - item->cached_table= (!actual_table->cacheable_table) ? 0 : actual_table; - - if (cur_field == WRONG_GRANT) - return (Field*) 0; - if (db || !thd->where) - return cur_field; - if (found) - { - if (report_error == REPORT_ALL_ERRORS || - report_error == IGNORE_EXCEPT_NON_UNIQUE) - my_error(ER_NON_UNIQ_ERROR, MYF(0), - item->full_name(),thd->where); - return (Field*) 0; - } - found= cur_field; - } - } - if (found) - return found; - /* - If there were no tables to search, we wouldn't go through the loop and - cur_table wouldn't be updated by the loop increment part. - */ - if (cur_table == first_table && (report_error == REPORT_ALL_ERRORS || - report_error == REPORT_EXCEPT_NON_UNIQUE)) - { - char buff[NAME_LEN*2+1]; - if (db && db[0]) - { - strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); - table_name=buff; - } - my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where); - } - else - if (report_error == REPORT_ALL_ERRORS || - report_error == REPORT_EXCEPT_NON_UNIQUE) - my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where); - else - return (Field*) not_found_field; - return (Field*) 0; - } - - /* The field we search for is not qualified. */ - allow_rowid= cur_table && !cur_table->next_local; for (; cur_table != last_table ; cur_table= cur_table->next_name_resolution_table) { Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name, - NULL, NULL, length, ref, + is_qualified ? table_name : NULL, + is_qualified ? db : NULL, + length, ref, (cur_table->table && test(cur_table->table->grant. want_privilege) && @@ -3086,26 +3026,57 @@ find_field_in_tables(THD *thd, Item_ident *item, item->cached_table= (!actual_table->cacheable_table || found) ? 0 : actual_table; + DBUG_ASSERT(thd->where); + /* + If we found a fully qualified field we return it directly as it can't + have duplicates. + */ + if (is_qualified && db) + return cur_field; + if (found) { - if (!thd->where) // Returns first found - break; if (report_error == REPORT_ALL_ERRORS || report_error == IGNORE_EXCEPT_NON_UNIQUE) - my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); + my_error(ER_NON_UNIQ_ERROR, MYF(0), + is_qualified ? item->full_name() : name, thd->where); return (Field*) 0; } found= cur_field; } } + if (found) return found; - if (report_error == REPORT_ALL_ERRORS || - report_error == REPORT_EXCEPT_NON_UNIQUE) - my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where); + + /* + If the field was qualified and there were no tables to search, issue + an error that an unknown table was given. The situation is detected + as follows: if there were no tables we wouldn't go through the loop + and cur_table wouldn't be updated by the loop increment part, so it + will be equal to the first table. + */ + if (is_qualified && (cur_table == first_table) && + (report_error == REPORT_ALL_ERRORS || + report_error == REPORT_EXCEPT_NON_UNIQUE)) + { + char buff[NAME_LEN*2+1]; + if (db && db[0]) + { + strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); + table_name=buff; + } + my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where); + } else - return (Field*) not_found_field; - return (Field*) 0; + if (report_error == REPORT_ALL_ERRORS || + report_error == REPORT_EXCEPT_NON_UNIQUE) + my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where); + else + found= not_found_field; + + DBUG_ASSERT(!found || found == not_found_field); + return found; } @@ -3510,10 +3481,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, Item_ident *item_ident_1, *item_ident_2; Item_func_eq *eq_cond; - DBUG_PRINT("info", ("new equi-join condition: %s.%s = %s.%s", - table_ref_1->alias, field_1->field_name, - table_ref_2->alias, field_2->field_name)); - if (!item_1 || !item_2) goto err; // out of memory @@ -3560,7 +3527,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, eq_cond); nj_col_1->is_common= nj_col_2->is_common= TRUE; - nj_col_1->is_coalesced= nj_col_2->is_coalesced= TRUE; if (field_1) { @@ -4310,29 +4276,28 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, } found= FALSE; - for (TABLE_LIST *tables= context->first_name_resolution_table; + + /* + If table names are qualified, then loop over all tables used in the query, + else treat natural joins as leaves and do not iterate over their underlying + tables. + */ + for (TABLE_LIST *tables= (table_name ? context->table_list : + context->first_name_resolution_table); tables; - tables= tables->next_name_resolution_table) + tables= (table_name ? tables->next_local : + tables->next_name_resolution_table) + ) { Field *field; TABLE *table= tables->table; DBUG_ASSERT(tables->is_leaf_for_name_resolution()); - /* - If optional table and db names do not match the ones used to qualify - the field being expanded, skip this table reference. However if this is - a NATURAL/USING join, we can't simply skip the whole table reference, - because its columns may come from different tables/views. For NATURAL/ - USING joins we perform this test for each column in the loop below. - */ - if (!tables->is_natural_join) - { - if (table_name && my_strcasecmp(table_alias_charset, table_name, - tables->alias) || - (db_name && strcmp(tables->db,db_name))) - continue; - } + if (table_name && my_strcasecmp(table_alias_charset, table_name, + tables->alias) || + (db_name && strcmp(tables->db,db_name))) + continue; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Ensure that we have access rights to all fields to be inserted. */ @@ -4369,21 +4334,6 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, { Item *item; - /* - If this is a column of a NATURAL/USING join, and the star was - qualified with a table (and database) name, check if the - column is not a coalesced one, and if not, that is belongs to - the same table. - */ - if (tables->is_natural_join && table_name) - { - if (field_iterator.is_coalesced() || - my_strcasecmp(table_alias_charset, table_name, - field_iterator.table_name()) || - (db_name && strcmp(db_name, field_iterator.db_name()))) - continue; - } - if (!(item= field_iterator.create_item(thd))) DBUG_RETURN(TRUE); @@ -4410,18 +4360,18 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, tables->is_natural_join); DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *fld= (Item_field*) item; - const char *table_name= field_iterator.table_name(); + const char *field_table_name= field_iterator.table_name(); if (!tables->schema_table && !(fld->have_privileges= (get_column_grant(thd, field_iterator.grant(), field_iterator.db_name(), - table_name, fld->field_name) & + field_table_name, fld->field_name) & VIEW_ANY_ACL))) { my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", thd->priv_user, thd->host_or_ip, - fld->field_name, table_name); + fld->field_name, field_table_name); DBUG_RETURN(TRUE); } } diff --git a/sql/table.cc b/sql/table.cc index beecd6442e8..5983b9afda7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2289,7 +2289,6 @@ Natural_join_column::Natural_join_column(Field_translator *field_param, table_field= NULL; table_ref= tab; is_common= FALSE; - is_coalesced= FALSE; } @@ -2301,7 +2300,6 @@ Natural_join_column::Natural_join_column(Field *field_param, view_field= NULL; table_ref= tab; is_common= FALSE; - is_coalesced= FALSE; } @@ -2641,13 +2639,6 @@ GRANT_INFO *Field_iterator_table_ref::grant() } -bool Field_iterator_table_ref::is_coalesced() -{ - if (table_ref->is_natural_join) - return natural_join_it.column_ref()->is_coalesced; - return FALSE; -} - /* Create new or return existing column reference to a column of a natural/using join. diff --git a/sql/table.h b/sql/table.h index c0e4ad4c150..b6616150610 100644 --- a/sql/table.h +++ b/sql/table.h @@ -388,12 +388,6 @@ public: we are looking at some column. */ bool is_common; - /* - A column is coalesced if it was common in some of several nested NATURAL/ - USING joins. We have to know this, because according to ANSI, coalesced - columns cannot be qualified. - */ - bool is_coalesced; public: Natural_join_column(Field_translator *field_param, st_table_list *tab); Natural_join_column(Field *field_param, st_table_list *tab); @@ -741,7 +735,6 @@ public: const char *table_name(); const char *db_name(); GRANT_INFO *grant(); - bool is_coalesced(); Item *create_item(THD *thd) { return field_it->create_item(thd); } Field *field() { return field_it->field(); } Natural_join_column *get_or_create_column_ref(THD *thd, bool *is_created); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 5558028bb06..75b41ebe4d1 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11801,8 +11801,8 @@ static void test_bug6046() stmt= mysql_stmt_init(mysql); - stmt_text= "SELECT a FROM t1 NATURAL JOIN t1 as X1 " - "WHERE b > ? ORDER BY a"; + stmt_text= "SELECT t1.a FROM t1 NATURAL JOIN t1 as X1 " + "WHERE t1.b > ? ORDER BY t1.a"; rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); From 2f2347e5566cf5927e1b72f6ab646bb5e70fa2c8 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Tue, 23 Aug 2005 19:00:28 +0300 Subject: [PATCH 208/230] Test case for BUG#10972 - Natural join of view and underlying table gives wrong result. The bug itself is fixed by WL#2486. --- mysql-test/r/select.result | 11 +++++++++++ mysql-test/t/select.test | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 801af85da64..1fb460535ef 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2818,3 +2818,14 @@ create table t2 (pk int primary key, c int); select pk from t1 inner join t2 using (pk); pk drop table t1,t2; +create table t1 (s1 int, s2 char(5), s3 decimal(10)); +create view v1 as select s1, s2, 'x' as s3 from t1; +select * from t1 natural join v1; +s1 s2 s3 +insert into t1 values (1,'x',5); +select * from t1 natural join v1; +s1 s2 s3 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'x' +drop table t1; +drop view v1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 61f792a799f..250d1972bf7 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2394,3 +2394,15 @@ create table t1 (pk int primary key, b int); create table t2 (pk int primary key, c int); select pk from t1 inner join t2 using (pk); drop table t1,t2; + +# +# Bug #10972 Natural join of view and underlying table gives wrong result +# + +create table t1 (s1 int, s2 char(5), s3 decimal(10)); +create view v1 as select s1, s2, 'x' as s3 from t1; +select * from t1 natural join v1; +insert into t1 values (1,'x',5); +select * from t1 natural join v1; +drop table t1; +drop view v1; From 9a6aefab3ab84a8af8a6fd92f78abbc7d8dde487 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Tue, 23 Aug 2005 20:03:32 +0300 Subject: [PATCH 209/230] Fix for BUG#6276. --- mysql-test/r/select.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/select.test | 20 ++++++++++++++++++++ sql/sql_base.cc | 5 +++++ 3 files changed, 56 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 1fb460535ef..8d52dcc22fe 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2829,3 +2829,34 @@ Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'x' drop table t1; drop view v1; +create table t1(a1 int); +create table t2(a2 int); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create view v2 (c) as select a1 from t1; +select * from t1 natural left join t2; +a1 a2 +1 1 +1 2 +2 1 +2 2 +select * from t1 natural right join t2; +a2 a1 +1 1 +1 2 +2 1 +2 2 +select * from v2 natural left join t2; +c a2 +1 1 +1 2 +2 1 +2 2 +select * from v2 natural right join t2; +a2 c +1 1 +1 2 +2 1 +2 2 +drop table t1, t2; +drop view v2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 250d1972bf7..414af3f9131 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2406,3 +2406,23 @@ insert into t1 values (1,'x',5); select * from t1 natural join v1; drop table t1; drop view v1; + +# +# Bug #6276 A SELECT that does a NATURAL OUTER JOIN without common +# columns crashes server because of empty ON condition +# + +create table t1(a1 int); +create table t2(a2 int); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create view v2 (c) as select a1 from t1; + +select * from t1 natural left join t2; +select * from t1 natural right join t2; + +select * from v2 natural left join t2; +select * from v2 natural right join t2; + +drop table t1, t2; +drop view v2; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 763fbc6c336..a7f5fa3ce03 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3851,6 +3851,11 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, */ table_ref_1->natural_join= table_ref_2->natural_join= NULL; + /* Add a TRUE condition to outer joins that have no common columns. */ + if (table_ref_2->outer_join && + !table_ref_1->on_expr && !table_ref_2->on_expr) + table_ref_2->on_expr= new Item_int((longlong) 1,1); /* Always true. */ + /* Change this table reference to become a leaf for name resolution. */ if (left_neighbor) { From 5f9d05d306e0fe4a30518e4c91d3dd5da512cb8c Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Tue, 23 Aug 2005 20:24:29 +0300 Subject: [PATCH 210/230] Test for BUG#4889 - inconsistent resilts of more than 2-way natural join due to incorrect transformation to JOIN ... ON. The bug itself is fixed by WL#2486. --- mysql-test/r/select.result | 15 +++++++++++++++ mysql-test/t/select.test | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 8d52dcc22fe..47dbdd49db9 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2860,3 +2860,18 @@ a2 c 2 2 drop table t1, t2; drop view v2; +create table t1 (a int(10), t1_val int(10)); +create table t2 (b int(10), t2_val int(10)); +create table t3 (a int(10), b int(10)); +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(2,2),(3,3); +insert into t3 values (1,1),(2,1),(3,1),(4,1); +select * from t1 natural join t2 natural join t3; +a b t1_val t2_val +1 1 1 1 +2 1 2 1 +select * from t1 natural join t3 natural join t2; +b a t1_val t2_val +1 1 1 1 +1 2 2 1 +drop table t1, t2, t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 414af3f9131..21fc4c25e61 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2426,3 +2426,20 @@ select * from v2 natural right join t2; drop table t1, t2; drop view v2; + + +# +# Bug #4789 Incosistent results of more than 2-way natural joins due to +# incorrect transformation to join ... on. +# + +create table t1 (a int(10), t1_val int(10)); +create table t2 (b int(10), t2_val int(10)); +create table t3 (a int(10), b int(10)); +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(2,2),(3,3); +insert into t3 values (1,1),(2,1),(3,1),(4,1); +# the following two queries must return the same result +select * from t1 natural join t2 natural join t3; +select * from t1 natural join t3 natural join t2; +drop table t1, t2, t3; From cf5dd176c0d83938a5fdc13cc7a4a5d049158a2e Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Tue, 23 Aug 2005 11:25:24 -0700 Subject: [PATCH 211/230] Fix build using --without-server. (Bug #11680) --- configure.in | 7 +++---- dbug/my_main.c | 2 ++ mysys/Makefile.am | 2 +- mysys/mf_getdate.c | 2 +- sql/share/Makefile.am | 2 +- tests/Makefile.am | 3 +-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/configure.in b/configure.in index 8a5220dbf38..612a51586ab 100644 --- a/configure.in +++ b/configure.in @@ -2444,7 +2444,7 @@ thread_dirs= dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. -sql_client_dirs="libmysql strings regex client" +sql_client_dirs="strings regex mysys sql/share libmysql client" linked_client_targets="linked_libmysql_sources" if test "$THREAD_SAFE_CLIENT" != "no" @@ -2482,10 +2482,10 @@ then AC_DEFINE([THREAD], [1], [Define if you want to have threaded code. This may be undef on client code]) # Avoid _PROGRAMS names - THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o" + THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o" AC_SUBST(THREAD_LOBJECTS) server_scripts="mysqld_safe mysql_install_db" - sql_server_dirs="strings mysys dbug extra regex" + sql_server_dirs="strings dbug extra regex" # @@ -2593,7 +2593,6 @@ esac # END of configuration for optional table handlers # sql_server_dirs="$sql_server_dirs myisam myisammrg heap vio sql" - fi # IMPORTANT - do not modify LIBS past this line - this hack is the only way diff --git a/dbug/my_main.c b/dbug/my_main.c index 90af23b42b9..ed1c9329235 100644 --- a/dbug/my_main.c +++ b/dbug/my_main.c @@ -18,7 +18,9 @@ char *argv[]; #if defined(HAVE_PTHREAD_INIT) && defined(THREAD) pthread_init(); /* Must be called before DBUG_ENTER */ #endif +#ifdef THREAD my_thread_global_init(); +#endif { DBUG_ENTER ("main"); DBUG_PROCESS (argv[0]); diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 9c58c18cf59..868f68096ae 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -30,7 +30,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ mf_path.c mf_loadpath.c my_file.c \ my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_pread.c my_write.c \ - mf_keycache.c mf_keycaches.c my_crc32.c \ + mf_keycaches.c my_crc32.c \ mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \ mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \ my_malloc.c my_realloc.c my_once.c mulalloc.c \ diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c index b12e68cc1f9..8998da8aefa 100644 --- a/mysys/mf_getdate.c +++ b/mysys/mf_getdate.c @@ -54,7 +54,7 @@ void get_date(register my_string to, int flag, time_t date) if (flag & GETDATE_GMT) start_time= localtime(&skr); else - gmtime(&skr,&tm_tmp); + start_time= gmtime(&skr); #endif if (flag & GETDATE_SHORT_DATE) sprintf(to,"%02d%02d%02d", diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index b7ab8fead22..2e23027f1f5 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -33,7 +33,7 @@ all-local: english/errmsg.sys # created. Normally these are created by extra/Makefile english/errmsg.sys: errmsg.txt - rm $(top_builddir)/include/mysqld_error.h + rm -f $(top_builddir)/include/mysqld_error.h (cd $(top_builddir)/extra && $(MAKE)) install-data-local: diff --git a/tests/Makefile.am b/tests/Makefile.am index ca7f04c91f9..131f8b1b625 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,8 +42,7 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ LIBS = @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ \ $(top_builddir)/libmysql/libmysqlclient.la -mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) \ - $(top_builddir)/mysys/libmysys.a +mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) mysql_client_test_SOURCES= mysql_client_test.c $(yassl_dummy_link_fix) insert_test_SOURCES= insert_test.c $(yassl_dummy_link_fix) select_test_SOURCES= select_test.c $(yassl_dummy_link_fix) From f58315f80aefdc9eb824830f72828b349dc79e12 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Tue, 23 Aug 2005 22:29:05 +0300 Subject: [PATCH 212/230] Test for BUG#6495. The bug itself is fixed by WL#2486. --- mysql-test/r/select.result | 12 ++++++++++++ mysql-test/t/select.test | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 47dbdd49db9..83682d87504 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2875,3 +2875,15 @@ b a t1_val t2_val 1 1 1 1 1 2 2 1 drop table t1, t2, t3; +create table t1 (a char(1)); +create table t2 (a char(1)); +insert into t1 values ('a'),('b'),('c'); +insert into t2 values ('b'),('c'),('d'); +select a from t1 natural join t2; +a +b +c +select * from t1 natural join t2 where a = 'b'; +a +b +drop table t1, t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 21fc4c25e61..ebd382b1df1 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2443,3 +2443,16 @@ insert into t3 values (1,1),(2,1),(3,1),(4,1); select * from t1 natural join t2 natural join t3; select * from t1 natural join t3 natural join t2; drop table t1, t2, t3; + + +# +# Bug #6495 Illogical requirement for column qualification in NATURAL join +# + +create table t1 (a char(1)); +create table t2 (a char(1)); +insert into t1 values ('a'),('b'),('c'); +insert into t2 values ('b'),('c'),('d'); +select a from t1 natural join t2; +select * from t1 natural join t2 where a = 'b'; +drop table t1, t2; From f98f46c471cdb18b61280be35f4b26d9bb0f6115 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Wed, 24 Aug 2005 01:45:15 +0200 Subject: [PATCH 213/230] BUG#12532: Fixes after review --- sql/log_event.cc | 13 ++++++------- sql/sql_parse.cc | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index a07efc21915..9e8c0695b90 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1330,14 +1330,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + time_zone_len + 1 + - data_len + 1 + -#ifndef MYSQL_CLIENT -#ifdef HAVE_QUERY_CACHE - QUERY_CACHE_FLAGS_SIZE + + data_len + 1 +#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) + + QUERY_CACHE_FLAGS_SIZE + + db_len + 1 #endif -#endif - db_len + 1, MYF(MY_WME)))) - DBUG_VOID_RETURN; + , MYF(MY_WME)))) + DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 31d0f3eb675..70920b07a97 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1218,7 +1218,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) length--; buff[length]=0; thd->query_length=length; - thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1); + thd->query= thd->memdup_w_gap(buff, length+1, + thd->db_length+1+QUERY_CACHE_FLAGS_SIZE); thd->query[length] = '\0'; /* We don't need to obtain LOCK_thread_count here because in bootstrap From 659809d30fd501e4af16f61e90badb9d17e952bb Mon Sep 17 00:00:00 2001 From: "petr@mysql.com" <> Date: Wed, 24 Aug 2005 02:46:13 +0200 Subject: [PATCH 214/230] fix compilation failure appeared after monty's cleanup --- sql/sp_head.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ebcbfb67fc8..dfc91f5a3f4 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -227,8 +227,8 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val))); -#endif } +#endif break; } case STRING_RESULT: From 04a6a8e01110cc171cb6fa609548da7be32ff662 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Wed, 24 Aug 2005 10:51:28 +0300 Subject: [PATCH 215/230] Post-fix for BUG#6276. --- sql/sql_base.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a7f5fa3ce03..b2ed392d1ac 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3763,8 +3763,13 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, TABLE_LIST *left_neighbor, TABLE_LIST *right_neighbor) { + Query_arena *arena, backup; + bool result= TRUE; + DBUG_ENTER("store_top_level_join_columns"); + arena= thd->change_arena_if_needed(&backup); + /* Call the procedure recursively for each nested table reference. */ if (table_ref->nested_join) { @@ -3797,7 +3802,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (cur_table_ref->nested_join && store_top_level_join_columns(thd, cur_table_ref, cur_left_neighbor, cur_right_neighbor)) - DBUG_RETURN(TRUE); + goto err; cur_right_neighbor= cur_table_ref; } } @@ -3829,7 +3834,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, swap_variables(TABLE_LIST*, table_ref_1, table_ref_2); if (mark_common_columns(thd, table_ref_1, table_ref_2, using_fields, &found_using_fields)) - DBUG_RETURN(TRUE); + goto err; /* Swap the join operands back, so that we pick the columns of the second @@ -3841,7 +3846,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (store_natural_using_join_columns(thd, table_ref, table_ref_1, table_ref_2, using_fields, found_using_fields)) - DBUG_RETURN(TRUE); + goto err; /* Change NATURAL JOIN to JOIN ... ON. We do this for both operands @@ -3872,7 +3877,12 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, else table_ref->next_name_resolution_table= NULL; } - DBUG_RETURN(FALSE); + result= FALSE; /* All is OK. */ + +err: + if (arena) + thd->restore_backup_item_arena(arena, &backup); + DBUG_RETURN(result); } From 2df4914e1172d5a59d6c3d0dc8dc2f9d347b0cf5 Mon Sep 17 00:00:00 2001 From: "petr@mysql.com" <> Date: Wed, 24 Aug 2005 12:25:57 +0400 Subject: [PATCH 216/230] fix test for a bug to use correct tables --- mysql-test/r/sp.result | 33 +++++++++++++++++---------------- mysql-test/t/sp.test | 33 +++++++++++++++++---------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index d1d41035475..423cd546a84 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3101,16 +3101,16 @@ call p_bug11247(10)| drop function f_bug11247| drop procedure p_bug11247| drop procedure if exists bug12168| -drop table if exists t1, t2| -create table t1 (a int)| -insert into t1 values (1),(2),(3),(4)| -create table t2 (a int)| +drop table if exists t3, t4| +create table t3 (a int)| +insert into t3 values (1),(2),(3),(4)| +create table t4 (a int)| create procedure bug12168(arg1 char(1)) begin declare b, c integer; if arg1 = 'a' then begin -declare c1 cursor for select a from t1 where a % 2; +declare c1 cursor for select a from t3 where a % 2; declare continue handler for not found set b = 1; set b = 0; open c1; @@ -3119,14 +3119,14 @@ fetch c1 into c; if (b = 1) then leave c1_repeat; end if; -insert into t2 values (c); +insert into t4 values (c); until b = 1 end repeat; end; end if; if arg1 = 'b' then begin -declare c2 cursor for select a from t1 where not a % 2; +declare c2 cursor for select a from t3 where not a % 2; declare continue handler for not found set b = 1; set b = 0; open c2; @@ -3135,35 +3135,36 @@ fetch c2 into c; if (b = 1) then leave c2_repeat; end if; -insert into t2 values (c); +insert into t4 values (c); until b = 1 end repeat; end; end if; end| call bug12168('a')| -select * from t2| +select * from t4| a 1 3 -truncate t2| +truncate t4| call bug12168('b')| -select * from t2| +select * from t4| a 2 4 -truncate t2| +truncate t4| call bug12168('a')| -select * from t2| +select * from t4| a 1 3 -truncate t2| +truncate t4| call bug12168('b')| -select * from t2| +select * from t4| a 2 4 -truncate t2| +truncate t4| +drop table t3, t4| drop procedure if exists bug12168| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f3e7c3e07a0..abff597405b 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3934,20 +3934,20 @@ drop procedure p_bug11247| # --disable_warnings drop procedure if exists bug12168| -drop table if exists t1, t2| +drop table if exists t3, t4| --enable_warnings -create table t1 (a int)| -insert into t1 values (1),(2),(3),(4)| +create table t3 (a int)| +insert into t3 values (1),(2),(3),(4)| -create table t2 (a int)| +create table t4 (a int)| create procedure bug12168(arg1 char(1)) begin declare b, c integer; if arg1 = 'a' then begin - declare c1 cursor for select a from t1 where a % 2; + declare c1 cursor for select a from t3 where a % 2; declare continue handler for not found set b = 1; set b = 0; open c1; @@ -3957,14 +3957,14 @@ begin leave c1_repeat; end if; - insert into t2 values (c); + insert into t4 values (c); until b = 1 end repeat; end; end if; if arg1 = 'b' then begin - declare c2 cursor for select a from t1 where not a % 2; + declare c2 cursor for select a from t3 where not a % 2; declare continue handler for not found set b = 1; set b = 0; open c2; @@ -3974,7 +3974,7 @@ begin leave c2_repeat; end if; - insert into t2 values (c); + insert into t4 values (c); until b = 1 end repeat; end; @@ -3982,17 +3982,18 @@ begin end| call bug12168('a')| -select * from t2| -truncate t2| +select * from t4| +truncate t4| call bug12168('b')| -select * from t2| -truncate t2| +select * from t4| +truncate t4| call bug12168('a')| -select * from t2| -truncate t2| +select * from t4| +truncate t4| call bug12168('b')| -select * from t2| -truncate t2| +select * from t4| +truncate t4| +drop table t3, t4| drop procedure if exists bug12168| # From f34398ba65d41528b1f4b0c94187f968d1131926 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Wed, 24 Aug 2005 11:14:41 +0200 Subject: [PATCH 217/230] BUG#12532: Fix for the case when my_malloc is macro --- sql/log_event.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 9e8c0695b90..c0a06bf5dab 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1328,14 +1328,19 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } } +#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + time_zone_len + 1 + - data_len + 1 -#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - + QUERY_CACHE_FLAGS_SIZE + - db_len + 1 + data_len + 1 + + QUERY_CACHE_FLAGS_SIZE + + db_len + 1, + MYF(MY_WME)))) +#else + if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + data_len + 1, + MYF(MY_WME)))) #endif - , MYF(MY_WME)))) DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { From 254db48603d33df86f2e2e318bd0c533748986c3 Mon Sep 17 00:00:00 2001 From: "georg@lmy002.wdf.sap.corp" <> Date: Wed, 24 Aug 2005 12:51:00 +0200 Subject: [PATCH 218/230] Fix for bug#5501 (SHOW TABLE STATUS should show "view" in upper case) --- mysql-test/r/information_schema.result | 2 +- mysql-test/r/view.result | 12 ++++++------ sql/sql_show.cc | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 404a20d5e9e..029e06ed1ba 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -152,7 +152,7 @@ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length I t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL t3 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL t5 MyISAM 10 Fixed 1 7 7 # 2048 0 11 # # NULL latin1_swedish_ci NULL -v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view +v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW show full columns from t3 like "a%"; Field Type Collation Null Key Default Extra Privileges Comment a int(11) NULL YES MUL NULL select,insert,update,references diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index f56c6558e4f..6467c080a17 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -150,12 +150,12 @@ v6 VIEW show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 MyISAM 10 Fixed 5 9 45 # 1024 0 NULL # # NULL latin1_swedish_ci NULL -v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view -v2 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view -v3 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view -v4 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view -v5 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view -v6 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view +v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW +v2 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW +v3 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW +v4 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW +v5 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW +v6 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW drop view v1,v2,v3,v4,v5,v6; create view v1 (c,d,e,f) as select a,b, a in (select a+2 from t1), a = all (select a from t1) from t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d1a968d2376..4a2315582fb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2210,7 +2210,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, else if (tables->view) { table->field[3]->store("VIEW", 4, cs); - table->field[20]->store("view", 4, cs); + table->field[20]->store("VIEW", 4, cs); } else { From 6fcc98ddb5bdaf062b8b04e24c048fd2fd90cf0c Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Wed, 24 Aug 2005 13:41:34 +0200 Subject: [PATCH 219/230] Increase version number (but leave status still at "beta"). --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 4aef78e5b18..5b3cfad6105 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.12-beta) +AM_INIT_AUTOMAKE(mysql, 5.0.13-beta) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -18,7 +18,7 @@ SHARED_LIB_VERSION=15:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=12 +NDB_VERSION_BUILD=13 NDB_VERSION_STATUS="beta" # Set all version vars based on $VERSION. How do we do this more elegant ? From 9f72d504b42d0e944bbb84a235075a29696f1358 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 24 Aug 2005 17:27:46 +0300 Subject: [PATCH 220/230] ha_innodb.cc: Fix bug #12779 : never give a row count estimate of 0 to the MySQL query optimizer, as then left join optimizer may beleive it KNOWS that the table is empty; note that this fix may change query optimization of many other queries where one table is empty; note that the proper fix would be to make the query optimizer to know that the row count estimates it receives really are just estimates, it cannot assume they are certain --- sql/ha_innodb.cc | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index bcd07198f5c..3ae56f13478 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4109,6 +4109,7 @@ ha_innobase::info( dict_table_t* ib_table; dict_index_t* index; ha_rows rec_per_key; + ib_longlong n_rows; ulong j; ulong i; @@ -4151,7 +4152,30 @@ ha_innobase::info( } if (flag & HA_STATUS_VARIABLE) { - records = (ha_rows)ib_table->stat_n_rows; + n_rows = ib_table->stat_n_rows; + + /* Because we do not protect stat_n_rows by any mutex in a + delete, it is theoretically possible that the value can be + smaller than zero! TODO: fix this race. + + The MySQL optimizer seems to assume in a left join that n_rows + is an accurate estimate if it is zero. Of course, it is not, + since we do not have any locks on the rows yet at this phase. + Since SHOW TABLE STATUS seems to call this function with the + HA_STATUS_TIME flag set, while the left join optizer does not + set that flag, we add one to a zero value if the flag is not + set. That way SHOW TABLE STATUS will show the best estimate, + while the optimizer never sees the table empty. */ + + if (n_rows < 0) { + n_rows = 0; + } + + if (n_rows == 0 && !(flag & HA_STATUS_TIME)) { + n_rows++; + } + + records = (ha_rows)n_rows; deleted = 0; data_file_length = ((ulonglong) ib_table->stat_clustered_index_size) From 4bedb3091c5b6869ea8611ca728dd7c1fdb03651 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 24 Aug 2005 18:05:54 +0300 Subject: [PATCH 221/230] subselect2.result: Update test result to reflect the fix of Bug #12779 : EXPLAIN SELECT of a subquery is now different --- mysql-test/r/subselect2.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index b04fec26c6f..148c670c589 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -120,9 +120,9 @@ DOCID DOCNAME DOCTYPEID FOLDERID AUTHOR CREATED TITLE SUBTITLE DOCABSTRACT PUBLI c373e9f5ad07993f3859444553544200 Last Discussion c373e9f5ad079174ff17444553544200 c373e9f5ad0796c0eca4444553544200 Goldilocks 2003-06-09 11:21:06 Title: Last Discussion NULL Setting new abstract and keeping doc checked out 2003-06-09 10:51:26 2003-06-09 10:51:26 NULL NULL NULL 03eea05112b845949f3fd03278b5fe43 2003-06-09 11:21:06 admin 0 NULL Discussion NULL NULL EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion'; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 system PRIMARY NULL NULL NULL 0 const row not found 1 PRIMARY t2 ALL DDOCTYPEID_IDX NULL NULL NULL 9 Using where 1 PRIMARY t4 eq_ref PRIMARY PRIMARY 32 test.t2.DOCTYPEID 1 +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 32 test.t2.DOCID 1 2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where 3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where 4 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where From 8e6aa0e7eacc22d061b1129fe8bf540414f6a036 Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Wed, 24 Aug 2005 19:37:27 +0300 Subject: [PATCH 222/230] Review fixes --- mysql-test/r/ctype_cp932.result | 3 +- mysql-test/r/rpl_drop_db.result | 1034 +------------------------------ mysql-test/t/ctype_cp932.test | 2 +- mysql-test/t/rpl_drop_db.test | 34 +- sql/sql_db.cc | 94 ++- 5 files changed, 84 insertions(+), 1083 deletions(-) diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result index 0711f251a07..d8221a58b9e 100644 --- a/mysql-test/r/ctype_cp932.result +++ b/mysql-test/r/ctype_cp932.result @@ -8581,9 +8581,8 @@ CREATE TABLE t1(f1 blob); PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; SET @var1= x'8300'; EXECUTE stmt1 USING @var1; -SHOW BINLOG EVENTS; +SHOW BINLOG EVENTS FROM 79; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 # Start 1 # Server ver: 4.1.15-debug-log, Binlog ver: 3 master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=95,COLLATION_CONNECTION=95,COLLATION_DATABASE=95,COLLATION_SERVER=8 master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1(f1 blob) master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=95,COLLATION_CONNECTION=95,COLLATION_DATABASE=95,COLLATION_SERVER=8 diff --git a/mysql-test/r/rpl_drop_db.result b/mysql-test/r/rpl_drop_db.result index 01a2af5341b..3d1dfba5b05 100644 --- a/mysql-test/r/rpl_drop_db.result +++ b/mysql-test/r/rpl_drop_db.result @@ -4,1029 +4,29 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -drop database if exists d1; -create database d1; -create table d1.t1 (n int); -insert into d1.t1 values (1); -select * from d1.t1 into outfile 'd1/f1.txt'; -create table d1.t2 (n int); -create table d1.t3 (n int); -drop database d1; -ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17) -use d1; +drop database if exists mysqltest; +create database mysqltest; +create table mysqltest.t1 (n int); +insert into mysqltest.t1 values (1); +select * from mysqltest.t1 into outfile 'mysqltest/f1.txt'; +create table mysqltest.t2 (n int); +create table mysqltest.t3 (n int); +drop database mysqltest; +ERROR HY000: Error dropping database (can't rmdir './mysqltest/', errno: 17) +use mysqltest; show tables; -Tables_in_d1 -create table d1.t1000(n int); -create table d1.t999(n int); -create table d1.t998(n int); -create table d1.t997(n int); -create table d1.t996(n int); -create table d1.t995(n int); -create table d1.t994(n int); -create table d1.t993(n int); -create table d1.t992(n int); -create table d1.t991(n int); -create table d1.t990(n int); -create table d1.t989(n int); -create table d1.t988(n int); -create table d1.t987(n int); -create table d1.t986(n int); -create table d1.t985(n int); -create table d1.t984(n int); -create table d1.t983(n int); -create table d1.t982(n int); -create table d1.t981(n int); -create table d1.t980(n int); -create table d1.t979(n int); -create table d1.t978(n int); -create table d1.t977(n int); -create table d1.t976(n int); -create table d1.t975(n int); -create table d1.t974(n int); -create table d1.t973(n int); -create table d1.t972(n int); -create table d1.t971(n int); -create table d1.t970(n int); -create table d1.t969(n int); -create table d1.t968(n int); -create table d1.t967(n int); -create table d1.t966(n int); -create table d1.t965(n int); -create table d1.t964(n int); -create table d1.t963(n int); -create table d1.t962(n int); -create table d1.t961(n int); -create table d1.t960(n int); -create table d1.t959(n int); -create table d1.t958(n int); -create table d1.t957(n int); -create table d1.t956(n int); -create table d1.t955(n int); -create table d1.t954(n int); -create table d1.t953(n int); -create table d1.t952(n int); -create table d1.t951(n int); -create table d1.t950(n int); -create table d1.t949(n int); -create table d1.t948(n int); -create table d1.t947(n int); -create table d1.t946(n int); -create table d1.t945(n int); -create table d1.t944(n int); -create table d1.t943(n int); -create table d1.t942(n int); -create table d1.t941(n int); -create table d1.t940(n int); -create table d1.t939(n int); -create table d1.t938(n int); -create table d1.t937(n int); -create table d1.t936(n int); -create table d1.t935(n int); -create table d1.t934(n int); -create table d1.t933(n int); -create table d1.t932(n int); -create table d1.t931(n int); -create table d1.t930(n int); -create table d1.t929(n int); -create table d1.t928(n int); -create table d1.t927(n int); -create table d1.t926(n int); -create table d1.t925(n int); -create table d1.t924(n int); -create table d1.t923(n int); -create table d1.t922(n int); -create table d1.t921(n int); -create table d1.t920(n int); -create table d1.t919(n int); -create table d1.t918(n int); -create table d1.t917(n int); -create table d1.t916(n int); -create table d1.t915(n int); -create table d1.t914(n int); -create table d1.t913(n int); -create table d1.t912(n int); -create table d1.t911(n int); -create table d1.t910(n int); -create table d1.t909(n int); -create table d1.t908(n int); -create table d1.t907(n int); -create table d1.t906(n int); -create table d1.t905(n int); -create table d1.t904(n int); -create table d1.t903(n int); -create table d1.t902(n int); -create table d1.t901(n int); -create table d1.t900(n int); -create table d1.t899(n int); -create table d1.t898(n int); -create table d1.t897(n int); -create table d1.t896(n int); -create table d1.t895(n int); -create table d1.t894(n int); -create table d1.t893(n int); -create table d1.t892(n int); -create table d1.t891(n int); -create table d1.t890(n int); -create table d1.t889(n int); -create table d1.t888(n int); -create table d1.t887(n int); -create table d1.t886(n int); -create table d1.t885(n int); -create table d1.t884(n int); -create table d1.t883(n int); -create table d1.t882(n int); -create table d1.t881(n int); -create table d1.t880(n int); -create table d1.t879(n int); -create table d1.t878(n int); -create table d1.t877(n int); -create table d1.t876(n int); -create table d1.t875(n int); -create table d1.t874(n int); -create table d1.t873(n int); -create table d1.t872(n int); -create table d1.t871(n int); -create table d1.t870(n int); -create table d1.t869(n int); -create table d1.t868(n int); -create table d1.t867(n int); -create table d1.t866(n int); -create table d1.t865(n int); -create table d1.t864(n int); -create table d1.t863(n int); -create table d1.t862(n int); -create table d1.t861(n int); -create table d1.t860(n int); -create table d1.t859(n int); -create table d1.t858(n int); -create table d1.t857(n int); -create table d1.t856(n int); -create table d1.t855(n int); -create table d1.t854(n int); -create table d1.t853(n int); -create table d1.t852(n int); -create table d1.t851(n int); -create table d1.t850(n int); -create table d1.t849(n int); -create table d1.t848(n int); -create table d1.t847(n int); -create table d1.t846(n int); -create table d1.t845(n int); -create table d1.t844(n int); -create table d1.t843(n int); -create table d1.t842(n int); -create table d1.t841(n int); -create table d1.t840(n int); -create table d1.t839(n int); -create table d1.t838(n int); -create table d1.t837(n int); -create table d1.t836(n int); -create table d1.t835(n int); -create table d1.t834(n int); -create table d1.t833(n int); -create table d1.t832(n int); -create table d1.t831(n int); -create table d1.t830(n int); -create table d1.t829(n int); -create table d1.t828(n int); -create table d1.t827(n int); -create table d1.t826(n int); -create table d1.t825(n int); -create table d1.t824(n int); -create table d1.t823(n int); -create table d1.t822(n int); -create table d1.t821(n int); -create table d1.t820(n int); -create table d1.t819(n int); -create table d1.t818(n int); -create table d1.t817(n int); -create table d1.t816(n int); -create table d1.t815(n int); -create table d1.t814(n int); -create table d1.t813(n int); -create table d1.t812(n int); -create table d1.t811(n int); -create table d1.t810(n int); -create table d1.t809(n int); -create table d1.t808(n int); -create table d1.t807(n int); -create table d1.t806(n int); -create table d1.t805(n int); -create table d1.t804(n int); -create table d1.t803(n int); -create table d1.t802(n int); -create table d1.t801(n int); -create table d1.t800(n int); -create table d1.t799(n int); -create table d1.t798(n int); -create table d1.t797(n int); -create table d1.t796(n int); -create table d1.t795(n int); -create table d1.t794(n int); -create table d1.t793(n int); -create table d1.t792(n int); -create table d1.t791(n int); -create table d1.t790(n int); -create table d1.t789(n int); -create table d1.t788(n int); -create table d1.t787(n int); -create table d1.t786(n int); -create table d1.t785(n int); -create table d1.t784(n int); -create table d1.t783(n int); -create table d1.t782(n int); -create table d1.t781(n int); -create table d1.t780(n int); -create table d1.t779(n int); -create table d1.t778(n int); -create table d1.t777(n int); -create table d1.t776(n int); -create table d1.t775(n int); -create table d1.t774(n int); -create table d1.t773(n int); -create table d1.t772(n int); -create table d1.t771(n int); -create table d1.t770(n int); -create table d1.t769(n int); -create table d1.t768(n int); -create table d1.t767(n int); -create table d1.t766(n int); -create table d1.t765(n int); -create table d1.t764(n int); -create table d1.t763(n int); -create table d1.t762(n int); -create table d1.t761(n int); -create table d1.t760(n int); -create table d1.t759(n int); -create table d1.t758(n int); -create table d1.t757(n int); -create table d1.t756(n int); -create table d1.t755(n int); -create table d1.t754(n int); -create table d1.t753(n int); -create table d1.t752(n int); -create table d1.t751(n int); -create table d1.t750(n int); -create table d1.t749(n int); -create table d1.t748(n int); -create table d1.t747(n int); -create table d1.t746(n int); -create table d1.t745(n int); -create table d1.t744(n int); -create table d1.t743(n int); -create table d1.t742(n int); -create table d1.t741(n int); -create table d1.t740(n int); -create table d1.t739(n int); -create table d1.t738(n int); -create table d1.t737(n int); -create table d1.t736(n int); -create table d1.t735(n int); -create table d1.t734(n int); -create table d1.t733(n int); -create table d1.t732(n int); -create table d1.t731(n int); -create table d1.t730(n int); -create table d1.t729(n int); -create table d1.t728(n int); -create table d1.t727(n int); -create table d1.t726(n int); -create table d1.t725(n int); -create table d1.t724(n int); -create table d1.t723(n int); -create table d1.t722(n int); -create table d1.t721(n int); -create table d1.t720(n int); -create table d1.t719(n int); -create table d1.t718(n int); -create table d1.t717(n int); -create table d1.t716(n int); -create table d1.t715(n int); -create table d1.t714(n int); -create table d1.t713(n int); -create table d1.t712(n int); -create table d1.t711(n int); -create table d1.t710(n int); -create table d1.t709(n int); -create table d1.t708(n int); -create table d1.t707(n int); -create table d1.t706(n int); -create table d1.t705(n int); -create table d1.t704(n int); -create table d1.t703(n int); -create table d1.t702(n int); -create table d1.t701(n int); -create table d1.t700(n int); -create table d1.t699(n int); -create table d1.t698(n int); -create table d1.t697(n int); -create table d1.t696(n int); -create table d1.t695(n int); -create table d1.t694(n int); -create table d1.t693(n int); -create table d1.t692(n int); -create table d1.t691(n int); -create table d1.t690(n int); -create table d1.t689(n int); -create table d1.t688(n int); -create table d1.t687(n int); -create table d1.t686(n int); -create table d1.t685(n int); -create table d1.t684(n int); -create table d1.t683(n int); -create table d1.t682(n int); -create table d1.t681(n int); -create table d1.t680(n int); -create table d1.t679(n int); -create table d1.t678(n int); -create table d1.t677(n int); -create table d1.t676(n int); -create table d1.t675(n int); -create table d1.t674(n int); -create table d1.t673(n int); -create table d1.t672(n int); -create table d1.t671(n int); -create table d1.t670(n int); -create table d1.t669(n int); -create table d1.t668(n int); -create table d1.t667(n int); -create table d1.t666(n int); -create table d1.t665(n int); -create table d1.t664(n int); -create table d1.t663(n int); -create table d1.t662(n int); -create table d1.t661(n int); -create table d1.t660(n int); -create table d1.t659(n int); -create table d1.t658(n int); -create table d1.t657(n int); -create table d1.t656(n int); -create table d1.t655(n int); -create table d1.t654(n int); -create table d1.t653(n int); -create table d1.t652(n int); -create table d1.t651(n int); -create table d1.t650(n int); -create table d1.t649(n int); -create table d1.t648(n int); -create table d1.t647(n int); -create table d1.t646(n int); -create table d1.t645(n int); -create table d1.t644(n int); -create table d1.t643(n int); -create table d1.t642(n int); -create table d1.t641(n int); -create table d1.t640(n int); -create table d1.t639(n int); -create table d1.t638(n int); -create table d1.t637(n int); -create table d1.t636(n int); -create table d1.t635(n int); -create table d1.t634(n int); -create table d1.t633(n int); -create table d1.t632(n int); -create table d1.t631(n int); -create table d1.t630(n int); -create table d1.t629(n int); -create table d1.t628(n int); -create table d1.t627(n int); -create table d1.t626(n int); -create table d1.t625(n int); -create table d1.t624(n int); -create table d1.t623(n int); -create table d1.t622(n int); -create table d1.t621(n int); -create table d1.t620(n int); -create table d1.t619(n int); -create table d1.t618(n int); -create table d1.t617(n int); -create table d1.t616(n int); -create table d1.t615(n int); -create table d1.t614(n int); -create table d1.t613(n int); -create table d1.t612(n int); -create table d1.t611(n int); -create table d1.t610(n int); -create table d1.t609(n int); -create table d1.t608(n int); -create table d1.t607(n int); -create table d1.t606(n int); -create table d1.t605(n int); -create table d1.t604(n int); -create table d1.t603(n int); -create table d1.t602(n int); -create table d1.t601(n int); -create table d1.t600(n int); -create table d1.t599(n int); -create table d1.t598(n int); -create table d1.t597(n int); -create table d1.t596(n int); -create table d1.t595(n int); -create table d1.t594(n int); -create table d1.t593(n int); -create table d1.t592(n int); -create table d1.t591(n int); -create table d1.t590(n int); -create table d1.t589(n int); -create table d1.t588(n int); -create table d1.t587(n int); -create table d1.t586(n int); -create table d1.t585(n int); -create table d1.t584(n int); -create table d1.t583(n int); -create table d1.t582(n int); -create table d1.t581(n int); -create table d1.t580(n int); -create table d1.t579(n int); -create table d1.t578(n int); -create table d1.t577(n int); -create table d1.t576(n int); -create table d1.t575(n int); -create table d1.t574(n int); -create table d1.t573(n int); -create table d1.t572(n int); -create table d1.t571(n int); -create table d1.t570(n int); -create table d1.t569(n int); -create table d1.t568(n int); -create table d1.t567(n int); -create table d1.t566(n int); -create table d1.t565(n int); -create table d1.t564(n int); -create table d1.t563(n int); -create table d1.t562(n int); -create table d1.t561(n int); -create table d1.t560(n int); -create table d1.t559(n int); -create table d1.t558(n int); -create table d1.t557(n int); -create table d1.t556(n int); -create table d1.t555(n int); -create table d1.t554(n int); -create table d1.t553(n int); -create table d1.t552(n int); -create table d1.t551(n int); -create table d1.t550(n int); -create table d1.t549(n int); -create table d1.t548(n int); -create table d1.t547(n int); -create table d1.t546(n int); -create table d1.t545(n int); -create table d1.t544(n int); -create table d1.t543(n int); -create table d1.t542(n int); -create table d1.t541(n int); -create table d1.t540(n int); -create table d1.t539(n int); -create table d1.t538(n int); -create table d1.t537(n int); -create table d1.t536(n int); -create table d1.t535(n int); -create table d1.t534(n int); -create table d1.t533(n int); -create table d1.t532(n int); -create table d1.t531(n int); -create table d1.t530(n int); -create table d1.t529(n int); -create table d1.t528(n int); -create table d1.t527(n int); -create table d1.t526(n int); -create table d1.t525(n int); -create table d1.t524(n int); -create table d1.t523(n int); -create table d1.t522(n int); -create table d1.t521(n int); -create table d1.t520(n int); -create table d1.t519(n int); -create table d1.t518(n int); -create table d1.t517(n int); -create table d1.t516(n int); -create table d1.t515(n int); -create table d1.t514(n int); -create table d1.t513(n int); -create table d1.t512(n int); -create table d1.t511(n int); -create table d1.t510(n int); -create table d1.t509(n int); -create table d1.t508(n int); -create table d1.t507(n int); -create table d1.t506(n int); -create table d1.t505(n int); -create table d1.t504(n int); -create table d1.t503(n int); -create table d1.t502(n int); -create table d1.t501(n int); -create table d1.t500(n int); -create table d1.t499(n int); -create table d1.t498(n int); -create table d1.t497(n int); -create table d1.t496(n int); -create table d1.t495(n int); -create table d1.t494(n int); -create table d1.t493(n int); -create table d1.t492(n int); -create table d1.t491(n int); -create table d1.t490(n int); -create table d1.t489(n int); -create table d1.t488(n int); -create table d1.t487(n int); -create table d1.t486(n int); -create table d1.t485(n int); -create table d1.t484(n int); -create table d1.t483(n int); -create table d1.t482(n int); -create table d1.t481(n int); -create table d1.t480(n int); -create table d1.t479(n int); -create table d1.t478(n int); -create table d1.t477(n int); -create table d1.t476(n int); -create table d1.t475(n int); -create table d1.t474(n int); -create table d1.t473(n int); -create table d1.t472(n int); -create table d1.t471(n int); -create table d1.t470(n int); -create table d1.t469(n int); -create table d1.t468(n int); -create table d1.t467(n int); -create table d1.t466(n int); -create table d1.t465(n int); -create table d1.t464(n int); -create table d1.t463(n int); -create table d1.t462(n int); -create table d1.t461(n int); -create table d1.t460(n int); -create table d1.t459(n int); -create table d1.t458(n int); -create table d1.t457(n int); -create table d1.t456(n int); -create table d1.t455(n int); -create table d1.t454(n int); -create table d1.t453(n int); -create table d1.t452(n int); -create table d1.t451(n int); -create table d1.t450(n int); -create table d1.t449(n int); -create table d1.t448(n int); -create table d1.t447(n int); -create table d1.t446(n int); -create table d1.t445(n int); -create table d1.t444(n int); -create table d1.t443(n int); -create table d1.t442(n int); -create table d1.t441(n int); -create table d1.t440(n int); -create table d1.t439(n int); -create table d1.t438(n int); -create table d1.t437(n int); -create table d1.t436(n int); -create table d1.t435(n int); -create table d1.t434(n int); -create table d1.t433(n int); -create table d1.t432(n int); -create table d1.t431(n int); -create table d1.t430(n int); -create table d1.t429(n int); -create table d1.t428(n int); -create table d1.t427(n int); -create table d1.t426(n int); -create table d1.t425(n int); -create table d1.t424(n int); -create table d1.t423(n int); -create table d1.t422(n int); -create table d1.t421(n int); -create table d1.t420(n int); -create table d1.t419(n int); -create table d1.t418(n int); -create table d1.t417(n int); -create table d1.t416(n int); -create table d1.t415(n int); -create table d1.t414(n int); -create table d1.t413(n int); -create table d1.t412(n int); -create table d1.t411(n int); -create table d1.t410(n int); -create table d1.t409(n int); -create table d1.t408(n int); -create table d1.t407(n int); -create table d1.t406(n int); -create table d1.t405(n int); -create table d1.t404(n int); -create table d1.t403(n int); -create table d1.t402(n int); -create table d1.t401(n int); -create table d1.t400(n int); -create table d1.t399(n int); -create table d1.t398(n int); -create table d1.t397(n int); -create table d1.t396(n int); -create table d1.t395(n int); -create table d1.t394(n int); -create table d1.t393(n int); -create table d1.t392(n int); -create table d1.t391(n int); -create table d1.t390(n int); -create table d1.t389(n int); -create table d1.t388(n int); -create table d1.t387(n int); -create table d1.t386(n int); -create table d1.t385(n int); -create table d1.t384(n int); -create table d1.t383(n int); -create table d1.t382(n int); -create table d1.t381(n int); -create table d1.t380(n int); -create table d1.t379(n int); -create table d1.t378(n int); -create table d1.t377(n int); -create table d1.t376(n int); -create table d1.t375(n int); -create table d1.t374(n int); -create table d1.t373(n int); -create table d1.t372(n int); -create table d1.t371(n int); -create table d1.t370(n int); -create table d1.t369(n int); -create table d1.t368(n int); -create table d1.t367(n int); -create table d1.t366(n int); -create table d1.t365(n int); -create table d1.t364(n int); -create table d1.t363(n int); -create table d1.t362(n int); -create table d1.t361(n int); -create table d1.t360(n int); -create table d1.t359(n int); -create table d1.t358(n int); -create table d1.t357(n int); -create table d1.t356(n int); -create table d1.t355(n int); -create table d1.t354(n int); -create table d1.t353(n int); -create table d1.t352(n int); -create table d1.t351(n int); -create table d1.t350(n int); -create table d1.t349(n int); -create table d1.t348(n int); -create table d1.t347(n int); -create table d1.t346(n int); -create table d1.t345(n int); -create table d1.t344(n int); -create table d1.t343(n int); -create table d1.t342(n int); -create table d1.t341(n int); -create table d1.t340(n int); -create table d1.t339(n int); -create table d1.t338(n int); -create table d1.t337(n int); -create table d1.t336(n int); -create table d1.t335(n int); -create table d1.t334(n int); -create table d1.t333(n int); -create table d1.t332(n int); -create table d1.t331(n int); -create table d1.t330(n int); -create table d1.t329(n int); -create table d1.t328(n int); -create table d1.t327(n int); -create table d1.t326(n int); -create table d1.t325(n int); -create table d1.t324(n int); -create table d1.t323(n int); -create table d1.t322(n int); -create table d1.t321(n int); -create table d1.t320(n int); -create table d1.t319(n int); -create table d1.t318(n int); -create table d1.t317(n int); -create table d1.t316(n int); -create table d1.t315(n int); -create table d1.t314(n int); -create table d1.t313(n int); -create table d1.t312(n int); -create table d1.t311(n int); -create table d1.t310(n int); -create table d1.t309(n int); -create table d1.t308(n int); -create table d1.t307(n int); -create table d1.t306(n int); -create table d1.t305(n int); -create table d1.t304(n int); -create table d1.t303(n int); -create table d1.t302(n int); -create table d1.t301(n int); -create table d1.t300(n int); -create table d1.t299(n int); -create table d1.t298(n int); -create table d1.t297(n int); -create table d1.t296(n int); -create table d1.t295(n int); -create table d1.t294(n int); -create table d1.t293(n int); -create table d1.t292(n int); -create table d1.t291(n int); -create table d1.t290(n int); -create table d1.t289(n int); -create table d1.t288(n int); -create table d1.t287(n int); -create table d1.t286(n int); -create table d1.t285(n int); -create table d1.t284(n int); -create table d1.t283(n int); -create table d1.t282(n int); -create table d1.t281(n int); -create table d1.t280(n int); -create table d1.t279(n int); -create table d1.t278(n int); -create table d1.t277(n int); -create table d1.t276(n int); -create table d1.t275(n int); -create table d1.t274(n int); -create table d1.t273(n int); -create table d1.t272(n int); -create table d1.t271(n int); -create table d1.t270(n int); -create table d1.t269(n int); -create table d1.t268(n int); -create table d1.t267(n int); -create table d1.t266(n int); -create table d1.t265(n int); -create table d1.t264(n int); -create table d1.t263(n int); -create table d1.t262(n int); -create table d1.t261(n int); -create table d1.t260(n int); -create table d1.t259(n int); -create table d1.t258(n int); -create table d1.t257(n int); -create table d1.t256(n int); -create table d1.t255(n int); -create table d1.t254(n int); -create table d1.t253(n int); -create table d1.t252(n int); -create table d1.t251(n int); -create table d1.t250(n int); -create table d1.t249(n int); -create table d1.t248(n int); -create table d1.t247(n int); -create table d1.t246(n int); -create table d1.t245(n int); -create table d1.t244(n int); -create table d1.t243(n int); -create table d1.t242(n int); -create table d1.t241(n int); -create table d1.t240(n int); -create table d1.t239(n int); -create table d1.t238(n int); -create table d1.t237(n int); -create table d1.t236(n int); -create table d1.t235(n int); -create table d1.t234(n int); -create table d1.t233(n int); -create table d1.t232(n int); -create table d1.t231(n int); -create table d1.t230(n int); -create table d1.t229(n int); -create table d1.t228(n int); -create table d1.t227(n int); -create table d1.t226(n int); -create table d1.t225(n int); -create table d1.t224(n int); -create table d1.t223(n int); -create table d1.t222(n int); -create table d1.t221(n int); -create table d1.t220(n int); -create table d1.t219(n int); -create table d1.t218(n int); -create table d1.t217(n int); -create table d1.t216(n int); -create table d1.t215(n int); -create table d1.t214(n int); -create table d1.t213(n int); -create table d1.t212(n int); -create table d1.t211(n int); -create table d1.t210(n int); -create table d1.t209(n int); -create table d1.t208(n int); -create table d1.t207(n int); -create table d1.t206(n int); -create table d1.t205(n int); -create table d1.t204(n int); -create table d1.t203(n int); -create table d1.t202(n int); -create table d1.t201(n int); -create table d1.t200(n int); -create table d1.t199(n int); -create table d1.t198(n int); -create table d1.t197(n int); -create table d1.t196(n int); -create table d1.t195(n int); -create table d1.t194(n int); -create table d1.t193(n int); -create table d1.t192(n int); -create table d1.t191(n int); -create table d1.t190(n int); -create table d1.t189(n int); -create table d1.t188(n int); -create table d1.t187(n int); -create table d1.t186(n int); -create table d1.t185(n int); -create table d1.t184(n int); -create table d1.t183(n int); -create table d1.t182(n int); -create table d1.t181(n int); -create table d1.t180(n int); -create table d1.t179(n int); -create table d1.t178(n int); -create table d1.t177(n int); -create table d1.t176(n int); -create table d1.t175(n int); -create table d1.t174(n int); -create table d1.t173(n int); -create table d1.t172(n int); -create table d1.t171(n int); -create table d1.t170(n int); -create table d1.t169(n int); -create table d1.t168(n int); -create table d1.t167(n int); -create table d1.t166(n int); -create table d1.t165(n int); -create table d1.t164(n int); -create table d1.t163(n int); -create table d1.t162(n int); -create table d1.t161(n int); -create table d1.t160(n int); -create table d1.t159(n int); -create table d1.t158(n int); -create table d1.t157(n int); -create table d1.t156(n int); -create table d1.t155(n int); -create table d1.t154(n int); -create table d1.t153(n int); -create table d1.t152(n int); -create table d1.t151(n int); -create table d1.t150(n int); -create table d1.t149(n int); -create table d1.t148(n int); -create table d1.t147(n int); -create table d1.t146(n int); -create table d1.t145(n int); -create table d1.t144(n int); -create table d1.t143(n int); -create table d1.t142(n int); -create table d1.t141(n int); -create table d1.t140(n int); -create table d1.t139(n int); -create table d1.t138(n int); -create table d1.t137(n int); -create table d1.t136(n int); -create table d1.t135(n int); -create table d1.t134(n int); -create table d1.t133(n int); -create table d1.t132(n int); -create table d1.t131(n int); -create table d1.t130(n int); -create table d1.t129(n int); -create table d1.t128(n int); -create table d1.t127(n int); -create table d1.t126(n int); -create table d1.t125(n int); -create table d1.t124(n int); -create table d1.t123(n int); -create table d1.t122(n int); -create table d1.t121(n int); -create table d1.t120(n int); -create table d1.t119(n int); -create table d1.t118(n int); -create table d1.t117(n int); -create table d1.t116(n int); -create table d1.t115(n int); -create table d1.t114(n int); -create table d1.t113(n int); -create table d1.t112(n int); -create table d1.t111(n int); -create table d1.t110(n int); -create table d1.t109(n int); -create table d1.t108(n int); -create table d1.t107(n int); -create table d1.t106(n int); -create table d1.t105(n int); -create table d1.t104(n int); -create table d1.t103(n int); -create table d1.t102(n int); -create table d1.t101(n int); -create table d1.t100(n int); -create table d1.t99(n int); -create table d1.t98(n int); -create table d1.t97(n int); -create table d1.t96(n int); -create table d1.t95(n int); -create table d1.t94(n int); -create table d1.t93(n int); -create table d1.t92(n int); -create table d1.t91(n int); -create table d1.t90(n int); -create table d1.t89(n int); -create table d1.t88(n int); -create table d1.t87(n int); -create table d1.t86(n int); -create table d1.t85(n int); -create table d1.t84(n int); -create table d1.t83(n int); -create table d1.t82(n int); -create table d1.t81(n int); -create table d1.t80(n int); -create table d1.t79(n int); -create table d1.t78(n int); -create table d1.t77(n int); -create table d1.t76(n int); -create table d1.t75(n int); -create table d1.t74(n int); -create table d1.t73(n int); -create table d1.t72(n int); -create table d1.t71(n int); -create table d1.t70(n int); -create table d1.t69(n int); -create table d1.t68(n int); -create table d1.t67(n int); -create table d1.t66(n int); -create table d1.t65(n int); -create table d1.t64(n int); -create table d1.t63(n int); -create table d1.t62(n int); -create table d1.t61(n int); -create table d1.t60(n int); -create table d1.t59(n int); -create table d1.t58(n int); -create table d1.t57(n int); -create table d1.t56(n int); -create table d1.t55(n int); -create table d1.t54(n int); -create table d1.t53(n int); -create table d1.t52(n int); -create table d1.t51(n int); -create table d1.t50(n int); -create table d1.t49(n int); -create table d1.t48(n int); -create table d1.t47(n int); -create table d1.t46(n int); -create table d1.t45(n int); -create table d1.t44(n int); -create table d1.t43(n int); -create table d1.t42(n int); -create table d1.t41(n int); -create table d1.t40(n int); -create table d1.t39(n int); -create table d1.t38(n int); -create table d1.t37(n int); -create table d1.t36(n int); -create table d1.t35(n int); -create table d1.t34(n int); -create table d1.t33(n int); -create table d1.t32(n int); -create table d1.t31(n int); -create table d1.t30(n int); -create table d1.t29(n int); -create table d1.t28(n int); -create table d1.t27(n int); -create table d1.t26(n int); -create table d1.t25(n int); -create table d1.t24(n int); -create table d1.t23(n int); -create table d1.t22(n int); -create table d1.t21(n int); -create table d1.t20(n int); -create table d1.t19(n int); -create table d1.t18(n int); -create table d1.t17(n int); -create table d1.t16(n int); -create table d1.t15(n int); -create table d1.t14(n int); -create table d1.t13(n int); -create table d1.t12(n int); -create table d1.t11(n int); -create table d1.t10(n int); -create table d1.t9(n int); -create table d1.t8(n int); -create table d1.t7(n int); -create table d1.t6(n int); -create table d1.t5(n int); -create table d1.t4(n int); -create table d1.t3(n int); -create table d1.t2(n int); -create table d1.t1(n int); -drop database d1; -ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17) -use d1; +Tables_in_mysqltest +drop database mysqltest; +ERROR HY000: Error dropping database (can't rmdir './mysqltest/', errno: 17) +use mysqltest; show tables; -Tables_in_d1 +Tables_in_mysqltest use test; create table t1 (n int); insert into t1 values (1234); -use d1; +use mysqltest; show tables; -Tables_in_d1 +Tables_in_mysqltest use test; select * from t1; n diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index 8f471ebb979..8e6c53af095 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -419,7 +419,7 @@ SET @var1= x'8300'; # exercise this code from mysql-test-run. EXECUTE stmt1 USING @var1; --replace_column 2 # 5 # -SHOW BINLOG EVENTS; +SHOW BINLOG EVENTS FROM 79; SELECT HEX(f1) FROM t1; DROP table t1; # end test for bug#11338 diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test index 71dc22f705f..7b4a56910d6 100644 --- a/mysql-test/t/rpl_drop_db.test +++ b/mysql-test/t/rpl_drop_db.test @@ -5,30 +5,32 @@ connection master; --disable_warnings -drop database if exists d1; +drop database if exists mysqltest; --enable_warnings -create database d1; -create table d1.t1 (n int); -insert into d1.t1 values (1); -select * from d1.t1 into outfile 'd1/f1.txt'; -create table d1.t2 (n int); -create table d1.t3 (n int); +create database mysqltest; +create table mysqltest.t1 (n int); +insert into mysqltest.t1 values (1); +select * from mysqltest.t1 into outfile 'mysqltest/f1.txt'; +create table mysqltest.t2 (n int); +create table mysqltest.t3 (n int); --error 1010 -drop database d1; -use d1; +drop database mysqltest; +use mysqltest; show tables; # test the branch of the code that deals with the query buffer overflow -let $1=1000; +disable_query_log; +let $1=50; while ($1) { - eval create table d1.t$1(n int); + eval create table mysqltest.mysql_test_long_table_name$1 (n int); dec $1; } +enable_query_log; --error 1010 -drop database d1; -use d1; +drop database mysqltest; +use mysqltest; show tables; use test; create table t1 (n int); @@ -36,7 +38,7 @@ insert into t1 values (1234); sync_slave_with_master; connection slave; -use d1; +use mysqltest; show tables; use test; select * from t1; @@ -48,5 +50,7 @@ sync_slave_with_master; #cleanup connection slave; stop slave; -system rm -rf var/master-data/d1; +system rm -rf var/master-data/mysqltest; + +# End of 4.1 tests diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 6dcc7be0904..a279fae93a9 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -33,12 +33,8 @@ static TYPELIB deletable_extentions= static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, const char *path, uint level, - TABLE_LIST** dropped_tables); + TABLE_LIST **dropped_tables); - -static inline void write_to_binlog(THD* thd, char* query, uint q_len, - char* db, uint db_len); - /* Database options hash */ static HASH dboptions; static my_bool dboptions_init= 0; @@ -56,6 +52,7 @@ typedef struct my_dbopt_st /* Function we use in the creation of our hash to get key. */ + static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, my_bool not_used __attribute__((unused))) { @@ -63,17 +60,19 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, return (byte*) opt->name; } + /* - Helper function to write a query to binlog used by mysql_rm_db() - */ -static inline void write_to_binlog(THD* thd, char* query, uint q_len, - char* db, uint db_len) + Helper function to write a query to binlog used by mysql_rm_db() +*/ + +static inline void write_to_binlog(THD *thd, char *query, uint q_len, + char *db, uint db_len) { - Query_log_event qinfo(thd, query, q_len, 0, 0); - qinfo.error_code= 0; - qinfo.db= db; - qinfo.db_len= db_len; - mysql_bin_log.write(&qinfo); + Query_log_event qinfo(thd, query, q_len, 0, 0); + qinfo.error_code= 0; + qinfo.db= db; + qinfo.db_len= db_len; + mysql_bin_log.write(&qinfo); } @@ -644,7 +643,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) error= -1; if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0, - &dropped_tables)) >= 0) + &dropped_tables)) >= 0) { ha_drop_database(path); query_cache_invalidate1(db); @@ -696,42 +695,40 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } else if (mysql_bin_log.is_open()) { - char* query= thd->alloc(MAX_DROP_TABLE_Q_LEN); + char *query, *query_pos, *query_end, *query_data_start; + TABLE_LIST *tbl; + uint db_len; + + if (!(query= thd->alloc(MAX_DROP_TABLE_Q_LEN))) + goto exit; /* not much else we can do */ + query_pos= query_data_start= strmov(query,"drop table "); + query_end= query + MAX_DROP_TABLE_Q_LEN; + db_len= strlen(db); - if (!query) - goto exit; /* not much else we can do */ - char* p= strmov(query,"drop table "); - char* p_end= query + MAX_DROP_TABLE_Q_LEN; - TABLE_LIST* tbl; - bool last_query_needs_write= 0; - uint db_len= strlen(db); - - for (tbl= dropped_tables;tbl;tbl= tbl->next) - { - if (!tbl->was_dropped) - continue; + for (tbl= dropped_tables; tbl; tbl= tbl->next) + { + uint tbl_name_len; + if (!tbl->was_dropped) + continue; - /* 3 for the quotes and the comma*/ - uint tbl_name_len= strlen(tbl->real_name) + 3; - if (p + tbl_name_len + 1 >= p_end) - { - *--p= 0; /* kill , */ - write_to_binlog(thd, query, p - query, db, db_len); - p= query + 11; /* reuse the initial "drop table" */ - } + /* 3 for the quotes and the comma*/ + tbl_name_len= strlen(tbl->real_name) + 3; + if (query_pos + tbl_name_len + 1 >= query_end) + { + write_to_binlog(thd, query, query_pos -1 - query, db, db_len); + query_pos= query_data_start; + } - *p++ = '`'; - p= strmov(p,tbl->real_name); - *p++ = '`'; - *p++ = ','; - last_query_needs_write= 1; - } + *query_pos++ = '`'; + query_pos= strmov(query_pos,tbl->real_name); + *query_pos++ = '`'; + *query_pos++ = ','; + } - if (last_query_needs_write) - { - *--p= 0; - write_to_binlog(thd, query, p - query, db, db_len); - } + if (query_pos != query_data_start) + { + write_to_binlog(thd, query, query_pos -1 - query, db, db_len); + } } exit: @@ -777,7 +774,8 @@ exit2: */ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, - const char *org_path, uint level, TABLE_LIST** dropped_tables) + const char *org_path, uint level, + TABLE_LIST **dropped_tables) { long deleted=0; ulong found_other_files=0; From 2a880905c48c897e67e8f75999b30f5b7f9875e6 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Wed, 24 Aug 2005 23:44:42 +0400 Subject: [PATCH 223/230] Correction of fix for bug #12280 "Triggers: crash if flush tables". We should not assume that "thd" argument of reload_acl_and_cache() is non-zero. Failure to do so will cause server to crash when one sends SIGHUP to it. --- sql/sql_parse.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 70920b07a97..c86b7eba024 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6517,7 +6517,7 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields) SYNOPSIS reload_acl_and_cache() - thd Thread handler + thd Thread handler (can be NULL!) options What should be reset/reloaded (tables, privileges, slave...) tables Tables to flush (if any) @@ -6539,7 +6539,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, select_errors=0; /* Write if more errors */ bool tmp_write_to_binlog= 1; - if (thd->in_sub_stmt) + if (thd && thd->in_sub_stmt) { my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH"); return 1; From bb7289b7d20c86caaa5e917dd541070a5631ebf0 Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Thu, 25 Aug 2005 00:21:47 +0300 Subject: [PATCH 224/230] Cleanups during review of new code Removed ASSERT that can obviously never be wrong --- sql/sql_base.cc | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a7f5fa3ce03..d742147db27 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2945,9 +2945,15 @@ find_field_in_tables(THD *thd, Item_ident *item, char name_buff[NAME_LEN+1]; TABLE_LIST *cur_table= first_table; TABLE_LIST *actual_table; - bool is_qualified= table_name && table_name[0]; - bool allow_rowid= is_qualified ? - TRUE : (cur_table && !cur_table->next_local); + bool allow_rowid; + + if (!table_name || !table_name[0]) + { + table_name= 0; // For easier test + db= 0; + } + + allow_rowid= table_name || (cur_table && !cur_table->next_local); if (item->cached_table) { @@ -3022,8 +3028,7 @@ find_field_in_tables(THD *thd, Item_ident *item, cur_table= cur_table->next_name_resolution_table) { Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name, - is_qualified ? table_name : NULL, - is_qualified ? db : NULL, + table_name, db, length, ref, (cur_table->table && test(cur_table->table->grant. @@ -3053,7 +3058,7 @@ find_field_in_tables(THD *thd, Item_ident *item, If we found a fully qualified field we return it directly as it can't have duplicates. */ - if (is_qualified && db) + if (db) return cur_field; if (found) @@ -3061,7 +3066,7 @@ find_field_in_tables(THD *thd, Item_ident *item, if (report_error == REPORT_ALL_ERRORS || report_error == IGNORE_EXCEPT_NON_UNIQUE) my_error(ER_NON_UNIQ_ERROR, MYF(0), - is_qualified ? item->full_name() : name, thd->where); + table_name ? item->full_name() : name, thd->where); return (Field*) 0; } found= cur_field; @@ -3078,7 +3083,7 @@ find_field_in_tables(THD *thd, Item_ident *item, and cur_table wouldn't be updated by the loop increment part, so it will be equal to the first table. */ - if (is_qualified && (cur_table == first_table) && + if (table_name && (cur_table == first_table) && (report_error == REPORT_ALL_ERRORS || report_error == REPORT_EXCEPT_NON_UNIQUE)) { @@ -3091,13 +3096,13 @@ find_field_in_tables(THD *thd, Item_ident *item, my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where); } else + { if (report_error == REPORT_ALL_ERRORS || report_error == REPORT_EXCEPT_NON_UNIQUE) my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where); else found= not_found_field; - - DBUG_ASSERT(!found || found == not_found_field); + } return found; } From 9e4a9e23c67dba556de37d4314e9fe26265ca4db Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 24 Aug 2005 15:50:58 -0700 Subject: [PATCH 225/230] Make SYSDATE() behave as in Oracle: always the current datetime, not the datetime of when the current statement began. This also makes SYSDATE() not safe in replication. (Bug #12562) --- mysql-test/r/func_time.result | 40 +++++++++++++++++++++ mysql-test/t/func_time.test | 52 +++++++++++++++++++++++++++ sql/item_timefunc.cc | 68 +++++++++++++++++++++++++++++++++-- sql/item_timefunc.h | 27 ++++++++++++++ sql/lex.h | 2 +- sql/sql_yacc.yy | 5 +++ 6 files changed, 191 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index e51dc113f97..87aa4b98d81 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -720,3 +720,43 @@ Warning 1292 Truncated incorrect datetime value: '2005-01-00' select time_format('100:00:00', '%H %k %h %I %l'); time_format('100:00:00', '%H %k %h %I %l') 100 100 04 04 4 +create table t1 (a timestamp default '2005-05-05 01:01:01', +b timestamp default '2005-05-05 01:01:01'); +create function t_slow_sysdate() returns timestamp +begin +do sleep(2); +return sysdate(); +end; +// +insert into t1 set a = sysdate(), b = t_slow_sysdate();// +create trigger t_before before insert on t1 +for each row begin +set new.b = t_slow_sysdate(); +end +// +insert into t1 set a = sysdate(); +select a != b from t1; +a != b +1 +1 +drop trigger t_before; +drop function t_slow_sysdate; +drop table t1; +create table t1 (a datetime, i int, b datetime); +insert into t1 select sysdate(), sleep(1), sysdate() from dual; +select a != b from t1; +a != b +1 +drop table t1; +create procedure t_sysdate() +begin +select sysdate() into @a; +do sleep(2); +select sysdate() into @b; +select @a != @b; +end; +// +call t_sysdate(); +@a != @b +1 +drop procedure t_sysdate; diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 0538e6111b9..3dd7f7276fb 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -353,3 +353,55 @@ select last_day('2005-01-00'); # the 0-11 range # select time_format('100:00:00', '%H %k %h %I %l'); + +# +# Bug #12562: Make SYSDATE behave like it does in Oracle: always the current +# time, regardless of magic to make NOW() always the same for the +# entirety of a statement. +create table t1 (a timestamp default '2005-05-05 01:01:01', + b timestamp default '2005-05-05 01:01:01'); +delimiter //; +create function t_slow_sysdate() returns timestamp +begin + do sleep(2); + return sysdate(); +end; +// + +insert into t1 set a = sysdate(), b = t_slow_sysdate();// + +create trigger t_before before insert on t1 +for each row begin + set new.b = t_slow_sysdate(); +end +// + +delimiter ;// + +insert into t1 set a = sysdate(); + +select a != b from t1; + +drop trigger t_before; +drop function t_slow_sysdate; +drop table t1; + +create table t1 (a datetime, i int, b datetime); +insert into t1 select sysdate(), sleep(1), sysdate() from dual; +select a != b from t1; +drop table t1; + +delimiter //; +create procedure t_sysdate() +begin + select sysdate() into @a; + do sleep(2); + select sysdate() into @b; + select @a != @b; +end; +// +delimiter ;// +call t_sysdate(); +drop procedure t_sysdate; + +# End of 5.0 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index dfbfca3b078..0d9e23ff0a1 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1476,9 +1476,9 @@ void Item_func_now_utc::store_now_in_TIME(TIME *now_time) bool Item_func_now::get_date(TIME *res, - uint fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { - *res=ltime; + *res= ltime; return 0; } @@ -1491,6 +1491,70 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) } +/* + Converts current time in my_time_t to TIME represenatation for local + time zone. Defines time zone (local) used for whole SYSDATE function. +*/ +void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time) +{ + THD *thd= current_thd; + thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL)); + thd->time_zone_used= 1; +} + + +String *Item_func_sysdate_local::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + store_now_in_TIME(<ime); + buff_length= (uint) my_datetime_to_str(<ime, buff); + str_value.set(buff, buff_length, &my_charset_bin); + return &str_value; +} + + +longlong Item_func_sysdate_local::val_int() +{ + DBUG_ASSERT(fixed == 1); + store_now_in_TIME(<ime); + return (longlong) TIME_to_ulonglong_datetime(<ime); +} + + +double Item_func_sysdate_local::val_real() +{ + DBUG_ASSERT(fixed == 1); + store_now_in_TIME(<ime); + return (longlong) TIME_to_ulonglong_datetime(<ime); +} + + +void Item_func_sysdate_local::fix_length_and_dec() +{ + decimals= 0; + collation.set(&my_charset_bin); + max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; +} + + +bool Item_func_sysdate_local::get_date(TIME *res, + uint fuzzy_date __attribute__((unused))) +{ + store_now_in_TIME(<ime); + *res= ltime; + return 0; +} + + +int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions) +{ + store_now_in_TIME(<ime); + to->set_notnull(); + to->store_time(<ime, MYSQL_TIMESTAMP_DATETIME); + return 0; +} + + String *Item_func_sec_to_time::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index d9300451fe7..4602088a5f5 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -446,6 +446,7 @@ public: class Item_func_now :public Item_date_func { +protected: longlong value; char buff[20*2+32]; // +32 to make my_snprintf_{8bit|ucs2} happy uint buff_length; @@ -485,6 +486,32 @@ public: }; +/* + This is like NOW(), but always uses the real current time, not the + query_start(). This matches the Oracle behavior. +*/ +class Item_func_sysdate_local :public Item_func_now +{ +public: + Item_func_sysdate_local() :Item_func_now() {} + Item_func_sysdate_local(Item *a) :Item_func_now(a) {} + bool const_item() const { return 0; } + const char *func_name() const { return "sysdate"; } + void store_now_in_TIME(TIME *now_time); + double val_real(); + longlong val_int(); + int save_in_field(Field *to, bool no_conversions); + String *val_str(String *str); + void fix_length_and_dec(); + bool get_date(TIME *res, uint fuzzy_date); + void update_used_tables() + { + Item_func_now::update_used_tables(); + used_tables_cache|= RAND_TABLE_BIT; + } +}; + + class Item_func_from_days :public Item_date { public: diff --git a/sql/lex.h b/sql/lex.h index 7b6d86e327e..4bf3671e5be 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -751,7 +751,7 @@ static SYMBOL sql_functions[] = { { "SUBSTRING_INDEX", SYM(SUBSTRING_INDEX)}, { "SUBTIME", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_subtime)}, { "SUM", SYM(SUM_SYM)}, - { "SYSDATE", SYM(NOW_SYM)}, + { "SYSDATE", SYM(SYSDATE)}, { "SYSTEM_USER", SYM(USER)}, { "TAN", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_tan)}, { "TIME_FORMAT", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b446a06ded1..6b447396dec 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -580,6 +580,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SUM_SYM %token SUPER_SYM %token SUSPEND_SYM +%token SYSDATE %token TABLES %token TABLESPACE %token TABLE_SYM @@ -4683,6 +4684,10 @@ simple_expr: { $$= new Item_func_substr($3,$5); } | SUBSTRING_INDEX '(' expr ',' expr ',' expr ')' { $$= new Item_func_substr_index($3,$5,$7); } + | SYSDATE optional_braces + { $$= new Item_func_sysdate_local(); Lex->safe_to_cache_query=0;} + | SYSDATE '(' expr ')' + { $$= new Item_func_sysdate_local($3); Lex->safe_to_cache_query=0;} | TIME_SYM '(' expr ')' { $$= new Item_time_typecast($3); } | TIMESTAMP '(' expr ')' From e11e73173f513c7943f0c02db86cd325ff913c6f Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 24 Aug 2005 17:08:55 -0700 Subject: [PATCH 226/230] Fix for building without --without-server, which was broken by fix for building with --without-server. --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 093ad166ff5..a661e73df56 100644 --- a/configure.in +++ b/configure.in @@ -2487,7 +2487,7 @@ then THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o" AC_SUBST(THREAD_LOBJECTS) server_scripts="mysqld_safe mysql_install_db" - sql_server_dirs="strings dbug extra regex" + sql_server_dirs="strings mysys dbug extra regex" # From f16c7b3c5c1493cf4fd572cc630f211e1a410be3 Mon Sep 17 00:00:00 2001 From: "monty@mishka.local" <> Date: Thu, 25 Aug 2005 09:38:06 +0300 Subject: [PATCH 227/230] After merge fixes --- mysql-test/r/subselect2.result | 2 +- sql/handler.cc | 2 +- sql/sql_acl.cc | 17 ++++++++++------- sql/sql_db.cc | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 4488af8206c..bc902ea7b0f 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -121,8 +121,8 @@ c373e9f5ad07993f3859444553544200 Last Discussion c373e9f5ad079174ff1744455354420 EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion'; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL DDOCTYPEID_IDX NULL NULL NULL 9 Using where +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 1 1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1 -1 PRIMARY t1 eq_ref PRIMARY PRIMARY 32 test.t2.DOCID 1 2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where 3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where 4 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where diff --git a/sql/handler.cc b/sql/handler.cc index 0b247f83af1..cf1fbfec465 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1023,7 +1023,7 @@ bool mysql_xa_recover(THD *thd) DBUG_RETURN(1); pthread_mutex_lock(&LOCK_xid_cache); - while (xs=(XID_STATE*)hash_element(&xid_cache, i++)) + while ((xs= (XID_STATE*)hash_element(&xid_cache, i++))) { if (xs->xa_state==XA_PREPARED) { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 13d84129d8e..4629752c6a7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2494,7 +2494,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, The following should always succeed as new users are created before this function is called! */ - if (!find_acl_user(combo.host.str,combo.user.str)) + if (!find_acl_user(combo.host.str, combo.user.str, FALSE)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); DBUG_RETURN(-1); @@ -4611,11 +4611,12 @@ static int handle_grant_struct(uint struct_no, bool drop, ACL_DB *acl_db; GRANT_NAME *grant_name; DBUG_ENTER("handle_grant_struct"); + DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'", + struct_no, user_from->user.str, user_from->host.str)); + LINT_INIT(acl_user); LINT_INIT(acl_db); LINT_INIT(grant_name); - DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'", - struct_no, user_from->user.str, user_from->host.str)); /* Get the number of elements in the in-memory structure. */ switch (struct_no) { @@ -5311,10 +5312,12 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, combo->user.str= thd->user; - if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str) && - !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str) && - !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str) && - !find_acl_user(combo->host.str=(char*)"%", combo->user.str)) + if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str, + FALSE) && + !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str, + FALSE) && + !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str, FALSE) && + !find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)) DBUG_RETURN(TRUE); bzero((char*)tables, sizeof(TABLE_LIST)); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 27f20753475..5ca3f07f0bd 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -706,14 +706,14 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) query_end= query + MAX_DROP_TABLE_Q_LEN; db_len= strlen(db); - for (tbl= dropped_tables; tbl; tbl= tbl->next) + for (tbl= dropped_tables; tbl; tbl= tbl->next_local) { uint tbl_name_len; if (!tbl->was_dropped) continue; /* 3 for the quotes and the comma*/ - tbl_name_len= strlen(tbl->real_name) + 3; + tbl_name_len= strlen(tbl->table_name) + 3; if (query_pos + tbl_name_len + 1 >= query_end) { write_to_binlog(thd, query, query_pos -1 - query, db, db_len); @@ -721,7 +721,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } *query_pos++ = '`'; - query_pos= strmov(query_pos,tbl->real_name); + query_pos= strmov(query_pos,tbl->table_name); *query_pos++ = '`'; *query_pos++ = ','; } From dde57f082bfcc955cb41291ad1119cf406d509a9 Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Thu, 25 Aug 2005 09:24:21 +0200 Subject: [PATCH 228/230] fix for bug #12533 (crash on DESCRIBE after renaming base table column) --- mysql-test/r/view.result | 12 ++++++++++++ mysql-test/t/view.test | 17 +++++++++++++++++ sql/sql_show.cc | 17 ++++++++++------- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index f56c6558e4f..4767ca0eca7 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2115,3 +2115,15 @@ CREATE VIEW v1 AS SELECT f1(); ERROR HY000: View's SELECT refers to a temporary table 't1' DROP FUNCTION f1; DROP TABLE t1; +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +CREATE TABLE t1 (f4 CHAR(5)); +CREATE VIEW v1 AS SELECT * FROM t1; +DESCRIBE v1; +Field Type Null Key Default Extra +f4 char(5) YES NULL +ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5); +DESCRIBE v1; +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) +DROP TABLE t1; +DROP VIEW v1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index a5b72a16972..4c11f93e683 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1966,3 +1966,20 @@ CREATE VIEW v1 AS SELECT f1(); DROP FUNCTION f1; DROP TABLE t1; +# +# BUG #12533 (crash on DESCRIBE after renaming base table column) +# +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +--enable_warnings + +CREATE TABLE t1 (f4 CHAR(5)); +CREATE VIEW v1 AS SELECT * FROM t1; +DESCRIBE v1; + +ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5); +--error 1356 +DESCRIBE v1; +DROP TABLE t1; +DROP VIEW v1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 3bb349d7c29..7e7771c5b37 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1985,13 +1985,15 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) lex->all_selects_list= lsel; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); - if (schema_table->process_table(thd, show_table_list, + /* + get_all_tables() returns 1 on failure and 0 on success thus + return only these and not the result code of ::process_table() + */ + error= test(schema_table->process_table(thd, show_table_list, table, res, show_table_list->db, - show_table_list->alias)) - goto err; + show_table_list->alias)); close_thread_tables(thd); show_table_list->table= 0; - error= 0; goto err; } @@ -2090,11 +2092,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) lex->derived_tables= 0; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); - if (schema_table->process_table(thd, show_table_list, table, + res= schema_table->process_table(thd, show_table_list, table, res, base_name, - show_table_list->alias)) - goto err; + show_table_list->alias); close_thread_tables(thd); + if (res) + goto err; } } } From aa18382680d6daf8f1adf886b48aad9e8b6d3552 Mon Sep 17 00:00:00 2001 From: "monty@mishka.mysql.com" <> Date: Thu, 25 Aug 2005 12:03:19 +0300 Subject: [PATCH 229/230] Make test predictable --- mysql-test/r/information_schema.result | 4 ++-- mysql-test/t/information_schema.test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 91a99e4ea55..6d8907fff00 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -273,10 +273,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE # ALL NULL NULL NULL NULL 2 1 SIMPLE # ALL NULL NULL NULL NULL 2 Using where select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a, -mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8); +mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8) order by 1; ROUTINE_NAME name -sub1 sub1 sel2 sel2 +sub1 sub1 select count(*) from information_schema.ROUTINES; count(*) 2 diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index d6a47b88ac0..23f88b75576 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -138,7 +138,7 @@ information_schema.SCHEMATA b where a.ROUTINE_SCHEMA = b.SCHEMA_NAME; select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a, -mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8); +mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8) order by 1; select count(*) from information_schema.ROUTINES; connect (user1,localhost,mysqltest_1,,); From 0c859d6651277c2ee3664cb14bb34a23d048731f Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Thu, 25 Aug 2005 13:15:29 +0200 Subject: [PATCH 230/230] config: updated tomas default checkout --- BitKeeper/etc/config | 1 + 1 file changed, 1 insertion(+) diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index d9c45d3d36a..81e867e514f 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -72,5 +72,6 @@ hours: [kostja:]checkout:get [nick:]checkout:get [jonas:]checkout:get +[tomas:]checkout:get checkout:edit eoln:unix