summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/RESYNC_TREE0
-rw-r--r--client/mysqlimport.c3
-rw-r--r--config/ac-macros/ha_federated.m42
-rw-r--r--extra/yassl/taocrypt/include/misc.hpp2
-rw-r--r--extra/yassl/taocrypt/include/runtime.hpp4
-rw-r--r--extra/yassl/taocrypt/include/types.hpp3
-rw-r--r--innobase/dict/dict0dict.c26
-rw-r--r--innobase/include/dict0dict.h5
-rw-r--r--innobase/include/row0mysql.h6
-rw-r--r--innobase/row/row0mysql.c8
-rw-r--r--mysql-test/r/connect.result6
-rw-r--r--mysql-test/r/ctype_utf8.result4
-rw-r--r--mysql-test/r/func_gconcat.result29
-rw-r--r--mysql-test/r/func_like.result7
-rw-r--r--mysql-test/r/func_math.result5
-rw-r--r--mysql-test/r/information_schema.result11
-rw-r--r--mysql-test/r/innodb.result12
-rw-r--r--mysql-test/r/join_outer.result135
-rw-r--r--mysql-test/r/olap.result51
-rw-r--r--mysql-test/r/ps.result44
-rw-r--r--mysql-test/r/select.result15
-rw-r--r--mysql-test/r/sp-error.result21
-rw-r--r--mysql-test/r/sp.result19
-rw-r--r--mysql-test/r/type_newdecimal.result32
-rw-r--r--mysql-test/r/variables.result7
-rw-r--r--mysql-test/r/view.result35
-rw-r--r--mysql-test/t/connect.test18
-rw-r--r--mysql-test/t/ctype_utf8.test6
-rw-r--r--mysql-test/t/func_gconcat.test26
-rw-r--r--mysql-test/t/func_like.test17
-rw-r--r--mysql-test/t/func_math.test9
-rw-r--r--mysql-test/t/information_schema.test14
-rw-r--r--mysql-test/t/innodb.test15
-rw-r--r--mysql-test/t/join_outer.test49
-rw-r--r--mysql-test/t/olap.test46
-rw-r--r--mysql-test/t/ps.test4
-rw-r--r--mysql-test/t/select.test22
-rw-r--r--mysql-test/t/sp-error.test30
-rw-r--r--mysql-test/t/sp.test26
-rw-r--r--mysql-test/t/type_newdecimal.test22
-rw-r--r--mysql-test/t/variables.test9
-rw-r--r--mysql-test/t/view.test41
-rw-r--r--ndb/include/kernel/signaldata/BackupImpl.hpp9
-rw-r--r--ndb/include/kernel/signaldata/BackupSignalData.hpp5
-rw-r--r--ndb/include/kernel/signaldata/NFCompleteRep.hpp18
-rw-r--r--ndb/include/kernel/signaldata/NodeFailRep.hpp28
-rw-r--r--ndb/src/kernel/blocks/backup/Backup.cpp104
-rw-r--r--ndb/src/kernel/blocks/backup/Backup.hpp3
-rw-r--r--ndb/src/kernel/main.cpp2
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp268
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.hpp3
-rw-r--r--ndb/src/ndbapi/Makefile.am3
-rw-r--r--ndb/src/ndbapi/NdbTransaction.cpp26
-rw-r--r--ndb/src/ndbapi/SignalSender.cpp269
-rw-r--r--ndb/src/ndbapi/SignalSender.hpp83
-rw-r--r--ndb/test/src/NdbBackup.cpp9
-rw-r--r--sql/examples/ha_tina.cc3
-rw-r--r--sql/ha_innodb.cc61
-rw-r--r--sql/item.cc35
-rw-r--r--sql/item.h12
-rw-r--r--sql/item_cmpfunc.cc198
-rw-r--r--sql/item_cmpfunc.h57
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_sum.cc8
-rw-r--r--sql/item_sum.h5
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/opt_range.cc15
-rw-r--r--sql/set_var.cc29
-rw-r--r--sql/set_var.h3
-rw-r--r--sql/sp_head.cc26
-rw-r--r--sql/sql_base.cc28
-rw-r--r--sql/sql_cache.cc114
-rw-r--r--sql/sql_cache.h5
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_select.cc60
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_show.cc21
-rw-r--r--sql/sql_yacc.yy25
-rw-r--r--strings/decimal.c16
-rw-r--r--support-files/mysql.server.sh13
81 files changed, 1911 insertions, 515 deletions
diff --git a/BitKeeper/etc/RESYNC_TREE b/BitKeeper/etc/RESYNC_TREE
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/BitKeeper/etc/RESYNC_TREE
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
index 43b0672e03e..ca0a751e963 100644
--- a/client/mysqlimport.c
+++ b/client/mysqlimport.c
@@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object,
const char *statement);
static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0,
- replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0,
+ replace=0,silent=0,ignore=0,opt_compress=0,
opt_low_priority= 0, tty_password= 0;
+static uint opt_local_file=0;
static MYSQL mysql_connection;
static char *opt_password=0, *current_user=0,
*current_host=0, *current_db=0, *fields_terminated=0,
diff --git a/config/ac-macros/ha_federated.m4 b/config/ac-macros/ha_federated.m4
index 4383a9d8d55..5c991f31666 100644
--- a/config/ac-macros/ha_federated.m4
+++ b/config/ac-macros/ha_federated.m4
@@ -6,7 +6,7 @@ AC_DEFUN([MYSQL_CHECK_FEDERATED], [
AC_ARG_WITH([federated-storage-engine],
[
--with-federated-storage-engine
- Enable the MySQL Storage Engine],
+ Enable the MySQL Federated Storage Engine],
[federateddb="$withval"],
[federateddb=no])
AC_MSG_CHECKING([for MySQL federated storage engine])
diff --git a/extra/yassl/taocrypt/include/misc.hpp b/extra/yassl/taocrypt/include/misc.hpp
index 5a31510911e..f705cc99970 100644
--- a/extra/yassl/taocrypt/include/misc.hpp
+++ b/extra/yassl/taocrypt/include/misc.hpp
@@ -91,7 +91,7 @@ public:
// no gas on these systems ?, disable for now
-#if defined(__sun__) || defined (__QNX__)
+#if defined(__sun__) || defined (__QNX__) || defined (__APPLE__)
#define TAOCRYPT_DISABLE_X86ASM
#endif
diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp
index f506040f0d8..254e67a7f64 100644
--- a/extra/yassl/taocrypt/include/runtime.hpp
+++ b/extra/yassl/taocrypt/include/runtime.hpp
@@ -25,7 +25,8 @@
-#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) && !defined(__ICC)
+#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__)
+#if !(defined(__ICC) || defined(__INTEL_COMPILER))
#define yaSSL_NEW_HPP
@@ -46,5 +47,6 @@ static int __cxa_pure_virtual()
} // extern "C"
#endif // __GNUC__ > 2
+#endif // ! _ICC
#endif // yaSSL_NEW_HPP && __GNUC__
diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp
index 92164eaaab4..db9c3792bbd 100644
--- a/extra/yassl/taocrypt/include/types.hpp
+++ b/extra/yassl/taocrypt/include/types.hpp
@@ -61,9 +61,10 @@ typedef unsigned int word32;
// compilers we've found 64-bit multiply insructions for
#if defined(__GNUC__) || defined(_MSC_VER) || defined(__DECCXX)
+#if !(defined(__ICC) || defined(__INTEL_COMPILER))
#define HAVE_64_MULTIPLY
#endif
-
+#endif
#if defined(HAVE_64_MULTIPLY) && (defined(__alpha__) || defined(__ia64__) \
|| defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__))
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 9580a80e7e7..5eee57c250b 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -2871,8 +2871,12 @@ dict_create_foreign_constraints_low(
table2 can be written also with the database
name before it: test.table2; the default
database is the database of parameter name */
- const char* name) /* in: table full name in the normalized form
+ const char* name, /* in: table full name in the normalized form
database_name/table_name */
+ ibool reject_fks)
+ /* in: if TRUE, fail with error code
+ DB_CANNOT_ADD_CONSTRAINT if any foreign
+ keys are found. */
{
dict_table_t* table;
dict_table_t* referenced_table;
@@ -2994,6 +2998,18 @@ loop:
}
if (*ptr == '\0') {
+ /* The proper way to reject foreign keys for temporary
+ tables would be to split the lexing and syntactical
+ analysis of foreign key clauses from the actual adding
+ of them, so that ha_innodb.cc could first parse the SQL
+ command, determine if there are any foreign keys, and
+ if so, immediately reject the command if the table is a
+ temporary one. For now, this kludge will work. */
+ if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0))
+ {
+ return DB_CANNOT_ADD_CONSTRAINT;
+ }
+
/**********************************************************/
/* The following call adds the foreign key constraints
to the data dictionary system tables on disk */
@@ -3417,9 +3433,12 @@ dict_create_foreign_constraints(
name before it: test.table2; the
default database id the database of
parameter name */
- const char* name) /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks) /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
{
char* str;
ulint err;
@@ -3428,7 +3447,8 @@ dict_create_foreign_constraints(
str = dict_strip_comments(sql_string);
heap = mem_heap_create(10000);
- err = dict_create_foreign_constraints_low(trx, heap, str, name);
+ err = dict_create_foreign_constraints_low(trx, heap, str, name,
+ reject_fks);
mem_heap_free(heap);
mem_free(str);
diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h
index d9cda402bac..a1232acdca7 100644
--- a/innobase/include/dict0dict.h
+++ b/innobase/include/dict0dict.h
@@ -228,9 +228,12 @@ dict_create_foreign_constraints(
name before it: test.table2; the
default database id the database of
parameter name */
- const char* name); /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks); /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
/**************************************************************************
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 4e6ff73b0f8..a61705b90be 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -355,9 +355,13 @@ row_table_add_foreign_constraints(
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the
database name before it: test.table2 */
- const char* name); /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks); /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
+
/*************************************************************************
The master thread in srv0srv.c calls this regularly to drop tables which
we must drop in background after queries to them have ended. Such lazy
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 29239210183..26aae117d1d 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -2088,9 +2088,12 @@ row_table_add_foreign_constraints(
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the
database name before it: test.table2 */
- const char* name) /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks) /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
{
ulint err;
@@ -2111,7 +2114,8 @@ row_table_add_foreign_constraints(
trx->dict_operation = TRUE;
- err = dict_create_foreign_constraints(trx, sql_string, name);
+ err = dict_create_foreign_constraints(trx, sql_string, name,
+ reject_fks);
if (err == DB_SUCCESS) {
/* Check that also referencing constraints are ok */
diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result
index fef813371c8..2508d751b46 100644
--- a/mysql-test/r/connect.result
+++ b/mysql-test/r/connect.result
@@ -1,3 +1,4 @@
+drop table if exists t1,t2;
show tables;
Tables_in_mysql
columns_priv
@@ -71,3 +72,8 @@ show tables;
Tables_in_test
delete from mysql.user where user=_binary"test";
flush privileges;
+create table t1 (id integer not null auto_increment primary key);
+create temporary table t2(id integer not null auto_increment primary key);
+set @id := 1;
+delete from t1 where id like @id;
+drop table t1;
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 64c693a292a..48ff82aeeb2 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -955,6 +955,10 @@ char_length(a) length(a) a
2 4 ан
drop table t1;
set names utf8;
+select 'andre%' like 'andreñ%' escape 'ñ';
+'andre%' like 'andreñ%' escape 'ñ'
+1
+set names utf8;
select 'a\\' like 'a\\';
'a\\' like 'a\\'
1
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index c4e8e08929d..6461c393d51 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -469,6 +469,15 @@ select collation(group_concat(a,b)) from t1;
ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat'
drop table t1;
drop table t2;
+CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850);
+INSERT INTO t1 VALUES ('À');
+SELECT a FROM t1;
+a
+SELECT GROUP_CONCAT(a) FROM t1;
+GROUP_CONCAT(a)
+DROP TABLE t1;
CREATE TABLE t1 (id int);
SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
gc
@@ -567,3 +576,23 @@ group_concat('x')
NULL
1
drop table t1;
+CREATE TABLE t1 (id int, a varchar(9));
+INSERT INTO t1 VALUES
+(2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, '');
+SELECT GROUP_CONCAT(a) FROM t1;
+GROUP_CONCAT(a)
+,,x,y,z,
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1;
+GROUP_CONCAT(a ORDER BY a)
+,,,x,y,z
+SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id;
+GROUP_CONCAT(a)
+,y
+,x
+z,
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id;
+GROUP_CONCAT(a ORDER BY a)
+,y
+,x
+,z
+DROP TABLE t1;
diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result
index ac8e5eda8e8..7e6fedb9403 100644
--- a/mysql-test/r/func_like.result
+++ b/mysql-test/r/func_like.result
@@ -158,3 +158,10 @@ DROP TABLE t1;
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
_cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin
1
+set names koi8r;
+select 'andre%' like 'andreÊ%' escape 'Ê';
+'andre%' like 'andreÊ%' escape 'Ê'
+1
+select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê';
+_cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'
+1
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index 0149911e36b..5b6c29f87fb 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -165,3 +165,8 @@ drop table t1;
select abs(-2) * -2;
abs(-2) * -2
-4
+create table t1 (i int);
+insert into t1 values (1);
+select rand(i) from t1;
+ERROR HY000: Incorrect arguments to RAND
+drop table t1;
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 20b2f12f0a8..9a7a0b48f47 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -979,3 +979,14 @@ 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
+DROP TABLE t1,t2;
+create table t1(f1 int);
+create view v1 (c) as select f1 from t1;
+select database();
+database()
+NULL
+show fields from test.v1;
+Field Type Null Key Default Extra
+c int(11) YES NULL
+drop view v1;
+drop table t1;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index d7f7536d401..cc074c8ebf5 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -2527,3 +2527,15 @@ SELECT * FROM t1;
id
1
DROP TABLE t2, t1;
+CREATE TABLE t1
+(
+id INT PRIMARY KEY
+) ENGINE=InnoDB;
+CREATE TEMPORARY TABLE t2
+(
+id INT NOT NULL PRIMARY KEY,
+b INT,
+FOREIGN KEY (b) REFERENCES test.t1(id)
+) ENGINE=InnoDB;
+Got one of the listed errors
+DROP TABLE t1;
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index d4a20209162..92b352aa608 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -200,7 +200,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas
INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL);
-INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
CREATE TABLE t2 (
idAssignatura int(11) DEFAULT '0' NOT NULL,
Grup int(11) DEFAULT '0' NOT NULL,
@@ -1001,3 +1001,136 @@ SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40;
c11 c21
40 NULL
DROP TABLE t1, t2;
+CREATE TABLE t1 (a int PRIMARY KEY, b int);
+CREATE TABLE t2 (a int PRIMARY KEY, b int);
+INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10);
+INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b;
+a b a b
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b;
+a b a b
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b);
+a b a b
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b;
+a b a b
+2 1 NULL NULL
+3 2 3 0
+4 3 4 1
+6 5 6 4
+8 7 NULL NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b;
+a b a b
+2 1 NULL NULL
+3 2 3 0
+4 3 4 1
+6 5 6 4
+8 7 NULL NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b);
+a b a b
+2 1 NULL NULL
+3 2 3 0
+4 3 4 1
+6 5 6 4
+8 7 NULL NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b;
+a b a b
+2 1 NULL NULL
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+8 7 NULL NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b);
+a b a b
+2 1 NULL NULL
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+8 7 NULL NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b);
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b);
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b));
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b;
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b);
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b));
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b);
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b));
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b;
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b));
+a b a b
+3 2 3 0
+4 3 4 1
+6 5 6 4
+7 8 7 5
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
+DROP TABLE t1,t2;
diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result
index 69871b2110b..df0ee09ea8e 100644
--- a/mysql-test/r/olap.result
+++ b/mysql-test/r/olap.result
@@ -555,6 +555,31 @@ IFNULL(a, 'TEST') COALESCE(b, 'TEST')
4 TEST
TEST TEST
DROP TABLE t1,t2;
+CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (1, 2);
+SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP;
+a b c count
+1 1 1 1
+1 1 NULL 1
+1 2 1 1
+1 2 NULL 1
+1 NULL NULL 2
+NULL NULL NULL 2
+DROP TABLE t1;
+CREATE TABLE t1 (a int(11) NOT NULL);
+INSERT INTO t1 VALUES (1),(2);
+SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t;
+a a + 1 COUNT(*)
+1 2 1
+2 3 1
+NULL NULL 2
+SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t;
+a LENGTH(a) COUNT(*)
+1 1 1
+2 1 1
+NULL NULL 2
+DROP TABLE t1;
CREATE TABLE t1(id int, type char(1));
INSERT INTO t1 VALUES
(1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"),
@@ -577,15 +602,19 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort
DROP VIEW v1;
DROP TABLE t1;
-CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL);
-INSERT INTO t1 VALUES (1, 1);
-INSERT INTO t1 VALUES (1, 2);
-SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP;
-a b c count
-1 1 1 1
-1 1 NULL 1
-1 2 1 1
-1 2 NULL 1
-1 NULL NULL 2
-NULL NULL NULL 2
+CREATE TABLE t1 (a int(11) NOT NULL);
+INSERT INTO t1 VALUES (1),(2);
+CREATE VIEW v1 AS
+SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
+DESC v1;
+Field Type Null Key Default Extra
+a bigint(11) YES NULL
+LENGTH(a) bigint(10) YES NULL
+COUNT(*) bigint(21) NO 0
+SELECT * FROM v1;
+a LENGTH(a) COUNT(*)
+1 1 1
+2 1 1
+NULL NULL 2
+DROP VIEW v1;
DROP TABLE t1;
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 0050dfc0841..dc78f8d04ea 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -335,39 +335,37 @@ create table t1 (a int);
insert into t1 (a) values (1), (2), (3), (4);
set @precision=10000000000;
select rand(),
-cast(rand(10)*@precision as unsigned integer),
-cast(rand(a)*@precision as unsigned integer) from t1;
-rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer)
-- 6570515219 -
-- 1282061302 -
-- 6698761160 -
-- 9647622201 -
+cast(rand(10)*@precision as unsigned integer) from t1;
+rand() cast(rand(10)*@precision as unsigned integer)
+- 6570515219
+- 1282061302
+- 6698761160
+- 9647622201
prepare stmt from
"select rand(),
cast(rand(10)*@precision as unsigned integer),
- cast(rand(a)*@precision as unsigned integer),
cast(rand(?)*@precision as unsigned integer) from t1";
set @var=1;
execute stmt using @var;
-rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
-- 6570515219 - 4054035371
-- 1282061302 - 8716141803
-- 6698761160 - 1418603212
-- 9647622201 - 944590960
+rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
+- 6570515219 -
+- 1282061302 -
+- 6698761160 -
+- 9647622201 -
set @var=2;
execute stmt using @var;
-rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
-- 6570515219 1559528654 6555866465
-- 1282061302 6238114970 1223466192
-- 6698761160 6511989195 6449731873
-- 9647622201 3845601374 8578261098
+rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
+- 6570515219 6555866465
+- 1282061302 1223466192
+- 6698761160 6449731873
+- 9647622201 8578261098
set @var=3;
execute stmt using @var;
-rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
-- 6570515219 1559528654 9057697559
-- 1282061302 6238114970 3730790581
-- 6698761160 6511989195 1480860534
-- 9647622201 3845601374 6211931236
+rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
+- 6570515219 9057697559
+- 1282061302 3730790581
+- 6698761160 1480860534
+- 9647622201 6211931236
drop table t1;
deallocate prepare stmt;
create database mysqltest1;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index 0d5c1aed485..24c89039566 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -2897,3 +2897,18 @@ select * from t1 natural join t2 where a = 'b';
a
b
drop table t1, t2;
+CREATE TABLE t1 (`id` TINYINT);
+CREATE TABLE t2 (`id` TINYINT);
+CREATE TABLE t3 (`id` TINYINT);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t3 VALUES (3);
+SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id);
+ERROR 23000: Column 'id' in from clause is ambiguous
+SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id);
+ERROR 23000: Column 'id' in from clause is ambiguous
+SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id);
+ERROR 23000: Column 'id' in from clause is ambiguous
+SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id);
+ERROR 23000: Column 'id' in from clause is ambiguous
+drop table t1, t2, t3;
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 1a061529fb0..09d829e9d12 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -765,3 +765,24 @@ OPTIMIZE TABLE t1;
RETURN 1;
END|
ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures
+DROP FUNCTION IF EXISTS bug12995|
+CREATE FUNCTION bug12995() RETURNS INT
+BEGIN
+HANDLER t1 OPEN;
+RETURN 1;
+END|
+ERROR 0A000: HANDLER is not allowed in stored procedures
+CREATE FUNCTION bug12995() RETURNS INT
+BEGIN
+HANDLER t1 READ FIRST;
+RETURN 1;
+END|
+ERROR 0A000: HANDLER is not allowed in stored procedures
+CREATE FUNCTION bug12995() RETURNS INT
+BEGIN
+HANDLER t1 CLOSE;
+RETURN 1;
+END|
+ERROR 0A000: HANDLER is not allowed in stored procedures
+SELECT bug12995()|
+ERROR 42000: FUNCTION test.bug12995 does not exist
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 5199377fbd1..cb696f93f79 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -3206,4 +3206,23 @@ set f1= concat( 'hello', f1 );
return f1;
end|
drop function bug9048|
+drop procedure if exists bug12849_1|
+create procedure bug12849_1(inout x char) select x into x|
+set @var='a'|
+call bug12849_1(@var)|
+select @var|
+@var
+a
+drop procedure bug12849_1|
+drop procedure if exists bug12849_2|
+create procedure bug12849_2(inout foo varchar(15))
+begin
+select concat(foo, foo) INTO foo;
+end|
+set @var='abcd'|
+call bug12849_2(@var)|
+select @var|
+@var
+abcdabcd
+drop procedure bug12849_2|
drop table t1,t2;
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 4980e2a73d2..f06e290a49b 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -984,3 +984,35 @@ t1 CREATE TABLE `t1` (
`f1` decimal(10,0) unsigned zerofill NOT NULL default '0000000000'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
+drop procedure if exists wg2;
+Warnings:
+Note 1305 PROCEDURE wg2 does not exist
+create procedure wg2()
+begin
+declare v int default 1;
+declare tdec decimal(5) default 0;
+while v <= 9 do set tdec =tdec * 10;
+select v, tdec;
+set v = v + 1;
+end while;
+end//
+call wg2()//
+v tdec
+1 0
+v tdec
+2 0
+v tdec
+3 0
+v tdec
+4 0
+v tdec
+5 0
+v tdec
+6 0
+v tdec
+7 0
+v tdec
+8 0
+v tdec
+9 0
+drop procedure wg2;
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index a5b76c03b29..265f353ae3c 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -545,3 +545,10 @@ select @@max_heap_table_size > 0;
select @@have_innodb;
@@have_innodb
#
+select @@character_set_system;
+@@character_set_system
+utf8
+set global character_set_system = latin1;
+ERROR HY000: Variable 'character_set_system' is a read only variable
+set @@global.version_compile_os='234';
+ERROR HY000: Variable 'version_compile_os' is a read only variable
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index a544fb4b020..558977a6d2d 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -2151,3 +2151,38 @@ select * from v1;
strcmp(f1,'a')
drop view v1;
drop table t1;
+create table t1 (f1 int, f2 int,f3 int);
+insert into t1 values (1,10,20),(2,0,0);
+create view v1 as select * from t1;
+select if(sum(f1)>1,f2,f3) from v1 group by f1;
+if(sum(f1)>1,f2,f3)
+20
+0
+drop view v1;
+drop table t1;
+create table t1 (
+r_object_id char(16) NOT NULL,
+group_name varchar(32) NOT NULL
+) engine = InnoDB;
+create table t2 (
+r_object_id char(16) NOT NULL,
+i_position int(11) NOT NULL,
+users_names varchar(32) default NULL
+) Engine = InnoDB;
+create view v1 as select r_object_id, group_name from t1;
+create view v2 as select r_object_id, i_position, users_names from t2;
+create unique index r_object_id on t1(r_object_id);
+create index group_name on t1(group_name);
+create unique index r_object_id_i_position on t2(r_object_id,i_position);
+create index users_names on t2(users_names);
+insert into t1 values('120001a080000542','tstgroup1');
+insert into t2 values('120001a080000542',-1, 'guser01');
+insert into t2 values('120001a080000542',-2, 'guser02');
+select v1.r_object_id, v2.users_names from v1, v2
+where (v1.group_name='tstgroup1') and v2.r_object_id=v1.r_object_id
+order by users_names;
+r_object_id users_names
+120001a080000542 guser01
+120001a080000542 guser02
+drop view v1, v2;
+drop table t1, t2;
diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test
index 64b170970ca..60ac7b88bbe 100644
--- a/mysql-test/t/connect.test
+++ b/mysql-test/t/connect.test
@@ -6,6 +6,10 @@
# This test makes no sense with the embedded server
--source include/not_embedded.inc
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+
#connect (con1,localhost,root,,"");
#show tables;
connect (con1,localhost,root,,mysql);
@@ -77,4 +81,18 @@ show tables;
delete from mysql.user where user=_binary"test";
flush privileges;
+#
+# Bug#12517: Clear user variables and replication events before
+# closing temp tables in thread cleanup.
+connect (con2,localhost,root,,test);
+connection con2;
+create table t1 (id integer not null auto_increment primary key);
+create temporary table t2(id integer not null auto_increment primary key);
+set @id := 1;
+delete from t1 where id like @id;
+disconnect con2;
+--sleep 5
+connection default;
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index ce259f465d9..041451272d4 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -810,6 +810,12 @@ alter table t1 modify a char(2) character set utf8;
select char_length(a), length(a), a from t1 order by a;
drop table t1;
+#
+# Bugs#12611
+# ESCAPE + LIKE do not work when the escape char is a multibyte one
+#
+set names utf8;
+select 'andre%' like 'andreñ%' escape 'ñ';
#
# Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0
diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test
index 0b61a445270..a519d51e0b5 100644
--- a/mysql-test/t/func_gconcat.test
+++ b/mysql-test/t/func_gconcat.test
@@ -282,6 +282,16 @@ drop table t1;
drop table t2;
#
+# Bug #12829
+# Cannot convert the charset of a GROUP_CONCAT result
+#
+CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850);
+INSERT INTO t1 VALUES ('À');
+SELECT a FROM t1;
+SELECT GROUP_CONCAT(a) FROM t1;
+DROP TABLE t1;
+
+#
# bug #7769: group_concat returning null is checked in having
#
CREATE TABLE t1 (id int);
@@ -363,4 +373,20 @@ select * from (select group_concat(a) from t1) t2;
select group_concat('x') UNION ALL select 1;
drop table t1;
+#
+# Bug #12863 : missing separators after first empty cancatanated elements
+#
+
+CREATE TABLE t1 (id int, a varchar(9));
+INSERT INTO t1 VALUES
+ (2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, '');
+
+SELECT GROUP_CONCAT(a) FROM t1;
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1;
+
+SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id;
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id;
+
+DROP TABLE t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test
index 684d7032038..4e1183afeff 100644
--- a/mysql-test/t/func_like.test
+++ b/mysql-test/t/func_like.test
@@ -96,4 +96,21 @@ DROP TABLE t1;
#
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
+#
+# Check 8bit escape character
+#
+set names koi8r;
+select 'andre%' like 'andreÊ%' escape 'Ê';
+
+# Check 8bit escape character with charset conversion:
+# For "a LIKE b ESCAPE c" expressions,
+# escape character is converted into the operation character set,
+# which is result of aggregation of character sets of "a" and "b".
+# "c" itself doesn't take part in aggregation, because its collation
+# doesn't matter, escape character is always compared binary.
+# In the example below, escape character is converted from koi8r into cp1251:
+#
+select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê';
+
+#
# End of 4.1 tests
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index bf692325a6a..633e36f51ab 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -107,4 +107,13 @@ drop table t1;
#
select abs(-2) * -2;
+#
+# Bug #6172 RAND(a) should only accept constant values as arguments
+#
+create table t1 (i int);
+insert into t1 values (1);
+--error 1210
+select rand(i) from t1;
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index 6be193e0e0c..aa1b632f919 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -665,4 +665,16 @@ 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
+DROP TABLE t1,t2;
+
+#
+# Bug #12905 show fields from view behaving erratically with current database
+#
+create table t1(f1 int);
+create view v1 (c) as select f1 from t1;
+connect (con5,localhost,root,,*NO-ONE*);
+select database();
+show fields from test.v1;
+connection default;
+drop view v1;
+drop table t1;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 0bd3d8137a3..7d449ac9261 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1451,3 +1451,18 @@ TRUNCATE t1;
INSERT INTO t1 (id) VALUES (NULL);
SELECT * FROM t1;
DROP TABLE t2, t1;
+
+-- Test that foreign keys in temporary tables are not accepted (bug #12084)
+CREATE TABLE t1
+(
+ id INT PRIMARY KEY
+) ENGINE=InnoDB;
+
+--error 1005,1005
+CREATE TEMPORARY TABLE t2
+(
+ id INT NOT NULL PRIMARY KEY,
+ b INT,
+ FOREIGN KEY (b) REFERENCES test.t1(id)
+) ENGINE=InnoDB;
+DROP TABLE t1;
diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test
index aabc32c009a..367b98f2485 100644
--- a/mysql-test/t/join_outer.test
+++ b/mysql-test/t/join_outer.test
@@ -135,7 +135,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas
INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL);
-INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
CREATE TABLE t2 (
idAssignatura int(11) DEFAULT '0' NOT NULL,
@@ -590,7 +590,6 @@ INSERT INTO t2 VALUES("0", "EN", "0-EN");
INSERT INTO t2 VALUES("0", "SV", "0-SV");
INSERT INTO t2 VALUES("10", "EN", "10-EN");
INSERT INTO t2 VALUES("10", "SV", "10-SV");
-
SELECT t1.id, t1.text_id, t2.text_data
FROM t1 LEFT JOIN t2
ON t1.text_id = t2.text_id
@@ -713,3 +712,49 @@ INSERT INTO t1 VALUES (30), (40), (50);
INSERT INTO t2 VALUES (300), (400), (500);
SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40;
DROP TABLE t1, t2;
+#
+# Test for bugs
+# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN
+# #12102: erroneously missing outer join elimination in case of WHERE IN/IF
+#
+
+CREATE TABLE t1 (a int PRIMARY KEY, b int);
+CREATE TABLE t2 (a int PRIMARY KEY, b int);
+
+INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10);
+INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b));
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b));
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b));
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b));
+
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1);
+
+DROP TABLE t1,t2;
+
diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test
index 2e09bc5b3a3..3a6a5e46f37 100644
--- a/mysql-test/t/olap.test
+++ b/mysql-test/t/olap.test
@@ -251,6 +251,33 @@ SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2
DROP TABLE t1,t2;
#
+# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY
+#
+
+CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (1, 2);
+
+SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP;
+
+DROP TABLE t1;
+
+#
+# Bug #12885(1): derived table specified by a subquery with
+# ROLLUP over expressions on not nullable group by attributes
+#
+
+CREATE TABLE t1 (a int(11) NOT NULL);
+INSERT INTO t1 VALUES (1),(2);
+
+SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t;
+SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t;
+
+DROP TABLE t1;
+
+# End of 4.1 tests
+
+#
# Tests for bug #11639: ROLLUP over view executed through filesort
#
@@ -266,15 +293,20 @@ EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP;
DROP VIEW v1;
DROP TABLE t1;
-# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY
+
+#
+# Bug #12885(2): view specified by a subquery with
+# ROLLUP over expressions on not nullable group by attributes
#
-CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL);
-INSERT INTO t1 VALUES (1, 1);
-INSERT INTO t1 VALUES (1, 2);
+CREATE TABLE t1 (a int(11) NOT NULL);
+INSERT INTO t1 VALUES (1),(2);
-SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP;
+CREATE VIEW v1 AS
+ SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP;
-DROP TABLE t1;
+DESC v1;
+SELECT * FROM v1;
-# End of 4.1 tests
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index b4c04e4432a..94596fbbc0e 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -371,12 +371,10 @@ insert into t1 (a) values (1), (2), (3), (4);
set @precision=10000000000;
--replace_column 1 - 3 -
select rand(),
- cast(rand(10)*@precision as unsigned integer),
- cast(rand(a)*@precision as unsigned integer) from t1;
+ cast(rand(10)*@precision as unsigned integer) from t1;
prepare stmt from
"select rand(),
cast(rand(10)*@precision as unsigned integer),
- cast(rand(a)*@precision as unsigned integer),
cast(rand(?)*@precision as unsigned integer) from t1";
set @var=1;
--replace_column 1 - 3 -
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index fad01ac9acf..62687a869b7 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -2465,3 +2465,25 @@ 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;
+
+#
+# Bug #12977 Compare table names with qualifying field tables only
+# for base tables, search all nested join operands of natural joins.
+#
+
+CREATE TABLE t1 (`id` TINYINT);
+CREATE TABLE t2 (`id` TINYINT);
+CREATE TABLE t3 (`id` TINYINT);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t3 VALUES (3);
+-- error 1052
+SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id);
+-- error 1052
+SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id);
+-- error 1052
+SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id);
+-- error 1052
+SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id);
+
+drop table t1, t2, t3;
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index abb927ab3b8..9f91c32c104 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -1099,6 +1099,36 @@ BEGIN
OPTIMIZE TABLE t1;
RETURN 1;
END|
+delimiter ;|
+
+#
+# Bug##12995 "Inside function "Table 't4' was not locked with LOCK TABLES"
+#
+delimiter |;
+--disable_warnings
+DROP FUNCTION IF EXISTS bug12995|
+--enable_warnings
+--error ER_SP_BADSTATEMENT
+CREATE FUNCTION bug12995() RETURNS INT
+BEGIN
+ HANDLER t1 OPEN;
+ RETURN 1;
+END|
+--error ER_SP_BADSTATEMENT
+CREATE FUNCTION bug12995() RETURNS INT
+BEGIN
+ HANDLER t1 READ FIRST;
+ RETURN 1;
+END|
+--error ER_SP_BADSTATEMENT
+CREATE FUNCTION bug12995() RETURNS INT
+BEGIN
+ HANDLER t1 CLOSE;
+ RETURN 1;
+END|
+--error 1305
+SELECT bug12995()|
+delimiter ;|
#
# BUG#NNNN: New bug synopsis
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index add51e806c0..3d315fa12df 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -4038,6 +4038,32 @@ end|
drop function bug9048|
#
+# Bug #12849 Stored Procedure: Crash on procedure call with CHAR type
+# 'INOUT' parameter
+#
+
+--disable_warnings
+drop procedure if exists bug12849_1|
+--enable_warnings
+create procedure bug12849_1(inout x char) select x into x|
+set @var='a'|
+call bug12849_1(@var)|
+select @var|
+drop procedure bug12849_1|
+
+--disable_warnings
+drop procedure if exists bug12849_2|
+--enable_warnings
+create procedure bug12849_2(inout foo varchar(15))
+begin
+select concat(foo, foo) INTO foo;
+end|
+set @var='abcd'|
+call bug12849_2(@var)|
+select @var|
+drop procedure bug12849_2|
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index f3be64506c7..55e0618a3e5 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -1015,3 +1015,25 @@ create table t1 (
f1 decimal (0,0) zerofill not null default 0);
show create table t1;
drop table t1;
+
+#
+# Bug 12938 (arithmetic loop's zero)
+#
+--disable-warnings
+drop procedure if exists wg2;
+--enable-warnings
+delimiter //;
+create procedure wg2()
+begin
+ declare v int default 1;
+ declare tdec decimal(5) default 0;
+ while v <= 9 do set tdec =tdec * 10;
+ select v, tdec;
+ set v = v + 1;
+ end while;
+end//
+
+call wg2()//
+
+delimiter ;//
+drop procedure wg2;
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index 372e865467e..afd0fe23805 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -435,3 +435,12 @@ select @@max_heap_table_size > 0;
--replace_column 1 #
select @@have_innodb;
+
+#
+# Bug #11775 Variable character_set_system does not exist (sometimes)
+#
+select @@character_set_system;
+--error 1238
+set global character_set_system = latin1;
+--error 1238
+set @@global.version_compile_os='234';
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 97625632618..7cca98391a8 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -2018,3 +2018,44 @@ create view v1 as select strcmp(f1,'a') from t1;
select * from v1;
drop view v1;
drop table t1;
+
+#
+# Bug #12922 if(sum(),...) with group from view returns wrong results
+#
+create table t1 (f1 int, f2 int,f3 int);
+insert into t1 values (1,10,20),(2,0,0);
+create view v1 as select * from t1;
+select if(sum(f1)>1,f2,f3) from v1 group by f1;
+drop view v1;
+drop table t1;
+# BUG#12941
+#
+create table t1 (
+ r_object_id char(16) NOT NULL,
+ group_name varchar(32) NOT NULL
+) engine = InnoDB;
+
+create table t2 (
+ r_object_id char(16) NOT NULL,
+ i_position int(11) NOT NULL,
+ users_names varchar(32) default NULL
+) Engine = InnoDB;
+
+create view v1 as select r_object_id, group_name from t1;
+create view v2 as select r_object_id, i_position, users_names from t2;
+
+create unique index r_object_id on t1(r_object_id);
+create index group_name on t1(group_name);
+create unique index r_object_id_i_position on t2(r_object_id,i_position);
+create index users_names on t2(users_names);
+
+insert into t1 values('120001a080000542','tstgroup1');
+insert into t2 values('120001a080000542',-1, 'guser01');
+insert into t2 values('120001a080000542',-2, 'guser02');
+
+select v1.r_object_id, v2.users_names from v1, v2
+where (v1.group_name='tstgroup1') and v2.r_object_id=v1.r_object_id
+order by users_names;
+
+drop view v1, v2;
+drop table t1, t2;
diff --git a/ndb/include/kernel/signaldata/BackupImpl.hpp b/ndb/include/kernel/signaldata/BackupImpl.hpp
index 2032e2347b5..298440ad377 100644
--- a/ndb/include/kernel/signaldata/BackupImpl.hpp
+++ b/ndb/include/kernel/signaldata/BackupImpl.hpp
@@ -33,7 +33,7 @@ class DefineBackupReq {
friend bool printDEFINE_BACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16);
public:
- STATIC_CONST( SignalLength = 8 + NdbNodeBitmask::Size);
+ STATIC_CONST( SignalLength = 9 + NdbNodeBitmask::Size);
private:
/**
@@ -60,6 +60,13 @@ private:
* Length of backup data
*/
Uint32 backupDataLen;
+
+ /**
+ * Backup flags
+ */
+ /* & 0x3 - waitCompleted
+ */
+ Uint32 flags;
};
class DefineBackupRef {
diff --git a/ndb/include/kernel/signaldata/BackupSignalData.hpp b/ndb/include/kernel/signaldata/BackupSignalData.hpp
index b38dd8d14b2..e1b8c6203a1 100644
--- a/ndb/include/kernel/signaldata/BackupSignalData.hpp
+++ b/ndb/include/kernel/signaldata/BackupSignalData.hpp
@@ -36,11 +36,14 @@ class BackupReq {
friend bool printBACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16);
public:
- STATIC_CONST( SignalLength = 2 );
+ STATIC_CONST( SignalLength = 3 );
private:
Uint32 senderData;
Uint32 backupDataLen;
+ /* & 0x3 - waitCompleted
+ */
+ Uint32 flags;
};
class BackupData {
diff --git a/ndb/include/kernel/signaldata/NFCompleteRep.hpp b/ndb/include/kernel/signaldata/NFCompleteRep.hpp
index c8bde705a86..764da85b163 100644
--- a/ndb/include/kernel/signaldata/NFCompleteRep.hpp
+++ b/ndb/include/kernel/signaldata/NFCompleteRep.hpp
@@ -30,28 +30,12 @@
* from the failed NDB node
*
*/
-class NFCompleteRep {
- /**
- * Sender(s)
- */
- friend class Dbdict;
- friend class Dblqh;
- friend class Dbtc;
- friend class Qmgr;
-
- /**
- * Sender/Reciver
- */
- friend class Dbdih;
- friend class ClusterMgr;
+struct NFCompleteRep {
friend bool printNF_COMPLETE_REP(FILE *, const Uint32 *, Uint32, Uint16);
-public:
STATIC_CONST( SignalLength = 5 );
-private:
-
/**
* Which block has completed...
*
diff --git a/ndb/include/kernel/signaldata/NodeFailRep.hpp b/ndb/include/kernel/signaldata/NodeFailRep.hpp
index 060acd6a3e2..fe57ba1a712 100644
--- a/ndb/include/kernel/signaldata/NodeFailRep.hpp
+++ b/ndb/include/kernel/signaldata/NodeFailRep.hpp
@@ -24,34 +24,8 @@
* This signals is sent by Qmgr to NdbCntr
* and then from NdbCntr sent to: dih, dict, lqh, tc & API
*/
-class NodeFailRep {
- /**
- * Sender(s)
- */
- friend class Qmgr;
-
- /**
- * Sender(s) / Reciver(s)
- */
- friend class Ndbcntr;
- friend class Dbdict;
-
- /**
- * Reciver(s)
- */
- friend class Dbdih;
- friend class Dblqh;
- friend class Dbtc;
- friend class ClusterMgr;
- friend class Trix;
- friend class Backup;
- friend class Suma;
- friend class Grep;
- friend class SafeCounterManager;
-
-public:
+struct NodeFailRep {
STATIC_CONST( SignalLength = 3 + NodeBitmask::Size );
-private:
Uint32 failNo;
diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp
index 34545d4c7ff..063e36a775f 100644
--- a/ndb/src/kernel/blocks/backup/Backup.cpp
+++ b/ndb/src/kernel/blocks/backup/Backup.cpp
@@ -69,6 +69,9 @@ static const Uint32 BACKUP_SEQUENCE = 0x1F000000;
static Uint32 g_TypeOfStart = NodeState::ST_ILLEGAL_TYPE;
+#define SEND_BACKUP_STARTED_FLAG(A) (((A) & 0x3) > 0)
+#define SEND_BACKUP_COMPLETED_FLAG(A) (((A) & 0x3) > 1)
+
void
Backup::execSTTOR(Signal* signal)
{
@@ -852,23 +855,24 @@ Backup::execBACKUP_REQ(Signal* signal)
const Uint32 senderData = req->senderData;
const BlockReference senderRef = signal->senderBlockRef();
const Uint32 dataLen32 = req->backupDataLen; // In 32 bit words
-
+ const Uint32 flags = signal->getLength() > 2 ? req->flags : 2;
+
if(getOwnNodeId() != getMasterNodeId()) {
jam();
- sendBackupRef(senderRef, signal, senderData, BackupRef::IAmNotMaster);
+ sendBackupRef(senderRef, flags, signal, senderData, BackupRef::IAmNotMaster);
return;
}//if
if (m_diskless)
{
- sendBackupRef(senderRef, signal, senderData,
+ sendBackupRef(senderRef, flags, signal, senderData,
BackupRef::CannotBackupDiskless);
return;
}
if(dataLen32 != 0) {
jam();
- sendBackupRef(senderRef, signal, senderData,
+ sendBackupRef(senderRef, flags, signal, senderData,
BackupRef::BackupDefinitionNotImplemented);
return;
}//if
@@ -883,7 +887,7 @@ Backup::execBACKUP_REQ(Signal* signal)
c_backups.seize(ptr);
if(ptr.i == RNIL) {
jam();
- sendBackupRef(senderRef, signal, senderData, BackupRef::OutOfBackupRecord);
+ sendBackupRef(senderRef, flags, signal, senderData, BackupRef::OutOfBackupRecord);
return;
}//if
@@ -894,6 +898,7 @@ Backup::execBACKUP_REQ(Signal* signal)
ptr.p->errorCode = 0;
ptr.p->clientRef = senderRef;
ptr.p->clientData = senderData;
+ ptr.p->flags = flags;
ptr.p->masterRef = reference();
ptr.p->nodes = c_aliveNodes;
ptr.p->backupId = 0;
@@ -931,20 +936,23 @@ void
Backup::sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode)
{
jam();
- sendBackupRef(ptr.p->clientRef, signal, ptr.p->clientData, errorCode);
+ sendBackupRef(ptr.p->clientRef, ptr.p->flags, signal, ptr.p->clientData, errorCode);
cleanup(signal, ptr);
}
void
-Backup::sendBackupRef(BlockReference senderRef, Signal *signal,
+Backup::sendBackupRef(BlockReference senderRef, Uint32 flags, Signal *signal,
Uint32 senderData, Uint32 errorCode)
{
jam();
- BackupRef* ref = (BackupRef*)signal->getDataPtrSend();
- ref->senderData = senderData;
- ref->errorCode = errorCode;
- ref->masterRef = numberToRef(BACKUP, getMasterNodeId());
- sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB);
+ if (SEND_BACKUP_STARTED_FLAG(flags))
+ {
+ BackupRef* ref = (BackupRef*)signal->getDataPtrSend();
+ ref->senderData = senderData;
+ ref->errorCode = errorCode;
+ ref->masterRef = numberToRef(BACKUP, getMasterNodeId());
+ sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB);
+ }
if(errorCode != BackupRef::IAmNotMaster){
signal->theData[0] = NDB_LE_BackupFailedToStart;
@@ -1098,6 +1106,7 @@ Backup::sendDefineBackupReq(Signal *signal, BackupRecordPtr ptr)
req->backupKey[1] = ptr.p->backupKey[1];
req->nodes = ptr.p->nodes;
req->backupDataLen = ptr.p->backupDataLen;
+ req->flags = ptr.p->flags;
ptr.p->masterData.gsn = GSN_DEFINE_BACKUP_REQ;
ptr.p->masterData.sendCounter = ptr.p->nodes;
@@ -1193,13 +1202,18 @@ Backup::defineBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId)
/**
* Reply to client
*/
- BackupConf * conf = (BackupConf*)signal->getDataPtrSend();
- conf->backupId = ptr.p->backupId;
- conf->senderData = ptr.p->clientData;
- conf->nodes = ptr.p->nodes;
- sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal,
- BackupConf::SignalLength, JBB);
-
+ CRASH_INSERTION((10034));
+
+ if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags))
+ {
+ BackupConf * conf = (BackupConf*)signal->getDataPtrSend();
+ conf->backupId = ptr.p->backupId;
+ conf->senderData = ptr.p->clientData;
+ conf->nodes = ptr.p->nodes;
+ sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal,
+ BackupConf::SignalLength, JBB);
+ }
+
signal->theData[0] = NDB_LE_BackupStarted;
signal->theData[1] = ptr.p->clientRef;
signal->theData[2] = ptr.p->backupId;
@@ -2080,19 +2094,22 @@ Backup::stopBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId)
if(!ptr.p->checkError())
{
- BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend();
- rep->backupId = ptr.p->backupId;
- rep->senderData = ptr.p->clientData;
- rep->startGCP = ptr.p->startGCP;
- rep->stopGCP = ptr.p->stopGCP;
- rep->noOfBytes = ptr.p->noOfBytes;
- rep->noOfRecords = ptr.p->noOfRecords;
- rep->noOfLogBytes = ptr.p->noOfLogBytes;
- rep->noOfLogRecords = ptr.p->noOfLogRecords;
- rep->nodes = ptr.p->nodes;
- sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal,
- BackupCompleteRep::SignalLength, JBB);
-
+ if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags))
+ {
+ BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend();
+ rep->backupId = ptr.p->backupId;
+ rep->senderData = ptr.p->clientData;
+ rep->startGCP = ptr.p->startGCP;
+ rep->stopGCP = ptr.p->stopGCP;
+ rep->noOfBytes = ptr.p->noOfBytes;
+ rep->noOfRecords = ptr.p->noOfRecords;
+ rep->noOfLogBytes = ptr.p->noOfLogBytes;
+ rep->noOfLogRecords = ptr.p->noOfLogRecords;
+ rep->nodes = ptr.p->nodes;
+ sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal,
+ BackupCompleteRep::SignalLength, JBB);
+ }
+
signal->theData[0] = NDB_LE_BackupCompleted;
signal->theData[1] = ptr.p->clientRef;
signal->theData[2] = ptr.p->backupId;
@@ -2129,13 +2146,15 @@ Backup::masterAbort(Signal* signal, BackupRecordPtr ptr)
return;
}
- BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend();
- rep->backupId = ptr.p->backupId;
- rep->senderData = ptr.p->clientData;
- rep->reason = ptr.p->errorCode;
- sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal,
- BackupAbortRep::SignalLength, JBB);
-
+ if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags))
+ {
+ BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend();
+ rep->backupId = ptr.p->backupId;
+ rep->senderData = ptr.p->clientData;
+ rep->reason = ptr.p->errorCode;
+ sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal,
+ BackupAbortRep::SignalLength, JBB);
+ }
signal->theData[0] = NDB_LE_BackupAborted;
signal->theData[1] = ptr.p->clientRef;
signal->theData[2] = ptr.p->backupId;
@@ -2267,6 +2286,13 @@ Backup::execDEFINE_BACKUP_REQ(Signal* signal)
ptr.p->errorCode = 0;
ptr.p->clientRef = req->clientRef;
ptr.p->clientData = req->clientData;
+ if(senderRef == reference())
+ ptr.p->flags = req->flags;
+ else
+ ptr.p->flags = req->flags & ~((Uint32)0x3); /* remove waitCompleted flags
+ * as non master should never
+ * reply
+ */
ptr.p->masterRef = senderRef;
ptr.p->nodes = req->nodes;
ptr.p->backupId = backupId;
diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp
index ab2bec7dad7..67b53d3eccd 100644
--- a/ndb/src/kernel/blocks/backup/Backup.hpp
+++ b/ndb/src/kernel/blocks/backup/Backup.hpp
@@ -412,6 +412,7 @@ public:
Uint32 clientRef;
Uint32 clientData;
+ Uint32 flags;
Uint32 backupId;
Uint32 backupKey[2];
Uint32 masterRef;
@@ -592,7 +593,7 @@ public:
bool insertFileHeader(BackupFormat::FileType, BackupRecord*, BackupFile*);
void sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode);
- void sendBackupRef(BlockReference ref, Signal *signal,
+ void sendBackupRef(BlockReference ref, Uint32 flags, Signal *signal,
Uint32 senderData, Uint32 errorCode);
void dumpUsedResources();
void cleanup(Signal*, BackupRecordPtr ptr);
diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp
index 850cdf37044..bec9c8b28f4 100644
--- a/ndb/src/kernel/main.cpp
+++ b/ndb/src/kernel/main.cpp
@@ -410,5 +410,5 @@ handler_sigusr1(int signum)
failed_startups++;
failed_startup_flag = true;
}
- g_eventLogger.info("Received signal %d. Ndbd failed startup (%u).", signum, failed_startups);
+ g_eventLogger.info("Angel received ndbd startup failure count %u.", failed_startups);
}
diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp
index 374d1f8de04..fae0941beb8 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.cpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -39,6 +39,8 @@
#include <signaldata/BackupSignalData.hpp>
#include <signaldata/GrepImpl.hpp>
#include <signaldata/ManagementServer.hpp>
+#include <signaldata/NFCompleteRep.hpp>
+#include <signaldata/NodeFailRep.hpp>
#include <NdbSleep.h>
#include <EventLogger.hpp>
#include <DebuggerNames.hpp>
@@ -56,6 +58,8 @@
#include <mgmapi_config_parameters.h>
#include <m_string.h>
+#include <SignalSender.hpp>
+
//#define MGM_SRV_DEBUG
#ifdef MGM_SRV_DEBUG
#define DEBUG(x) do ndbout << x << endl; while(0)
@@ -727,6 +731,15 @@ int MgmtSrvr::okToSendTo(NodeId processId, bool unCond)
}
}
+void report_unknown_signal(SimpleSignal *signal)
+{
+ g_eventLogger.error("Unknown signal received. SignalNumber: "
+ "%i from (%d, %x)",
+ signal->readSignalNumber(),
+ refToNode(signal->header.theSendersBlockRef),
+ refToBlock(signal->header.theSendersBlockRef));
+}
+
/*****************************************************************************
* Starting and stopping database nodes
****************************************************************************/
@@ -1927,81 +1940,6 @@ MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal)
}
break;
- case GSN_BACKUP_CONF:{
- const BackupConf * const conf =
- CAST_CONSTPTR(BackupConf, signal->getDataPtr());
- BackupEvent event;
- event.Event = BackupEvent::BackupStarted;
- event.Started.BackupId = conf->backupId;
- event.Nodes = conf->nodes;
-#ifdef VM_TRACE
- ndbout_c("Backup master is %d", refToNode(signal->theSendersBlockRef));
-#endif
- backupCallback(event);
- }
- break;
-
- case GSN_BACKUP_REF:{
- const BackupRef * const ref =
- CAST_CONSTPTR(BackupRef, signal->getDataPtr());
- Uint32 errCode = ref->errorCode;
- if(ref->errorCode == BackupRef::IAmNotMaster){
- const Uint32 aNodeId = refToNode(ref->masterRef);
-#ifdef VM_TRACE
- ndbout_c("I'm not master resending to %d", aNodeId);
-#endif
- theWaitNode= aNodeId;
- NdbApiSignal aSignal(_ownReference);
- BackupReq* req = CAST_PTR(BackupReq, aSignal.getDataPtrSend());
- aSignal.set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ,
- BackupReq::SignalLength);
- req->senderData = 19;
- req->backupDataLen = 0;
-
- int i = theFacade->sendSignalUnCond(&aSignal, aNodeId);
- if(i == 0){
- return;
- }
- errCode = 5030;
- }
- BackupEvent event;
- event.Event = BackupEvent::BackupFailedToStart;
- event.FailedToStart.ErrorCode = errCode;
- backupCallback(event);
- break;
- }
-
- case GSN_BACKUP_ABORT_REP:{
- const BackupAbortRep * const rep =
- CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr());
- BackupEvent event;
- event.Event = BackupEvent::BackupAborted;
- event.Aborted.Reason = rep->reason;
- event.Aborted.BackupId = rep->backupId;
- event.Aborted.ErrorCode = rep->reason;
- backupCallback(event);
- }
- break;
-
- case GSN_BACKUP_COMPLETE_REP:{
- const BackupCompleteRep * const rep =
- CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr());
- BackupEvent event;
- event.Event = BackupEvent::BackupCompleted;
- event.Completed.BackupId = rep->backupId;
-
- event.Completed.NoOfBytes = rep->noOfBytes;
- event.Completed.NoOfLogBytes = rep->noOfLogBytes;
- event.Completed.NoOfRecords = rep->noOfRecords;
- event.Completed.NoOfLogRecords = rep->noOfLogRecords;
- event.Completed.stopGCP = rep->stopGCP;
- event.Completed.startGCP = rep->startGCP;
- event.Nodes = rep->nodes;
-
- backupCallback(event);
- }
- break;
-
case GSN_MGM_LOCK_CONFIG_REP:
case GSN_MGM_LOCK_CONFIG_REQ:
case GSN_MGM_UNLOCK_CONFIG_REP:
@@ -2466,6 +2404,9 @@ MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData)
int
MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted)
{
+ SignalSender ss(theFacade);
+ ss.lock(); // lock will be released on exit
+
bool next;
NodeId nodeId = 0;
while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
@@ -2473,50 +2414,127 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted)
if(!next) return NO_CONTACT_WITH_DB_NODES;
- NdbApiSignal* signal = getSignal();
- if (signal == NULL) {
- return COULD_NOT_ALLOCATE_MEMORY;
- }
+ SimpleSignal ssig;
- BackupReq* req = CAST_PTR(BackupReq, signal->getDataPtrSend());
- signal->set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ,
- BackupReq::SignalLength);
+ BackupReq* req = CAST_PTR(BackupReq, ssig.getDataPtrSend());
+ ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ,
+ BackupReq::SignalLength);
req->senderData = 19;
req->backupDataLen = 0;
+ assert(waitCompleted < 3);
+ req->flags = waitCompleted & 0x3;
- int result;
- if (waitCompleted == 2) {
- result = sendRecSignal(nodeId, WAIT_BACKUP_COMPLETED,
- signal, true, 48*60*60*1000 /* 48 hours */);
- }
- else if (waitCompleted == 1) {
- result = sendRecSignal(nodeId, WAIT_BACKUP_STARTED,
- signal, true, 5*60*1000 /*5 mins*/);
- }
- else {
- result = sendRecSignal(nodeId, NO_WAIT, signal, true);
- }
- if (result == -1) {
- return SEND_OR_RECEIVE_FAILED;
- }
-
- if (waitCompleted){
- switch(m_lastBackupEvent.Event){
- case BackupEvent::BackupCompleted:
- backupId = m_lastBackupEvent.Completed.BackupId;
+ BackupEvent event;
+ int do_send = 1;
+ while (1) {
+ if (do_send)
+ {
+ SendStatus result = ss.sendSignal(nodeId, &ssig);
+ if (result != SEND_OK) {
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ if (waitCompleted == 0)
+ return 0;
+ do_send = 0;
+ }
+ SimpleSignal *signal = ss.waitFor();
+
+ int gsn = signal->readSignalNumber();
+ switch (gsn) {
+ case GSN_BACKUP_CONF:{
+ const BackupConf * const conf =
+ CAST_CONSTPTR(BackupConf, signal->getDataPtr());
+ event.Event = BackupEvent::BackupStarted;
+ event.Started.BackupId = conf->backupId;
+ event.Nodes = conf->nodes;
+#ifdef VM_TRACE
+ ndbout_c("Backup(%d) master is %d", conf->backupId,
+ refToNode(signal->header.theSendersBlockRef));
+#endif
+ backupId = conf->backupId;
+ if (waitCompleted == 1)
+ return 0;
+ // wait for next signal
break;
- case BackupEvent::BackupStarted:
- backupId = m_lastBackupEvent.Started.BackupId;
+ }
+ case GSN_BACKUP_COMPLETE_REP:{
+ const BackupCompleteRep * const rep =
+ CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("Backup(%d) completed %d", rep->backupId);
+#endif
+ event.Event = BackupEvent::BackupCompleted;
+ event.Completed.BackupId = rep->backupId;
+
+ event.Completed.NoOfBytes = rep->noOfBytes;
+ event.Completed.NoOfLogBytes = rep->noOfLogBytes;
+ event.Completed.NoOfRecords = rep->noOfRecords;
+ event.Completed.NoOfLogRecords = rep->noOfLogRecords;
+ event.Completed.stopGCP = rep->stopGCP;
+ event.Completed.startGCP = rep->startGCP;
+ event.Nodes = rep->nodes;
+
+ backupId = rep->backupId;
+ return 0;
+ }
+ case GSN_BACKUP_REF:{
+ const BackupRef * const ref =
+ CAST_CONSTPTR(BackupRef, signal->getDataPtr());
+ if(ref->errorCode == BackupRef::IAmNotMaster){
+ nodeId = refToNode(ref->masterRef);
+#ifdef VM_TRACE
+ ndbout_c("I'm not master resending to %d", nodeId);
+#endif
+ do_send = 1; // try again
+ continue;
+ }
+ event.Event = BackupEvent::BackupFailedToStart;
+ event.FailedToStart.ErrorCode = ref->errorCode;
+ return ref->errorCode;
+ }
+ case GSN_BACKUP_ABORT_REP:{
+ const BackupAbortRep * const rep =
+ CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr());
+ event.Event = BackupEvent::BackupAborted;
+ event.Aborted.Reason = rep->reason;
+ event.Aborted.BackupId = rep->backupId;
+ event.Aborted.ErrorCode = rep->reason;
+#ifdef VM_TRACE
+ ndbout_c("Backup %d aborted", rep->backupId);
+#endif
+ return rep->reason;
+ }
+ case GSN_NF_COMPLETEREP:{
+ const NFCompleteRep * const rep =
+ CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("Node %d fail completed", rep->failedNodeId);
+#endif
+ if (rep->failedNodeId == nodeId ||
+ waitCompleted == 1)
+ return 1326;
+ // wait for next signal
+ // master node will report aborted backup
break;
- case BackupEvent::BackupFailedToStart:
- return m_lastBackupEvent.FailedToStart.ErrorCode;
- case BackupEvent::BackupAborted:
- return m_lastBackupEvent.Aborted.ErrorCode;
- default:
- return -1;
+ }
+ case GSN_NODE_FAILREP:{
+ const NodeFailRep * const rep =
+ CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("Node %d failed", rep->failNo);
+#endif
+ if (rep->failNo == nodeId ||
+ waitCompleted == 1)
+ return 1326;
+ // wait for next signal
+ // master node will report aborted backup
break;
}
+ default:
+ report_unknown_signal(signal);
+ return SEND_OR_RECEIVE_FAILED;
+ }
}
return 0;
@@ -2555,36 +2573,6 @@ MgmtSrvr::abortBackup(Uint32 backupId)
return 0;
}
-void
-MgmtSrvr::backupCallback(BackupEvent & event)
-{
- DBUG_ENTER("MgmtSrvr::backupCallback");
- m_lastBackupEvent = event;
- switch(event.Event){
- case BackupEvent::BackupFailedToStart:
- DBUG_PRINT("info",("BackupEvent::BackupFailedToStart"));
- theWaitState = NO_WAIT;
- break;
- case BackupEvent::BackupAborted:
- DBUG_PRINT("info",("BackupEvent::BackupAborted"));
- theWaitState = NO_WAIT;
- break;
- case BackupEvent::BackupCompleted:
- DBUG_PRINT("info",("BackupEvent::BackupCompleted"));
- theWaitState = NO_WAIT;
- break;
- case BackupEvent::BackupStarted:
- if(theWaitState == WAIT_BACKUP_STARTED)
- {
- DBUG_PRINT("info",("BackupEvent::BackupStarted NO_WAIT"));
- theWaitState = NO_WAIT;
- } else {
- DBUG_PRINT("info",("BackupEvent::BackupStarted"));
- }
- }
- DBUG_VOID_RETURN;
-}
-
/*****************************************************************************
* Global Replication
diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp
index b7983e6b441..de1af1286ff 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.hpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.hpp
@@ -768,9 +768,6 @@ private:
static void *signalRecvThread_C(void *);
void signalRecvThreadRun();
- void backupCallback(BackupEvent &);
- BackupEvent m_lastBackupEvent;
-
Config *_props;
int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type);
diff --git a/ndb/src/ndbapi/Makefile.am b/ndb/src/ndbapi/Makefile.am
index b734e058b87..99b75ffbd53 100644
--- a/ndb/src/ndbapi/Makefile.am
+++ b/ndb/src/ndbapi/Makefile.am
@@ -34,7 +34,8 @@ libndbapi_la_SOURCES = \
NdbDictionaryImpl.cpp \
DictCache.cpp \
ndb_cluster_connection.cpp \
- NdbBlob.cpp
+ NdbBlob.cpp \
+ SignalSender.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi
diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp
index 675c9383c6e..294012d780c 100644
--- a/ndb/src/ndbapi/NdbTransaction.cpp
+++ b/ndb/src/ndbapi/NdbTransaction.cpp
@@ -264,6 +264,7 @@ NdbTransaction::execute(ExecType aTypeOfExec,
AbortOption abortOption,
int forceSend)
{
+ NdbError savedError= theError;
DBUG_ENTER("NdbTransaction::execute");
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
aTypeOfExec, abortOption));
@@ -293,7 +294,11 @@ NdbTransaction::execute(ExecType aTypeOfExec,
NdbBlob* tBlob = tPrepOp->theBlobList;
while (tBlob != NULL) {
if (tBlob->preExecute(tExecType, batch) == -1)
+ {
ret = -1;
+ if(savedError.code==0)
+ savedError= theError;
+ }
tBlob = tBlob->theNext;
}
if (batch) {
@@ -322,7 +327,11 @@ NdbTransaction::execute(ExecType aTypeOfExec,
NdbBlob* tBlob = tOp->theBlobList;
while (tBlob != NULL) {
if (tBlob->preCommit() == -1)
- ret = -1;
+ {
+ ret = -1;
+ if(savedError.code==0)
+ savedError= theError;
+ }
tBlob = tBlob->theNext;
}
}
@@ -344,7 +353,12 @@ NdbTransaction::execute(ExecType aTypeOfExec,
}
if (executeNoBlobs(tExecType, abortOption, forceSend) == -1)
- ret = -1;
+ {
+ ret = -1;
+ if(savedError.code==0)
+ savedError= theError;
+ }
+
#ifdef ndb_api_crash_on_complex_blob_abort
assert(theFirstOpInList == NULL && theLastOpInList == NULL);
#else
@@ -359,7 +373,11 @@ NdbTransaction::execute(ExecType aTypeOfExec,
while (tBlob != NULL) {
// may add new operations if batch
if (tBlob->postExecute(tExecType) == -1)
+ {
ret = -1;
+ if(savedError.code==0)
+ savedError= theError;
+ }
tBlob = tBlob->theNext;
}
}
@@ -390,6 +408,10 @@ NdbTransaction::execute(ExecType aTypeOfExec,
ndbout << "completed ops: " << n << endl;
}
#endif
+
+ if(savedError.code!=0 && theError.code==4350) // Trans already aborted
+ theError= savedError;
+
DBUG_RETURN(ret);
}
diff --git a/ndb/src/ndbapi/SignalSender.cpp b/ndb/src/ndbapi/SignalSender.cpp
new file mode 100644
index 00000000000..6314361e55c
--- /dev/null
+++ b/ndb/src/ndbapi/SignalSender.cpp
@@ -0,0 +1,269 @@
+/* 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 "SignalSender.hpp"
+#include <NdbSleep.h>
+#include <SignalLoggerManager.hpp>
+#include <signaldata/NFCompleteRep.hpp>
+#include <signaldata/NodeFailRep.hpp>
+
+SimpleSignal::SimpleSignal(bool dealloc){
+ memset(this, 0, sizeof(* this));
+ deallocSections = dealloc;
+}
+
+SimpleSignal::~SimpleSignal(){
+ if(!deallocSections)
+ return;
+ if(ptr[0].p != 0) delete []ptr[0].p;
+ if(ptr[1].p != 0) delete []ptr[1].p;
+ if(ptr[2].p != 0) delete []ptr[2].p;
+}
+
+void
+SimpleSignal::set(class SignalSender& ss,
+ Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len){
+
+ header.theTrace = trace;
+ header.theReceiversBlockNumber = recBlock;
+ header.theVerId_signalNumber = gsn;
+ header.theLength = len;
+ header.theSendersBlockRef = refToBlock(ss.getOwnRef());
+}
+
+void
+SimpleSignal::print(FILE * out){
+ fprintf(out, "---- Signal ----------------\n");
+ SignalLoggerManager::printSignalHeader(out, header, 0, 0, false);
+ SignalLoggerManager::printSignalData(out, header, theData);
+ for(Uint32 i = 0; i<header.m_noOfSections; i++){
+ Uint32 len = ptr[i].sz;
+ fprintf(out, " --- Section %d size=%d ---\n", i, len);
+ Uint32 * signalData = ptr[i].p;
+ while(len >= 7){
+ fprintf(out,
+ " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n",
+ signalData[0], signalData[1], signalData[2], signalData[3],
+ signalData[4], signalData[5], signalData[6]);
+ len -= 7;
+ signalData += 7;
+ }
+ if(len > 0){
+ fprintf(out, " H\'%.8x", signalData[0]);
+ for(Uint32 i = 1; i<len; i++)
+ fprintf(out, " H\'%.8x", signalData[i]);
+ fprintf(out, "\n");
+ }
+ }
+}
+
+SignalSender::SignalSender(TransporterFacade *facade)
+ : m_lock(0)
+{
+ m_cond = NdbCondition_Create();
+ theFacade = facade;
+ m_blockNo = theFacade->open(this, execSignal, execNodeStatus);
+ assert(m_blockNo > 0);
+}
+
+SignalSender::~SignalSender(){
+ int i;
+ if (m_lock)
+ unlock();
+ theFacade->close(m_blockNo,0);
+ // free these _after_ closing theFacade to ensure that
+ // we delete all signals
+ for (i= m_jobBuffer.size()-1; i>= 0; i--)
+ delete m_jobBuffer[i];
+ for (i= m_usedBuffer.size()-1; i>= 0; i--)
+ delete m_usedBuffer[i];
+ NdbCondition_Destroy(m_cond);
+}
+
+int SignalSender::lock()
+{
+ if (NdbMutex_Lock(theFacade->theMutexPtr))
+ return -1;
+ m_lock= 1;
+ return 0;
+}
+
+int SignalSender::unlock()
+{
+ if (NdbMutex_Unlock(theFacade->theMutexPtr))
+ return -1;
+ m_lock= 0;
+ return 0;
+}
+
+Uint32
+SignalSender::getOwnRef() const {
+ return numberToRef(m_blockNo, theFacade->ownId());
+}
+
+Uint32
+SignalSender::getAliveNode() const{
+ return theFacade->get_an_alive_node();
+}
+
+const ClusterMgr::Node &
+SignalSender::getNodeInfo(Uint16 nodeId) const {
+ return theFacade->theClusterMgr->getNodeInfo(nodeId);
+}
+
+Uint32
+SignalSender::getNoOfConnectedNodes() const {
+ return theFacade->theClusterMgr->getNoOfConnectedNodes();
+}
+
+SendStatus
+SignalSender::sendSignal(Uint16 nodeId, const SimpleSignal * s){
+ return theFacade->theTransporterRegistry->prepareSend(&s->header,
+ 1, // JBB
+ &s->theData[0],
+ nodeId,
+ &s->ptr[0]);
+}
+
+template<class T>
+SimpleSignal *
+SignalSender::waitFor(Uint32 timeOutMillis, T & t)
+{
+ SimpleSignal * s = t.check(m_jobBuffer);
+ if(s != 0){
+ return s;
+ }
+
+ NDB_TICKS now = NdbTick_CurrentMillisecond();
+ NDB_TICKS stop = now + timeOutMillis;
+ Uint32 wait = (timeOutMillis == 0 ? 10 : timeOutMillis);
+ do {
+ NdbCondition_WaitTimeout(m_cond,
+ theFacade->theMutexPtr,
+ wait);
+
+
+ SimpleSignal * s = t.check(m_jobBuffer);
+ if(s != 0){
+ m_usedBuffer.push_back(s);
+ return s;
+ }
+
+ now = NdbTick_CurrentMillisecond();
+ wait = (timeOutMillis == 0 ? 10 : stop - now);
+ } while(stop > now || timeOutMillis == 0);
+
+ return 0;
+}
+
+class WaitForAny {
+public:
+ SimpleSignal * check(Vector<SimpleSignal*> & m_jobBuffer){
+ if(m_jobBuffer.size() > 0){
+ SimpleSignal * s = m_jobBuffer[0];
+ m_jobBuffer.erase(0);
+ return s;
+ }
+ return 0;
+ }
+};
+
+SimpleSignal *
+SignalSender::waitFor(Uint32 timeOutMillis){
+
+ WaitForAny w;
+ return waitFor(timeOutMillis, w);
+}
+
+class WaitForNode {
+public:
+ Uint32 m_nodeId;
+ SimpleSignal * check(Vector<SimpleSignal*> & m_jobBuffer){
+ Uint32 len = m_jobBuffer.size();
+ for(Uint32 i = 0; i<len; i++){
+ if(refToNode(m_jobBuffer[i]->header.theSendersBlockRef) == m_nodeId){
+ SimpleSignal * s = m_jobBuffer[i];
+ m_jobBuffer.erase(i);
+ return s;
+ }
+ }
+ return 0;
+ }
+};
+
+SimpleSignal *
+SignalSender::waitFor(Uint16 nodeId, Uint32 timeOutMillis){
+
+ WaitForNode w;
+ w.m_nodeId = nodeId;
+ return waitFor(timeOutMillis, w);
+}
+
+#include <NdbApiSignal.hpp>
+
+void
+SignalSender::execSignal(void* signalSender,
+ NdbApiSignal* signal,
+ class LinearSectionPtr ptr[3]){
+ SimpleSignal * s = new SimpleSignal(true);
+ s->header = * signal;
+ memcpy(&s->theData[0], signal->getDataPtr(), 4 * s->header.theLength);
+ for(Uint32 i = 0; i<s->header.m_noOfSections; i++){
+ s->ptr[i].p = new Uint32[ptr[i].sz];
+ s->ptr[i].sz = ptr[i].sz;
+ memcpy(s->ptr[i].p, ptr[i].p, 4 * ptr[i].sz);
+ }
+ SignalSender * ss = (SignalSender*)signalSender;
+ ss->m_jobBuffer.push_back(s);
+ NdbCondition_Signal(ss->m_cond);
+}
+
+void
+SignalSender::execNodeStatus(void* signalSender,
+ Uint32 nodeId,
+ bool alive,
+ bool nfCompleted){
+ if (alive) {
+ // node connected
+ return;
+ }
+
+ SimpleSignal * s = new SimpleSignal(true);
+ SignalSender * ss = (SignalSender*)signalSender;
+
+ // node disconnected
+ if(nfCompleted)
+ {
+ // node shutdown complete
+ s->header.theVerId_signalNumber = GSN_NF_COMPLETEREP;
+ NFCompleteRep *rep = (NFCompleteRep *)s->getDataPtrSend();
+ rep->failedNodeId = nodeId;
+ }
+ else
+ {
+ // node failure
+ s->header.theVerId_signalNumber = GSN_NODE_FAILREP;
+ NodeFailRep *rep = (NodeFailRep *)s->getDataPtrSend();
+ rep->failNo = nodeId;
+ }
+
+ ss->m_jobBuffer.push_back(s);
+ NdbCondition_Signal(ss->m_cond);
+}
+
+template SimpleSignal* SignalSender::waitFor<WaitForNode>(unsigned, WaitForNode&);
+template SimpleSignal* SignalSender::waitFor<WaitForAny>(unsigned, WaitForAny&);
+template class Vector<SimpleSignal*>;
diff --git a/ndb/src/ndbapi/SignalSender.hpp b/ndb/src/ndbapi/SignalSender.hpp
new file mode 100644
index 00000000000..4b991460034
--- /dev/null
+++ b/ndb/src/ndbapi/SignalSender.hpp
@@ -0,0 +1,83 @@
+/* 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 SIGNAL_SENDER_HPP
+#define SIGNAL_SENDER_HPP
+
+#include <ndb_global.h>
+#include "TransporterFacade.hpp"
+#include <Vector.hpp>
+
+struct SimpleSignal {
+public:
+ SimpleSignal(bool dealloc = false);
+ ~SimpleSignal();
+
+ void set(class SignalSender&,
+ Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len);
+
+ struct SignalHeader header;
+ Uint32 theData[25];
+ LinearSectionPtr ptr[3];
+
+ int readSignalNumber() {return header.theVerId_signalNumber; }
+ Uint32 *getDataPtrSend() { return theData; }
+ const Uint32 *getDataPtr() const { return theData; }
+
+ void print(FILE * out = stdout);
+private:
+ bool deallocSections;
+};
+
+class SignalSender {
+public:
+ SignalSender(TransporterFacade *facade);
+ virtual ~SignalSender();
+
+ int lock();
+ int unlock();
+
+ Uint32 getOwnRef() const;
+ Uint32 getAliveNode() const;
+ const ClusterMgr::Node &getNodeInfo(Uint16 nodeId) const;
+ Uint32 getNoOfConnectedNodes() const;
+
+ SendStatus sendSignal(Uint16 nodeId, const SimpleSignal *);
+
+ SimpleSignal * waitFor(Uint32 timeOutMillis = 0);
+ SimpleSignal * waitFor(Uint16 nodeId, Uint32 timeOutMillis = 0);
+ SimpleSignal * waitFor(Uint16 nodeId, Uint16 gsn, Uint32 timeOutMillis = 0);
+private:
+ int m_blockNo;
+ TransporterFacade * theFacade;
+
+ static void execSignal(void* signalSender,
+ NdbApiSignal* signal,
+ class LinearSectionPtr ptr[3]);
+
+ static void execNodeStatus(void* signalSender, Uint32 nodeId,
+ bool alive, bool nfCompleted);
+
+ int m_lock;
+ struct NdbCondition * m_cond;
+ Vector<SimpleSignal *> m_jobBuffer;
+ Vector<SimpleSignal *> m_usedBuffer;
+
+ template<class T>
+ SimpleSignal * waitFor(Uint32 timeOutMillis, T & t);
+};
+
+#endif
diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp
index fe101b9c80b..9f65fe6b3bc 100644
--- a/ndb/test/src/NdbBackup.cpp
+++ b/ndb/test/src/NdbBackup.cpp
@@ -50,14 +50,17 @@ NdbBackup::start(unsigned int & _backup_id){
2, // wait until completed
&_backup_id,
&reply) == -1) {
- g_err << "Could not start backup " << endl;
- g_err << "Error: " << reply.message << endl;
+ g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl;
+ g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl;
+ g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl;
return -1;
}
if(reply.return_code != 0){
g_err << "PLEASE CHECK CODE NdbBackup.cpp line=" << __LINE__ << endl;
- g_err << "Error: " << reply.message << endl;
+ g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl;
+ g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl;
+ g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl;
return reply.return_code;
}
return 0;
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
index 74ff3457cd2..5c3cbdcf2ca 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -651,7 +651,8 @@ int ha_tina::rnd_init(bool scan)
records= 0;
chain_ptr= chain;
#ifdef HAVE_MADVISE
- (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
+ if (scan)
+ (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
#endif
DBUG_RETURN(0);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index aa53b69a617..4ed5fadb603 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -4687,13 +4687,7 @@ ha_innobase::create(
form->s->row_type != ROW_TYPE_REDUNDANT);
if (error) {
- innobase_commit_low(trx);
-
- row_mysql_unlock_data_dictionary(trx);
-
- trx_free_for_mysql(trx);
-
- DBUG_RETURN(error);
+ goto cleanup;
}
/* Look for a primary key */
@@ -4717,13 +4711,7 @@ ha_innobase::create(
error = create_clustered_index_when_no_primary(trx,
norm_name);
if (error) {
- innobase_commit_low(trx);
-
- row_mysql_unlock_data_dictionary(trx);
-
- trx_free_for_mysql(trx);
-
- DBUG_RETURN(error);
+ goto cleanup;
}
}
@@ -4732,13 +4720,7 @@ ha_innobase::create(
first */
if ((error = create_index(trx, form, norm_name,
(uint) primary_key_no))) {
- innobase_commit_low(trx);
-
- row_mysql_unlock_data_dictionary(trx);
-
- trx_free_for_mysql(trx);
-
- DBUG_RETURN(error);
+ goto cleanup;
}
}
@@ -4747,14 +4729,7 @@ ha_innobase::create(
if (i != (uint) primary_key_no) {
if ((error = create_index(trx, form, norm_name, i))) {
-
- innobase_commit_low(trx);
-
- row_mysql_unlock_data_dictionary(trx);
-
- trx_free_for_mysql(trx);
-
- DBUG_RETURN(error);
+ goto cleanup;
}
}
}
@@ -4767,21 +4742,18 @@ ha_innobase::create(
current_thd->query_length,
current_thd->charset())) {
error = HA_ERR_OUT_OF_MEM;
- } else {
- error = row_table_add_foreign_constraints(trx,
- q.str, norm_name);
-
- error = convert_error_code_to_mysql(error, NULL);
+
+ goto cleanup;
}
- if (error) {
- innobase_commit_low(trx);
-
- row_mysql_unlock_data_dictionary(trx);
+ error = row_table_add_foreign_constraints(trx,
+ q.str, norm_name,
+ create_info->options & HA_LEX_CREATE_TMP_TABLE);
- trx_free_for_mysql(trx);
+ error = convert_error_code_to_mysql(error, NULL);
- DBUG_RETURN(error);
+ if (error) {
+ goto cleanup;
}
}
@@ -4821,6 +4793,15 @@ ha_innobase::create(
trx_free_for_mysql(trx);
DBUG_RETURN(0);
+
+cleanup:
+ innobase_commit_low(trx);
+
+ row_mysql_unlock_data_dictionary(trx);
+
+ trx_free_for_mysql(trx);
+
+ DBUG_RETURN(error);
}
/*********************************************************************
diff --git a/sql/item.cc b/sql/item.cc
index b4992faa65e..e7da646ae73 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -818,8 +818,25 @@ String *Item_splocal::val_str(String *sp)
DBUG_ASSERT(fixed);
Item *it= this_item();
String *ret= it->val_str(sp);
+ /*
+ This way we mark returned value of val_str as const,
+ so that various functions (e.g. CONCAT) won't try to
+ modify the value of the Item. Analogous mechanism is
+ implemented for Item_param.
+ Without this trick Item_splocal could be changed as a
+ side-effect of expression computation. Here is an example
+ of what happens without it: suppose x is varchar local
+ variable in a SP with initial value 'ab' Then
+ select concat(x,'c');
+ would change x's value to 'abc', as Item_func_concat::val_str()
+ would use x's internal buffer to compute the result.
+ This is intended behaviour of Item_func_concat. Comments to
+ Item_param class contain some more details on the topic.
+ */
+ str_value_ptr.set(ret->ptr(), ret->length(),
+ ret->charset());
null_value= it->null_value;
- return ret;
+ return &str_value_ptr;
}
@@ -1022,9 +1039,9 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
/* Will split complicated items and ignore simple ones */
split_sum_func(thd, ref_pointer_array, fields);
}
- else if ((type() == SUM_FUNC_ITEM ||
- (used_tables() & ~PARAM_TABLE_BIT)) &&
- type() != REF_ITEM)
+ else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) &&
+ (type() != REF_ITEM ||
+ ((Item_ref*)this)->ref_type() == Item_ref::VIEW_REF))
{
/*
Replace item with a reference so that we can easily calculate
@@ -1033,15 +1050,17 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
The test above is to ensure we don't do a reference for things
that are constants (PARAM_TABLE_BIT is in effect a constant)
or already referenced (for example an item in HAVING)
+ Exception is Item_direct_view_ref which we need to convert to
+ Item_ref to allow fields from view being stored in tmp table.
*/
uint el= fields.elements;
- Item *new_item;
- ref_pointer_array[el]= this;
+ Item *new_item, *real_itm= real_item();
+
+ ref_pointer_array[el]= real_itm;
if (!(new_item= new Item_ref(&thd->lex->current_select->context,
ref_pointer_array + el, 0, name)))
return; // fatal_error is set
- fields.push_front(this);
- ref_pointer_array[el]= this;
+ fields.push_front(real_itm);
thd->change_item_tree(ref, new_item);
}
}
diff --git a/sql/item.h b/sql/item.h
index b934e1f9f3f..381ba98e193 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -715,9 +715,17 @@ public:
class Item_splocal : public Item
{
uint m_offset;
+
public:
LEX_STRING m_name;
+ /*
+ Buffer, pointing to the string value of the item. We need it to
+ protect internal buffer from changes. See comment to analogous
+ member in Item_param for more details.
+ */
+ String str_value_ptr;
+
/*
Position of this reference to SP variable in the statement (the
statement itself is in sp_instr_stmt::m_query).
@@ -1537,6 +1545,7 @@ class Item_ref :public Item_ident
protected:
void set_properties();
public:
+ enum Ref_Type { REF, DIRECT_REF, VIEW_REF };
Field *result_field; /* Save result here */
Item **ref;
Item_ref(Name_resolution_context *context_arg,
@@ -1617,6 +1626,7 @@ public:
void cleanup();
Item_field *filed_for_view_update()
{ return (*ref)->filed_for_view_update(); }
+ virtual Ref_Type ref_type() { return REF; }
};
@@ -1641,6 +1651,7 @@ public:
bool val_bool();
bool is_null();
bool get_date(TIME *ltime,uint fuzzydate);
+ virtual Ref_Type ref_type() { return DIRECT_REF; }
};
/*
@@ -1660,6 +1671,7 @@ public:
bool fix_fields(THD *, Item **);
bool eq(const Item *item, bool binary_cmp) const;
+ virtual Ref_Type ref_type() { return VIEW_REF; }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index cc2849ff7e6..5079c462ac0 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -988,6 +988,53 @@ longlong Item_func_interval::val_int()
}
+/*
+ Perform context analysis of a BETWEEN item tree
+
+ SYNOPSIS:
+ fix_fields()
+ thd reference to the global context of the query thread
+ tables list of all open tables involved in the query
+ ref pointer to Item* variable where pointer to resulting "fixed"
+ item is to be assigned
+
+ DESCRIPTION
+ This function performs context analysis (name resolution) and calculates
+ various attributes of the item tree with Item_func_between as its root.
+ The function saves in ref the pointer to the item or to a newly created
+ item that is considered as a replacement for the original one.
+
+ NOTES
+ Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
+ a predicate/function level. Then it's easy to show that:
+ T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2))
+ T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
+ T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
+ T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
+
+ RETURN
+ 0 ok
+ 1 got error
+*/
+
+bool
+Item_func_between::fix_fields(THD *thd, Item **ref)
+{
+ if (Item_func_opt_neg::fix_fields(thd, ref))
+ return 1;
+
+ /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
+ if (pred_level && !negated)
+ return 0;
+
+ /* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */
+ not_null_tables_cache= args[0]->not_null_tables() |
+ (args[1]->not_null_tables() & args[2]->not_null_tables());
+
+ return 0;
+}
+
+
void Item_func_between::fix_length_and_dec()
{
max_length= 1;
@@ -1040,8 +1087,9 @@ longlong Item_func_between::val_int()
a=args[1]->val_str(&value1);
b=args[2]->val_str(&value2);
if (!args[1]->null_value && !args[2]->null_value)
- return (sortcmp(value,a,cmp_collation.collation) >= 0 &&
- sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0;
+ return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
+ sortcmp(value,b,cmp_collation.collation) <= 0) !=
+ negated);
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
@@ -1063,7 +1111,7 @@ longlong Item_func_between::val_int()
a=args[1]->val_int();
b=args[2]->val_int();
if (!args[1]->null_value && !args[2]->null_value)
- return (value >= a && value <= b) ? 1 : 0;
+ return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
@@ -1084,8 +1132,8 @@ longlong Item_func_between::val_int()
a_dec= args[1]->val_decimal(&a_buf);
b_dec= args[2]->val_decimal(&b_buf);
if (!args[1]->null_value && !args[2]->null_value)
- return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0);
-
+ return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
+ my_decimal_cmp(dec, b_dec) <= 0) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
@@ -1101,7 +1149,7 @@ longlong Item_func_between::val_int()
a= args[1]->val_real();
b= args[2]->val_real();
if (!args[1]->null_value && !args[2]->null_value)
- return (value >= a && value <= b) ? 1 : 0;
+ return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
@@ -1113,7 +1161,7 @@ longlong Item_func_between::val_int()
null_value= value >= a;
}
}
- return 0;
+ return (longlong) (!null_value && negated);
}
@@ -1244,6 +1292,49 @@ Item_func_ifnull::str_op(String *str)
}
+/*
+ Perform context analysis of an IF item tree
+
+ SYNOPSIS:
+ fix_fields()
+ thd reference to the global context of the query thread
+ tables list of all open tables involved in the query
+ ref pointer to Item* variable where pointer to resulting "fixed"
+ item is to be assigned
+
+ DESCRIPTION
+ This function performs context analysis (name resolution) and calculates
+ various attributes of the item tree with Item_func_if as its root.
+ The function saves in ref the pointer to the item or to a newly created
+ item that is considered as a replacement for the original one.
+
+ NOTES
+ Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
+ a predicate/function level. Then it's easy to show that:
+ T0(IF(e,e1,e2) = T1(IF(e,e1,e2))
+ T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2))
+
+ RETURN
+ 0 ok
+ 1 got error
+*/
+
+bool
+Item_func_if::fix_fields(THD *thd, Item **ref)
+{
+ DBUG_ASSERT(fixed == 0);
+ args[0]->top_level_item();
+
+ if (Item_func::fix_fields(thd, ref))
+ return 1;
+
+ not_null_tables_cache= (args[1]->not_null_tables()
+ & args[2]->not_null_tables());
+
+ return 0;
+}
+
+
void
Item_func_if::fix_length_and_dec()
{
@@ -2184,6 +2275,56 @@ bool Item_func_in::nulls_in_row()
}
+/*
+ Perform context analysis of an IN item tree
+
+ SYNOPSIS:
+ fix_fields()
+ thd reference to the global context of the query thread
+ tables list of all open tables involved in the query
+ ref pointer to Item* variable where pointer to resulting "fixed"
+ item is to be assigned
+
+ DESCRIPTION
+ This function performs context analysis (name resolution) and calculates
+ various attributes of the item tree with Item_func_in as its root.
+ The function saves in ref the pointer to the item or to a newly created
+ item that is considered as a replacement for the original one.
+
+ NOTES
+ Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
+ a predicate/function level. Then it's easy to show that:
+ T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
+ T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
+ T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei)))
+ T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
+
+ RETURN
+ 0 ok
+ 1 got error
+*/
+
+bool
+Item_func_in::fix_fields(THD *thd, Item **ref)
+{
+ Item **arg, **arg_end;
+
+ if (Item_func_opt_neg::fix_fields(thd, ref))
+ return 1;
+
+ /* not_null_tables_cache == union(T1(e),union(T1(ei))) */
+ if (pred_level && negated)
+ return 0;
+
+ /* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
+ not_null_tables_cache= ~(table_map) 0;
+ for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++)
+ not_null_tables_cache&= (*arg)->not_null_tables();
+ not_null_tables_cache|= (*args)->not_null_tables();
+ return 0;
+}
+
+
static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{
return cs->coll->strnncollsp(cs,
@@ -2283,7 +2424,7 @@ longlong Item_func_in::val_int()
{
int tmp=array->find(args[0]);
null_value=args[0]->null_value || (!tmp && have_null);
- return tmp;
+ return (longlong) (!null_value && tmp != negated);
}
in_item->store_value(args[0]);
if ((null_value=args[0]->null_value))
@@ -2292,11 +2433,11 @@ longlong Item_func_in::val_int()
for (uint i=1 ; i < arg_count ; i++)
{
if (!in_item->cmp(args[i]) && !args[i]->null_value)
- return 1; // Would maybe be nice with i ?
+ return (longlong) (!negated);
have_null|= args[i]->null_value;
}
null_value= have_null;
- return 0;
+ return (longlong) (!null_value && negated);
}
@@ -2811,7 +2952,42 @@ 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= escape_str ? *(escape_str->ptr()) : '\\';
+ if (escape_str)
+ {
+ CHARSET_INFO *cs= cmp.cmp_collation.collation;
+ if (use_mb(cs))
+ {
+ my_wc_t wc;
+ int rc= cs->cset->mb_wc(cs, &wc,
+ (const uchar*) escape_str->ptr(),
+ (const uchar*) escape_str->ptr() +
+ escape_str->length());
+ escape= (int) (rc > 0 ? wc : '\\');
+ }
+ else
+ {
+ /*
+ In the case of 8bit character set, we pass native
+ code instead of Unicode code as "escape" argument.
+ Convert to "cs" if charset of escape differs.
+ */
+ uint32 unused;
+ if (escape_str->needs_conversion(escape_str->length(),
+ escape_str->charset(), cs, &unused))
+ {
+ char ch;
+ uint errors;
+ uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(),
+ escape_str->length(),
+ escape_str->charset(), &errors);
+ escape= cnvlen ? ch : '\\';
+ }
+ else
+ escape= *(escape_str->ptr());
+ }
+ }
+ else
+ escape= '\\';
/*
We could also do boyer-more for non-const items, but as we would have to
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1915dbaabf6..3bbc78f5db8 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -401,17 +401,49 @@ public:
};
-class Item_func_between :public Item_int_func
+/*
+ The class Item_func_opt_neg is defined to factor out the functionality
+ common for the classes Item_func_between and Item_func_in. The objects
+ of these classes can express predicates or there negations.
+ The alternative approach would be to create pairs Item_func_between,
+ Item_func_notbetween and Item_func_in, Item_func_notin.
+
+*/
+
+class Item_func_opt_neg :public Item_int_func
+{
+public:
+ bool negated; /* <=> the item represents NOT <func> */
+ bool pred_level; /* <=> [NOT] <func> is used on a predicate level */
+public:
+ Item_func_opt_neg(Item *a, Item *b, Item *c)
+ :Item_int_func(a, b, c), negated(0), pred_level(0) {}
+ Item_func_opt_neg(List<Item> &list)
+ :Item_int_func(list), negated(0), pred_level(0) {}
+public:
+ inline void negate() { negated= !negated; }
+ inline void top_level_item() { pred_level= 1; }
+ Item *neg_transformer(THD *thd)
+ {
+ negated= !negated;
+ return this;
+ }
+};
+
+
+class Item_func_between :public Item_func_opt_neg
{
DTCollation cmp_collation;
public:
Item_result cmp_type;
String value0,value1,value2;
- Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {}
+ Item_func_between(Item *a, Item *b, Item *c)
+ :Item_func_opt_neg(a, b, c) {}
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_KEY; }
enum Functype functype() const { return BETWEEN; }
const char *func_name() const { return "between"; }
+ bool fix_fields(THD *, Item **);
void fix_length_and_dec();
void print(String *str);
bool is_bool_func() { return 1; }
@@ -505,16 +537,10 @@ public:
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
- bool fix_fields(THD *thd, Item **ref)
- {
- DBUG_ASSERT(fixed == 0);
- args[0]->top_level_item();
- return Item_func::fix_fields(thd, ref);
- }
+ bool fix_fields(THD *, Item **);
void fix_length_and_dec();
uint decimal_precision() const;
const char *func_name() const { return "if"; }
- table_map not_null_tables() const { return 0; }
};
@@ -819,7 +845,7 @@ public:
}
};
-class Item_func_in :public Item_int_func
+class Item_func_in :public Item_func_opt_neg
{
Item_result cmp_type;
in_vector *array;
@@ -828,11 +854,12 @@ class Item_func_in :public Item_int_func
DTCollation cmp_collation;
public:
Item_func_in(List<Item> &list)
- :Item_int_func(list), array(0), in_item(0), have_null(0)
+ :Item_func_opt_neg(list), array(0), in_item(0), have_null(0)
{
allowed_arg_cols= 0; // Fetch this value from first argument
}
longlong val_int();
+ bool fix_fields(THD *, Item **);
void fix_length_and_dec();
uint decimal_precision() const { return 1; }
void cleanup()
@@ -853,12 +880,6 @@ class Item_func_in :public Item_int_func
bool nulls_in_row();
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- /*
- IN() protect from NULL only first argument, if construction like
- "expression IN ()" will be allowed, we will need to check number of
- argument here, because "NOT(NULL IN ())" is TRUE.
- */
- table_map not_null_tables() const { return args[0]->not_null_tables(); }
};
/* Functions used by where clause */
@@ -966,7 +987,7 @@ class Item_func_like :public Item_bool_func2
Item *escape_item;
public:
- char escape;
+ int escape;
Item_func_like(Item *a,Item *b, Item *escape_arg)
:Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0),
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c9565801389..b47d7d19fbd 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1874,6 +1874,11 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
used_tables_cache|= RAND_TABLE_BIT;
if (arg_count)
{ // Only use argument once in query
+ if (!args[0]->const_during_execution())
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND");
+ return TRUE;
+ }
/*
Allocate rand structure once: we must use thd->stmt_arena
to create rand in proper mem_root if it's a prepared statement or
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index f6544d76504..13587d8a4c3 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -2740,8 +2740,10 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
String *result= &item->result;
Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
- if (result->length())
- result->append(*item->separator);
+ if (item->no_appended)
+ item->no_appended= FALSE;
+ else
+ item->result.append(*item->separator);
tmp.length(0);
@@ -2925,6 +2927,7 @@ void Item_func_group_concat::clear()
result.copy();
null_value= TRUE;
warning_for_row= FALSE;
+ no_appended= TRUE;
if (tree)
reset_tree(tree);
/* No need to reset the table as we never call write_row */
@@ -3001,6 +3004,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
args, arg_count, MY_COLL_ALLOW_CONV))
return 1;
+ result.set_charset(collation.collation);
result_field= 0;
null_value= 1;
thd->allow_sum_func= 1;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 0da9178eabf..87cc248e5e4 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -881,6 +881,7 @@ class Item_func_group_concat : public Item_sum
bool distinct;
bool warning_for_row;
bool always_null;
+ bool no_appended;
/*
Following is 0 normal object and pointer to original one for copy
(to correctly free resources)
@@ -912,8 +913,8 @@ public:
virtual Item_result result_type () const { return STRING_RESULT; }
void clear();
bool add();
- void reset_field() {} // not used
- void update_field() {} // not used
+ void reset_field() { DBUG_ASSERT(0); } // not used
+ void update_field() { DBUG_ASSERT(0); } // not used
bool fix_fields(THD *,Item **);
bool setup(THD *thd);
void make_unique();
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 3430bd77e0f..0bddf92e6aa 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -545,6 +545,7 @@ struct Query_cache_query_flags
#define query_cache_store_query(A, B) query_cache.store_query(A, B)
#define query_cache_destroy() query_cache.destroy()
#define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
+#define query_cache_init() query_cache.init()
#define query_cache_resize(A) query_cache.resize(A)
#define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A)
#define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
@@ -558,6 +559,7 @@ struct Query_cache_query_flags
#define query_cache_store_query(A, B)
#define query_cache_destroy()
#define query_cache_result_size_limit(A)
+#define query_cache_init()
#define query_cache_resize(A)
#define query_cache_set_min_res_unit(A)
#define query_cache_invalidate3(A, B, C)
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 76ee08d73a3..f7e9b21076e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2781,6 +2781,7 @@ static int init_server_components()
query_cache_result_size_limit(query_cache_limit);
query_cache_set_min_res_unit(query_cache_min_res_unit);
+ query_cache_init();
query_cache_resize(query_cache_size);
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3fabb1667e9..cb250251155 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3524,18 +3524,9 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
}
Item_func *cond_func= (Item_func*) cond;
- if (cond_func->functype() == Item_func::NOT_FUNC)
- {
- /* Optimize NOT BETWEEN and NOT IN */
- Item *arg= cond_func->arguments()[0];
- if (arg->type() != Item::FUNC_ITEM)
- DBUG_RETURN(0);
- cond_func= (Item_func*) arg;
- if (cond_func->functype() != Item_func::BETWEEN &&
- cond_func->functype() != Item_func::IN_FUNC)
- DBUG_RETURN(0);
- inv= TRUE;
- }
+ if (cond_func->functype() == Item_func::BETWEEN ||
+ cond_func->functype() == Item_func::IN_FUNC)
+ inv= ((Item_func_opt_neg *) cond_func)->negated;
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index ea4c08cea27..774062dedf2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -142,11 +142,8 @@ sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size",
sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size",
&SV::bulk_insert_buff_size);
sys_var_character_set_server sys_character_set_server("character_set_server");
-sys_var_str sys_charset_system("character_set_system",
- sys_check_charset,
- sys_update_charset,
- sys_set_default_charset,
- (char *)my_charset_utf8_general_ci.name);
+sys_var_const_str sys_charset_system("character_set_system",
+ (char *)my_charset_utf8_general_ci.name);
sys_var_character_set_database sys_character_set_database("character_set_database");
sys_var_character_set_client sys_character_set_client("character_set_client");
sys_var_character_set_connection sys_character_set_connection("character_set_connection");
@@ -569,6 +566,7 @@ sys_var *sys_variables[]=
&sys_character_set_client,
&sys_character_set_connection,
&sys_character_set_results,
+ &sys_charset_system,
&sys_collation_connection,
&sys_collation_database,
&sys_collation_server,
@@ -1117,27 +1115,6 @@ static void sys_default_ftb_syntax(THD *thd, enum_var_type type)
sizeof(ft_boolean_syntax)-1);
}
-/*
- The following 3 functions need to be changed in 4.1 when we allow
- one to change character sets
-*/
-
-static int sys_check_charset(THD *thd, set_var *var)
-{
- return 0;
-}
-
-
-static bool sys_update_charset(THD *thd, set_var *var)
-{
- return 0;
-}
-
-
-static void sys_set_default_charset(THD *thd, enum_var_type type)
-{
-}
-
/*
If one sets the LOW_PRIORIY UPDATES flag, we also must change the
diff --git a/sql/set_var.h b/sql/set_var.h
index c8b075ddd35..40ff4c8583f 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -190,6 +190,7 @@ public:
return 1;
}
bool check_default(enum_var_type type) { return 1; }
+ bool is_readonly() const { return 1; }
};
@@ -900,7 +901,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list);
bool not_all_support_one_shot(List<set_var_base> *var_list);
void fix_delay_key_write(THD *thd, enum_var_type type);
ulong fix_sql_mode(ulong sql_mode);
-extern sys_var_str sys_charset_system;
+extern sys_var_const_str sys_charset_system;
extern sys_var_str sys_init_connect;
extern sys_var_str sys_init_slave;
extern sys_var_thd_time_zone sys_time_zone;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 833a9209360..1ab8e0c205c 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -275,8 +275,19 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
}
DBUG_PRINT("info",("STRING_RESULT: %*s",
s->length(), s->c_ptr_quick()));
- CHARSET_INFO *itcs= it->collation.collation;
- CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_string(itcs),
+ /*
+ Reuse mechanism in sp_eval_func_item() is only employed for assignments
+ to local variables and OUT/INOUT SP parameters repsesented by
+ Item_splocal. Usually we have some expression, which needs
+ to be calculated and stored into the local variable. However in the
+ case if "it" equals to "reuse", there is no "calculation" step. So,
+ no reason to employ reuse mechanism to save variable into itself.
+ */
+ if (it == reuse)
+ DBUG_RETURN(it);
+
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
+ Item_string(it->collation.collation),
use_callers_arena, &backup_arena);
/*
We have to use special constructor and allocate string
@@ -1855,17 +1866,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
thd->query_id= next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count));
- /*
- FIXME. Resetting statement (and using it) is not reentrant, thus recursive
- functions which try to use the same LEX twice will crash server.
- We should prevent such situations by tracking if LEX is already
- in use and throwing error about unallowed recursion if needed.
- OTOH it is nice to allow recursion in cases when LEX is not really
- used (e.g. in mathematical functions), so such tracking should be
- implemented at the same time as ability not to store LEX for
- instruction if it is not really used.
- */
-
if (thd->prelocked_mode == NON_PRELOCKED)
{
/*
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7025568a1c8..07c5896dd2e 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2877,14 +2877,15 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
/*
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
+ This is done differently for NATURAL/USING joins or nested joins that
+ are operands of 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 table_name, db_name and tables->db always points to
something !
*/
- if (!table_list->is_natural_join &&
+ if (!(table_list->nested_join && table_list->join_columns) &&
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] &&
@@ -2899,8 +2900,13 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
register_tree_change)))
*actual_table= table_list;
}
- else if (table_list->is_natural_join)
+ else if (table_list->nested_join && table_list->join_columns)
{
+ /*
+ If this is a NATURAL/USING join, or an operand of such join which is a
+ join itself, and the field name is qualified, then search for the field
+ in the operands of the join.
+ */
if (table_name && table_name[0])
{
/*
@@ -2922,7 +2928,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
}
/*
Non-qualified field, search directly in the result columns of the
- natural join.
+ natural join. The condition of the outer IF is true for the top-most
+ natural join, thus if the field is not qualified, we will search
+ directly the top-most NATURAL/USING join.
*/
fld= find_field_in_natural_join(thd, table_list, name, length, ref,
/* TIMOUR_TODO: check this with Sanja */
@@ -3528,10 +3536,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
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. */
+ /*
+ Compare the two columns and check for duplicate common fields.
+ A common field is duplicate either if it was already found in
+ table_ref_2 (then found == TRUE), or if a field in table_ref_2
+ was already matched by some previous field in table_ref_1
+ (then cur_nj_col_2->is_common == TRUE).
+ */
if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2))
{
- if (found)
+ if (found || cur_nj_col_2->is_common)
{
my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where);
goto err;
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 81eed413a8e..04663c5b096 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -573,13 +573,18 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
{
DBUG_ENTER("query_cache_insert");
-#ifndef DBUG_OFF
- // Check if we have called query_cache.wreck() (which disables the cache)
- if (query_cache.query_cache_size == 0)
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ /*
+ It is very unlikely that following condition is TRUE (it is possible
+ only if other thread is resizing cache), so we check it only after guard
+ mutex lock
+ */
+ if (unlikely(query_cache.query_cache_size == 0))
+ {
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
-#endif
+ }
- STRUCT_LOCK(&query_cache.structure_guard_mutex);
Query_cache_block *query_block = ((Query_cache_block*)
net->query_cache_query);
if (query_block)
@@ -623,14 +628,20 @@ void query_cache_abort(NET *net)
{
DBUG_ENTER("query_cache_abort");
-#ifndef DBUG_OFF
- // Check if we have called query_cache.wreck() (which disables the cache)
- if (query_cache.query_cache_size == 0)
- DBUG_VOID_RETURN;
-#endif
if (net->query_cache_query != 0) // Quick check on unlocked structure
{
STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ /*
+ It is very unlikely that following condition is TRUE (it is possible
+ only if other thread is resizing cache), so we check it only after guard
+ mutex lock
+ */
+ if (unlikely(query_cache.query_cache_size == 0))
+ {
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+
Query_cache_block *query_block = ((Query_cache_block*)
net->query_cache_query);
if (query_block) // Test if changed by other thread
@@ -652,11 +663,6 @@ void query_cache_end_of_result(THD *thd)
{
DBUG_ENTER("query_cache_end_of_result");
-#ifndef DBUG_OFF
- // Check if we have called query_cache.wreck() (which disables the cache)
- if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN;
-#endif
-
if (thd->net.query_cache_query != 0) // Quick check on unlocked structure
{
#ifdef EMBEDDED_LIBRARY
@@ -664,6 +670,17 @@ void query_cache_end_of_result(THD *thd)
emb_count_querycache_size(thd));
#endif
STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ /*
+ It is very unlikely that following condition is TRUE (it is possible
+ only if other thread is resizing cache), so we check it only after guard
+ mutex lock
+ */
+ if (unlikely(query_cache.query_cache_size == 0))
+ {
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+
Query_cache_block *query_block = ((Query_cache_block*)
thd->net.query_cache_query);
if (query_block)
@@ -743,9 +760,14 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
DBUG_ENTER("Query_cache::resize");
DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size,
query_cache_size_arg));
- free_cache(0);
+ DBUG_ASSERT(initialized);
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ free_cache();
query_cache_size= query_cache_size_arg;
- DBUG_RETURN(::query_cache_size= init_cache());
+ ::query_cache_size= init_cache();
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(::query_cache_size);
}
@@ -1438,7 +1460,7 @@ void Query_cache::destroy()
}
else
{
- free_cache(1);
+ free_cache();
pthread_mutex_destroy(&structure_guard_mutex);
initialized = 0;
}
@@ -1467,8 +1489,6 @@ ulong Query_cache::init_cache()
int align;
DBUG_ENTER("Query_cache::init_cache");
- if (!initialized)
- init();
approx_additional_data_size = (sizeof(Query_cache) +
sizeof(gptr)*(def_query_hash_size+
def_table_hash_size));
@@ -1526,14 +1546,9 @@ ulong Query_cache::init_cache()
goto err;
query_cache_size -= additional_data_size;
- STRUCT_LOCK(&structure_guard_mutex);
-
- if (!(cache = (byte *)
- my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
- {
- STRUCT_UNLOCK(&structure_guard_mutex);
+ if (!(cache= (byte *)
+ my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
goto err;
- }
DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins",
query_cache_size, min_allocation_unit, mem_bin_num));
@@ -1629,7 +1644,6 @@ ulong Query_cache::init_cache()
queries_in_cache = 0;
queries_blocks = 0;
- STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_RETURN(query_cache_size +
additional_data_size + approx_additional_data_size);
@@ -1645,6 +1659,7 @@ void Query_cache::make_disabled()
{
DBUG_ENTER("Query_cache::make_disabled");
query_cache_size= 0;
+ queries_blocks= 0;
free_memory= 0;
bins= 0;
steps= 0;
@@ -1656,14 +1671,11 @@ void Query_cache::make_disabled()
}
-void Query_cache::free_cache(my_bool destruction)
+void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
if (query_cache_size > 0)
{
- if (!destruction)
- STRUCT_LOCK(&structure_guard_mutex);
-
flush_cache();
#ifndef DBUG_OFF
if (bins[0].free_blocks == 0)
@@ -1685,8 +1697,6 @@ void Query_cache::free_cache(my_bool destruction)
make_disabled();
hash_free(&queries);
hash_free(&tables);
- if (!destruction)
- STRUCT_UNLOCK(&structure_guard_mutex);
}
DBUG_VOID_RETURN;
}
@@ -2401,7 +2411,19 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min,
}
if (!under_guard)
+ {
STRUCT_LOCK(&structure_guard_mutex);
+ /*
+ It is very unlikely that following condition is TRUE (it is possible
+ only if other thread is resizing cache), so we check it only after
+ guard mutex lock
+ */
+ if (unlikely(query_cache.query_cache_size == 0))
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(0);
+ }
+ }
/* Free old queries until we have enough memory to store this block */
Query_cache_block *block;
@@ -2947,6 +2969,17 @@ void Query_cache::pack_cache()
{
DBUG_ENTER("Query_cache::pack_cache");
STRUCT_LOCK(&structure_guard_mutex);
+ /*
+ It is very unlikely that following condition is TRUE (it is possible
+ only if other thread is resizing cache), so we check it only after
+ guard mutex lock
+ */
+ if (unlikely(query_cache_size == 0))
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
byte *border = 0;
@@ -3256,6 +3289,7 @@ my_bool Query_cache::join_results(ulong join_limit)
STRUCT_LOCK(&structure_guard_mutex);
if (queries_blocks != 0)
{
+ DBUG_ASSERT(query_cache_size > 0);
Query_cache_block *block = queries_blocks;
do
{
@@ -3552,7 +3586,19 @@ my_bool Query_cache::check_integrity(bool not_locked)
DBUG_RETURN(0);
}
if (!not_locked)
+ {
STRUCT_LOCK(&structure_guard_mutex);
+ /*
+ It is very unlikely that following condition is TRUE (it is possible
+ only if other thread is resizing cache), so we check it only after
+ guard mutex lock
+ */
+ if (unlikely(query_cache_size == 0))
+ {
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_RETURN(0);
+ }
+ }
if (hash_check(&queries))
{
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index c1b08904f51..123d16b606d 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -327,10 +327,9 @@ protected:
Following function control structure_guard_mutex
by themself or don't need structure_guard_mutex
*/
- void init();
ulong init_cache();
void make_disabled();
- void free_cache(my_bool destruction);
+ void free_cache();
Query_cache_block *write_block_data(ulong data_len, gptr data,
ulong header_len,
Query_cache_block::block_type type,
@@ -366,6 +365,8 @@ protected:
uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE,
uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE);
+ /* initialize cache (mutex) */
+ void init();
/* resize query cache (return real query size, 0 if disabled) */
ulong resize(ulong query_cache_size);
/* set limit on result size */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 2ff0413e05e..497d20c2ab8 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -377,12 +377,12 @@ void THD::cleanup(void)
mysql_ha_flush(this, (TABLE_LIST*) 0,
MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL);
hash_free(&handler_tables_hash);
+ delete_dynamic(&user_var_events);
+ hash_free(&user_vars);
close_temporary_tables(this);
my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
- delete_dynamic(&user_var_events);
- hash_free(&user_vars);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
if (global_read_lock)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0de06ea395a..28afec2f688 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2862,19 +2862,6 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
if (cond->type() != Item::FUNC_ITEM)
return;
Item_func *cond_func= (Item_func*) cond;
- if (cond_func->functype() == Item_func::NOT_FUNC)
- {
- Item *item= cond_func->arguments()[0];
- /*
- At this moment all NOT before simple comparison predicates
- are eliminated. NOT IN and NOT BETWEEN are treated similar
- IN and BETWEEN respectively.
- */
- if (item->type() == Item::FUNC_ITEM &&
- ((Item_func *) item)->select_optimize() == Item_func::OPTIMIZE_KEY)
- add_key_fields(key_fields,and_level,item,usable_tables);
- return;
- }
switch (cond_func->select_optimize()) {
case Item_func::OPTIMIZE_NONE:
break;
@@ -8054,12 +8041,17 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
bool table_cant_handle_bit_fields,
uint convert_blob_length)
{
+ Item::Type orig_type;
+ Item *orig_item;
+
if (type != Item::FIELD_ITEM &&
item->real_item()->type() == Item::FIELD_ITEM &&
(item->type() != Item::REF_ITEM ||
!((Item_ref *) item)->depended_from))
{
+ orig_item= item;
item= item->real_item();
+ orig_type= type;
type= Item::FIELD_ITEM;
}
switch (type) {
@@ -8075,29 +8067,34 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::DEFAULT_VALUE_ITEM:
{
Item_field *field= (Item_field*) item;
+ bool orig_modify= modify_item;
+ Field *result;
+ if (orig_type == Item::REF_ITEM)
+ modify_item= 0;
/*
If item have to be able to store NULLs but underlaid field can't do it,
create_tmp_field_from_field() can't be used for tmp field creation.
*/
if (field->maybe_null && !field->field->maybe_null())
{
- Field *res= create_tmp_field_from_item(thd, item, table, NULL,
+ result= create_tmp_field_from_item(thd, item, table, NULL,
modify_item, convert_blob_length);
*from_field= field->field;
- if (res && modify_item)
- ((Item_field*)item)->result_field= res;
- return res;
- }
-
- if (table_cant_handle_bit_fields &&
- field->field->type() == FIELD_TYPE_BIT)
- return create_tmp_field_from_item(thd, item, table, copy_func,
+ if (result && modify_item)
+ ((Item_field*)item)->result_field= result;
+ }
+ else if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT)
+ result= create_tmp_field_from_item(thd, item, table, copy_func,
modify_item, convert_blob_length);
- return create_tmp_field_from_field(thd, (*from_field= field->field),
+ else
+ result= create_tmp_field_from_field(thd, (*from_field= field->field),
item->name, table,
modify_item ? (Item_field*) item :
NULL,
convert_blob_length);
+ if (orig_type == Item::REF_ITEM && orig_modify)
+ ((Item_ref*)orig_item)->set_result_field(result);
+ return result;
}
/* Fall through */
case Item::FUNC_ITEM:
@@ -13046,6 +13043,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select)
The function replaces occurrences of group by fields in expr
by ref objects for these fields unless they are under aggregate
functions.
+ The function also corrects value of the the maybe_null attribute
+ for the items of all subexpressions containing group by fields.
IMPLEMENTATION
The function recursively traverses the tree of the expr expression,
@@ -13056,6 +13055,9 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select)
This substitution is needed GROUP BY queries with ROLLUP if
SELECT list contains expressions over group by attributes.
+ TODO: Some functions are not null-preserving. For those functions
+ updating of the maybe_null attribute is an overkill.
+
EXAMPLES
SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP
SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP
@@ -13077,6 +13079,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
arg != arg_end; arg++)
{
Item *item= *arg;
+ bool arg_changed= FALSE;
if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM)
{
ORDER *group_tmp;
@@ -13089,15 +13092,20 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
item->name)))
return 1; // fatal_error is set
thd->change_item_tree(arg, new_item);
- *changed= TRUE;
+ arg_changed= TRUE;
}
}
}
else if (item->type() == Item::FUNC_ITEM)
{
- if (change_group_ref(thd, (Item_func *) item, group_list, changed))
+ if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed))
return 1;
}
+ if (arg_changed)
+ {
+ expr->maybe_null= 1;
+ *changed= TRUE;
+ }
}
}
return 0;
@@ -13160,7 +13168,7 @@ bool JOIN::rollup_init()
}
if (item->type() == Item::FUNC_ITEM)
{
- bool changed= 0;
+ bool changed= FALSE;
if (change_group_ref(thd, (Item_func *) item, group_list, &changed))
return 1;
/*
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 78fa88801be..47906c2697e 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -230,7 +230,7 @@ class JOIN :public Sql_alloc
/* Is set if we have a GROUP BY and we have ORDER BY on a constant. */
bool skip_sort_order;
- bool need_tmp, hidden_group_fields, buffer_result;
+ bool need_tmp, hidden_group_fields;
DYNAMIC_ARRAY keyuse;
Item::cond_result cond_value;
List<Item> all_fields; // to store all fields that used in query
@@ -299,8 +299,6 @@ class JOIN :public Sql_alloc
skip_sort_order= 0;
need_tmp= 0;
hidden_group_fields= 0; /*safety*/
- buffer_result= test(select_options & OPTION_BUFFER_RESULT) &&
- !test(select_options & OPTION_FOUND_ROWS);
error= 0;
select= 0;
return_tab= 0;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index bc3c8fbdc5d..51330a6109b 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1988,10 +1988,20 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
/*
get_all_tables() returns 1 on failure and 0 on success thus
return only these and not the result code of ::process_table()
+
+ We should use show_table_list->alias instead of
+ show_table_list->table_name because table_name
+ could be changed during opening of I_S tables. It's safe
+ to use alias because alias contains original table name
+ in this case(this part of code is used only for
+ 'show columns' & 'show statistics' commands).
*/
error= test(schema_table->process_table(thd, show_table_list,
- table, res, show_table_list->db,
- show_table_list->alias));
+ table, res,
+ (show_table_list->view ?
+ show_table_list->view_db.str :
+ show_table_list->db),
+ show_table_list->alias));
close_thread_tables(thd);
show_table_list->table= 0;
goto err;
@@ -2092,6 +2102,13 @@ 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);
+ /*
+ We should use show_table_list->alias instead of
+ show_table_list->table_name because table_name
+ could be changed during opening of I_S tables. It's safe
+ to use alias because alias contains original table name
+ in this case.
+ */
res= schema_table->process_table(thd, show_table_list, table,
res, base_name,
show_table_list->alias);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index cc286e4ff45..a39ee7c82aa 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4279,7 +4279,9 @@ predicate:
else
{
$5->push_front($1);
- $$= negate_expression(YYTHD, new Item_func_in(*$5));
+ Item_func_in *item = new Item_func_in(*$5);
+ item->negate();
+ $$= item;
}
}
| bit_expr IN_SYM in_subselect
@@ -4289,7 +4291,11 @@ predicate:
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); }
| bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
- { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); }
+ {
+ Item_func_between *item= new Item_func_between($1,$4,$6);
+ item->negate();
+ $$= item;
+ }
| bit_expr SOUNDS_SYM LIKE bit_expr
{ $$= new Item_func_eq(new Item_func_soundex($1),
new Item_func_soundex($4)); }
@@ -8157,6 +8163,11 @@ handler:
HANDLER_SYM table_ident OPEN_SYM opt_table_alias
{
LEX *lex= Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
+ YYABORT;
+ }
lex->sql_command = SQLCOM_HA_OPEN;
if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
YYABORT;
@@ -8164,6 +8175,11 @@ handler:
| HANDLER_SYM table_ident_nodb CLOSE_SYM
{
LEX *lex= Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
+ YYABORT;
+ }
lex->sql_command = SQLCOM_HA_CLOSE;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
YYABORT;
@@ -8171,6 +8187,11 @@ handler:
| HANDLER_SYM table_ident_nodb READ_SYM
{
LEX *lex=Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
+ YYABORT;
+ }
lex->sql_command = SQLCOM_HA_READ;
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
lex->current_select->select_limit= new Item_int((int32) 1);
diff --git a/strings/decimal.c b/strings/decimal.c
index 4dc5fa91e0a..7816f340eef 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1933,7 +1933,7 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
intg0=ROUND_UP(from1->intg+from2->intg),
- frac0=frac1+frac2, error, i, j;
+ frac0=frac1+frac2, error, i, j, d_to_move;
dec1 *buf1=from1->buf+intg1, *buf2=from2->buf+intg2, *buf0,
*start2, *stop2, *stop1, *start0, carry;
@@ -2007,6 +2007,20 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
}
}
}
+ buf1= to->buf;
+ d_to_move= intg0 + ROUND_UP(to->frac);
+ while (!*buf1 && (to->intg > DIG_PER_DEC1))
+ {
+ buf1++;
+ to->intg-= DIG_PER_DEC1;
+ d_to_move--;
+ }
+ if (to->buf < buf1)
+ {
+ dec1 *cur_d= to->buf;
+ for (; d_to_move; d_to_move--, cur_d++, buf1++)
+ *cur_d= *buf1;
+ }
return error;
}
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index 6757a1052a8..6dbffdc9778 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -39,7 +39,8 @@
# If you want to affect other MySQL variables, you should make your changes
# in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files.
-# If you change base dir, you must also change datadir
+# If you change base dir, you must also change datadir. These may get
+# overwritten by settings in the MySQL configuration files.
basedir=
datadir=
@@ -61,8 +62,8 @@ then
else
bindir="$basedir/bin"
datadir="$basedir/data"
- sbindir="$basedir/bin"
- libexecdir="$basedir/bin"
+ sbindir="$basedir/sbin"
+ libexecdir="$basedir/libexec"
fi
#
@@ -99,8 +100,8 @@ parse_server_arguments() {
--basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
bindir="$basedir/bin"
datadir="$basedir/data"
- sbindir="$basedir/bin"
- libexecdir="$basedir/bin"
+ sbindir="$basedir/sbin"
+ libexecdir="$basedir/libexec"
;;
--datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
--user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
@@ -240,7 +241,7 @@ case "$mode" in
if test -x $libexecdir/mysqlmanager
then
manager=$libexecdir/mysqlmanager
- elif test -x $bindir/mysqlmanager
+ elif test -x $sbindir/mysqlmanager
then
manager=$sbindir/mysqlmanager
fi