summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorOtto Kekäläinen <otto@seravo.fi>2015-09-05 21:28:14 +0300
committerOtto Kekäläinen <otto@seravo.fi>2015-09-05 21:28:14 +0300
commitd6c5e7e2cc16fa63875ef9e5a63caf5c9f147e7c (patch)
treec0c1c07edf6beeb1b8e97783934b5b9a778117da /storage
parentb9fee60871264ea56a5582ca7a436aabdabea6fc (diff)
parent67dbfab3d7945886caf6ba8de6a17799e3db25aa (diff)
downloadmariadb-git-d6c5e7e2cc16fa63875ef9e5a63caf5c9f147e7c.tar.gz
Merge branch '10.1' of https://github.com/MariaDB/server into ok-debpkg-10.1
Diffstat (limited to 'storage')
-rw-r--r--storage/connect/CMakeLists.txt4
-rw-r--r--storage/connect/ha_connect.cc51
-rw-r--r--storage/connect/jsonudf.cpp2
-rw-r--r--storage/connect/mysql-test/connect/r/endian.result105
-rw-r--r--storage/connect/mysql-test/connect/r/grant.result19
-rw-r--r--storage/connect/mysql-test/connect/r/grant2.result691
-rw-r--r--storage/connect/mysql-test/connect/r/ini_grant.result4
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_grant.result4
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_index.result114
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result16
-rw-r--r--storage/connect/mysql-test/connect/r/xml_grant.result3
-rw-r--r--storage/connect/mysql-test/connect/t/endian.test88
-rw-r--r--storage/connect/mysql-test/connect/t/grant.inc3
-rw-r--r--storage/connect/mysql-test/connect/t/grant.test5
-rw-r--r--storage/connect/mysql-test/connect/t/grant2.test869
-rw-r--r--storage/connect/mysql-test/connect/t/ini_grant.test4
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_grant.test4
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_index.test66
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_postgresql.test9
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test14
-rw-r--r--storage/connect/tabmysql.cpp32
-rw-r--r--storage/connect/tabodbc.cpp7
-rw-r--r--storage/federatedx/federatedx_io_mysql.cc1
-rw-r--r--storage/innobase/api/api0api.cc12
-rw-r--r--storage/innobase/btr/btr0btr.cc51
-rw-r--r--storage/innobase/btr/btr0cur.cc89
-rw-r--r--storage/innobase/buf/buf0buf.cc345
-rw-r--r--storage/innobase/buf/buf0flu.cc10
-rw-r--r--storage/innobase/buf/buf0rea.cc56
-rw-r--r--storage/innobase/dict/dict0crea.cc144
-rw-r--r--storage/innobase/dict/dict0dict.cc617
-rw-r--r--storage/innobase/dict/dict0load.cc4
-rw-r--r--storage/innobase/dict/dict0mem.cc3
-rw-r--r--storage/innobase/fil/fil0crypt.cc66
-rw-r--r--storage/innobase/fil/fil0fil.cc59
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc14
-rw-r--r--storage/innobase/handler/ha_innodb.cc167
-rw-r--r--storage/innobase/handler/handler0alter.cc212
-rw-r--r--storage/innobase/include/btr0btr.ic13
-rw-r--r--storage/innobase/include/btr0cur.h4
-rw-r--r--storage/innobase/include/btr0pcur.h4
-rw-r--r--storage/innobase/include/btr0pcur.ic20
-rw-r--r--storage/innobase/include/buf0buf.h14
-rw-r--r--storage/innobase/include/buf0buf.ic7
-rw-r--r--storage/innobase/include/buf0rea.h4
-rw-r--r--storage/innobase/include/db0err.h6
-rw-r--r--storage/innobase/include/dict0crea.h22
-rw-r--r--storage/innobase/include/dict0dict.h46
-rw-r--r--storage/innobase/include/dict0dict.ic4
-rw-r--r--storage/innobase/include/dict0mem.h8
-rw-r--r--storage/innobase/include/fil0crypt.h11
-rw-r--r--storage/innobase/include/fil0fil.h6
-rw-r--r--storage/innobase/include/fts0fts.h2
-rw-r--r--storage/innobase/include/ha_prototypes.h19
-rw-r--r--storage/innobase/include/page0cur.ic17
-rw-r--r--storage/innobase/include/row0purge.h12
-rw-r--r--storage/innobase/include/univ.i2
-rw-r--r--storage/innobase/log/log0crypt.cc42
-rw-r--r--storage/innobase/os/os0file.cc18
-rw-r--r--storage/innobase/row/row0import.cc109
-rw-r--r--storage/innobase/row/row0ins.cc32
-rw-r--r--storage/innobase/row/row0merge.cc18
-rw-r--r--storage/innobase/row/row0mysql.cc30
-rw-r--r--storage/innobase/row/row0purge.cc79
-rw-r--r--storage/innobase/row/row0sel.cc43
-rw-r--r--storage/innobase/ut/ut0ut.cc2
-rw-r--r--storage/maria/ma_blockrec.c6
-rw-r--r--storage/maria/ma_check_standalone.h2
-rw-r--r--storage/maria/ma_dynrec.c21
-rw-r--r--storage/maria/ma_pagecache.c28
-rw-r--r--storage/maria/maria_pack.c10
-rw-r--r--storage/mroonga/CMakeLists.txt56
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt2
-rw-r--r--storage/mroonga/vendor/groonga/CMakeLists.txt85
-rw-r--r--storage/oqgraph/CMakeLists.txt19
-rw-r--r--storage/perfschema/ha_perfschema.cc2
-rw-r--r--storage/perfschema/pfs_account.cc4
-rw-r--r--storage/perfschema/pfs_con_slice.cc11
-rw-r--r--storage/perfschema/pfs_digest.cc17
-rw-r--r--storage/perfschema/pfs_digest.h2
-rw-r--r--storage/perfschema/pfs_events_stages.cc6
-rw-r--r--storage/perfschema/pfs_events_statements.cc16
-rw-r--r--storage/perfschema/pfs_events_statements.h4
-rw-r--r--storage/perfschema/pfs_events_waits.cc6
-rw-r--r--storage/perfschema/pfs_global.cc38
-rw-r--r--storage/perfschema/pfs_global.h18
-rw-r--r--storage/perfschema/pfs_host.cc2
-rw-r--r--storage/perfschema/pfs_instr.cc40
-rw-r--r--storage/perfschema/pfs_instr.h2
-rw-r--r--storage/perfschema/pfs_instr_class.cc38
-rw-r--r--storage/perfschema/pfs_server.h2
-rw-r--r--storage/perfschema/pfs_setup_actor.cc6
-rw-r--r--storage/perfschema/pfs_setup_object.cc6
-rw-r--r--storage/perfschema/pfs_user.cc2
-rw-r--r--storage/perfschema/table_events_stages.cc14
-rw-r--r--storage/perfschema/table_events_statements.cc24
-rw-r--r--storage/perfschema/table_events_waits.cc17
-rw-r--r--storage/perfschema/table_helper.cc2
-rw-r--r--storage/perfschema/unittest/CMakeLists.txt2
-rw-r--r--storage/perfschema/unittest/pfs_misc-t.cc72
-rw-r--r--storage/perfschema/unittest/pfs_server_stubs.cc6
-rw-r--r--storage/perfschema/unittest/stub_pfs_global.h24
-rw-r--r--storage/perfschema/unittest/stub_print_error.h19
-rw-r--r--storage/spider/CMakeLists.txt5
-rw-r--r--storage/tokudb/CMakeLists.txt39
-rw-r--r--storage/tokudb/ft-index/cmake_modules/TokuSetupCompiler.cmake73
-rw-r--r--storage/tokudb/ha_tokudb.cc2
-rw-r--r--storage/xtradb/CMakeLists.txt8
-rw-r--r--storage/xtradb/api/api0api.cc15
-rw-r--r--storage/xtradb/btr/btr0btr.cc51
-rw-r--r--storage/xtradb/btr/btr0cur.cc87
-rw-r--r--storage/xtradb/buf/buf0buf.cc622
-rw-r--r--storage/xtradb/buf/buf0checksum.cc21
-rw-r--r--storage/xtradb/buf/buf0flu.cc10
-rw-r--r--storage/xtradb/buf/buf0rea.cc35
-rw-r--r--storage/xtradb/dict/dict0crea.cc143
-rw-r--r--storage/xtradb/dict/dict0dict.cc546
-rw-r--r--storage/xtradb/dict/dict0load.cc4
-rw-r--r--storage/xtradb/dict/dict0mem.cc3
-rw-r--r--storage/xtradb/fil/fil0crypt.cc66
-rw-r--r--storage/xtradb/fil/fil0fil.cc48
-rw-r--r--storage/xtradb/fsp/fsp0fsp.cc16
-rw-r--r--storage/xtradb/handler/ha_innodb.cc147
-rw-r--r--storage/xtradb/handler/handler0alter.cc46
-rw-r--r--storage/xtradb/include/api0api.h10
-rw-r--r--storage/xtradb/include/btr0btr.ic13
-rw-r--r--storage/xtradb/include/btr0cur.h4
-rw-r--r--storage/xtradb/include/btr0pcur.h4
-rw-r--r--storage/xtradb/include/btr0pcur.ic20
-rw-r--r--storage/xtradb/include/buf0buf.h16
-rw-r--r--storage/xtradb/include/buf0buf.ic7
-rw-r--r--storage/xtradb/include/buf0checksum.h9
-rw-r--r--storage/xtradb/include/buf0lru.h2
-rw-r--r--storage/xtradb/include/buf0rea.h11
-rw-r--r--storage/xtradb/include/db0err.h6
-rw-r--r--storage/xtradb/include/dict0crea.h12
-rw-r--r--storage/xtradb/include/dict0dict.h19
-rw-r--r--storage/xtradb/include/dict0mem.h8
-rw-r--r--storage/xtradb/include/fil0crypt.h11
-rw-r--r--storage/xtradb/include/fil0fil.h4
-rw-r--r--storage/xtradb/include/ha_prototypes.h30
-rw-r--r--storage/xtradb/include/os0file.h8
-rw-r--r--storage/xtradb/include/page0cur.ic17
-rw-r--r--storage/xtradb/include/page0page.h26
-rw-r--r--storage/xtradb/include/page0types.h4
-rw-r--r--storage/xtradb/include/page0zip.h21
-rw-r--r--storage/xtradb/include/srv0srv.h1
-rw-r--r--storage/xtradb/include/univ.i4
-rw-r--r--storage/xtradb/lock/lock0lock.cc3
-rw-r--r--storage/xtradb/log/log0crypt.cc40
-rw-r--r--storage/xtradb/os/os0file.cc11
-rw-r--r--storage/xtradb/page/page0page.cc55
-rw-r--r--storage/xtradb/page/page0zip.cc122
-rw-r--r--storage/xtradb/row/row0import.cc2
-rw-r--r--storage/xtradb/row/row0ins.cc32
-rw-r--r--storage/xtradb/row/row0merge.cc18
-rw-r--r--storage/xtradb/row/row0mysql.cc125
-rw-r--r--storage/xtradb/row/row0sel.cc40
-rw-r--r--storage/xtradb/srv/srv0start.cc29
-rw-r--r--storage/xtradb/sync/sync0arr.cc8
-rw-r--r--storage/xtradb/trx/trx0sys.cc4
-rw-r--r--storage/xtradb/trx/trx0trx.cc6
-rw-r--r--storage/xtradb/ut/ut0ut.cc2
163 files changed, 6345 insertions, 1595 deletions
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
index 02fe5ee8dad..2de00db1bfd 100644
--- a/storage/connect/CMakeLists.txt
+++ b/storage/connect/CMakeLists.txt
@@ -48,7 +48,7 @@ IF(UNIX)
# Bar: -Wfatal-errors removed (does not present in gcc on solaris10)
if(WITH_WARNINGS)
add_definitions(-Wall -Wextra -Wmissing-declarations)
- message(STATUS "CONNECT: GCC: All warnings enabled")
+ #message(STATUS "CONNECT: GCC: All warnings enabled")
else()
add_definitions(-Wall -Wmissing-declarations)
add_definitions(-Wno-write-strings)
@@ -69,7 +69,7 @@ IF(UNIX)
# These switches are for C++ only
# add_definitions(-Wno-reorder)
- message(STATUS "CONNECT: GCC: Some warnings disabled")
+ #message(STATUS "CONNECT: GCC: Some warnings disabled")
endif(WITH_WARNINGS)
add_definitions( -DUNIX -DLINUX -DUBUNTU )
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index f2f37936213..e296238f0c8 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -169,7 +169,7 @@
#define JSONMAX 10 // JSON Default max grp size
extern "C" {
- char version[]= "Version 1.03.0007 June 03, 2015";
+ char version[]= "Version 1.03.0007 July 05, 2015";
#if defined(__WIN__)
char compver[]= "Version 1.03.0007 " __DATE__ " " __TIME__;
char slash= '\\';
@@ -1114,7 +1114,7 @@ int GetIntegerTableOption(PGLOBAL g, PTOS options, char *opname, int idef)
else if (!stricmp(opname, "Compressed"))
opval= (options->compressed);
- if (opval == NO_IVAL) {
+ if (opval == (ulonglong)NO_IVAL) {
char *pv;
if ((pv= GetListOption(g, opname, options->oplist)))
@@ -2237,7 +2237,9 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q,
case OP_EQ:
case OP_GT:
case OP_GE:
- oom|= qry->Append((PSZ)GetValStr(op, false));
+ case OP_LT:
+ case OP_LE:
+ oom |= qry->Append((PSZ)GetValStr(op, false));
break;
default:
oom|= qry->Append(" ??? ");
@@ -4017,7 +4019,27 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn)
case TAB_MAC:
case TAB_WMI:
case TAB_OEM:
- return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0);
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ return false;
+#endif
+ /*
+ If table or table->mdl_ticket is NULL - it's a DLL, e.g. CREATE TABLE.
+ if the table has an MDL_EXCLUSIVE lock - it's a DDL too, e.g. the
+ insert step of CREATE ... SELECT.
+
+ Otherwise it's a DML, the table was normally opened, locked,
+ privilege were already checked, and table->grant.privilege is set.
+ With SQL SECURITY DEFINER, table->grant.privilege has definer's privileges.
+ */
+ if (!table || !table->mdl_ticket || table->mdl_ticket->get_type() == MDL_EXCLUSIVE)
+ return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0);
+ if (table->grant.privilege & FILE_ACL)
+ return false;
+ status_var_increment(thd->status_var.access_denied_errors);
+ my_error(access_denied_error_code(thd->password), MYF(0),
+ thd->security_ctx->priv_user, thd->security_ctx->priv_host,
+ (thd->password ? ER(ER_YES) : ER(ER_NO)));
+ return true;
// This is temporary until a solution is found
case TAB_TBL:
@@ -4404,15 +4426,16 @@ int ha_connect::external_lock(THD *thd, int lock_type)
xmod= MODE_ANY; // For info commands
DBUG_RETURN(rc);
} // endif MODE_ANY
-
- DBUG_ASSERT(table && table->s);
-
+ else
if (check_privileges(thd, options, table->s->db.str)) {
strcpy(g->Message, "This operation requires the FILE privilege");
htrc("%s\n", g->Message);
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif check_privileges
+
+ DBUG_ASSERT(table && table->s);
+
// Table mode depends on the query type
newmode= CheckMode(g, thd, newmode, &xcheck, &cras);
@@ -5666,6 +5689,14 @@ int ha_connect::create(const char *name, TABLE *table_arg,
PGLOBAL g= xp->g;
DBUG_ENTER("ha_connect::create");
+ /*
+ This assignment fixes test failures if some
+ "ALTER TABLE t1 ADD KEY(a)" query exits on ER_ACCESS_DENIED_ERROR
+ (e.g. on missing FILE_ACL). All following "CREATE TABLE" failed with
+ "ERROR 1105: CONNECT index modification should be in-place"
+ TODO: check with Olivier.
+ */
+ g->Xchk= NULL;
int sqlcom= thd_sql_command(table_arg->in_use);
PTOS options= GetTableOptionStruct(table_arg->s);
@@ -6155,10 +6186,6 @@ bool ha_connect::FileExists(const char *fn, bool bf)
int n;
struct stat info;
- if (check_access(ha_thd(), FILE_ACL, table->s->db.str,
- NULL, NULL, 0, 0))
- return true;
-
#if defined(__WIN__)
s= "\\";
#else // !__WIN__
@@ -6648,6 +6675,6 @@ maria_declare_plugin(connect)
NULL, /* status variables */
connect_system_variables, /* system variables */
"1.03.0007", /* string version */
- MariaDB_PLUGIN_MATURITY_BETA /* maturity */
+ MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */
}
maria_declare_plugin_end;
diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp
index ff4025ee0fb..b2d983712aa 100644
--- a/storage/connect/jsonudf.cpp
+++ b/storage/connect/jsonudf.cpp
@@ -261,7 +261,7 @@ static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
break;
case INT_RESULT:
- jvp->SetInteger(g, *(int*)sap);
+ jvp->SetInteger(g, (int)*(long long*)sap);
break;
case REAL_RESULT:
jvp->SetFloat(g, *(double*)sap);
diff --git a/storage/connect/mysql-test/connect/r/endian.result b/storage/connect/mysql-test/connect/r/endian.result
new file mode 100644
index 00000000000..a4c81e43b6b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/endian.result
@@ -0,0 +1,105 @@
+SET time_zone='+00:00';
+#
+# Testing little endian table
+#
+CREATE TABLE t1
+(
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL FIELD_FORMAT='L',
+id CHAR(5) NOT NULL FIELD_FORMAT='L2',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='LF',
+dept INT(4) NOT NULL FIELD_FORMAT='L2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t1;
+CREATE TABLE t1
+(
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id CHAR(5) NOT NULL FIELD_FORMAT='S',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+#
+# Testing big endian table
+#
+CREATE TABLE t2 (
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL FIELD_FORMAT='B',
+id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+dept INT(4) NOT NULL FIELD_FORMAT='B2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+INSERT INTO t2 SELECT * FROM t1;
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t2;
+CREATE TABLE t2 (
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id CHAR(5) NOT NULL FIELD_FORMAT='S',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept INT(4) NOT NULL FIELD_FORMAT='2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t2;
+CREATE TABLE t2 (
+fig CHAR(4) NOT NULL,
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id SMALLINT(5) NOT NULL,
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept SMALLINT(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t2;
+CREATE TABLE t2 (
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL FIELD_FORMAT='B',
+id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+dept SMALLINT(4) NOT NULL FIELD_FORMAT='B'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/grant.result b/storage/connect/mysql-test/connect/r/grant.result
index ba5728703a5..4e64b983ea7 100644
--- a/storage/connect/mysql-test/connect/r/grant.result
+++ b/storage/connect/mysql-test/connect/r/grant.result
@@ -1,3 +1,4 @@
+set sql_mode="";
#
# Testing FILE privilege
#
@@ -46,7 +47,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -70,6 +71,7 @@ DROP USER user@localhost;
#
# Beginning of grant.inc
#
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
SELECT user();
@@ -130,7 +132,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -164,6 +166,7 @@ DROP USER user@localhost;
#
# Beginning of grant.inc
#
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
SELECT user();
@@ -224,7 +227,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -258,6 +261,7 @@ DROP USER user@localhost;
#
# Beginning of grant.inc
#
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
SELECT user();
@@ -318,7 +322,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -352,6 +356,7 @@ DROP USER user@localhost;
#
# Beginning of grant.inc
#
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
SELECT user();
@@ -412,7 +417,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -446,6 +451,7 @@ DROP USER user@localhost;
#
# Beginning of grant.inc
#
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
SELECT user();
@@ -506,7 +512,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -537,3 +543,4 @@ DROP USER user@localhost;
#
# End of grant.inc
#
+set sql_mode=default;
diff --git a/storage/connect/mysql-test/connect/r/grant2.result b/storage/connect/mysql-test/connect/r/grant2.result
new file mode 100644
index 00000000000..acefe6df659
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/grant2.result
@@ -0,0 +1,691 @@
+#
+# MDEV-7574 Security definer views don't work with CONNECT ODBC tables
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+# Testing SQLCOM_SELECT
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE DEFINER=user@localhost SQL SECURITY DEFINER VIEW v1_baddefiner AS SELECT * FROM t1;
+SELECT * FROM t1;
+a
+10
+SELECT * FROM v1_invoker;
+a
+10
+SELECT * FROM v1_definer;
+a
+10
+SELECT * FROM v1_baddefiner;
+ERROR 28000: Access denied for user 'root'@'localhost' (using password: NO)
+SELECT * FROM t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+SELECT * FROM v1_invoker;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+SELECT * FROM v1_definer;
+a
+10
+DROP VIEW v1_invoker, v1_definer, v1_baddefiner;
+DROP TABLE t1;
+# Testing SQLCOM_UPDATE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+UPDATE t1 SET a=11;
+UPDATE v1_invoker SET a=12;
+UPDATE v1_definer SET a=13;
+UPDATE t1 SET a=21;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker SET a=22;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_definer SET a=23;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_INSERT
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO v1_invoker VALUES (12);
+INSERT INTO v1_definer VALUES (13);
+INSERT INTO t1 VALUES (21);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_invoker VALUES (22);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_definer VALUES (23);
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_REPLACE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+REPLACE INTO t1 VALUES (11);
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker VALUES (12);
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer VALUES (13);
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO t1 VALUES (21);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO v1_invoker VALUES (22);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO v1_definer VALUES (23);
+ERROR 42000: CONNECT Unsupported command
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_DELETE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DELETE FROM t1 WHERE a=11;
+DELETE FROM v1_invoker WHERE a=12;
+DELETE FROM v1_definer WHERE a=13;
+DELETE FROM t1 WHERE a=21;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE FROM v1_invoker WHERE a=22;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE FROM v1_definer WHERE a=23;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_LOAD
+CREATE TABLE t1 (a VARCHAR(128)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_TRUNCATE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (11);
+TRUNCATE TABLE t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_DROP_TABLE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+DROP TABLE t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_DROP_VIEW
+# DROP VIEW does not need FILE_ACL.
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DROP VIEW v1_invoker, v1_definer;
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DROP VIEW v1_invoker;
+DROP VIEW v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_CREATE_TABLE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+# Testing SQLCOM_LOCK_TABLES
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+LOCK TABLE t1 READ;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker READ;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+LOCK TABLE t1 READ;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+LOCK TABLE t1 WRITE;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+LOCK TABLE v1_invoker READ;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+LOCK TABLE v1_invoker WRITE;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_UPDATE_MULTI
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+# Testing SQLCOM_DELETE_MULTI
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+# Testing SQLCOM_CREATE_VIEW
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+DROP VIEW v2;
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+CREATE VIEW v2 AS SELECT * FROM t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_INSERT_SELECT
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_REPLACE_SELECT
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_RENAME_TABLE
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+RENAME TABLE t1 TO t2;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='t1.fix'
+RENAME TABLE t2 TO t1;
+RENAME TABLE t1 TO t2;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (for ALTER..RENAME)
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 RENAME TO t2;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='t1.fix'
+ALTER TABLE t2 RENAME TO t1;
+ALTER TABLE t1 RENAME TO t2;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (changing ENGINE to non-CONNECT)
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ENGINE=MyISAM;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ENGINE=MyISAM;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (changing ENGINE to CONNECT)
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+DROP TABLE t1;
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_OPTIMIZE
+CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize Error Access denied for user 'user'@'localhost' (using password: NO)
+test.t1 optimize Error Can't lock file (errno: 122 "Internal (unspecified) error in handler")
+test.t1 optimize error Corrupt
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (adding columns)
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ADD b INT;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+ALTER TABLE t1 ADD c INT;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (removing columns)
+CREATE TABLE t1 (a INT,b INT,c INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10,10);
+ALTER TABLE t1 DROP b;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+ALTER TABLE t1 DROP c;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (adding keys)
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 ADD KEY(a);
+ALTER TABLE t1 ADD KEY(b);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (removing keys)
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL, KEY a(a), KEY b(b)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 DROP KEY a;
+ALTER TABLE t1 DROP KEY b;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing SQLCOM_CREATE_INDEX and SQLCOM_DROP_INDEX
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+CREATE INDEX a ON t1 (a);
+DROP INDEX a ON t1;
+CREATE INDEX a ON t1 (a);
+CREATE INDEX b ON t1 (b);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP INDEX a ON t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DROP TABLE t1;
+# Testing stored procedures
+CREATE PROCEDURE p_definer() SQL SECURITY DEFINER
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE PROCEDURE p_invoker() SQL SECURITY INVOKER
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE DEFINER=user@localhost PROCEDURE p_baddefiner() SQL SECURITY DEFINER
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CALL p_definer();
+DROP TABLE t1;
+CALL p_invoker();
+DROP TABLE t1;
+CALL p_baddefiner();
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CALL p_invoker();
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CALL p_definer();
+DROP TABLE t1;
+DROP PROCEDURE p_definer;
+DROP PROCEDURE p_invoker;
+DROP PROCEDURE p_baddefiner;
+DROP USER user@localhost;
diff --git a/storage/connect/mysql-test/connect/r/ini_grant.result b/storage/connect/mysql-test/connect/r/ini_grant.result
index c3acf7c8dfc..68330278183 100644
--- a/storage/connect/mysql-test/connect/r/ini_grant.result
+++ b/storage/connect/mysql-test/connect/r/ini_grant.result
@@ -1,8 +1,10 @@
#
# Checking FILE privileges
#
+set sql_mode="";
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
SELECT user();
user()
user@localhost
@@ -59,7 +61,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
diff --git a/storage/connect/mysql-test/connect/r/mysql_grant.result b/storage/connect/mysql-test/connect/r/mysql_grant.result
index f8d0ee6ad6f..5f630834392 100644
--- a/storage/connect/mysql-test/connect/r/mysql_grant.result
+++ b/storage/connect/mysql-test/connect/r/mysql_grant.result
@@ -1,8 +1,10 @@
#
# Testing FILE privilege
#
+set sql_mode="";
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
SELECT user();
user()
user@localhost
@@ -40,7 +42,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
diff --git a/storage/connect/mysql-test/connect/r/mysql_index.result b/storage/connect/mysql-test/connect/r/mysql_index.result
new file mode 100644
index 00000000000..4ebf10802ae
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_index.result
@@ -0,0 +1,114 @@
+#
+# Make remote table
+#
+CREATE TABLE t1 (
+id int(11) NOT NULL,
+msg char(100) DEFAULT NULL,
+PRIMARY KEY (id)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES(1,'Un'),(3,'Trois'),(5,'Cinq');
+INSERT INTO t1 VALUES(2,'Two'),(4,'Four'),(6,'Six');
+SELECT * FROM t1;
+id msg
+1 Un
+3 Trois
+5 Cinq
+2 Two
+4 Four
+6 Six
+#
+# Make local MYSQL table with indexed id column
+#
+CREATE TABLE t2 (
+id int(11) NOT NULL,
+msg char(100) DEFAULT NULL,
+PRIMARY KEY (id)
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 TABLE_TYPE=MYSQL TABNAME=t1;
+#
+# Testing SELECT, etc.
+#
+SELECT * FROM t2;
+id msg
+1 Un
+3 Trois
+5 Cinq
+2 Two
+4 Four
+6 Six
+SELECT * FROM t2 WHERE id = 3;
+id msg
+3 Trois
+SELECT * FROM t2 WHERE id IN (2,4);
+id msg
+2 Two
+4 Four
+SELECT * FROM t2 WHERE id IN (2,4) AND msg = 'Two';
+id msg
+2 Two
+SELECT * FROM t2 WHERE id > 3;
+id msg
+5 Cinq
+4 Four
+6 Six
+SELECT * FROM t2 WHERE id >= 3;
+id msg
+3 Trois
+5 Cinq
+4 Four
+6 Six
+SELECT * FROM t2 WHERE id < 3;
+id msg
+1 Un
+2 Two
+SELECT * FROM t2 WHERE id < 3 OR id > 4;
+id msg
+1 Un
+2 Two
+5 Cinq
+6 Six
+SELECT * FROM t2 WHERE id <= 3;
+id msg
+1 Un
+2 Two
+3 Trois
+SELECT * FROM t2 WHERE id BETWEEN 3 AND 5;
+id msg
+3 Trois
+4 Four
+5 Cinq
+SELECT * FROM t2 WHERE id > 2 AND id < 6;
+id msg
+3 Trois
+4 Four
+5 Cinq
+SELECT * FROM t2 ORDER BY id;
+id msg
+1 Un
+2 Two
+3 Trois
+4 Four
+5 Cinq
+6 Six
+UPDATE t2 SET msg = 'Five' WHERE id = 5;
+Warnings:
+Note 1105 t1: 1 affected rows
+SELECT * FROM t2;
+id msg
+1 Un
+3 Trois
+5 Five
+2 Two
+4 Four
+6 Six
+DELETE FROM t2 WHERE id = 4;
+Warnings:
+Note 1105 t1: 1 affected rows
+SELECT * FROM t2;
+id msg
+1 Un
+3 Trois
+5 Five
+2 Two
+6 Six
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
index 364f340eddf..06b4239bd69 100644
--- a/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
+++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
@@ -49,10 +49,11 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
CREATE VIEW v1 AS SELECT * FROM t1;
ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
# Testing a VIEW created with FILE privileges but accessed with no FILE
+# using SQL SECIRITY INVOKER
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
@@ -64,6 +65,19 @@ UPDATE v1 SET a=123;
ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
DELETE FROM v1;
ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+# using SQL SECIRITY DEFINER
+DROP VIEW v1;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT * FROM t1;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1 WHERE a='test1';
+a
+test1
SELECT user();
user()
root@localhost
diff --git a/storage/connect/mysql-test/connect/r/xml_grant.result b/storage/connect/mysql-test/connect/r/xml_grant.result
index ea38e57af86..9eb818bf32f 100644
--- a/storage/connect/mysql-test/connect/r/xml_grant.result
+++ b/storage/connect/mysql-test/connect/r/xml_grant.result
@@ -3,6 +3,7 @@ Warning 1105 No file name. Table will use t1.xml
#
# Beginning of grant.inc
#
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
SELECT user();
@@ -63,7 +64,7 @@ ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
SELECT user();
user()
root@localhost
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
SELECT user();
user()
user@localhost
diff --git a/storage/connect/mysql-test/connect/t/endian.test b/storage/connect/mysql-test/connect/t/endian.test
new file mode 100644
index 00000000000..e5f4a24f52d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/endian.test
@@ -0,0 +1,88 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
+
+SET time_zone='+00:00';
+
+--echo #
+--echo # Testing little endian table
+--echo #
+CREATE TABLE t1
+(
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL FIELD_FORMAT='L',
+ id CHAR(5) NOT NULL FIELD_FORMAT='L2',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='LF',
+ dept INT(4) NOT NULL FIELD_FORMAT='L2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
+SELECT * FROM t1;
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+
+DROP TABLE t1;
+CREATE TABLE t1
+(
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id CHAR(5) NOT NULL FIELD_FORMAT='S',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+SELECT * FROM t1;
+
+--echo #
+--echo # Testing big endian table
+--echo #
+CREATE TABLE t2 (
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL FIELD_FORMAT='B',
+ id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+ dept INT(4) NOT NULL FIELD_FORMAT='B2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+INSERT INTO t2 SELECT * FROM t1;
+SELECT * FROM t2;
+
+DROP TABLE t2;
+CREATE TABLE t2 (
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id CHAR(5) NOT NULL FIELD_FORMAT='S',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept INT(4) NOT NULL FIELD_FORMAT='2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+
+DROP TABLE t2;
+CREATE TABLE t2 (
+ fig CHAR(4) NOT NULL,
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id SMALLINT(5) NOT NULL,
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept SMALLINT(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+
+DROP TABLE t2;
+CREATE TABLE t2 (
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL FIELD_FORMAT='B',
+ id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+ dept SMALLINT(4) NOT NULL FIELD_FORMAT='B'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+SELECT * FROM t2;
+
+DROP TABLE t1, t2;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/Testbal.dat
+--remove_file $MYSQLD_DATADIR/test/Testbal.bin
diff --git a/storage/connect/mysql-test/connect/t/grant.inc b/storage/connect/mysql-test/connect/t/grant.inc
index 7bb214dc9fd..6580c845b56 100644
--- a/storage/connect/mysql-test/connect/t/grant.inc
+++ b/storage/connect/mysql-test/connect/t/grant.inc
@@ -1,6 +1,7 @@
--echo #
--echo # Beginning of grant.inc
--echo #
+CREATE USER user@localhost;
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
--connect(user,localhost,user,,)
@@ -53,7 +54,7 @@ CREATE VIEW v1 AS SELECT * FROM t1;
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
--connection default
SELECT user();
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
--connection user
SELECT user();
--error ER_ACCESS_DENIED_ERROR
diff --git a/storage/connect/mysql-test/connect/t/grant.test b/storage/connect/mysql-test/connect/t/grant.test
index 909bb4117a1..738f156d8a4 100644
--- a/storage/connect/mysql-test/connect/t/grant.test
+++ b/storage/connect/mysql-test/connect/t/grant.test
@@ -1,4 +1,5 @@
-- source include/not_embedded.inc
+set sql_mode="";
let $MYSQLD_DATADIR= `select @@datadir`;
@@ -49,7 +50,7 @@ CREATE VIEW v1 AS SELECT * FROM t1;
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
--connection default
SELECT user();
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
--connection user
SELECT user();
--error ER_ACCESS_DENIED_ERROR
@@ -92,4 +93,4 @@ let $TABLE_OPTIONS=TABLE_TYPE=VEC MAX_ROWS=100;
let $FILE_EXT=VEC;
--source grant.inc
-
+set sql_mode=default;
diff --git a/storage/connect/mysql-test/connect/t/grant2.test b/storage/connect/mysql-test/connect/t/grant2.test
new file mode 100644
index 00000000000..8e7d9453e70
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/grant2.test
@@ -0,0 +1,869 @@
+-- source include/not_embedded.inc
+
+# Tests that involve SQL SECURITY DEFINER (e.g. in VIEWs)
+# TODO: add test with stored routines eventually.
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # MDEV-7574 Security definer views don't work with CONNECT ODBC tables
+--echo #
+
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+
+--echo # Testing SQLCOM_SELECT
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE DEFINER=user@localhost SQL SECURITY DEFINER VIEW v1_baddefiner AS SELECT * FROM t1;
+SELECT * FROM t1;
+SELECT * FROM v1_invoker;
+SELECT * FROM v1_definer;
+--error ER_ACCESS_DENIED_ERROR
+SELECT * FROM v1_baddefiner;
+
+--connect(user,localhost,user,,)
+--error ER_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_ACCESS_DENIED_ERROR
+SELECT * FROM v1_invoker;
+SELECT * FROM v1_definer;
+--connection default
+DROP VIEW v1_invoker, v1_definer, v1_baddefiner;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_UPDATE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+UPDATE t1 SET a=11;
+UPDATE v1_invoker SET a=12;
+UPDATE v1_definer SET a=13;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 SET a=21;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker SET a=22;
+UPDATE v1_definer SET a=23;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_INSERT
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO v1_invoker VALUES (12);
+INSERT INTO v1_definer VALUES (13);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES (21);
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker VALUES (22);
+INSERT INTO v1_definer VALUES (23);
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_REPLACE
+# REPLACE is not supported by ConnectSE, so we're testing the difference
+# between ER_ACCESS_DENIED_ERROR vs ER_NOT_ALLOWED_COMMAND
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 VALUES (11);
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker VALUES (12);
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer VALUES (13);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO t1 VALUES (21);
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker VALUES (22);
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer VALUES (23);
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_DELETE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DELETE FROM t1 WHERE a=11;
+DELETE FROM v1_invoker WHERE a=12;
+DELETE FROM v1_definer WHERE a=13;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+DELETE FROM t1 WHERE a=21;
+--error ER_ACCESS_DENIED_ERROR
+DELETE FROM v1_invoker WHERE a=22;
+DELETE FROM v1_definer WHERE a=23;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_LOAD
+--connection default
+CREATE TABLE t1 (a VARCHAR(128)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer
+--connection user
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--error ER_ACCESS_DENIED_ERROR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--error ER_ACCESS_DENIED_ERROR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_TRUNCATE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (11);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+# TODO: Perhaps FILE_ACL is not needed for DROP TABLE. Discuss with Olivier.
+--echo # Testing SQLCOM_DROP_TABLE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+DROP TABLE t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_DROP_VIEW
+--echo # DROP VIEW does not need FILE_ACL.
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DROP VIEW v1_invoker, v1_definer;
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--connection user
+DROP VIEW v1_invoker;
+DROP VIEW v1_definer;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_CREATE_TABLE
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+--connection default
+
+--echo # Testing SQLCOM_LOCK_TABLES
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+LOCK TABLE t1 READ;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker READ;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+LOCK TABLE t1 READ;
+--error ER_ACCESS_DENIED_ERROR
+LOCK TABLE t1 WRITE;
+--error ER_ACCESS_DENIED_ERROR
+LOCK TABLE v1_invoker READ;
+--error ER_ACCESS_DENIED_ERROR
+LOCK TABLE v1_invoker WRITE;
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_UPDATE_MULTI
+--connection default
+# t1 and t2 require FILE_ACL, t3 does not
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+--connection user
+
+# All queries with t1 should fail
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# All queries with t2 should fail
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# t3 does not need FILE_ALC
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+# This is OK:
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+# This is OK:
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+# This is OK:
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# All queries with v1_invoker should fail
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# v1_definer does not need FILE_ACL from the invoker
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# All queries with v2_invoker should fail
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# v2_definer does not need FILE_ACL from the invoker
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+--connection default
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t2.fix
+
+--echo # Testing SQLCOM_DELETE_MULTI
+--connection default
+# t1 and t2 require FILE_ACL, t3 does not
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+
+--connection user
+
+# All queries with t1 should fail
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# All queries with t2 should fail
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# t3 does not need FILE_ALC
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+# This is OK:
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+# This is OK:
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+# This is OK:
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# All queries with v1_invoker should fail
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# v1_definer does not need FILE_ACL from the invoker
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# All queries with v2_invoker should fail
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# v2_definer does not need FILE_ACL from the invoker
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+
+--connection default
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t2.fix
+
+--echo # Testing SQLCOM_CREATE_VIEW
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+DROP VIEW v2;
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+CREATE VIEW v2 AS SELECT * FROM t1;
+--error ER_ACCESS_DENIED_ERROR
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_INSERT_SELECT
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+# This is OK:
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_REPLACE_SELECT
+# REPLACE is not supported by CONNECT
+# so we're testing ER_NOT_ALLOWED_COMMAND vs ER_ACCESS_DENIED_ERROR here
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+--error ER_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_RENAME_TABLE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+RENAME TABLE t1 TO t2;
+SHOW CREATE TABLE t2;
+RENAME TABLE t2 TO t1;
+--connection user
+# TODO: Perhaps FILE_ACL is needed for RENAME. Discuss with Oliver.
+--error ER_ACCESS_DENIED_ERROR
+RENAME TABLE t1 TO t2;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (for ALTER..RENAME)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 RENAME TO t2;
+SHOW CREATE TABLE t2;
+ALTER TABLE t2 RENAME TO t1;
+--connection user
+# TODO: Perhaps FILE_ACL is not needed for ALTER..RENAME. Discuss with Olivier.
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 RENAME TO t2;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (changing ENGINE to non-CONNECT)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ENGINE=MyISAM;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ENGINE=MyISAM;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (changing ENGINE to CONNECT)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+# This should succeed, as 't1.fix' does not exists.
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+DROP TABLE t1;
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+--connection default
+DROP TABLE t1;
+
+--echo # Testing SQLCOM_OPTIMIZE
+--connection default
+CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+OPTIMIZE TABLE t1;
+--connection user
+# This command succeeds, but reports "Access denied" in the "Msg_text" column.
+OPTIMIZE TABLE t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (adding columns)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ADD b INT;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ADD c INT;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (removing columns)
+--connection default
+CREATE TABLE t1 (a INT,b INT,c INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10,10);
+ALTER TABLE t1 DROP b;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 DROP c;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (adding keys)
+--connection default
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 ADD KEY(a);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ADD KEY(b);
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t1.fnx
+
+--echo # Testing SQLCOM_ALTER_TABLE (removing keys)
+--connection default
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL, KEY a(a), KEY b(b)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 DROP KEY a;
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 DROP KEY b;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t1.fnx
+
+--echo # Testing SQLCOM_CREATE_INDEX and SQLCOM_DROP_INDEX
+--connection default
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+CREATE INDEX a ON t1 (a);
+DROP INDEX a ON t1;
+CREATE INDEX a ON t1 (a);
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+CREATE INDEX b ON t1 (b);
+--error ER_ACCESS_DENIED_ERROR
+DROP INDEX a ON t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t1.fnx
+
+--echo # Testing stored procedures
+CREATE PROCEDURE p_definer() SQL SECURITY DEFINER
+ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE PROCEDURE p_invoker() SQL SECURITY INVOKER
+ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE DEFINER=user@localhost PROCEDURE p_baddefiner() SQL SECURITY DEFINER
+ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+
+CALL p_definer();
+DROP TABLE t1;
+CALL p_invoker();
+DROP TABLE t1;
+--error ER_ACCESS_DENIED_ERROR
+CALL p_baddefiner();
+
+--connection user
+--error ER_ACCESS_DENIED_ERROR
+CALL p_invoker();
+CALL p_definer();
+
+--connection default
+DROP TABLE t1;
+DROP PROCEDURE p_definer;
+DROP PROCEDURE p_invoker;
+DROP PROCEDURE p_baddefiner;
+
+DROP USER user@localhost;
diff --git a/storage/connect/mysql-test/connect/t/ini_grant.test b/storage/connect/mysql-test/connect/t/ini_grant.test
index 30678645692..b0ddcb57979 100644
--- a/storage/connect/mysql-test/connect/t/ini_grant.test
+++ b/storage/connect/mysql-test/connect/t/ini_grant.test
@@ -5,8 +5,10 @@ let $MYSQLD_DATADIR= `select @@datadir`;
--echo #
--echo # Checking FILE privileges
--echo #
+set sql_mode="";
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
--connect(user,localhost,user,,)
--connection user
SELECT user();
@@ -54,7 +56,7 @@ CREATE VIEW v1 AS SELECT * FROM t1;
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
--connection default
SELECT user();
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
--connection user
SELECT user();
--error ER_ACCESS_DENIED_ERROR
diff --git a/storage/connect/mysql-test/connect/t/mysql_grant.test b/storage/connect/mysql-test/connect/t/mysql_grant.test
index 7c75103ed3b..7d3d05cb8fd 100644
--- a/storage/connect/mysql-test/connect/t/mysql_grant.test
+++ b/storage/connect/mysql-test/connect/t/mysql_grant.test
@@ -19,8 +19,10 @@ DROP TABLE t1;
--echo #
--echo # Testing FILE privilege
--echo #
+set sql_mode="";
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
--connect(user,localhost,user,,)
--connection user
SELECT user();
@@ -54,7 +56,7 @@ CREATE VIEW v1 AS SELECT * FROM t1;
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
--connection default
SELECT user();
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
--connection user
SELECT user();
--error ER_ACCESS_DENIED_ERROR
diff --git a/storage/connect/mysql-test/connect/t/mysql_index.test b/storage/connect/mysql-test/connect/t/mysql_index.test
new file mode 100644
index 00000000000..9a162b4d8e3
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_index.test
@@ -0,0 +1,66 @@
+-- source include/not_embedded.inc
+
+#
+# TODO: consider a possibility to run this test
+# against some remote MySQL server
+#
+
+let $PORT= `select @@port`;
+
+--disable_query_log
+--replace_result $PORT PORT
+--error 0,ER_UNKNOWN_ERROR
+--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
+{
+ Skip Need MySQL support;
+}
+DROP TABLE t1;
+--enable_query_log
+
+--echo #
+--echo # Make remote table
+--echo #
+CREATE TABLE t1 (
+ id int(11) NOT NULL,
+ msg char(100) DEFAULT NULL,
+ PRIMARY KEY (id)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES(1,'Un'),(3,'Trois'),(5,'Cinq');
+INSERT INTO t1 VALUES(2,'Two'),(4,'Four'),(6,'Six');
+SELECT * FROM t1;
+
+--echo #
+--echo # Make local MYSQL table with indexed id column
+--echo #
+CREATE TABLE t2 (
+ id int(11) NOT NULL,
+ msg char(100) DEFAULT NULL,
+ PRIMARY KEY (id)
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 TABLE_TYPE=MYSQL TABNAME=t1;
+
+--echo #
+--echo # Testing SELECT, etc.
+--echo #
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE id = 3;
+SELECT * FROM t2 WHERE id IN (2,4);
+SELECT * FROM t2 WHERE id IN (2,4) AND msg = 'Two';
+SELECT * FROM t2 WHERE id > 3;
+SELECT * FROM t2 WHERE id >= 3;
+SELECT * FROM t2 WHERE id < 3;
+SELECT * FROM t2 WHERE id < 3 OR id > 4;
+SELECT * FROM t2 WHERE id <= 3;
+SELECT * FROM t2 WHERE id BETWEEN 3 AND 5;
+SELECT * FROM t2 WHERE id > 2 AND id < 6;
+SELECT * FROM t2 ORDER BY id;
+UPDATE t2 SET msg = 'Five' WHERE id = 5;
+SELECT * FROM t2;
+DELETE FROM t2 WHERE id = 4;
+SELECT * FROM t2;
+
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_postgresql.test b/storage/connect/mysql-test/connect/t/odbc_postgresql.test
index f634b34323f..7fc16130713 100644
--- a/storage/connect/mysql-test/connect/t/odbc_postgresql.test
+++ b/storage/connect/mysql-test/connect/t/odbc_postgresql.test
@@ -27,6 +27,15 @@
#Servername=localhost
#Port=5432
#
+# 5. Allow user "mtr" to connect to the database "mtr"
+# Add this line into the begginning of pg_hba.conf
+# (usually /var/lib/pgsql/data/pg_hba.conf on Linux):
+#host mtr mtr 127.0.0.1/32 password
+#
+# 6. Restart the server:
+# sudo service postgresql restart
+#
+#
SET NAMES utf8;
diff --git a/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test b/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test
index 7664a4473ba..887385af2dc 100644
--- a/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test
+++ b/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test
@@ -56,9 +56,10 @@ ALTER TABLE t1 READONLY=1;
CREATE VIEW v1 AS SELECT * FROM t1;
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--echo # using SQL SECIRITY INVOKER
--connection default
SELECT user();
-CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
--connection user
SELECT user();
--error ER_ACCESS_DENIED_ERROR
@@ -70,6 +71,17 @@ UPDATE v1 SET a=123;
--error ER_ACCESS_DENIED_ERROR
DELETE FROM v1;
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--echo # using SQL SECIRITY DEFINER
+--connection default
+DROP VIEW v1;
+SELECT user();
+CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+SELECT * FROM v1 WHERE a='test1';
+
+
--disconnect user
--connection default
SELECT user();
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp
index 19a5dfd758f..f82cca3b514 100644
--- a/storage/connect/tabmysql.cpp
+++ b/storage/connect/tabmysql.cpp
@@ -1058,6 +1058,24 @@ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const void *key, int len)
{
bool oom;
int oldlen = Query->GetLength();
+ PHC hc = To_Def->GetHandler();
+
+ if (op == OP_FIRST && hc->end_range) {
+#ifdef _DEBUG
+ assert(!key);
+#endif
+ key_range *end_key = &hc->save_end_range;
+
+ key = end_key->key;
+ len = end_key->length;
+
+ switch (end_key->flag) {
+ case HA_READ_BEFORE_KEY: op = OP_LT; break;
+ case HA_READ_AFTER_KEY: op = OP_LE; break;
+ default: key = NULL;
+ } // endswitch flag
+
+ } // endif OP_FIRST
if (!key || op == OP_NEXT ||
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
@@ -1069,22 +1087,12 @@ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const void *key, int len)
} // endif key
return false;
- } else if (op == OP_FIRST) {
- if (To_CondFil) {
- oom = Query->Append(" WHERE ");
-
- if ((oom |= Query->Append(To_CondFil->Body))) {
- strcpy(g->Message, "Readkey: Out of memory");
- return true;
- } // endif oom
-
- } // endif To_Condfil
-
} else {
if (Myc.m_Res)
Myc.FreeResult();
- To_Def->GetHandler()->MakeKeyWhere(g, Query, op, '`', key, len);
+ if (hc->MakeKeyWhere(g, Query, op, '`', key, len))
+ return true;
if (To_CondFil) {
oom = Query->Append(" AND (");
diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp
index 307509848f4..098ed1ac114 100644
--- a/storage/connect/tabodbc.cpp
+++ b/storage/connect/tabodbc.cpp
@@ -1268,9 +1268,10 @@ void ODBCCOL::ReadColumn(PGLOBAL g)
} // endif Buf_Type
- // Handle null values
- if (Value->IsZero())
- Value->SetNull(Nullable);
+ // Nulls are handled by StrLen[n] == SQL_NULL_DATA
+ // MDEV-8561
+//if (Value->IsZero())
+// Value->SetNull(Nullable);
if (trace) {
char buf[64];
diff --git a/storage/federatedx/federatedx_io_mysql.cc b/storage/federatedx/federatedx_io_mysql.cc
index 1ff6abc4c77..6f551b41311 100644
--- a/storage/federatedx/federatedx_io_mysql.cc
+++ b/storage/federatedx/federatedx_io_mysql.cc
@@ -30,6 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define MYSQL_SERVER 1
#include <my_global.h>
#include "sql_priv.h"
+#include <mysqld_error.h>
#include "ha_federatedx.h"
diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc
index 0fe21423232..739ea9f7572 100644
--- a/storage/innobase/api/api0api.cc
+++ b/storage/innobase/api/api0api.cc
@@ -245,7 +245,7 @@ ib_open_table_by_id(
dict_mutex_enter_for_mysql();
}
- table = dict_table_open_on_id(table_id, FALSE, DICT_TABLE_OP_NORMAL);
+ table = dict_table_open_on_id(table_id, TRUE, DICT_TABLE_OP_NORMAL);
if (table != NULL && table->ibd_file_missing) {
table = NULL;
@@ -2116,6 +2116,10 @@ ib_cursor_moveto(
n_fields = dict_index_get_n_ordering_defined_by_user(prebuilt->index);
+ if (n_fields > dtuple_get_n_fields(tuple->ptr)) {
+ n_fields = dtuple_get_n_fields(tuple->ptr);
+ }
+
dtuple_set_n_fields(search_tuple, n_fields);
dtuple_set_n_fields_cmp(search_tuple, n_fields);
@@ -3753,14 +3757,14 @@ ib_table_truncate(
if (trunc_err == DB_SUCCESS) {
ut_a(ib_trx_state(ib_trx) == static_cast<ib_trx_state_t>(
TRX_STATE_NOT_STARTED));
-
- err = ib_trx_release(ib_trx);
- ut_a(err == DB_SUCCESS);
} else {
err = ib_trx_rollback(ib_trx);
ut_a(err == DB_SUCCESS);
}
+ err = ib_trx_release(ib_trx);
+ ut_a(err == DB_SUCCESS);
+
/* Set the memcached_sync_count back. */
if (table != NULL && memcached_sync != 0) {
dict_mutex_enter_for_mysql();
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 92539ce1524..d271dc4dd60 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -2,6 +2,7 @@
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2014, 2015, MariaDB Corporation
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
@@ -734,6 +735,20 @@ btr_root_block_get(
root_page_no = dict_index_get_page(index);
block = btr_block_get(space, zip_size, root_page_no, mode, index, mtr);
+
+ if (!block) {
+ index->table->is_encrypted = TRUE;
+ index->table->corrupted = FALSE;
+
+ ib_push_warning(index->table->thd, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s in tablespace %lu is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name, space);
+
+ return NULL;
+ }
+
btr_assert_not_corrupted(block, index);
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
@@ -759,8 +774,10 @@ btr_root_get(
const dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in: mtr */
{
- return(buf_block_get_frame(btr_root_block_get(index, RW_X_LATCH,
- mtr)));
+ buf_block_t* root = btr_root_block_get(index, RW_X_LATCH,
+ mtr);
+
+ return(root ? buf_block_get_frame(root) : NULL);
}
/**************************************************************//**
@@ -775,7 +792,7 @@ btr_height_get(
dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- ulint height;
+ ulint height=0;
buf_block_t* root_block;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -786,13 +803,15 @@ btr_height_get(
/* S latches the page */
root_block = btr_root_block_get(index, RW_S_LATCH, mtr);
- height = btr_page_get_level(buf_block_get_frame(root_block), mtr);
+ if (root_block) {
+ height = btr_page_get_level(buf_block_get_frame(root_block), mtr);
- /* Release the S latch on the root page. */
- mtr_memo_release(mtr, root_block, MTR_MEMO_PAGE_S_FIX);
+ /* Release the S latch on the root page. */
+ mtr_memo_release(mtr, root_block, MTR_MEMO_PAGE_S_FIX);
#ifdef UNIV_SYNC_DEBUG
- sync_thread_reset_level(&root_block->lock);
+ sync_thread_reset_level(&root_block->lock);
#endif /* UNIV_SYNC_DEBUG */
+ }
return(height);
}
@@ -1240,7 +1259,7 @@ btr_get_size_and_reserved(
{
fseg_header_t* seg_header;
page_t* root;
- ulint n;
+ ulint n=ULINT_UNDEFINED;
ulint dummy;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -1254,17 +1273,21 @@ btr_get_size_and_reserved(
}
root = btr_root_get(index, mtr);
+ *used = 0;
+
+ if (root) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
- n = fseg_n_reserved_pages(seg_header, used, mtr);
+ n = fseg_n_reserved_pages(seg_header, used, mtr);
- if (flag == BTR_TOTAL_SIZE) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+ if (flag == BTR_TOTAL_SIZE) {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
- n += fseg_n_reserved_pages(seg_header, &dummy, mtr);
- *used += dummy;
+ n += fseg_n_reserved_pages(seg_header, &dummy, mtr);
+ *used += dummy;
+ }
}
return(n);
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 1a4eb347cd2..acf9ffc45eb 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -3,6 +3,7 @@
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -347,7 +348,7 @@ search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record. */
UNIV_INTERN
-void
+dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -397,6 +398,7 @@ btr_cur_search_to_nth_level(
page_cur_t* page_cursor;
btr_op_t btr_op;
ulint root_height = 0; /* remove warning */
+ dberr_t err = DB_SUCCESS;
#ifdef BTR_CUR_ADAPT
btr_search_t* info;
@@ -513,7 +515,7 @@ btr_cur_search_to_nth_level(
|| mode != PAGE_CUR_LE);
btr_cur_n_sea++;
- return;
+ return err;
}
# endif /* BTR_CUR_HASH_ADAPT */
#endif /* BTR_CUR_ADAPT */
@@ -609,7 +611,21 @@ search_loop:
retry_page_get:
block = buf_page_get_gen(
space, zip_size, page_no, rw_latch, guess, buf_mode,
- file, line, mtr);
+ file, line, mtr, &err);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+
+ goto func_exit;
+ }
if (block == NULL) {
/* This must be a search to perform an insert/delete
@@ -822,12 +838,14 @@ func_exit:
rw_lock_s_lock(&btr_search_latch);
}
+
+ return err;
}
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
-void
+dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,
@@ -853,6 +871,8 @@ btr_cur_open_at_index_side_func(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
+ dberr_t err = DB_SUCCESS;
+
rec_offs_init(offsets_);
estimate = latch_mode & BTR_ESTIMATE;
@@ -890,11 +910,26 @@ btr_cur_open_at_index_side_func(
height = ULINT_UNDEFINED;
for (;;) {
- buf_block_t* block;
- page_t* page;
+ buf_block_t* block=NULL;
+ page_t* page=NULL;
+
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
- file, line, mtr);
+ file, line, mtr, &err);
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+
+ goto exit_loop;
+ }
+
page = buf_block_get_frame(block);
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(index->id == btr_page_get_index_id(page));
@@ -979,9 +1014,12 @@ btr_cur_open_at_index_side_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
+ exit_loop:
if (heap) {
mem_heap_free(heap);
}
+
+ return err;
}
/**********************************************************************//**
@@ -1029,10 +1067,25 @@ btr_cur_open_at_rnd_pos_func(
for (;;) {
buf_block_t* block;
page_t* page;
+ dberr_t err=DB_SUCCESS;
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
- file, line, mtr);
+ file, line, mtr, &err);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+ goto exit_loop;
+ }
+
page = buf_block_get_frame(block);
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(index->id == btr_page_get_index_id(page));
@@ -1066,6 +1119,7 @@ btr_cur_open_at_rnd_pos_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
+ exit_loop:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -3562,6 +3616,7 @@ btr_estimate_n_rows_in_range_on_level(
mtr_t mtr;
page_t* page;
buf_block_t* block;
+ dberr_t err=DB_SUCCESS;
mtr_start(&mtr);
@@ -3572,7 +3627,23 @@ btr_estimate_n_rows_in_range_on_level(
silence a debug assertion about this. */
block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH,
NULL, BUF_GET_POSSIBLY_FREED,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, &err);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+
+ mtr_commit(&mtr);
+ goto inexact;
+ }
+
page = buf_block_get_frame(block);
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 81e6839b500..bbe93dada4f 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -56,6 +56,7 @@ Created 11/5/1995 Heikki Tuuri
#include "srv0mon.h"
#include "buf0checksum.h"
#include "fil0pagecompress.h"
+#include "ha_prototypes.h"
#include "ut0byte.h"
#include <new>
@@ -313,6 +314,18 @@ on the io_type */
: (counter##_WRITTEN))
/********************************************************************//**
+Check if page is maybe compressed, encrypted or both when we encounter
+corrupted page. Note that we can't be 100% sure if page is corrupted
+or decrypt/decompress just failed.
+*/
+static
+ibool
+buf_page_check_corrupt(
+/*===================*/
+ buf_page_t* bpage); /*!< in/out: buffer page read from
+ disk */
+
+/********************************************************************//**
Gets the smallest oldest_modification lsn for any page in the pool. Returns
zero if all modified pages have been flushed to disk.
@return oldest modification in pool, zero if none */
@@ -1052,6 +1065,9 @@ buf_block_init(
block->page.key_version = 0;
block->page.page_encrypted = false;
block->page.page_compressed = false;
+ block->page.encrypted = false;
+ block->page.stored_checksum = BUF_NO_CHECKSUM_MAGIC;
+ block->page.calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
@@ -2243,7 +2259,7 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(space, zip_size, offset);
+ buf_read_page(space, zip_size, offset, NULL);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2718,7 +2734,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mini-transaction */
+ mtr_t* mtr, /*!< in: mini-transaction */
+ dberr_t* err) /*!< out: error code */
{
buf_block_t* block;
ulint fold;
@@ -2735,6 +2752,11 @@ buf_page_get_gen(
ut_ad((rw_latch == RW_S_LATCH)
|| (rw_latch == RW_X_LATCH)
|| (rw_latch == RW_NO_LATCH));
+
+ if (err) {
+ *err = DB_SUCCESS;
+ }
+
#ifdef UNIV_DEBUG
switch (mode) {
case BUF_GET_NO_LATCH:
@@ -2795,6 +2817,8 @@ loop:
}
if (block == NULL) {
+ buf_page_t* bpage=NULL;
+
/* Page not in buf_pool: needs to be read from file */
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
@@ -2827,36 +2851,77 @@ loop:
return(NULL);
}
- if (buf_read_page(space, zip_size, offset)) {
+ if (buf_read_page(space, zip_size, offset, &bpage)) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr));
retries = 0;
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
+
+ bool corrupted = true;
+
+ if (bpage) {
+ corrupted = buf_page_check_corrupt(bpage);
+ }
+
+ /* Do not try again for encrypted pages */
+ if (!corrupted) {
+ ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
+ buf_pool_mutex_enter(buf_pool);
+ mutex_enter(pmutex);
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ buf_pool_mutex_exit(buf_pool);
+ mutex_exit(pmutex);
+
+ if (err) {
+ *err = DB_ENCRYPTED_DECRYPT_FAILED;
+ }
+ return (NULL);
+ }
+
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
+ bool corrupted = true;
- fprintf(stderr, "InnoDB: Error: Unable"
- " to read tablespace %lu page no"
- " %lu into the buffer pool after"
- " %lu attempts\n"
- "InnoDB: The most probable cause"
- " of this error may be that the"
- " table has been corrupted.\n"
- "InnoDB: You can try to fix this"
- " problem by using"
- " innodb_force_recovery.\n"
- "InnoDB: Please see reference manual"
- " for more details.\n"
- "InnoDB: Aborting...\n",
- space, offset,
- BUF_PAGE_READ_MAX_RETRIES);
+ if (bpage) {
+ corrupted = buf_page_check_corrupt(bpage);
+ }
- ut_error;
+ if (corrupted) {
+ fprintf(stderr, "InnoDB: Error: Unable"
+ " to read tablespace %lu page no"
+ " %lu into the buffer pool after"
+ " %lu attempts\n"
+ "InnoDB: The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted.\n"
+ "InnoDB: You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery.\n"
+ "InnoDB: Please see reference manual"
+ " for more details.\n"
+ "InnoDB: Aborting...\n",
+ space, offset,
+ BUF_PAGE_READ_MAX_RETRIES);
+
+ ut_error;
+ } else {
+ ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
+ buf_pool_mutex_enter(buf_pool);
+ mutex_enter(pmutex);
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ buf_pool_mutex_exit(buf_pool);
+ mutex_exit(pmutex);
+
+ if (err) {
+ *err = DB_ENCRYPTED_DECRYPT_FAILED;
+ }
+ return (NULL);
+ }
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -3591,8 +3656,11 @@ buf_page_init_low(
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->key_version = 0;
+ bpage->stored_checksum = BUF_NO_CHECKSUM_MAGIC;
+ bpage->calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
bpage->page_encrypted = false;
bpage->page_compressed = false;
+ bpage->encrypted = false;
bpage->real_size = 0;
bpage->slot = NULL;
@@ -4245,34 +4313,40 @@ buf_mark_space_corrupt(
ulint space = bpage->space;
ibool ret = TRUE;
- /* First unfix and release lock on the bpage */
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
+ if (!bpage->encrypted) {
+ /* First unfix and release lock on the bpage */
+ buf_pool_mutex_enter(buf_pool);
+ mutex_enter(buf_page_get_mutex(bpage));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
+ }
- mutex_exit(buf_page_get_mutex(bpage));
+ mutex_exit(buf_page_get_mutex(bpage));
+ }
/* Find the table with specified space id, and mark it corrupted */
if (dict_set_corrupted_by_space(space)) {
- buf_LRU_free_one_page(bpage);
+ if (!bpage->encrypted) {
+ buf_LRU_free_one_page(bpage);
+ }
} else {
ret = FALSE;
}
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
+ if (!bpage->encrypted) {
+ ut_ad(buf_pool->n_pend_reads > 0);
+ buf_pool->n_pend_reads--;
- buf_pool_mutex_exit(buf_pool);
+ buf_pool_mutex_exit(buf_pool);
+ }
return(ret);
}
@@ -4283,42 +4357,77 @@ corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
*/
static
-void
+ibool
buf_page_check_corrupt(
/*===================*/
- const buf_page_t* bpage) /*!< in/out: buffer page read from disk */
+ buf_page_t* bpage) /*!< in/out: buffer page read from disk */
{
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
unsigned key_version = bpage->key_version;
bool page_compressed = bpage->page_encrypted;
+ ulint stored_checksum = bpage->stored_checksum;
+ ulint calculated_checksum = bpage->stored_checksum;
bool page_compressed_encrypted = bpage->page_compressed;
ulint space_id = mach_read_from_4(
dst_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
fil_space_t* space = fil_space_found_by_id(space_id);
+ bool corrupted = true;
+
+ if (key_version != 0 || page_compressed_encrypted) {
+ bpage->encrypted = true;
+ }
if (key_version != 0 ||
(crypt_data && crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) ||
page_compressed || page_compressed_encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Maybe corruption: Block space_id %lu in file %s maybe corrupted.",
- space_id, space ? space->name : "NULL");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Page based on contents %s encrypted.",
- (key_version == 0 && page_compressed_encrypted == false) ? "not" : "maybe");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Reason could be that key_version %u in page "
- "or in crypt_data %p could not be found.",
- key_version, crypt_data);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Reason could be also that key management plugin is not found or"
- "used encryption algorithm or method does not match.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Based on page page compressed %d, compressed and encrypted %d.",
- page_compressed, page_compressed_encrypted);
+
+ /* Page is really corrupted if post encryption stored
+ checksum does not match calculated checksum after page was
+ read. For pages compressed and then encrypted, there is no
+ checksum. */
+ corrupted = (!page_compressed_encrypted && stored_checksum != calculated_checksum);
+
+ if (corrupted) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "%s: Block in space_id %lu in file %s corrupted.",
+ page_compressed_encrypted ? "Maybe corruption" : "Corruption",
+ space_id, space ? space->name : "NULL");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page based on contents %s encrypted.",
+ (key_version == 0 && page_compressed_encrypted == false) ? "not" : "maybe");
+ if (stored_checksum != BUF_NO_CHECKSUM_MAGIC || calculated_checksum != BUF_NO_CHECKSUM_MAGIC) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page stored checksum %lu but calculated checksum %lu.",
+ stored_checksum, calculated_checksum);
+ }
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reason could be that key_version %u in page "
+ "or in crypt_data %p could not be found.",
+ key_version, crypt_data);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reason could be also that key management plugin is not found or"
+ " used encryption algorithm or method does not match.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Based on page page compressed %d, compressed and encrypted %d.",
+ page_compressed, page_compressed_encrypted);
+ } else {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Block in space_id %lu in file %s encrypted.",
+ space_id, space ? space->name : "NULL");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "However key management plugin or used key_id %u is not found or"
+ " used encryption algorithm or method does not match.",
+ key_version);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Marking tablespace as missing. You may drop this table or"
+ " install correct key management plugin and key file.");
+ }
}
+
+ return corrupted;
}
/********************************************************************//**
@@ -4437,44 +4546,46 @@ buf_page_io_complete(
goto page_not_corrupt;
;);
corrupt:
- fil_system_enter();
- space = fil_space_get_by_id(bpage->space);
- fil_system_exit();
-
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Database page corruption on disk"
- " or a failed");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Space %lu file %s read of page %lu.",
- (ulint)bpage->space,
- space ? space->name : "NULL",
- (ulong) bpage->offset);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "You may have to recover"
- " from a backup.");
-
- buf_page_check_corrupt(bpage);
-
- buf_page_print(frame, buf_page_get_zip_size(bpage),
- BUF_PAGE_PRINT_NO_CRASH);
-
- ib_logf(IB_LOG_LEVEL_ERROR,
- "It is also possible that your operating"
- "system has corrupted its own file cache.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "and rebooting your computer removes the error.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "If the corrupt page is an index page you can also try to");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "fix the corruption by dumping, dropping, and reimporting");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "the corrupt table. You can use CHECK");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "TABLE to scan your table for corruption.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "See also "
- REFMAN "forcing-innodb-recovery.html"
- " about forcing recovery.");
+ bool corrupted = buf_page_check_corrupt(bpage);
+
+ if (corrupted) {
+ fil_system_enter();
+ space = fil_space_get_by_id(bpage->space);
+ fil_system_exit();
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Database page corruption on disk"
+ " or a failed");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Space %lu file %s read of page %lu.",
+ (ulint)bpage->space,
+ space ? space->name : "NULL",
+ (ulong) bpage->offset);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "You may have to recover"
+ " from a backup.");
+
+
+ buf_page_print(frame, buf_page_get_zip_size(bpage),
+ BUF_PAGE_PRINT_NO_CRASH);
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "It is also possible that your operating"
+ "system has corrupted its own file cache.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "and rebooting your computer removes the error.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "If the corrupt page is an index page you can also try to");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "fix the corruption by dumping, dropping, and reimporting");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "the corrupt table. You can use CHECK");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "TABLE to scan your table for corruption.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "See also "
+ REFMAN "forcing-innodb-recovery.html"
+ " about forcing recovery.");
+ }
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
/* If page space id is larger than TRX_SYS_SPACE
@@ -4484,12 +4595,30 @@ corrupt:
&& buf_mark_space_corrupt(bpage)) {
return(false);
} else {
- buf_page_check_corrupt(bpage);
+ corrupted = buf_page_check_corrupt(bpage);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Ending processing because of a corrupt database page.");
+ if (corrupted) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Ending processing because of a corrupt database page.");
- ut_error;
+ ut_error;
+ }
+
+ ib_push_warning((void *)NULL, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table in tablespace %lu encrypted."
+ "However key management plugin or used key_id %lu is not found or"
+ " used encryption algorithm or method does not match."
+ " Can't continue opening the table.",
+ bpage->key_version);
+
+ if (bpage->space > TRX_SYS_SPACE) {
+ if (corrupted) {
+ buf_mark_space_corrupt(bpage);
+ }
+ } else {
+ ut_error;
+ }
+ return(false);
}
}
}
@@ -4630,11 +4759,13 @@ buf_all_freed_instance(
const buf_block_t* block = buf_chunk_not_freed(chunk);
if (UNIV_LIKELY_NULL(block)) {
- fprintf(stderr,
- "Page %lu %lu still fixed or dirty\n",
- (ulong) block->page.space,
- (ulong) block->page.offset);
- ut_error;
+ if (block->page.key_version == 0) {
+ fprintf(stderr,
+ "Page %lu %lu still fixed or dirty\n",
+ (ulong) block->page.space,
+ (ulong) block->page.offset);
+ ut_error;
+ }
}
}
@@ -5950,6 +6081,11 @@ buf_page_decrypt_after_read(
bool page_compressed_encrypted = fil_page_is_compressed_encrypted(dst_frame);
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
+ /* If page is encrypted read post-encryption checksum */
+ if (!page_compressed_encrypted && key_version != 0) {
+ bpage->stored_checksum = mach_read_from_4(dst_frame + + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4);
+ }
+
ut_ad(bpage->key_version == 0);
if (bpage->offset == 0) {
@@ -5994,6 +6130,13 @@ buf_page_decrypt_after_read(
#ifdef UNIV_DEBUG
fil_page_type_validate(dst_frame);
#endif
+
+ /* Calculate checksum before decrypt, this will be
+ used later to find out if incorrect key was used. */
+ if (!page_compressed_encrypted) {
+ bpage->calculated_checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
+ }
+
/* decrypt using crypt_buf to dst_frame */
fil_space_decrypt(bpage->space,
slot->crypt_buf,
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index d893d424b02..780230b38ba 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -1,8 +1,8 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
-Copyright (c) 2013, 2014, Fusion-io. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates
+Copyright (c) 2013, 2015, MariaDB Corporation
+Copyright (c) 2013, 2014, Fusion-io
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
@@ -889,11 +889,11 @@ buf_flush_write_block_low(
break;
case BUF_BLOCK_ZIP_DIRTY:
frame = bpage->zip.data;
+ mach_write_to_8(frame + FIL_PAGE_LSN,
+ bpage->newest_modification);
ut_a(page_zip_verify_checksum(frame, zip_size));
- mach_write_to_8(frame + FIL_PAGE_LSN,
- bpage->newest_modification);
memset(frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
break;
case BUF_BLOCK_FILE_PAGE:
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index b4b474c547f..285fc465160 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015. MariaDB Corporation.
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
@@ -105,21 +106,22 @@ ulint
buf_read_page_low(
/*==============*/
dberr_t* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
- trying to read from a non-existent tablespace, or a
- tablespace which is just now being dropped */
- bool sync, /*!< in: true if synchronous aio is desired */
- ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
- ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
- at read-ahead functions) */
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size, or 0 */
- ibool unzip, /*!< in: TRUE=request uncompressed page */
- ib_int64_t tablespace_version, /*!< in: if the space memory object has
- this timestamp different from what we are giving here,
- treat the tablespace as dropped; this is a timestamp we
- use to stop dangling page reads from a tablespace
- which we have DISCARDed + IMPORTed back */
- ulint offset) /*!< in: page number */
+ trying to read from a non-existent tablespace, or a
+ tablespace which is just now being dropped */
+ bool sync, /*!< in: true if synchronous aio is desired */
+ ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
+ ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
+ at read-ahead functions) */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size, or 0 */
+ ibool unzip, /*!< in: TRUE=request uncompressed page */
+ ib_int64_t tablespace_version, /*!< in: if the space memory object has
+ this timestamp different from what we are giving here,
+ treat the tablespace as dropped; this is a timestamp we
+ use to stop dangling page reads from a tablespace
+ which we have DISCARDed + IMPORTed back */
+ ulint offset, /*!< in: page number */
+ buf_page_t** rbpage) /*!< out: page */
{
buf_page_t* bpage;
ulint wake_later;
@@ -214,10 +216,17 @@ buf_read_page_low(
/* The i/o is already completed when we arrive from
fil_read */
if (!buf_page_io_complete(bpage)) {
+ if (rbpage) {
+ *rbpage = bpage;
+ }
return(0);
}
}
+ if (rbpage) {
+ *rbpage = bpage;
+ }
+
return(1);
}
@@ -348,7 +357,7 @@ read_ahead:
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
- tablespace_version, i);
+ tablespace_version, i, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -398,7 +407,8 @@ buf_read_page(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
- ulint offset) /*!< in: page number */
+ ulint offset, /*!< in: page number */
+ buf_page_t** bpage) /*!< out: page */
{
ib_int64_t tablespace_version;
ulint count;
@@ -411,7 +421,7 @@ buf_read_page(
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, FALSE,
- tablespace_version, offset);
+ tablespace_version, offset, bpage);
srv_stats.buf_pool_reads.add(count);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
@@ -459,7 +469,7 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
- tablespace_version, offset);
+ tablespace_version, offset, NULL);
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -718,7 +728,7 @@ buf_read_ahead_linear(
count += buf_read_page_low(
&err, false,
ibuf_mode,
- space, zip_size, FALSE, tablespace_version, i);
+ space, zip_size, FALSE, tablespace_version, i, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -808,7 +818,7 @@ buf_read_ibuf_merge_pages(
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
- page_nos[i]);
+ page_nos[i], NULL);
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
@@ -903,12 +913,12 @@ buf_read_recv_pages(
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
- page_nos[i]);
+ page_nos[i], NULL);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
- tablespace_version, page_nos[i]);
+ tablespace_version, page_nos[i], NULL);
}
}
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index 36a30cb75b7..6ba9be07348 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -1566,12 +1566,111 @@ dict_create_add_foreign_field_to_dictionary(
}
/********************************************************************//**
+Construct foreign key constraint defintion from data dictionary information.
+*/
+UNIV_INTERN
+char*
+dict_foreign_def_get(
+/*=================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx) /*!< in: trx */
+{
+ char* fk_def = (char *)mem_heap_alloc(foreign->heap, 4*1024);
+ const char* tbname;
+ char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
+ int i;
+ char* bufend;
+
+ tbname = dict_remove_db_name(foreign->id);
+ bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
+ tbname, strlen(tbname), trx->mysql_thd, FALSE);
+ tablebuf[bufend - tablebuf] = '\0';
+
+ sprintf(fk_def,
+ (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
+
+ for(i = 0; i < foreign->n_fields; i++) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->foreign_col_names[i],
+ strlen(foreign->foreign_col_names[i]),
+ trx->mysql_thd, FALSE);
+ strcat(fk_def, buf);
+ if (i < foreign->n_fields-1) {
+ strcat(fk_def, (char *)",");
+ }
+ }
+
+ strcat(fk_def,(char *)") REFERENCES ");
+
+ bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
+ foreign->referenced_table_name,
+ strlen(foreign->referenced_table_name),
+ trx->mysql_thd, TRUE);
+ tablebuf[bufend - tablebuf] = '\0';
+
+ strcat(fk_def, tablebuf);
+ strcat(fk_def, " (");
+
+ for(i = 0; i < foreign->n_fields; i++) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->referenced_col_names[i],
+ strlen(foreign->referenced_col_names[i]),
+ trx->mysql_thd, FALSE);
+ buf[bufend - buf] = '\0';
+ strcat(fk_def, buf);
+ if (i < foreign->n_fields-1) {
+ strcat(fk_def, (char *)",");
+ }
+ }
+ strcat(fk_def, (char *)")");
+
+ return fk_def;
+}
+
+/********************************************************************//**
+Convert foreign key column names from data dictionary to SQL-layer.
+*/
+static
+void
+dict_foreign_def_get_fields(
+/*========================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx, /*!< in: trx */
+ char** field, /*!< out: foreign column */
+ char** field2, /*!< out: referenced column */
+ int col_no) /*!< in: column number */
+{
+ char* bufend;
+ char* fieldbuf = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
+ char* fieldbuf2 = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
+
+ bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
+ foreign->foreign_col_names[col_no],
+ strlen(foreign->foreign_col_names[col_no]),
+ trx->mysql_thd, FALSE);
+
+ fieldbuf[bufend - fieldbuf] = '\0';
+
+ bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
+ foreign->referenced_col_names[col_no],
+ strlen(foreign->referenced_col_names[col_no]),
+ trx->mysql_thd, FALSE);
+
+ fieldbuf2[bufend - fieldbuf2] = '\0';
+ *field = fieldbuf;
+ *field2 = fieldbuf2;
+}
+
+/********************************************************************//**
Add a foreign key definition to the data dictionary tables.
@return error code or DB_SUCCESS */
UNIV_INTERN
dberr_t
dict_create_add_foreign_to_dictionary(
/*==================================*/
+ dict_table_t* table, /*!< in: table */
const char* name, /*!< in: table name */
const dict_foreign_t* foreign,/*!< in: foreign key */
trx_t* trx) /*!< in/out: dictionary transaction */
@@ -1599,6 +1698,29 @@ dict_create_add_foreign_to_dictionary(
if (error != DB_SUCCESS) {
+ if (error == DB_DUPLICATE_KEY) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ char tablename[MAX_TABLE_NAME_LEN + 1] = "";
+ char* fk_def;
+
+ innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
+ table->name, strlen(table->name),
+ trx->mysql_thd, TRUE);
+
+ innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
+
+ fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx);
+
+ ib_push_warning(trx, error,
+ "Create or Alter table %s with foreign key constraint"
+ " failed. Foreign key constraint %s"
+ " already exists on data dictionary."
+ " Foreign key constraint names need to be unique in database."
+ " Error in foreign key definition: %s.",
+ tablename, buf, fk_def);
+ }
+
return(error);
}
@@ -1607,6 +1729,26 @@ dict_create_add_foreign_to_dictionary(
i, name, foreign, trx);
if (error != DB_SUCCESS) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ char tablename[MAX_TABLE_NAME_LEN + 1] = "";
+ char* field=NULL;
+ char* field2=NULL;
+ char* fk_def;
+
+ innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
+ table->name, strlen(table->name),
+ trx->mysql_thd, TRUE);
+ innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
+ fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx);
+ dict_foreign_def_get_fields((dict_foreign_t*)foreign, trx, &field, &field2, i);
+
+ ib_push_warning(trx, error,
+ "Create or Alter table %s with foreign key constraint"
+ " failed. Error adding foreign key constraint name %s"
+ " fields %s or %s to the dictionary."
+ " Error in foreign key definition: %s.",
+ tablename, buf, i+1, fk_def);
return(error);
}
@@ -1653,7 +1795,7 @@ dict_create_add_foreigns_to_dictionary(
foreign = *it;
ut_ad(foreign->id != NULL);
- error = dict_create_add_foreign_to_dictionary(table->name,
+ error = dict_create_add_foreign_to_dictionary((dict_table_t*)table, table->name,
foreign, trx);
if (error != DB_SUCCESS) {
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 48053a954cf..dba03785f09 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -3276,6 +3276,11 @@ dict_index_build_internal_fts(
}
/*====================== FOREIGN KEY PROCESSING ========================*/
+#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
+#define DB_FOREIGN_KEY_COL_NOT_NULL 201
+#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
+#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
+
/*********************************************************************//**
Checks if a table is referenced by foreign keys.
@return TRUE if table is referenced by a foreign key */
@@ -3288,71 +3293,6 @@ dict_table_is_referenced_by_foreign_key(
return(!table->referenced_set.empty());
}
-/*********************************************************************//**
-Check if the index is referenced by a foreign key, if TRUE return foreign
-else return NULL
-@return pointer to foreign key struct if index is defined for foreign
-key, otherwise NULL */
-UNIV_INTERN
-dict_foreign_t*
-dict_table_get_referenced_constraint(
-/*=================================*/
- dict_table_t* table, /*!< in: InnoDB table */
- dict_index_t* index) /*!< in: InnoDB index */
-{
- dict_foreign_t* foreign;
-
- ut_ad(index != NULL);
- ut_ad(table != NULL);
-
- for (dict_foreign_set::iterator it = table->referenced_set.begin();
- it != table->referenced_set.end();
- ++it) {
-
- foreign = *it;
-
- if (foreign->referenced_index == index) {
-
- return(foreign);
- }
- }
-
- return(NULL);
-}
-
-/*********************************************************************//**
-Checks if a index is defined for a foreign key constraint. Index is a part
-of a foreign key constraint if the index is referenced by foreign key
-or index is a foreign key index.
-@return pointer to foreign key struct if index is defined for foreign
-key, otherwise NULL */
-UNIV_INTERN
-dict_foreign_t*
-dict_table_get_foreign_constraint(
-/*==============================*/
- dict_table_t* table, /*!< in: InnoDB table */
- dict_index_t* index) /*!< in: InnoDB index */
-{
- dict_foreign_t* foreign;
-
- ut_ad(index != NULL);
- ut_ad(table != NULL);
-
- for (dict_foreign_set::iterator it = table->foreign_set.begin();
- it != table->foreign_set.end();
- ++it) {
-
- foreign = *it;
-
- if (foreign->foreign_index == index) {
-
- return(foreign);
- }
- }
-
- return(NULL);
-}
-
/**********************************************************************//**
Removes a foreign constraint struct from the dictionary cache. */
UNIV_INTERN
@@ -3430,15 +3370,26 @@ dict_foreign_find_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
{
dict_index_t* index;
ut_ad(mutex_own(&dict_sys->mutex));
+ if (error) {
+ *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
+ }
+
index = dict_table_get_first_index(table);
while (index != NULL) {
@@ -3448,7 +3399,12 @@ dict_foreign_find_index(
&& dict_foreign_qualify_index(
table, col_names, columns, n_cols,
index, types_idx,
- check_charsets, check_null)) {
+ check_charsets, check_null,
+ error, err_col_no,err_index)) {
+ if (error) {
+ *error = DB_SUCCESS;
+ }
+
return(index);
}
@@ -3477,7 +3433,7 @@ wsrep_dict_foreign_find_index(
{
return dict_foreign_find_index(
table, col_names, columns, n_cols, types_idx, check_charsets,
- check_null);
+ check_null, NULL, NULL, NULL);
}
#endif /* WITH_WSREP */
/**********************************************************************//**
@@ -3575,11 +3531,15 @@ dict_foreign_add_to_cache(
}
if (ref_table && !for_in_cache->referenced_table) {
+ ulint index_error;
+ ulint err_col;
+ dict_index_t *err_index=NULL;
+
index = dict_foreign_find_index(
ref_table, NULL,
for_in_cache->referenced_col_names,
for_in_cache->n_fields, for_in_cache->foreign_index,
- check_charsets, false);
+ check_charsets, false, &index_error, &err_col, &err_index);
if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3611,6 +3571,10 @@ dict_foreign_add_to_cache(
}
if (for_table && !for_in_cache->foreign_table) {
+ ulint index_error;
+ ulint err_col;
+ dict_index_t *err_index=NULL;
+
index = dict_foreign_find_index(
for_table, col_names,
for_in_cache->foreign_col_names,
@@ -3618,7 +3582,8 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_index, check_charsets,
for_in_cache->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL
- | DICT_FOREIGN_ON_UPDATE_SET_NULL));
+ | DICT_FOREIGN_ON_UPDATE_SET_NULL),
+ &index_error, &err_col, &err_index);
if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -4278,6 +4243,8 @@ static
void
dict_foreign_report_syntax_err(
/*===========================*/
+ const char* fmt, /*!< in: syntax err msg */
+ const char* oper, /*!< in: operation */
const char* name, /*!< in: table name */
const char* start_of_latest_foreign,
/*!< in: start of the foreign key clause
@@ -4290,12 +4257,102 @@ dict_foreign_report_syntax_err(
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
- start_of_latest_foreign, ptr);
+ fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr);
mutex_exit(&dict_foreign_err_mutex);
}
/*********************************************************************//**
+Push warning message to SQL-layer based on foreign key constraint
+index match error. */
+static
+void
+dict_foreign_push_index_error(
+/*==========================*/
+ trx_t* trx, /*!< in: trx */
+ const char* operation, /*!< in: operation create or alter
+ */
+ const char* create_name, /*!< in: table name in create or
+ alter table */
+ const char* latest_foreign, /*!< in: start of latest foreign key
+ constraint name */
+ const char** columns, /*!< in: foreign key columns */
+ ulint index_error, /*!< in: error code */
+ ulint err_col, /*!< in: column where error happened
+ */
+ dict_index_t* err_index, /*!< in: index where error happened
+ */
+ dict_table_t* table, /*!< in: table */
+ FILE* ef) /*!< in: output stream */
+{
+ switch (index_error) {
+ case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
+ fprintf(ef,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is no index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.\n",
+ operation, create_name, latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is no index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.",
+ operation, create_name, latest_foreign);
+ break;
+ }
+ case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
+ fprintf(ef,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is only prefix index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.\n",
+ operation, create_name, latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is only prefix index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.",
+ operation, create_name, latest_foreign);
+ break;
+ }
+ case DB_FOREIGN_KEY_COL_NOT_NULL: {
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but "
+ "field %s on index is defined as NOT NULL close to %s\n",
+ operation, create_name, columns[err_col], latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but "
+ "field %s on index is defined as NOT NULL close to %s",
+ operation, create_name, columns[err_col], latest_foreign);
+ break;
+ }
+ case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
+ dict_field_t* field;
+ const char* col_name;
+ field = dict_index_get_nth_field(err_index, err_col);
+
+ col_name = dict_table_get_col_name(
+ table, dict_col_get_no(field->col));
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Field type or character set for column %s "
+ "does not mach referenced column %s close to %s\n",
+ operation, create_name, columns[err_col], col_name, latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Field type or character set for column %s "
+ "does not mach referenced column %s close to %s",
+ operation, create_name, columns[err_col], col_name, latest_foreign);
+ break;
+ }
+ default:
+ ut_error;
+ }
+}
+
+/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
@@ -4323,16 +4380,21 @@ dict_create_foreign_constraints_low(
DB_CANNOT_ADD_CONSTRAINT if any foreign
keys are found. */
{
- dict_table_t* table;
- dict_table_t* referenced_table;
- dict_table_t* table_to_alter;
+ dict_table_t* table = NULL;
+ dict_table_t* referenced_table = NULL;
+ dict_table_t* table_to_alter = NULL;
+ dict_table_t* table_to_create = NULL;
ulint highest_id_so_far = 0;
ulint number = 1;
- dict_index_t* index;
- dict_foreign_t* foreign;
+ dict_index_t* index = NULL;
+ dict_foreign_t* foreign = NULL;
const char* ptr = sql_string;
const char* start_of_latest_foreign = sql_string;
+ const char* start_of_latest_set = NULL;
FILE* ef = dict_foreign_err_file;
+ ulint index_error = DB_SUCCESS;
+ dict_index_t* err_index = NULL;
+ ulint err_col;
const char* constraint_name;
ibool success;
dberr_t error;
@@ -4345,37 +4407,80 @@ dict_create_foreign_constraints_low(
ulint n_on_updates;
const dict_col_t*columns[500];
const char* column_names[500];
+ const char* ref_column_names[500];
const char* referenced_table_name;
dict_foreign_set local_fk_set;
dict_foreign_set_free local_fk_set_free(local_fk_set);
+ const char* create_table_name;
+ const char* orig;
+ char create_name[MAX_TABLE_NAME_LEN + 1];
+ char operation[8];
ut_ad(!srv_read_only_mode);
ut_ad(mutex_own(&(dict_sys->mutex)));
table = dict_table_get_low(name);
+ /* First check if we are actually doing an ALTER TABLE, and in that
+ case look for the table being altered */
+ orig = ptr;
+ ptr = dict_accept(cs, ptr, "ALTER", &success);
+
+ strcpy((char *)operation, success ? "Alter " : "Create ");
+
+ if (!success) {
+ orig = ptr;
+ ptr = dict_scan_to(ptr, "CREATE");
+ ptr = dict_scan_to(ptr, "TABLE");
+ ptr = dict_accept(cs, ptr, "TABLE", &success);
+
+ if (success) {
+ ptr = dict_scan_table_name(cs, ptr, &table_to_create, name,
+ &success, heap, &create_table_name);
+ }
+
+ if (success) {
+ char *bufend;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ create_table_name, strlen(create_table_name),
+ trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+ ptr = orig;
+ } else {
+ char *bufend;
+ ptr = orig;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ name, strlen(name), trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+ }
+
+ goto loop;
+ }
if (table == NULL) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef,
- "Cannot find the table in the internal"
- " data dictionary of InnoDB.\n"
- "Create table statement:\n%s\n", sql_string);
+ dict_foreign_error_report_low(ef, create_name);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef, "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.\n",
+ operation, create_name, create_name, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_ERROR,
+ "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.",
+ operation, create_name, create_name, start_of_latest_foreign);
return(DB_ERROR);
}
- /* First check if we are actually doing an ALTER TABLE, and in that
- case look for the table being altered */
-
- ptr = dict_accept(cs, ptr, "ALTER", &success);
-
+ /* If not alter table jump to loop */
if (!success) {
goto loop;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "TABLE", &success);
if (!success) {
@@ -4385,13 +4490,40 @@ dict_create_foreign_constraints_low(
/* We are doing an ALTER TABLE: scan the table name we are altering */
+ orig = ptr;
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
&success, heap, &referenced_table_name);
+
+ if (table_to_alter) {
+ char *bufend;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ table_to_alter->name, strlen(table_to_alter->name),
+ trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+ } else {
+ char *bufend;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ referenced_table_name, strlen(referenced_table_name),
+ trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+
+ }
+
if (!success) {
- fprintf(stderr,
- "InnoDB: Error: could not find"
- " the table being ALTERED in:\n%s\n",
- sql_string);
+ mutex_enter(&dict_foreign_err_mutex);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.\n",
+ operation, create_name, create_name, orig);
+ mutex_exit(&dict_foreign_err_mutex);
+
+ ib_push_warning(trx, DB_ERROR,
+ "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.",
+ operation, create_name, create_name, orig);
return(DB_ERROR);
}
@@ -4428,6 +4560,7 @@ loop:
of the constraint to system tables. */
ptr = ptr1;
+ orig = ptr;
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
ut_a(success);
@@ -4458,6 +4591,19 @@ loop:
if so, immediately reject the command if the table is a
temporary one. For now, this kludge will work. */
if (reject_fks && !local_fk_set.empty()) {
+ mutex_enter(&dict_foreign_err_mutex);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef, "%s table %s with foreign key constraint"
+ " failed. Temporary tables can't have foreign key constraints."
+ " Error close to %s.\n",
+ operation, create_name, start_of_latest_foreign);
+ mutex_exit(&dict_foreign_err_mutex);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Temporary tables can't have foreign key constraints."
+ " Error close to %s.",
+ operation, create_name, start_of_latest_foreign);
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4483,6 +4629,7 @@ loop:
start_of_latest_foreign = ptr;
+ orig = ptr;
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
if (!success) {
@@ -4493,6 +4640,7 @@ loop:
goto loop;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "KEY", &success);
if (!success) {
@@ -4518,6 +4666,7 @@ loop:
}
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success);
if (!success) {
@@ -4527,8 +4676,17 @@ loop:
ptr = dict_skip_word(cs, ptr, &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
- return(DB_CANNOT_ADD_CONSTRAINT);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
}
else {
@@ -4555,15 +4713,26 @@ loop:
/* Scan the columns in the first list */
col_loop1:
ut_a(i < (sizeof column_names) / sizeof *column_names);
+ orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
heap, column_names + i);
if (!success) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
- start_of_latest_foreign, ptr);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4575,11 +4744,22 @@ col_loop1:
goto col_loop1;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4590,27 +4770,41 @@ col_loop1:
set to 0 */
index = dict_foreign_find_index(
- table, NULL, column_names, i, NULL, TRUE, FALSE);
+ table, NULL, column_names, i,
+ NULL, TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
+ dict_foreign_error_report_low(ef, create_name);
fputs("There is no index in table ", ef);
- ut_print_name(ef, NULL, TRUE, name);
+ ut_print_name(ef, NULL, TRUE, create_name);
fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n"
"See " REFMAN "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
start_of_latest_foreign);
- mutex_exit(&dict_foreign_err_mutex);
+ dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
+ column_names, index_error, err_col, err_index, table, ef);
- return(DB_CHILD_NO_INDEX);
+ mutex_exit(&dict_foreign_err_mutex);
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
+
+ orig = ptr;
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
if (!success || !my_isspace(cs, *ptr)) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4679,21 +4873,46 @@ col_loop1:
checking of foreign key constraints! */
if (!success || (!referenced_table && trx->check_foreigns)) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ char* bufend;
+
+ bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ referenced_table_name, strlen(referenced_table_name),
+ trx->mysql_thd, TRUE);
+ buf[bufend - buf] = '\0';
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
+ "close to %s.",
+ operation, create_name, buf, start_of_latest_foreign);
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nCannot resolve table name close to:\n"
- "%s\n",
- start_of_latest_foreign, ptr);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
+ "close to %s.\n",
+ operation, create_name, buf, start_of_latest_foreign);
+
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success);
if (!success) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4701,34 +4920,54 @@ col_loop1:
i = 0;
col_loop2:
+ orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
- heap, column_names + i);
+ heap, ref_column_names + i);
i++;
if (!success) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nCannot resolve column name close to:\n"
- "%s\n",
- start_of_latest_foreign, ptr);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, ",", &success);
if (success) {
goto col_loop2;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success);
if (!success || foreign->n_fields != i) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s. Too few referenced columns.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s. Too few referenced columns, you have %d when you should have %d.",
+ operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4738,6 +4977,7 @@ col_loop2:
scan_on_conditions:
/* Loop here as long as we can find ON ... conditions */
+ start_of_latest_set = ptr;
ptr = dict_accept(cs, ptr, "ON", &success);
if (!success) {
@@ -4745,15 +4985,27 @@ scan_on_conditions:
goto try_find_index;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "DELETE", &success);
if (!success) {
+ orig = ptr;
ptr = dict_accept(cs, ptr, "UPDATE", &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4764,12 +5016,14 @@ scan_on_conditions:
n_on_deletes++;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
if (success) {
goto scan_on_conditions;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "CASCADE", &success);
if (success) {
@@ -4782,14 +5036,25 @@ scan_on_conditions:
goto scan_on_conditions;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "NO", &success);
if (success) {
+ orig = ptr;
ptr = dict_accept(cs, ptr, "ACTION", &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4803,38 +5068,69 @@ scan_on_conditions:
goto scan_on_conditions;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "SET", &success);
if (!success) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "NULL", &success);
if (!success) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
for (j = 0; j < foreign->n_fields; j++) {
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
& DATA_NOT_NULL) {
+ const dict_col_t* col
+ = dict_index_get_nth_col(foreign->foreign_index, j);
+ const char* col_name = dict_table_get_col_name(foreign->foreign_index->table,
+ dict_col_get_no(col));
/* It is not sensible to define SET NULL
if the column is not allowed to be NULL! */
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\n"
- "You have defined a SET NULL condition"
- " though some of the\n"
- "columns are defined as NOT NULL.\n",
- start_of_latest_foreign);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
+ " in %s close to %s.\n",
+ operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
+ " in %s close to %s.",
+ operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
}
@@ -4852,11 +5148,20 @@ try_find_index:
/* It is an error to define more than 1 action */
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\n"
- "You have twice an ON DELETE clause"
- " or twice an ON UPDATE clause.\n",
- start_of_latest_foreign);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. You have more than one on delete or on update clause"
+ " in %s close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. You have more than one on delete or on update clause"
+ " in %s close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ dict_foreign_free(foreign);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT);
@@ -4868,12 +5173,12 @@ try_find_index:
if (referenced_table) {
index = dict_foreign_find_index(referenced_table, NULL,
- column_names, i,
+ ref_column_names, i,
foreign->foreign_index,
- TRUE, FALSE);
+ TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
+ dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n"
"Cannot find an index in the"
" referenced table where the\n"
@@ -4891,9 +5196,13 @@ try_find_index:
"innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
start_of_latest_foreign);
+
+ dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
+ column_names, index_error, err_col, err_index, referenced_table, ef);
+
mutex_exit(&dict_foreign_err_mutex);
- return(DB_PARENT_NO_INDEX);
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
} else {
ut_a(trx->check_foreigns == FALSE);
@@ -4912,11 +5221,12 @@ try_find_index:
for (i = 0; i < foreign->n_fields; i++) {
foreign->referenced_col_names[i]
- = mem_heap_strdup(foreign->heap, column_names[i]);
+ = mem_heap_strdup(foreign->heap, ref_column_names[i]);
}
goto loop;
}
+
/**************************************************************************
Determines whether a string starts with the specified keyword.
@return TRUE if str starts with keyword */
@@ -6068,7 +6378,8 @@ dict_foreign_replace_index(
foreign->foreign_table, col_names,
foreign->foreign_col_names,
foreign->n_fields, index,
- /*check_charsets=*/TRUE, /*check_null=*/FALSE);
+ /*check_charsets=*/TRUE, /*check_null=*/FALSE,
+ NULL, NULL, NULL);
if (new_index) {
ut_ad(new_index->table == index->table);
ut_ad(!new_index->to_be_dropped);
@@ -6092,7 +6403,8 @@ dict_foreign_replace_index(
foreign->referenced_table, NULL,
foreign->referenced_col_names,
foreign->n_fields, index,
- /*check_charsets=*/TRUE, /*check_null=*/FALSE);
+ /*check_charsets=*/TRUE, /*check_null=*/FALSE,
+ NULL, NULL, NULL);
/* There must exist an alternative index,
since this must have been checked earlier. */
if (new_index) {
@@ -6661,10 +6973,17 @@ dict_foreign_qualify_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
{
if (dict_index_get_n_fields(index) < n_cols) {
return(false);
@@ -6681,11 +7000,21 @@ dict_foreign_qualify_index(
if (field->prefix_len != 0) {
/* We do not accept column prefix
indexes here */
+ if (error && err_col_no && err_index) {
+ *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
+ *err_col_no = i;
+ *err_index = (dict_index_t*)index;
+ }
return(false);
}
if (check_null
&& (field->col->prtype & DATA_NOT_NULL)) {
+ if (error && err_col_no && err_index) {
+ *error = DB_FOREIGN_KEY_COL_NOT_NULL;
+ *err_col_no = i;
+ *err_index = (dict_index_t*)index;
+ }
return(false);
}
@@ -6701,6 +7030,12 @@ dict_foreign_qualify_index(
dict_index_get_nth_col(index, i),
dict_index_get_nth_col(types_idx, i),
check_charsets)) {
+ if (error && err_col_no && err_index) {
+ *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
+ *err_col_no = i;
+ *err_index = (dict_index_t*)index;
+ }
+
return(false);
}
}
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 149811dab60..d8bd0a66ade 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -1168,7 +1168,7 @@ loop:
dberr_t err = fil_open_single_table_tablespace(
read_page_0, srv_read_only_mode ? false : true,
space_id, dict_tf_to_fsp_flags(flags),
- name, filepath);
+ name, filepath, NULL);
if (err != DB_SUCCESS) {
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -2412,7 +2412,7 @@ err_exit:
err = fil_open_single_table_tablespace(
true, false, table->space,
dict_tf_to_fsp_flags(table->flags),
- name, filepath);
+ name, filepath, table);
if (err != DB_SUCCESS) {
/* We failed to find a sensible
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 9c186304d27..1724ac024fa 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -417,7 +417,8 @@ dict_mem_table_col_rename_low(
dict_index_t* new_index = dict_foreign_find_index(
foreign->foreign_table, NULL,
foreign->foreign_col_names,
- foreign->n_fields, NULL, true, false);
+ foreign->n_fields, NULL, true, false,
+ NULL, NULL, NULL);
/* There must be an equivalent index in this case. */
ut_ad(new_index != NULL);
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 2633bd96360..32fe58750e1 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -650,31 +650,8 @@ fil_space_encrypt(
/* handle post encryption checksum */
ib_uint32_t checksum = 0;
- srv_checksum_algorithm_t algorithm =
- static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
- if (zip_size == 0) {
- switch (algorithm) {
- case SRV_CHECKSUM_ALGORITHM_CRC32:
- case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
- checksum = buf_calc_page_crc32(dst_frame);
- break;
- case SRV_CHECKSUM_ALGORITHM_INNODB:
- case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
- checksum = (ib_uint32_t) buf_calc_page_new_checksum(
- dst_frame);
- break;
- case SRV_CHECKSUM_ALGORITHM_NONE:
- case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
- checksum = BUF_NO_CHECKSUM_MAGIC;
- break;
- /* no default so the compiler will emit a warning
- * if new enum is added and not handled here */
- }
- } else {
- checksum = page_zip_calc_checksum(dst_frame, zip_size,
- algorithm);
- }
+ checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
// store the post-encryption checksum after the key-version
mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4, checksum);
@@ -818,6 +795,47 @@ fil_space_decrypt(
return src_frame;
}
+/******************************************************************
+Calculate post encryption checksum
+@return page checksum or BUF_NO_CHECKSUM_MAGIC
+not needed. */
+UNIV_INTERN
+ulint
+fil_crypt_calculate_checksum(
+/*=========================*/
+ ulint zip_size, /*!< in: zip_size or 0 */
+ byte* dst_frame) /*!< in: page where to calculate */
+{
+ ib_uint32_t checksum = 0;
+ srv_checksum_algorithm_t algorithm =
+ static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
+
+ if (zip_size == 0) {
+ switch (algorithm) {
+ case SRV_CHECKSUM_ALGORITHM_CRC32:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+ checksum = buf_calc_page_crc32(dst_frame);
+ break;
+ case SRV_CHECKSUM_ALGORITHM_INNODB:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+ checksum = (ib_uint32_t) buf_calc_page_new_checksum(
+ dst_frame);
+ break;
+ case SRV_CHECKSUM_ALGORITHM_NONE:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+ checksum = BUF_NO_CHECKSUM_MAGIC;
+ break;
+ /* no default so the compiler will emit a warning
+ * if new enum is added and not handled here */
+ }
+ } else {
+ checksum = page_zip_calc_checksum(dst_frame, zip_size,
+ algorithm);
+ }
+
+ return checksum;
+}
+
/*********************************************************************
Verify checksum for a page (iff it's encrypted)
NOTE: currently this function can only be run in single threaded mode
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 249e20da1bc..831a3319eff 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates.
+Copyright (c) 2013, 2015, MariaDB Corporation.
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
@@ -1986,6 +1986,7 @@ fil_read_first_page(
const char* check_msg = NULL;
fil_space_crypt_t* cdata;
+
buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
/* Align the memory for a possible read from a raw device */
@@ -2015,6 +2016,10 @@ fil_read_first_page(
fsp_flags_get_zip_size(*flags), NULL);
cdata = fil_space_read_crypt_data(space, page, offset);
+ if (crypt_data) {
+ *crypt_data = cdata;
+ }
+
/* If file space is encrypted we need to have at least some
encryption service available where to get keys */
if ((cdata && cdata->encryption == FIL_SPACE_ENCRYPTION_ON) ||
@@ -2022,16 +2027,14 @@ fil_read_first_page(
cdata && cdata->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
if (!encryption_key_id_exists(cdata->key_id)) {
- ib_logf(IB_LOG_LEVEL_FATAL,
- "Tablespace id %ld encrypted but encryption service"
- " not available. Can't continue opening tablespace.\n",
- space);
- ut_error;
- }
- }
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Tablespace id %ld is encrypted but encryption service"
+ " or used key_id %u is not available. Can't continue opening tablespace.",
+ space, cdata->key_id);
- if (crypt_data) {
- *crypt_data = cdata;
+ return ("table encrypted but encryption service not available.");
+
+ }
}
ut_free(buf);
@@ -3621,7 +3624,8 @@ fil_open_single_table_tablespace(
ulint flags, /*!< in: tablespace flags */
const char* tablename, /*!< in: table name in the
databasename/tablename format */
- const char* path_in) /*!< in: tablespace filepath */
+ const char* path_in, /*!< in: tablespace filepath */
+ dict_table_t* table) /*!< in: table */
{
dberr_t err = DB_SUCCESS;
bool dict_filepath_same_as_default = false;
@@ -3738,6 +3742,10 @@ fil_open_single_table_tablespace(
&def.lsn, &def.lsn, &def.crypt_data);
def.valid = !def.check_msg;
+ if (table) {
+ table->crypt_data = def.crypt_data;
+ }
+
/* Validate this single-table-tablespace with SYS_TABLES,
but do not compare the DATA_DIR flag, in case the
tablespace was relocated. */
@@ -3763,6 +3771,10 @@ fil_open_single_table_tablespace(
&remote.lsn, &remote.lsn, &remote.crypt_data);
remote.valid = !remote.check_msg;
+ if (table) {
+ table->crypt_data = remote.crypt_data;
+ }
+
/* Validate this single-table-tablespace with SYS_TABLES,
but do not compare the DATA_DIR flag, in case the
tablespace was relocated. */
@@ -3789,6 +3801,10 @@ fil_open_single_table_tablespace(
&dict.lsn, &dict.lsn, &dict.crypt_data);
dict.valid = !dict.check_msg;
+ if (table) {
+ table->crypt_data = dict.crypt_data;
+ }
+
/* Validate this single-table-tablespace with SYS_TABLES,
but do not compare the DATA_DIR flag, in case the
tablespace was relocated. */
@@ -3970,7 +3986,9 @@ cleanup_and_exit:
mem_free(remote.filepath);
}
if (remote.crypt_data && remote.crypt_data != crypt_data) {
- fil_space_destroy_crypt_data(&remote.crypt_data);
+ if (err == DB_SUCCESS) {
+ fil_space_destroy_crypt_data(&remote.crypt_data);
+ }
}
if (dict.success) {
os_file_close(dict.file);
@@ -3985,7 +4003,9 @@ cleanup_and_exit:
os_file_close(def.file);
}
if (def.crypt_data && def.crypt_data != crypt_data) {
- fil_space_destroy_crypt_data(&def.crypt_data);
+ if (err == DB_SUCCESS) {
+ fil_space_destroy_crypt_data(&def.crypt_data);
+ }
}
mem_free(def.filepath);
@@ -5730,9 +5750,10 @@ fil_io(
space = fil_space_get_by_id(space_id);
- /* If we are deleting a tablespace we don't allow any read
- operations on that. However, we do allow write operations. */
- if (space == 0 || (type == OS_FILE_READ && space->stop_new_ops)) {
+ /* If we are deleting a tablespace we don't allow async read operations
+ on that. However, we do allow write and sync read operations */
+ if (space == 0
+ || (type == OS_FILE_READ && !sync && space->stop_new_ops)) {
mutex_exit(&fil_system->mutex);
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -5871,9 +5892,9 @@ fil_io(
if (!ret) {
return(DB_OUT_OF_FILE_SPACE);
- } else {
- return(DB_SUCCESS);
}
+
+ return(DB_SUCCESS);
}
#ifndef UNIV_HOTBACKUP
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 5c5e2d69514..927763cec01 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -2721,6 +2721,8 @@ fsp_reserve_free_extents(
ulint reserve;
ibool success;
ulint n_pages_added;
+ size_t total_reserved = 0;
+ ulint rounds = 0;
ut_ad(mtr);
*n_reserved = n_ext;
@@ -2789,6 +2791,7 @@ try_again:
}
success = fil_space_reserve_free_extents(space, n_free, n_ext);
+ *n_reserved = n_ext;
if (success) {
return(TRUE);
@@ -2796,8 +2799,19 @@ try_again:
try_to_extend:
success = fsp_try_extend_data_file(&n_pages_added, space,
space_header, mtr);
+
if (success && n_pages_added > 0) {
+ rounds++;
+ total_reserved += n_pages_added;
+
+ if (rounds > 50) {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Space id %lu trying to reserve %lu extents actually reserved %lu "
+ " reserve %lu free %lu size %lu rounds %lu total_reserved %lu",
+ space, n_ext, n_pages_added, reserve, n_free, size, rounds, total_reserved);
+ }
+
goto try_again;
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 4031ccd5b8f..514f9bec647 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -108,7 +108,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X))
#ifdef MYSQL_DYNAMIC_PLUGIN
-#define tc_size 400
+#define tc_size 2000
#define tdc_size 400
#endif
@@ -1747,6 +1747,7 @@ convert_error_code_to_mysql(
case DB_TABLESPACE_DELETED:
case DB_TABLE_NOT_FOUND:
+ case DB_ENCRYPTED_DECRYPT_FAILED:
return(HA_ERR_NO_SUCH_TABLE);
case DB_TABLESPACE_NOT_FOUND:
@@ -2365,6 +2366,7 @@ check_trx_exists(
if (trx == NULL) {
trx = innobase_trx_allocate(thd);
+ thd_set_ha_data(thd, innodb_hton_ptr, trx);
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
mem_analyze_corruption(trx);
ut_error;
@@ -5591,7 +5593,14 @@ table_opened:
innobase_copy_frm_flags_from_table_share(ib_table, table->s);
- dict_stats_init(ib_table);
+ ib_table->thd = (void*)thd;
+
+ /* No point to init any statistics if tablespace is still encrypted. */
+ if (!ib_table->is_encrypted) {
+ dict_stats_init(ib_table);
+ } else {
+ ib_table->stat_initialized = 1;
+ }
MONITOR_INC(MONITOR_TABLE_OPEN);
@@ -5620,6 +5629,11 @@ table_opened:
file, best to play it safe. */
no_tablespace = true;
+ } else if (ib_table->is_encrypted) {
+ /* This means that tablespace was found but we could not
+ decrypt encrypted page. */
+ no_tablespace = true;
+ ib_table->ibd_file_missing = true;
} else {
no_tablespace = false;
}
@@ -5628,6 +5642,33 @@ table_opened:
free_share(share);
my_errno = ENOENT;
+ /* If table has no talespace but it has crypt data, check
+ is tablespace made unaccessible because encryption service
+ or used key_id is not available. */
+ if (ib_table) {
+ fil_space_crypt_t* crypt_data = ib_table->crypt_data;
+ if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
+ (srv_encrypt_tables &&
+ crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
+
+ if (!encryption_key_id_exists(crypt_data->key_id)) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_NO_SUCH_TABLE,
+ "Table %s is encrypted but encryption service or"
+ " used key_id %u is not available. "
+ " Can't continue reading table.",
+ ib_table->name, crypt_data->key_id);
+ }
+ } else if (ib_table->is_encrypted) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_NO_SUCH_TABLE,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ ib_table->name);
+ }
+ }
+
dict_table_close(ib_table, FALSE, FALSE);
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
@@ -7755,10 +7796,11 @@ no_commit:
;
} else if (src_table == prebuilt->table) {
#ifdef WITH_WSREP
- if (wsrep_on(user_thd) && wsrep_load_data_splitting &&
+ if (wsrep_on(user_thd) &&
+ wsrep_load_data_splitting &&
sql_command == SQLCOM_LOAD &&
- !thd_test_options(
- user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ !thd_test_options(user_thd,
+ OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
{
switch (wsrep_run_wsrep_commit(user_thd, 1))
{
@@ -7786,10 +7828,11 @@ no_commit:
prebuilt->sql_stat_start = TRUE;
} else {
#ifdef WITH_WSREP
- if (wsrep_on(user_thd) && wsrep_load_data_splitting &&
+ if (wsrep_on(user_thd) &&
+ wsrep_load_data_splitting &&
sql_command == SQLCOM_LOAD &&
- !thd_test_options(
- user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ !thd_test_options(user_thd,
+ OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
{
switch (wsrep_run_wsrep_commit(user_thd, 1))
{
@@ -8011,14 +8054,15 @@ report_error:
user_thd);
#ifdef WITH_WSREP
- if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
- wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) &&
- (sql_command != SQLCOM_LOAD ||
- thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) {
-
- if (wsrep_append_keys(user_thd, false, record, NULL)) {
- DBUG_PRINT("wsrep", ("row key failed"));
- error_result = HA_ERR_INTERNAL_ERROR;
+ if (!error_result &&
+ wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd) &&
+ !wsrep_consistency_check(user_thd))
+ {
+ if (wsrep_append_keys(user_thd, false, record, NULL))
+ {
+ DBUG_PRINT("wsrep", ("row key failed"));
+ error_result = HA_ERR_INTERNAL_ERROR;
goto wsrep_error;
}
}
@@ -10052,6 +10096,27 @@ wsrep_append_key(
DBUG_RETURN(0);
}
+static bool
+referenced_by_foreign_key2(dict_table_t* table,
+ dict_index_t* index) {
+ ut_ad(table != NULL);
+ ut_ad(index != NULL);
+
+ const dict_foreign_set* fks = &table->referenced_set;
+ for (dict_foreign_set::const_iterator it = fks->begin();
+ it != fks->end();
+ ++it)
+ {
+ dict_foreign_t* foreign = *it;
+ if (foreign->referenced_index != index) {
+ continue;
+ }
+ ut_ad(table == foreign->referenced_table);
+ return true;
+ }
+ return false;
+}
+
int
ha_innobase::wsrep_append_keys(
/*==================*/
@@ -10131,7 +10196,7 @@ ha_innobase::wsrep_append_keys(
/* !hasPK == table with no PK, must append all non-unique keys */
if (!hasPK || key_info->flags & HA_NOSAME ||
((tab &&
- dict_table_get_referenced_constraint(tab, idx)) ||
+ referenced_by_foreign_key2(tab, idx)) ||
(!tab && referenced_by_foreign_key()))) {
len = wsrep_store_key_val_for_row(
@@ -10346,7 +10411,8 @@ create_table_def(
/* MySQL does the name length check. But we do additional check
on the name length here */
- if (strlen(table_name) > MAX_FULL_NAME_LEN) {
+ const size_t table_name_len = strlen(table_name);
+ if (table_name_len > MAX_FULL_NAME_LEN) {
push_warning_printf(
thd, Sql_condition::WARN_LEVEL_WARN,
ER_TABLE_NAME,
@@ -10355,6 +10421,15 @@ create_table_def(
DBUG_RETURN(ER_TABLE_NAME);
}
+ if (table_name[table_name_len - 1] == '/') {
+ push_warning_printf(
+ thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_TABLE_NAME,
+ "InnoDB: Table name is empty");
+
+ DBUG_RETURN(ER_WRONG_TABLE_NAME);
+ }
+
n_cols = form->s->fields;
/* Check whether there already exists a FTS_DOC_ID column */
@@ -20131,3 +20206,59 @@ static void innodb_remember_check_sysvar_funcs()
ut_ad((MYSQL_SYSVAR_NAME(checksum_algorithm).flags & 0x1FF) == PLUGIN_VAR_ENUM);
check_sysvar_enum = MYSQL_SYSVAR_NAME(checksum_algorithm).check;
}
+
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ trx_t* trx, /*!< in: trx */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...)
+{
+ va_list args;
+ THD *thd = (THD *)trx->mysql_thd;
+ char *buf;
+#define MAX_BUF_SIZE 4*1024
+
+ va_start(args, format);
+ buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
+ vsprintf(buf,format, args);
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ convert_error_code_to_mysql((dberr_t)error, 0, thd),
+ buf);
+ my_free(buf);
+ va_end(args);
+}
+
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ void* ithd, /*!< in: thd */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...)
+{
+ va_list args;
+ THD *thd = (THD *)ithd;
+ char *buf;
+#define MAX_BUF_SIZE 4*1024
+
+ if (ithd == NULL) {
+ thd = current_thd;
+ }
+
+ va_start(args, format);
+ buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
+ vsprintf(buf,format, args);
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ convert_error_code_to_mysql((dberr_t)error, 0, thd),
+ buf);
+ my_free(buf);
+ va_end(args);
+}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 3d6c0ecac32..3ed0067f395 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2005, 2015, Oracle and/or its affiliates
+Copyright (c) 2013, 2015, SkySQL 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
@@ -30,6 +30,7 @@ Smart ALTER TABLE
#include <innodb_priv.h>
#include <sql_alter.h>
#include <sql_class.h>
+#include <sql_table.h>
#include "dict0crea.h"
#include "dict0dict.h"
@@ -396,6 +397,35 @@ ha_innobase::check_if_supported_inplace_alter(
}
}
+ /* If we have column that has changed from NULL -> NOT NULL
+ and column default has changed we need to do additional
+ check. */
+ if ((ha_alter_info->handler_flags
+ & Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) &&
+ (ha_alter_info->handler_flags
+ & Alter_inplace_info::ALTER_COLUMN_DEFAULT)) {
+ Alter_info *alter_info = ha_alter_info->alter_info;
+ List_iterator<Create_field> def_it(alter_info->create_list);
+ Create_field *def;
+ while ((def=def_it++)) {
+
+ /* If this is first column definition whose SQL type
+ is TIMESTAMP and it is defined as NOT NULL and
+ it has either constant default or function default
+ we must use "Copy" method. */
+ if (is_timestamp_type(def->sql_type)) {
+ if ((def->flags & NOT_NULL_FLAG) != 0 && // NOT NULL
+ (def->def != NULL || // constant default ?
+ def->unireg_check != Field::NONE)) { // function default
+ ha_alter_info->unsupported_reason = innobase_get_err_msg(
+ ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ break;
+ }
+ }
+ }
+
/* We should be able to do the operation in-place.
See if we can do it online (LOCK=NONE). */
bool online = true;
@@ -523,12 +553,9 @@ ha_innobase::check_if_supported_inplace_alter(
} else if (((ha_alter_info->handler_flags
& Alter_inplace_info::ADD_PK_INDEX)
|| innobase_need_rebuild(ha_alter_info))
- && (innobase_fulltext_exist(altered_table)
- || (prebuilt->table->flags2
- & DICT_TF2_FTS_HAS_DOC_ID))) {
+ && (innobase_fulltext_exist(altered_table))) {
/* Refuse to rebuild the table online, if
- fulltext indexes are to survive the rebuild,
- or if the table contains a hidden FTS_DOC_ID column. */
+ fulltext indexes are to survive the rebuild. */
online = false;
/* If the table already contains fulltext indexes,
refuse to rebuild the table natively altogether. */
@@ -819,7 +846,8 @@ innobase_find_fk_index(
if (!(index->type & DICT_FTS)
&& dict_foreign_qualify_index(
table, col_names, columns, n_cols,
- index, NULL, true, 0)) {
+ index, NULL, true, 0,
+ NULL, NULL, NULL)) {
for (ulint i = 0; i < n_drop_index; i++) {
if (index == drop_index[i]) {
/* Skip to-be-dropped indexes. */
@@ -886,10 +914,8 @@ innobase_get_foreign_key_info(
char* tbl_namep = NULL;
ulint db_name_len = 0;
ulint tbl_name_len = 0;
-#ifdef __WIN__
char db_name[MAX_DATABASE_NAME_LEN];
char tbl_name[MAX_TABLE_NAME_LEN];
-#endif
fk_key = static_cast<Foreign_key*>(key);
@@ -942,24 +968,29 @@ innobase_get_foreign_key_info(
add_fk[num_fk] = dict_mem_foreign_create();
#ifndef __WIN__
- tbl_namep = fk_key->ref_table.str;
- tbl_name_len = fk_key->ref_table.length;
- db_namep = fk_key->ref_db.str;
- db_name_len = fk_key->ref_db.length;
+ if(fk_key->ref_db.str) {
+ tablename_to_filename(fk_key->ref_db.str, db_name,
+ MAX_DATABASE_NAME_LEN);
+ db_namep = db_name;
+ db_name_len = strlen(db_name);
+ }
+ if (fk_key->ref_table.str) {
+ tablename_to_filename(fk_key->ref_table.str, tbl_name,
+ MAX_TABLE_NAME_LEN);
+ tbl_namep = tbl_name;
+ tbl_name_len = strlen(tbl_name);
+ }
#else
ut_ad(fk_key->ref_table.str);
-
- memcpy(tbl_name, fk_key->ref_table.str,
- fk_key->ref_table.length);
- tbl_name[fk_key->ref_table.length] = 0;
+ tablename_to_filename(fk_key->ref_table.str, tbl_name,
+ MAX_TABLE_NAME_LEN);
innobase_casedn_str(tbl_name);
tbl_name_len = strlen(tbl_name);
tbl_namep = &tbl_name[0];
if (fk_key->ref_db.str != NULL) {
- memcpy(db_name, fk_key->ref_db.str,
- fk_key->ref_db.length);
- db_name[fk_key->ref_db.length] = 0;
+ tablename_to_filename(fk_key->ref_db.str, db_name,
+ MAX_DATABASE_NAME_LEN);
innobase_casedn_str(db_name);
db_name_len = strlen(db_name);
db_namep = &db_name[0];
@@ -1009,7 +1040,8 @@ innobase_get_foreign_key_info(
referenced_table, 0,
referenced_column_names,
i, index,
- TRUE, FALSE);
+ TRUE, FALSE,
+ NULL, NULL, NULL);
DBUG_EXECUTE_IF(
"innodb_test_no_reference_idx",
@@ -3310,58 +3342,74 @@ innobase_check_foreign_key_index(
ulint n_drop_fk) /*!< in: Number of foreign keys
to drop */
{
- dict_foreign_t* foreign;
+ ut_ad(index != NULL);
+ ut_ad(indexed_table != NULL);
- /* Check if the index is referenced. */
- foreign = dict_table_get_referenced_constraint(indexed_table, index);
-
- ut_ad(!foreign || indexed_table
- == foreign->referenced_table);
-
- if (foreign
- && !dict_foreign_find_index(
- indexed_table, col_names,
- foreign->referenced_col_names,
- foreign->n_fields, index,
- /*check_charsets=*/TRUE,
- /*check_null=*/FALSE)
- && !innobase_find_equiv_index(
- foreign->referenced_col_names,
- foreign->n_fields,
- ha_alter_info->key_info_buffer,
- ha_alter_info->index_add_buffer,
- ha_alter_info->index_add_count)
- ) {
- trx->error_info = index;
- return(true);
+ const dict_foreign_set* fks = &indexed_table->referenced_set;
+
+ /* Check for all FK references from other tables to the index. */
+ for (dict_foreign_set::const_iterator it = fks->begin();
+ it != fks->end(); ++it) {
+
+ dict_foreign_t* foreign = *it;
+ if (foreign->referenced_index != index) {
+ continue;
+ }
+ ut_ad(indexed_table == foreign->referenced_table);
+
+ if (NULL == dict_foreign_find_index(
+ indexed_table, col_names,
+ foreign->referenced_col_names,
+ foreign->n_fields, index,
+ /*check_charsets=*/TRUE,
+ /*check_null=*/FALSE,
+ NULL, NULL, NULL)
+ && NULL == innobase_find_equiv_index(
+ foreign->referenced_col_names,
+ foreign->n_fields,
+ ha_alter_info->key_info_buffer,
+ ha_alter_info->index_add_buffer,
+ ha_alter_info->index_add_count)) {
+
+ /* Index cannot be dropped. */
+ trx->error_info = index;
+ return(true);
+ }
}
- /* Check if this index references some
- other table */
- foreign = dict_table_get_foreign_constraint(
- indexed_table, index);
-
- ut_ad(!foreign || indexed_table
- == foreign->foreign_table);
-
- if (foreign
- && !innobase_dropping_foreign(
- foreign, drop_fk, n_drop_fk)
- && !dict_foreign_find_index(
- indexed_table, col_names,
- foreign->foreign_col_names,
- foreign->n_fields, index,
- /*check_charsets=*/TRUE,
- /*check_null=*/FALSE)
- && !innobase_find_equiv_index(
- foreign->foreign_col_names,
- foreign->n_fields,
- ha_alter_info->key_info_buffer,
- ha_alter_info->index_add_buffer,
- ha_alter_info->index_add_count)
- ) {
- trx->error_info = index;
- return(true);
+ fks = &indexed_table->foreign_set;
+
+ /* Check for all FK references in current table using the index. */
+ for (dict_foreign_set::const_iterator it = fks->begin();
+ it != fks->end(); ++it) {
+
+ dict_foreign_t* foreign = *it;
+ if (foreign->foreign_index != index) {
+ continue;
+ }
+
+ ut_ad(indexed_table == foreign->foreign_table);
+
+ if (!innobase_dropping_foreign(
+ foreign, drop_fk, n_drop_fk)
+ && NULL == dict_foreign_find_index(
+ indexed_table, col_names,
+ foreign->foreign_col_names,
+ foreign->n_fields, index,
+ /*check_charsets=*/TRUE,
+ /*check_null=*/FALSE,
+ NULL, NULL, NULL)
+ && NULL == innobase_find_equiv_index(
+ foreign->foreign_col_names,
+ foreign->n_fields,
+ ha_alter_info->key_info_buffer,
+ ha_alter_info->index_add_buffer,
+ ha_alter_info->index_add_count)) {
+
+ /* Index cannot be dropped. */
+ trx->error_info = index;
+ return(true);
+ }
}
return(false);
@@ -3596,6 +3644,19 @@ check_if_ok_to_rename:
if (index->type & DICT_FTS) {
DBUG_ASSERT(index->type == DICT_FTS
|| (index->type & DICT_CORRUPT));
+
+ /* We need to drop any corrupted fts indexes
+ before we add a new fts index. */
+ if (add_fts_idx && index->type & DICT_CORRUPT) {
+ ib_errf(user_thd, IB_LOG_LEVEL_ERROR,
+ ER_INNODB_INDEX_CORRUPT,
+ "Fulltext index '%s' is corrupt. "
+ "you should drop this index first.",
+ index->name);
+
+ goto err_exit_no_heap;
+ }
+
continue;
}
@@ -4118,6 +4179,10 @@ oom:
: ha_alter_info->key_info_buffer[
prebuilt->trx->error_key_num].name);
break;
+ case DB_ENCRYPTED_DECRYPT_FAILED:
+ my_error(ER_NO_SUCH_TABLE_IN_ENGINE, MYF(0),
+ table_share->db.str, table_share->table_name.str);
+ break;
default:
my_error_innodb(error,
table_share->table_name.str,
@@ -4817,7 +4882,8 @@ innobase_update_foreign_try(
fk->n_fields, fk->referenced_index, TRUE,
fk->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL
- | DICT_FOREIGN_ON_UPDATE_SET_NULL));
+ | DICT_FOREIGN_ON_UPDATE_SET_NULL),
+ NULL, NULL, NULL);
if (!fk->foreign_index) {
my_error(ER_FK_INCORRECT_OPTION,
MYF(0), table_name, fk->id);
@@ -4829,7 +4895,7 @@ innobase_update_foreign_try(
names, while the columns in ctx->old_table have not
been renamed yet. */
error = dict_create_add_foreign_to_dictionary(
- ctx->old_table->name, fk, trx);
+ (dict_table_t*)ctx->old_table,ctx->old_table->name, fk, trx);
DBUG_EXECUTE_IF(
"innodb_test_cannot_add_fk_system",
diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic
index 40b468b200a..6604ac6a6f0 100644
--- a/storage/innobase/include/btr0btr.ic
+++ b/storage/innobase/include/btr0btr.ic
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -57,13 +58,15 @@ btr_block_get_func(
buf_block_t* block;
block = buf_page_get_gen(space, zip_size, page_no, mode,
- NULL, BUF_GET, file, line, mtr);
+ NULL, BUF_GET, file, line, mtr);
- if (mode != RW_NO_LATCH) {
+ if (block) {
+ if (mode != RW_NO_LATCH) {
- buf_block_dbg_add_level(
- block, index != NULL && dict_index_is_ibuf(index)
- ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
+ buf_block_dbg_add_level(
+ block, index != NULL && dict_index_is_ibuf(index)
+ ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
+ }
}
return(block);
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index d0fd5c2158a..88e3b84e04b 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -136,7 +136,7 @@ Note that if mode is PAGE_CUR_LE, which is used in inserts, then
cursor->up_match and cursor->low_match both will have sensible values.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
UNIV_INTERN
-void
+dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -173,7 +173,7 @@ btr_cur_search_to_nth_level(
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
-void
+dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index cfbaacf4de3..d8e7cf6b283 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -114,7 +114,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -143,7 +143,7 @@ btr_pcur_open_with_no_init_func(
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,
diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic
index 7e355d3709d..1cd13824542 100644
--- a/storage/innobase/include/btr0pcur.ic
+++ b/storage/innobase/include/btr0pcur.ic
@@ -447,7 +447,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -472,6 +472,7 @@ btr_pcur_open_with_no_init_func(
mtr_t* mtr) /*!< in: mtr */
{
btr_cur_t* btr_cursor;
+ dberr_t err = DB_SUCCESS;
cursor->latch_mode = latch_mode;
cursor->search_mode = mode;
@@ -480,20 +481,21 @@ btr_pcur_open_with_no_init_func(
btr_cursor = btr_pcur_get_btr_cur(cursor);
- btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
- btr_cursor, has_search_latch,
- file, line, mtr);
+ err = btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
+ btr_cursor, has_search_latch,
+ file, line, mtr);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
cursor->trx_if_known = NULL;
+ return err;
}
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,
@@ -506,6 +508,8 @@ btr_pcur_open_at_index_side(
(0=leaf) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
+ dberr_t err = DB_SUCCESS;
+
pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
@@ -514,13 +518,15 @@ btr_pcur_open_at_index_side(
btr_pcur_init(pcur);
}
- btr_cur_open_at_index_side(from_left, index, latch_mode,
- btr_pcur_get_btr_cur(pcur), level, mtr);
+ err = btr_cur_open_at_index_side(from_left, index, latch_mode,
+ btr_pcur_get_btr_cur(pcur), level, mtr);
pcur->pos_state = BTR_PCUR_IS_POSITIONED;
pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
pcur->trx_if_known = NULL;
+
+ return (err);
}
/**********************************************************************//**
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 11cf7ebc8cc..6c8e8e00507 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2015, MariaDB Corporation.
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
@@ -430,7 +430,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
- mtr_t* mtr); /*!< in: mini-transaction */
+ mtr_t* mtr, /*!< in: mini-transaction */
+ dberr_t* err = NULL); /*!< out: error code */
/********************************************************************//**
Initializes a page to the buffer buf_pool. The page is usually not read
from a file even if it cannot be found in the buffer buf_pool. This is one
@@ -1582,9 +1583,14 @@ struct buf_page_t{
operation needed. */
unsigned key_version; /*!< key version for this block */
- bool page_encrypted; /*!< page is encrypted */
+ bool page_encrypted; /*!< page is page encrypted */
bool page_compressed;/*!< page is page compressed */
-
+ ulint stored_checksum;/*!< stored page checksum if page
+ encrypted */
+ bool encrypted; /*!< page is still encrypted */
+ ulint calculated_checksum;
+ /*!< calculated checksum if page
+ encrypted */
ulint real_size; /*!< Real size of the page
Normal pages == UNIV_PAGE_SIZE
page compressed pages, payload
diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
index 6c128b097b0..a80a4c0a391 100644
--- a/storage/innobase/include/buf0buf.ic
+++ b/storage/innobase/include/buf0buf.ic
@@ -663,13 +663,18 @@ buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
{
- ut_ad(block);
+ if (!block) {
+ return NULL;
+ }
switch (buf_block_get_state(block)) {
case BUF_BLOCK_POOL_WATCH:
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_ZIP_DIRTY:
case BUF_BLOCK_NOT_USED:
+ if (block->page.encrypted) {
+ goto ok;
+ }
ut_error;
break;
case BUF_BLOCK_FILE_PAGE:
diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h
index d2a1f264ff5..10714031710 100644
--- a/storage/innobase/include/buf0rea.h
+++ b/storage/innobase/include/buf0rea.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -41,7 +42,8 @@ buf_read_page(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
- ulint offset);/*!< in: page number */
+ ulint offset, /*!< in: page number */
+ buf_page_t** bpage);/*!< out: page */
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index 1e87ce3fdb8..24889a9b9c5 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -132,6 +133,11 @@ enum dberr_t {
/*< Too many words in a phrase */
DB_TOO_BIG_FOR_REDO, /* Record length greater than 10%
of redo log */
+ DB_ENCRYPTED_DECRYPT_FAILED, /* Tablespace encrypted and
+ decrypt operaton failed because
+ of missing key management plugin,
+ or missing or incorrect key or
+ incorret AES method or algorithm. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
index c40e5356ece..564fad35748 100644
--- a/storage/innobase/include/dict0crea.h
+++ b/storage/innobase/include/dict0crea.h
@@ -113,6 +113,17 @@ UNIV_INTERN
dberr_t
dict_create_or_check_foreign_constraint_tables(void);
/*================================================*/
+
+/********************************************************************//**
+Construct foreign key constraint defintion from data dictionary information.
+*/
+UNIV_INTERN
+char*
+dict_foreign_def_get(
+/*=================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx); /*!< in: trx */
+
/********************************************************************//**
Generate a foreign key constraint name when it was not named by the user.
A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER,
@@ -177,11 +188,22 @@ UNIV_INTERN
dberr_t
dict_create_add_foreign_to_dictionary(
/*==================================*/
+ dict_table_t* table, /*!< in: table */
const char* name, /*!< in: table name */
const dict_foreign_t* foreign,/*!< in: foreign key */
trx_t* trx) /*!< in/out: dictionary transaction */
__attribute__((nonnull, warn_unused_result));
+/********************************************************************//**
+Construct foreign key constraint defintion from data dictionary information.
+*/
+UNIV_INTERN
+char*
+dict_foreign_def_get(
+/*=================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx); /*!< in: trx */
+
/* Table create node structure */
struct tab_node_t{
que_common_t common; /*!< node type: QUE_NODE_TABLE_CREATE */
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 820353a0c93..6b1856b8187 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
@@ -449,18 +449,6 @@ dict_foreign_add_to_cache(
/*!< in: error to be ignored */
__attribute__((nonnull(1), warn_unused_result));
/*********************************************************************//**
-Check if the index is referenced by a foreign key, if TRUE return the
-matching instance NULL otherwise.
-@return pointer to foreign key struct if index is defined for foreign
-key, otherwise NULL */
-UNIV_INTERN
-dict_foreign_t*
-dict_table_get_referenced_constraint(
-/*=================================*/
- dict_table_t* table, /*!< in: InnoDB table */
- dict_index_t* index) /*!< in: InnoDB index */
- __attribute__((nonnull, warn_unused_result));
-/*********************************************************************//**
Checks if a table is referenced by foreign keys.
@return TRUE if table is referenced by a foreign key */
UNIV_INTERN
@@ -495,19 +483,6 @@ dict_str_starts_with_keyword(
const char* keyword) /*!< in: keyword to look for */
__attribute__((nonnull, warn_unused_result));
/*********************************************************************//**
-Checks if a index is defined for a foreign key constraint. Index is a part
-of a foreign key constraint if the index is referenced by foreign key
-or index is a foreign key index
-@return pointer to foreign key struct if index is defined for foreign
-key, otherwise NULL */
-UNIV_INTERN
-dict_foreign_t*
-dict_table_get_foreign_constraint(
-/*==============================*/
- dict_table_t* table, /*!< in: InnoDB table */
- dict_index_t* index) /*!< in: InnoDB index */
- __attribute__((nonnull, warn_unused_result));
-/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function
should be called after the indexes for a table have been created.
@@ -596,10 +571,18 @@ dict_foreign_find_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
+
__attribute__((nonnull(1,3), warn_unused_result));
/**********************************************************************//**
Returns a column's name.
@@ -691,10 +674,17 @@ dict_foreign_qualify_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
__attribute__((nonnull(1,3), warn_unused_result));
#ifdef UNIV_DEBUG
/********************************************************************//**
diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
index dd42b478c1f..a3a3446d507 100644
--- a/storage/innobase/include/dict0dict.ic
+++ b/storage/innobase/include/dict0dict.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates
+Copyright (c) 2013, 2015, SkySQL 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
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 24db728ae08..53a5d6cb08b 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2015, MariaDB Corporation.
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
@@ -48,6 +48,9 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0types.h"
#include "fts0fts.h"
#include "os0once.h"
+#include "fil0fil.h"
+#include <my_crypt.h>
+#include "fil0crypt.h"
#include <set>
#include <algorithm>
#include <iterator>
@@ -1014,6 +1017,8 @@ struct dict_table_t{
table_id_t id; /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */
char* name; /*!< table name */
+ void* thd; /*!< thd */
+ fil_space_crypt_t *crypt_data; /*!< crypt data if present */
const char* dir_path_of_temp_table;/*!< NULL or the directory path
where a TEMPORARY table that was explicitly
created by a user should be placed if
@@ -1326,6 +1331,7 @@ struct dict_table_t{
locks; /*!< list of locks on the table; protected
by lock_sys->mutex */
#endif /* !UNIV_HOTBACKUP */
+ ibool is_encrypted;
#ifdef UNIV_DEBUG
ulint magic_n;/*!< magic number */
diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h
index 34452badc9f..30db095775f 100644
--- a/storage/innobase/include/fil0crypt.h
+++ b/storage/innobase/include/fil0crypt.h
@@ -382,6 +382,17 @@ fil_crypt_set_encrypt_tables(
uint val); /*!< in: New srv_encrypt_tables setting */
+/******************************************************************
+Calculate post encryption checksum
+@return page checksum or BUF_NO_CHECKSUM_MAGIC
+not needed. */
+UNIV_INTERN
+ulint
+fil_crypt_calculate_checksum(
+/*=========================*/
+ ulint zip_size, /*!< in: zip_size or 0 */
+ byte* dst_frame); /*!< in: page where to calculate */
+
#ifndef UNIV_NONINL
#include "fil0crypt.ic"
#endif
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index 93ff999bcfe..e842049e734 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -213,7 +213,8 @@ struct fsp_open_info {
#ifdef UNIV_LOG_ARCHIVE
ulint arch_log_no; /*!< latest archived log file number */
#endif /* UNIV_LOG_ARCHIVE */
- fil_space_crypt_t* crypt_data; /*!< crypt data */
+ fil_space_crypt_t* crypt_data; /*!< crypt data */
+ dict_table_t* table; /*!< table */
};
struct fil_space_t;
@@ -833,7 +834,8 @@ fil_open_single_table_tablespace(
ulint flags, /*!< in: tablespace flags */
const char* tablename, /*!< in: table name in the
databasename/tablename format */
- const char* filepath) /*!< in: tablespace filepath */
+ const char* filepath, /*!< in: tablespace filepath */
+ dict_table_t* table) /*!< in: table */
__attribute__((nonnull(5), warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h
index a2996ecacc8..d54ed281d9a 100644
--- a/storage/innobase/include/fts0fts.h
+++ b/storage/innobase/include/fts0fts.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 4d523cf1289..59abb0863d9 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -625,5 +625,22 @@ innobase_convert_to_filename_charset(
const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */
-
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ trx_t* trx, /*!< in: trx */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...);
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ void* ithd, /*!< in: thd */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...);
#endif /* HA_INNODB_PROTOTYPES_H */
diff --git a/storage/innobase/include/page0cur.ic b/storage/innobase/include/page0cur.ic
index 028d33b17aa..6e068d9f739 100644
--- a/storage/innobase/include/page0cur.ic
+++ b/storage/innobase/include/page0cur.ic
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -39,7 +40,10 @@ page_cur_get_page(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
- ut_ad(page_align(cur->rec) == cur->block->frame);
+
+ if (cur->rec) {
+ ut_ad(page_align(cur->rec) == cur->block->frame);
+ }
return(page_align(cur->rec));
}
@@ -54,7 +58,11 @@ page_cur_get_block(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
- ut_ad(page_align(cur->rec) == cur->block->frame);
+
+ if (cur->rec) {
+ ut_ad(page_align(cur->rec) == cur->block->frame);
+ }
+
return(cur->block);
}
@@ -80,7 +88,10 @@ page_cur_get_rec(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
- ut_ad(page_align(cur->rec) == cur->block->frame);
+
+ if (cur->rec) {
+ ut_ad(page_align(cur->rec) == cur->block->frame);
+ }
return(cur->rec);
}
diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h
index 93dcf9cf49b..888289a6c79 100644
--- a/storage/innobase/include/row0purge.h
+++ b/storage/innobase/include/row0purge.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -119,6 +119,16 @@ struct purge_node_t{
clustered index record */
ibool done; /* Debug flag */
+#ifdef UNIV_DEBUG
+ /***********************************************************//**
+ Validate the persisent cursor. The purge node has two references
+ to the clustered index record - one via the ref member, and the
+ other via the persistent cursor. These two references must match
+ each other if the found_clust flag is set.
+ @return true if the persistent cursor is consistent with
+ the ref member.*/
+ bool validate_pcur();
+#endif
};
#ifndef UNIV_NONINL
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index 4732ac48290..8dd97cf0070 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -45,7 +45,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 5
#define INNODB_VERSION_MINOR 6
-#define INNODB_VERSION_BUGFIX 25
+#define INNODB_VERSION_BUGFIX 26
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index 6d0a2d6a1f8..8c4fd623fc6 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -131,15 +131,16 @@ log_blocks_crypt(
const byte* block, /*!< in: blocks before encrypt/decrypt*/
ulint size, /*!< in: size of block */
byte* dst_block, /*!< out: blocks after encrypt/decrypt */
- bool is_encrypt) /*!< in: encrypt or decrypt*/
+ int what) /*!< in: encrypt or decrypt*/
{
byte *log_block = (byte*)block;
Crypt_result rc = MY_AES_OK;
uint dst_len;
byte aes_ctr_counter[MY_AES_BLOCK_SIZE];
+ byte is_encrypt= what == ENCRYPTION_FLAG_ENCRYPT;
lsn_t lsn = is_encrypt ? log_sys->lsn : srv_start_lsn;
- const int src_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE;
+ const uint src_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE;
for (ulint i = 0; i < size ; i += OS_FILE_LOG_BLOCK_SIZE) {
ulint log_block_no = log_block_get_hdr_no(log_block);
lsn_t log_block_start_lsn = log_block_get_start_lsn(
@@ -174,21 +175,13 @@ log_blocks_crypt(
bzero(aes_ctr_counter + 15, 1);
int rc;
- if (is_encrypt) {
- rc = encryption_encrypt(log_block + LOG_BLOCK_HDR_SIZE, src_len,
- dst_block + LOG_BLOCK_HDR_SIZE, &dst_len,
- (unsigned char*)(info->crypt_key), 16,
- aes_ctr_counter, MY_AES_BLOCK_SIZE, 1,
- LOG_DEFAULT_ENCRYPTION_KEY,
- info->key_version);
- } else {
- rc = encryption_decrypt(log_block + LOG_BLOCK_HDR_SIZE, src_len,
- dst_block + LOG_BLOCK_HDR_SIZE, &dst_len,
- (unsigned char*)(info->crypt_key), 16,
- aes_ctr_counter, MY_AES_BLOCK_SIZE, 1,
- LOG_DEFAULT_ENCRYPTION_KEY,
- info->key_version);
- }
+ rc = encryption_crypt(log_block + LOG_BLOCK_HDR_SIZE, src_len,
+ dst_block + LOG_BLOCK_HDR_SIZE, &dst_len,
+ (unsigned char*)(info->crypt_key), 16,
+ aes_ctr_counter, MY_AES_BLOCK_SIZE,
+ what | ENCRYPTION_FLAG_NOPAD,
+ LOG_DEFAULT_ENCRYPTION_KEY,
+ info->key_version);
ut_a(rc == MY_AES_OK);
ut_a(dst_len == src_len);
@@ -230,10 +223,11 @@ init_crypt_key(
}
uint dst_len;
- int rc= my_aes_encrypt_ecb(info->crypt_msg, sizeof(info->crypt_msg), //src, srclen
- info->crypt_key, &dst_len, //dst, &dstlen
- (unsigned char*)&mysqld_key, sizeof(mysqld_key),
- NULL, 0, 1);
+ int rc= my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_NOPAD|ENCRYPTION_FLAG_ENCRYPT,
+ info->crypt_msg, sizeof(info->crypt_msg), //src, srclen
+ info->crypt_key, &dst_len, //dst, &dstlen
+ (unsigned char*)&mysqld_key, sizeof(mysqld_key),
+ NULL, 0);
if (rc != MY_AES_OK || dst_len != MY_AES_BLOCK_SIZE) {
fprintf(stderr,
@@ -296,7 +290,7 @@ log_blocks_encrypt(
const ulint size, /*!< in: size of blocks, must be multiple of a log block */
byte* dst_block) /*!< out: blocks after encryption */
{
- return log_blocks_crypt(block, size, dst_block, true);
+ return log_blocks_crypt(block, size, dst_block, ENCRYPTION_FLAG_ENCRYPT);
}
/*********************************************************************//**
@@ -366,7 +360,7 @@ log_encrypt_before_write(
byte* dst_frame = (byte*)malloc(size);
//encrypt log blocks content
- Crypt_result result = log_blocks_crypt(block, size, dst_frame, true);
+ Crypt_result result = log_blocks_crypt(block, size, dst_frame, ENCRYPTION_FLAG_ENCRYPT);
if (result == MY_AES_OK) {
ut_ad(block[0] == dst_frame[0]);
@@ -392,7 +386,7 @@ log_decrypt_after_read(
byte* dst_frame = (byte*)malloc(size);
// decrypt log blocks content
- Crypt_result result = log_blocks_crypt(frame, size, dst_frame, false);
+ Crypt_result result = log_blocks_crypt(frame, size, dst_frame, ENCRYPTION_FLAG_DECRYPT);
if (result == MY_AES_OK) {
memcpy(frame, dst_frame, size);
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index 80525a39d1e..7aa321cfddb 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -1571,6 +1571,7 @@ os_file_create_simple_no_error_handling_func(
*success = (file != INVALID_HANDLE_VALUE);
#else /* __WIN__ */
int create_flag;
+ const char* mode_str = NULL;
ut_a(name);
if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
@@ -1581,6 +1582,8 @@ os_file_create_simple_no_error_handling_func(
if (create_mode == OS_FILE_OPEN) {
+ mode_str = "OPEN";
+
if (access_type == OS_FILE_READ_ONLY) {
create_flag = O_RDONLY;
@@ -1599,10 +1602,14 @@ os_file_create_simple_no_error_handling_func(
} else if (srv_read_only_mode) {
+ mode_str = "OPEN";
+
create_flag = O_RDONLY;
} else if (create_mode == OS_FILE_CREATE) {
+ mode_str = "CREATE";
+
create_flag = O_RDWR | O_CREAT | O_EXCL;
} else {
@@ -1617,6 +1624,17 @@ os_file_create_simple_no_error_handling_func(
*success = file == -1 ? FALSE : TRUE;
+ /* This function is always called for data files, we should disable
+ OS caching (O_DIRECT) here as we do in os_file_create_func(), so
+ we open the same file in the same mode, see man page of open(2). */
+ if (!srv_read_only_mode
+ && *success
+ && (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT
+ || srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC)) {
+
+ os_file_set_nocache(file, name, mode_str);
+ }
+
#ifdef USE_FILE_LOCK
if (!srv_read_only_mode
&& *success
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index d5f766ef51b..4034a228153 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2012, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -139,14 +139,6 @@ struct row_import {
ulint find_col(const char* name) const UNIV_NOTHROW;
/**
- Find the index field entry in in the cfg indexes fields.
- @name - of the index to look for
- @return instance if found else 0. */
- const dict_field_t* find_field(
- const row_index_t* cfg_index,
- const char* name) const UNIV_NOTHROW;
-
- /**
Get the number of rows for which purge failed during the convert phase.
@param name - index name
@return number of rows for which purge failed. */
@@ -1141,30 +1133,6 @@ row_import::find_col(
}
/**
-Find the index field entry in in the cfg indexes fields.
-@name - of the index to look for
-@return instance if found else 0. */
-const dict_field_t*
-row_import::find_field(
- const row_index_t* cfg_index,
- const char* name) const UNIV_NOTHROW
-{
- const dict_field_t* field = cfg_index->m_fields;
-
- for (ulint i = 0; i < cfg_index->m_n_fields; ++i, ++field) {
- const char* field_name;
-
- field_name = reinterpret_cast<const char*>(field->name);
-
- if (strcmp(field_name, name) == 0) {
- return(field);
- }
- }
-
- return(0);
-}
-
-/**
Check if the index schema that was read from the .cfg file matches the
in memory index definition.
@return DB_SUCCESS or error code. */
@@ -1187,51 +1155,60 @@ row_import::match_index_columns(
return(DB_ERROR);
}
- cfg_index->m_srv_index = index;
+ if (cfg_index->m_n_fields != index->n_fields) {
- const dict_field_t* field = index->fields;
+ ib_errf(thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Index field count %lu doesn't match"
+ " tablespace metadata file value %lu",
+ (ulong) index->n_fields,
+ (ulong) cfg_index->m_n_fields);
- for (ulint i = 0; i < index->n_fields; ++i, ++field) {
+ return(DB_ERROR);
+ }
- const dict_field_t* cfg_field;
+ cfg_index->m_srv_index = index;
- cfg_field = find_field(cfg_index, field->name);
+ const dict_field_t* field = index->fields;
+ const dict_field_t* cfg_field = cfg_index->m_fields;
- if (cfg_field == 0) {
+ for (ulint i = 0; i < index->n_fields; ++i, ++field, ++cfg_field) {
+
+ if (strcmp(field->name, cfg_field->name) != 0) {
ib_errf(thd, IB_LOG_LEVEL_ERROR,
ER_TABLE_SCHEMA_MISMATCH,
- "Index %s field %s not found in tablespace "
- "meta-data file.",
- index->name, field->name);
+ "Index field name %s doesn't match"
+ " tablespace metadata field name %s"
+ " for field position %lu",
+ field->name, cfg_field->name, (ulong) i);
err = DB_ERROR;
- } else {
+ }
- if (cfg_field->prefix_len != field->prefix_len) {
- ib_errf(thd, IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Index %s field %s prefix len %lu "
- "doesn't match meta-data file value "
- "%lu",
- index->name, field->name,
- (ulong) field->prefix_len,
- (ulong) cfg_field->prefix_len);
+ if (cfg_field->prefix_len != field->prefix_len) {
+ ib_errf(thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Index %s field %s prefix len %lu"
+ " doesn't match metadata file value"
+ " %lu",
+ index->name, field->name,
+ (ulong) field->prefix_len,
+ (ulong) cfg_field->prefix_len);
- err = DB_ERROR;
- }
+ err = DB_ERROR;
+ }
- if (cfg_field->fixed_len != field->fixed_len) {
- ib_errf(thd, IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Index %s field %s fixed len %lu "
- "doesn't match meta-data file value "
- "%lu",
- index->name, field->name,
- (ulong) field->fixed_len,
- (ulong) cfg_field->fixed_len);
+ if (cfg_field->fixed_len != field->fixed_len) {
+ ib_errf(thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Index %s field %s fixed len %lu"
+ " doesn't match metadata file value"
+ " %lu",
+ index->name, field->name,
+ (ulong) field->fixed_len,
+ (ulong) cfg_field->fixed_len);
- err = DB_ERROR;
- }
+ err = DB_ERROR;
}
}
@@ -3651,7 +3628,7 @@ row_import_for_mysql(
err = fil_open_single_table_tablespace(
true, true, table->space,
dict_tf_to_fsp_flags(table->flags),
- table->name, filepath);
+ table->name, filepath, table);
DBUG_EXECUTE_IF("ib_import_open_tablespace_failure",
err = DB_TABLESPACE_NOT_FOUND;);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 44c9ac32d16..4f891e0f114 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -2338,7 +2338,7 @@ row_ins_clust_index_entry_low(
{
btr_cur_t cursor;
ulint* offsets = NULL;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
big_rec_t* big_rec = NULL;
mtr_t mtr;
mem_heap_t* offsets_heap = NULL;
@@ -2361,9 +2361,16 @@ row_ins_clust_index_entry_low(
the function will return in both low_match and up_match of the
cursor sensible values */
- btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
+ err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
+ if (err != DB_SUCCESS) {
+ index->table->is_encrypted = true;
+ index->table->ibd_file_missing = true;
+ mtr_commit(&mtr);
+ goto func_exit;
+ }
+
#ifdef UNIV_DEBUG
{
page_t* page = btr_cur_get_page(&cursor);
@@ -2669,9 +2676,22 @@ row_ins_sec_index_entry_low(
search_mode |= BTR_IGNORE_SEC_UNIQUE;
}
- btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
- search_mode,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
+ search_mode,
+ &cursor, 0, __FILE__, __LINE__, &mtr);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning(trx->mysql_thd,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+ goto func_exit;
+ }
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
/* The insert was buffered during the search: we are done */
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index c1d3e08beaa..ab2ea05b2f2 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -1431,6 +1431,13 @@ row_merge_read_clustered_index(
row_ext_t* ext;
page_cur_t* cur = btr_pcur_get_page_cur(&pcur);
+ /* Do not continue if table pages are still encrypted */
+ if (old_table->is_encrypted || new_table->is_encrypted) {
+ err = DB_ENCRYPTED_DECRYPT_FAILED;
+ trx->error_key_num = 0;
+ goto func_exit;
+ }
+
page_cur_move_to_next(cur);
if (page_cur_is_after_last(cur)) {
@@ -3754,6 +3761,17 @@ row_merge_build_indexes(
pct_cost = COST_READ_CLUSTERED_INDEX * 100 / (total_static_cost + total_dynamic_cost);
+ /* Do not continue if we can't encrypt table pages */
+ if (old_table->is_encrypted || new_table->is_encrypted) {
+ error = DB_ENCRYPTED_DECRYPT_FAILED;
+ ib_push_warning(trx->mysql_thd, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ old_table->is_encrypted ? old_table->name : new_table->name);
+ goto func_exit;
+ }
+
/* Read clustered index of the table and create files for
secondary index entries for merge sort */
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 9ed14ffc9cb..d46e2b1c3ef 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -623,6 +623,8 @@ handle_new_error:
case DB_FTS_INVALID_DOCID:
case DB_INTERRUPTED:
case DB_DICT_CHANGED:
+ case DB_TABLE_NOT_FOUND:
+ case DB_ENCRYPTED_DECRYPT_FAILED:
if (savept) {
/* Roll back the latest, possibly incomplete insertion
or update */
@@ -1315,7 +1317,13 @@ row_insert_for_mysql(
prebuilt->table->name);
return(DB_TABLESPACE_NOT_FOUND);
-
+ } else if (prebuilt->table->is_encrypted) {
+ ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s in tablespace %lu encrypted."
+ "However key management plugin or used key_id is not found or"
+ " used encryption algorithm or method does not match.",
+ prebuilt->table->name, prebuilt->table->space);
+ return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
@@ -1710,6 +1718,13 @@ row_update_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
return(DB_ERROR);
+ } else if (prebuilt->table->is_encrypted) {
+ ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s in tablespace %lu encrypted."
+ "However key management plugin or used key_id is not found or"
+ " used encryption algorithm or method does not match.",
+ prebuilt->table->name, prebuilt->table->space);
+ return (DB_TABLE_NOT_FOUND);
}
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
@@ -3919,6 +3934,19 @@ row_drop_table_for_mysql(
goto funct_exit;
}
+ /* If table is encrypted and table page encryption failed
+ mark this table read only. */
+ if (table->is_encrypted) {
+
+ if (table->can_be_evicted) {
+ dict_table_move_from_lru_to_non_lru(table);
+ }
+
+ dict_table_close(table, TRUE, FALSE);
+ err = DB_READ_ONLY;
+ goto funct_exit;
+ }
+
/* Turn on this drop bit before we could release the dictionary
latch */
table->to_be_dropped = true;
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 8212a7b43e0..b26ba971a95 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -84,7 +84,7 @@ row_purge_node_create(
/***********************************************************//**
Repositions the pcur in the purge node on the clustered index record,
-if found.
+if found. If the record is not found, close pcur.
@return TRUE if the record was found */
static
ibool
@@ -95,11 +95,10 @@ row_purge_reposition_pcur(
mtr_t* mtr) /*!< in: mtr */
{
if (node->found_clust) {
- ibool found;
+ ut_ad(node->validate_pcur());
- found = btr_pcur_restore_position(mode, &node->pcur, mtr);
+ node->found_clust = btr_pcur_restore_position(mode, &node->pcur, mtr);
- return(found);
} else {
node->found_clust = row_search_on_row_ref(
&node->pcur, mode, node->table, node->ref, mtr);
@@ -109,6 +108,11 @@ row_purge_reposition_pcur(
}
}
+ /* Close the current cursor if we fail to position it correctly. */
+ if (!node->found_clust) {
+ btr_pcur_close(&node->pcur);
+ }
+
return(node->found_clust);
}
@@ -182,7 +186,12 @@ func_exit:
mem_heap_free(heap);
}
- btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
+ /* Persistent cursor is closed if reposition fails. */
+ if (node->found_clust) {
+ btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
+ } else {
+ mtr_commit(&mtr);
+ }
return(success);
}
@@ -251,7 +260,12 @@ row_purge_poss_sec(
btr_pcur_get_rec(&node->pcur),
&mtr, index, entry);
- btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
+ /* Persistent cursor is closed if reposition fails. */
+ if (node->found_clust) {
+ btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
+ } else {
+ mtr_commit(&mtr);
+ }
return(can_delete);
}
@@ -831,6 +845,8 @@ row_purge_record_func(
dict_index_t* clust_index;
bool purged = true;
+ ut_ad(!node->found_clust);
+
clust_index = dict_table_get_first_index(node->table);
node->index = dict_table_get_next_index(clust_index);
@@ -986,3 +1002,52 @@ row_purge_step(
return(thr);
}
+
+#ifdef UNIV_DEBUG
+/***********************************************************//**
+Validate the persisent cursor. The purge node has two references
+to the clustered index record - one via the ref member, and the
+other via the persistent cursor. These two references must match
+each other if the found_clust flag is set.
+@return true if the stored copy of persistent cursor is consistent
+with the ref member.*/
+bool
+purge_node_t::validate_pcur()
+{
+ if (!found_clust) {
+ return(true);
+ }
+
+ if (index == NULL) {
+ return(true);
+ }
+
+ if (index->type == DICT_FTS) {
+ return(true);
+ }
+
+ if (pcur.old_stored != BTR_PCUR_OLD_STORED) {
+ return(true);
+ }
+
+ dict_index_t* clust_index = pcur.btr_cur.index;
+
+ ulint* offsets = rec_get_offsets(
+ pcur.old_rec, clust_index, NULL, pcur.old_n_fields, &heap);
+
+ /* Here we are comparing the purge ref record and the stored initial
+ part in persistent cursor. Both cases we store n_uniq fields of the
+ cluster index and so it is fine to do the comparison. We note this
+ dependency here as pcur and ref belong to different modules. */
+ int st = cmp_dtuple_rec(ref, pcur.old_rec, offsets);
+
+ if (st != 0) {
+ fprintf(stderr, "Purge node pcur validation failed\n");
+ dtuple_print(stderr, ref);
+ rec_print(stderr, pcur.old_rec, clust_index);
+ return(false);
+ }
+
+ return(true);
+}
+#endif /* UNIV_DEBUG */
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index b0e0c89b778..53ec30b1f42 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -1,7 +1,8 @@
/*****************************************************************************
-Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
+Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -3717,6 +3718,9 @@ row_search_for_mysql(
return(DB_TABLESPACE_NOT_FOUND);
+ } else if (prebuilt->table->is_encrypted) {
+
+ return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (!prebuilt->index_usable) {
return(DB_MISSING_HISTORY);
@@ -4143,9 +4147,14 @@ wait_table_again:
} else if (dtuple_get_n_fields(search_tuple) > 0) {
- btr_pcur_open_with_no_init(index, search_tuple, mode,
- BTR_SEARCH_LEAF,
- pcur, 0, &mtr);
+ err = btr_pcur_open_with_no_init(index, search_tuple, mode,
+ BTR_SEARCH_LEAF,
+ pcur, 0, &mtr);
+
+ if (err != DB_SUCCESS) {
+ rec = NULL;
+ goto lock_wait_or_error;
+ }
pcur->trx_if_known = trx;
@@ -4179,9 +4188,23 @@ wait_table_again:
}
}
} else if (mode == PAGE_CUR_G || mode == PAGE_CUR_L) {
- btr_pcur_open_at_index_side(
+ err = btr_pcur_open_at_index_side(
mode == PAGE_CUR_G, index, BTR_SEARCH_LEAF,
pcur, false, 0, &mtr);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning(trx->mysql_thd,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ prebuilt->table->name);
+ index->table->is_encrypted = true;
+ }
+ rec = NULL;
+ goto lock_wait_or_error;
+ }
}
rec_loop:
@@ -4196,6 +4219,12 @@ rec_loop:
/* PHASE 4: Look for matching records in a loop */
rec = btr_pcur_get_rec(pcur);
+
+ if (!rec) {
+ err = DB_ENCRYPTED_DECRYPT_FAILED;
+ goto lock_wait_or_error;
+ }
+
ut_ad(!!page_rec_is_comp(rec) == comp);
#ifdef UNIV_SEARCH_DEBUG
/*
@@ -5113,7 +5142,9 @@ lock_wait_or_error:
/*-------------------------------------------------------------*/
- btr_pcur_store_position(pcur, &mtr);
+ if (rec) {
+ btr_pcur_store_position(pcur, &mtr);
+ }
lock_table_wait:
mtr_commit(&mtr);
diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc
index 68446cc85ef..f19737aa123 100644
--- a/storage/innobase/ut/ut0ut.cc
+++ b/storage/innobase/ut/ut0ut.cc
@@ -824,6 +824,8 @@ ut_strerr(
return("Too many words in a FTS phrase or proximity search");
case DB_TOO_BIG_FOR_REDO:
return("BLOB record length is greater than 10%% of redo log");
+ case DB_ENCRYPTED_DECRYPT_FAILED:
+ return("Table is encrypted but decrypt failed.");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index 4a5c48a5891..2f2558d22c0 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -5187,8 +5187,7 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
Don't allocate more than 16K on the stack to ensure we don't get
stack overflow.
*/
- if (!(old_record= my_safe_alloca(info->s->base.reclength,
- MARIA_MAX_RECORD_ON_STACK)))
+ if (!(old_record= my_safe_alloca(info->s->base.reclength)))
DBUG_RETURN(1);
/* Don't let the compare destroy blobs that may be in use */
@@ -5210,8 +5209,7 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
info->rec_buff_size= org_rec_buff_size;
}
DBUG_PRINT("exit", ("result: %d", error));
- my_safe_afree(old_record, info->s->base.reclength,
- MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(old_record, info->s->base.reclength);
DBUG_RETURN(error != 0);
}
diff --git a/storage/maria/ma_check_standalone.h b/storage/maria/ma_check_standalone.h
index c240ca056e7..6626a62c4ef 100644
--- a/storage/maria/ma_check_standalone.h
+++ b/storage/maria/ma_check_standalone.h
@@ -30,7 +30,7 @@ static unsigned int no_key()
struct encryption_service_st encryption_handler=
{
- no_key, 0, 0, 0, 0, 0
+ no_key, 0, 0, 0, 0, 0, 0
};
int encryption_scheme_encrypt(const unsigned char* src __attribute__((unused)),
diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c
index eb6352b7a87..2e17a95f390 100644
--- a/storage/maria/ma_dynrec.c
+++ b/storage/maria/ma_dynrec.c
@@ -250,8 +250,7 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
MARIA_DYN_DELETE_BLOCK_HEADER+1);
reclength= (info->s->base.pack_reclength +
_ma_calc_total_blob_length(info,record)+ extra);
- if (!(rec_buff=(uchar*) my_safe_alloca(reclength,
- MARIA_MAX_RECORD_ON_STACK)))
+ if (!(rec_buff=(uchar*) my_safe_alloca(reclength)))
{
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1);
@@ -265,7 +264,7 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
error= write_dynamic_record(info,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
reclength2);
- my_safe_afree(rec_buff, reclength, MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(rec_buff, reclength);
return(error != 0);
}
@@ -289,8 +288,7 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
return 1;
}
#endif
- if (!(rec_buff=(uchar*) my_safe_alloca(reclength,
- MARIA_MAX_RECORD_ON_STACK)))
+ if (!(rec_buff=(uchar*) my_safe_alloca(reclength)))
{
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1);
@@ -300,7 +298,7 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
error=update_dynamic_record(info,pos,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
reclength);
- my_safe_afree(rec_buff, reclength, MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(rec_buff, reclength);
return(error != 0);
}
@@ -1555,8 +1553,7 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
my_bool error;
DBUG_ENTER("_ma_cmp_dynamic_unique");
- if (!(old_record= my_safe_alloca(info->s->base.reclength,
- MARIA_MAX_RECORD_ON_STACK)))
+ if (!(old_record= my_safe_alloca(info->s->base.reclength)))
DBUG_RETURN(1);
/* Don't let the compare destroy blobs that may be in use */
@@ -1577,8 +1574,7 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
info->rec_buff= old_rec_buff;
info->rec_buff_size= old_rec_buff_size;
}
- my_safe_afree(old_record, info->s->base.reclength,
- MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(old_record, info->s->base.reclength);
DBUG_RETURN(error);
}
@@ -1613,8 +1609,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
{
buffer_length= (info->s->base.pack_reclength +
_ma_calc_total_blob_length(info,record));
- if (!(buffer=(uchar*) my_safe_alloca(buffer_length,
- MARIA_MAX_RECORD_ON_STACK)))
+ if (!(buffer=(uchar*) my_safe_alloca(buffer_length)))
DBUG_RETURN(1);
}
reclength= _ma_rec_pack(info,buffer,record);
@@ -1666,7 +1661,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
error= 0;
err:
if (buffer != info->rec_buff)
- my_safe_afree(buffer, buffer_length, MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(buffer, buffer_length);
DBUG_PRINT("exit", ("result: %d", error));
DBUG_RETURN(error);
}
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
index 8315c3136c5..bba99703119 100644
--- a/storage/maria/ma_pagecache.c
+++ b/storage/maria/ma_pagecache.c
@@ -833,17 +833,23 @@ ulong init_pagecache(PAGECACHE *pagecache, size_t use_mem,
Allocate memory for blocks, hash_links and hash entries;
For each block 2 hash links are allocated
*/
- if (my_multi_malloc(MYF(MY_ZEROFILL),
- &pagecache->block_root, blocks * sizeof(PAGECACHE_BLOCK_LINK),
- &pagecache->hash_root,
- sizeof(PAGECACHE_HASH_LINK*) * pagecache->hash_entries,
- &pagecache->hash_link_root,
- hash_links * sizeof(PAGECACHE_HASH_LINK),
- &pagecache->changed_blocks,
- sizeof(PAGECACHE_BLOCK_LINK*) * changed_blocks_hash_size,
- &pagecache->file_blocks,
- sizeof(PAGECACHE_BLOCK_LINK*) * changed_blocks_hash_size,
- NullS))
+ if (my_multi_malloc_large(MYF(MY_ZEROFILL),
+ &pagecache->block_root,
+ (ulonglong) (blocks *
+ sizeof(PAGECACHE_BLOCK_LINK)),
+ &pagecache->hash_root,
+ (ulonglong) (sizeof(PAGECACHE_HASH_LINK*) *
+ pagecache->hash_entries),
+ &pagecache->hash_link_root,
+ (ulonglong) (hash_links *
+ sizeof(PAGECACHE_HASH_LINK)),
+ &pagecache->changed_blocks,
+ (ulonglong) (sizeof(PAGECACHE_BLOCK_LINK*) *
+ changed_blocks_hash_size),
+ &pagecache->file_blocks,
+ (ulonglong) (sizeof(PAGECACHE_BLOCK_LINK*) *
+ changed_blocks_hash_size),
+ NullS))
break;
my_large_free(pagecache->block_mem);
pagecache->block_mem= 0;
diff --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c
index 7eca9e14e93..280c5ff8f0a 100644
--- a/storage/maria/maria_pack.c
+++ b/storage/maria/maria_pack.c
@@ -861,7 +861,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
reclength= mrg->file[0]->s->base.reclength;
null_bytes= mrg->file[0]->s->base.null_bytes;
- record=(uchar*) my_safe_alloca(reclength, MARIA_MAX_RECORD_ON_STACK);
+ record=(uchar*) my_safe_alloca(reclength);
end_count=huff_counts+mrg->file[0]->s->base.fields;
record_count=0; glob_crc=0;
max_blob_length=0;
@@ -1145,7 +1145,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
mrg->records=record_count;
mrg->max_blob_length=max_blob_length;
- my_safe_afree(record, reclength, MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(record, reclength);
DBUG_RETURN(error != HA_ERR_END_OF_FILE);
}
@@ -2415,8 +2415,7 @@ static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
DBUG_ENTER("compress_maria_file");
/* Allocate a buffer for the records (excluding blobs). */
- if (!(record=(uchar*) my_safe_alloca(isam_file->s->base.reclength,
- MARIA_MAX_RECORD_ON_STACK)))
+ if (!(record=(uchar*) my_safe_alloca(isam_file->s->base.reclength)))
return -1;
end_count=huff_counts+isam_file->s->base.fields;
@@ -2779,8 +2778,7 @@ static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
if (verbose >= 2)
printf("wrote %s records.\n", llstr((longlong) record_count, llbuf));
- my_safe_afree(record, isam_file->s->base.reclength,
- MARIA_MAX_RECORD_ON_STACK);
+ my_safe_afree(record, isam_file->s->base.reclength);
mrg->ref_length=max_pack_length;
mrg->min_pack_length=max_record_length ? min_record_length : 0;
mrg->max_pack_length=max_record_length;
diff --git a/storage/mroonga/CMakeLists.txt b/storage/mroonga/CMakeLists.txt
index 3b88d942165..9aa5a4bd990 100644
--- a/storage/mroonga/CMakeLists.txt
+++ b/storage/mroonga/CMakeLists.txt
@@ -132,31 +132,6 @@ include(${MRN_SOURCE_DIR}/build/cmake_modules/ReadFileList.cmake)
set(MRN_C_COMPILE_FLAGS "")
set(MRN_CXX_COMPILE_FLAGS "")
-macro(mrn_check_cflag flag)
- string(REGEX REPLACE "[-=]" "_" temporary_variable_name ${flag})
- string(TOUPPER "${temporary_variable_name}" temporary_variable_name)
- set(temporary_variable_name "CFLAG${temporary_variable_name}")
- check_c_compiler_flag(${flag} ${temporary_variable_name})
- if(${temporary_variable_name})
- set(MRN_C_COMPILE_FLAGS "${MRN_C_COMPILE_FLAGS} ${flag}")
- endif()
-endmacro()
-
-macro(mrn_check_cxxflag flag)
- string(REGEX REPLACE "[-=]" "_" temporary_variable_name ${flag})
- string(TOUPPER "${temporary_variable_name}" temporary_variable_name)
- set(temporary_variable_name "CXXFLAG${temporary_variable_name}")
- check_cxx_compiler_flag(${flag} ${temporary_variable_name})
- if(${temporary_variable_name})
- set(MRN_CXX_COMPILE_FLAGS "${MRN_CXX_COMPILE_FLAGS} ${flag}")
- endif()
-endmacro()
-
-macro(mrn_build_flag flag)
- mrn_check_cflag(${flag})
- mrn_check_cxxflag(${flag})
-endmacro()
-
if(MRN_BUNDLED)
set(MRN_RELATIVE_DIR_PREFIX "${MRN_SOURCE_DIR}/")
else()
@@ -360,19 +335,15 @@ else()
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
- mrn_build_flag("-Wall")
- mrn_build_flag("-Wextra")
- mrn_build_flag("-Wno-unused-parameter")
- mrn_build_flag("-Wno-strict-aliasing")
- mrn_build_flag("-Wno-deprecated")
- mrn_check_cxxflag("-fno-implicit-templates")
- if(("${MYSQL_VARIANT}" STREQUAL "MariaDB") OR
- ("${MYSQL_VARIANT}" STREQUAL "MySQL" AND
- ${MYSQL_VERSION} VERSION_LESS "5.7.0"))
- mrn_check_cxxflag("-fno-exceptions")
- mrn_check_cxxflag("-fno-rtti")
- endif()
- mrn_check_cxxflag("-felide-constructors")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wall")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wextra")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-unused-parameter")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-strict-aliasing")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-deprecated")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fno-implicit-templates")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fno-exceptions")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fno-rtti")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-felide-constructors")
endif()
set_source_files_properties(${MRN_SOURCES} PROPERTIES
COMPILE_FLAGS "${MYSQL_CFLAGS} ${MRN_CXX_COMPILE_FLAGS}")
@@ -392,11 +363,9 @@ else()
endif()
if(GROONGA_NORMALIZER_MYSQL_FOUND)
- set_property(TARGET mroonga APPEND PROPERTY
- COMPILE_DEFINITIONS "WITH_GROONGA_NORMALIZER_MYSQL=1")
+ add_definitions("-DWITH_GROONGA_NORMALIZER_MYSQL=1")
if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
- set_property(TARGET mroonga APPEND PROPERTY
- COMPILE_DEFINITIONS "MRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED")
+ add_definitions("-DMRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED")
else()
set_property(TARGET mroonga APPEND PROPERTY
COMPILE_DEFINITIONS "GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME=\"normalizers/mysql\"")
@@ -404,8 +373,7 @@ if(GROONGA_NORMALIZER_MYSQL_FOUND)
endif()
if(MRN_GROONGA_EMBED)
- set_property(TARGET mroonga APPEND PROPERTY
- COMPILE_DEFINITIONS "MRN_GROONGA_EMBEDDED")
+ add_definitions("-DMRN_GROONGA_EMBEDDED")
endif()
set(MRN_DEFAULT_PARSER "" CACHE STRING
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt b/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt
index 611d08f0c78..d2ed32ddf34 100644
--- a/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt
@@ -1 +1 @@
---performance-schema
+--loose-performance-schema
diff --git a/storage/mroonga/vendor/groonga/CMakeLists.txt b/storage/mroonga/vendor/groonga/CMakeLists.txt
index ebe7f6b7fe5..625a65b48d0 100644
--- a/storage/mroonga/vendor/groonga/CMakeLists.txt
+++ b/storage/mroonga/vendor/groonga/CMakeLists.txt
@@ -143,59 +143,34 @@ if(CMAKE_COMPILER_IS_GNUCC)
endif()
-macro(check_cflag flag)
- string(REGEX REPLACE "[-=]" "_" temporary_variable_name ${flag})
- string(TOUPPER "${temporary_variable_name}" temporary_variable_name)
- set(temporary_variable_name "CFLAG${temporary_variable_name}")
- check_c_compiler_flag(${flag} ${temporary_variable_name})
- if(${temporary_variable_name})
- set(GRN_C_COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS} ${flag}")
- endif()
-endmacro()
-
-macro(check_cxxflag flag)
- string(REGEX REPLACE "[-=]" "_" temporary_variable_name ${flag})
- string(TOUPPER "${temporary_variable_name}" temporary_variable_name)
- set(temporary_variable_name "CXXFLAG${temporary_variable_name}")
- check_cxx_compiler_flag(${flag} ${temporary_variable_name})
- if(${temporary_variable_name})
- set(GRN_CXX_COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS} ${flag}")
- endif()
-endmacro()
-
-macro(check_build_flag flag)
- check_cflag(${flag})
- check_cxxflag(${flag})
-endmacro()
-
if(CMAKE_COMPILER_IS_GNUCXX)
- check_build_flag("-Wall")
- check_build_flag("-Wextra")
- check_build_flag("-Wno-unused-but-set-variable")
- check_build_flag("-Wno-unused-parameter")
- check_build_flag("-Wno-sign-compare")
- check_cflag("-Wno-pointer-sign")
- check_build_flag("-Wno-missing-field-initializers")
- check_build_flag("-Wformat=2")
- check_build_flag("-Wstrict-aliasing=2")
- check_build_flag("-fno-strict-aliasing")
- check_build_flag("-Wdisabled-optimization")
- check_build_flag("-Wfloat-equal")
- check_build_flag("-Wpointer-arith")
- check_cflag("-Wdeclaration-after-statement")
- check_cflag("-Wbad-function-cast")
- check_build_flag("-Wcast-align")
- # check_build_flag("-Wredundant-decls")
- check_build_flag("-Wwrite-strings")
- check_cxxflag("-fexceptions")
- check_cxxflag("-fimplicit-templates")
- check_build_flag("-Wno-clobbered")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wall")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wextra")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-unused-but-set-variable")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-unused-parameter")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-sign-compare")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-pointer-sign")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-missing-field-initializers")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wformat=2")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wstrict-aliasing=2")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fno-strict-aliasing")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wdisabled-optimization")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wfloat-equal")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wpointer-arith")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wdeclaration-after-statement")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wbad-function-cast")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wcast-align")
+ #MY_CHECK_AND_SET_COMPILER_FLAG("-Wredundant-decls")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wwrite-strings")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fexceptions")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fimplicit-templates")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-clobbered")
endif()
if(NOT DEFINED CMAKE_C_COMPILE_OPTIONS_PIC)
# For old CMake
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGCXX)
- check_build_flag("-fPIC")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fPIC")
endif()
endif()
@@ -366,7 +341,9 @@ endif()
set(GRN_WITH_LZ4 "auto"
CACHE STRING "Support data compression by LZ4.")
if(NOT ${GRN_WITH_LZ4} STREQUAL "no")
- pkg_check_modules(LIBLZ4 liblz4)
+ if(NOT DEFINED LIBLZ4_FOUND)
+ pkg_check_modules(LIBLZ4 liblz4)
+ endif()
if(LIBLZ4_FOUND)
set(GRN_WITH_LZ4 TRUE)
else()
@@ -417,7 +394,9 @@ endif()
set(GRN_WITH_KYTEA "auto"
CACHE STRING "use KyTea for morphological analysis")
if(NOT ${GRN_WITH_KYTEA} STREQUAL "no")
- pkg_check_modules(KYTEA kytea)
+ if(NOT DEFINED KYTEA_FOUND)
+ pkg_check_modules(KYTEA kytea)
+ endif()
if(KYTEA_FOUND)
set(GRN_WITH_KYTEA TRUE)
else()
@@ -465,7 +444,9 @@ endif()
set(GRN_WITH_ZEROMQ "auto"
CACHE STRING "use ZeroMQ for suggestion")
if(NOT ${GRN_WITH_ZEROMQ} STREQUAL "no")
- pkg_check_modules(ZEROMQ libzmq)
+ if(NOT DEFINED ZEROMQ_FOUND)
+ pkg_check_modules(ZEROMQ libzmq)
+ endif()
if(ZEROMQ_FOUND)
set(GRN_WITH_ZEROMQ TRUE)
else()
@@ -508,7 +489,9 @@ endif()
set(GRN_WITH_MESSAGE_PACK "auto"
CACHE STRING "use MessagePack for suggestion")
if(NOT ${GRN_WITH_MESSAGE_PACK} STREQUAL "no")
- pkg_check_modules(MESSAGE_PACK msgpack)
+ if(NOT DEFINED MESSAGE_PACK_FOUND)
+ pkg_check_modules(MESSAGE_PACK msgpack)
+ endif()
if(MESSAGE_PACK_FOUND)
set(GRN_WITH_MESSAGE_PACK TRUE)
else()
diff --git a/storage/oqgraph/CMakeLists.txt b/storage/oqgraph/CMakeLists.txt
index 1cb5c828d92..772a8f61bd5 100644
--- a/storage/oqgraph/CMakeLists.txt
+++ b/storage/oqgraph/CMakeLists.txt
@@ -5,6 +5,7 @@ MESSAGE(STATUS "Configuring OQGraph")
FIND_PACKAGE(Boost 1.40.0)
IF(NOT Boost_FOUND)
MESSAGE(STATUS "Boost not found. OQGraph will not be compiled")
+ SET(OQGRAPH_OK 0 CACHE INTERNAL "")
RETURN()
ENDIF()
INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS})
@@ -12,6 +13,7 @@ INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS})
FIND_PACKAGE(Judy)
IF(NOT Judy_FOUND)
MESSAGE(STATUS "Judy not found. OQGraph will not be compiled")
+ SET(OQGRAPH_OK 0 CACHE INTERNAL "")
RETURN()
ENDIF()
INCLUDE_DIRECTORIES(${Judy_INCLUDE_DIR})
@@ -19,9 +21,9 @@ INCLUDE_DIRECTORIES(${Judy_INCLUDE_DIR})
IF(MSVC)
# # lp:756966 OQGRAPH on Win64 does not compile
# IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
-# SET(BOOST_OK 0)
+# SET(OQGRAPH_OK 0 CACHE INTERNAL "")
# ELSE()
- SET(BOOST_OK 1)
+ SET(OQGRAPH_OK 1 CACHE INTERNAL "")
# ENDIF()
ELSE()
# See if that works. On old gcc it'll fail because of -fno-rtti
@@ -33,10 +35,10 @@ CHECK_CXX_SOURCE_COMPILES(
#include <boost/config.hpp>
#include <boost/property_map/property_map.hpp>
int main() { return 0; }
-" BOOST_OK)
+" OQGRAPH_OK)
ENDIF()
-IF(BOOST_OK)
+IF(OQGRAPH_OK)
ADD_DEFINITIONS(-DHAVE_OQGRAPH)
IF(MSVC)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc" PARENT_SCOPE)
@@ -50,7 +52,6 @@ IF(BOOST_OK)
ENDIF(MSVC)
ADD_DEFINITIONS(-DBOOST_NO_RTTI=1 -DBOOST_NO_TYPEID=1 -DBOOST_DISABLE_ASSERTS=1)
- MESSAGE(STATUS "OQGraph OK")
MYSQL_ADD_PLUGIN(oqgraph ha_oqgraph.cc graphcore.cc graphcore-graph.cc
oqgraph_shim.cc oqgraph_thunk.cc oqgraph_judy.cc
STORAGE_ENGINE
@@ -58,9 +59,11 @@ IF(BOOST_OK)
RECOMPILE_FOR_EMBEDDED
COMPONENT oqgraph-engine
LINK_LIBRARIES ${Judy_LIBRARIES})
-ELSE(BOOST_OK)
+ELSE(OQGRAPH_OK)
MESSAGE(STATUS "Requisites for OQGraph not met. OQGraph will not be compiled")
-ENDIF(BOOST_OK)
+ENDIF(OQGRAPH_OK)
ENDFUNCTION()
-CHECK_OQGRAPH()
+IF(NOT DEFINED OQGRAPH_OK)
+ CHECK_OQGRAPH()
+ENDIF()
diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc
index 81592c85d0c..29e74271670 100644
--- a/storage/perfschema/ha_perfschema.cc
+++ b/storage/perfschema/ha_perfschema.cc
@@ -225,7 +225,7 @@ maria_declare_plugin(perfschema)
0x0001,
pfs_status_vars,
NULL,
- "5.6.25",
+ "5.6.26",
MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
diff --git a/storage/perfschema/pfs_account.cc b/storage/perfschema/pfs_account.cc
index 3eff670f44d..4e3a6d8d1d3 100644
--- a/storage/perfschema/pfs_account.cc
+++ b/storage/perfschema/pfs_account.cc
@@ -69,8 +69,8 @@ int init_account(const PFS_global_param *param)
if (account_max > 0)
{
- account_array= PFS_MALLOC_ARRAY(account_max, PFS_account,
- MYF(MY_ZEROFILL));
+ account_array= PFS_MALLOC_ARRAY(account_max, sizeof(PFS_account), PFS_account,
+ MYF(MY_ZEROFILL));
if (unlikely(account_array == NULL))
return 1;
}
diff --git a/storage/perfschema/pfs_con_slice.cc b/storage/perfschema/pfs_con_slice.cc
index 263f25c1c08..bd449df0a4b 100644
--- a/storage/perfschema/pfs_con_slice.cc
+++ b/storage/perfschema/pfs_con_slice.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -39,7 +39,8 @@ PFS_connection_slice::alloc_waits_slice(uint sizing)
if (sizing > 0)
{
- slice= PFS_MALLOC_ARRAY(sizing, PFS_single_stat, MYF(MY_ZEROFILL));
+ slice= PFS_MALLOC_ARRAY(sizing, sizeof(PFS_single_stat), PFS_single_stat,
+ MYF(MY_ZEROFILL));
if (unlikely(slice == NULL))
return NULL;
@@ -58,7 +59,8 @@ PFS_connection_slice::alloc_stages_slice(uint sizing)
if (sizing > 0)
{
- slice= PFS_MALLOC_ARRAY(sizing, PFS_stage_stat, MYF(MY_ZEROFILL));
+ slice= PFS_MALLOC_ARRAY(sizing, sizeof(PFS_stage_stat), PFS_stage_stat,
+ MYF(MY_ZEROFILL));
if (unlikely(slice == NULL))
return NULL;
@@ -77,7 +79,8 @@ PFS_connection_slice::alloc_statements_slice(uint sizing)
if (sizing > 0)
{
- slice= PFS_MALLOC_ARRAY(sizing, PFS_statement_stat, MYF(MY_ZEROFILL));
+ slice= PFS_MALLOC_ARRAY(sizing, sizeof(PFS_statement_stat), PFS_statement_stat,
+ MYF(MY_ZEROFILL));
if (unlikely(slice == NULL))
return NULL;
diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc
index 6c0b41908e1..0a01ee08993 100644
--- a/storage/perfschema/pfs_digest.cc
+++ b/storage/perfschema/pfs_digest.cc
@@ -35,7 +35,7 @@
#include "sql_string.h"
#include <string.h>
-ulong digest_max= 0;
+size_t digest_max= 0;
ulong digest_lost= 0;
/** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
@@ -59,8 +59,6 @@ static bool digest_hash_inited= false;
*/
int init_digest(const PFS_global_param *param)
{
- unsigned int index;
-
/*
Allocate memory for statements_digest_stat_array based on
performance_schema_digests_size values
@@ -75,6 +73,7 @@ int init_digest(const PFS_global_param *param)
statements_digest_stat_array=
PFS_MALLOC_ARRAY(digest_max,
+ sizeof(PFS_statements_digest_stat),
PFS_statements_digest_stat,
MYF(MY_ZEROFILL));
@@ -86,8 +85,12 @@ int init_digest(const PFS_global_param *param)
if (pfs_max_digest_length > 0)
{
+ /* Size of each digest array. */
+ size_t digest_memory_size= pfs_max_digest_length * sizeof(unsigned char);
+
statements_digest_token_array=
- PFS_MALLOC_ARRAY(digest_max * pfs_max_digest_length,
+ PFS_MALLOC_ARRAY(digest_max,
+ digest_memory_size,
unsigned char,
MYF(MY_ZEROFILL));
@@ -98,7 +101,7 @@ int init_digest(const PFS_global_param *param)
}
}
- for (index= 0; index < digest_max; index++)
+ for (size_t index= 0; index < digest_max; index++)
{
statements_digest_stat_array[index].reset_data(statements_digest_token_array
+ index * pfs_max_digest_length, pfs_max_digest_length);
@@ -336,8 +339,6 @@ void PFS_statements_digest_stat::reset_index(PFS_thread *thread)
void reset_esms_by_digest()
{
- uint index;
-
if (statements_digest_stat_array == NULL)
return;
@@ -346,7 +347,7 @@ void reset_esms_by_digest()
return;
/* Reset statements_digest_stat_array. */
- for (index= 0; index < digest_max; index++)
+ for (size_t index= 0; index < digest_max; index++)
{
statements_digest_stat_array[index].reset_index(thread);
statements_digest_stat_array[index].reset_data(statements_digest_token_array + index * pfs_max_digest_length, pfs_max_digest_length);
diff --git a/storage/perfschema/pfs_digest.h b/storage/perfschema/pfs_digest.h
index 9d021737c44..76d6c33d984 100644
--- a/storage/perfschema/pfs_digest.h
+++ b/storage/perfschema/pfs_digest.h
@@ -27,7 +27,7 @@
#include "sql_digest.h"
extern bool flag_statements_digest;
-extern ulong digest_max;
+extern size_t digest_max;
extern ulong digest_lost;
struct PFS_thread;
diff --git a/storage/perfschema/pfs_events_stages.cc b/storage/perfschema/pfs_events_stages.cc
index 282071f830e..7351c95c9cb 100644
--- a/storage/perfschema/pfs_events_stages.cc
+++ b/storage/perfschema/pfs_events_stages.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -59,8 +59,8 @@ int init_events_stages_history_long(uint events_stages_history_long_sizing)
return 0;
events_stages_history_long_array=
- PFS_MALLOC_ARRAY(events_stages_history_long_size, PFS_events_stages,
- MYF(MY_ZEROFILL));
+ PFS_MALLOC_ARRAY(events_stages_history_long_size, sizeof(PFS_events_stages),
+ PFS_events_stages, MYF(MY_ZEROFILL));
return (events_stages_history_long_array ? 0 : 1);
}
diff --git a/storage/perfschema/pfs_events_statements.cc b/storage/perfschema/pfs_events_statements.cc
index dc34755d747..cecd0167c38 100644
--- a/storage/perfschema/pfs_events_statements.cc
+++ b/storage/perfschema/pfs_events_statements.cc
@@ -30,7 +30,7 @@
#include "pfs_atomic.h"
#include "m_string.h"
-ulong events_statements_history_long_size= 0;
+size_t events_statements_history_long_size= 0;
/** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */
bool flag_events_statements_current= false;
/** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */
@@ -50,9 +50,8 @@ static unsigned char *h_long_stmts_digest_token_array= NULL;
Initialize table EVENTS_STATEMENTS_HISTORY_LONG.
@param events_statements_history_long_sizing table sizing
*/
-int init_events_statements_history_long(uint events_statements_history_long_sizing)
+int init_events_statements_history_long(size_t events_statements_history_long_sizing)
{
- uint index;
events_statements_history_long_size= events_statements_history_long_sizing;
events_statements_history_long_full= false;
PFS_atomic::store_u32(&events_statements_history_long_index, 0);
@@ -61,8 +60,8 @@ int init_events_statements_history_long(uint events_statements_history_long_sizi
return 0;
events_statements_history_long_array=
- PFS_MALLOC_ARRAY(events_statements_history_long_size, PFS_events_statements,
- MYF(MY_ZEROFILL));
+ PFS_MALLOC_ARRAY(events_statements_history_long_size, sizeof(PFS_events_statements),
+ PFS_events_statements, MYF(MY_ZEROFILL));
if (events_statements_history_long_array == NULL)
{
@@ -72,8 +71,11 @@ int init_events_statements_history_long(uint events_statements_history_long_sizi
if (pfs_max_digest_length > 0)
{
+ /* Size of each digest token array. */
+ size_t digest_text_size= pfs_max_digest_length * sizeof(unsigned char);
+
h_long_stmts_digest_token_array=
- PFS_MALLOC_ARRAY(events_statements_history_long_size * pfs_max_digest_length,
+ PFS_MALLOC_ARRAY(events_statements_history_long_size, digest_text_size,
unsigned char, MYF(MY_ZEROFILL));
if (h_long_stmts_digest_token_array == NULL)
{
@@ -82,7 +84,7 @@ int init_events_statements_history_long(uint events_statements_history_long_sizi
}
}
- for (index= 0; index < events_statements_history_long_size; index++)
+ for (size_t index= 0; index < events_statements_history_long_size; index++)
{
events_statements_history_long_array[index].m_digest_storage.reset(h_long_stmts_digest_token_array
+ index * pfs_max_digest_length, pfs_max_digest_length);
diff --git a/storage/perfschema/pfs_events_statements.h b/storage/perfschema/pfs_events_statements.h
index 3637e4ca764..b1e303e7021 100644
--- a/storage/perfschema/pfs_events_statements.h
+++ b/storage/perfschema/pfs_events_statements.h
@@ -106,9 +106,9 @@ extern bool flag_events_statements_history_long;
extern bool events_statements_history_long_full;
extern volatile uint32 events_statements_history_long_index;
extern PFS_events_statements *events_statements_history_long_array;
-extern ulong events_statements_history_long_size;
+extern size_t events_statements_history_long_size;
-int init_events_statements_history_long(uint events_statements_history_long_sizing);
+int init_events_statements_history_long(size_t events_statements_history_long_sizing);
void cleanup_events_statements_history_long();
void reset_events_statements_current();
diff --git a/storage/perfschema/pfs_events_waits.cc b/storage/perfschema/pfs_events_waits.cc
index 2799550c81d..1120ac2a445 100644
--- a/storage/perfschema/pfs_events_waits.cc
+++ b/storage/perfschema/pfs_events_waits.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -63,8 +63,8 @@ int init_events_waits_history_long(uint events_waits_history_long_sizing)
return 0;
events_waits_history_long_array=
- PFS_MALLOC_ARRAY(events_waits_history_long_size, PFS_events_waits,
- MYF(MY_ZEROFILL));
+ PFS_MALLOC_ARRAY(events_waits_history_long_size, sizeof(PFS_events_waits),
+ PFS_events_waits, MYF(MY_ZEROFILL));
return (events_waits_history_long_array ? 0 : 1);
}
diff --git a/storage/perfschema/pfs_global.cc b/storage/perfschema/pfs_global.cc
index 0744bbab7d5..bd346f2b235 100644
--- a/storage/perfschema/pfs_global.cc
+++ b/storage/perfschema/pfs_global.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -52,7 +52,7 @@ void *pfs_malloc(size_t size, myf flags)
DBUG_ASSERT(! pfs_initialized);
DBUG_ASSERT(size > 0);
- void *ptr;
+ void *ptr= NULL;
#ifdef PFS_ALIGNEMENT
#ifdef HAVE_POSIX_MEMALIGN
@@ -128,6 +128,40 @@ void pfs_print_error(const char *format, ...)
fflush(stderr);
}
+/**
+ Array allocation for the performance schema.
+ Checks for overflow of n * size before allocating.
+ @param n number of array elements
+ @param size element size
+ @param flags malloc flags
+ @return pointer to memory on success, else NULL
+*/
+void *pfs_malloc_array(size_t n, size_t size, myf flags)
+{
+ DBUG_ASSERT(n > 0);
+ DBUG_ASSERT(size > 0);
+ size_t array_size= n * size;
+ /* Check for overflow before allocating. */
+ if (is_overflow(array_size, n, size))
+ return NULL;
+ return pfs_malloc(array_size, flags);
+}
+
+/**
+ Detect multiplication overflow.
+ @param product multiplication product
+ @param n1 operand
+ @param n2 operand
+ @return true if multiplication caused an overflow.
+*/
+bool is_overflow(size_t product, size_t n1, size_t n2)
+{
+ if (n1 != 0 && (product / n1 != n2))
+ return true;
+ else
+ return false;
+}
+
/** Convert raw ip address into readable format. Do not do a reverse DNS lookup. */
uint pfs_get_socket_address(char *host,
diff --git a/storage/perfschema/pfs_global.h b/storage/perfschema/pfs_global.h
index f9687524cd5..f3326c5589f 100644
--- a/storage/perfschema/pfs_global.h
+++ b/storage/perfschema/pfs_global.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -44,18 +44,24 @@ extern size_t pfs_allocated_memory;
void *pfs_malloc(size_t size, myf flags);
+/** Allocate an array of structures with overflow check. */
+void *pfs_malloc_array(size_t n, size_t size, myf flags);
+
/**
Helper, to allocate an array of structures.
- @param n number of elements in the array.
- @param T type of an element.
+ @param n number of elements in the array
+ @param s size of array element
+ @param T type of an element
@param f flags to use when allocating memory
*/
-#define PFS_MALLOC_ARRAY(n, T, f) \
- reinterpret_cast<T*> (pfs_malloc((n) * sizeof(T), (f)))
+#define PFS_MALLOC_ARRAY(n, s, T, f) \
+ reinterpret_cast<T*>(pfs_malloc_array((n), (s), (f)))
/** Free memory allocated with @sa pfs_malloc. */
void pfs_free(void *ptr);
+/** Detect multiplication overflow. */
+bool is_overflow(size_t product, size_t n1, size_t n2);
uint pfs_get_socket_address(char *host,
uint host_len,
@@ -107,7 +113,7 @@ inline uint randomized_index(const void *ptr, uint max_size)
value= (reinterpret_cast<intptr> (ptr)) >> 3;
value*= 1789;
value+= seed2 + seed1 + 1;
-
+
result= (static_cast<uint> (value)) % max_size;
seed2= seed1*seed1;
diff --git a/storage/perfschema/pfs_host.cc b/storage/perfschema/pfs_host.cc
index 80f3900275d..7da34a6d5f6 100644
--- a/storage/perfschema/pfs_host.cc
+++ b/storage/perfschema/pfs_host.cc
@@ -66,7 +66,7 @@ int init_host(const PFS_global_param *param)
if (host_max > 0)
{
- host_array= PFS_MALLOC_ARRAY(host_max, PFS_host,
+ host_array= PFS_MALLOC_ARRAY(host_max, sizeof(PFS_host), PFS_host,
MYF(MY_ZEROFILL));
if (unlikely(host_array == NULL))
return 1;
diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc
index 5e75df4a16f..a9ea6faf212 100644
--- a/storage/perfschema/pfs_instr.cc
+++ b/storage/perfschema/pfs_instr.cc
@@ -94,7 +94,7 @@ ulong events_stages_history_per_thread;
/** Number of EVENTS_STATEMENTS_HISTORY records per thread. */
ulong events_statements_history_per_thread;
uint statement_stack_max;
-uint pfs_max_digest_length= 0;
+size_t pfs_max_digest_length= 0;
/** Number of locker lost. @sa LOCKER_STACK_SIZE. */
ulong locker_lost= 0;
/** Number of statement lost. @sa STATEMENT_STACK_SIZE. */
@@ -287,56 +287,56 @@ int init_instruments(const PFS_global_param *param)
if (mutex_max > 0)
{
- mutex_array= PFS_MALLOC_ARRAY(mutex_max, PFS_mutex, MYF(MY_ZEROFILL));
+ mutex_array= PFS_MALLOC_ARRAY(mutex_max, sizeof(PFS_mutex), PFS_mutex, MYF(MY_ZEROFILL));
if (unlikely(mutex_array == NULL))
return 1;
}
if (rwlock_max > 0)
{
- rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, PFS_rwlock, MYF(MY_ZEROFILL));
+ rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, sizeof(PFS_rwlock), PFS_rwlock, MYF(MY_ZEROFILL));
if (unlikely(rwlock_array == NULL))
return 1;
}
if (cond_max > 0)
{
- cond_array= PFS_MALLOC_ARRAY(cond_max, PFS_cond, MYF(MY_ZEROFILL));
+ cond_array= PFS_MALLOC_ARRAY(cond_max, sizeof(PFS_cond), PFS_cond, MYF(MY_ZEROFILL));
if (unlikely(cond_array == NULL))
return 1;
}
if (file_max > 0)
{
- file_array= PFS_MALLOC_ARRAY(file_max, PFS_file, MYF(MY_ZEROFILL));
+ file_array= PFS_MALLOC_ARRAY(file_max, sizeof(PFS_file), PFS_file, MYF(MY_ZEROFILL));
if (unlikely(file_array == NULL))
return 1;
}
if (file_handle_max > 0)
{
- file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, PFS_file*, MYF(MY_ZEROFILL));
+ file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, sizeof(PFS_file*), PFS_file*, MYF(MY_ZEROFILL));
if (unlikely(file_handle_array == NULL))
return 1;
}
if (table_max > 0)
{
- table_array= PFS_MALLOC_ARRAY(table_max, PFS_table, MYF(MY_ZEROFILL));
+ table_array= PFS_MALLOC_ARRAY(table_max, sizeof(PFS_table), PFS_table, MYF(MY_ZEROFILL));
if (unlikely(table_array == NULL))
return 1;
}
if (socket_max > 0)
{
- socket_array= PFS_MALLOC_ARRAY(socket_max, PFS_socket, MYF(MY_ZEROFILL));
+ socket_array= PFS_MALLOC_ARRAY(socket_max, sizeof(PFS_socket), PFS_socket, MYF(MY_ZEROFILL));
if (unlikely(socket_array == NULL))
return 1;
}
if (thread_max > 0)
{
- thread_array= PFS_MALLOC_ARRAY(thread_max, PFS_thread, MYF(MY_ZEROFILL));
+ thread_array= PFS_MALLOC_ARRAY(thread_max, sizeof(PFS_thread), PFS_thread, MYF(MY_ZEROFILL));
if (unlikely(thread_array == NULL))
return 1;
}
@@ -344,7 +344,7 @@ int init_instruments(const PFS_global_param *param)
if (thread_waits_history_sizing > 0)
{
thread_waits_history_array=
- PFS_MALLOC_ARRAY(thread_waits_history_sizing, PFS_events_waits,
+ PFS_MALLOC_ARRAY(thread_waits_history_sizing, sizeof(PFS_events_waits), PFS_events_waits,
MYF(MY_ZEROFILL));
if (unlikely(thread_waits_history_array == NULL))
return 1;
@@ -354,7 +354,7 @@ int init_instruments(const PFS_global_param *param)
{
thread_instr_class_waits_array=
PFS_MALLOC_ARRAY(thread_instr_class_waits_sizing,
- PFS_single_stat, MYF(MY_ZEROFILL));
+ sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL));
if (unlikely(thread_instr_class_waits_array == NULL))
return 1;
@@ -365,7 +365,7 @@ int init_instruments(const PFS_global_param *param)
if (thread_stages_history_sizing > 0)
{
thread_stages_history_array=
- PFS_MALLOC_ARRAY(thread_stages_history_sizing, PFS_events_stages,
+ PFS_MALLOC_ARRAY(thread_stages_history_sizing, sizeof(PFS_events_stages), PFS_events_stages,
MYF(MY_ZEROFILL));
if (unlikely(thread_stages_history_array == NULL))
return 1;
@@ -375,7 +375,7 @@ int init_instruments(const PFS_global_param *param)
{
thread_instr_class_stages_array=
PFS_MALLOC_ARRAY(thread_instr_class_stages_sizing,
- PFS_stage_stat, MYF(MY_ZEROFILL));
+ sizeof(PFS_stage_stat), PFS_stage_stat, MYF(MY_ZEROFILL));
if (unlikely(thread_instr_class_stages_array == NULL))
return 1;
@@ -386,8 +386,8 @@ int init_instruments(const PFS_global_param *param)
if (thread_statements_history_sizing > 0)
{
thread_statements_history_array=
- PFS_MALLOC_ARRAY(thread_statements_history_sizing, PFS_events_statements,
- MYF(MY_ZEROFILL));
+ PFS_MALLOC_ARRAY(thread_statements_history_sizing, sizeof(PFS_events_statements),
+ PFS_events_statements, MYF(MY_ZEROFILL));
if (unlikely(thread_statements_history_array == NULL))
return 1;
}
@@ -395,8 +395,8 @@ int init_instruments(const PFS_global_param *param)
if (thread_statements_stack_sizing > 0)
{
thread_statements_stack_array=
- PFS_MALLOC_ARRAY(thread_statements_stack_sizing, PFS_events_statements,
- MYF(MY_ZEROFILL));
+ PFS_MALLOC_ARRAY(thread_statements_stack_sizing, sizeof(PFS_events_statements),
+ PFS_events_statements, MYF(MY_ZEROFILL));
if (unlikely(thread_statements_stack_array == NULL))
return 1;
}
@@ -405,7 +405,7 @@ int init_instruments(const PFS_global_param *param)
{
thread_instr_class_statements_array=
PFS_MALLOC_ARRAY(thread_instr_class_statements_sizing,
- PFS_statement_stat, MYF(MY_ZEROFILL));
+ sizeof(PFS_statement_stat), PFS_statement_stat, MYF(MY_ZEROFILL));
if (unlikely(thread_instr_class_statements_array == NULL))
return 1;
@@ -477,7 +477,7 @@ int init_instruments(const PFS_global_param *param)
{
global_instr_class_stages_array=
PFS_MALLOC_ARRAY(stage_class_max,
- PFS_stage_stat, MYF(MY_ZEROFILL));
+ sizeof(PFS_stage_stat), PFS_stage_stat, MYF(MY_ZEROFILL));
if (unlikely(global_instr_class_stages_array == NULL))
return 1;
@@ -489,7 +489,7 @@ int init_instruments(const PFS_global_param *param)
{
global_instr_class_statements_array=
PFS_MALLOC_ARRAY(statement_class_max,
- PFS_statement_stat, MYF(MY_ZEROFILL));
+ sizeof(PFS_statement_stat), PFS_statement_stat, MYF(MY_ZEROFILL));
if (unlikely(global_instr_class_statements_array == NULL))
return 1;
diff --git a/storage/perfschema/pfs_instr.h b/storage/perfschema/pfs_instr.h
index a639f94fada..b25f5769b69 100644
--- a/storage/perfschema/pfs_instr.h
+++ b/storage/perfschema/pfs_instr.h
@@ -299,7 +299,7 @@ struct PFS_ALIGNED PFS_socket : public PFS_instr
/** Max size of the statements stack. */
extern uint statement_stack_max;
/** Max size of the digests token array. */
-extern uint pfs_max_digest_length;
+extern size_t pfs_max_digest_length;
/**
@def PFS_MAX_ALLOC_RETRY
diff --git a/storage/perfschema/pfs_instr_class.cc b/storage/perfschema/pfs_instr_class.cc
index 84e0a0357a0..c67c120283d 100644
--- a/storage/perfschema/pfs_instr_class.cc
+++ b/storage/perfschema/pfs_instr_class.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -255,24 +255,24 @@ int init_sync_class(uint mutex_class_sizing,
if (mutex_class_max > 0)
{
- mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, PFS_mutex_class,
- MYF(MY_ZEROFILL));
+ mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, sizeof(PFS_mutex_class),
+ PFS_mutex_class, MYF(MY_ZEROFILL));
if (unlikely(mutex_class_array == NULL))
return 1;
}
if (rwlock_class_max > 0)
{
- rwlock_class_array= PFS_MALLOC_ARRAY(rwlock_class_max, PFS_rwlock_class,
- MYF(MY_ZEROFILL));
+ rwlock_class_array= PFS_MALLOC_ARRAY(rwlock_class_max, sizeof(PFS_rwlock_class),
+ PFS_rwlock_class, MYF(MY_ZEROFILL));
if (unlikely(rwlock_class_array == NULL))
return 1;
}
if (cond_class_max > 0)
{
- cond_class_array= PFS_MALLOC_ARRAY(cond_class_max, PFS_cond_class,
- MYF(MY_ZEROFILL));
+ cond_class_array= PFS_MALLOC_ARRAY(cond_class_max, sizeof(PFS_cond_class),
+ PFS_cond_class, MYF(MY_ZEROFILL));
if (unlikely(cond_class_array == NULL))
return 1;
}
@@ -308,8 +308,8 @@ int init_thread_class(uint thread_class_sizing)
if (thread_class_max > 0)
{
- thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, PFS_thread_class,
- MYF(MY_ZEROFILL));
+ thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, sizeof(PFS_thread_class),
+ PFS_thread_class, MYF(MY_ZEROFILL));
if (unlikely(thread_class_array == NULL))
result= 1;
}
@@ -341,8 +341,8 @@ int init_table_share(uint table_share_sizing)
if (table_share_max > 0)
{
- table_share_array= PFS_MALLOC_ARRAY(table_share_max, PFS_table_share,
- MYF(MY_ZEROFILL));
+ table_share_array= PFS_MALLOC_ARRAY(table_share_max, sizeof(PFS_table_share),
+ PFS_table_share, MYF(MY_ZEROFILL));
if (unlikely(table_share_array == NULL))
result= 1;
}
@@ -481,8 +481,8 @@ int init_file_class(uint file_class_sizing)
if (file_class_max > 0)
{
- file_class_array= PFS_MALLOC_ARRAY(file_class_max, PFS_file_class,
- MYF(MY_ZEROFILL));
+ file_class_array= PFS_MALLOC_ARRAY(file_class_max, sizeof(PFS_file_class),
+ PFS_file_class, MYF(MY_ZEROFILL));
if (unlikely(file_class_array == NULL))
return 1;
}
@@ -515,8 +515,8 @@ int init_stage_class(uint stage_class_sizing)
if (stage_class_max > 0)
{
- stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, PFS_stage_class,
- MYF(MY_ZEROFILL));
+ stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, sizeof(PFS_stage_class),
+ PFS_stage_class, MYF(MY_ZEROFILL));
if (unlikely(stage_class_array == NULL))
return 1;
}
@@ -549,8 +549,8 @@ int init_statement_class(uint statement_class_sizing)
if (statement_class_max > 0)
{
- statement_class_array= PFS_MALLOC_ARRAY(statement_class_max, PFS_statement_class,
- MYF(MY_ZEROFILL));
+ statement_class_array= PFS_MALLOC_ARRAY(statement_class_max, sizeof(PFS_statement_class),
+ PFS_statement_class, MYF(MY_ZEROFILL));
if (unlikely(statement_class_array == NULL))
return 1;
}
@@ -583,8 +583,8 @@ int init_socket_class(uint socket_class_sizing)
if (socket_class_max > 0)
{
- socket_class_array= PFS_MALLOC_ARRAY(socket_class_max, PFS_socket_class,
- MYF(MY_ZEROFILL));
+ socket_class_array= PFS_MALLOC_ARRAY(socket_class_max, sizeof(PFS_socket_class),
+ PFS_socket_class, MYF(MY_ZEROFILL));
if (unlikely(socket_class_array == NULL))
return 1;
}
diff --git a/storage/perfschema/pfs_server.h b/storage/perfschema/pfs_server.h
index e0fe71bc8c5..bc0c69e86b9 100644
--- a/storage/perfschema/pfs_server.h
+++ b/storage/perfschema/pfs_server.h
@@ -200,7 +200,7 @@ struct PFS_global_param
/** Maximum number of session attribute strings per thread */
long m_session_connect_attrs_sizing;
- uint m_max_digest_length;
+ long m_max_digest_length;
/** Sizing hints, for auto tuning. */
PFS_sizing_hints m_hints;
diff --git a/storage/perfschema/pfs_setup_actor.cc b/storage/perfschema/pfs_setup_actor.cc
index ff45e4a0971..f12d70840c1 100644
--- a/storage/perfschema/pfs_setup_actor.cc
+++ b/storage/perfschema/pfs_setup_actor.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -60,8 +60,8 @@ int init_setup_actor(const PFS_global_param *param)
if (setup_actor_max > 0)
{
- setup_actor_array= PFS_MALLOC_ARRAY(setup_actor_max, PFS_setup_actor,
- MYF(MY_ZEROFILL));
+ setup_actor_array= PFS_MALLOC_ARRAY(setup_actor_max, sizeof(PFS_setup_actor),
+ PFS_setup_actor, MYF(MY_ZEROFILL));
if (unlikely(setup_actor_array == NULL))
return 1;
}
diff --git a/storage/perfschema/pfs_setup_object.cc b/storage/perfschema/pfs_setup_object.cc
index c77039663b2..809fe8edd24 100644
--- a/storage/perfschema/pfs_setup_object.cc
+++ b/storage/perfschema/pfs_setup_object.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -55,8 +55,8 @@ int init_setup_object(const PFS_global_param *param)
if (setup_object_max > 0)
{
- setup_object_array= PFS_MALLOC_ARRAY(setup_object_max, PFS_setup_object,
- MYF(MY_ZEROFILL));
+ setup_object_array= PFS_MALLOC_ARRAY(setup_object_max, sizeof(PFS_setup_object),
+ PFS_setup_object, MYF(MY_ZEROFILL));
if (unlikely(setup_object_array == NULL))
return 1;
}
diff --git a/storage/perfschema/pfs_user.cc b/storage/perfschema/pfs_user.cc
index a009e5d65ef..528457fe017 100644
--- a/storage/perfschema/pfs_user.cc
+++ b/storage/perfschema/pfs_user.cc
@@ -66,7 +66,7 @@ int init_user(const PFS_global_param *param)
if (user_max > 0)
{
- user_array= PFS_MALLOC_ARRAY(user_max, PFS_user,
+ user_array= PFS_MALLOC_ARRAY(user_max, sizeof(PFS_user), PFS_user,
MYF(MY_ZEROFILL));
if (unlikely(user_array == NULL))
return 1;
diff --git a/storage/perfschema/table_events_stages.cc b/storage/perfschema/table_events_stages.cc
index f98ff60d569..42761d92abf 100644
--- a/storage/perfschema/table_events_stages.cc
+++ b/storage/perfschema/table_events_stages.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -121,6 +121,7 @@ void table_events_stages_common::make_row(PFS_events_stages *stage)
{
const char *base;
const char *safe_source_file;
+ ulonglong timer_end;
m_row_exists= false;
@@ -135,7 +136,16 @@ void table_events_stages_common::make_row(PFS_events_stages *stage)
m_row.m_nesting_event_id= stage->m_nesting_event_id;
m_row.m_nesting_event_type= stage->m_nesting_event_type;
- m_normalizer->to_pico(stage->m_timer_start, stage->m_timer_end,
+ if (m_row.m_end_event_id == 0)
+ {
+ timer_end= get_timer_raw_value(stage_timer);
+ }
+ else
+ {
+ timer_end= stage->m_timer_end;
+ }
+
+ m_normalizer->to_pico(stage->m_timer_start, timer_end,
& m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
m_row.m_name= klass->m_name;
diff --git a/storage/perfschema/table_events_statements.cc b/storage/perfschema/table_events_statements.cc
index 16f048a0a7f..84f30ce000f 100644
--- a/storage/perfschema/table_events_statements.cc
+++ b/storage/perfschema/table_events_statements.cc
@@ -215,6 +215,7 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat
{
const char *base;
const char *safe_source_file;
+ ulonglong timer_end;
m_row_exists= false;
@@ -229,7 +230,16 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat
m_row.m_nesting_event_id= statement->m_nesting_event_id;
m_row.m_nesting_event_type= statement->m_nesting_event_type;
- m_normalizer->to_pico(statement->m_timer_start, statement->m_timer_end,
+ if (m_row.m_end_event_id == 0)
+ {
+ timer_end= get_timer_raw_value(statement_timer);
+ }
+ else
+ {
+ timer_end= statement->m_timer_end;
+ }
+
+ m_normalizer->to_pico(statement->m_timer_start, timer_end,
& m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
m_row.m_lock_time= statement->m_lock_time * MICROSEC_TO_PICOSEC;
@@ -249,8 +259,8 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat
return;
base= base_name(safe_source_file);
- m_row.m_source_length= my_snprintf(m_row.m_source, sizeof(m_row.m_source),
- "%s:%d", base, statement->m_source_line);
+ m_row.m_source_length= (uint)my_snprintf(m_row.m_source, sizeof(m_row.m_source),
+ "%s:%d", base, statement->m_source_line);
if (m_row.m_source_length > sizeof(m_row.m_source))
m_row.m_source_length= sizeof(m_row.m_source);
@@ -291,7 +301,7 @@ void table_events_statements_common::make_row_part_2(const sql_digest_storage *d
/*
Filling up statement digest information.
*/
- uint safe_byte_count= digest->m_byte_count;
+ size_t safe_byte_count= digest->m_byte_count;
if (safe_byte_count > 0 &&
safe_byte_count <= pfs_max_digest_length)
{
@@ -428,7 +438,7 @@ int table_events_statements_common::read_row_values(TABLE *table,
f->set_null();
break;
case 19: /* MESSAGE_TEXT */
- len= strlen(m_row.m_message_text);
+ len= (uint)strlen(m_row.m_message_text);
if (len)
set_field_varchar_utf8(f, m_row.m_message_text, len);
else
@@ -790,7 +800,7 @@ int table_events_statements_history_long::rnd_init(bool scan)
int table_events_statements_history_long::rnd_next(void)
{
PFS_events_statements *statement;
- uint limit;
+ size_t limit;
if (events_statements_history_long_size == 0)
return HA_ERR_END_OF_FILE;
@@ -819,7 +829,7 @@ int table_events_statements_history_long::rnd_next(void)
int table_events_statements_history_long::rnd_pos(const void *pos)
{
PFS_events_statements *statement;
- uint limit;
+ size_t limit;
if (events_statements_history_long_size == 0)
return HA_ERR_RECORD_DELETED;
diff --git a/storage/perfschema/table_events_waits.cc b/storage/perfschema/table_events_waits.cc
index 8e2d0064538..cd32d81519e 100644
--- a/storage/perfschema/table_events_waits.cc
+++ b/storage/perfschema/table_events_waits.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -318,6 +318,8 @@ void table_events_waits_common::make_row(bool thread_own_wait,
PFS_instr_class *safe_class;
const char *base;
const char *safe_source_file;
+ enum_timer_name timer_name= wait_timer;
+ ulonglong timer_end;
m_row_exists= false;
safe_thread= sanitize_thread(pfs_thread);
@@ -356,6 +358,7 @@ void table_events_waits_common::make_row(bool thread_own_wait,
case WAIT_CLASS_IDLE:
clear_object_columns();
safe_class= sanitize_idle_class(wait->m_class);
+ timer_name= idle_timer;
break;
case WAIT_CLASS_MUTEX:
clear_object_columns();
@@ -399,7 +402,17 @@ void table_events_waits_common::make_row(bool thread_own_wait,
m_row.m_nesting_event_type= wait->m_nesting_event_type;
get_normalizer(safe_class);
- m_normalizer->to_pico(wait->m_timer_start, wait->m_timer_end,
+
+ if (m_row.m_end_event_id == 0)
+ {
+ timer_end= get_timer_raw_value(timer_name);
+ }
+ else
+ {
+ timer_end= wait->m_timer_end;
+ }
+
+ m_normalizer->to_pico(wait->m_timer_start, timer_end,
& m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
m_row.m_name= safe_class->m_name;
diff --git a/storage/perfschema/table_helper.cc b/storage/perfschema/table_helper.cc
index c9def1bfc74..d064333dc7e 100644
--- a/storage/perfschema/table_helper.cc
+++ b/storage/perfschema/table_helper.cc
@@ -110,7 +110,7 @@ int PFS_digest_row::make_row(PFS_statements_digest_stat* pfs)
if (m_schema_name_length > 0)
memcpy(m_schema_name, pfs->m_digest_key.m_schema_name, m_schema_name_length);
- uint safe_byte_count= pfs->m_digest_storage.m_byte_count;
+ size_t safe_byte_count= pfs->m_digest_storage.m_byte_count;
if (safe_byte_count > pfs_max_digest_length)
safe_byte_count= 0;
diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt
index e8b11e807bf..4c6b0b91021 100644
--- a/storage/perfschema/unittest/CMakeLists.txt
+++ b/storage/perfschema/unittest/CMakeLists.txt
@@ -28,5 +28,5 @@ ADD_CONVENIENCE_LIBRARY(pfs_server_stubs pfs_server_stubs.cc)
ADD_DEPENDENCIES(pfs_server_stubs GenError)
MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom
- pfs_account-oom pfs_host-oom pfs_timer pfs_user-oom pfs
+ pfs_account-oom pfs_host-oom pfs_timer pfs_user-oom pfs pfs_misc
EXT "cc" LINK_LIBRARIES perfschema mysys pfs_server_stubs)
diff --git a/storage/perfschema/unittest/pfs_misc-t.cc b/storage/perfschema/unittest/pfs_misc-t.cc
new file mode 100644
index 00000000000..a4b11b9a727
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_misc-t.cc
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+
+ 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; version 2 of the License.
+
+ 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <pfs_instr.h>
+#include <pfs_stat.h>
+#include <pfs_global.h>
+#include <pfs_instr_class.h>
+#include <tap.h>
+
+#include <memory.h>
+
+void test_digest_length_overflow()
+{
+ if (sizeof(size_t) != 4)
+ {
+ skip(2, "digest length overflow requires a 32-bit environment");
+ return;
+ }
+
+ PFS_global_param param;
+ memset(&param, 0, sizeof(param));
+ param.m_enabled= true;
+ /*
+ Force 32-bit arithmetic overflow using the digest memory allocation
+ parameters. The Performance Schema should detect the overflow, free
+ allocated memory and abort initialization with a warning.
+ */
+
+ /* Max digest length, events_statements_history_long. */
+ param.m_events_statements_history_long_sizing= 10000;
+ param.m_digest_sizing= 1000;
+ param.m_max_digest_length= (1024 * 1024);
+ pfs_max_digest_length= param.m_max_digest_length;
+
+ int rc = init_events_statements_history_long(param.m_events_statements_history_long_sizing);
+ ok(rc == 1, "digest length overflow (init_events_statements_history_long");
+
+ /* Max digest length, events_statements_summary_by_digest. */
+ param.m_max_digest_length= (1024 * 1024);
+ param.m_digest_sizing= 10000;
+
+ rc = init_digest(&param);
+ ok(rc == 1, "digest length overflow (init_digest)");
+}
+
+void do_all_tests()
+{
+ test_digest_length_overflow();
+}
+
+int main(int, char **)
+{
+ plan(2);
+ MY_INIT("pfs_misc-t");
+ do_all_tests();
+ my_end(0);
+ return exit_status();
+}
+
diff --git a/storage/perfschema/unittest/pfs_server_stubs.cc b/storage/perfschema/unittest/pfs_server_stubs.cc
index a023414357a..7c0e275edc7 100644
--- a/storage/perfschema/unittest/pfs_server_stubs.cc
+++ b/storage/perfschema/unittest/pfs_server_stubs.cc
@@ -34,7 +34,11 @@ void compute_digest_md5(const sql_digest_storage *, unsigned char *)
}
class sys_var { public: enum where { AUTO }; };
-void mark_sys_var_value_origin(void *ptr, enum sys_var::where here)
+void set_sys_var_value_origin(void *ptr, enum sys_var::where here)
{
}
+enum sys_var::where get_sys_var_value_origin(void *ptr)
+{
+ return sys_var::AUTO;
+}
diff --git a/storage/perfschema/unittest/stub_pfs_global.h b/storage/perfschema/unittest/stub_pfs_global.h
index 34c52e18b5a..8f204006f48 100644
--- a/storage/perfschema/unittest/stub_pfs_global.h
+++ b/storage/perfschema/unittest/stub_pfs_global.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -25,6 +25,11 @@ int stub_alloc_fails_after_count= 0;
void *pfs_malloc(size_t size, myf)
{
+ /*
+ Catch non initialized sizing parameter in the unit tests.
+ */
+ DBUG_ASSERT(size <= 100*1024*1024);
+
if (stub_alloc_always_fails)
return NULL;
@@ -43,6 +48,23 @@ void pfs_free(void *ptr)
free(ptr);
}
+void *pfs_malloc_array(size_t n, size_t size, myf flags)
+{
+ size_t array_size= n * size;
+ /* Check for overflow before allocating. */
+ if (is_overflow(array_size, n, size))
+ return NULL;
+ return pfs_malloc(array_size, flags);
+}
+
+bool is_overflow(size_t product, size_t n1, size_t n2)
+{
+ if (n1 != 0 && (product / n1 != n2))
+ return true;
+ else
+ return false;
+}
+
void pfs_print_error(const char *format, ...)
{
}
diff --git a/storage/perfschema/unittest/stub_print_error.h b/storage/perfschema/unittest/stub_print_error.h
index caad24e5257..e9b8bc25548 100644
--- a/storage/perfschema/unittest/stub_print_error.h
+++ b/storage/perfschema/unittest/stub_print_error.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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
@@ -33,6 +33,23 @@ void pfs_free(void *ptr)
free(ptr);
}
+void *pfs_malloc_array(size_t n, size_t size, myf flags)
+{
+ size_t array_size= n * size;
+ /* Check for overflow before allocating. */
+ if (is_overflow(array_size, n, size))
+ return NULL;
+ return pfs_malloc(array_size, flags);
+}
+
+bool is_overflow(size_t product, size_t n1, size_t n2)
+{
+ if (n1 != 0 && (product / n1 != n2))
+ return true;
+ else
+ return false;
+}
+
void pfs_print_error(const char *format, ...)
{
/* Do not pollute the unit test output with annoying messages. */
diff --git a/storage/spider/CMakeLists.txt b/storage/spider/CMakeLists.txt
index 33786e2b85a..402c74b2cde 100644
--- a/storage/spider/CMakeLists.txt
+++ b/storage/spider/CMakeLists.txt
@@ -1,10 +1,7 @@
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_HANDLERSOCKET")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_HANDLERSOCKET")
-IF(HAVE_WVLA)
- SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-vla")
- SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wno-vla")
-ENDIF()
+MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-vla" DEBUG)
SET(SPIDER_SOURCES
spd_param.cc spd_sys_table.cc spd_trx.cc spd_db_conn.cc spd_conn.cc
diff --git a/storage/tokudb/CMakeLists.txt b/storage/tokudb/CMakeLists.txt
index a8a821e5ad6..7cbc8a119e4 100644
--- a/storage/tokudb/CMakeLists.txt
+++ b/storage/tokudb/CMakeLists.txt
@@ -17,12 +17,8 @@ IF(NOT LIBJEMALLOC)
MESSAGE(WARNING "TokuDB is enabled, but jemalloc is not. This configuration is not supported")
ENDIF()
-IF (HAVE_WVLA)
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-vla")
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-vla")
- SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wno-vla")
- SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-vla")
-ENDIF()
+MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-vla")
+MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-vla" DEBUG)
############################################
SET(TOKUDB_DEB_FILES "usr/lib/mysql/plugin/ha_tokudb.so\netc/mysql/conf.d/tokudb.cnf\nusr/bin/tokuftdump\nusr/share/doc/mariadb-server-10.1/README-TOKUDB\nusr/share/doc/mariadb-server-10.1/README.md" PARENT_SCOPE)
@@ -70,36 +66,7 @@ ENDIF()
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
-macro(set_cflags_if_supported)
- foreach(flag ${ARGN})
- string(REGEX REPLACE "-" "_" temp_flag ${flag})
- check_c_compiler_flag(${flag} HAVE_C_${temp_flag})
- if (HAVE_C_${temp_flag})
- set(CMAKE_C_FLAGS "${flag} ${CMAKE_C_FLAGS}")
- endif ()
- check_cxx_compiler_flag(${flag} HAVE_CXX_${temp_flag})
- if (HAVE_CXX_${temp_flag})
- set(CMAKE_CXX_FLAGS "${flag} ${CMAKE_CXX_FLAGS}")
- endif ()
- endforeach(flag)
-endmacro(set_cflags_if_supported)
-
-macro(append_cflags_if_supported)
- foreach(flag ${ARGN})
- string(REGEX REPLACE "-" "_" temp_flag ${flag})
- check_c_compiler_flag(${flag} HAVE_C_${temp_flag})
- if (HAVE_C_${temp_flag})
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
- endif ()
- check_cxx_compiler_flag(${flag} HAVE_CXX_${temp_flag})
- if (HAVE_CXX_${temp_flag})
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
- endif ()
- endforeach(flag)
-endmacro(append_cflags_if_supported)
-
-set_cflags_if_supported(-Wno-missing-field-initializers)
-append_cflags_if_supported(-Wno-vla)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-missing-field-initializers)
ADD_SUBDIRECTORY(ft-index)
diff --git a/storage/tokudb/ft-index/cmake_modules/TokuSetupCompiler.cmake b/storage/tokudb/ft-index/cmake_modules/TokuSetupCompiler.cmake
index 99629e40bdb..ee45e7cccf3 100644
--- a/storage/tokudb/ft-index/cmake_modules/TokuSetupCompiler.cmake
+++ b/storage/tokudb/ft-index/cmake_modules/TokuSetupCompiler.cmake
@@ -47,18 +47,6 @@ include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
## adds a compiler flag if the compiler supports it
-macro(set_cflags_if_supported_named flag flagname)
- check_c_compiler_flag("${flag}" HAVE_C_${flagname})
- if (HAVE_C_${flagname})
- set(CMAKE_C_FLAGS "${flag} ${CMAKE_C_FLAGS}")
- endif ()
- check_cxx_compiler_flag("${flag}" HAVE_CXX_${flagname})
- if (HAVE_CXX_${flagname})
- set(CMAKE_CXX_FLAGS "${flag} ${CMAKE_CXX_FLAGS}")
- endif ()
-endmacro(set_cflags_if_supported_named)
-
-## adds a compiler flag if the compiler supports it
macro(set_cflags_if_supported)
foreach(flag ${ARGN})
check_c_compiler_flag(${flag} HAVE_C_${flag})
@@ -84,21 +72,19 @@ macro(set_ldflags_if_supported)
endmacro(set_ldflags_if_supported)
## disable some warnings
-set_cflags_if_supported(
- -Wno-missing-field-initializers
- -Wstrict-null-sentinel
- -Winit-self
- -Wswitch
- -Wtrampolines
- -Wlogical-op
- -Wmissing-format-attribute
- -Wno-error=missing-format-attribute
- -Wno-error=address-of-array-temporary
- -Wno-error=tautological-constant-out-of-range-compare
- -Wno-ignored-attributes
- -fno-rtti
- -fno-exceptions
- )
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-missing-field-initializers)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wstrict-null-sentinel)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Winit-self)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wswitch)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wtrampolines)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wlogical-op)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wmissing-format-attribute)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-error=missing-format-attribute)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-error=address-of-array-temporary)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-error=tautological-constant-out-of-range-compare)
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-ignored-attributes)
+MY_CHECK_AND_SET_COMPILER_FLAG(-fno-rtti)
+MY_CHECK_AND_SET_COMPILER_FLAG(-fno-exceptions)
## set_cflags_if_supported_named("-Weffc++" -Weffcpp)
if (CMAKE_CXX_FLAGS MATCHES -fno-implicit-templates)
@@ -111,19 +97,12 @@ endif()
## Clang has stricter POD checks. So, only enable this warning on our other builds (Linux + GCC)
if (NOT CMAKE_CXX_COMPILER_ID MATCHES Clang)
- set_cflags_if_supported(
- -Wpacked
- )
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wpacked)
endif ()
## this hits with optimized builds somewhere in ftleaf_split, we don't
## know why but we don't think it's a big deal
-set_cflags_if_supported(
- -Wno-error=strict-overflow
- )
-set_ldflags_if_supported(
- -Wno-error=strict-overflow
- )
+MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-error=strict-overflow)
## set extra debugging flags and preprocessor definitions
set(CMAKE_C_FLAGS_DEBUG "-g3 -O0 ${CMAKE_C_FLAGS_DEBUG}")
@@ -154,16 +133,15 @@ else ()
endif ()
## set warnings
-set_cflags_if_supported(
- -Wextra
- -Wbad-function-cast
- -Wno-missing-noreturn
- -Wstrict-prototypes
- -Wmissing-prototypes
- -Wmissing-declarations
- -Wpointer-arith
- -Wmissing-format-attribute
- -Wshadow
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wextra)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wbad-function-cast)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wno-missing-noreturn)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wstrict-prototypes)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wmissing-prototypes)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wmissing-declarations)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wpointer-arith)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wmissing-format-attribute)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wshadow)
## other flags to try:
#-Wunsafe-loop-optimizations
#-Wpointer-arith
@@ -173,11 +151,10 @@ set_cflags_if_supported(
#-Wzero-as-null-pointer-constant
#-Wlogical-op
#-Wvector-optimization-performance
- )
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL Clang)
# Disabling -Wcast-align with clang. TODO: fix casting and re-enable it, someday.
- set_cflags_if_supported(-Wcast-align)
+ MY_CHECK_AND_SET_COMPILER_FLAG(-Wcast-align)
endif ()
## always want these
diff --git a/storage/tokudb/ha_tokudb.cc b/storage/tokudb/ha_tokudb.cc
index e0e4bab2072..97fadae8b8e 100644
--- a/storage/tokudb/ha_tokudb.cc
+++ b/storage/tokudb/ha_tokudb.cc
@@ -172,7 +172,7 @@ static inline uint32_t get_len_of_offsets(KEY_AND_COL_INFO* kc_info, TABLE_SHARE
}
-#ifndef NOT_USED
+#ifdef NOT_USED
static int get_thread_query_string(my_thread_id id, String &qs) {
mysql_mutex_lock(&LOCK_thread_count);
I_List_iterator<THD> it(threads);
diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt
index a6e2014e679..0ae3528e512 100644
--- a/storage/xtradb/CMakeLists.txt
+++ b/storage/xtradb/CMakeLists.txt
@@ -462,14 +462,6 @@ SET(INNOBASE_SOURCES
ut/ut0wqueue.cc
ut/ut0timer.cc)
-# These files have unused result errors, so we skip Werror
-CHECK_C_COMPILER_FLAG("-Werror" HAVE_WERROR)
-IF(HAVE_WERROR)
- INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/compile_flags.cmake)
- ADD_COMPILE_FLAGS(page/page0zip.c COMPILE_FLAGS "-Wno-error")
- ADD_COMPILE_FLAGS(ut/ut0ut.c COMPILE_FLAGS "-Wno-error")
-ENDIF()
-
IF(XTRADB_OK)
MYSQL_ADD_PLUGIN(xtradb ${INNOBASE_SOURCES} STORAGE_ENGINE
DEFAULT RECOMPILE_FOR_EMBEDDED
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc
index 8769fc47166..0fe21423232 100644
--- a/storage/xtradb/api/api0api.cc
+++ b/storage/xtradb/api/api0api.cc
@@ -595,6 +595,21 @@ ib_trx_begin(
return(static_cast<ib_trx_t>(trx));
}
+
+/*****************************************************************//**
+Check if transaction is read_only
+@return transaction read_only status */
+UNIV_INTERN
+ib_u32_t
+ib_trx_read_only(
+/*=============*/
+ ib_trx_t ib_trx) /*!< in: trx handle */
+{
+ trx_t* trx = (trx_t*) ib_trx;
+
+ return(trx->read_only);
+}
+
/*****************************************************************//**
Get the transaction's state.
@return transaction state */
diff --git a/storage/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc
index 2f248c98651..86e70109db5 100644
--- a/storage/xtradb/btr/btr0btr.cc
+++ b/storage/xtradb/btr/btr0btr.cc
@@ -2,6 +2,7 @@
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2014, 2015, MariaDB Corporation
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
@@ -741,6 +742,19 @@ btr_root_block_get(
block = btr_block_get(space, zip_size, root_page_no, mode, index, mtr);
+ if (!block) {
+ index->table->is_encrypted = TRUE;
+ index->table->corrupted = FALSE;
+
+ ib_push_warning(index->table->thd, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s in tablespace %lu is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name, space);
+
+ return NULL;
+ }
+
SRV_CORRUPT_TABLE_CHECK(block, return(0););
btr_assert_not_corrupted(block, index);
@@ -779,8 +793,10 @@ btr_root_get(
const dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in: mtr */
{
- return(buf_block_get_frame(btr_root_block_get(index, RW_X_LATCH,
- mtr)));
+ buf_block_t* root = btr_root_block_get(index, RW_X_LATCH,
+ mtr);
+
+ return(root ? buf_block_get_frame(root) : NULL);
}
/**************************************************************//**
@@ -795,7 +811,7 @@ btr_height_get(
dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- ulint height;
+ ulint height=0;
buf_block_t* root_block;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -806,13 +822,16 @@ btr_height_get(
/* S latches the page */
root_block = btr_root_block_get(index, RW_S_LATCH, mtr);
- height = btr_page_get_level(buf_block_get_frame_fast(root_block), mtr);
+ if (root_block) {
+
+ height = btr_page_get_level(buf_block_get_frame_fast(root_block), mtr);
- /* Release the S latch on the root page. */
- mtr_memo_release(mtr, root_block, MTR_MEMO_PAGE_S_FIX);
+ /* Release the S latch on the root page. */
+ mtr_memo_release(mtr, root_block, MTR_MEMO_PAGE_S_FIX);
#ifdef UNIV_SYNC_DEBUG
- sync_thread_reset_level(&root_block->lock);
+ sync_thread_reset_level(&root_block->lock);
#endif /* UNIV_SYNC_DEBUG */
+ }
return(height);
}
@@ -1260,7 +1279,7 @@ btr_get_size_and_reserved(
{
fseg_header_t* seg_header;
page_t* root;
- ulint n;
+ ulint n=ULINT_UNDEFINED;
ulint dummy;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -1274,17 +1293,21 @@ btr_get_size_and_reserved(
}
root = btr_root_get(index, mtr);
+ *used = 0;
+
+ if (root) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
- n = fseg_n_reserved_pages(seg_header, used, mtr);
+ n = fseg_n_reserved_pages(seg_header, used, mtr);
- if (flag == BTR_TOTAL_SIZE) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+ if (flag == BTR_TOTAL_SIZE) {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
- n += fseg_n_reserved_pages(seg_header, &dummy, mtr);
- *used += dummy;
+ n += fseg_n_reserved_pages(seg_header, &dummy, mtr);
+ *used += dummy;
+ }
}
return(n);
diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index 4e5e6a713ed..316271077ae 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -3,6 +3,7 @@
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -386,7 +387,7 @@ search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record. */
UNIV_INTERN
-void
+dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -436,6 +437,7 @@ btr_cur_search_to_nth_level(
page_cur_t* page_cursor;
btr_op_t btr_op;
ulint root_height = 0; /* remove warning */
+ dberr_t err = DB_SUCCESS;
#ifdef BTR_CUR_ADAPT
btr_search_t* info;
@@ -553,7 +555,7 @@ btr_cur_search_to_nth_level(
|| mode != PAGE_CUR_LE);
btr_cur_n_sea++;
- return;
+ return err;
}
# endif /* BTR_CUR_HASH_ADAPT */
#endif /* BTR_CUR_ADAPT */
@@ -649,7 +651,21 @@ search_loop:
retry_page_get:
block = buf_page_get_gen(
space, zip_size, page_no, rw_latch, guess, buf_mode,
- file, line, mtr);
+ file, line, mtr, &err);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+
+ goto func_exit;
+ }
if (block == NULL) {
SRV_CORRUPT_TABLE_CHECK(buf_mode == BUF_GET_IF_IN_POOL ||
@@ -889,12 +905,14 @@ func_exit:
rw_lock_s_lock(btr_search_get_latch(cursor->index));
}
+
+ return err;
}
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
-void
+dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,
@@ -920,6 +938,8 @@ btr_cur_open_at_index_side_func(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
+ dberr_t err = DB_SUCCESS;
+
rec_offs_init(offsets_);
estimate = latch_mode & BTR_ESTIMATE;
@@ -957,11 +977,26 @@ btr_cur_open_at_index_side_func(
height = ULINT_UNDEFINED;
for (;;) {
- buf_block_t* block;
- page_t* page;
+ buf_block_t* block=NULL;
+ page_t* page=NULL;
+
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
- file, line, mtr);
+ file, line, mtr, &err);
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+
+ goto exit_loop;
+ }
+
page = buf_block_get_frame(block);
SRV_CORRUPT_TABLE_CHECK(page,
@@ -1066,6 +1101,8 @@ exit_loop:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
+
+ return err;
}
/**********************************************************************//**
@@ -1113,10 +1150,25 @@ btr_cur_open_at_rnd_pos_func(
for (;;) {
buf_block_t* block;
page_t* page;
+ dberr_t err=DB_SUCCESS;
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
- file, line, mtr);
+ file, line, mtr, &err);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+ goto exit_loop;
+ }
+
page = buf_block_get_frame(block);
SRV_CORRUPT_TABLE_CHECK(page,
@@ -3749,6 +3801,7 @@ btr_estimate_n_rows_in_range_on_level(
mtr_t mtr;
page_t* page;
buf_block_t* block;
+ dberr_t err=DB_SUCCESS;
mtr_start(&mtr);
@@ -3759,7 +3812,23 @@ btr_estimate_n_rows_in_range_on_level(
silence a debug assertion about this. */
block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH,
NULL, BUF_GET_POSSIBLY_FREED,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, &err);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning((void *)NULL,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+
+ mtr_commit(&mtr);
+ goto inexact;
+ }
+
page = buf_block_get_frame(block);
diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index 361b0783482..31157aa737f 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved.
@@ -59,11 +59,24 @@ Created 11/5/1995 Heikki Tuuri
#include "srv0start.h"
#include "ut0byte.h"
#include "fil0pagecompress.h"
+#include "ha_prototypes.h"
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
+/********************************************************************//**
+Check if page is maybe compressed, encrypted or both when we encounter
+corrupted page. Note that we can't be 100% sure if page is corrupted
+or decrypt/decompress just failed.
+*/
+static
+ibool
+buf_page_check_corrupt(
+/*===================*/
+ buf_page_t* bpage); /*!< in/out: buffer page read from
+ disk */
+
static inline
void
_increment_page_get_statistics(buf_block_t* block, trx_t* trx)
@@ -564,6 +577,79 @@ buf_page_is_zeroes(
return(true);
}
+/** Checks if the page is in crc32 checksum format.
+@param[in] read_buf database page
+@param[in] checksum_field1 new checksum field
+@param[in] checksum_field2 old checksum field
+@return true if the page is in crc32 checksum format */
+UNIV_INLINE
+bool
+buf_page_is_checksum_valid_crc32(
+ const byte* read_buf,
+ ulint checksum_field1,
+ ulint checksum_field2)
+{
+ ib_uint32_t crc32 = buf_calc_page_crc32(read_buf);
+
+ return(checksum_field1 == crc32 && checksum_field2 == crc32);
+}
+
+/** Checks if the page is in innodb checksum format.
+@param[in] read_buf database page
+@param[in] checksum_field1 new checksum field
+@param[in] checksum_field2 old checksum field
+@return true if the page is in innodb checksum format */
+UNIV_INLINE
+bool
+buf_page_is_checksum_valid_innodb(
+ const byte* read_buf,
+ ulint checksum_field1,
+ ulint checksum_field2)
+{
+ /* There are 2 valid formulas for
+ checksum_field2 (old checksum field) which algo=innodb could have
+ written to the page:
+
+ 1. Very old versions of InnoDB only stored 8 byte lsn to the
+ start and the end of the page.
+
+ 2. Newer InnoDB versions store the old formula checksum
+ (buf_calc_page_old_checksum()). */
+
+ if (checksum_field2 != mach_read_from_4(read_buf + FIL_PAGE_LSN)
+ && checksum_field2 != buf_calc_page_old_checksum(read_buf)) {
+ return(false);
+ }
+
+ /* old field is fine, check the new field */
+
+ /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
+ (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */
+
+ if (checksum_field1 != 0
+ && checksum_field1 != buf_calc_page_new_checksum(read_buf)) {
+ return(false);
+ }
+
+ return(true);
+}
+
+/** Checks if the page is in none checksum format.
+@param[in] read_buf database page
+@param[in] checksum_field1 new checksum field
+@param[in] checksum_field2 old checksum field
+@return true if the page is in none checksum format */
+UNIV_INLINE
+bool
+buf_page_is_checksum_valid_none(
+ const byte* read_buf,
+ ulint checksum_field1,
+ ulint checksum_field2)
+{
+ return(checksum_field1 == checksum_field2
+ && checksum_field1 == BUF_NO_CHECKSUM_MAGIC);
+}
+
/********************************************************************//**
Checks if a page is corrupt.
@return TRUE if corrupted */
@@ -580,8 +666,6 @@ buf_page_is_corrupted(
ulint page_encrypted = fil_page_is_encrypted(read_buf);
ulint checksum_field1;
ulint checksum_field2;
- ibool crc32_inited = FALSE;
- ib_uint32_t crc32 = ULINT32_UNDEFINED;
if (!page_encrypted && !zip_size
&& memcmp(read_buf + FIL_PAGE_LSN + 4,
@@ -664,148 +748,121 @@ buf_page_is_corrupted(
return(FALSE);
}
- switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) {
- case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
-
- crc32 = buf_calc_page_crc32(read_buf);
-
- return(checksum_field1 != crc32 || checksum_field2 != crc32);
-
- case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
-
- return(checksum_field1
- != buf_calc_page_new_checksum(read_buf)
- || checksum_field2
- != buf_calc_page_old_checksum(read_buf));
-
- case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+ DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(TRUE); );
- return(checksum_field1 != BUF_NO_CHECKSUM_MAGIC
- || checksum_field2 != BUF_NO_CHECKSUM_MAGIC);
+ ulint page_no = mach_read_from_4(read_buf + FIL_PAGE_OFFSET);
+ ulint space_id = mach_read_from_4(read_buf + FIL_PAGE_SPACE_ID);
+ const srv_checksum_algorithm_t curr_algo =
+ static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
+ switch (curr_algo) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
- case SRV_CHECKSUM_ALGORITHM_INNODB:
- /* There are 3 valid formulas for
- checksum_field2 (old checksum field):
-
- 1. Very old versions of InnoDB only stored 8 byte lsn to the
- start and the end of the page.
-
- 2. InnoDB versions before MySQL 5.6.3 store the old formula
- checksum (buf_calc_page_old_checksum()).
-
- 3. InnoDB versions 5.6.3 and newer with
- innodb_checksum_algorithm=strict_crc32|crc32 store CRC32. */
-
- /* since innodb_checksum_algorithm is not strict_* allow
- any of the algos to match for the old field */
-
- if (checksum_field2
- != mach_read_from_4(read_buf + FIL_PAGE_LSN)
- && checksum_field2 != BUF_NO_CHECKSUM_MAGIC) {
-
- /* The checksum does not match any of the
- fast to check. First check the selected algorithm
- for writing checksums because we assume that the
- chance of it matching is higher. */
-
- if (srv_checksum_algorithm
- == SRV_CHECKSUM_ALGORITHM_CRC32) {
-
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = TRUE;
-
- if (checksum_field2 != crc32
- && checksum_field2
- != buf_calc_page_old_checksum(read_buf)) {
+ case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
- return(TRUE);
- }
- } else {
- ut_ad(srv_checksum_algorithm
- == SRV_CHECKSUM_ALGORITHM_INNODB);
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2)) {
+ return(FALSE);
+ }
- if (checksum_field2
- != buf_calc_page_old_checksum(read_buf)) {
+ if (buf_page_is_checksum_valid_none(read_buf,
+ checksum_field1, checksum_field2)) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_NONE,
+ space_id, page_no);
+ }
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = TRUE;
+ return(FALSE);
+ }
- if (checksum_field2 != crc32) {
- return(TRUE);
- }
- }
+ if (buf_page_is_checksum_valid_innodb(read_buf,
+ checksum_field1, checksum_field2)) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_INNODB,
+ space_id, page_no);
}
- }
- /* old field is fine, check the new field */
+ return(FALSE);
+ }
- /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
- (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */
+ return(TRUE);
- if (checksum_field1 != 0
- && checksum_field1 != BUF_NO_CHECKSUM_MAGIC) {
+ case SRV_CHECKSUM_ALGORITHM_INNODB:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
- /* The checksum does not match any of the
- fast to check. First check the selected algorithm
- for writing checksums because we assume that the
- chance of it matching is higher. */
+ if (buf_page_is_checksum_valid_innodb(read_buf,
+ checksum_field1, checksum_field2)) {
+ return(FALSE);
+ }
- if (srv_checksum_algorithm
- == SRV_CHECKSUM_ALGORITHM_CRC32) {
+ if (buf_page_is_checksum_valid_none(read_buf,
+ checksum_field1, checksum_field2)) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_NONE,
+ space_id, page_no);
+ }
- if (!crc32_inited) {
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = TRUE;
- }
+ return(FALSE);
+ }
- if (checksum_field1 != crc32
- && checksum_field1
- != buf_calc_page_new_checksum(read_buf)) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2)) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_CRC32,
+ space_id, page_no);
+ }
- return(TRUE);
- }
- } else {
- ut_ad(srv_checksum_algorithm
- == SRV_CHECKSUM_ALGORITHM_INNODB);
+ return(FALSE);
+ }
- if (checksum_field1
- != buf_calc_page_new_checksum(read_buf)) {
+ return(TRUE);
- if (!crc32_inited) {
- crc32 = buf_calc_page_crc32(
- read_buf);
- crc32_inited = TRUE;
- }
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
- if (checksum_field1 != crc32) {
- return(TRUE);
- }
- }
- }
+ if (buf_page_is_checksum_valid_none(read_buf,
+ checksum_field1, checksum_field2)) {
+ return(FALSE);
}
- /* If CRC32 is stored in at least one of the fields, then the
- other field must also be CRC32 */
- if (crc32_inited
- && ((checksum_field1 == crc32
- && checksum_field2 != crc32)
- || (checksum_field1 != crc32
- && checksum_field2 == crc32))) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2)) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_CRC32,
+ space_id, page_no);
+ return(FALSE);
+ }
- return(TRUE);
+ if (buf_page_is_checksum_valid_innodb(read_buf,
+ checksum_field1, checksum_field2)) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_INNODB,
+ space_id, page_no);
+ return(FALSE);
}
- break;
+ return(TRUE);
+
case SRV_CHECKSUM_ALGORITHM_NONE:
/* should have returned FALSE earlier */
- ut_error;
+ break;
/* no default so the compiler will emit a warning if new enum
is added and not handled here */
}
- DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(TRUE); );
-
+ ut_error;
return(FALSE);
}
@@ -1084,6 +1141,9 @@ buf_block_init(
block->page.key_version = 0;
block->page.page_encrypted = false;
block->page.page_compressed = false;
+ block->page.encrypted = false;
+ block->page.stored_checksum = BUF_NO_CHECKSUM_MAGIC;
+ block->page.calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
@@ -1817,6 +1877,9 @@ page_found:
goto page_found;
}
+ /* The maximum number of purge threads should never exceed
+ BUF_POOL_WATCH_SIZE. So there is no way for purge thread
+ instance to hold a watch when setting another watch. */
for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) {
bpage = &buf_pool->watch[i];
@@ -2187,7 +2250,7 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(space, zip_size, offset, trx);
+ buf_read_page(space, zip_size, offset, trx, NULL);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2706,7 +2769,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mini-transaction */
+ mtr_t* mtr, /*!< in: mini-transaction */
+ dberr_t* err) /*!< out: error code */
{
buf_block_t* block;
ulint fold;
@@ -2724,6 +2788,11 @@ buf_page_get_gen(
ut_ad((rw_latch == RW_S_LATCH)
|| (rw_latch == RW_X_LATCH)
|| (rw_latch == RW_NO_LATCH));
+
+ if (err) {
+ *err = DB_SUCCESS;
+ }
+
#ifdef UNIV_DEBUG
switch (mode) {
case BUF_GET_NO_LATCH:
@@ -2787,6 +2856,8 @@ loop:
}
if (block == NULL) {
+ buf_page_t* bpage=NULL;
+
/* Page not in buf_pool: needs to be read from file */
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
@@ -2821,36 +2892,77 @@ loop:
return(NULL);
}
- if (buf_read_page(space, zip_size, offset, trx)) {
+ if (buf_read_page(space, zip_size, offset, trx, &bpage)) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr), trx);
retries = 0;
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
+
+ bool corrupted = true;
+
+ if (bpage) {
+ corrupted = buf_page_check_corrupt(bpage);
+ }
+
+ /* Do not try again for encrypted pages */
+ if (!corrupted) {
+ ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
+ mutex_enter(&buf_pool->LRU_list_mutex);
+ mutex_enter(pmutex);
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ buf_LRU_free_page(bpage, zip_size ? true : false);
+ mutex_exit(pmutex);
+
+ if (err) {
+ *err = DB_ENCRYPTED_DECRYPT_FAILED;
+ }
+ return (NULL);
+ }
+
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
+ bool corrupted = true;
- fprintf(stderr, "InnoDB: Error: Unable"
- " to read tablespace %lu page no"
- " %lu into the buffer pool after"
- " %lu attempts\n"
- "InnoDB: The most probable cause"
- " of this error may be that the"
- " table has been corrupted.\n"
- "InnoDB: You can try to fix this"
- " problem by using"
- " innodb_force_recovery.\n"
- "InnoDB: Please see reference manual"
- " for more details.\n"
- "InnoDB: Aborting...\n",
- space, offset,
- BUF_PAGE_READ_MAX_RETRIES);
+ if (bpage) {
+ corrupted = buf_page_check_corrupt(bpage);
+ }
- ut_error;
+ if (corrupted) {
+ fprintf(stderr, "InnoDB: Error: Unable"
+ " to read tablespace %lu page no"
+ " %lu into the buffer pool after"
+ " %lu attempts\n"
+ "InnoDB: The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted.\n"
+ "InnoDB: You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery.\n"
+ "InnoDB: Please see reference manual"
+ " for more details.\n"
+ "InnoDB: Aborting...\n",
+ space, offset,
+ BUF_PAGE_READ_MAX_RETRIES);
+
+ ut_error;
+ } else {
+ ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
+ mutex_enter(&buf_pool->LRU_list_mutex);
+ mutex_enter(pmutex);
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ buf_LRU_free_page(bpage, zip_size ? true : false);
+ mutex_exit(pmutex);
+
+ if (err) {
+ *err = DB_ENCRYPTED_DECRYPT_FAILED;
+ }
+ return (NULL);
+ }
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -3623,8 +3735,11 @@ buf_page_init_low(
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->key_version = 0;
+ bpage->stored_checksum = BUF_NO_CHECKSUM_MAGIC;
+ bpage->calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
bpage->page_encrypted = false;
bpage->page_compressed = false;
+ bpage->encrypted = false;
bpage->real_size = 0;
HASH_INVALIDATE(bpage, hash);
@@ -4294,33 +4409,41 @@ buf_mark_space_corrupt(
/* First unfix and release lock on the bpage */
ut_ad(!mutex_own(&buf_pool->LRU_list_mutex));
- mutex_enter(&buf_pool->LRU_list_mutex);
- rw_lock_x_lock(hash_lock);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ if (!bpage->encrypted) {
+ mutex_enter(&buf_pool->LRU_list_mutex);
+ rw_lock_x_lock(hash_lock);
+ mutex_enter(buf_page_get_mutex(bpage));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
+
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
+ }
}
/* Find the table with specified space id, and mark it corrupted */
if (dict_set_corrupted_by_space(space)) {
- buf_LRU_free_one_page(bpage);
+ if (!bpage->encrypted) {
+ buf_LRU_free_one_page(bpage);
+ }
} else {
- mutex_exit(buf_page_get_mutex(bpage));
+ if (!bpage->encrypted) {
+ mutex_exit(buf_page_get_mutex(bpage));
+ }
ret = FALSE;
}
- mutex_exit(&buf_pool->LRU_list_mutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
+ if(!bpage->encrypted) {
+ mutex_exit(&buf_pool->LRU_list_mutex);
+ ut_ad(buf_pool->n_pend_reads > 0);
+ os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
+ }
return(ret);
}
@@ -4331,42 +4454,77 @@ corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
*/
static
-void
+ibool
buf_page_check_corrupt(
/*===================*/
- const buf_page_t* bpage) /*!< in/out: buffer page read from disk */
+ buf_page_t* bpage) /*!< in/out: buffer page read from disk */
{
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
unsigned key_version = bpage->key_version;
bool page_compressed = bpage->page_encrypted;
+ ulint stored_checksum = bpage->stored_checksum;
+ ulint calculated_checksum = bpage->stored_checksum;
bool page_compressed_encrypted = bpage->page_compressed;
ulint space_id = mach_read_from_4(
dst_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
fil_space_t* space = fil_space_found_by_id(space_id);
+ bool corrupted = true;
+
+ if (key_version != 0 || page_compressed_encrypted) {
+ bpage->encrypted = true;
+ }
if (key_version != 0 ||
(crypt_data && crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) ||
page_compressed || page_compressed_encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Maybe corruption: Block space_id %lu in file %s maybe corrupted.",
- space_id, space ? space->name : "NULL");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Page based on contents %s encrypted.",
- (key_version == 0 && page_compressed_encrypted == false) ? "not" : "maybe");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Reason could be that key_version %u in page "
- "or in crypt_data %p could not be found.",
- key_version, crypt_data);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Reason could be also that key management plugin is not found or"
- "used encryption algorithm or method does not match.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Based on page page compressed %d, compressed and encrypted %d.",
- page_compressed, page_compressed_encrypted);
+
+ /* Page is really corrupted if post encryption stored
+ checksum does not match calculated checksum after page was
+ read. For pages compressed and then encrypted, there is no
+ checksum. */
+ corrupted = (!page_compressed_encrypted && stored_checksum != calculated_checksum);
+
+ if (corrupted) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "%s: Block in space_id %lu in file %s corrupted.",
+ page_compressed_encrypted ? "Maybe corruption" : "Corruption",
+ space_id, space ? space->name : "NULL");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page based on contents %s encrypted.",
+ (key_version == 0 && page_compressed_encrypted == false) ? "not" : "maybe");
+ if (stored_checksum != BUF_NO_CHECKSUM_MAGIC || calculated_checksum != BUF_NO_CHECKSUM_MAGIC) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page stored checksum %lu but calculated checksum %lu.",
+ stored_checksum, calculated_checksum);
+ }
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reason could be that key_version %u in page "
+ "or in crypt_data %p could not be found.",
+ key_version, crypt_data);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reason could be also that key management plugin is not found or"
+ " used encryption algorithm or method does not match.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Based on page page compressed %d, compressed and encrypted %d.",
+ page_compressed, page_compressed_encrypted);
+ } else {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Block in space_id %lu in file %s encrypted.",
+ space_id, space ? space->name : "NULL");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "However key management plugin or used key_id %u is not found or"
+ " used encryption algorithm or method does not match.",
+ key_version);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Marking tablespace as missing. You may drop this table or"
+ " install correct key management plugin and key file.");
+ }
}
+
+ return corrupted;
}
/********************************************************************//**
@@ -4487,42 +4645,46 @@ buf_page_io_complete(
;);
corrupt:
- fil_system_enter();
- space = fil_space_get_by_id(bpage->space);
- fil_system_exit();
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Database page corruption on disk"
- " or a failed");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Space %lu file %s read of page %lu.",
- (ulint)bpage->space,
- space ? space->name : "NULL",
- (ulong) bpage->offset);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "You may have to recover"
- " from a backup.");
-
- buf_page_check_corrupt(bpage);
-
- buf_page_print(frame, buf_page_get_zip_size(bpage),
- BUF_PAGE_PRINT_NO_CRASH);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "It is also possible that your operating"
- "system has corrupted its own file cache.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "and rebooting your computer removes the error.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "If the corrupt page is an index page you can also try to");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "fix the corruption by dumping, dropping, and reimporting");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "the corrupt table. You can use CHECK");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "TABLE to scan your table for corruption.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "See also "
- REFMAN "forcing-innodb-recovery.html"
- " about forcing recovery.");
+ bool corrupted = buf_page_check_corrupt(bpage);
+
+ if (corrupted) {
+ fil_system_enter();
+ space = fil_space_get_by_id(bpage->space);
+ fil_system_exit();
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Database page corruption on disk"
+ " or a failed");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Space %lu file %s read of page %lu.",
+ (ulint)bpage->space,
+ space ? space->name : "NULL",
+ (ulong) bpage->offset);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "You may have to recover"
+ " from a backup.");
+
+
+ buf_page_print(frame, buf_page_get_zip_size(bpage),
+ BUF_PAGE_PRINT_NO_CRASH);
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "It is also possible that your operating"
+ "system has corrupted its own file cache.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "and rebooting your computer removes the error.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "If the corrupt page is an index page you can also try to");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "fix the corruption by dumping, dropping, and reimporting");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "the corrupt table. You can use CHECK");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "TABLE to scan your table for corruption.");
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "See also "
+ REFMAN "forcing-innodb-recovery.html"
+ " about forcing recovery.");
+ }
if (srv_pass_corrupt_table && bpage->space != 0
&& bpage->space < SRV_LOG_SPACE_FIRST_ID) {
@@ -4550,12 +4712,30 @@ corrupt:
&& buf_mark_space_corrupt(bpage)) {
return(false);
} else {
- buf_page_check_corrupt(bpage);
+ corrupted = buf_page_check_corrupt(bpage);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Ending processing because of a corrupt database page.");
+ if (corrupted) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Ending processing because of a corrupt database page.");
- ut_error;
+ ut_error;
+ }
+
+ ib_push_warning(innobase_get_trx(), DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table in tablespace %lu encrypted."
+ "However key management plugin or used key_id %lu is not found or"
+ " used encryption algorithm or method does not match."
+ " Can't continue opening the table.",
+ bpage->key_version);
+
+ if (bpage->space > TRX_SYS_SPACE) {
+ if (corrupted) {
+ buf_mark_space_corrupt(bpage);
+ }
+ } else {
+ ut_error;
+ }
+ return(false);
}
}
}
@@ -4733,11 +4913,13 @@ buf_all_freed_instance(
mutex_exit(&buf_pool->LRU_list_mutex);
if (UNIV_LIKELY_NULL(block)) {
- fprintf(stderr,
- "Page %lu %lu still fixed or dirty\n",
- (ulong) block->page.space,
- (ulong) block->page.offset);
- ut_error;
+ if (block->page.key_version == 0) {
+ fprintf(stderr,
+ "Page %lu %lu still fixed or dirty\n",
+ (ulong) block->page.space,
+ (ulong) block->page.offset);
+ ut_error;
+ }
}
}
@@ -6077,6 +6259,11 @@ buf_page_decrypt_after_read(
bool page_compressed_encrypted = fil_page_is_compressed_encrypted(dst_frame);
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
+ /* If page is encrypted read post-encryption checksum */
+ if (!page_compressed_encrypted && key_version != 0) {
+ bpage->stored_checksum = mach_read_from_4(dst_frame + + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4);
+ }
+
ut_ad(bpage->key_version == 0);
if (bpage->offset == 0) {
@@ -6121,6 +6308,13 @@ buf_page_decrypt_after_read(
#ifdef UNIV_DEBUG
fil_page_type_validate(dst_frame);
#endif
+
+ /* Calculate checksum before decrypt, this will be
+ used later to find out if incorrect key was used. */
+ if (!page_compressed_encrypted) {
+ bpage->calculated_checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
+ }
+
/* decrypt using crypt_buf to dst_frame */
fil_space_decrypt(bpage->space,
slot->crypt_buf,
diff --git a/storage/xtradb/buf/buf0checksum.cc b/storage/xtradb/buf/buf0checksum.cc
index 451fef2f82e..01b646a78e0 100644
--- a/storage/xtradb/buf/buf0checksum.cc
+++ b/storage/xtradb/buf/buf0checksum.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -27,11 +27,13 @@ Created Aug 11, 2011 Vasil Dimov
#include "fil0fil.h" /* FIL_* */
#include "ut0crc32.h" /* ut_crc32() */
#include "ut0rnd.h" /* ut_fold_binary() */
+#include "buf0types.h"
#ifndef UNIV_INNOCHECKSUM
#include "srv0srv.h" /* SRV_CHECKSUM_* */
-#include "buf0types.h"
+
+#endif /* !UNIV_INNOCHECKSUM */
/** the macro MYSQL_SYSVAR_ENUM() requires "long unsigned int" and if we
use srv_checksum_algorithm_t here then we get a compiler error:
@@ -39,8 +41,6 @@ ha_innodb.cc:12251: error: cannot convert 'srv_checksum_algorithm_t*' to
'long unsigned int*' in initialization */
UNIV_INTERN ulong srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_INNODB;
-#endif /* !UNIV_INNOCHECKSUM */
-
/********************************************************************//**
Calculates a page CRC32 which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
@@ -127,8 +127,6 @@ buf_calc_page_old_checksum(
return(checksum);
}
-#ifndef UNIV_INNOCHECKSUM
-
/********************************************************************//**
Return a printable string describing the checksum algorithm.
@return algorithm name */
@@ -140,18 +138,19 @@ buf_checksum_algorithm_name(
{
switch (algo) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
- case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
return("crc32");
+ case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+ return("strict_crc32");
case SRV_CHECKSUM_ALGORITHM_INNODB:
- case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
return("innodb");
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+ return("strict_innodb");
case SRV_CHECKSUM_ALGORITHM_NONE:
- case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
return("none");
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+ return("strict_none");
}
ut_error;
return(NULL);
}
-
-#endif /* !UNIV_INNOCHECKSUM */
diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc
index 6443043310b..c891e53381a 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -1,8 +1,8 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
-Copyright (c) 2013, 2014, Fusion-io. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates
+Copyright (c) 2013, 2015, SkySQL Ab
+Copyright (c) 2013, 2014, Fusion-io
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
@@ -932,11 +932,11 @@ buf_flush_write_block_low(
case BUF_BLOCK_ZIP_DIRTY:
frame = bpage->zip.data;
- ut_a(page_zip_verify_checksum(frame, zip_size));
-
mach_write_to_8(frame + FIL_PAGE_LSN,
bpage->newest_modification);
memset(frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
+
+ ut_a(page_zip_verify_checksum(frame, zip_size));
break;
case BUF_BLOCK_FILE_PAGE:
frame = bpage->zip.data;
diff --git a/storage/xtradb/buf/buf0rea.cc b/storage/xtradb/buf/buf0rea.cc
index 6c74c30739e..15465699726 100644
--- a/storage/xtradb/buf/buf0rea.cc
+++ b/storage/xtradb/buf/buf0rea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
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
@@ -124,7 +124,8 @@ buf_read_page_low(
use to stop dangling page reads from a tablespace
which we have DISCARDed + IMPORTed back */
ulint offset, /*!< in: page number */
- trx_t* trx)
+ trx_t* trx, /*!< in: trx */
+ buf_page_t** rbpage) /*!< out: page */
{
buf_page_t* bpage;
ulint wake_later;
@@ -259,10 +260,17 @@ not_to_recover:
/* The i/o is already completed when we arrive from
fil_read */
if (!buf_page_io_complete(bpage)) {
+ if (rbpage) {
+ *rbpage = bpage;
+ }
return(0);
}
}
+ if (rbpage) {
+ *rbpage = bpage;
+ }
+
return(1);
}
@@ -398,7 +406,7 @@ read_ahead:
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
- tablespace_version, i, trx);
+ tablespace_version, i, trx, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -446,10 +454,11 @@ UNIV_INTERN
ibool
buf_read_page(
/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- trx_t* trx)
+ ulint space, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
+ ulint offset, /*!< in: page number */
+ trx_t* trx, /*!< in: trx */
+ buf_page_t** bpage) /*!< out: page */
{
ib_int64_t tablespace_version;
ulint count;
@@ -462,7 +471,7 @@ buf_read_page(
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, FALSE,
- tablespace_version, offset, trx);
+ tablespace_version, offset, trx, bpage);
srv_stats.buf_pool_reads.add(count);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
@@ -510,7 +519,7 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
- tablespace_version, offset, NULL);
+ tablespace_version, offset, NULL,NULL);
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -778,7 +787,7 @@ buf_read_ahead_linear(
count += buf_read_page_low(
&err, false,
ibuf_mode,
- space, zip_size, FALSE, tablespace_version, i, trx);
+ space, zip_size, FALSE, tablespace_version, i, trx, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -868,7 +877,7 @@ buf_read_ibuf_merge_pages(
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
- page_nos[i], NULL);
+ page_nos[i], NULL, NULL);
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
@@ -1008,12 +1017,12 @@ not_to_recover:
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
- page_nos[i], NULL);
+ page_nos[i], NULL, NULL);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
- tablespace_version, page_nos[i], NULL);
+ tablespace_version, page_nos[i], NULL, NULL);
}
}
diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc
index 36a30cb75b7..fec4e27f058 100644
--- a/storage/xtradb/dict/dict0crea.cc
+++ b/storage/xtradb/dict/dict0crea.cc
@@ -1566,12 +1566,111 @@ dict_create_add_foreign_field_to_dictionary(
}
/********************************************************************//**
+Construct foreign key constraint defintion from data dictionary information.
+*/
+UNIV_INTERN
+char*
+dict_foreign_def_get(
+/*=================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx) /*!< in: trx */
+{
+ char* fk_def = (char *)mem_heap_alloc(foreign->heap, 4*1024);
+ const char* tbname;
+ char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
+ int i;
+ char* bufend;
+
+ tbname = dict_remove_db_name(foreign->id);
+ bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
+ tbname, strlen(tbname), trx->mysql_thd, FALSE);
+ tablebuf[bufend - tablebuf] = '\0';
+
+ sprintf(fk_def,
+ (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
+
+ for(i = 0; i < foreign->n_fields; i++) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->foreign_col_names[i],
+ strlen(foreign->foreign_col_names[i]),
+ trx->mysql_thd, FALSE);
+ strcat(fk_def, buf);
+ if (i < foreign->n_fields-1) {
+ strcat(fk_def, (char *)",");
+ }
+ }
+
+ strcat(fk_def,(char *)") REFERENCES ");
+
+ bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
+ foreign->referenced_table_name,
+ strlen(foreign->referenced_table_name),
+ trx->mysql_thd, TRUE);
+ tablebuf[bufend - tablebuf] = '\0';
+
+ strcat(fk_def, tablebuf);
+ strcat(fk_def, " (");
+
+ for(i = 0; i < foreign->n_fields; i++) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->referenced_col_names[i],
+ strlen(foreign->referenced_col_names[i]),
+ trx->mysql_thd, FALSE);
+ buf[bufend - buf] = '\0';
+ strcat(fk_def, buf);
+ if (i < foreign->n_fields-1) {
+ strcat(fk_def, (char *)",");
+ }
+ }
+ strcat(fk_def, (char *)")");
+
+ return fk_def;
+}
+
+/********************************************************************//**
+Convert foreign key column names from data dictionary to SQL-layer.
+*/
+static
+void
+dict_foreign_def_get_fields(
+/*========================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx, /*!< in: trx */
+ char** field, /*!< out: foreign column */
+ char** field2, /*!< out: referenced column */
+ int col_no) /*!< in: column number */
+{
+ char* bufend;
+ char* fieldbuf = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
+ char* fieldbuf2 = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
+
+ bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
+ foreign->foreign_col_names[col_no],
+ strlen(foreign->foreign_col_names[col_no]),
+ trx->mysql_thd, FALSE);
+
+ fieldbuf[bufend - fieldbuf] = '\0';
+
+ bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
+ foreign->referenced_col_names[col_no],
+ strlen(foreign->referenced_col_names[col_no]),
+ trx->mysql_thd, FALSE);
+
+ fieldbuf2[bufend - fieldbuf2] = '\0';
+ *field = fieldbuf;
+ *field2 = fieldbuf2;
+}
+
+/********************************************************************//**
Add a foreign key definition to the data dictionary tables.
@return error code or DB_SUCCESS */
UNIV_INTERN
dberr_t
dict_create_add_foreign_to_dictionary(
/*==================================*/
+ dict_table_t* table,
const char* name, /*!< in: table name */
const dict_foreign_t* foreign,/*!< in: foreign key */
trx_t* trx) /*!< in/out: dictionary transaction */
@@ -1598,6 +1697,28 @@ dict_create_add_foreign_to_dictionary(
, name, foreign->id, trx);
if (error != DB_SUCCESS) {
+ if (error == DB_DUPLICATE_KEY) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ char tablename[MAX_TABLE_NAME_LEN + 1] = "";
+ char* fk_def;
+
+ innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
+ table->name, strlen(table->name),
+ trx->mysql_thd, TRUE);
+
+ innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
+
+ fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx);
+
+ ib_push_warning(trx, error,
+ "Create or Alter table %s with foreign key constraint"
+ " failed. Foreign key constraint %s"
+ " already exists on data dictionary."
+ " Foreign key constraint names need to be unique in database."
+ " Error in foreign key definition: %s.",
+ tablename, buf, fk_def);
+ }
return(error);
}
@@ -1607,6 +1728,26 @@ dict_create_add_foreign_to_dictionary(
i, name, foreign, trx);
if (error != DB_SUCCESS) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ char tablename[MAX_TABLE_NAME_LEN + 1] = "";
+ char* field=NULL;
+ char* field2=NULL;
+ char* fk_def;
+
+ innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
+ table->name, strlen(table->name),
+ trx->mysql_thd, TRUE);
+ innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
+ fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx);
+ dict_foreign_def_get_fields((dict_foreign_t*)foreign, trx, &field, &field2, i);
+
+ ib_push_warning(trx, error,
+ "Create or Alter table %s with foreign key constraint"
+ " failed. Error adding foreign key constraint name %s"
+ " fields %s or %s to the dictionary."
+ " Error in foreign key definition: %s.",
+ tablename, buf, i+1, fk_def);
return(error);
}
@@ -1653,7 +1794,7 @@ dict_create_add_foreigns_to_dictionary(
foreign = *it;
ut_ad(foreign->id != NULL);
- error = dict_create_add_foreign_to_dictionary(table->name,
+ error = dict_create_add_foreign_to_dictionary((dict_table_t*)table, table->name,
foreign, trx);
if (error != DB_SUCCESS) {
diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index 811d737e6bf..0e1906a1827 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -3280,6 +3280,11 @@ dict_index_build_internal_fts(
}
/*====================== FOREIGN KEY PROCESSING ========================*/
+#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
+#define DB_FOREIGN_KEY_COL_NOT_NULL 201
+#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
+#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
+
/*********************************************************************//**
Checks if a table is referenced by foreign keys.
@return TRUE if table is referenced by a foreign key */
@@ -3434,15 +3439,26 @@ dict_foreign_find_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
{
dict_index_t* index;
ut_ad(mutex_own(&dict_sys->mutex));
+ if (error) {
+ *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
+ }
+
index = dict_table_get_first_index(table);
while (index != NULL) {
@@ -3452,7 +3468,12 @@ dict_foreign_find_index(
&& dict_foreign_qualify_index(
table, col_names, columns, n_cols,
index, types_idx,
- check_charsets, check_null)) {
+ check_charsets, check_null,
+ error, err_col_no,err_index)) {
+ if (error) {
+ *error = DB_SUCCESS;
+ }
+
return(index);
}
@@ -3481,7 +3502,7 @@ wsrep_dict_foreign_find_index(
{
return dict_foreign_find_index(
table, col_names, columns, n_cols, types_idx, check_charsets,
- check_null);
+ check_null, NULL, NULL, NULL);
}
#endif /* WITH_WSREP */
/**********************************************************************//**
@@ -3583,7 +3604,7 @@ dict_foreign_add_to_cache(
ref_table, NULL,
for_in_cache->referenced_col_names,
for_in_cache->n_fields, for_in_cache->foreign_index,
- check_charsets, false);
+ check_charsets, false, NULL, NULL, NULL);
if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3615,6 +3636,10 @@ dict_foreign_add_to_cache(
}
if (for_table && !for_in_cache->foreign_table) {
+ ulint index_error;
+ ulint err_col;
+ dict_index_t *err_index=NULL;
+
index = dict_foreign_find_index(
for_table, col_names,
for_in_cache->foreign_col_names,
@@ -3622,7 +3647,8 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_index, check_charsets,
for_in_cache->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL
- | DICT_FOREIGN_ON_UPDATE_SET_NULL));
+ | DICT_FOREIGN_ON_UPDATE_SET_NULL),
+ &index_error, &err_col, &err_index);
if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -4282,6 +4308,8 @@ static
void
dict_foreign_report_syntax_err(
/*===========================*/
+ const char* fmt, /*!< in: syntax err msg */
+ const char* oper, /*!< in: operation */
const char* name, /*!< in: table name */
const char* start_of_latest_foreign,
/*!< in: start of the foreign key clause
@@ -4294,12 +4322,102 @@ dict_foreign_report_syntax_err(
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
- start_of_latest_foreign, ptr);
+ fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr);
mutex_exit(&dict_foreign_err_mutex);
}
/*********************************************************************//**
+Push warning message to SQL-layer based on foreign key constraint
+index match error. */
+static
+void
+dict_foreign_push_index_error(
+/*==========================*/
+ trx_t* trx, /*!< in: trx */
+ const char* operation, /*!< in: operation create or alter
+ */
+ const char* create_name, /*!< in: table name in create or
+ alter table */
+ const char* latest_foreign, /*!< in: start of latest foreign key
+ constraint name */
+ const char** columns, /*!< in: foreign key columns */
+ ulint index_error, /*!< in: error code */
+ ulint err_col, /*!< in: column where error happened
+ */
+ dict_index_t* err_index, /*!< in: index where error happened
+ */
+ dict_table_t* table, /*!< in: table */
+ FILE* ef) /*!< in: output stream */
+{
+ switch (index_error) {
+ case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
+ fprintf(ef,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is no index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.\n",
+ operation, create_name, latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is no index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.",
+ operation, create_name, latest_foreign);
+ break;
+ }
+ case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
+ fprintf(ef,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is only prefix index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.\n",
+ operation, create_name, latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table '%s' with foreign key constraint"
+ " failed. There is only prefix index in the referenced"
+ " table where the referenced columns appear"
+ " as the first columns. Error close to %s.",
+ operation, create_name, latest_foreign);
+ break;
+ }
+ case DB_FOREIGN_KEY_COL_NOT_NULL: {
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but "
+ "field %s on index is defined as NOT NULL close to %s\n",
+ operation, create_name, columns[err_col], latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but "
+ "field %s on index is defined as NOT NULL close to %s",
+ operation, create_name, columns[err_col], latest_foreign);
+ break;
+ }
+ case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
+ dict_field_t* field;
+ const char* col_name;
+ field = dict_index_get_nth_field(err_index, err_col);
+
+ col_name = dict_table_get_col_name(
+ table, dict_col_get_no(field->col));
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Field type or character set for column %s "
+ "does not mach referenced column %s close to %s\n",
+ operation, create_name, columns[err_col], col_name, latest_foreign);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Field type or character set for column %s "
+ "does not mach referenced column %s close to %s",
+ operation, create_name, columns[err_col], col_name, latest_foreign);
+ break;
+ }
+ default:
+ ut_error;
+ }
+}
+
+/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
@@ -4327,16 +4445,21 @@ dict_create_foreign_constraints_low(
DB_CANNOT_ADD_CONSTRAINT if any foreign
keys are found. */
{
- dict_table_t* table;
- dict_table_t* referenced_table;
- dict_table_t* table_to_alter;
+ dict_table_t* table = NULL;
+ dict_table_t* referenced_table = NULL;
+ dict_table_t* table_to_alter = NULL;
+ dict_table_t* table_to_create = NULL;
ulint highest_id_so_far = 0;
ulint number = 1;
- dict_index_t* index;
- dict_foreign_t* foreign;
+ dict_index_t* index = NULL;
+ dict_foreign_t* foreign = NULL;
const char* ptr = sql_string;
const char* start_of_latest_foreign = sql_string;
+ const char* start_of_latest_set = NULL;
FILE* ef = dict_foreign_err_file;
+ ulint index_error = DB_SUCCESS;
+ dict_index_t* err_index = NULL;
+ ulint err_col;
const char* constraint_name;
ibool success;
dberr_t error;
@@ -4349,37 +4472,80 @@ dict_create_foreign_constraints_low(
ulint n_on_updates;
const dict_col_t*columns[500];
const char* column_names[500];
+ const char* ref_column_names[500];
const char* referenced_table_name;
dict_foreign_set local_fk_set;
dict_foreign_set_free local_fk_set_free(local_fk_set);
+ const char* create_table_name;
+ const char* orig;
+ char create_name[MAX_TABLE_NAME_LEN + 1];
+ char operation[8];
ut_ad(!srv_read_only_mode);
ut_ad(mutex_own(&(dict_sys->mutex)));
table = dict_table_get_low(name);
+ /* First check if we are actually doing an ALTER TABLE, and in that
+ case look for the table being altered */
+ orig = ptr;
+ ptr = dict_accept(cs, ptr, "ALTER", &success);
+
+ strcpy((char *)operation, success ? "Alter " : "Create ");
+
+ if (!success) {
+ orig = ptr;
+ ptr = dict_scan_to(ptr, "CREATE");
+ ptr = dict_scan_to(ptr, "TABLE");
+ ptr = dict_accept(cs, ptr, "TABLE", &success);
+
+ if (success) {
+ ptr = dict_scan_table_name(cs, ptr, &table_to_create, name,
+ &success, heap, &create_table_name);
+ }
+
+ if (success) {
+ char *bufend;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ create_table_name, strlen(create_table_name),
+ trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+ ptr = orig;
+ } else {
+ char *bufend;
+ ptr = orig;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ name, strlen(name), trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+ }
+
+ goto loop;
+ }
if (table == NULL) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef,
- "Cannot find the table in the internal"
- " data dictionary of InnoDB.\n"
- "Create table statement:\n%s\n", sql_string);
+ dict_foreign_error_report_low(ef, create_name);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef, "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.\n",
+ operation, create_name, create_name, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_ERROR,
+ "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.",
+ operation, create_name, create_name, start_of_latest_foreign);
return(DB_ERROR);
}
- /* First check if we are actually doing an ALTER TABLE, and in that
- case look for the table being altered */
-
- ptr = dict_accept(cs, ptr, "ALTER", &success);
-
+ /* If not alter table jump to loop */
if (!success) {
goto loop;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "TABLE", &success);
if (!success) {
@@ -4389,13 +4555,40 @@ dict_create_foreign_constraints_low(
/* We are doing an ALTER TABLE: scan the table name we are altering */
+ orig = ptr;
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
&success, heap, &referenced_table_name);
+
+ if (table_to_alter) {
+ char *bufend;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ table_to_alter->name, strlen(table_to_alter->name),
+ trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+ } else {
+ char *bufend;
+ bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
+ referenced_table_name, strlen(referenced_table_name),
+ trx->mysql_thd, TRUE);
+ create_name[bufend-create_name]='\0';
+
+ }
+
if (!success) {
- fprintf(stderr,
- "InnoDB: Error: could not find"
- " the table being ALTERED in:\n%s\n",
- sql_string);
+ mutex_enter(&dict_foreign_err_mutex);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.\n",
+ operation, create_name, create_name, orig);
+ mutex_exit(&dict_foreign_err_mutex);
+
+ ib_push_warning(trx, DB_ERROR,
+ "%s table %s with foreign key constraint"
+ " failed. Table %s not found from data dictionary."
+ " Error close to %s.",
+ operation, create_name, create_name, orig);
return(DB_ERROR);
}
@@ -4432,6 +4625,7 @@ loop:
of the constraint to system tables. */
ptr = ptr1;
+ orig = ptr;
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
ut_a(success);
@@ -4462,6 +4656,19 @@ loop:
if so, immediately reject the command if the table is a
temporary one. For now, this kludge will work. */
if (reject_fks && !local_fk_set.empty()) {
+ mutex_enter(&dict_foreign_err_mutex);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef, "%s table %s with foreign key constraint"
+ " failed. Temporary tables can't have foreign key constraints."
+ " Error close to %s.\n",
+ operation, create_name, start_of_latest_foreign);
+ mutex_exit(&dict_foreign_err_mutex);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Temporary tables can't have foreign key constraints."
+ " Error close to %s.",
+ operation, create_name, start_of_latest_foreign);
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4487,6 +4694,7 @@ loop:
start_of_latest_foreign = ptr;
+ orig = ptr;
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
if (!success) {
@@ -4497,6 +4705,7 @@ loop:
goto loop;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "KEY", &success);
if (!success) {
@@ -4522,6 +4731,7 @@ loop:
}
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success);
if (!success) {
@@ -4531,8 +4741,17 @@ loop:
ptr = dict_skip_word(cs, ptr, &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
- return(DB_CANNOT_ADD_CONSTRAINT);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
}
else {
@@ -4559,15 +4778,26 @@ loop:
/* Scan the columns in the first list */
col_loop1:
ut_a(i < (sizeof column_names) / sizeof *column_names);
+ orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
heap, column_names + i);
if (!success) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
- start_of_latest_foreign, ptr);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4579,11 +4809,22 @@ col_loop1:
goto col_loop1;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4594,27 +4835,41 @@ col_loop1:
set to 0 */
index = dict_foreign_find_index(
- table, NULL, column_names, i, NULL, TRUE, FALSE);
+ table, NULL, column_names, i,
+ NULL, TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
+ dict_foreign_error_report_low(ef, create_name);
fputs("There is no index in table ", ef);
- ut_print_name(ef, NULL, TRUE, name);
+ ut_print_name(ef, NULL, TRUE, create_name);
fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n"
"See " REFMAN "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
start_of_latest_foreign);
- mutex_exit(&dict_foreign_err_mutex);
+ dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
+ column_names, index_error, err_col, err_index, table, ef);
- return(DB_CHILD_NO_INDEX);
+ mutex_exit(&dict_foreign_err_mutex);
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
+
+ orig = ptr;
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
if (!success || !my_isspace(cs, *ptr)) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4683,21 +4938,46 @@ col_loop1:
checking of foreign key constraints! */
if (!success || (!referenced_table && trx->check_foreigns)) {
+ char buf[MAX_TABLE_NAME_LEN + 1] = "";
+ char* bufend;
+
+ bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
+ referenced_table_name, strlen(referenced_table_name),
+ trx->mysql_thd, TRUE);
+ buf[bufend - buf] = '\0';
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
+ "close to %s.",
+ operation, create_name, buf, start_of_latest_foreign);
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nCannot resolve table name close to:\n"
- "%s\n",
- start_of_latest_foreign, ptr);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
+ "close to %s.\n",
+ operation, create_name, buf, start_of_latest_foreign);
+
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success);
if (!success) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4705,34 +4985,54 @@ col_loop1:
i = 0;
col_loop2:
+ orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
- heap, column_names + i);
+ heap, ref_column_names + i);
i++;
if (!success) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\nCannot resolve column name close to:\n"
- "%s\n",
- start_of_latest_foreign, ptr);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, orig);
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, ",", &success);
if (success) {
goto col_loop2;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success);
if (!success || foreign->n_fields != i) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s. Too few referenced columns.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s. Too few referenced columns, you have %d when you should have %d.",
+ operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4742,6 +5042,7 @@ col_loop2:
scan_on_conditions:
/* Loop here as long as we can find ON ... conditions */
+ start_of_latest_set = ptr;
ptr = dict_accept(cs, ptr, "ON", &success);
if (!success) {
@@ -4749,15 +5050,27 @@ scan_on_conditions:
goto try_find_index;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "DELETE", &success);
if (!success) {
+ orig = ptr;
ptr = dict_accept(cs, ptr, "UPDATE", &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4768,12 +5081,14 @@ scan_on_conditions:
n_on_deletes++;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
if (success) {
goto scan_on_conditions;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "CASCADE", &success);
if (success) {
@@ -4786,14 +5101,25 @@ scan_on_conditions:
goto scan_on_conditions;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "NO", &success);
if (success) {
+ orig = ptr;
ptr = dict_accept(cs, ptr, "ACTION", &success);
if (!success) {
dict_foreign_report_syntax_err(
- name, start_of_latest_foreign, ptr);
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -4807,38 +5133,69 @@ scan_on_conditions:
goto scan_on_conditions;
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "SET", &success);
if (!success) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ orig = ptr;
ptr = dict_accept(cs, ptr, "NULL", &success);
if (!success) {
- dict_foreign_report_syntax_err(name, start_of_latest_foreign,
- ptr);
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Foreign key constraint parse error in %s"
+ " close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
for (j = 0; j < foreign->n_fields; j++) {
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
& DATA_NOT_NULL) {
+ const dict_col_t* col
+ = dict_index_get_nth_col(foreign->foreign_index, j);
+ const char* col_name = dict_table_get_col_name(foreign->foreign_index->table,
+ dict_col_get_no(col));
/* It is not sensible to define SET NULL
if the column is not allowed to be NULL! */
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\n"
- "You have defined a SET NULL condition"
- " though some of the\n"
- "columns are defined as NOT NULL.\n",
- start_of_latest_foreign);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
+ " in %s close to %s.\n",
+ operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
mutex_exit(&dict_foreign_err_mutex);
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
+ " in %s close to %s.",
+ operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
}
@@ -4856,11 +5213,20 @@ try_find_index:
/* It is an error to define more than 1 action */
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
- fprintf(ef, "%s:\n"
- "You have twice an ON DELETE clause"
- " or twice an ON UPDATE clause.\n",
- start_of_latest_foreign);
+ dict_foreign_error_report_low(ef, create_name);
+ fprintf(ef,
+ "%s table %s with foreign key constraint"
+ " failed. You have more than one on delete or on update clause"
+ " in %s close to %s.\n",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. You have more than one on delete or on update clause"
+ " in %s close to %s.",
+ operation, create_name, start_of_latest_foreign, start_of_latest_set);
+
+ dict_foreign_free(foreign);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT);
@@ -4872,12 +5238,12 @@ try_find_index:
if (referenced_table) {
index = dict_foreign_find_index(referenced_table, NULL,
- column_names, i,
+ ref_column_names, i,
foreign->foreign_index,
- TRUE, FALSE);
+ TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) {
mutex_enter(&dict_foreign_err_mutex);
- dict_foreign_error_report_low(ef, name);
+ dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n"
"Cannot find an index in the"
" referenced table where the\n"
@@ -4895,9 +5261,13 @@ try_find_index:
"innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
start_of_latest_foreign);
+
+ dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
+ column_names, index_error, err_col, err_index, referenced_table, ef);
+
mutex_exit(&dict_foreign_err_mutex);
- return(DB_PARENT_NO_INDEX);
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
} else {
ut_a(trx->check_foreigns == FALSE);
@@ -4916,11 +5286,12 @@ try_find_index:
for (i = 0; i < foreign->n_fields; i++) {
foreign->referenced_col_names[i]
- = mem_heap_strdup(foreign->heap, column_names[i]);
+ = mem_heap_strdup(foreign->heap, ref_column_names[i]);
}
goto loop;
}
+
/**************************************************************************
Determines whether a string starts with the specified keyword.
@return TRUE if str starts with keyword */
@@ -6110,7 +6481,8 @@ dict_foreign_replace_index(
foreign->foreign_table, col_names,
foreign->foreign_col_names,
foreign->n_fields, index,
- /*check_charsets=*/TRUE, /*check_null=*/FALSE);
+ /*check_charsets=*/TRUE, /*check_null=*/FALSE,
+ NULL, NULL, NULL);
if (new_index) {
ut_ad(new_index->table == index->table);
ut_ad(!new_index->to_be_dropped);
@@ -6134,7 +6506,8 @@ dict_foreign_replace_index(
foreign->referenced_table, NULL,
foreign->referenced_col_names,
foreign->n_fields, index,
- /*check_charsets=*/TRUE, /*check_null=*/FALSE);
+ /*check_charsets=*/TRUE, /*check_null=*/FALSE,
+ NULL, NULL, NULL);
/* There must exist an alternative index,
since this must have been checked earlier. */
if (new_index) {
@@ -6695,10 +7068,15 @@ dict_foreign_qualify_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error happened */
{
if (dict_index_get_n_fields(index) < n_cols) {
return(false);
@@ -6715,11 +7093,21 @@ dict_foreign_qualify_index(
if (field->prefix_len != 0) {
/* We do not accept column prefix
indexes here */
+ if (error && err_col_no && err_index) {
+ *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
+ *err_col_no = i;
+ *err_index = (dict_index_t*)index;
+ }
return(false);
}
if (check_null
&& (field->col->prtype & DATA_NOT_NULL)) {
+ if (error && err_col_no && err_index) {
+ *error = DB_FOREIGN_KEY_COL_NOT_NULL;
+ *err_col_no = i;
+ *err_index = (dict_index_t*)index;
+ }
return(false);
}
@@ -6735,6 +7123,12 @@ dict_foreign_qualify_index(
dict_index_get_nth_col(index, i),
dict_index_get_nth_col(types_idx, i),
check_charsets)) {
+ if (error && err_col_no && err_index) {
+ *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
+ *err_col_no = i;
+ *err_index = (dict_index_t*)index;
+ }
+
return(false);
}
}
diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc
index 58521b833b6..d6ed8acb39e 100644
--- a/storage/xtradb/dict/dict0load.cc
+++ b/storage/xtradb/dict/dict0load.cc
@@ -1168,7 +1168,7 @@ loop:
dberr_t err = fil_open_single_table_tablespace(
read_page_0, srv_read_only_mode ? false : true,
space_id, dict_tf_to_fsp_flags(flags),
- name, filepath);
+ name, filepath, NULL);
if (err != DB_SUCCESS) {
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -2413,7 +2413,7 @@ err_exit:
err = fil_open_single_table_tablespace(
true, false, table->space,
dict_tf_to_fsp_flags(table->flags),
- name, filepath);
+ name, filepath, table);
if (err != DB_SUCCESS) {
/* We failed to find a sensible
diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc
index ffdc5100558..a4f6cd6c91f 100644
--- a/storage/xtradb/dict/dict0mem.cc
+++ b/storage/xtradb/dict/dict0mem.cc
@@ -420,7 +420,8 @@ dict_mem_table_col_rename_low(
dict_index_t* new_index = dict_foreign_find_index(
foreign->foreign_table, NULL,
foreign->foreign_col_names,
- foreign->n_fields, NULL, true, false);
+ foreign->n_fields, NULL, true, false,
+ NULL, NULL, NULL);
/* There must be an equivalent index in this case. */
ut_ad(new_index != NULL);
diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc
index 289c4df60bf..f60a4fb3fcf 100644
--- a/storage/xtradb/fil/fil0crypt.cc
+++ b/storage/xtradb/fil/fil0crypt.cc
@@ -650,31 +650,8 @@ fil_space_encrypt(
/* handle post encryption checksum */
ib_uint32_t checksum = 0;
- srv_checksum_algorithm_t algorithm =
- static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
- if (zip_size == 0) {
- switch (algorithm) {
- case SRV_CHECKSUM_ALGORITHM_CRC32:
- case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
- checksum = buf_calc_page_crc32(dst_frame);
- break;
- case SRV_CHECKSUM_ALGORITHM_INNODB:
- case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
- checksum = (ib_uint32_t) buf_calc_page_new_checksum(
- dst_frame);
- break;
- case SRV_CHECKSUM_ALGORITHM_NONE:
- case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
- checksum = BUF_NO_CHECKSUM_MAGIC;
- break;
- /* no default so the compiler will emit a warning
- * if new enum is added and not handled here */
- }
- } else {
- checksum = page_zip_calc_checksum(dst_frame, zip_size,
- algorithm);
- }
+ checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
// store the post-encryption checksum after the key-version
mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4, checksum);
@@ -818,6 +795,47 @@ fil_space_decrypt(
return src_frame;
}
+/******************************************************************
+Calculate post encryption checksum
+@return page checksum or BUF_NO_CHECKSUM_MAGIC
+not needed. */
+UNIV_INTERN
+ulint
+fil_crypt_calculate_checksum(
+/*=========================*/
+ ulint zip_size, /*!< in: zip_size or 0 */
+ byte* dst_frame) /*!< in: page where to calculate */
+{
+ ib_uint32_t checksum = 0;
+ srv_checksum_algorithm_t algorithm =
+ static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
+
+ if (zip_size == 0) {
+ switch (algorithm) {
+ case SRV_CHECKSUM_ALGORITHM_CRC32:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+ checksum = buf_calc_page_crc32(dst_frame);
+ break;
+ case SRV_CHECKSUM_ALGORITHM_INNODB:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+ checksum = (ib_uint32_t) buf_calc_page_new_checksum(
+ dst_frame);
+ break;
+ case SRV_CHECKSUM_ALGORITHM_NONE:
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+ checksum = BUF_NO_CHECKSUM_MAGIC;
+ break;
+ /* no default so the compiler will emit a warning
+ * if new enum is added and not handled here */
+ }
+ } else {
+ checksum = page_zip_calc_checksum(dst_frame, zip_size,
+ algorithm);
+ }
+
+ return checksum;
+}
+
/*********************************************************************
Verify checksum for a page (iff it's encrypted)
NOTE: currently this function can only be run in single threaded mode
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index 3fc9506a15a..47d8803710a 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -2023,6 +2023,7 @@ fil_read_first_page(
const char* check_msg = NULL;
fil_space_crypt_t* cdata;
+
buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
/* Align the memory for a possible read from a raw device */
@@ -2053,6 +2054,10 @@ fil_read_first_page(
fsp_flags_get_zip_size(*flags), NULL);
cdata = fil_space_read_crypt_data(space, page, offset);
+ if (crypt_data) {
+ *crypt_data = cdata;
+ }
+
/* If file space is encrypted we need to have at least some
encryption service available where to get keys */
if ((cdata && cdata->encryption == FIL_SPACE_ENCRYPTION_ON) ||
@@ -2060,16 +2065,14 @@ fil_read_first_page(
cdata && cdata->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
if (!encryption_key_id_exists(cdata->key_id)) {
- ib_logf(IB_LOG_LEVEL_FATAL,
- "Tablespace id %ld encrypted but encryption service"
- " not available. Can't continue opening tablespace.\n",
- space);
- ut_error;
- }
- }
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Tablespace id %ld is encrypted but encryption service"
+ " or used key_id %u is not available. Can't continue opening tablespace.",
+ space, cdata->key_id);
- if (crypt_data) {
- *crypt_data = cdata;
+ return ("table encrypted but encryption service not available.");
+
+ }
}
ut_free(buf);
@@ -3655,7 +3658,8 @@ fil_open_single_table_tablespace(
ulint flags, /*!< in: tablespace flags */
const char* tablename, /*!< in: table name in the
databasename/tablename format */
- const char* path_in) /*!< in: tablespace filepath */
+ const char* path_in, /*!< in: tablespace filepath */
+ dict_table_t* table) /*!< in: table */
{
dberr_t err = DB_SUCCESS;
bool dict_filepath_same_as_default = false;
@@ -3769,6 +3773,10 @@ fil_open_single_table_tablespace(
&def.lsn, &def.lsn, &def.crypt_data);
def.valid = !def.check_msg;
+ if (table) {
+ table->crypt_data = def.crypt_data;
+ }
+
/* Validate this single-table-tablespace with SYS_TABLES,
but do not compare the DATA_DIR flag, in case the
tablespace was relocated. */
@@ -3791,6 +3799,10 @@ fil_open_single_table_tablespace(
&remote.lsn, &remote.lsn, &remote.crypt_data);
remote.valid = !remote.check_msg;
+ if (table) {
+ table->crypt_data = remote.crypt_data;
+ }
+
/* Validate this single-table-tablespace with SYS_TABLES,
but do not compare the DATA_DIR flag, in case the
tablespace was relocated. */
@@ -3814,6 +3826,10 @@ fil_open_single_table_tablespace(
&dict.lsn, &dict.lsn, &dict.crypt_data);
dict.valid = !dict.check_msg;
+ if (table) {
+ table->crypt_data = dict.crypt_data;
+ }
+
/* Validate this single-table-tablespace with SYS_TABLES,
but do not compare the DATA_DIR flag, in case the
tablespace was relocated. */
@@ -3995,7 +4011,9 @@ cleanup_and_exit:
mem_free(remote.filepath);
}
if (remote.crypt_data && remote.crypt_data != crypt_data) {
- fil_space_destroy_crypt_data(&remote.crypt_data);
+ if (err == DB_SUCCESS) {
+ fil_space_destroy_crypt_data(&remote.crypt_data);
+ }
}
if (dict.success) {
os_file_close(dict.file);
@@ -4010,7 +4028,9 @@ cleanup_and_exit:
os_file_close(def.file);
}
if (def.crypt_data && def.crypt_data != crypt_data) {
- fil_space_destroy_crypt_data(&def.crypt_data);
+ if (err == DB_SUCCESS) {
+ fil_space_destroy_crypt_data(&def.crypt_data);
+ }
}
mem_free(def.filepath);
@@ -5928,9 +5948,9 @@ _fil_io(
if (!ret) {
return(DB_OUT_OF_FILE_SPACE);
- } else {
- return(DB_SUCCESS);
}
+
+ return(DB_SUCCESS);
}
#ifndef UNIV_HOTBACKUP
diff --git a/storage/xtradb/fsp/fsp0fsp.cc b/storage/xtradb/fsp/fsp0fsp.cc
index 363a46d7fdf..1358fab90ea 100644
--- a/storage/xtradb/fsp/fsp0fsp.cc
+++ b/storage/xtradb/fsp/fsp0fsp.cc
@@ -2730,6 +2730,8 @@ fsp_reserve_free_extents(
ulint reserve;
ibool success;
ulint n_pages_added;
+ size_t total_reserved = 0;
+ ulint rounds = 0;
ut_ad(mtr);
*n_reserved = n_ext;
@@ -2743,7 +2745,7 @@ fsp_reserve_free_extents(
try_again:
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
- if (size < FSP_EXTENT_SIZE) {
+ if (size < FSP_EXTENT_SIZE / 2) {
/* Use different rules for small single-table tablespaces */
*n_reserved = 0;
return(fsp_reserve_free_pages(space, space_header, size, mtr));
@@ -2758,7 +2760,6 @@ try_again:
some of them will contain extent descriptor pages, and therefore
will not be free extents */
- ut_ad(size >= free_limit);
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
if (n_free_up > 0) {
@@ -2799,6 +2800,7 @@ try_again:
}
success = fil_space_reserve_free_extents(space, n_free, n_ext);
+ *n_reserved = n_ext;
if (success) {
return(TRUE);
@@ -2808,6 +2810,16 @@ try_to_extend:
space_header, mtr);
if (success && n_pages_added > 0) {
+ rounds++;
+ total_reserved += n_pages_added;
+
+ if (rounds > 50) {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Space id %lu trying to reserve %lu extents actually reserved %lu "
+ " reserve %lu free %lu size %lu rounds %lu total_reserved %lu",
+ space, n_ext, n_pages_added, reserve, n_free, size, rounds, total_reserved);
+ }
+
goto try_again;
}
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index a7f5653c389..227509a24cc 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -1,10 +1,10 @@
/*****************************************************************************
-Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+Copyright (c) 2013, 2015, MariaDB Corporation.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -607,7 +607,8 @@ ib_cb_t innodb_api_cb[] = {
(ib_cb_t) ib_get_idx_field_name,
(ib_cb_t) ib_trx_get_start_time,
(ib_cb_t) ib_cfg_bk_commit_interval,
- (ib_cb_t) ib_cursor_stmt_begin
+ (ib_cb_t) ib_cursor_stmt_begin,
+ (ib_cb_t) ib_trx_read_only
};
@@ -2005,6 +2006,7 @@ convert_error_code_to_mysql(
case DB_TABLESPACE_DELETED:
case DB_TABLE_NOT_FOUND:
+ case DB_ENCRYPTED_DECRYPT_FAILED:
return(HA_ERR_NO_SUCH_TABLE);
case DB_TABLESPACE_NOT_FOUND:
@@ -2636,6 +2638,7 @@ check_trx_exists(
if (trx == NULL) {
trx = innobase_trx_allocate(thd);
+ thd_set_ha_data(thd, innodb_hton_ptr, trx);
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
mem_analyze_corruption(trx);
ut_error;
@@ -6041,7 +6044,14 @@ table_opened:
innobase_copy_frm_flags_from_table_share(ib_table, table->s);
- dict_stats_init(ib_table);
+ ib_table->thd = (void*)thd;
+
+ /* No point to init any statistics if tablespace is still encrypted. */
+ if (!ib_table->is_encrypted) {
+ dict_stats_init(ib_table);
+ } else {
+ ib_table->stat_initialized = 1;
+ }
MONITOR_INC(MONITOR_TABLE_OPEN);
@@ -6070,6 +6080,11 @@ table_opened:
file, best to play it safe. */
no_tablespace = true;
+ } else if (ib_table->is_encrypted) {
+ /* This means that tablespace was found but we could not
+ decrypt encrypted page. */
+ no_tablespace = true;
+ ib_table->ibd_file_missing = true;
} else {
no_tablespace = false;
}
@@ -6078,6 +6093,33 @@ table_opened:
free_share(share);
my_errno = ENOENT;
+ /* If table has no talespace but it has crypt data, check
+ is tablespace made unaccessible because encryption service
+ or used key_id is not available. */
+ if (ib_table) {
+ fil_space_crypt_t* crypt_data = ib_table->crypt_data;
+ if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
+ (srv_encrypt_tables &&
+ crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
+
+ if (!encryption_key_id_exists(crypt_data->key_id)) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_NO_SUCH_TABLE,
+ "Table %s is encrypted but encryption service or"
+ " used key_id %u is not available. "
+ " Can't continue reading table.",
+ ib_table->name, crypt_data->key_id);
+ }
+ } else if (ib_table->is_encrypted) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_NO_SUCH_TABLE,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ ib_table->name);
+ }
+ }
+
dict_table_close(ib_table, FALSE, FALSE);
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
@@ -8209,10 +8251,11 @@ no_commit:
;
} else if (src_table == prebuilt->table) {
#ifdef WITH_WSREP
- if (wsrep_on(user_thd) && wsrep_load_data_splitting &&
+ if (wsrep_on(user_thd) &&
+ wsrep_load_data_splitting &&
sql_command == SQLCOM_LOAD &&
- !thd_test_options(
- user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ !thd_test_options(user_thd,
+ OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
{
switch (wsrep_run_wsrep_commit(user_thd, 1))
{
@@ -8240,10 +8283,11 @@ no_commit:
prebuilt->sql_stat_start = TRUE;
} else {
#ifdef WITH_WSREP
- if (wsrep_on(user_thd) && wsrep_load_data_splitting &&
+ if (wsrep_on(user_thd) &&
+ wsrep_load_data_splitting &&
sql_command == SQLCOM_LOAD &&
- !thd_test_options(
- user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ !thd_test_options(user_thd,
+ OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
{
switch (wsrep_run_wsrep_commit(user_thd, 1))
{
@@ -8474,14 +8518,15 @@ report_error:
user_thd);
#ifdef WITH_WSREP
- if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
- wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) &&
- (sql_command != SQLCOM_LOAD ||
- thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) {
-
- if (wsrep_append_keys(user_thd, false, record, NULL)) {
- DBUG_PRINT("wsrep", ("row key failed"));
- error_result = HA_ERR_INTERNAL_ERROR;
+ if (!error_result &&
+ wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd) &&
+ !wsrep_consistency_check(user_thd))
+ {
+ if (wsrep_append_keys(user_thd, false, record, NULL))
+ {
+ DBUG_PRINT("wsrep", ("row key failed"));
+ error_result = HA_ERR_INTERNAL_ERROR;
goto wsrep_error;
}
}
@@ -13135,6 +13180,13 @@ ha_innobase::estimate_rows_upper_bound()
prebuilt->trx->op_info = "";
+ /* Set num_rows less than MERGEBUFF to simulate the case where we do
+ not have enough space to merge the externally sorted file blocks. */
+ DBUG_EXECUTE_IF("set_num_rows_lt_MERGEBUFF",
+ estimate = 2;
+ DBUG_SET("-d,set_num_rows_lt_MERGEBUFF");
+ );
+
DBUG_RETURN((ha_rows) estimate);
}
@@ -13400,7 +13452,6 @@ ha_innobase::info_low(
dict_table_t* ib_table;
ha_rows rec_per_key;
ib_uint64_t n_rows;
- char path[FN_REFLEN];
os_file_stat_t stat_info;
DBUG_ENTER("info");
@@ -13457,6 +13508,7 @@ ha_innobase::info_low(
prebuilt->trx->op_info =
"returning various info to MySQL";
}
+
}
if (flag & HA_STATUS_VARIABLE) {
@@ -13588,6 +13640,7 @@ ha_innobase::info_low(
if (flag & HA_STATUS_CONST) {
ulong i;
+ char path[FN_REFLEN];
/* Verify the number of index in InnoDB and MySQL
matches up. If prebuilt->clust_index_was_generated
holds, InnoDB defines GEN_CLUST_INDEX internally */
@@ -21343,3 +21396,59 @@ static void innodb_remember_check_sysvar_funcs()
ut_ad((MYSQL_SYSVAR_NAME(checksum_algorithm).flags & 0x1FF) == PLUGIN_VAR_ENUM);
check_sysvar_enum = MYSQL_SYSVAR_NAME(checksum_algorithm).check;
}
+
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ trx_t* trx, /*!< in: trx */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...)
+{
+ va_list args;
+ THD *thd = (THD *)trx->mysql_thd;
+ char *buf;
+#define MAX_BUF_SIZE 4*1024
+
+ va_start(args, format);
+ buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
+ vsprintf(buf,format, args);
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ convert_error_code_to_mysql((dberr_t)error, 0, thd),
+ buf);
+ my_free(buf);
+ va_end(args);
+}
+
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ void* ithd, /*!< in: thd */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...)
+{
+ va_list args;
+ THD *thd = (THD *)ithd;
+ char *buf;
+#define MAX_BUF_SIZE 4*1024
+
+ if (ithd == NULL) {
+ thd = current_thd;
+ }
+
+ va_start(args, format);
+ buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
+ vsprintf(buf,format, args);
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ convert_error_code_to_mysql((dberr_t)error, 0, thd),
+ buf);
+ my_free(buf);
+ va_end(args);
+}
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 7f5ee15049e..5a190e4ca9a 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -400,6 +400,35 @@ ha_innobase::check_if_supported_inplace_alter(
}
}
+ /* If we have column that has changed from NULL -> NOT NULL
+ and column default has changed we need to do additional
+ check. */
+ if ((ha_alter_info->handler_flags
+ & Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) &&
+ (ha_alter_info->handler_flags
+ & Alter_inplace_info::ALTER_COLUMN_DEFAULT)) {
+ Alter_info *alter_info = ha_alter_info->alter_info;
+ List_iterator<Create_field> def_it(alter_info->create_list);
+ Create_field *def;
+ while ((def=def_it++)) {
+
+ /* If this is first column definition whose SQL type
+ is TIMESTAMP and it is defined as NOT NULL and
+ it has either constant default or function default
+ we must use "Copy" method. */
+ if (is_timestamp_type(def->sql_type)) {
+ if ((def->flags & NOT_NULL_FLAG) != 0 && // NOT NULL
+ (def->def != NULL || // constant default ?
+ def->unireg_check != Field::NONE)) { // function default
+ ha_alter_info->unsupported_reason = innobase_get_err_msg(
+ ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ break;
+ }
+ }
+ }
+
/* We should be able to do the operation in-place.
See if we can do it online (LOCK=NONE). */
bool online = true;
@@ -824,7 +853,7 @@ innobase_find_fk_index(
if (!(index->type & DICT_FTS)
&& dict_foreign_qualify_index(
table, col_names, columns, n_cols,
- index, NULL, true, 0)) {
+ index, NULL, true, 0, NULL, NULL, NULL)) {
for (ulint i = 0; i < n_drop_index; i++) {
if (index == drop_index[i]) {
/* Skip to-be-dropped indexes. */
@@ -1014,7 +1043,7 @@ innobase_get_foreign_key_info(
referenced_table, 0,
referenced_column_names,
i, index,
- TRUE, FALSE);
+ TRUE, FALSE, NULL, NULL, NULL);
DBUG_EXECUTE_IF(
"innodb_test_no_reference_idx",
@@ -3341,7 +3370,7 @@ innobase_check_foreign_key_index(
foreign->referenced_col_names,
foreign->n_fields, index,
/*check_charsets=*/TRUE,
- /*check_null=*/FALSE)
+ /*check_null=*/FALSE, NULL, NULL, NULL)
&& !innobase_find_equiv_index(
foreign->referenced_col_names,
foreign->n_fields,
@@ -3369,7 +3398,7 @@ innobase_check_foreign_key_index(
foreign->foreign_col_names,
foreign->n_fields, index,
/*check_charsets=*/TRUE,
- /*check_null=*/FALSE)
+ /*check_null=*/FALSE, NULL,NULL, NULL)
&& !innobase_find_equiv_index(
foreign->foreign_col_names,
foreign->n_fields,
@@ -4139,6 +4168,10 @@ oom:
: ha_alter_info->key_info_buffer[
prebuilt->trx->error_key_num].name);
break;
+ case DB_ENCRYPTED_DECRYPT_FAILED:
+ my_error(ER_NO_SUCH_TABLE_IN_ENGINE, MYF(0),
+ table_share->db.str, table_share->table_name.str);
+ break;
default:
my_error_innodb(error,
table_share->table_name.str,
@@ -4838,7 +4871,8 @@ innobase_update_foreign_try(
fk->n_fields, fk->referenced_index, TRUE,
fk->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL
- | DICT_FOREIGN_ON_UPDATE_SET_NULL));
+ | DICT_FOREIGN_ON_UPDATE_SET_NULL),
+ NULL, NULL, NULL);
if (!fk->foreign_index) {
my_error(ER_FK_INCORRECT_OPTION,
MYF(0), table_name, fk->id);
@@ -4850,7 +4884,7 @@ innobase_update_foreign_try(
names, while the columns in ctx->old_table have not
been renamed yet. */
error = dict_create_add_foreign_to_dictionary(
- ctx->old_table->name, fk, trx);
+ (dict_table_t*)ctx->old_table, ctx->old_table->name, fk, trx);
DBUG_EXECUTE_IF(
"innodb_test_cannot_add_fk_system",
diff --git a/storage/xtradb/include/api0api.h b/storage/xtradb/include/api0api.h
index d77d691becc..e4c9c941de5 100644
--- a/storage/xtradb/include/api0api.h
+++ b/storage/xtradb/include/api0api.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -494,6 +494,14 @@ ib_trx_state(
/*=========*/
ib_trx_t ib_trx); /*!< in: trx handle */
+
+/*****************************************************************//**
+Check if the transaction is read_only */
+ib_u32_t
+ib_trx_read_only(
+/*=============*/
+ ib_trx_t ib_trx); /*!< in: trx handle */
+
/*****************************************************************//**
Release the resources of the transaction. If the transaction was
selected as a victim by InnoDB and rolled back then use this function
diff --git a/storage/xtradb/include/btr0btr.ic b/storage/xtradb/include/btr0btr.ic
index 40b468b200a..6604ac6a6f0 100644
--- a/storage/xtradb/include/btr0btr.ic
+++ b/storage/xtradb/include/btr0btr.ic
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -57,13 +58,15 @@ btr_block_get_func(
buf_block_t* block;
block = buf_page_get_gen(space, zip_size, page_no, mode,
- NULL, BUF_GET, file, line, mtr);
+ NULL, BUF_GET, file, line, mtr);
- if (mode != RW_NO_LATCH) {
+ if (block) {
+ if (mode != RW_NO_LATCH) {
- buf_block_dbg_add_level(
- block, index != NULL && dict_index_is_ibuf(index)
- ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
+ buf_block_dbg_add_level(
+ block, index != NULL && dict_index_is_ibuf(index)
+ ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
+ }
}
return(block);
diff --git a/storage/xtradb/include/btr0cur.h b/storage/xtradb/include/btr0cur.h
index f4b91b08fc5..2c60f3ad64c 100644
--- a/storage/xtradb/include/btr0cur.h
+++ b/storage/xtradb/include/btr0cur.h
@@ -136,7 +136,7 @@ Note that if mode is PAGE_CUR_LE, which is used in inserts, then
cursor->up_match and cursor->low_match both will have sensible values.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
UNIV_INTERN
-void
+dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -173,7 +173,7 @@ btr_cur_search_to_nth_level(
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
-void
+dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,
diff --git a/storage/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h
index cfbaacf4de3..d8e7cf6b283 100644
--- a/storage/xtradb/include/btr0pcur.h
+++ b/storage/xtradb/include/btr0pcur.h
@@ -114,7 +114,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -143,7 +143,7 @@ btr_pcur_open_with_no_init_func(
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,
diff --git a/storage/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic
index 7e355d3709d..1cd13824542 100644
--- a/storage/xtradb/include/btr0pcur.ic
+++ b/storage/xtradb/include/btr0pcur.ic
@@ -447,7 +447,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -472,6 +472,7 @@ btr_pcur_open_with_no_init_func(
mtr_t* mtr) /*!< in: mtr */
{
btr_cur_t* btr_cursor;
+ dberr_t err = DB_SUCCESS;
cursor->latch_mode = latch_mode;
cursor->search_mode = mode;
@@ -480,20 +481,21 @@ btr_pcur_open_with_no_init_func(
btr_cursor = btr_pcur_get_btr_cur(cursor);
- btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
- btr_cursor, has_search_latch,
- file, line, mtr);
+ err = btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
+ btr_cursor, has_search_latch,
+ file, line, mtr);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
cursor->trx_if_known = NULL;
+ return err;
}
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,
@@ -506,6 +508,8 @@ btr_pcur_open_at_index_side(
(0=leaf) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
+ dberr_t err = DB_SUCCESS;
+
pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
@@ -514,13 +518,15 @@ btr_pcur_open_at_index_side(
btr_pcur_init(pcur);
}
- btr_cur_open_at_index_side(from_left, index, latch_mode,
- btr_pcur_get_btr_cur(pcur), level, mtr);
+ err = btr_cur_open_at_index_side(from_left, index, latch_mode,
+ btr_pcur_get_btr_cur(pcur), level, mtr);
pcur->pos_state = BTR_PCUR_IS_POSITIONED;
pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
pcur->trx_if_known = NULL;
+
+ return (err);
}
/**********************************************************************//**
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 2e8e4139843..b35ab9df338 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2015, MariaDB Corporation.
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
@@ -97,9 +97,6 @@ extern buf_block_t* back_block1; /*!< first block, for --apply-log */
extern buf_block_t* back_block2; /*!< second block, for page reorganize */
#endif /* !UNIV_HOTBACKUP */
-/** Magic value to use instead of checksums when they are disabled */
-#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
-
/** @brief States of a control block
@see buf_page_t
@@ -431,7 +428,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
- mtr_t* mtr); /*!< in: mini-transaction */
+ mtr_t* mtr, /*!< in: mini-transaction */
+ dberr_t* err = NULL); /*!< out: error code */
/********************************************************************//**
Initializes a page to the buffer buf_pool. The page is usually not read
from a file even if it cannot be found in the buffer buf_pool. This is one
@@ -1614,8 +1612,14 @@ struct buf_page_t{
operation needed. */
unsigned key_version; /*!< key version for this block */
- bool page_encrypted; /*!< page is encrypted */
+ bool page_encrypted; /*!< page is page encrypted */
bool page_compressed;/*!< page is page compressed */
+ ulint stored_checksum;/*!< stored page checksum if page
+ encrypted */
+ bool encrypted; /*!< page is still encrypted */
+ ulint calculated_checksum;
+ /*!< calculated checksum if page
+ encrypted */
ulint real_size; /*!< Real size of the page
Normal pages == UNIV_PAGE_SIZE
diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic
index 89c35caa815..8c8a3c9f975 100644
--- a/storage/xtradb/include/buf0buf.ic
+++ b/storage/xtradb/include/buf0buf.ic
@@ -689,6 +689,10 @@ buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
{
+ if (!block) {
+ return NULL;
+ }
+
SRV_CORRUPT_TABLE_CHECK(block, return(0););
switch (buf_block_get_state(block)) {
@@ -696,6 +700,9 @@ buf_block_get_frame(
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_ZIP_DIRTY:
case BUF_BLOCK_NOT_USED:
+ if (block->page.encrypted) {
+ goto ok;
+ }
ut_error;
break;
case BUF_BLOCK_FILE_PAGE:
diff --git a/storage/xtradb/include/buf0checksum.h b/storage/xtradb/include/buf0checksum.h
index cd21781dc6e..6818345f965 100644
--- a/storage/xtradb/include/buf0checksum.h
+++ b/storage/xtradb/include/buf0checksum.h
@@ -28,11 +28,10 @@ Created Aug 11, 2011 Vasil Dimov
#include "univ.i"
-#ifndef UNIV_INNOCHECKSUM
-
#include "buf0types.h"
-#endif /* !UNIV_INNOCHECKSUM */
+/** Magic value to use instead of checksums when they are disabled */
+#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
/********************************************************************//**
Calculates a page CRC32 which is stored to the page when it is written
@@ -70,8 +69,6 @@ buf_calc_page_old_checksum(
/*=======================*/
const byte* page); /*!< in: buffer page */
-#ifndef UNIV_INNOCHECKSUM
-
/********************************************************************//**
Return a printable string describing the checksum algorithm.
@return algorithm name */
@@ -83,6 +80,4 @@ buf_checksum_algorithm_name(
extern ulong srv_checksum_algorithm;
-#endif /* !UNIV_INNOCHECKSUM */
-
#endif /* buf0checksum_h */
diff --git a/storage/xtradb/include/buf0lru.h b/storage/xtradb/include/buf0lru.h
index 6415540178c..f421e329bf0 100644
--- a/storage/xtradb/include/buf0lru.h
+++ b/storage/xtradb/include/buf0lru.h
@@ -28,7 +28,9 @@ Created 11/5/1995 Heikki Tuuri
#include "univ.i"
#ifndef UNIV_HOTBACKUP
+#ifndef UNIV_INNOCHECKSUM
#include "ut0byte.h"
+#endif
#include "buf0types.h"
// Forward declaration
diff --git a/storage/xtradb/include/buf0rea.h b/storage/xtradb/include/buf0rea.h
index 9adeaa7455a..f0652b5d2cd 100644
--- a/storage/xtradb/include/buf0rea.h
+++ b/storage/xtradb/include/buf0rea.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -39,10 +40,12 @@ UNIV_INTERN
ibool
buf_read_page(
/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- trx_t* trx);
+ ulint space, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
+ ulint offset, /*!< in: page number */
+ trx_t* trx, /*!< in: trx */
+ buf_page_t** bpage /*!< out: page */
+);
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index dab917e18db..bb206dde72b 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/include/db0err.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -132,6 +133,11 @@ enum dberr_t {
/*< Too many words in a phrase */
DB_TOO_BIG_FOR_REDO, /* Record length greater than 10%
of redo log */
+ DB_ENCRYPTED_DECRYPT_FAILED, /* Tablespace encrypted and
+ decrypt operaton failed because
+ of missing key management plugin,
+ or missing or incorrect key or
+ incorret AES method or algorithm. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/xtradb/include/dict0crea.h b/storage/xtradb/include/dict0crea.h
index c40e5356ece..3b746fcf83c 100644
--- a/storage/xtradb/include/dict0crea.h
+++ b/storage/xtradb/include/dict0crea.h
@@ -113,6 +113,17 @@ UNIV_INTERN
dberr_t
dict_create_or_check_foreign_constraint_tables(void);
/*================================================*/
+
+/********************************************************************//**
+Construct foreign key constraint defintion from data dictionary information.
+*/
+UNIV_INTERN
+char*
+dict_foreign_def_get(
+/*=================*/
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx); /*!< in: trx */
+
/********************************************************************//**
Generate a foreign key constraint name when it was not named by the user.
A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER,
@@ -177,6 +188,7 @@ UNIV_INTERN
dberr_t
dict_create_add_foreign_to_dictionary(
/*==================================*/
+ dict_table_t* table, /*!< in: table */
const char* name, /*!< in: table name */
const dict_foreign_t* foreign,/*!< in: foreign key */
trx_t* trx) /*!< in/out: dictionary transaction */
diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h
index 09b43fe0e71..5dfdba54f29 100644
--- a/storage/xtradb/include/dict0dict.h
+++ b/storage/xtradb/include/dict0dict.h
@@ -596,10 +596,17 @@ dict_foreign_find_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
__attribute__((nonnull(1,3), warn_unused_result));
/**********************************************************************//**
Returns a column's name.
@@ -691,10 +698,18 @@ dict_foreign_qualify_index(
/*!< in: whether to check
charsets. only has an effect
if types_idx != NULL */
- ulint check_null)
+ ulint check_null,
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
+ ulint* error, /*!< out: error code */
+ ulint* err_col_no,
+ /*!< out: column number where
+ error happened */
+ dict_index_t** err_index)
+ /*!< out: index where error
+ happened */
+
__attribute__((nonnull(1,3), warn_unused_result));
#ifdef UNIV_DEBUG
/********************************************************************//**
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index d5cd8c595c2..9c43829cecf 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2015, MariaDB Corporation.
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
@@ -51,6 +51,9 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0types.h"
#include "fts0fts.h"
#include "os0once.h"
+#include "fil0fil.h"
+#include <my_crypt.h>
+#include "fil0crypt.h"
#include <set>
#include <algorithm>
#include <iterator>
@@ -1030,6 +1033,8 @@ struct dict_table_t{
table_id_t id; /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */
char* name; /*!< table name */
+ void* thd; /*!< thd */
+ fil_space_crypt_t *crypt_data; /*!< crypt data if present */
const char* dir_path_of_temp_table;/*!< NULL or the directory path
where a TEMPORARY table that was explicitly
created by a user should be placed if
@@ -1342,6 +1347,7 @@ struct dict_table_t{
locks; /*!< list of locks on the table; protected
by lock_sys->mutex */
ibool is_corrupt;
+ ibool is_encrypted;
#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_DEBUG
diff --git a/storage/xtradb/include/fil0crypt.h b/storage/xtradb/include/fil0crypt.h
index 4fd41d4b789..a9491e3131f 100644
--- a/storage/xtradb/include/fil0crypt.h
+++ b/storage/xtradb/include/fil0crypt.h
@@ -381,6 +381,17 @@ fil_crypt_set_encrypt_tables(
/*=========================*/
uint val); /*!< in: New srv_encrypt_tables setting */
+/******************************************************************
+Calculate post encryption checksum
+@return page checksum or BUF_NO_CHECKSUM_MAGIC
+not needed. */
+UNIV_INTERN
+ulint
+fil_crypt_calculate_checksum(
+/*=========================*/
+ ulint zip_size, /*!< in: zip_size or 0 */
+ byte* dst_frame); /*!< in: page where to calculate */
+
#ifndef UNIV_NONINL
#include "fil0crypt.ic"
#endif
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index 66ceffbed26..2a3995519a7 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -207,6 +207,7 @@ struct fsp_open_info {
ulint flags; /*!< Tablespace flags */
ulint encryption_error; /*!< if an encryption error occurs */
fil_space_crypt_t* crypt_data; /*!< crypt data */
+ dict_table_t* table; /*!< table */
};
struct fil_space_t;
@@ -828,7 +829,8 @@ fil_open_single_table_tablespace(
ulint flags, /*!< in: tablespace flags */
const char* tablename, /*!< in: table name in the
databasename/tablename format */
- const char* filepath) /*!< in: tablespace filepath */
+ const char* filepath, /*!< in: tablespace filepath */
+ dict_table_t* table) /*!< in: table */
__attribute__((nonnull(5), warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h
index 22cb3eed42d..724453cb4f6 100644
--- a/storage/xtradb/include/ha_prototypes.h
+++ b/storage/xtradb/include/ha_prototypes.h
@@ -28,14 +28,17 @@ Created 5/11/2006 Osku Salerma
#define HA_INNODB_PROTOTYPES_H
#include "my_dbug.h"
-#include "mysqld_error.h"
#include "my_compare.h"
#include "my_sys.h"
#include "m_string.h"
-#include "debug_sync.h"
#include "my_base.h"
+#ifndef UNIV_INNOCHECKSUM
+#include "mysqld_error.h"
+#include "debug_sync.h"
#include "trx0types.h"
+#endif
+
#include "m_ctype.h" /* CHARSET_INFO */
// Forward declarations
@@ -81,6 +84,8 @@ innobase_raw_format(
ulint buf_size); /*!< in: output buffer size
in bytes */
+#ifndef UNIV_INNOCHECKSUM
+
/*****************************************************************//**
Invalidates the MySQL query cache for the table. */
UNIV_INTERN
@@ -97,6 +102,8 @@ innobase_invalidate_query_cache(
ulint full_name_len); /*!< in: full name length where
also the null chars count */
+#endif /* #ifndef UNIV_INNOCHECKSUM */
+
/*****************************************************************//**
Convert a table or index name to the MySQL system_charset_info (UTF-8)
and quote it if needed.
@@ -620,5 +627,22 @@ innobase_convert_to_filename_charset(
const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */
-
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ trx_t* trx, /*!< in: trx */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...);
+/********************************************************************//**
+Helper function to push warnings from InnoDB internals to SQL-layer. */
+UNIV_INTERN
+void
+ib_push_warning(
+ void* ithd, /*!< in: thd */
+ ulint error, /*!< in: error code to push as warning */
+ const char *format,/*!< in: warning message */
+ ...);
#endif /* HA_INNODB_PROTOTYPES_H */
diff --git a/storage/xtradb/include/os0file.h b/storage/xtradb/include/os0file.h
index 88ba7e18ac3..e9faac0d945 100644
--- a/storage/xtradb/include/os0file.h
+++ b/storage/xtradb/include/os0file.h
@@ -1,6 +1,6 @@
/***********************************************************************
-Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2015, MariaDB Corporation.
@@ -405,10 +405,10 @@ to original un-instrumented file I/O APIs */
enum os_file_type_t {
OS_FILE_TYPE_UNKNOWN = 0,
- OS_FILE_TYPE_FILE, /* regular file */
+ OS_FILE_TYPE_FILE, /* regular file
+ (or a character/block device) */
OS_FILE_TYPE_DIR, /* directory */
- OS_FILE_TYPE_LINK, /* symbolic link */
- OS_FILE_TYPE_BLOCK /* block device */
+ OS_FILE_TYPE_LINK /* symbolic link */
};
/* Maximum path string length in bytes when referring to tables with in the
diff --git a/storage/xtradb/include/page0cur.ic b/storage/xtradb/include/page0cur.ic
index 028d33b17aa..6e068d9f739 100644
--- a/storage/xtradb/include/page0cur.ic
+++ b/storage/xtradb/include/page0cur.ic
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, MariaDB Corporation.
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
@@ -39,7 +40,10 @@ page_cur_get_page(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
- ut_ad(page_align(cur->rec) == cur->block->frame);
+
+ if (cur->rec) {
+ ut_ad(page_align(cur->rec) == cur->block->frame);
+ }
return(page_align(cur->rec));
}
@@ -54,7 +58,11 @@ page_cur_get_block(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
- ut_ad(page_align(cur->rec) == cur->block->frame);
+
+ if (cur->rec) {
+ ut_ad(page_align(cur->rec) == cur->block->frame);
+ }
+
return(cur->block);
}
@@ -80,7 +88,10 @@ page_cur_get_rec(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
- ut_ad(page_align(cur->rec) == cur->block->frame);
+
+ if (cur->rec) {
+ ut_ad(page_align(cur->rec) == cur->block->frame);
+ }
return(cur->rec);
}
diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h
index 6940040a130..2da5d793fa9 100644
--- a/storage/xtradb/include/page0page.h
+++ b/storage/xtradb/include/page0page.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -28,6 +28,10 @@ Created 2/2/1994 Heikki Tuuri
#include "univ.i"
+#include "buf0types.h"
+
+#ifndef UNIV_INNOCHECKSUM
+
#include "page0types.h"
#include "fil0fil.h"
#include "buf0buf.h"
@@ -1110,6 +1114,24 @@ page_find_rec_with_heap_no(
const rec_t*
page_find_rec_max_not_deleted(
const page_t* page);
+
+#endif /* #ifndef UNIV_INNOCHECKSUM */
+
+/** Issue a warning when the checksum that is stored in the page is valid,
+but different than the global setting innodb_checksum_algorithm.
+@param[in] current_algo current checksum algorithm
+@param[in] page_checksum page valid checksum
+@param[in] space_id tablespace id
+@param[in] page_no page number */
+void
+page_warn_strict_checksum(
+ srv_checksum_algorithm_t curr_algo,
+ srv_checksum_algorithm_t page_checksum,
+ ulint space_id,
+ ulint page_no);
+
+#ifndef UNIV_INNOCHECKSUM
+
#ifdef UNIV_MATERIALIZE
#undef UNIV_INLINE
#define UNIV_INLINE UNIV_INLINE_ORIGINAL
@@ -1119,4 +1141,6 @@ page_find_rec_max_not_deleted(
#include "page0page.ic"
#endif
+#endif /* #ifndef UNIV_INNOCHECKSUM */
+
#endif
diff --git a/storage/xtradb/include/page0types.h b/storage/xtradb/include/page0types.h
index 95143a4bb44..74ad6f72f7e 100644
--- a/storage/xtradb/include/page0types.h
+++ b/storage/xtradb/include/page0types.h
@@ -107,6 +107,8 @@ struct page_zip_stat_t {
{ }
};
+#ifndef UNIV_INNOCHECKSUM
+
/** Compression statistics types */
typedef map<index_id_t, page_zip_stat_t> page_zip_stat_per_index_t;
@@ -119,6 +121,8 @@ extern ib_mutex_t page_zip_stat_per_index_mutex;
extern mysql_pfs_key_t page_zip_stat_per_index_mutex_key;
#endif /* HAVE_PSI_INTERFACE */
+#endif /* !UNIV_INNOCHECKSUM */
+
/**********************************************************************//**
Write the "deleted" flag of a record on a compressed page. The flag must
already have been written on the uncompressed page. */
diff --git a/storage/xtradb/include/page0zip.h b/storage/xtradb/include/page0zip.h
index 2f9efc4a40c..41eb1e35d78 100644
--- a/storage/xtradb/include/page0zip.h
+++ b/storage/xtradb/include/page0zip.h
@@ -32,13 +32,17 @@ Created June 2005 by Marko Makela
# define UNIV_INLINE
#endif
-#include "mtr0types.h"
+#ifndef UNIV_INNOCHECKSUM
#include "page0types.h"
-#include "buf0types.h"
+#include "mtr0types.h"
#include "dict0types.h"
#include "srv0srv.h"
#include "trx0types.h"
#include "mem0mem.h"
+#else
+#include "univ.i"
+#endif /* !UNIV_INNOCHECKSUM */
+#include "buf0types.h"
/* Compression level to be used by zlib. Settable by user. */
extern uint page_zip_level;
@@ -50,6 +54,7 @@ extern uint page_zip_level;
compression algorithm changes in zlib. */
extern my_bool page_zip_log_pages;
+#ifndef UNIV_INNOCHECKSUM
/**********************************************************************//**
Determine the size of a compressed page in bytes.
@return size in bytes */
@@ -159,6 +164,8 @@ page_zip_simple_validate(
descriptor */
#endif /* UNIV_DEBUG */
+#endif /* !UNIV_INNOCHECKSUM */
+
#ifdef UNIV_ZIP_DEBUG
/**********************************************************************//**
Check that the compressed and decompressed pages match.
@@ -185,6 +192,7 @@ page_zip_validate(
__attribute__((nonnull(1,2)));
#endif /* UNIV_ZIP_DEBUG */
+#ifndef UNIV_INNOCHECKSUM
/**********************************************************************//**
Determine how big record can be inserted without recompressing the page.
@return a positive number indicating the maximum size of a record
@@ -452,6 +460,8 @@ page_zip_parse_compress(
page_zip_des_t* page_zip)/*!< out: compressed page */
__attribute__((nonnull(1,2)));
+#endif /* !UNIV_INNOCHECKSUM */
+
/**********************************************************************//**
Calculate the compressed page checksum.
@return page checksum */
@@ -474,6 +484,9 @@ page_zip_verify_checksum(
/*=====================*/
const void* data, /*!< in: compressed page */
ulint size); /*!< in: size of compressed page */
+
+#ifndef UNIV_INNOCHECKSUM
+
/**********************************************************************//**
Write a log record of compressing an index page without the data on the page. */
UNIV_INLINE
@@ -506,6 +519,8 @@ void
page_zip_reset_stat_per_index();
/*===========================*/
+#endif /* !UNIV_INNOCHECKSUM */
+
#ifndef UNIV_HOTBACKUP
/** Check if a pointer to an uncompressed page matches a compressed page.
When we IMPORT a tablespace the blocks and accompanying frames are allocted
@@ -531,8 +546,10 @@ from outside the buffer pool.
# define UNIV_INLINE UNIV_INLINE_ORIGINAL
#endif
+#ifndef UNIV_INNOCHECKSUM
#ifndef UNIV_NONINL
# include "page0zip.ic"
#endif
+#endif /* !UNIV_INNOCHECKSUM */
#endif /* page0zip_h */
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index 78a402d488c..45300bc2ded 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -514,7 +514,6 @@ extern my_bool srv_stats_sample_traditional;
extern ibool srv_use_doublewrite_buf;
extern ulong srv_doublewrite_batch_size;
-extern ulong srv_checksum_algorithm;
extern ulong srv_log_arch_expire_sec;
diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index 241f210869f..8105d1f318b 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -45,10 +45,10 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 5
#define INNODB_VERSION_MINOR 6
-#define INNODB_VERSION_BUGFIX 24
+#define INNODB_VERSION_BUGFIX 25
#ifndef PERCONA_INNODB_VERSION
-#define PERCONA_INNODB_VERSION 72.2
+#define PERCONA_INNODB_VERSION 73.1
#endif
/* Enable UNIV_LOG_ARCHIVE in XtraDB */
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index b3d9e470816..26d868ca94d 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -3027,7 +3027,8 @@ lock_rec_inherit_to_gap(
&& !((srv_locks_unsafe_for_binlog
|| lock->trx->isolation_level
<= TRX_ISO_READ_COMMITTED)
- && lock_get_mode(lock) == LOCK_X)) {
+ && lock_get_mode(lock) ==
+ (lock->trx->duplicates ? LOCK_S : LOCK_X))) {
lock_rec_add_to_queue(
LOCK_REC | LOCK_GAP | lock_get_mode(lock),
diff --git a/storage/xtradb/log/log0crypt.cc b/storage/xtradb/log/log0crypt.cc
index 38b82d6ceb4..8c4fd623fc6 100644
--- a/storage/xtradb/log/log0crypt.cc
+++ b/storage/xtradb/log/log0crypt.cc
@@ -131,12 +131,13 @@ log_blocks_crypt(
const byte* block, /*!< in: blocks before encrypt/decrypt*/
ulint size, /*!< in: size of block */
byte* dst_block, /*!< out: blocks after encrypt/decrypt */
- bool is_encrypt) /*!< in: encrypt or decrypt*/
+ int what) /*!< in: encrypt or decrypt*/
{
byte *log_block = (byte*)block;
Crypt_result rc = MY_AES_OK;
uint dst_len;
byte aes_ctr_counter[MY_AES_BLOCK_SIZE];
+ byte is_encrypt= what == ENCRYPTION_FLAG_ENCRYPT;
lsn_t lsn = is_encrypt ? log_sys->lsn : srv_start_lsn;
const uint src_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE;
@@ -174,21 +175,13 @@ log_blocks_crypt(
bzero(aes_ctr_counter + 15, 1);
int rc;
- if (is_encrypt) {
- rc = encryption_encrypt(log_block + LOG_BLOCK_HDR_SIZE, src_len,
- dst_block + LOG_BLOCK_HDR_SIZE, &dst_len,
- (unsigned char*)(info->crypt_key), 16,
- aes_ctr_counter, MY_AES_BLOCK_SIZE, 1,
- LOG_DEFAULT_ENCRYPTION_KEY,
- info->key_version);
- } else {
- rc = encryption_decrypt(log_block + LOG_BLOCK_HDR_SIZE, src_len,
- dst_block + LOG_BLOCK_HDR_SIZE, &dst_len,
- (unsigned char*)(info->crypt_key), 16,
- aes_ctr_counter, MY_AES_BLOCK_SIZE, 1,
- LOG_DEFAULT_ENCRYPTION_KEY,
- info->key_version);
- }
+ rc = encryption_crypt(log_block + LOG_BLOCK_HDR_SIZE, src_len,
+ dst_block + LOG_BLOCK_HDR_SIZE, &dst_len,
+ (unsigned char*)(info->crypt_key), 16,
+ aes_ctr_counter, MY_AES_BLOCK_SIZE,
+ what | ENCRYPTION_FLAG_NOPAD,
+ LOG_DEFAULT_ENCRYPTION_KEY,
+ info->key_version);
ut_a(rc == MY_AES_OK);
ut_a(dst_len == src_len);
@@ -230,10 +223,11 @@ init_crypt_key(
}
uint dst_len;
- int rc= my_aes_encrypt_ecb(info->crypt_msg, sizeof(info->crypt_msg), //src, srclen
- info->crypt_key, &dst_len, //dst, &dstlen
- (unsigned char*)&mysqld_key, sizeof(mysqld_key),
- NULL, 0, 1);
+ int rc= my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_NOPAD|ENCRYPTION_FLAG_ENCRYPT,
+ info->crypt_msg, sizeof(info->crypt_msg), //src, srclen
+ info->crypt_key, &dst_len, //dst, &dstlen
+ (unsigned char*)&mysqld_key, sizeof(mysqld_key),
+ NULL, 0);
if (rc != MY_AES_OK || dst_len != MY_AES_BLOCK_SIZE) {
fprintf(stderr,
@@ -296,7 +290,7 @@ log_blocks_encrypt(
const ulint size, /*!< in: size of blocks, must be multiple of a log block */
byte* dst_block) /*!< out: blocks after encryption */
{
- return log_blocks_crypt(block, size, dst_block, true);
+ return log_blocks_crypt(block, size, dst_block, ENCRYPTION_FLAG_ENCRYPT);
}
/*********************************************************************//**
@@ -366,7 +360,7 @@ log_encrypt_before_write(
byte* dst_frame = (byte*)malloc(size);
//encrypt log blocks content
- Crypt_result result = log_blocks_crypt(block, size, dst_frame, true);
+ Crypt_result result = log_blocks_crypt(block, size, dst_frame, ENCRYPTION_FLAG_ENCRYPT);
if (result == MY_AES_OK) {
ut_ad(block[0] == dst_frame[0]);
@@ -392,7 +386,7 @@ log_decrypt_after_read(
byte* dst_frame = (byte*)malloc(size);
// decrypt log blocks content
- Crypt_result result = log_blocks_crypt(frame, size, dst_frame, false);
+ Crypt_result result = log_blocks_crypt(frame, size, dst_frame, ENCRYPTION_FLAG_DECRYPT);
if (result == MY_AES_OK) {
memcpy(frame, dst_frame, size);
diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc
index cb074cdf4f5..9ef9adf5b74 100644
--- a/storage/xtradb/os/os0file.cc
+++ b/storage/xtradb/os/os0file.cc
@@ -1,6 +1,6 @@
/***********************************************************************
-Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2015, MariaDB Corporation.
@@ -3604,8 +3604,9 @@ os_file_get_status(
stat_info->type = OS_FILE_TYPE_LINK;
break;
case S_IFBLK:
- stat_info->type = OS_FILE_TYPE_BLOCK;
- break;
+ /* Handle block device as regular file. */
+ case S_IFCHR:
+ /* Handle character device as regular file. */
case S_IFREG:
stat_info->type = OS_FILE_TYPE_FILE;
break;
@@ -3614,8 +3615,8 @@ os_file_get_status(
}
- if (check_rw_perm && (stat_info->type == OS_FILE_TYPE_FILE
- || stat_info->type == OS_FILE_TYPE_BLOCK)) {
+ if (check_rw_perm && stat_info->type == OS_FILE_TYPE_FILE) {
+
int fh;
int access;
diff --git a/storage/xtradb/page/page0page.cc b/storage/xtradb/page/page0page.cc
index 4aff88818bb..6adbdeb95a4 100644
--- a/storage/xtradb/page/page0page.cc
+++ b/storage/xtradb/page/page0page.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
This program is free software; you can redistribute it and/or modify it under
@@ -31,6 +31,11 @@ Created 2/2/1994 Heikki Tuuri
#endif
#undef THIS_MODULE
+#include "ha_prototypes.h"
+#include "buf0checksum.h"
+
+#ifndef UNIV_INNOCHECKSUM
+
#include "page0cur.h"
#include "page0zip.h"
#include "buf0buf.h"
@@ -2819,3 +2824,51 @@ page_find_rec_max_not_deleted(
}
return(prev_rec);
}
+
+#endif /* #ifndef UNIV_INNOCHECKSUM */
+
+/** Issue a warning when the checksum that is stored in the page is valid,
+but different than the global setting innodb_checksum_algorithm.
+@param[in] current_algo current checksum algorithm
+@param[in] page_checksum page valid checksum
+@param[in] space_id tablespace id
+@param[in] page_no page number */
+void
+page_warn_strict_checksum(
+ srv_checksum_algorithm_t curr_algo,
+ srv_checksum_algorithm_t page_checksum,
+ ulint space_id,
+ ulint page_no)
+{
+ srv_checksum_algorithm_t curr_algo_nonstrict;
+ switch (curr_algo) {
+ case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+ curr_algo_nonstrict = SRV_CHECKSUM_ALGORITHM_CRC32;
+ break;
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+ curr_algo_nonstrict = SRV_CHECKSUM_ALGORITHM_INNODB;
+ break;
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+ curr_algo_nonstrict = SRV_CHECKSUM_ALGORITHM_NONE;
+ break;
+ default:
+ ut_error;
+ }
+
+#ifdef UNIV_INNOCHECKSUM
+ fprintf(stderr,
+#else
+ ib_logf(IB_LOG_LEVEL_WARN,
+#endif
+ "innodb_checksum_algorithm is set to \"%s\""
+ " but the page [page id: space=" ULINTPF ","
+ " page number=" ULINTPF "] contains a valid checksum \"%s\"."
+ " Accepting the page as valid. Change innodb_checksum_algorithm"
+ " to \"%s\" to silently accept such pages or rewrite all pages"
+ " so that they contain \"%s\" checksum.",
+ buf_checksum_algorithm_name(curr_algo),
+ space_id, page_no,
+ buf_checksum_algorithm_name(page_checksum),
+ buf_checksum_algorithm_name(curr_algo_nonstrict),
+ buf_checksum_algorithm_name(curr_algo_nonstrict));
+}
diff --git a/storage/xtradb/page/page0zip.cc b/storage/xtradb/page/page0zip.cc
index 58559cc438b..42ffd3668d8 100644
--- a/storage/xtradb/page/page0zip.cc
+++ b/storage/xtradb/page/page0zip.cc
@@ -37,30 +37,40 @@ using namespace std;
# include "page0zip.ic"
#endif
#undef THIS_MODULE
+#include "buf0checksum.h"
#include "page0page.h"
+#ifndef UNIV_INNOCHECKSUM
#include "mtr0log.h"
-#include "ut0sort.h"
#include "dict0dict.h"
#include "btr0cur.h"
-#include "page0types.h"
#include "log0recv.h"
+#endif /* !UNIV_INNOCHECKSUM */
#include "zlib.h"
+#include "fil0fil.h"
+#include "ut0sort.h"
+#include "page0types.h"
#ifndef UNIV_HOTBACKUP
+#ifndef UNIV_INNOCHECKSUM
# include "buf0buf.h"
-# include "buf0lru.h"
# include "btr0sea.h"
# include "dict0boot.h"
# include "lock0lock.h"
# include "srv0mon.h"
# include "srv0srv.h"
+#endif /* !UNIV_INNOCHECKSUM */
+# include "buf0lru.h"
# include "ut0crc32.h"
#else /* !UNIV_HOTBACKUP */
-# include "buf0checksum.h"
# define lock_move_reorganize_page(block, temp_block) ((void) 0)
# define buf_LRU_stat_inc_unzip() ((void) 0)
#endif /* !UNIV_HOTBACKUP */
+#ifdef UNIV_INNOCHECKSUM
+#include "mach0data.h"
+#endif /* UNIV_INNOCHECKSUM */
+
#ifndef UNIV_HOTBACKUP
+#ifndef UNIV_INNOCHECKSUM
/** Statistics on compression, indexed by page_zip_des_t::ssize - 1 */
UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_SSIZE_MAX];
/** Statistics on compression, indexed by index->id */
@@ -70,6 +80,7 @@ UNIV_INTERN ib_mutex_t page_zip_stat_per_index_mutex;
#ifdef HAVE_PSI_INTERFACE
UNIV_INTERN mysql_pfs_key_t page_zip_stat_per_index_mutex_key;
#endif /* HAVE_PSI_INTERFACE */
+#endif /* !UNIV_INNOCHECKSUM */
#endif /* !UNIV_HOTBACKUP */
/* Compression level to be used by zlib. Settable by user. */
@@ -82,6 +93,8 @@ UNIV_INTERN my_bool page_zip_log_pages = false;
/* Please refer to ../include/page0zip.ic for a description of the
compressed page format. */
+#ifndef UNIV_INNOCHECKSUM
+
/* The infimum and supremum records are omitted from the compressed page.
On compress, we compare that the records are there, and on uncompress we
restore the records. */
@@ -105,6 +118,8 @@ static const byte supremum_extra_data[] = {
0x65, 0x6d, 0x75, 0x6d /* "supremum" */
};
+#endif /* !UNIV_INNOCHECKSUM */
+
/** Assert that a block of memory is filled with zero bytes.
Compare at most sizeof(field_ref_zero) bytes.
@param b in: memory block
@@ -151,6 +166,7 @@ page_zip_fail_func(
# define page_zip_fail(fmt_args) /* empty */
#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
+#ifndef UNIV_INNOCHECKSUM
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
Determine the guaranteed free space on an empty page.
@@ -4843,6 +4859,7 @@ corrupt:
return(ptr + 8 + size + trailer_size);
}
+#endif /* !UNIV_INNOCHECKSUM */
/**********************************************************************//**
Calculate the compressed page checksum.
@@ -4918,6 +4935,10 @@ page_zip_verify_checksum(
stored = static_cast<ib_uint32_t>(mach_read_from_4(
static_cast<const unsigned char*>(data) + FIL_PAGE_SPACE_OR_CHKSUM));
+ ulint page_no = mach_read_from_4(static_cast<const unsigned char*> (data) + FIL_PAGE_OFFSET);
+ ulint space_id = mach_read_from_4(static_cast<const unsigned char*>
+ (data) + FIL_PAGE_SPACE_ID);
+
#if FIL_PAGE_LSN % 8
#error "FIL_PAGE_LSN must be 64 bit aligned"
#endif
@@ -4938,40 +4959,113 @@ page_zip_verify_checksum(
return(TRUE);
}
+ const srv_checksum_algorithm_t curr_algo =
+ static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
+
+ if (curr_algo == SRV_CHECKSUM_ALGORITHM_NONE) {
+ return(TRUE);
+ }
+
calc = static_cast<ib_uint32_t>(page_zip_calc_checksum(
- data, size, static_cast<srv_checksum_algorithm_t>(
- srv_checksum_algorithm)));
+ data, size, curr_algo));
if (stored == calc) {
return(TRUE);
}
- switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) {
+ switch (curr_algo) {
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
- case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
- case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
- return(stored == calc);
case SRV_CHECKSUM_ALGORITHM_CRC32:
+
if (stored == BUF_NO_CHECKSUM_MAGIC) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_NONE,
+ space_id, page_no);
+ }
+
return(TRUE);
}
- crc32 = calc;
+
innodb = static_cast<ib_uint32_t>(page_zip_calc_checksum(
data, size, SRV_CHECKSUM_ALGORITHM_INNODB));
+
+ if (stored == innodb) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_INNODB,
+ space_id, page_no);
+ }
+
+ return(TRUE);
+ }
+
break;
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
case SRV_CHECKSUM_ALGORITHM_INNODB:
+
if (stored == BUF_NO_CHECKSUM_MAGIC) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_NONE,
+ space_id, page_no);
+ }
+
return(TRUE);
}
+
crc32 = static_cast<ib_uint32_t>(page_zip_calc_checksum(
data, size, SRV_CHECKSUM_ALGORITHM_CRC32));
- innodb = calc;
+
+ if (stored == crc32) {
+ if (curr_algo
+ == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_CRC32,
+ space_id, page_no);
+ }
+
+ return(TRUE);
+ }
+
+ break;
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+
+ crc32 = static_cast<ib_uint32_t>(page_zip_calc_checksum(
+ data, size, SRV_CHECKSUM_ALGORITHM_CRC32));
+
+ if (stored == crc32) {
+ page_warn_strict_checksum(
+ curr_algo, SRV_CHECKSUM_ALGORITHM_CRC32,
+ space_id, page_no);
+
+ return(TRUE);
+ }
+
+ innodb = static_cast<ib_uint32_t>(page_zip_calc_checksum(
+ data, size, SRV_CHECKSUM_ALGORITHM_INNODB));
+
+ if (stored == innodb) {
+ page_warn_strict_checksum(
+ curr_algo,
+ SRV_CHECKSUM_ALGORITHM_INNODB,
+ space_id, page_no);
+ return(TRUE);
+ }
+
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
- return(TRUE);
+ ut_error;
/* no default so the compiler will emit a warning if new enum
is added and not handled here */
}
- return(stored == crc32 || stored == innodb);
+ return(FALSE);
}
diff --git a/storage/xtradb/row/row0import.cc b/storage/xtradb/row/row0import.cc
index d5f766ef51b..88846976064 100644
--- a/storage/xtradb/row/row0import.cc
+++ b/storage/xtradb/row/row0import.cc
@@ -3651,7 +3651,7 @@ row_import_for_mysql(
err = fil_open_single_table_tablespace(
true, true, table->space,
dict_tf_to_fsp_flags(table->flags),
- table->name, filepath);
+ table->name, filepath, table);
DBUG_EXECUTE_IF("ib_import_open_tablespace_failure",
err = DB_TABLESPACE_NOT_FOUND;);
diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc
index fb719266a16..3f22a7d422d 100644
--- a/storage/xtradb/row/row0ins.cc
+++ b/storage/xtradb/row/row0ins.cc
@@ -2350,7 +2350,7 @@ row_ins_clust_index_entry_low(
{
btr_cur_t cursor;
ulint* offsets = NULL;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
big_rec_t* big_rec = NULL;
mtr_t mtr;
mem_heap_t* offsets_heap = NULL;
@@ -2380,9 +2380,16 @@ row_ins_clust_index_entry_low(
the function will return in both low_match and up_match of the
cursor sensible values */
- btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
+ err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
+ if (err != DB_SUCCESS) {
+ index->table->is_encrypted = true;
+ index->table->ibd_file_missing = true;
+ mtr_commit(&mtr);
+ goto func_exit;
+ }
+
#ifdef UNIV_DEBUG
{
page_t* page = btr_cur_get_page(&cursor);
@@ -2696,9 +2703,22 @@ row_ins_sec_index_entry_low(
search_mode |= BTR_IGNORE_SEC_UNIQUE;
}
- btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
- search_mode,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
+ search_mode,
+ &cursor, 0, __FILE__, __LINE__, &mtr);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning(trx->mysql_thd,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ index->table->name);
+ index->table->is_encrypted = true;
+ }
+ goto func_exit;
+ }
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
/* The insert was buffered during the search: we are done */
@@ -2765,6 +2785,8 @@ row_ins_sec_index_entry_low(
goto func_exit;
}
+ DEBUG_SYNC_C("row_ins_sec_index_entry_dup_locks_created");
+
/* We did not find a duplicate and we have now
locked with s-locks the necessary records to
prevent any insertion of a duplicate by another
diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc
index 2df9c2bea82..20fc1768eda 100644
--- a/storage/xtradb/row/row0merge.cc
+++ b/storage/xtradb/row/row0merge.cc
@@ -1433,6 +1433,13 @@ row_merge_read_clustered_index(
row_ext_t* ext;
page_cur_t* cur = btr_pcur_get_page_cur(&pcur);
+ /* Do not continue if table pages are still encrypted */
+ if (old_table->is_encrypted || new_table->is_encrypted) {
+ err = DB_ENCRYPTED_DECRYPT_FAILED;
+ trx->error_key_num = 0;
+ goto func_exit;
+ }
+
page_cur_move_to_next(cur);
if (page_cur_is_after_last(cur)) {
@@ -3762,6 +3769,17 @@ row_merge_build_indexes(
pct_cost = COST_READ_CLUSTERED_INDEX * 100 / (total_static_cost + total_dynamic_cost);
+ /* Do not continue if we can't encrypt table pages */
+ if (old_table->is_encrypted || new_table->is_encrypted) {
+ error = DB_ENCRYPTED_DECRYPT_FAILED;
+ ib_push_warning(trx->mysql_thd, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ old_table->is_encrypted ? old_table->name : new_table->name);
+ goto func_exit;
+ }
+
/* Read clustered index of the table and create files for
secondary index entries for merge sort */
diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc
index efc5c568cd5..64c6783f1e4 100644
--- a/storage/xtradb/row/row0mysql.cc
+++ b/storage/xtradb/row/row0mysql.cc
@@ -622,6 +622,8 @@ handle_new_error:
case DB_FTS_INVALID_DOCID:
case DB_INTERRUPTED:
case DB_DICT_CHANGED:
+ case DB_TABLE_NOT_FOUND:
+ case DB_ENCRYPTED_DECRYPT_FAILED:
if (savept) {
/* Roll back the latest, possibly incomplete insertion
or update */
@@ -1314,7 +1316,13 @@ row_insert_for_mysql(
prebuilt->table->name);
return(DB_TABLESPACE_NOT_FOUND);
-
+ } else if (prebuilt->table->is_encrypted) {
+ ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s in tablespace %lu encrypted."
+ "However key management plugin or used key_id is not found or"
+ " used encryption algorithm or method does not match.",
+ prebuilt->table->name, prebuilt->table->space);
+ return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
@@ -1326,18 +1334,14 @@ row_insert_for_mysql(
mem_analyze_corruption(prebuilt);
ut_error;
- } else if (srv_created_new_raw || srv_force_recovery) {
- fputs("InnoDB: A new raw disk partition was initialized or\n"
- "InnoDB: innodb_force_recovery is on: we do not allow\n"
+ } else if (srv_force_recovery) {
+ fputs("InnoDB: innodb_force_recovery is on: we do not allow\n"
"InnoDB: database modifications by the user. Shut down\n"
"InnoDB: mysqld and edit my.cnf so that"
- " newraw is replaced\n"
- "InnoDB: with raw, and innodb_force_... is removed.\n",
+ "InnoDB: innodb_force_... is removed.\n",
stderr);
- if(srv_force_recovery) {
- return(DB_READ_ONLY);
- }
- return(DB_ERROR);
+
+ return(DB_READ_ONLY);
}
trx->op_info = "inserting";
@@ -1717,6 +1721,13 @@ row_update_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
return(DB_ERROR);
+ } else if (prebuilt->table->is_encrypted) {
+ ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s in tablespace %lu encrypted."
+ "However key management plugin or used key_id is not found or"
+ " used encryption algorithm or method does not match.",
+ prebuilt->table->name, prebuilt->table->space);
+ return (DB_TABLE_NOT_FOUND);
}
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
@@ -1732,18 +1743,14 @@ row_update_for_mysql(
ut_error;
}
- if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
- fputs("InnoDB: A new raw disk partition was initialized or\n"
- "InnoDB: innodb_force_recovery is on: we do not allow\n"
+ if (UNIV_UNLIKELY(srv_force_recovery)) {
+ fputs("InnoDB: innodb_force_recovery is on: we do not allow\n"
"InnoDB: database modifications by the user. Shut down\n"
- "InnoDB: mysqld and edit my.cnf so that newraw"
- " is replaced\n"
- "InnoDB: with raw, and innodb_force_... is removed.\n",
+ "InnoDB: mysqld and edit my.cnf so that"
+ "InnoDB: innodb_force_... is removed.\n",
stderr);
- if(srv_force_recovery) {
- return(DB_READ_ONLY);
- }
- return(DB_ERROR);
+
+ return(DB_READ_ONLY);
}
DEBUG_SYNC_C("innodb_row_update_for_mysql_begin");
@@ -2254,22 +2261,6 @@ row_create_table_for_mysql(
goto err_exit;
);
- if (srv_created_new_raw) {
- fputs("InnoDB: A new raw disk partition was initialized:\n"
- "InnoDB: we do not allow database modifications"
- " by the user.\n"
- "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
- " is replaced with raw.\n", stderr);
-err_exit:
- dict_mem_table_free(table);
-
- if (commit) {
- trx_commit_for_mysql(trx);
- }
-
- return(DB_ERROR);
- }
-
trx->op_info = "creating table";
if (row_mysql_is_system_table(table->name)) {
@@ -2280,7 +2271,19 @@ err_exit:
"InnoDB: MySQL system tables must be"
" of the MyISAM type!\n",
table->name);
- goto err_exit;
+
+#ifndef DBUG_OFF
+err_exit:
+#endif /* !DBUG_OFF */
+ dict_mem_table_free(table);
+
+ if (commit) {
+ trx_commit_for_mysql(trx);
+ }
+
+ trx->op_info = "";
+
+ return(DB_ERROR);
}
trx_start_if_not_started_xa(trx);
@@ -3365,16 +3368,6 @@ row_truncate_table_for_mysql(
ut_ad(table);
- if (srv_created_new_raw) {
- fputs("InnoDB: A new raw disk partition was initialized:\n"
- "InnoDB: we do not allow database modifications"
- " by the user.\n"
- "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
- " is replaced with raw.\n", stderr);
-
- return(DB_ERROR);
- }
-
if (dict_table_is_discarded(table)) {
return(DB_TABLESPACE_DELETED);
} else if (table->ibd_file_missing) {
@@ -3864,16 +3857,6 @@ row_drop_table_for_mysql(
ut_a(name != NULL);
- if (srv_created_new_raw) {
- fputs("InnoDB: A new raw disk partition was initialized:\n"
- "InnoDB: we do not allow database modifications"
- " by the user.\n"
- "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
- " is replaced with raw.\n", stderr);
-
- DBUG_RETURN(DB_ERROR);
- }
-
/* The table name is prefixed with the database name and a '/'.
Certain table names starting with 'innodb_' have their special
meaning regardless of the database name. Thus, we need to
@@ -3964,6 +3947,19 @@ row_drop_table_for_mysql(
goto funct_exit;
}
+ /* If table is encrypted and table page encryption failed
+ mark this table read only. */
+ if (table->is_encrypted) {
+
+ if (table->can_be_evicted) {
+ dict_table_move_from_lru_to_non_lru(table);
+ }
+
+ dict_table_close(table, TRUE, FALSE);
+ err = DB_READ_ONLY;
+ goto funct_exit;
+ }
+
/* Turn on this drop bit before we could release the dictionary
latch */
table->to_be_dropped = true;
@@ -4892,19 +4888,16 @@ row_rename_table_for_mysql(
ut_a(new_name != NULL);
ut_ad(trx->state == TRX_STATE_ACTIVE);
- if (srv_created_new_raw || srv_force_recovery) {
- fputs("InnoDB: A new raw disk partition was initialized or\n"
- "InnoDB: innodb_force_recovery is on: we do not allow\n"
+ if (srv_force_recovery) {
+ fputs("InnoDB: innodb_force_recovery is on: we do not allow\n"
"InnoDB: database modifications by the user. Shut down\n"
- "InnoDB: mysqld and edit my.cnf so that newraw"
- " is replaced\n"
- "InnoDB: with raw, and innodb_force_... is removed.\n",
+ "InnoDB: mysqld and edit my.cnf so that"
+ "InnoDB: innodb_force_... is removed.\n",
stderr);
- if(srv_force_recovery) {
- err = DB_READ_ONLY;
- }
+ err = DB_READ_ONLY;
goto funct_exit;
+
} else if (row_mysql_is_system_table(new_name)) {
fprintf(stderr,
diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index b1d64c16c60..a1edbca757c 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -2,6 +2,7 @@
Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
+Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -3726,6 +3727,9 @@ row_search_for_mysql(
return(DB_TABLESPACE_NOT_FOUND);
+ } else if (prebuilt->table->is_encrypted) {
+
+ return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (!prebuilt->index_usable) {
return(DB_MISSING_HISTORY);
@@ -4137,9 +4141,14 @@ wait_table_again:
} else if (dtuple_get_n_fields(search_tuple) > 0) {
- btr_pcur_open_with_no_init(index, search_tuple, mode,
- BTR_SEARCH_LEAF,
- pcur, 0, &mtr);
+ err = btr_pcur_open_with_no_init(index, search_tuple, mode,
+ BTR_SEARCH_LEAF,
+ pcur, 0, &mtr);
+
+ if (err != DB_SUCCESS) {
+ rec = NULL;
+ goto lock_wait_or_error;
+ }
pcur->trx_if_known = trx;
@@ -4173,9 +4182,23 @@ wait_table_again:
}
}
} else if (mode == PAGE_CUR_G || mode == PAGE_CUR_L) {
- btr_pcur_open_at_index_side(
+ err = btr_pcur_open_at_index_side(
mode == PAGE_CUR_G, index, BTR_SEARCH_LEAF,
pcur, false, 0, &mtr);
+
+ if (err != DB_SUCCESS) {
+ if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
+ ib_push_warning(trx->mysql_thd,
+ DB_ENCRYPTED_DECRYPT_FAILED,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ prebuilt->table->name);
+ index->table->is_encrypted = true;
+ }
+ rec = NULL;
+ goto lock_wait_or_error;
+ }
}
rec_loop:
@@ -4191,6 +4214,11 @@ rec_loop:
rec = btr_pcur_get_rec(pcur);
+ if (!rec) {
+ err = DB_ENCRYPTED_DECRYPT_FAILED;
+ goto lock_wait_or_error;
+ }
+
SRV_CORRUPT_TABLE_CHECK(rec,
{
err = DB_CORRUPTION;
@@ -5132,7 +5160,9 @@ lock_wait_or_error:
/*-------------------------------------------------------------*/
- btr_pcur_store_position(pcur, &mtr);
+ if (rec) {
+ btr_pcur_store_position(pcur, &mtr);
+ }
lock_table_wait:
mtr_commit(&mtr);
diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index 3f558170f97..54ac04e7248 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2015, MariaDB Corporation
@@ -264,8 +264,8 @@ srv_file_check_mode(
/* Note: stat.rw_perm is only valid of files */
- if (stat.type == OS_FILE_TYPE_FILE
- || stat.type == OS_FILE_TYPE_BLOCK) {
+ if (stat.type == OS_FILE_TYPE_FILE) {
+
if (!stat.rw_perm) {
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -462,14 +462,18 @@ srv_parse_data_file_paths_and_sizes(
&& *(str + 1) == 'e'
&& *(str + 2) == 'w') {
str += 3;
- (srv_data_file_is_raw_partition)[i] = SRV_NEW_RAW;
+ /* Initialize new raw device only during bootstrap */
+ (srv_data_file_is_raw_partition)[i] =
+ opt_bootstrap ? SRV_NEW_RAW : SRV_OLD_RAW;
}
if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') {
str += 3;
+ /* Initialize new raw device only during bootstrap */
if ((srv_data_file_is_raw_partition)[i] == 0) {
- (srv_data_file_is_raw_partition)[i] = SRV_OLD_RAW;
+ (srv_data_file_is_raw_partition)[i] =
+ opt_bootstrap ? SRV_NEW_RAW : SRV_OLD_RAW;
}
}
@@ -945,6 +949,21 @@ open_or_create_data_files(
return(DB_ERROR);
}
+
+ const char* check_msg;
+ check_msg = fil_read_first_page(
+ files[i], FALSE, &flags, &space,
+ min_flushed_lsn, max_flushed_lsn, NULL);
+
+ /* If first page is valid, don't overwrite DB.
+ It prevents overwriting DB when mysql_install_db
+ starts mysqld multiple times during bootstrap. */
+ if (check_msg == NULL) {
+
+ srv_created_new_raw = FALSE;
+ ret = FALSE;
+ }
+
} else if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) {
srv_start_raw_disk_in_use = TRUE;
diff --git a/storage/xtradb/sync/sync0arr.cc b/storage/xtradb/sync/sync0arr.cc
index 01cae70a8ce..d881c5de2f5 100644
--- a/storage/xtradb/sync/sync0arr.cc
+++ b/storage/xtradb/sync/sync0arr.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved.
@@ -1206,8 +1206,8 @@ sync_array_print_info_low(
ulint count = 0;
fprintf(file,
- "OS WAIT ARRAY INFO: reservation count %ld\n",
- (long) arr->res_count);
+ "OS WAIT ARRAY INFO: reservation count " ULINTPF "\n",
+ arr->res_count);
for (i = 0; count < arr->n_reserved; ++i) {
sync_cell_t* cell;
@@ -1303,7 +1303,7 @@ sync_array_print(
}
fprintf(file,
- "OS WAIT ARRAY INFO: signal count %ld\n", (long) sg_count);
+ "OS WAIT ARRAY INFO: signal count " ULINTPF "\n", sg_count);
}
diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc
index 32948d6847c..bebd28b0df3 100644
--- a/storage/xtradb/trx/trx0sys.cc
+++ b/storage/xtradb/trx/trx0sys.cc
@@ -1332,8 +1332,6 @@ trx_sys_close(void)
/* Free the double write data structures. */
buf_dblwr_free();
- mutex_enter(&trx_sys->mutex);
-
ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
/* Only prepared transactions may be left in the system. Free them. */
@@ -1373,8 +1371,6 @@ trx_sys_close(void)
ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
- mutex_exit(&trx_sys->mutex);
-
mutex_free(&trx_sys->mutex);
ut_ad(trx_sys->descr_n_used == 0);
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 5d3b86e158f..9bca6de9c26 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -481,9 +481,7 @@ trx_free_prepared(
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED));
ut_a(trx->magic_n == TRX_MAGIC_N);
- mutex_exit(&trx_sys->mutex);
lock_trx_release_locks(trx);
- mutex_enter(&trx_sys->mutex);
trx_undo_free_prepared(trx);
assert_trx_in_rw_list(trx);
@@ -493,7 +491,9 @@ trx_free_prepared(
UT_LIST_REMOVE(trx_list, trx_sys->rw_trx_list, trx);
ut_d(trx->in_rw_trx_list = FALSE);
+ mutex_enter(&trx_sys->mutex);
trx_release_descriptor(trx);
+ mutex_exit(&trx_sys->mutex);
/* Undo trx_resurrect_table_locks(). */
UT_LIST_INIT(trx->lock.trx_locks);
diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc
index 121cbdb7bc0..96f2c537deb 100644
--- a/storage/xtradb/ut/ut0ut.cc
+++ b/storage/xtradb/ut/ut0ut.cc
@@ -827,6 +827,8 @@ ut_strerr(
return("Too many words in a FTS phrase or proximity search");
case DB_TOO_BIG_FOR_REDO:
return("BLOB record length is greater than 10%% of redo log");
+ case DB_ENCRYPTED_DECRYPT_FAILED:
+ return("Table is encrypted but decrypt failed.");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */